Skip to content

fix(client): allow transport restart after close()#1828

Open
felixweinberger wants to merge 1 commit intomainfrom
fweinberger/fix-transport-restart
Open

fix(client): allow transport restart after close()#1828
felixweinberger wants to merge 1 commit intomainfrom
fweinberger/fix-transport-restart

Conversation

@felixweinberger
Copy link
Copy Markdown
Contributor

Allows StreamableHTTPClientTransport and SSEClientTransport to restart after close().

Motivation and Context

Fixes #1641. start() throws "already started" after close() because the start guard checks whether _abortController exists, not whether it was aborted. This breaks OAuth re-authentication flows: start → 401 → close → OAuth → start (throws).

StreamableHTTPClientTransport: Changed the start() guard from if (this._abortController) to if (this._abortController && !this._abortController.signal.aborted). This is safer than clearing _abortController in close(), which would break the signal.aborted checks at :344, :437, :456 used by late-firing reconnection callbacks. Also clears _sessionId in close() so the stale server-assigned ID is not sent on post-restart requests (would 404).

SSEClientTransport: Clears _eventSource, _endpoint, _abortController in close(). SSE's start guard checks _eventSource, and there are no signal.aborted dependencies.

How Has This Been Tested?

Added a test that receives a session ID, closes, restarts, and asserts both start() succeeds and the stale session ID is not sent. Test fails on main (expected 'stale-session-abc' to be undefined), passes with the fix. All 347 client tests pass.

Breaking Changes

None.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

Credit to @matantsach for #1647 which identified the issue and the SSE state-reset approach.

StreamableHTTPClientTransport: change start() guard from 'controller exists'
to 'controller exists and not aborted', allowing restart after close(). Also
clear _sessionId in close() so the stale server-assigned ID is not sent on
post-restart requests.

SSEClientTransport: clear _eventSource, _endpoint, _abortController in close()
so start()'s guard allows restart.

Fixes #1641
@felixweinberger felixweinberger requested a review from a team as a code owner March 31, 2026 13:33
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Mar 31, 2026

🦋 Changeset detected

Latest commit: db137d9

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

This PR includes changesets to release 1 package
Name Type
@modelcontextprotocol/client 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
Copy link
Copy Markdown

pkg-pr-new bot commented Mar 31, 2026

Open in StackBlitz

@modelcontextprotocol/client

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/client@1828

@modelcontextprotocol/server

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/server@1828

@modelcontextprotocol/express

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/express@1828

@modelcontextprotocol/hono

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/hono@1828

@modelcontextprotocol/node

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/node@1828

commit: db137d9

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.

StreamableHTTPClientTransport cannot be restarted after close() — breaks OAuth re-authentication

1 participant