From d297272705950555ccfac1772fcd9ff30bc4a0a1 Mon Sep 17 00:00:00 2001 From: Xie Zhihao Date: Mon, 3 Nov 2025 23:12:28 +0800 Subject: [PATCH] mcp: relax SSE connection response handling in non-strict mode (#611) Some MCP servers do not support SSE, but when receiving a request, they return 400 Bad Request or 404 Not Found instead of the standard 405 Method Not Allowed. The TypeScript and Python SDK ignore this error, while the Go SDK terminates the session. This patch addresses the issue in the non-strict mode. Fixes #610 --------- Signed-off-by: Xie Zhihao --- mcp/streamable.go | 9 +++++---- mcp/streamable_client_test.go | 12 ++++++++++-- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/mcp/streamable.go b/mcp/streamable.go index 178b246..12e24ff 100644 --- a/mcp/streamable.go +++ b/mcp/streamable.go @@ -1377,13 +1377,14 @@ func (c *streamableClientConn) connectStandaloneSSE() { resp.Body.Close() return } - if resp.StatusCode == http.StatusNotFound && !c.strict { - // modelcontextprotocol/gosdk#393: some servers return NotFound instead - // of MethodNotAllowed for the standalone SSE stream. + if resp.StatusCode >= 400 && resp.StatusCode < 500 && !c.strict { + // modelcontextprotocol/go-sdk#393,#610: some servers return NotFound or + // other status codes instead of MethodNotAllowed for the standalone SSE + // stream. // // Treat this like MethodNotAllowed in non-strict mode. if c.logger != nil { - c.logger.Warn("got 404 instead of 405 for standalone SSE stream") + c.logger.Warn(fmt.Sprintf("got %d instead of 405 for standalone SSE stream", resp.StatusCode)) } resp.Body.Close() return diff --git a/mcp/streamable_client_test.go b/mcp/streamable_client_test.go index 42472c5..6d3d83b 100644 --- a/mcp/streamable_client_test.go +++ b/mcp/streamable_client_test.go @@ -239,7 +239,11 @@ func TestStreamableClientGETHandling(t *testing.T) { }{ {http.StatusOK, ""}, {http.StatusMethodNotAllowed, ""}, - {http.StatusBadRequest, "standalone SSE"}, + // The client error status code is not treated as an error in non-strict + // mode. + {http.StatusNotFound, ""}, + {http.StatusBadRequest, ""}, + {http.StatusInternalServerError, "standalone SSE"}, } for _, test := range tests { @@ -305,7 +309,11 @@ func TestStreamableClientStrictness(t *testing.T) { {"strict initialized", true, http.StatusOK, http.StatusMethodNotAllowed, true}, {"unstrict initialized", false, http.StatusOK, http.StatusMethodNotAllowed, false}, {"strict GET", true, http.StatusAccepted, http.StatusNotFound, true}, - {"unstrict GET", false, http.StatusOK, http.StatusNotFound, false}, + // The client error status code is not treated as an error in non-strict + // mode. + {"unstrict GET on StatusNotFound", false, http.StatusOK, http.StatusNotFound, false}, + {"unstrict GET on StatusBadRequest", false, http.StatusOK, http.StatusBadRequest, false}, + {"GET on InternlServerError", false, http.StatusOK, http.StatusInternalServerError, true}, } for _, test := range tests { t.Run(test.label, func(t *testing.T) {