Przeglądaj źródła

fix(mcp): preserve headers during auth and debug (#31802)

Aiden Cline 2 miesięcy temu
rodzic
commit
bf05e8a122

+ 2 - 0
packages/opencode/src/cli/cmd/mcp.ts

@@ -744,6 +744,7 @@ export const McpDebugCommand = effectCmd({
         const response = await fetch(serverConfig.url, {
           method: "POST",
           headers: {
+            ...serverConfig.headers,
             "Content-Type": "application/json",
             Accept: "application/json, text/event-stream",
           },
@@ -792,6 +793,7 @@ export const McpDebugCommand = effectCmd({
           // Try creating transport with auth provider to trigger discovery
           const transport = new StreamableHTTPClientTransport(new URL(serverConfig.url), {
             authProvider,
+            requestInit: serverConfig.headers ? { headers: serverConfig.headers } : undefined,
           })
 
           try {

+ 4 - 1
packages/opencode/src/mcp/index.ts

@@ -741,7 +741,10 @@ export const layer = Layer.effect(
         auth,
       )
 
-      const transport = new StreamableHTTPClientTransport(url, { authProvider })
+      const transport = new StreamableHTTPClientTransport(url, {
+        authProvider,
+        requestInit: mcpConfig.headers ? { headers: mcpConfig.headers } : undefined,
+      })
 
       return yield* Effect.tryPromise({
         try: () => {

+ 9 - 4
packages/opencode/test/mcp/oauth-browser.test.ts

@@ -38,7 +38,7 @@ class MockUnauthorizedError extends Error {
 const transportCalls: Array<{
   type: "streamable" | "sse"
   url: string
-  options: { authProvider?: unknown }
+  options: { authProvider?: unknown; requestInit?: RequestInit }
 }> = []
 
 // Mock the transport constructors
@@ -46,7 +46,10 @@ void mock.module("@modelcontextprotocol/sdk/client/streamableHttp.js", () => ({
   StreamableHTTPClientTransport: class MockStreamableHTTP {
     url: string
     authProvider: { redirectToAuthorization?: (url: URL) => Promise<void> } | undefined
-    constructor(url: URL, options?: { authProvider?: { redirectToAuthorization?: (url: URL) => Promise<void> } }) {
+    constructor(
+      url: URL,
+      options?: { authProvider?: { redirectToAuthorization?: (url: URL) => Promise<void> }; requestInit?: RequestInit },
+    ) {
       this.url = url.toString()
       this.authProvider = options?.authProvider
       transportCalls.push({
@@ -127,11 +130,12 @@ const mcpTest = testEffect(
 )
 const service = MCP.Service as unknown as Effect.Effect<MCPNS.Interface, never, never>
 
-const config = (name: string) => ({
+const config = (name: string, headers?: Record<string, string>) => ({
   mcp: {
     [name]: {
       type: "remote" as const,
       url: "https://example.com/mcp",
+      headers,
     },
   },
 })
@@ -227,6 +231,7 @@ mcpTest.instance(
       expect(failure).toEqual(Option.none())
       expect(typeof url).toBe("string")
       expect(url).toContain("https://")
+      expect(transportCalls.at(-1)?.options.requestInit?.headers).toEqual({ "X-Custom-Header": "custom-value" })
     }),
-  { config: config("test-oauth-server-3") },
+  { config: config("test-oauth-server-3", { "X-Custom-Header": "custom-value" }) },
 )