modelcontextprotocol / modelcontextprotocol/typescript-sdk
Streamable HTTP: close replayed request streams once no in-flight requests remain
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 13.4k
- Forks
- 2.2k
- Avg merge
- 3d 15h
- Merged PRs (30d)
- 4
Description
When a client resumes a request stream with Last-Event-ID, the replayed stream stays open indefinitely (keep-alive now keeps it healthy) even when every correlated response has already been delivered or stored.
Three narrow races follow from this:
- A response that becomes store-visible while a resume is mid-flight is missed by that replay's snapshot and never delivered to the now-permanent successor.
- A superseded successor's dedup state does not transfer, so a double reconnect during an in-flight store write can double-deliver a response.
- A stream resumed after
closeSSEStreampolling delivers the replayed response but never ends.
Closing a replayed request stream after replay whenever no in-flight requests map to it turns the polling loop into one that converges: the client re-polls until a replay snapshot includes the response.
Applies to both main and v1.x (the send()/replay code has the same shape in both). Split out from the review discussion on #2547.
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.
Research direction
Start with the send()/replay code for Streamable HTTP in both the main and v1.x implementations, and trace how closeSSEStream polling handles resumed streams. Verify the three replay races and ensure a replayed request stream closes after replay when no in-flight requests map to it. Done means polling converges without missed or duplicate responses and the replayed stream ends.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- api
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100