fix(mcp): use public CORS (*) so claude.ai and external MCP clients connect (#2416)

getCorsHeaders() restricts ACAO to worldmonitor.app origins only.
claude.ai sends Origin: https://claude.ai which fails the isDisallowedOrigin
check and gets ACAO: https://worldmonitor.app back — browser rejects it.

MCP is secured by API key (validateApiKey forceKey:true), not by origin.
Switch to getPublicCorsHeaders() (ACAO: *) and remove isDisallowedOrigin
block so any authenticated MCP client (claude.ai, Claude Desktop, agents)
can connect.
This commit is contained in:
Elie Habib
2026-03-28 13:12:03 +04:00
committed by GitHub
parent 5fb2365d66
commit e9cbbc65d5

View File

@@ -1,7 +1,7 @@
import { Ratelimit } from '@upstash/ratelimit';
import { Redis } from '@upstash/redis';
// @ts-expect-error — JS module, no declaration file
import { getCorsHeaders, isDisallowedOrigin } from './_cors.js';
import { getPublicCorsHeaders } from './_cors.js';
// @ts-expect-error — JS module, no declaration file
import { jsonResponse } from './_json-response.js';
// @ts-expect-error — JS module, no declaration file
@@ -417,16 +417,13 @@ async function executeTool(tool: CacheToolDef): Promise<{ cached_at: string | nu
// Main handler
// ---------------------------------------------------------------------------
export default async function handler(req: Request): Promise<Response> {
const corsHeaders = getCorsHeaders(req, 'POST, OPTIONS');
// MCP is a public API endpoint secured by API key — allow all origins (claude.ai, Claude Desktop, custom agents)
const corsHeaders = getPublicCorsHeaders('POST, OPTIONS');
if (req.method === 'OPTIONS') {
return new Response(null, { status: 204, headers: corsHeaders });
}
if (isDisallowedOrigin(req)) {
return rpcError(null, -32001, 'Origin not allowed');
}
// Auth — always require API key (MCP clients are never same-origin browser requests)
const auth = validateApiKey(req, { forceKey: true });
if (!auth.valid) {