StreamableHTTPClientTransport cannot be restarted after close() — breaks OAuth re-authentication
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 72/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Quiet
- Tech stack
- typescript
- Domain
- api, authentication
Research direction
Start in src/client/streamableHttp.ts at StreamableHTTPClientTransport.start() and close(), then trace the _abortController lifecycle. Done when closing leaves the transport restartable and the OAuth re-authentication sequence can call start() without the already-started error.
Written by the indexing model from the issue text.
Description
Bug Description
StreamableHTTPClientTransport.start() throws "StreamableHTTPClientTransport already started!" if called after close(), because close() aborts the _abortController but never resets it to undefined.
This breaks any flow that needs to reconnect after OAuth authentication, because:
transport.start()is called → setsthis._abortController- Server returns 401 → OAuth flow begins
transport.close()is called → aborts_abortControllerbut does NOT set it toundefined- After OAuth completes,
transport.start()is called again - The guard at line 257 checks
if (this._abortController)→ still truthy → throws
Reproduction
Any MCP client that uses StreamableHTTPClientTransport with an OAuth auth provider hitting a server that requires authentication will fail on the first connection attempt. The token is saved successfully, but the transport cannot be restarted in the same process.
This is observable with tools like mcporter when connecting to an OAuth-protected MCP server for the first time.
Root Cause
In src/client/streamableHttp.ts, the close() method aborts the controller but doesn't clear the reference:
async close(): Promise<void> {
// ...
this._abortController?.abort(); // aborts but keeps reference
this.onclose?.();
}
While start() guards against re-entry by checking if _abortController exists:
async start(): Promise<void> {
if (this._abortController) {
throw new Error('StreamableHTTPClientTransport already started!...');
}
this._abortController = new AbortController();
}
Suggested Fix
Reset _abortController to undefined in close():
async close(): Promise<void> {
// ...
this._abortController?.abort();
this._abortController = undefined;
this.onclose?.();
}
This allows the transport to be restarted after being closed, which is the expected lifecycle for OAuth re-authentication flows.
Environment
@modelcontextprotocol/sdk: 1.27.1- Runtime: Node.js
- Transport: StreamableHTTPClientTransport
- Dominant language
- TypeScript
- Stars
- 13.4k
- Forks
- 2.2k
- Avg merge
- 3d 12h
- Merged PRs (30d)
- 3
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from modelcontextprotocol/typescript-sdk
-
Auth metadata discovery: fallback URL built on resource host instead of authorization-server host Open
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
modelcontextprotocol/typescript-sdk#2783 · 1 comment ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
-
Difficulty 1/5 Under an hour Newbie friendliness 92/100
modelcontextprotocol/typescript-sdk#2766 · 1 comment ·
-
Difficulty 2/5 1-2 days Newbie friendliness 72/100
All issues in modelcontextprotocol/typescript-sdk
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
Eynzof/Hermes-CN-Desktop#610 ·
-
bug clawsweeper:linked-pr-open clawsweeper:needs-live-repro clawsweeper:no-new-fix-pr impact:message-loss issue-rating: 🐚 platinum hermit P2 regression
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
-
enhancement
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
-
calcite-components needs triage refactor
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
Esri/calcite-design-system#15203 ·
-
Difficulty 1/5 Under an hour Newbie friendliness 78/100
fullcalendar/fullcalendar#8106 ·