modelcontextprotocol / modelcontextprotocol/typescript-sdk

Streamable HTTP: pre-existing hardening items from the #2547 review

Open
#2,562 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug P2 ready for work v1 v2
Dominant language
TypeScript
Stars
13.4k
Forks
2.2k
Avg merge
3d 15h
Merged PRs (30d)
4

Description

Three pre-existing Streamable HTTP transport items surfaced during the #2547 review that are independent of the keep-alive and delivery work there. Collecting them here so they don't get lost; each is small enough to fix individually.

  1. Protocol-version gate accepts unvalidated strings on initialize. The priming/resumability gate compares protocolVersion >= '2025-11-25' lexicographically, and for initialize requests the string comes verbatim from the request body without being checked against SUPPORTED_PROTOCOL_VERSIONS (non-initialize requests are header-validated). Unsupported strings that sort above the threshold (draft, 2026-01-01) enable priming events and the polling callbacks for the initialize stream even though the negotiated version in the response may be lower. Gate on the negotiated version instead.

  2. Concurrent DELETE requests can fire onsessionclosed twice. While the first DELETE is parked on the callback await, _closed is still false, so a second DELETE passes the guards and fires the callback again for the same session. A flag set before invoking the callback closes the window.

  3. The EventStore contract has no session scoping for the standalone stream. Every transport stores standalone server-initiated messages under the fixed id _GET_stream, so a store instance shared across sessions (module-level store in ssePollingExample, or any multi-node shared store) mixes sessions on standalone resume: one session's resume can replay another session's notifications. The contract needs a session dimension, or documented single-session store usage.

Applies to both main and v1.x.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the initialize protocol-version gate, the concurrent DELETE session-close path, and the EventStore standalone-stream contract described here, comparing both main and v1.x implementations. Review the related #2547 context and existing transport coverage; done means unsupported versions cannot enable features, concurrent DELETEs invoke onsessionclosed once, and shared stores keep sessions isolated or document single-session usage.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
backend-api-design, networking
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.