921b1c6a34
Co-authored-by: Matt Carey <mcarey@cloudflare.com>
120 lines
4.0 KiB
TypeScript
120 lines
4.0 KiB
TypeScript
import { describe, expect } from "bun:test"
|
|
import { Server, WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/server"
|
|
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
|
import { Effect } from "effect"
|
|
import { testEffect } from "../lib/effect"
|
|
import { MCP } from "../../src/mcp/index"
|
|
|
|
const it = testEffect(LayerNode.compile(MCP.node))
|
|
|
|
const serve = Effect.acquireRelease(
|
|
Effect.promise(async () => {
|
|
const requests: Headers[] = []
|
|
const protocol = new Server({ name: "headers", version: "1.0.0" }, { capabilities: { tools: {} } })
|
|
protocol.setRequestHandler("tools/list", () => Promise.resolve({ tools: [] }))
|
|
const transport = new WebStandardStreamableHTTPServerTransport({
|
|
sessionIdGenerator: () => crypto.randomUUID(),
|
|
enableJsonResponse: true,
|
|
})
|
|
await protocol.connect(transport)
|
|
const http = Bun.serve({
|
|
port: 0,
|
|
fetch(request) {
|
|
requests.push(new Headers(request.headers))
|
|
return transport.handleRequest(request)
|
|
},
|
|
})
|
|
return {
|
|
requests,
|
|
url: http.url.toString(),
|
|
close: async () => {
|
|
await http.stop(true)
|
|
await protocol.close()
|
|
},
|
|
}
|
|
}),
|
|
(server) => Effect.promise(server.close),
|
|
)
|
|
|
|
const serveUnauthorized = Effect.acquireRelease(
|
|
Effect.sync(() => Bun.serve({ port: 0, fetch: () => new Response("Unauthorized", { status: 401 }) })),
|
|
(server) => Effect.sync(() => server.stop(true)),
|
|
)
|
|
|
|
describe("mcp.headers", () => {
|
|
it.instance("headers are passed to transports when oauth is enabled (default)", () =>
|
|
Effect.gen(function* () {
|
|
const server = yield* serve
|
|
const mcp = yield* MCP.Service
|
|
const result = yield* mcp.add("test-server", {
|
|
type: "remote",
|
|
url: server.url,
|
|
headers: {
|
|
Authorization: "Bearer test-token",
|
|
"X-Custom-Header": "custom-value",
|
|
},
|
|
})
|
|
|
|
expect(result.status).toMatchObject({ "test-server": { status: "connected" } })
|
|
expect(server.requests.length).toBeGreaterThan(0)
|
|
for (const headers of server.requests) {
|
|
expect(headers.get("authorization")).toBe("Bearer test-token")
|
|
expect(headers.get("x-custom-header")).toBe("custom-value")
|
|
}
|
|
}),
|
|
)
|
|
|
|
it.instance("headers are passed to transports when oauth is explicitly disabled", () =>
|
|
Effect.gen(function* () {
|
|
const server = yield* serve
|
|
const mcp = yield* MCP.Service
|
|
const result = yield* mcp.add("test-server-no-oauth", {
|
|
type: "remote",
|
|
url: server.url,
|
|
oauth: false,
|
|
headers: {
|
|
Authorization: "Bearer test-token",
|
|
},
|
|
})
|
|
|
|
expect(result.status).toMatchObject({ "test-server-no-oauth": { status: "connected" } })
|
|
expect(server.requests.length).toBeGreaterThan(0)
|
|
for (const headers of server.requests) {
|
|
expect(headers.get("authorization")).toBe("Bearer test-token")
|
|
}
|
|
}),
|
|
)
|
|
|
|
it.instance("no requestInit when headers are not provided", () =>
|
|
Effect.gen(function* () {
|
|
const server = yield* serve
|
|
const mcp = yield* MCP.Service
|
|
const result = yield* mcp.add("test-server-no-headers", {
|
|
type: "remote",
|
|
url: server.url,
|
|
})
|
|
|
|
expect(result.status).toMatchObject({ "test-server-no-headers": { status: "connected" } })
|
|
expect(server.requests.length).toBeGreaterThan(0)
|
|
for (const headers of server.requests) {
|
|
expect(headers.has("authorization")).toBe(false)
|
|
expect(headers.has("x-custom-header")).toBe(false)
|
|
}
|
|
}),
|
|
)
|
|
|
|
it.instance("reports 401 as failed when oauth is explicitly disabled", () =>
|
|
Effect.gen(function* () {
|
|
const server = yield* serveUnauthorized
|
|
const mcp = yield* MCP.Service
|
|
const result = yield* mcp.add("unauthorized-no-oauth", {
|
|
type: "remote",
|
|
url: server.url.toString(),
|
|
oauth: false,
|
|
})
|
|
|
|
expect(result.status).toMatchObject({ "unauthorized-no-oauth": { status: "failed" } })
|
|
}),
|
|
)
|
|
})
|