mcp: fix connectStandaloneSSE checking Content-Type header (#736)
Issue encountered: the MCP server request was unexpectedly redirected to an HTML page. Because the client didn’t validate the response Content-Type, it still entered handleSSE, which then kept treating the HTML as an SSE stream and repeatedly re-requesting the same page—creating an infinite request loop.
This commit is contained in:
parent
9c4d349ec0
commit
e66c23fae4
2 changed files with 19 additions and 8 deletions
|
|
@ -1555,6 +1555,14 @@ func (c *streamableClientConn) connectStandaloneSSE() {
|
|||
resp.Body.Close()
|
||||
return
|
||||
}
|
||||
if resp.Header.Get("Content-Type") != "text/event-stream" {
|
||||
// modelcontextprotocol/go-sdk#736: some servers return 200 OK or redirect with
|
||||
// non-SSE content type instead of text/event-stream for the standalone
|
||||
// SSE stream.
|
||||
c.logger.Warn(fmt.Sprintf("got Content-Type %s instead of text/event-stream for standalone SSE stream", resp.Header.Get("Content-Type")))
|
||||
resp.Body.Close()
|
||||
return
|
||||
}
|
||||
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
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
|
||||
"github.com/modelcontextprotocol/go-sdk/internal/jsonrpc2"
|
||||
"github.com/modelcontextprotocol/go-sdk/jsonrpc"
|
||||
)
|
||||
|
|
@ -258,14 +259,16 @@ func TestStreamableClientGETHandling(t *testing.T) {
|
|||
tests := []struct {
|
||||
status int
|
||||
wantErrorContaining string
|
||||
contentType string
|
||||
}{
|
||||
{http.StatusOK, ""},
|
||||
{http.StatusMethodNotAllowed, ""},
|
||||
// The client error status code is not treated as an error in non-strict
|
||||
// mode.
|
||||
{http.StatusNotFound, ""},
|
||||
{http.StatusBadRequest, ""},
|
||||
{http.StatusInternalServerError, "standalone SSE"},
|
||||
{http.StatusOK, "", "text/event-stream"},
|
||||
{http.StatusMethodNotAllowed, "", "text/event-stream"},
|
||||
//// The client error status code is not treated as an error in non-strict
|
||||
//// mode.
|
||||
{http.StatusNotFound, "", "text/event-stream"},
|
||||
{http.StatusBadRequest, "", "text/event-stream"},
|
||||
{http.StatusInternalServerError, "standalone SSE", "text/event-stream"},
|
||||
{http.StatusOK, "", "text/html; charset=utf-8"},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
|
@ -286,7 +289,7 @@ func TestStreamableClientGETHandling(t *testing.T) {
|
|||
},
|
||||
{"GET", "123", "", ""}: {
|
||||
header: header{
|
||||
"Content-Type": "text/event-stream",
|
||||
"Content-Type": test.contentType,
|
||||
},
|
||||
status: test.status,
|
||||
wantProtocolVersion: latestProtocolVersion,
|
||||
|
|
|
|||
Loading…
Reference in a new issue