Title: fix(streamable-http): reject duplicate in-flight request ids by Sammy-Dabbas · Pull Request #3063 · modelcontextprotocol/python-sdk · GitHub
Open Graph Title: fix(streamable-http): reject duplicate in-flight request ids by Sammy-Dabbas · Pull Request #3063 · modelcontextprotocol/python-sdk
X Title: fix(streamable-http): reject duplicate in-flight request ids by Sammy-Dabbas · Pull Request #3063 · modelcontextprotocol/python-sdk
Description: Fixes #3060. The stateful streamable HTTP transport keys per-request routing by the request id and assigns the slot without an existence check. Two concurrent POSTs sharing an id cross-wire: the second overwrites the first's routing slot, the first request's response is delivered to the second POST, and the first hangs while its stream leaks. Reproduced on main before the fix. This adds a guard in _handle_post_request that rejects a POST whose request id is already in flight on the session with HTTP 400 and JSON-RPC -32600, placed before the JSON/SSE branch so both response modes are covered. The spec requires request ids to be unique within a session. Sequential reuse of an id after the earlier request completes still works, since deployed clients send a constant id for every request; a regression test pins that behavior. Tests: the new duplicate-id test fails on unpatched main and passes with the fix. tests/shared/test_streamable_http.py passes 67/67 and the full suite passes locally (5282 passed). A stress run of 500 rapid sequential same-id requests produced no spurious rejections. ruff and pyright are clean on the touched files. Scope note: this is the transport-level guard only. The dispatcher-level blind overwrite in jsonrpc_dispatcher.py (TODO from #3046) is deliberately left to the follow-up discussed on the issue, since the two guards compose. Disclosure: this change was developed with AI assistance (Claude Code). I reviewed the change and the test results before submitting.
Open Graph Description: Fixes #3060. The stateful streamable HTTP transport keys per-request routing by the request id and assigns the slot without an existence check. Two concurrent POSTs sharing an id cross-wire: the se...
X Description: Fixes #3060. The stateful streamable HTTP transport keys per-request routing by the request id and assigns the slot without an existence check. Two concurrent POSTs sharing an id cross-wire: the se...
Opengraph URL: https://github.com/modelcontextprotocol/python-sdk/pull/3063
X: @github
Domain: github.com
| route-pattern | /:user_id/:repository/pull/:id/files(.:format) |
| route-controller | pull_requests |
| route-action | files |
| fetch-nonce | v2:c037df62-3ec9-f20e-bd9d-f68e11227a6b |
| current-catalog-service-hash | ae870bc5e265a340912cde392f23dad3671a0a881730ffdadd82f2f57d81641b |
| request-id | D642:1B5602:3DA9C0F:50E28C9:6A5D35F3 |
| html-safe-nonce | 87e4864cf0e063db87254db60800030bd0e28accb83d9f899559b240b0cca22a |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJENjQyOjFCNTYwMjozREE5QzBGOjUwRTI4Qzk6NkE1RDM1RjMiLCJ2aXNpdG9yX2lkIjoiNjAzMzY0ODczMDEyMTI1NDM4NyIsInJlZ2lvbl9lZGdlIjoiaWFkIiwicmVnaW9uX3JlbmRlciI6ImlhZCJ9 |
| visitor-hmac | 4958b9c7c8db0b2660ac09105cb4cfb873fc6468404c83873dee9afd4072a3ee |
| hovercard-subject-tag | pull_request:3989592161 |
| github-keyboard-shortcuts | repository,pull-request-list,pull-request-conversation,pull-request-files-changed,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/modelcontextprotocol/python-sdk/pull/3063/files |
| twitter:image | https://avatars.githubusercontent.com/u/108543652?s=400&v=4 |
| twitter:card | summary_large_image |
| og:image | https://avatars.githubusercontent.com/u/108543652?s=400&v=4 |
| og:image:alt | Fixes #3060. The stateful streamable HTTP transport keys per-request routing by the request id and assigns the slot without an existence check. Two concurrent POSTs sharing an id cross-wire: the se... |
| og:site_name | GitHub |
| og:type | object |
| hostname | github.com |
| expected-hostname | github.com |
| None | 5290d7e14309ad1e76106a9c4237bd1041517e83ea182c8ab756752cb0c6940b |
| turbo-cache-control | no-preview |
| diff-view | unified |
| go-import | github.com/modelcontextprotocol/python-sdk git https://github.com/modelcontextprotocol/python-sdk.git |
| octolytics-dimension-user_id | 182288589 |
| octolytics-dimension-user_login | modelcontextprotocol |
| octolytics-dimension-repository_id | 862584018 |
| octolytics-dimension-repository_nwo | modelcontextprotocol/python-sdk |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 862584018 |
| octolytics-dimension-repository_network_root_nwo | modelcontextprotocol/python-sdk |
| turbo-body-classes | logged-out env-production page-responsive full-width |
| disable-turbo | true |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | 9c975978430e9ad293956f2bbdaf153b1bd84a99 |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width