Skip to content

Commit d77ab00

Browse files
fix: accept HTTP 204 No Content in SendNotification
HTTP 204 is a valid success status code per RFC 7231, commonly returned by servers for notification endpoints where no response body is expected. The client previously only accepted 200 and 202, causing initialization to fail when connecting to servers that return 204 for the initialized notification. Refactored the status code handling to a switch statement for clarity. Fixes #700 Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 859588d commit d77ab00

File tree

2 files changed

+39
-11
lines changed

2 files changed

+39
-11
lines changed

client/transport/streamable_http.go

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -573,26 +573,24 @@ func (c *StreamableHTTP) SendNotification(ctx context.Context, notification mcp.
573573
}
574574
defer resp.Body.Close()
575575

576-
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusAccepted {
577-
// Handle unauthorized error
578-
if resp.StatusCode == http.StatusUnauthorized {
579-
if c.oauthHandler != nil {
580-
return &OAuthAuthorizationRequiredError{
581-
Handler: c.oauthHandler,
582-
}
576+
switch resp.StatusCode {
577+
case http.StatusOK, http.StatusAccepted, http.StatusNoContent:
578+
return nil
579+
case http.StatusUnauthorized:
580+
if c.oauthHandler != nil {
581+
return &OAuthAuthorizationRequiredError{
582+
Handler: c.oauthHandler,
583583
}
584-
return ErrUnauthorized
585584
}
586-
585+
return ErrUnauthorized
586+
default:
587587
body, _ := io.ReadAll(resp.Body)
588588
return fmt.Errorf(
589589
"notification failed with status %d: %s",
590590
resp.StatusCode,
591591
body,
592592
)
593593
}
594-
595-
return nil
596594
}
597595

598596
func (c *StreamableHTTP) SetNotificationHandler(handler func(mcp.JSONRPCNotification)) {

client/transport/streamable_http_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -988,6 +988,36 @@ func TestStreamableHTTP_SendNotification_Unauthorized_StaticToken(t *testing.T)
988988
}
989989
}
990990

991+
// TestStreamableHTTP_SendNotification_Accepts204NoContent verifies that SendNotification
992+
// treats HTTP 204 No Content as a success response per RFC 7231.
993+
// See: https://github.com/mark3labs/mcp-go/issues/700
994+
func TestStreamableHTTP_SendNotification_Accepts204NoContent(t *testing.T) {
995+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
996+
w.WriteHeader(http.StatusNoContent)
997+
}))
998+
defer server.Close()
999+
1000+
transport, err := NewStreamableHTTP(server.URL)
1001+
if err != nil {
1002+
t.Fatalf("Failed to create StreamableHTTP: %v", err)
1003+
}
1004+
1005+
if err := transport.Start(context.Background()); err != nil {
1006+
t.Fatalf("Failed to start transport: %v", err)
1007+
}
1008+
1009+
err = transport.SendNotification(context.Background(), mcp.JSONRPCNotification{
1010+
JSONRPC: "2.0",
1011+
Notification: mcp.Notification{
1012+
Method: "notifications/initialized",
1013+
},
1014+
})
1015+
1016+
if err != nil {
1017+
t.Fatalf("SendNotification should accept 204 No Content, got error: %v", err)
1018+
}
1019+
}
1020+
9911021
// TestStreamableHTTPHostOverride tests Host header override for StreamableHTTP transport
9921022
func TestStreamableHTTPHostOverride(t *testing.T) {
9931023
// Create a test server that captures the Host header

0 commit comments

Comments
 (0)