@@ -59,12 +59,11 @@ class StreamableHTTPSessionManager:
5959 session_idle_timeout: Optional idle timeout in seconds for stateful sessions.
6060 If set, sessions that receive no HTTP requests for this
6161 duration will be automatically terminated and removed.
62- When retry_interval is also set, the effective idle
63- threshold is at least ``retry_interval / 1000 * 3`` to
64- avoid prematurely reaping sessions that are simply
65- waiting for SSE polling reconnections. Default is None
66- (no timeout). A value of 1800 (30 minutes) is
67- recommended for most deployments.
62+ When retry_interval is also configured, ensure the idle
63+ timeout comfortably exceeds the retry interval to avoid
64+ reaping sessions during normal SSE polling gaps.
65+ Default is None (no timeout). A value of 1800
66+ (30 minutes) is recommended for most deployments.
6867 """
6968
7069 def __init__ (
@@ -237,8 +236,8 @@ async def _handle_stateful_request(
237236 transport = self ._server_instances [request_mcp_session_id ]
238237 logger .debug ("Session already exists, handling request directly" )
239238 # Push back idle deadline on activity
240- if transport .idle_scope is not None :
241- transport .idle_scope .deadline = anyio .current_time () + self ._effective_idle_timeout ()
239+ if transport .idle_scope is not None and self . session_idle_timeout is not None :
240+ transport .idle_scope .deadline = anyio .current_time () + self .session_idle_timeout
242241 await transport .handle_request (scope , receive , send )
243242 return
244243
@@ -271,8 +270,7 @@ async def run_server(*, task_status: TaskStatus[None] = anyio.TASK_STATUS_IGNORE
271270 # Incoming requests push the deadline forward.
272271 idle_scope = anyio .CancelScope ()
273272 if self .session_idle_timeout is not None :
274- timeout = self ._effective_idle_timeout ()
275- idle_scope .deadline = anyio .current_time () + timeout
273+ idle_scope .deadline = anyio .current_time () + self .session_idle_timeout
276274 http_transport .idle_scope = idle_scope
277275
278276 with idle_scope :
@@ -332,19 +330,3 @@ async def run_server(*, task_status: TaskStatus[None] = anyio.TASK_STATUS_IGNORE
332330 media_type = "application/json" ,
333331 )
334332 await response (scope , receive , send )
335-
336- def _effective_idle_timeout (self ) -> float :
337- """Compute the effective idle timeout, accounting for retry_interval.
338-
339- When SSE retry_interval is configured, clients periodically reconnect
340- to resume the event stream. A gap of up to ``retry_interval`` between
341- connections is normal, not a sign of idleness. We use a 3x multiplier
342- to tolerate up to two consecutive missed polls (network jitter, slow
343- client) before considering the session idle.
344- """
345- assert self .session_idle_timeout is not None
346- timeout = self .session_idle_timeout
347- if self .retry_interval is not None :
348- retry_seconds = self .retry_interval / 1000.0
349- timeout = max (timeout , retry_seconds * 3 )
350- return timeout
0 commit comments