Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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
5 changes: 5 additions & 0 deletions .changeset/fix-sse-disconnect-noise.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@modelcontextprotocol/client': patch
---

Suppress `onerror` when an SSE stream disconnects but reconnection will be scheduled. Previously `onerror` fired unconditionally on every stream disconnect, producing `"SSE stream disconnected: TypeError: terminated"` noise every few minutes on long-lived connections even though the transport recovered transparently.
6 changes: 3 additions & 3 deletions packages/client/src/client/streamableHttp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -445,9 +445,6 @@ export class StreamableHTTPClientTransport implements Transport {
);
}
} catch (error) {
// Handle stream errors - likely a network disconnect
this.onerror?.(new Error(`SSE stream disconnected: ${error}`));

// Attempt to reconnect if the stream disconnects unexpectedly and we aren't closing
// Reconnect if: already reconnectable (GET stream) OR received a priming event (POST stream with event ID)
// BUT don't reconnect if we already received a response - the request is complete
Comment thread
claude[bot] marked this conversation as resolved.
Expand All @@ -467,6 +464,9 @@ export class StreamableHTTPClientTransport implements Transport {
} catch (error) {
this.onerror?.(new Error(`Failed to reconnect: ${error instanceof Error ? error.message : String(error)}`));
}
} else {
// Stream disconnected and reconnection will not happen; surface the error
this.onerror?.(new Error(`SSE stream disconnected: ${error}`));
Comment thread
claude[bot] marked this conversation as resolved.
Outdated
}
}
};
Expand Down
9 changes: 3 additions & 6 deletions packages/client/test/client/streamableHttp.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -832,12 +832,9 @@ describe('StreamableHTTPClientTransport', () => {
await vi.advanceTimersByTimeAsync(20); // Trigger reconnection timeout

// ASSERT
expect(errorSpy).toHaveBeenCalledWith(
expect.objectContaining({
message: expect.stringContaining('SSE stream disconnected: Error: Network failure')
})
);
// THE KEY ASSERTION: A second fetch call proves reconnection was attempted.
// onerror is NOT called: reconnection will handle the disconnect transparently
expect(errorSpy).not.toHaveBeenCalled();
// A second fetch call proves reconnection was attempted.
expect(fetchMock).toHaveBeenCalledTimes(2);
expect(fetchMock.mock.calls[0]![1]?.method).toBe('GET');
expect(fetchMock.mock.calls[1]![1]?.method).toBe('GET');
Expand Down
Loading