+
    wi7                       R t ^ RIHt ^ RIt^ RIt^ RIHt ^ RIHt ^ RI	H
t
 ^ RIHt ^ RIt^ RIHt ^ RIHt ^ R	IHt ^ R
IHtHtHt ^ RIHt ^ RIHtHtHt ^ RIH t  ^ RI!H"t"H#t#H$t$ ]PJ                  ! ]&4      t' ! R R4      t(R# )z/StreamableHTTP Session Manager for MCP servers.)annotationsN)AsyncIterator)
HTTPStatus)Any)uuid4)
TaskStatus)Request)Response)ReceiveScopeSend)Server)MCP_SESSION_ID_HEADER
EventStoreStreamableHTTPServerTransport)TransportSecuritySettings)INVALID_REQUEST	ErrorDataJSONRPCErrorc                  x    ] tR t^tRtRR R llt]P                  R R l4       tR R lt	R	 R
 lt
R R ltRtR# )StreamableHTTPSessionManagera  
Manages StreamableHTTP sessions with optional resumability via event store.

This class abstracts away the complexity of session management, event storage,
and request handling for StreamableHTTP transports. It handles:

1. Session tracking for clients
2. Resumability via an optional event store
3. Connection management and lifecycle
4. Request handling and transport setup
5. Idle session cleanup via optional timeout

Important: Only one StreamableHTTPSessionManager instance should be created
per application. The instance cannot be reused after its run() context has
completed. If you need to restart the manager, create a new instance.

Args:
    app: The MCP server instance
    event_store: Optional event store for resumability support. If provided, enables resumable connections
        where clients can reconnect and receive missed events. If None, sessions are still tracked but not
        resumable.
    json_response: Whether to use JSON responses instead of SSE streams
    stateless: If True, creates a completely fresh transport for each request with no session tracking or
        state persistence between requests.
    security_settings: Optional transport security settings.
    retry_interval: Retry interval in milliseconds to suggest to clients in SSE retry field. Used for SSE
        polling behavior.
    session_idle_timeout: Optional idle timeout in seconds for stateful sessions. If set, sessions that
        receive no HTTP requests for this duration will be automatically terminated and removed. When
        retry_interval is also configured, ensure the idle timeout comfortably exceeds the retry interval to
        avoid reaping sessions during normal SSE polling gaps. Default is None (no timeout). A value of 1800
        (30 minutes) is recommended for most deployments.
Nc               4    V ^8  d   QhRRRRRRRRRR	R
RRR/# )   appzMCPServer[Any, Any]event_storezEventStore | Nonejson_responsebool	statelesssecurity_settingsz TransportSecuritySettings | Noneretry_intervalz
int | Nonesession_idle_timeoutzfloat | None )formats   "V/home/ubuntu/.local/lib/python3.14/site-packages/mcp/server/streamable_http_manager.py__annotate__)StreamableHTTPSessionManager.__annotate__A   sP     " " " '" 	"
 " <" #" +"    c                	F   Ve   V^ 8:  d   \        R4      hV'       d   Ve   \        R4      hWn        W n        W0n        W@n        WPn        W`n        Wpn        \        P                  ! 4       V n        / V n        R V n        \        P                  ! 4       V n        RV n        R # )Nz9session_idle_timeout must be a positive number of secondsz7session_idle_timeout is not supported in stateless modeF)
ValueErrorRuntimeErrorr   r   r   r   r   r   r    anyioLock_session_creation_lock_server_instances_task_group	_run_lock_has_started)selfr   r   r   r   r   r   r    s   &&&&&&&&r#   __init__%StreamableHTTPSessionManager.__init__A   s      +0D0IXYY-9XYY&*"!2,$8! ',jjl#KM  !r&   c                   V ^8  d   QhRR/# )r   returnzAsyncIterator[None]r!   )r"   s   "r#   r$   r%   c   s     &/ &/. &/r&   c               *  "   V P                   ;_uu_4       GRj  xL
  V P                  '       d   \        R4      hRV n        RRR4      GRj  xL
  \        P                  ! 4       ;_uu_4       GRj  xL
 pWn        \        P                  R4        R5x  \        P                  R4       VP                  P                  4        RV n        V P                  P                  4        RRR4      GRj  xL
  R#  L L  + GRj  xL 
 '       g   i     L; i L  \        P                  R4       TP                  P                  4        RT n        T P                  P                  4        i ; i L}  + GRj  xL 
 '       g   i     R# ; i5i)a  
Run the session manager with proper lifecycle management.

This creates and manages the task group for all session operations.

Important: This method can only be called once per instance. The same
StreamableHTTPSessionManager instance cannot be reused after this
context manager exits. Create a new instance if you need to restart.

Use this in the lifespan context manager of your Starlette app:

@contextlib.asynccontextmanager
async def lifespan(app: Starlette) -> AsyncIterator[None]:
    async with session_manager.run():
        yield
