Production hotfix — cherry-pick of #10288 onto production. Closes the same MCP authentication-bypass that PR #10288 fixes on master. Two changes:
Always require API key or JWT for MCP access. API key validation was previously conditional on project_config.requireMcpApiKey (default false for pre-March 2026 orgs). An attacker holding only a captured server UUID could connect and execute tools without any API key. Server ID alone is no longer sufficient authentication.
Disable SSE transport entirely. GET /v3/mcp/:id/sse now returns 405. SSE is not an officially supported transport, held Lambda connections for 300s at 4096MB each, and was an additional unauthenticated attack surface.
Cherry-picked from commit 134c00a3 (PR #10288). The resolvers.ts hunk required a manual conflict resolution because production and master have diverged in resolveMCPAuthNext: production keeps an explicit let authenticatedAuthInfo declaration before the auth gate. The security change (drop shouldEnforceApiKey, drop the no-API-key debug log, always enter the auth block) was applied on top of production's structure. The route.ts change applied cleanly and is byte-identical to #10288.
Pre-March 2026 orgs connecting to MCP without an API key will now get 401s and must add an x-api-key header. SSE clients will get 405s and must switch to streamable HTTP transport.
production (route.ts: SSE disabled / GET always 405; resolvers.ts: API key/JWT always enforced).shouldEnforceApiKey is fully removed, authenticatedAuthInfo declaration preserved, apiKey/sanitizeEmail still used.Manual runtime verification still recommended before deploy:
- MCP POST with valid API key works
- MCP POST without API key returns 401
GET /v3/mcp/:id/ssereturns 405- Monitor Datadog for the expected 401 spike from customers who need to add API keys
🤖 Generated with Claude Code