Fix off-by-one error in reconnection attempts#1356
Merged
stephentoub merged 4 commits intomainfrom Feb 23, 2026
Merged
Conversation
…n loop When ReceiveUnsolicitedMessagesAsync calls SendGetSseRequestWithRetriesAsync, the first attempt is an initial GET SSE connection (not a reconnection). Previously, this initial attempt was counted against MaxReconnectionAttempts, meaning with the default value of 2, only 1 actual reconnection was made. Fix: initialize attempt = -1 when LastEventId is null (initial connection), so the initial attempt doesn't consume a reconnection slot. When LastEventId is set (pure reconnection from POST SSE resume), attempt starts at 0 as before. Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
…axReconnectionAttempts Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
Contributor
|
@copilot there are build failures |
…ic TaskCompletionSource Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
Contributor
Author
stephentoub
approved these changes
Feb 22, 2026
jeffhandley
approved these changes
Feb 23, 2026
Contributor
There was a problem hiding this comment.
Pull request overview
This pull request fixes an off-by-one error in the SSE (Server-Sent Events) reconnection retry logic for the Streamable HTTP client transport. The bug caused the initial GET SSE connection to be incorrectly counted as a reconnection attempt, effectively reducing the configured MaxReconnectionAttempts by one.
Changes:
- Fixed the retry counter initialization to distinguish initial connections from reconnections
- Added comprehensive test coverage to verify the fix
- Ensured .NET Framework compatibility using generic
TaskCompletionSource<bool>
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
src/ModelContextProtocol.Core/Client/StreamableHttpClientSessionTransport.cs |
Fixed off-by-one error by initializing attempt = -1 for initial connections (when LastEventId is null) and attempt = 0 for reconnections (when LastEventId is set), with clear inline comments explaining the logic |
tests/ModelContextProtocol.Tests/Transport/HttpClientTransportTests.cs |
Added test StreamableHttp_InitialGetSseConnection_DoesNotCountAgainstMaxReconnectionAttempts that verifies the initial connection plus configured reconnection attempts equals the total number of GET requests, and added System.Text import for test setup |
MackinnonBuck
approved these changes
Feb 23, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
SendGetSseRequestWithRetriesAsyncretry loopattempt = -1whenstate.LastEventIdis null (initial connection case inReceiveUnsolicitedMessagesAsync)TaskCompletionSource<bool>instead of non-genericTaskCompletionSource💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.