NzyStreamableHTTPSessionManager .run() can only be called once per instance. Create a new instance if you need to run again.Tz&StreamableHTTP session manager startedz,StreamableHTTP session manager shutting down)r/   r0   r)   r*   create_task_groupr.   loggerinfocancel_scopecancelr-   clear)r1   tgs   & r#   run StreamableHTTPSessionManager.runb   s    & >>>>   "Y  !%D "> **,,,!KK@A/JK&&(#' &&,,. -,, ">>> - JK&&(#' &&,,. -,,,s   FC=F%DFC?%F5D6F9E6DAE6+F6E47F?FD	D

D	D		FAE11E64F6F	<E?=
F	F	
	Fc               (    V ^8  d   QhRRRRRRRR/# 	r   scoper   receiver
   sendr   r5   Noner!   )r"   s   "r#   r$   r%      s8     F FF F 	F
 
Fr&   c                   "   V P                   f   \        R4      hV P                  '       d   V P                  WV4      G Rj  xL
  R# V P	                  WV4      G Rj  xL
  R#  L" L5i)z
Process ASGI request with proper session handling and transport setup.

Dispatches to the appropriate handler based on stateless mode.

Args:
    scope: ASGI scope
    receive: ASGI receive function
    send: ASGI send function
Nz6Task group is not initialized. Make sure to use run().)r.   r)   r   _handle_stateless_request_handle_stateful_request)r1   rB   rC   rD   s   &&&&r#   handle_request+StreamableHTTPSessionManager.handle_request   s_       #WXX >>>00FFF//EEE GEs(   +A*A*A&A*A( A*(A*c               (    V ^8  d   QhRRRRRRRR/# rA   r!   )r"   s   "r#   r$   r%      s2     /) /)/) /) 	/)
 
/)r&   c                  a a"   \         P                  R4       \        RS P                  RS P                  R7      oR\
        P                  /R VV 3R lllpS P                  f   Q hS P                  P                  V4      G Rj  xL
  SP                  WV4      G Rj  xL
  SP                  4       G Rj  xL
  R#  L8 L  L
5i)z
Process request in stateless mode - creating a new transport for each request.

Args:
    scope: ASGI scope
    receive: ASGI receive function
    send: ASGI send function
z7Stateless mode: Creating new transport for this requestN)mcp_session_idis_json_response_enabledr   r   task_statusc                   V ^8  d   QhRR/# )r   rO   TaskStatus[None]r!   )r"   s   "r#   r$   LStreamableHTTPSessionManager._handle_stateless_request.<locals>.__annotate__   s     	B 	B7G 	Br&   c           	       <"   SP                  4       ;_uu_4       GR j  xL
 pVw  r#V P                  4         SP                  P                  VVSP                  P	                  4       RR7      G R j  xL
  R R R 4      GR j  xL
  R #  Lj L  \
         d    \        P                  R4        L8i ; i L0  + GR j  xL 
 '       g   i     R # ; i5i)NTr   zStateless session crashed)connectstartedr   r>   create_initialization_options	Exceptionr8   	exception)rO   streamsread_streamwrite_streamhttp_transportr1   s   $   r#   run_stateless_serverTStreamableHTTPSessionManager._handle_stateless_request.<locals>.run_stateless_server   s     %--///7,3)##%B((,,#$>>@"&	 '   	 0// ! B$$%@AB 0///sy   CBCB7:B4B5B9CB5CB B2/B71B22B75C7C	=C >
