fix(client): thread onresumptiontoken and onRequestStreamEnd through the send() resume path#2519
Open
lntutor wants to merge 1 commit into
Open
fix(client): thread onresumptiontoken and onRequestStreamEnd through the send() resume path#2519lntutor wants to merge 1 commit into
lntutor wants to merge 1 commit into
Conversation
…the send() resume path The resumptionToken branch of StreamableHTTPClientTransport._send() reopened the SSE stream with the right Last-Event-ID but passed neither onresumptiontoken nor onRequestStreamEnd to _startOrAuthSse(), while the original POST path and resumeStream() both thread them. A caller resuming a long-running request therefore never saw newer resumption tokens (its persisted token went stale, causing replayed or lost events on the next resume) and never learned when the stream ended non-resumably. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N6RtoHuxrDqTUo9Mw9h4Cv
🦋 Changeset detectedLatest commit: 713c448 The changes in this PR will be included in the next version bump. This PR includes changesets to release 6 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
@modelcontextprotocol/client
@modelcontextprotocol/codemod
@modelcontextprotocol/core
@modelcontextprotocol/server
@modelcontextprotocol/server-legacy
@modelcontextprotocol/express
@modelcontextprotocol/fastify
@modelcontextprotocol/hono
@modelcontextprotocol/node
commit: |
This was referenced Jul 19, 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.
What's broken
When
send()is called with aresumptionToken(the documented flow for resuming a long-running request after a disconnect), the resume branch reopens the SSE stream with the correctLast-Event-ID— but forwards neitheronresumptiontokennoronRequestStreamEndto_startOrAuthSse():Both callbacks arrive in the same
optionsobject (Protocolforwards{ resumptionToken, onresumptiontoken, requestSignal }on everytransport.send), and the original POST path threads both (_send, further down), as doesresumeStream()for the identical stream. The comment above the resume branch showsrequestSignalwas threaded deliberately; the two callbacks sitting next to it were overlooked.Observable failure
For the rest of a resumed request's life — including all of its internal reconnects, which rebuild options from
StartSSEOptions— the caller'sonresumptiontokennever fires again. The host's persisted token goes permanently stale, so a later resume replays already-delivered events (duplicate responses/side effects) or falls outside the server event store's retention window entirely.onRequestStreamEndis dropped on the same line, so a resumed per-request stream that dies non-resumably never notifies the caller.Related but distinct from #2499 / #2509: that fix seeds
_handleSseStream's internallastEventIdtracker from the token; this one is about the caller-facing callbacks never being attached on thesend()resume path at all. Even with #2509 merged, the callback still never fires here.Fix
Thread
onresumptiontokenandonRequestStreamEndthrough the resume branch's_startOrAuthSse()call, matching the POST path andresumeStream().Tests
New test in
packages/client/test/client/streamableHttp.test.ts: resumes viasend(..., { resumptionToken, onresumptiontoken, onRequestStreamEnd })against a mocked GET SSE stream that delivers one id-bearing event and ends non-resumably (maxRetries: 0). Before the fix the GET goes out with the rightLast-Event-IDbut neither callback ever fires; after the fix both do. Full@modelcontextprotocol/clientsuite passes (749 tests), typecheck and lint clean. Changeset included (patch).🤖 Generated with Claude Code
https://claude.ai/code/session_01N6RtoHuxrDqTUo9Mw9h4Cv