From a21dcc725d079f0823e2307dbbf8e8580053597a Mon Sep 17 00:00:00 2001 From: Leo McArdle Date: Mon, 5 Oct 2026 14:05:31 +0100 Subject: [PATCH] fix(server): return 405 to sse requests instead of redirecting extend normal redirect to /mcp as well --- index.js | 7 ++++++- test/server.test.js | 31 +++++++++++++++++++++++++++---- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/index.js b/index.js index 4d9613c..c3fd340 100644 --- a/index.js +++ b/index.js @@ -13,7 +13,12 @@ app.use(express.json()); app.post(["/", "/mcp"], handleRequest); -app.get("/", (_req, res) => { +app.get(["/", "/mcp"], (req, res) => { + // Redirecting SSE clients to HTML can cause an endless reconnect loop. + if (req.accepts(["html", "text/event-stream"]) === "text/event-stream") { + res.set("Allow", "POST").sendStatus(405); + return; + } res.redirect(302, "https://developer.mozilla.org/en-US/mcp"); }); diff --git a/test/server.test.js b/test/server.test.js index d3e5371..146413b 100644 --- a/test/server.test.js +++ b/test/server.test.js @@ -30,10 +30,33 @@ describe("server", () => { assert.deepEqual(ping, {}); }); - it("should redirect get requests to the repo", async () => { - const res = await fetch(`http://localhost:${server.port}`); - assert.ok(res.redirected); - assert.strictEqual(res.url, "https://developer.mozilla.org/en-US/mcp"); + it("should redirect ordinary visits to the landing page", async () => { + for (const path of ["/", "/mcp"]) { + for (const accept of ["*/*", "text/html"]) { + const res = await fetch(`http://localhost:${server.port}${path}`, { + headers: { Accept: accept }, + }); + assert.ok(res.redirected); + assert.strictEqual(res.url, "https://developer.mozilla.org/en-US/mcp"); + } + } + }); + + it("should reject optional MCP notification streams without redirecting", async () => { + for (const path of ["/", "/mcp"]) { + for (const accept of [ + "text/event-stream", + "application/json, text/event-stream", + ]) { + const res = await fetch(`http://localhost:${server.port}${path}`, { + headers: { Accept: accept }, + redirect: "manual", + }); + assert.equal(res.status, 405); + assert.equal(res.headers.get("allow"), "POST"); + assert.equal(res.headers.get("location"), null); + } + } }); after(() => {