From 1eabff5b68c63cdd02052835ed52973c428b7a8d Mon Sep 17 00:00:00 2001 From: Victor <70475442+vsolano9@users.noreply.github.com> Date: Sun, 23 Aug 2026 14:54:21 +0200 Subject: [PATCH] fix: reject empty JSON-RPC batches Return the required Invalid Request response before dispatch while preserving response-free notification batches. --- src/mcp.ts | 4 ++++ test/mcp.test.ts | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 test/mcp.test.ts diff --git a/src/mcp.ts b/src/mcp.ts index 8a4acf7..24ad9ff 100644 --- a/src/mcp.ts +++ b/src/mcp.ts @@ -155,6 +155,10 @@ export async function handleMcpRequest(request: Request): Promise { return jsonRpcError(null, -32700, "Parse error"); } + if (Array.isArray(body) && body.length === 0) { + return jsonRpcError(null, -32600, "Invalid Request"); + } + const requests = Array.isArray(body) ? body : [body]; const responses: unknown[] = []; diff --git a/test/mcp.test.ts b/test/mcp.test.ts new file mode 100644 index 0000000..78fa0d9 --- /dev/null +++ b/test/mcp.test.ts @@ -0,0 +1,35 @@ +import { describe, expect, it } from "vitest"; +import { handleMcpRequest } from "../src/mcp"; + +function postJson(body: unknown): Request { + return new Request("https://casebook.test/mcp", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(body), + }); +} + +describe("handleMcpRequest batches", () => { + it("returns Invalid Request for an empty batch", async () => { + const response = await handleMcpRequest(postJson([])); + + expect(response.status).toBe(400); + expect(await response.json()).toEqual({ + jsonrpc: "2.0", + id: null, + error: { code: -32600, message: "Invalid Request" }, + }); + }); + + it("keeps non-empty notification-only batches response-free", async () => { + const response = await handleMcpRequest( + postJson([ + { jsonrpc: "2.0", method: "notifications/initialized" }, + { jsonrpc: "2.0", method: "ping" }, + ]), + ); + + expect(response.status).toBe(202); + expect(await response.text()).toBe(""); + }); +});