C		C		C)r8   debugr   r   r   r*   TASK_STATUS_IGNOREDr.   startrI   	terminate)r1   rB   rC   rD   r^   r]   s   f&&& @r#   rG   6StreamableHTTPSessionManager._handle_stateless_request   s      	NO6%)%7%7"44	
	B%JcJc 	B 	B +++$$%9::: ++EDAAA &&((( 	; 	B 	)s6   BCC C!C"C9C:CCCc               (    V ^8  d   QhRRRRRRRR/# rA   r!   )r"   s   "r#   r$   r%      s8     o1 o1o1 o1 	o1
 
o1r&   c           
     D  a a"   \        W4      pVP                  P                  \        4      pVe   VS P                  9   d   S P                  V,          p\
        P                  R4       VP                  eD   S P                  e6   \        P                  ! 4       S P                  ,           VP                  n        VP                  WV4      G Rj  xL
  R# VEf;   \
        P                  R4       S P                  ;_uu_4       GRj  xL
  \        4       P                  p\!        VS P"                  S P$                  S P&                  S P(                  R7      oSP*                  f   Q hSS P                  SP*                  &   \
        P-                  RV 24       R\        P.                  /R VV 3R lllpS P0                  f   Q hS P0                  P3                  V4      G Rj  xL
  SP                  WV4      G Rj  xL
  RRR4      GRj  xL
  R# \5        R	R
\7        \8        RR7      R7      p	\;        V	P=                  RRR7      \>        P@                  RR7      p
V
! WV4      G Rj  xL
  R#  EL ELm L L{ Lm  + GRj  xL 
 '       g   i     R# ; i L/5i)z
Process request in stateful mode - maintaining session state between requests.

Args:
    scope: ASGI scope
    receive: ASGI receive function
    send: ASGI send function
Nz1Session already exists, handling request directlyzCreating new transport)rM   rN   r   r   r   z'Created new transport with session ID: rO   c                    V ^8  d   QhRRRR/# )r   rO   rQ   r5   rE   r!   )r"   s   "r#   r$   KStreamableHTTPSessionManager._handle_stateful_request.<locals>.__annotate__  s      (Z (Z5E (Zfj (Zr&   c                  <"   SP                  4       ;_uu_4       GR j  xL
 pVw  r#V P                  4         \        P                  ! 4       pSP                  e3   \        P
                  ! 4       SP                  ,           Vn        VSn        T;_uu_ 4        SP                  P                  VVSP                  P                  4       RR7      G R j  xL
  R R R 4       VP                  '       dr   SP                  f   Q h\        P                  RSP                   R24       SP                  P!                  SP                  R 4       SP#                  4       G R j  xL
  SP                  '       dh   SP                  SP                  9   dM   SP(                  '       g;   \        P                  RSP                   R24       SP                  SP                   R R R 4      GR j  xL
  R #  EL EL  + '       g   i     EL%; i L  \$         d'    \        P'                  RSP                   R24        Li ; i  SP                  '       dk   SP                  SP                  9   dO   SP(                  '       g<   \        P                  RSP                   R24       SP                  SP                   i i i i ; i L  + GR j  xL 
 '       g   i     R # ; i5i)NFrT   zSession z idle timeoutz crashedzCleaning up crashed session z from active instances.)rU   rV   r*   CancelScoper    current_timedeadline
idle_scoper   r>   rW   cancelled_caughtrM   r8   r9   r-   poprc   rX   rY   is_terminated)rO   rZ   r[   r\   rm   r]   r1   s   $    r#   
run_serverIStreamableHTTPSessionManager._handle_stateful_request.<locals>.run_server  sg    -5577774;1#++-$Z
 */):):)<J#88D6;6H6H6JTMfMf6f
 3<F 9!+&*hhll$/$0$(HH$J$J$L.3	 '3 '" !" !" ",  *:::'5'D'D'P P'P &h~7T7T6UUb,c d $ 6 6 : :>;X;XZ^ _&4&>&>&@ @ @
 !/ = = =$2$A$ATE[E[$[(6(D(D(D &$B'5'D'D&E F8%8!"
 %)$:$:>;X;X$YO  877!" ", !A( a",,x8U8U7VV^-_`a !/ = = =$2$A$ATE[E[$[(6(D(D(D &$B'5'D'D&E F8%8!"
 %)$:$:>;X;X$Y )E %\ !>=  8777s   KG/KKAH;G5	G2G5	H3A,HH	 H$>K#:KK(K )K2G5	5H 
H.H<9H?;H<<H???J=?>J==K KK	K	
K	K		Kz2.0zserver-errorzSession not found)codemessage)jsonrpciderrorT)by_aliasexclude_nonezapplication/json)contentstatus_code
media_type)!r   headersgetr   r-   r8   r`   rm   r    r*   rk   rl   rI   r,   r   hexr   r   r   r   r   rM   r9   ra   r.   rb   r   r   r   r	   model_dump_jsonr   	NOT_FOUND)r1   rB   rC   rD   requestrequest_mcp_session_id	transportnew_session_idrq   error_responseresponser]   s   f&&&       @r#   rH   5StreamableHTTPSessionManager._handle_stateful_request   sE     %)!(!4!45J!K "-2HDLbLb2b../EFILLLM##/D4M4M4Y050B0B0DtG`G`0`	$$-**54@@@!)LL122222!&!>#1-1-?-? $ 0 0&*&<&<#'#6#6" &44@@@HV&&~'D'DEEnEUVW(ZHaHa (Z (ZV ''333&&,,Z888 %33EDIII 322H *!(/N  &66SW6X&00-H
 54000o A 3x 9 J 3222b 1s   CJ I58J I8J CJ'I;(JI=JJ I?AJ .J/J 8J ;J=J?J J	J

J	J	
J )r0   r/   r-   r,   r.   r   r   r   r   r   r    r   )NFFNNN)__name__
__module____qualname____firstlineno____doc__r2   
contextlibasynccontextmanagerr>   rI   rG   rH   __static_attributes__r!   r&   r#   r   r      sA     D"B ##&/ $&/PF2/)bo1 o1r&   r   ))r   
__future__r   r   loggingcollections.abcr   httpr   typingr   uuidr   r*   	anyio.abcr   starlette.requestsr   starlette.responsesr	   starlette.typesr
   r   r   mcp.server.lowlevel.serverr   	MCPServermcp.server.streamable_httpr   r   r   mcp.server.transport_securityr   	mcp.typesr   r   r   	getLoggerr   r8   r   r!   r&   r#   <module>r      sd    5 "   )       & ( 0 0 : 
 D > >			8	$f1 f1r&   