mcp: accept ?api_key= query param (for MCP hosts without custom-header support, e.g. claude.ai custom connectors)

This commit is contained in:
Scot Thom 2026-07-18 07:21:01 +00:00
parent 475bcf9448
commit 18acb4f71b

View file

@ -5,7 +5,7 @@ import { z } from "zod";
import { pool } from "./db.js";
import { guideMarkdown } from "./guide.js";
import { renderVideo } from "./video.js";
import { authFromHeader, type AuthedKey, type Scope } from "./auth.js";
import { authFromHeader, lookupKey, type AuthedKey, type Scope } from "./auth.js";
import { randomBytes } from "node:crypto";
/**
@ -323,7 +323,13 @@ function buildServer(key: AuthedKey): McpServer {
export async function mcpRoutes(app: FastifyInstance): Promise<void> {
// Stateless Streamable HTTP: fresh server+transport per request, auth per request.
app.post("/mcp", async (req, reply) => {
const key = await authFromHeader(req.headers.authorization);
// Auth: Authorization header OR ?api_key= query param. The query-param form
// exists for MCP hosts whose connector UI cannot set custom headers
// (e.g. claude.ai custom connectors where header auth is still beta).
const q = (req.query as { api_key?: string }) ?? {};
const key = q.api_key
? await lookupKey(q.api_key)
: await authFromHeader(req.headers.authorization);
if (!key) return reply.code(401).send({ error: "invalid or missing API key" });
const server = buildServer(key);
const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined });