From 5ae0db042d70b61a83112d0b5688899a0435cabc Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Mon, 18 May 2026 13:28:31 +0900 Subject: [PATCH] fix(websearch): use Bearer auth for Exa MCP Switch from query-param (?exaApiKey=...) to Authorization: Bearer header for Exa MCP authentication. The MCP SDK's SSE endpoint resolution discards query parameters when the server replies with a relative path, causing EXA_API_KEY to be silently lost and falling back to rate-limited free tier. Bearer auth via header survives URL resolution and is consistent with the Tavily MCP config pattern already in use. Fixes #3763 Relands #4090 (CLA unsigned by original author) Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Minsoo Choi Co-authored-by: Sisyphus --- src/mcp/websearch.test.ts | 33 +++++++++++++++++++++++++++++++++ src/mcp/websearch.ts | 6 ++---- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/mcp/websearch.test.ts b/src/mcp/websearch.test.ts index 707961670..87fb2dce4 100644 --- a/src/mcp/websearch.test.ts +++ b/src/mcp/websearch.test.ts @@ -54,3 +54,36 @@ describe("createWebsearchConfig Tavily handling", () => { expect(config?.url).toBe("https://mcp.tavily.com/mcp/") }) }) + +describe("createWebsearchConfig Exa handling", () => { + test("keeps EXA_API_KEY out of URL query params and sends bearer auth header", () => { + process.env.EXA_API_KEY = "exa-secret" + + const config = createWebsearchConfig({ provider: "exa" }) + + expect(config).toEqual({ + type: "remote", + url: "https://mcp.exa.ai/mcp?tools=web_search_exa", + enabled: true, + headers: { + Authorization: "Bearer exa-secret", + }, + oauth: false, + }) + expect(config?.url).not.toContain("exaApiKey") + expect(config?.headers).not.toHaveProperty("x-api-key") + }) + + test("uses unauthenticated Exa URL when EXA_API_KEY is missing", () => { + delete process.env.EXA_API_KEY + + const config = createWebsearchConfig({ provider: "exa" }) + + expect(config).toEqual({ + type: "remote", + url: "https://mcp.exa.ai/mcp?tools=web_search_exa", + enabled: true, + oauth: false, + }) + }) +}) diff --git a/src/mcp/websearch.ts b/src/mcp/websearch.ts index be3bad4b2..5417e8289 100644 --- a/src/mcp/websearch.ts +++ b/src/mcp/websearch.ts @@ -32,11 +32,9 @@ export function createWebsearchConfig(config?: WebsearchConfig): RemoteMcpConfig return { type: "remote" as const, - url: process.env.EXA_API_KEY - ? `https://mcp.exa.ai/mcp?tools=web_search_exa&exaApiKey=${encodeURIComponent(process.env.EXA_API_KEY)}` - : "https://mcp.exa.ai/mcp?tools=web_search_exa", + url: "https://mcp.exa.ai/mcp?tools=web_search_exa", enabled: true, - ...(process.env.EXA_API_KEY ? { headers: { "x-api-key": process.env.EXA_API_KEY } } : {}), + ...(process.env.EXA_API_KEY ? { headers: { Authorization: `Bearer ${process.env.EXA_API_KEY}` } } : {}), oauth: false as const, } }