support API key authentication on the HTTP MCP endpoint
What would you like to change?
The HTTP MCP endpoint (/api/mcp) is OAuth-only, which leaves non-interactive clients with no supported way to connect. Please allow a Kaneo API key (Settings → Account → Developer) to authenticate it.
Why it currently cannot work — validateBearerToken() in apps/api/src/mcp/index.ts:
It requires
Authorization: Bearer <token>and then rebuilds the header set (const headers = new Headers(); headers.set("authorization", ...)), so anx-api-keyheader is dropped before auth ever runs.It resolves the Bearer value through
auth.api.getSession(), i.e. against the session table. An API key has no row there, soAuthorization: Bearer <apiKey>always returns:401 {"error":"invalid_token","error_description":"Missing or invalid token"}The API key plugin is configured with
enableSessionForAPIKeys: truebutapiKeyHeaders: "x-api-key", so it only accepts the key from that header — which the MCP route never forwards.
The same key works on REST (authenticateApiRequest → verifyApiKey), so the credential is valid; only the MCP route cannot consume it. There is no header combination that gets in.
Impact: clients that cannot open a browser — headless agents, server-to-server integrations, or clients that support only a static auth header — cannot use /api/mcp at all. The workarounds are running the OAuth flow by hand and pasting the resulting token (grant_types_supported is ["authorization_code"], so there is no refresh grant and the token expires), or running the stdio package as a local process.
Suggestion: either forward x-api-key into the getSession call in validateBearerToken, or fall back to verifyApiKey when the session lookup fails. Both leave the existing session/OAuth path untouched.
Additional context
- #1410, #1411 and #1412 implemented exactly this and were all closed without review; #1410 touched only
apps/api/src/mcp/index.ts. - If OAuth-only is intentional, it would help to state that explicitly on the MCP docs page. It describes OAuth for
/api/mcpand device authorization for stdio, but never says API keys are unsupported on the HTTP endpoint — while the@kaneo/mcpREADME presentsKANEO_API_KEYas the headless credential, which reads as though it applies to MCP generally.
Originally requested by @Gadgitmatic on 2026-09-28. Original GitHub request #1842.