Title: streamable_http_client: one concurrent request HTTPStatusError tears down sibling requests · Issue #2604 · modelcontextprotocol/python-sdk · GitHub
Open Graph Title: streamable_http_client: one concurrent request HTTPStatusError tears down sibling requests · Issue #2604 · modelcontextprotocol/python-sdk
X Title: streamable_http_client: one concurrent request HTTPStatusError tears down sibling requests · Issue #2604 · modelcontextprotocol/python-sdk
Description: Initial Checks I confirm that I'm using the latest version of MCP Python SDK I confirm that I searched for my issue in https://github.com/modelcontextprotocol/python-sdk/issues before opening this issue Description When using streamable_...
Open Graph Description: Initial Checks I confirm that I'm using the latest version of MCP Python SDK I confirm that I searched for my issue in https://github.com/modelcontextprotocol/python-sdk/issues before opening this ...
X Description: Initial Checks I confirm that I'm using the latest version of MCP Python SDK I confirm that I searched for my issue in https://github.com/modelcontextprotocol/python-sdk/issues before opening t...
Opengraph URL: https://github.com/modelcontextprotocol/python-sdk/issues/2604
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"streamable_http_client: one concurrent request HTTPStatusError tears down sibling requests","articleBody":"### Initial Checks\n\n- [x] I confirm that I'm using the latest version of MCP Python SDK\n- [x] I confirm that I searched for my issue in https://github.com/modelcontextprotocol/python-sdk/issues before opening this issue\n\n### Description\n\nWhen using `streamable_http_client` with concurrent JSON-RPC requests over the same Streamable HTTP session, an HTTP error from one request can escape the transport task group and disrupt unrelated sibling requests that are still waiting for their responses.\n\nThis happens because `post_writer()` starts each JSON-RPC request as a task: `tg.start_soon(handle_request_async)` and `_handle_post_request()` calls: `response.raise_for_status()`\n\nIf one concurrent request receives a non-2xx HTTP response, e.g. 400 Bad Request, the resulting `httpx.HTTPStatusError` escapes from that per-request task into the shared task group. The task group then exits with:\n`ExceptionGroup: unhandled errors in a TaskGroup` (1 sub-exception)\n\nAt the same time, sibling requests that were still waiting in `ClientSession.send_request()` can be cancelled/disrupted. In our production traces, the sibling request stack showed:\n\n```\nFile \".../mcp/shared/session.py\", line 292, in send_request\n response_or_error = await response_stream_reader.receive()\n\nFile \".../anyio/streams/memory.py\", line 117, in receive\n return self.receive_nowait()\n\nFile \".../anyio/streams/memory.py\", line 112, in receive_nowait\n raise WouldBlock\n\nanyio.WouldBlock\n```\nThe `WouldBlock` is not the root cause by itself; it appears because the sibling request was waiting for a response when the transport/session was torn down by the other request's HTTP error.\n\n#### Expected Behavior\nA non-2xx HTTP response for one request should be scoped to that request only.\n\nFor example, if request A receives HTTP 400, request A should receive a request-level exception or MCP error, but request B should continue waiting for its own response and should be able to complete successfully.\n\n#### Actual Behavior\nA single request's HTTPStatusError escapes the shared transport task group and can poison the whole Streamable HTTP session, cancelling or disrupting sibling requests.\n\n#### Why this matters\nParallel tool calls are a common and useful pattern for MCP clients. In our agent, we intentionally allow parallel MCP tool calls to reduce latency. If one tool call gets a server-side HTTP 400 while another valid tool call is still in flight, the valid sibling call can fail too.\n\n#### Related Issues\nThis seems related to but more specific than:\n\nhttps://github.com/modelcontextprotocol/python-sdk/issues/2110\nhttps://github.com/modelcontextprotocol/python-sdk/issues/1805\n\nThose discuss non-2xx propagation and stream cleanup races. This issue is specifically about concurrent Streamable HTTP requests where one request's HTTP error escapes the per-request boundary and tears down sibling in-flight requests.\n\n### Example Code\n\n```Python\n\n```\n\n### Python \u0026 MCP Python SDK\n\n```Text\nPython 3.12\nMCP Python SDK 1.26.0\n\nI also inspected 1.27.1, which is currently the latest PyPI release, and the same relevant logic appears to still be present.\n```","author":{"url":"https://github.com/Jarda8","@type":"Person","name":"Jarda8"},"datePublished":"2026-05-15T11:41:52.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":5},"url":"https://github.com/2604/python-sdk/issues/2604"}
| route-pattern | /_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format) |
| route-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:d6439387-8990-b480-e14a-92a42ee037f6 |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | E39E:C0A64:8FBE45:C1FD35:6A600F45 |
| html-safe-nonce | a596d164288dfafc90ccaf71956134539997c00bfc4320b827f830527f1a4c21 |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJFMzlFOkMwQTY0OjhGQkU0NTpDMUZEMzU6NkE2MDBGNDUiLCJ2aXNpdG9yX2lkIjoiMjg1ODYyMTMzNTEwNjQ5MDE4MSIsInJlZ2lvbl9lZGdlIjoiaWFkIiwicmVnaW9uX3JlbmRlciI6ImlhZCJ9 |
| visitor-hmac | d5a97b0eaae6a0cce44dde24358ca7f729416a57eefe7cae17a698411a436d7a |
| hovercard-subject-tag | issue:4453610405 |
| github-keyboard-shortcuts | repository,issues,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/_view_fragments/issues/show/modelcontextprotocol/python-sdk/2604/issue_layout |
| twitter:image | https://opengraph.githubassets.com/9cd7b9699e5a29b7ebd7021243a78c57bbbcbf5d7ed67627be59c1a15f4f5b8b/modelcontextprotocol/python-sdk/issues/2604 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/9cd7b9699e5a29b7ebd7021243a78c57bbbcbf5d7ed67627be59c1a15f4f5b8b/modelcontextprotocol/python-sdk/issues/2604 |
| og:image:alt | Initial Checks I confirm that I'm using the latest version of MCP Python SDK I confirm that I searched for my issue in https://github.com/modelcontextprotocol/python-sdk/issues before opening this ... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | Jarda8 |
| hostname | github.com |
| expected-hostname | github.com |
| None | 48cb2ed2304f8ae5a4a05d6327faf70466c4c0d9dcbf7b9df76251ca9c669a90 |
| turbo-cache-control | no-preview |
| 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 |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | cb0f10a384099e0765239a7cc220992cae52bdba |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width