mcp: fix SSEClientTransport to report HTTP errors properly (#740)

Fix SSEClientTransport.Connect to check HTTP status code before attempting to parse SSE events.

Fixes #714
This commit is contained in:
ZAIN ULHASSAN 2026-01-01 01:16:20 +09:00 • committed by GitHub
commit 27b3354f80
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 63 additions and 0 deletions

View file

@ -351,6 +351,14 @@ func (c *SSEClientTransport) Connect(ctx context.Context) (Connection, error) {
return nil, err
}
// Check HTTP status code before attempting to parse SSE events.
// This ensures proper error reporting for authentication failures (401),
// authorization failures (403), and other HTTP errors.
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
resp.Body.Close()
return nil, fmt.Errorf("failed to connect: %s", http.StatusText(resp.StatusCode))
}
msgEndpoint, err := func() (*url.URL, error) {
var evt Event
for evt, err = range scanEvents(resp.Body) {

View file

@ -131,3 +131,58 @@ type roundTripperFunc func(*http.Request) (*http.Response, error)
func (f roundTripperFunc) RoundTrip(req *http.Request) (*http.Response, error) {
return f(req)
}
func TestSSEClientTransport_HTTPErrors(t *testing.T) {
tests := []struct {
name string
statusCode int
wantErrContain string
}{
{
name: "401 Unauthorized",
statusCode: http.StatusUnauthorized,
wantErrContain: "Unauthorized",
},
{
name: "403 Forbidden",
statusCode: http.StatusForbidden,
wantErrContain: "Forbidden",
},
{
name: "404 Not Found",
statusCode: http.StatusNotFound,
wantErrContain: "Not Found",
},
{
name: "500 Internal Server Error",
statusCode: http.StatusInternalServerError,
wantErrContain: "Internal Server Error",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Create a test server that returns the specified status code
httpServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
http.Error(w, http.StatusText(tt.statusCode), tt.statusCode)
}))
defer httpServer.Close()
clientTransport := &SSEClientTransport{
Endpoint: httpServer.URL,
}
c := NewClient(testImpl, nil)
_, err := c.Connect(context.Background(), clientTransport, nil)
if err == nil {
t.Fatalf("expected error, got nil")
}
errStr := err.Error()
if !bytes.Contains([]byte(errStr), []byte(tt.wantErrContain)) {
t.Errorf("error message %q does not contain %q", errStr, tt.wantErrContain)
}
})
}
}