diff --git a/extensions/general/mcp-server/index.ts b/extensions/general/mcp-server/index.ts index f42d2816..542be1e8 100644 --- a/extensions/general/mcp-server/index.ts +++ b/extensions/general/mcp-server/index.ts @@ -36,14 +36,18 @@ export const mcpServerExtension: Extension = { method: 'GET', path: '/mcp', skipAuth: true, + // This server is stateless and offers no server-initiated SSE stream, so + // the Streamable HTTP spec requires 405 Method Not Allowed here. Returning + // 401 (as we previously did) makes spec-compliant clients (Claude + // connector, Claude Desktop, Cursor) treat the SSE GET as an auth failure + // and retry-loop — refresh token → re-open GET → 401 → … — which storms + // the endpoint and churns OAuth key rotation. OAuth discovery is + // bootstrapped on the POST 401 (WWW-Authenticate), not here. handler: async (request: Request) => { if (isForbiddenOrigin(request)) return forbiddenOriginResponse() - const appUrl = process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000' - return new Response('Authorization required', { - status: 401, - headers: { - 'WWW-Authenticate': `Bearer resource_metadata="${appUrl}/.well-known/oauth-protected-resource"`, - }, + return new Response('Method Not Allowed', { + status: 405, + headers: { Allow: 'POST, DELETE' }, }) }, },