Sfoglia il codice sorgente

fix(mcp): handle 404 responses from streamableHttp servers (#8321)

* fix(mcp): handle 404 responses from streamableHttp servers

The MCP SDK sends a GET request to check for SSE stream support when
connecting to streamableHttp servers. Per the MCP spec, servers that
don't support SSE should return 405 (Method Not Allowed), but many
servers incorrectly return 404 (Not Found).

The SDK only gracefully handles 405 responses, so servers returning 404
cause connection failures with "Failed to open SSE stream: Not Found".

This was exposed by the SDK upgrade from 1.22.0 to 1.25.1 in v3.46.0,
which added stricter SSE stream initialization checks.

This fix wraps the fetch function to normalize 404 -> 405 for GET
requests, allowing Cline to work with non-compliant servers while
they update to return proper 405 responses.

Fixes #8320
Fixes #7577

* chore: add changeset
Saoud Rizwan 3 settimane fa
parent
commit
46ab08c9f8
2 ha cambiato i file con 24 aggiunte e 0 eliminazioni
  1. 5 0
      .changeset/fix-mcp-404-handling.md
  2. 19 0
      src/services/mcp/McpHub.ts

+ 5 - 0
.changeset/fix-mcp-404-handling.md

@@ -0,0 +1,5 @@
+---
+"claude-dev": patch
+---
+
+Fixed connection failures with remote MCP servers that return 404 instead of 405 for SSE stream checks. This was causing "Failed to open SSE stream: Not Found" errors after the v3.46.0 SDK upgrade.

+ 19 - 0
src/services/mcp/McpHub.ts

@@ -436,11 +436,30 @@ export class McpHub {
 					break
 				}
 				case "streamableHttp": {
+					// Custom fetch wrapper that treats 404 as 405 for GET requests.
+					// The MCP SDK sends a GET request to check for SSE stream support.
+					// Per MCP spec, servers should return 405 if they don't support SSE,
+					// but many servers (incorrectly) return 404. The SDK only handles 405
+					// gracefully, so we normalize 404 -> 405 to fix compatibility.
+					// See: https://github.com/modelcontextprotocol/typescript-sdk/issues/1150
+					const streamableHttpFetch: typeof fetch = async (url, init) => {
+						const response = await fetch(url, init)
+						if (init?.method === "GET" && response.status === 404) {
+							return new Response(response.body, {
+								status: 405,
+								statusText: "Method Not Allowed",
+								headers: response.headers,
+							})
+						}
+						return response
+					}
+
 					transport = new StreamableHTTPClientTransport(new URL(expandedConfig.url), {
 						authProvider,
 						requestInit: {
 							headers: expandedConfig.headers ?? undefined,
 						},
+						fetch: streamableHttpFetch,
 					})
 					transport.onerror = async (error) => {
 						console.error(`Transport error for "${name}":`, error)