
    Ch+                        S r SSKJr  SSKrSSKrSSKJr  SSKJr  SSK	J
r
  SSKJr  SSKrSSKJr  SS	KJr  SS
KJr  SSKJrJrJr  SSKJr  SSKJrJrJr  SSKJ r   \RB                  " \"5      r# " S S5      r$g)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)TransportSecuritySettingsc                      \ rS rSrSr    S
         SS jjr\R                  SS j5       r        SS jr	        SS jr
        SS jrS	rg)StreamableHTTPSessionManager   ap  
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

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.
Nc                    Xl         X l        X0l        X@l        XPl        [
        R                  " 5       U l        0 U l        S U l	        [
        R                  " 5       U l
        SU l        g )NF)appevent_storejson_response	statelesssecurity_settingsanyioLock_session_creation_lock_server_instances_task_group	_run_lock_has_started)selfr   r   r   r   r   s         \/home/james-whalen/.local/lib/python3.13/site-packages/mcp/server/streamable_http_manager.py__init__%StreamableHTTPSessionManager.__init__8   sW     &*"!2 ',jjl#KM  !    c                 #    U R                    ISh  vN   U R                  (       a  [        S5      eSU l        SSS5      ISh  vN   [        R                  " 5        ISh  vN nXl        [        R                  S5         S7v   [        R                  S5        UR                  R                  5         SU l        U R                  R                  5         SSS5      ISh  vN   g N N! , ISh  vN  (       d  f       N= f N! [        R                  S5        UR                  R                  5         SU l        U R                  R                  5         f = f Nz! , ISh  vN  (       d  f       g= f7f)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!   r"   RuntimeErrorr   create_task_groupr    loggerinfocancel_scopecancelr   clear)r#   tgs     r$   run StreamableHTTPSessionManager.runP   s    & >>>  "Y  !%D "> **,,!KK@A/JK&&(#' &&,,. -,, ">>> - JK&&(#' &&,,. -,,,s   E<C+E<$C/E<C-E<$D	%E<(E"D
AE"E<%E &E<-E</D5C86DE<AEE" E<"E9(E+)E95E<c                   #    U R                   c  [        S5      eU R                  (       a  U R                  XU5      I Sh  vN   gU R	                  XU5      I Sh  vN   g N  N7f)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)r#   scopereceivesends       r$   handle_request+StreamableHTTPSessionManager.handle_requesty   s]       #WXX >>00FFF//EEE GEs#   ?A&A"A&A$A&$A&c                  ^ ^#    [         R                  S5        [        ST R                  ST R                  S9m[
        R                  S.SUU 4S jjjnT R                  c   eT R                  R                  U5      I Sh  vN   TR                  XU5      I Sh  vN   TR                  5       I Sh  vN   g N7 N N	7f)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                  >#    TR                  5        IS h  vN nUu  p#U R                  5          TR                  R                  UUTR                  R	                  5       SS9I S h  vN   S S S 5      IS h  vN   g  Nf N! [
         a    [        R                  S5         N6f = f N.! , IS h  vN  (       d  f       g = f7f)NTr   zStateless session crashed)connectstartedr   r1   create_initialization_options	Exceptionr+   	exception)r@   streamsread_streamwrite_streamhttp_transportr#   s       r$   run_stateless_serverTStreamableHTTPSessionManager._handle_stateless_request.<locals>.run_stateless_server   s     %--//7,3)##%B((,,#$>>@"&	 '   	 0// ! B$$%@AB 0///ss   CA?CB*7B)B*B.C9B(:CBB%"B*$B%%B*(C*C0B31C=C)r@   TaskStatus[None])r+   debugr   r   r   r   TASK_STATUS_IGNOREDr    startr9   	terminate)r#   r6   r7   r8   rL   rK   s   `    @r$   r4   6StreamableHTTPSessionManager._handle_stateless_request   s      	NO6%)%7%7"44	
 KPJcJc 	B 	B +++$$%9::: ++EDAAA &&((( 	; 	B 	)s6   A>C B:C B<C 4B>5C <C >C c                  ^ ^
#    [        X5      nUR                  R                  [        5      nUbO  UT R                  ;   a?  T R                  U   n[
        R                  S5        UR                  XU5      I Sh  vN   gUGc   [
        R                  S5        T R                   ISh  vN   [        5       R                  n[        UT R                  T R                  T R                  S9m
T
R                  c   eT
T R                  T
R                  '   [
        R!                  SU 35        ["        R$                  S.S
U
U 4S jjjnT R&                  c   eT R&                  R)                  U5      I Sh  vN   T
R                  XU5      I Sh  vN   SSS5      ISh  vN   g[+        S[,        R.                  S	9n	U	" XU5      I Sh  vN   g GNT GN( N_ NG N9! , ISh  vN  (       d  f       g= f N+7f)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 transportr<   z'Created new transport with session ID: r?   c                  >#    TR                  5        IS h  vN nUu  p#U R                  5          TR                  R                  UUTR                  R	                  5       SS9I S h  vN   TR                  (       ae  TR                  TR                  ;   aK  TR                  (       d:  [        R                  STR                   S35        TR                  TR                  	 S S S 5      IS h  vN   g  N N! [
         a.  n[        R                  STR                   SU 3SS9   S nANS nAff = f! TR                  (       ah  TR                  TR                  ;   aM  TR                  (       d;  [        R                  STR                   S35        TR                  TR                  	 f f f f = f N! , IS h  vN  (       d  f       g = f7f)	NFrB   zSession z
 crashed: T)exc_infozCleaning up crashed session z from active instances.)rC   rD   r   r1   rE   rF   r+   errorr=   r   is_terminatedr,   )r@   rH   rI   rJ   erK   r#   s        r$   
run_serverIStreamableHTTPSessionManager._handle_stateful_request.<locals>.run_server   s    -557774;1#++-Z"&((,, + , $ F F H*/	 #/ #   !/ = =$2$A$ATE[E[$[(6(D(D &$B'5'D'D&E F8%8!"
 %)$:$:>;X;X$Y7  877  ) "LL"*>+H+H*ITUSV W)- )  !/ = =$2$A$ATE[E[$[(6(D(D &$B'5'D'D&E F8%8!"
 %)$:$:>;X;X$Y )E %\ !>%  8777s   GC5GF47C9)C7*C9.A6F4$G/F20G7C99
D1$D,'D4,D11D44A;F//F42G4G:F=;GGz)Bad Request: No valid session ID provided)status_code)r@   rN   returnNone)r	   headersgetr   r   r+   rO   r9   r   r   hexr   r   r   r   r=   r,   r   rP   r    rQ   r
   r   BAD_REQUEST)r#   r6   r7   r8   requestrequest_mcp_session_id	transportnew_session_idrZ   responserK   s   `         @r$   r5   5StreamableHTTPSessionManager._handle_stateful_request   s     %)!(!4!45J!K "-2HDLbLb2b../EFILLLM**54@@@!)LL12222!&!>#1-1-?-? $ 0 0&*&<&<	" &44@@@HV&&~'D'DEEnEUVW INHaHa Z Z> ''333&&,,Z888 %33EDIIIe 322j  ;&22H 54000 A 3^ 9 Je 3222r 1s   A7G7;G<.G7*G+G7.CG5G6GGGG7G )G7	G5
G7G7GGG7G2!G$"G2.G7)
r"   r!   r   r   r    r   r   r   r   r   )NFFN)
r   zMCPServer[Any, Any]r   zEventStore | Noner   boolr   ri   r   z TransportSecuritySettings | None)r]   zAsyncIterator[None])r6   r   r7   r   r8   r   r]   r^   )__name__
__module____qualname____firstlineno____doc__r%   
contextlibasynccontextmanagerr1   r9   r4   r5   __static_attributes__ r'   r$   r   r      s    : *.#>B" " '" 	"
 " <"0 ##&/ $&/PFF F 	F
 
F2/)/) /) 	/)
 
/)bT1T1 T1 	T1
 
T1r'   r   )%rn   
__future__r   ro   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   	getLoggerrj   r+   r   rr   r'   r$   <module>r      s^    5 "   )       & ( 0 0 : 
 D			8	$z1 z1r'   