Title: fix: stop the standalone GET stream reconnecting forever on empty connections by heyhayes · Pull Request #3087 · modelcontextprotocol/python-sdk · GitHub
Open Graph Title: fix: stop the standalone GET stream reconnecting forever on empty connections by heyhayes · Pull Request #3087 · modelcontextprotocol/python-sdk
X Title: fix: stop the standalone GET stream reconnecting forever on empty connections by heyhayes · Pull Request #3087 · modelcontextprotocol/python-sdk
Description: Summary Split out from #2122. Since that PR was opened, its core fix — propagating an error to a waiting request when an SSE stream ends without a response — has landed upstream independently via the _resolve_abandoned_request helper (introduced in #3047), which resolves an abandoned request with a synthesized error both when an id-bearing stream ends unresumably and when reconnection attempts are exhausted. This PR carries forward only the two fixes from #2122 that are not covered by that work. Relates to #1401. What changed Stop the standalone GET stream reconnecting forever on empty connections. handle_get_stream reset its attempt counter to 0 whenever a connection ended "normally" — i.e. the async for over the SSE events completed without raising. A server that accepts the GET but immediately closes the stream with no events hits exactly this path, so the counter never advances and the client reconnects in an unbounded loop (throttled only by the reconnect delay). The counter now resets only when events were actually received; empty connections count toward MAX_RECONNECTION_ATTEMPTS, so the loop gives up. That give-up branch was previously marked unreachable (# pragma: no cover) — it is now reachable and covered by a test. Log unhandled exceptions in the default message handler. Transport-level errors not tied to a specific pending request (e.g. a GET stream failure) reach _default_message_handler as an Exception item and were silently discarded. It now logs a warning as an observability safety net. Testing New regression test drives repeated empty GET streams and asserts the loop terminates after MAX_RECONNECTION_ATTEMPTS rather than reconnecting forever. New test asserts _default_message_handler logs a warning for an Exception item. Full suite green; both changed files at 100% branch coverage.
Open Graph Description: Summary Split out from #2122. Since that PR was opened, its core fix — propagating an error to a waiting request when an SSE stream ends without a response — has landed upstream independently via t...
X Description: Summary Split out from #2122. Since that PR was opened, its core fix — propagating an error to a waiting request when an SSE stream ends without a response — has landed upstream independently via t...
Opengraph URL: https://github.com/modelcontextprotocol/python-sdk/pull/3087
X: @github
Domain: github.com
| route-pattern | /:user_id/:repository/pull/:id/files(.:format) |
| route-controller | pull_requests |
| route-action | files |
| fetch-nonce | v2:789bf967-8d6c-e0a5-a8e2-f06efcaf30a3 |
| current-catalog-service-hash | ae870bc5e265a340912cde392f23dad3671a0a881730ffdadd82f2f57d81641b |
| request-id | B724:1FBD82:19CC6B5:21E563C:6A5C786C |
| html-safe-nonce | 325a3335107538b455c14a8c835cd002c8531b3428a48e1250e1a352b0efdbf9 |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJCNzI0OjFGQkQ4MjoxOUNDNkI1OjIxRTU2M0M6NkE1Qzc4NkMiLCJ2aXNpdG9yX2lkIjoiNjYyMzY2MzkwOTU4NDUzMzYxMiIsInJlZ2lvbl9lZGdlIjoiaWFkIiwicmVnaW9uX3JlbmRlciI6ImlhZCJ9 |
| visitor-hmac | 06c1f75af66cc9a71d1c4a847674414c37b5c939d302bcc7edfdec935a406d1f |
| hovercard-subject-tag | pull_request:4031886296 |
| 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/3087/files |
| twitter:image | https://avatars.githubusercontent.com/u/39026099?s=400&v=4 |
| twitter:card | summary_large_image |
| og:image | https://avatars.githubusercontent.com/u/39026099?s=400&v=4 |
| og:image:alt | Summary Split out from #2122. Since that PR was opened, its core fix — propagating an error to a waiting request when an SSE stream ends without a response — has landed upstream independently via t... |
| 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