Title: Bind authenticated identity to sessions in StreamableHTTPSessionManager · Issue #2100 · modelcontextprotocol/python-sdk · GitHub
Open Graph Title: Bind authenticated identity to sessions in StreamableHTTPSessionManager · Issue #2100 · modelcontextprotocol/python-sdk
X Title: Bind authenticated identity to sessions in StreamableHTTPSessionManager · Issue #2100 · modelcontextprotocol/python-sdk
Description: Problem StreamableHTTPSessionManager._handle_stateful_request routes incoming requests to existing sessions based solely on the Mcp-Session-Id header value. There is no check that the authenticated identity on the incoming request matche...
Open Graph Description: Problem StreamableHTTPSessionManager._handle_stateful_request routes incoming requests to existing sessions based solely on the Mcp-Session-Id header value. There is no check that the authenticated...
X Description: Problem StreamableHTTPSessionManager._handle_stateful_request routes incoming requests to existing sessions based solely on the Mcp-Session-Id header value. There is no check that the authenticated...
Opengraph URL: https://github.com/modelcontextprotocol/python-sdk/issues/2100
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"Bind authenticated identity to sessions in StreamableHTTPSessionManager","articleBody":"## Problem\n\n`StreamableHTTPSessionManager._handle_stateful_request` routes incoming requests to existing sessions based solely on the `Mcp-Session-Id` header value. There is no check that the authenticated identity on the incoming request matches the identity that originally created the session.\n\nThe auth middleware (`BearerAuthBackend` / `RequireAuthMiddleware`) and session routing are completely decoupled layers — auth validates the token and stores it in a contextvar, while the session manager does a plain dict lookup on the header value. These two layers never cross-reference each other.\n\nThis means that if a valid `Mcp-Session-Id` is obtained by a different authenticated user (e.g., leaked via logs, shared infrastructure, or network interception without TLS), that user can send requests on the original session with no additional verification.\n\n## Expected behavior\n\nWhen auth is enabled, `_handle_stateful_request` should verify that the authenticated identity (e.g., `client_id` or subject from the access token) on the incoming request matches the identity that created the session. Requests with a mismatched identity should be rejected.\n\n## Proposed approach\n\n1. When a new session is created and auth is active, record the authenticated identity (from `AuthContextMiddleware` / `auth_context_var`) on the session or transport\n2. On subsequent requests to an existing session, compare the current request's authenticated identity against the stored one\n3. Reject with an appropriate error if they differ\n\nThis should happen at the session manager level, before the request reaches any handler.\n\n## Context\n\n- The `Mcp-Session-Id` is a `uuid4().hex` (128-bit random), so it is not guessable in practice\n- SEP-1299 and SEP-1415 in the spec repo discuss related session binding concerns at the protocol level\n- This is an SDK-level hardening that can be done independently of spec changes\n\n\u003csub\u003e[AI Disclaimer](https://gist.github.com/maxisbey/6123d132484e4c533eab519a2800693d)\u003c/sub\u003e","author":{"url":"https://github.com/maxisbey","@type":"Person","name":"maxisbey"},"datePublished":"2026-02-19T16:54:42.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":1},"url":"https://github.com/2100/python-sdk/issues/2100"}
| 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:692a25bf-4c6c-7962-ab9d-e59ec8d33e47 |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | 86F0:2A801F:9D05A:C4E41:6A5B5C9A |
| html-safe-nonce | 02b31aaea0301e0d6a922b9358fe8592cac192c8ed5d2942123fbbf6ecfeeaa0 |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiI4NkYwOjJBODAxRjo5RDA1QTpDNEU0MTo2QTVCNUM5QSIsInZpc2l0b3JfaWQiOiI3NTYzMzk2OTcyOTIzMjgwNTM4IiwicmVnaW9uX2VkZ2UiOiJpYWQiLCJyZWdpb25fcmVuZGVyIjoiaWFkIn0= |
| visitor-hmac | 25258a5df336b10085ffd81b633a42e2689a040333a3c240abae4a4c77c3004e |
| hovercard-subject-tag | issue:3963975723 |
| 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/2100/issue_layout |
| twitter:image | https://opengraph.githubassets.com/d8db2ae33f982e450a0b37d7daca08f2b2205137865bf0d429d52a7aa8e38746/modelcontextprotocol/python-sdk/issues/2100 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/d8db2ae33f982e450a0b37d7daca08f2b2205137865bf0d429d52a7aa8e38746/modelcontextprotocol/python-sdk/issues/2100 |
| og:image:alt | Problem StreamableHTTPSessionManager._handle_stateful_request routes incoming requests to existing sessions based solely on the Mcp-Session-Id header value. There is no check that the authenticated... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | maxisbey |
| hostname | github.com |
| expected-hostname | github.com |
| None | 5290d7e14309ad1e76106a9c4237bd1041517e83ea182c8ab756752cb0c6940b |
| 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 | 9c975978430e9ad293956f2bbdaf153b1bd84a99 |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width