Skip to content

fix(client): preserve resumption token when a resumed SSE stream drops before any id-bearing event - #2745

Open
ayush00git wants to merge 1 commit into
modelcontextprotocol:mainfrom
ayush00git:fix/preserve-resumption-token-on-reconnect
Open

fix(client): preserve resumption token when a resumed SSE stream drops before any id-bearing event#2745
ayush00git wants to merge 1 commit into
modelcontextprotocol:mainfrom
ayush00git:fix/preserve-resumption-token-on-reconnect

Conversation

@ayush00git

Copy link
Copy Markdown

Fixes #2499

What the error was

In StreamableHTTPClientTransport, _handleSseStream() keeps track of the latest SSE event id in a local lastEventId that starts out as undefined. It was never seeded from the resumptionToken the stream was opened with, but both reconnect paths (graceful close and network error) pass that local along as the token for the next attempt.

So if a stream resumed with Last-Event-ID: e1 got cut again before the server replayed any id-bearing event (load balancer idle timeout, server restart), the reconnect GET went out with no Last-Event-ID header at all. The server saw a brand-new stream, the missed events were never replayed, and a long-running request just hung until it timed out.

How this PR fixes it

lastEventId is now initialised from options.resumptionToken. A reconnect that saw no new events re-sends the same cursor, which is safe because replay from an already-seen id is idempotent. Once a newer event id arrives it overrides the seed as before. onresumptiontoken behaviour is unchanged: it still only fires for ids actually received on the wire, not for the seed.

Added three regression tests under Reconnection Logic:

  • resumed stream closes gracefully before any event → reconnect carries the same Last-Event-ID
  • resumed stream errors before any event → same
  • a newer id arrives → reconnect uses the newer id and the seed is not re-announced via onresumptiontoken

The first two fail on main and pass with this change. Also added a patch changeset for @modelcontextprotocol/client.

…s before any id-bearing event

Seed _handleSseStream's lastEventId tracker from the resumptionToken the
stream was opened with, so a reconnect that saw no new events re-sends the
same Last-Event-ID instead of dropping it.

Fixes modelcontextprotocol#2499
@ayush00git
ayush00git requested a review from a team as a code owner September 2, 2026 08:45
@changeset-bot

changeset-bot Bot commented Sep 2, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: e01c0ae

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 6 packages
Name Type
@modelcontextprotocol/client Patch
@modelcontextprotocol/codemod Patch
@modelcontextprotocol/core Patch
@modelcontextprotocol/server-legacy Patch
@modelcontextprotocol/server Patch
@modelcontextprotocol/core-internal Patch

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

@pkg-pr-new

pkg-pr-new Bot commented Sep 2, 2026

Copy link
Copy Markdown

Open in StackBlitz

@modelcontextprotocol/client

npm i https://pkg.pr.new/@modelcontextprotocol/client@2745

@modelcontextprotocol/codemod

npm i https://pkg.pr.new/@modelcontextprotocol/codemod@2745

@modelcontextprotocol/core

npm i https://pkg.pr.new/@modelcontextprotocol/core@2745

@modelcontextprotocol/server

npm i https://pkg.pr.new/@modelcontextprotocol/server@2745

@modelcontextprotocol/server-legacy

npm i https://pkg.pr.new/@modelcontextprotocol/server-legacy@2745

@modelcontextprotocol/express

npm i https://pkg.pr.new/@modelcontextprotocol/express@2745

@modelcontextprotocol/fastify

npm i https://pkg.pr.new/@modelcontextprotocol/fastify@2745

@modelcontextprotocol/hono

npm i https://pkg.pr.new/@modelcontextprotocol/hono@2745

@modelcontextprotocol/node

npm i https://pkg.pr.new/@modelcontextprotocol/node@2745

commit: e01c0ae

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: Resumption token dropped when a resumed SSE stream disconnects before any id-bearing event

1 participant