From 09745e3288c0e9564d83af861d46af899d28caf3 Mon Sep 17 00:00:00 2001 From: Evan Date: Mon, 6 Apr 2026 23:12:50 +0900 Subject: [PATCH] fix: handle null body status in createCustomFetch proxy When an MCP server returns HTTP 204 No Content (e.g., on DELETE session termination), the proxy's createCustomFetch crashes with: TypeError: Response constructor: Invalid response status code 204 This happens because node-fetch returns a non-null body stream even for 204 responses, and the Web Response constructor rejects a body for null body statuses per the Fetch spec. Additionally, returning the raw node-fetch response (path #3) causes `response.body?.cancel is not a function` because node-fetch uses Node.js Readable streams, not Web ReadableStreams. Fix: detect null body statuses (204, 205, 304) and return a proper Web Response with null body before the SSE stream conversion check. --- server/src/index.ts | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/server/src/index.ts b/server/src/index.ts index 4d1fffa29..45908e11c 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -338,6 +338,28 @@ const createCustomFetch = (headerHolder: { headers: HeadersInit }) => { const acceptHeader = finalHeaders.get("Accept"); const isSSE = acceptHeader?.includes("text/event-stream"); + // Null body statuses (204, 205, 304) must not have a body per the + // Fetch spec. node-fetch may still provide a non-null body stream, + // but the Web Response constructor rejects a body for these statuses. + // Return a proper Web Response with null body so the SDK's + // response.body?.cancel() call works correctly. + const isNullBodyStatus = + response.status === 204 || + response.status === 205 || + response.status === 304; + + if (isNullBodyStatus) { + const responseHeaders: Record = {}; + response.headers.forEach((value: string, key: string) => { + responseHeaders[key] = value; + }); + return new Response(null, { + status: response.status, + statusText: response.statusText, + headers: responseHeaders, + }); + } + if (isSSE && response.body) { // For SSE requests, we need to convert the Node.js stream to a web ReadableStream // because the EventSource polyfill expects web-compatible streams