diff --git a/client/src/lib/hooks/__tests__/useConnection.test.tsx b/client/src/lib/hooks/__tests__/useConnection.test.tsx index 4907a085b..7c6d983ec 100644 --- a/client/src/lib/hooks/__tests__/useConnection.test.tsx +++ b/client/src/lib/hooks/__tests__/useConnection.test.tsx @@ -1384,6 +1384,35 @@ describe("useConnection", () => { expect(mockSSETransport.url?.toString()).toBe("http://localhost:8080/"); }); + test("does not send x-custom-auth-headers for direct connections", async () => { + const customHeaders: CustomHeaders = [ + { name: "Authorization", value: "Bearer token123", enabled: true }, + { name: "X-Tenant-ID", value: "acme-inc", enabled: true }, + ]; + + const directPropsWithHeaders = { + ...defaultProps, + connectionType: "direct" as const, + customHeaders, + }; + + const { result } = renderHook(() => + useConnection(directPropsWithHeaders), + ); + + await act(async () => { + await result.current.connect(); + }); + + const headers = mockSSETransport.options?.requestInit?.headers; + // Custom headers should still be sent + expect(headers).toHaveProperty("Authorization", "Bearer token123"); + expect(headers).toHaveProperty("X-Tenant-ID", "acme-inc"); + // But the x-custom-auth-headers meta-header should NOT be sent for direct connections + // because MCP servers don't expect it and it breaks CORS preflight + expect(headers).not.toHaveProperty("x-custom-auth-headers"); + }); + test("uses proxy server URL when connectionType is 'proxy'", async () => { const proxyProps = { ...defaultProps, diff --git a/client/src/lib/hooks/useConnection.ts b/client/src/lib/hooks/useConnection.ts index e14d1037f..f4e06a0db 100644 --- a/client/src/lib/hooks/useConnection.ts +++ b/client/src/lib/hooks/useConnection.ts @@ -558,8 +558,11 @@ export function useConnection({ } }); - // Add custom header names as a special request header for server processing - if (customHeaderNames.length > 0) { + // Add custom header names as a special request header for proxy server processing. + // Only include this meta-header for proxied connections — direct connections send + // headers straight to the MCP server, which won't include x-custom-auth-headers + // in its Access-Control-Allow-Headers, breaking CORS preflight checks. + if (customHeaderNames.length > 0 && connectionType !== "direct") { headers["x-custom-auth-headers"] = JSON.stringify(customHeaderNames); }