feat(session-manager): tenant validation on session access#13
Merged
andylim-duo merged 4 commits intomainfrom Mar 18, 2026
Merged
feat(session-manager): tenant validation on session access#13andylim-duo merged 4 commits intomainfrom
andylim-duo merged 4 commits intomainfrom
Conversation
Prevent cross-tenant session hijacking by validating that the authenticated tenant matches the session's bound tenant on every request. Sessions created without a tenant (no auth) remain accessible to all requests for backward compatibility. Adds a parallel _session_tenants dict that records the tenant_id from tenant_id_var at session creation time. On existing session lookup, a mismatch returns 404 (same as "session not found" to avoid information leakage). Tenant mappings are cleaned up alongside sessions on all exit paths: idle timeout, crash, and shutdown. Includes 7 tests covering bidirectional isolation, same-tenant reuse, backward compatibility, unauthenticated access rejection, and cleanup. 100% branch coverage on streamable_http_manager.py.
andylim-duo
commented
Mar 18, 2026
andylim-duo
commented
Mar 18, 2026
andylim-duo
commented
Mar 18, 2026
Add tests for _extract_session_id and _extract_status that exercise the "skip non-start messages" and "not found" paths, replacing pragma suppressions with actual coverage.
- Split tenant mismatch log: WARNING with session ID only, DEBUG for tenant values to avoid leaking sensitive data at default log levels - _set_tenant/_reset_tenant helpers always set/reset the contextvar unconditionally, avoiding subtle bugs when tenant is None - Wrap all blocking-session tests in try/finally to ensure stop.set() runs even on assertion failures, preventing test hangs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds tenant-scoped session isolation to
StreamableHTTPSessionManager, preventing cross-tenant session hijacking. This is iteration 5 of 6 in the multi-tenancy implementation plan.Context: Multi-Tenancy Implementation Plan
tenant_idto authentication tokens (done, PR feat(auth): add tenant_id field to authentication token models #2)tenant_idto session and request context (done, PR feat(auth): add tenant_id to session and request context #3)tenant_idfrom handlers to managers (done, PR feat(server): thread tenant_id through MCPServer handlers to managers #9)Changes
src/mcp/server/streamable_http_manager.py:_session_tenantsdict to track which tenant owns each sessiontenant_id_varNone) allow access from any request (backward compatibility)tests/server/test_streamable_http_manager.py— 7 new tests:Design Decision
The plan originally proposed composite keys
(tenant_id, session_id)for session storage. This was unnecessary since session IDs are globally unique UUIDs. Instead, a simpler parallel_session_tenantsdict validates tenant ownership on lookup — same security guarantee, less invasive change.Backward Compatibility
Fully backward compatible. Sessions created without authentication (
tenant_id=None) behave exactly as before — no tenant validation is applied.Test plan
streamable_http_manager.pypyrightpasses with 0 errorsruffpasses