From c57117daae1b1949a73d679d6c9458cad2d6b724 Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Fri, 21 Aug 2026 06:29:55 -0700 Subject: [PATCH] Fix: move mcp method ordering --- src/pages/api/mcp/index.js | 11 ++++++----- src/pages/api/mcp/index.test.js | 34 +++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/src/pages/api/mcp/index.js b/src/pages/api/mcp/index.js index 13f69cfcb..9e52acf25 100644 --- a/src/pages/api/mcp/index.js +++ b/src/pages/api/mcp/index.js @@ -15,6 +15,12 @@ export default async function handler(req, res) { return res.status(404).end("Not Found"); } + // Method check precedes auth so CORS preflights aren't answered with a 401. + if (req.method !== "POST") { + res.setHeader("Allow", "POST"); + return res.status(405).end("Method Not Allowed"); + } + const tokenError = mcpTokenConfigError(); if (tokenError) { createLogger("mcp").error(tokenError); @@ -25,11 +31,6 @@ export default async function handler(req, res) { return res.status(401).json({ error: "Unauthorized" }); } - if (req.method !== "POST") { - res.setHeader("Allow", "POST"); - return res.status(405).end("Method Not Allowed"); - } - const response = handleMcpRequest(req.body); if (!response) { return res.status(202).end(); diff --git a/src/pages/api/mcp/index.test.js b/src/pages/api/mcp/index.test.js index e98e6d963..30bf73140 100644 --- a/src/pages/api/mcp/index.test.js +++ b/src/pages/api/mcp/index.test.js @@ -214,4 +214,38 @@ describe("pages/api/mcp", () => { expect(res.status).toHaveBeenCalledWith(405); expect(res.setHeader).toHaveBeenCalledWith("Allow", "POST"); }); + + it("answers unauthenticated CORS preflights with 405 rather than 401", async () => { + process.env.HOMEPAGE_MCP_ENABLED = "true"; + process.env.HOMEPAGE_MCP_TOKEN = "mcp-tok-0123456789abcdefghijklmnopqrstuv"; + const handler = await loadHandler(); + const res = mockResponse(); + + // a preflight never carries the Authorization header the browser strips + await handler( + { + method: "OPTIONS", + headers: { + origin: "https://claude.ai", + "access-control-request-method": "POST", + "access-control-request-headers": "authorization,content-type", + }, + }, + res, + ); + + expect(res.status).toHaveBeenCalledWith(405); + expect(res.setHeader).toHaveBeenCalledWith("Allow", "POST"); + expect(getServerSession).not.toHaveBeenCalled(); + }); + + it("still returns 404 for non-POST requests while disabled", async () => { + delete process.env.HOMEPAGE_MCP_ENABLED; + const handler = await loadHandler(); + const res = mockResponse(); + + await handler({ method: "OPTIONS", headers: {} }, res); + + expect(res.status).toHaveBeenCalledWith(404); + }); });