| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153 |
- import { test, expect, mock, beforeEach } from "bun:test"
- // Track what options were passed to each transport constructor
- const transportCalls: Array<{
- type: "streamable" | "sse"
- url: string
- options: { authProvider?: unknown; requestInit?: RequestInit }
- }> = []
- // Mock the transport constructors to capture their arguments
- mock.module("@modelcontextprotocol/sdk/client/streamableHttp.js", () => ({
- StreamableHTTPClientTransport: class MockStreamableHTTP {
- constructor(url: URL, options?: { authProvider?: unknown; requestInit?: RequestInit }) {
- transportCalls.push({
- type: "streamable",
- url: url.toString(),
- options: options ?? {},
- })
- }
- async start() {
- throw new Error("Mock transport cannot connect")
- }
- },
- }))
- mock.module("@modelcontextprotocol/sdk/client/sse.js", () => ({
- SSEClientTransport: class MockSSE {
- constructor(url: URL, options?: { authProvider?: unknown; requestInit?: RequestInit }) {
- transportCalls.push({
- type: "sse",
- url: url.toString(),
- options: options ?? {},
- })
- }
- async start() {
- throw new Error("Mock transport cannot connect")
- }
- },
- }))
- beforeEach(() => {
- transportCalls.length = 0
- })
- // Import MCP after mocking
- const { MCP } = await import("../../src/mcp/index")
- const { Instance } = await import("../../src/project/instance")
- const { tmpdir } = await import("../fixture/fixture")
- test("headers are passed to transports when oauth is enabled (default)", async () => {
- await using tmp = await tmpdir({
- init: async (dir) => {
- await Bun.write(
- `${dir}/opencode.json`,
- JSON.stringify({
- $schema: "https://opencode.ai/config.json",
- mcp: {
- "test-server": {
- type: "remote",
- url: "https://example.com/mcp",
- headers: {
- Authorization: "Bearer test-token",
- "X-Custom-Header": "custom-value",
- },
- },
- },
- }),
- )
- },
- })
- await Instance.provide({
- directory: tmp.path,
- fn: async () => {
- // Trigger MCP initialization - it will fail to connect but we can check the transport options
- await MCP.add("test-server", {
- type: "remote",
- url: "https://example.com/mcp",
- headers: {
- Authorization: "Bearer test-token",
- "X-Custom-Header": "custom-value",
- },
- }).catch(() => {})
- // Both transports should have been created with headers
- expect(transportCalls.length).toBeGreaterThanOrEqual(1)
- for (const call of transportCalls) {
- expect(call.options.requestInit).toBeDefined()
- expect(call.options.requestInit?.headers).toEqual({
- Authorization: "Bearer test-token",
- "X-Custom-Header": "custom-value",
- })
- // OAuth should be enabled by default, so authProvider should exist
- expect(call.options.authProvider).toBeDefined()
- }
- },
- })
- })
- test("headers are passed to transports when oauth is explicitly disabled", async () => {
- await using tmp = await tmpdir()
- await Instance.provide({
- directory: tmp.path,
- fn: async () => {
- transportCalls.length = 0
- await MCP.add("test-server-no-oauth", {
- type: "remote",
- url: "https://example.com/mcp",
- oauth: false,
- headers: {
- Authorization: "Bearer test-token",
- },
- }).catch(() => {})
- expect(transportCalls.length).toBeGreaterThanOrEqual(1)
- for (const call of transportCalls) {
- expect(call.options.requestInit).toBeDefined()
- expect(call.options.requestInit?.headers).toEqual({
- Authorization: "Bearer test-token",
- })
- // OAuth is disabled, so no authProvider
- expect(call.options.authProvider).toBeUndefined()
- }
- },
- })
- })
- test("no requestInit when headers are not provided", async () => {
- await using tmp = await tmpdir()
- await Instance.provide({
- directory: tmp.path,
- fn: async () => {
- transportCalls.length = 0
- await MCP.add("test-server-no-headers", {
- type: "remote",
- url: "https://example.com/mcp",
- }).catch(() => {})
- expect(transportCalls.length).toBeGreaterThanOrEqual(1)
- for (const call of transportCalls) {
- // No headers means requestInit should be undefined
- expect(call.options.requestInit).toBeUndefined()
- }
- },
- })
- })
|