@@ -51,6 +51,9 @@ class StreamableHTTPSessionManager:
51
51
json_response: Whether to use JSON responses instead of SSE streams
52
52
stateless: If True, creates a completely fresh transport for each request
53
53
with no session tracking or state persistence between requests.
54
+ single_tenant: If True, only one transport will be created to process the entire
55
+ every request, regardless of the MCP session id. This is useful for
56
+ hosting platforms where the MCP server is launched in a single-tenant box.
54
57
"""
55
58
56
59
def __init__ (
@@ -59,12 +62,18 @@ def __init__(
59
62
event_store : EventStore | None = None ,
60
63
json_response : bool = False ,
61
64
stateless : bool = False ,
65
+ single_tenant : bool = False ,
62
66
security_settings : TransportSecuritySettings | None = None ,
63
67
):
64
68
self .app = app
65
69
self .event_store = event_store
66
70
self .json_response = json_response
67
71
self .stateless = stateless
72
+ self .single_tenant = single_tenant
73
+ if self .stateless and self .single_tenant :
74
+ # A single-tenant server must be stateful, but stateful server does not
75
+ # have to be single tenant.
76
+ raise ValueError ("A single-tenant server must stateful." )
68
77
self .security_settings = security_settings
69
78
70
79
# Session tracking (only used if not stateless)
@@ -209,6 +218,19 @@ async def _handle_stateful_request(
209
218
request = Request (scope , receive )
210
219
request_mcp_session_id = request .headers .get (MCP_SESSION_ID_HEADER )
211
220
221
+ if self .single_tenant and self ._server_instances :
222
+ # being single_tenant means that there is only one ASGI server for the entire application.
223
+ # that server is used to process all the mcp requests because the hosting platform
224
+ # is already distributing the request to the box where the single-tenant mcp server runs.
225
+ assert len (self ._server_instances ) == 1
226
+ # hosting platforms might exposes a different mcp session ID hence
227
+ # we take the first key of server instances as the mcp session id
228
+ request_mcp_session_id = next (iter (self ._server_instances .keys ()))
229
+ headers = dict (scope ["headers" ])
230
+ # Also need to reset the incoming request mcp session id to this existing session id
231
+ headers [MCP_SESSION_ID_HEADER .encode ("latin-1" )] = request_mcp_session_id .encode ("latin-1" )
232
+ scope ["headers" ] = list (headers .items ())
233
+
212
234
# Existing session case
213
235
if request_mcp_session_id is not None and request_mcp_session_id in self ._server_instances :
214
236
transport = self ._server_instances [request_mcp_session_id ]
0 commit comments