Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion mcp/streamable.go
Original file line number Diff line number Diff line change
Expand Up @@ -2288,6 +2288,10 @@ func (t *StreamableClientTransport) Connect(ctx context.Context) (Connection, er
} else if maxRetries < 0 {
maxRetries = 0
}
maxEventSize := t.MaxEventSize
if maxEventSize == 0 {
maxEventSize = DefaultMaxEventSize
}
// Create a new cancellable context that will manage the connection's lifecycle.
// This is crucial for cleanly shutting down the background SSE listener by
// cancelling its blocking network operations, which prevents hangs on exit.
Expand Down Expand Up @@ -2318,7 +2322,7 @@ func (t *StreamableClientTransport) Connect(ctx context.Context) (Connection, er
failed: make(chan struct{}),
disableStandaloneSSE: t.DisableStandaloneSSE,
oauthHandler: t.OAuthHandler,
maxEventSize: t.MaxEventSize,
maxEventSize: maxEventSize,
}
return conn, nil
}
Expand Down
30 changes: 30 additions & 0 deletions mcp/streamable_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3012,6 +3012,36 @@ func TestProcessStreamMaxEventSize(t *testing.T) {
}
}

// TestStreamableClientDefaultMaxEventSize verifies that a zero
// StreamableClientTransport.MaxEventSize applies DefaultMaxEventSize rather
// than disabling the cap.
func TestStreamableClientDefaultMaxEventSize(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
w.WriteHeader(http.StatusMethodNotAllowed)
return
}
w.Header().Set("Content-Type", "text/event-stream")
w.Header().Set("Mcp-Session-Id", "session")
io.WriteString(w, "event: message\ndata: ")
chunk := strings.Repeat("A", 1<<20)
for range 2 * DefaultMaxEventSize / len(chunk) {
if _, err := io.WriteString(w, chunk); err != nil {
return
}
}
}))
defer srv.Close()

client := NewClient(testImpl, nil)
transport := &StreamableClientTransport{Endpoint: srv.URL, DisableStandaloneSSE: true}
_, err := client.Connect(t.Context(), transport, nil)
want := fmt.Sprintf("SSE event exceeded %d bytes", DefaultMaxEventSize)
if err == nil || !strings.Contains(err.Error(), want) {
t.Fatalf("Connect() error = %v, want an error containing %q", err, want)
}
}

// TestScanEventsPingFiltering is a unit test for the low-level event scanning
// with ping events to verify scanEvents properly parses all event types.
func TestScanEventsPingFiltering(t *testing.T) {
Expand Down
Loading