
    AHj&0                        d Z ddlZddlmZ ddlmZ ddlmZ ddlm	Z	m
Z
 ddlZddlmZmZ ddlmZ dd	lmZ dd
lmZ ddlmZ ddlmZmZmZ ddlmZ ddlmZmZm Z  ddl!m"Z"m#Z# ddl$m%Z%m&Z&  ejN                  e(      Z) G d d      Z*y)a  
SSE Server Transport Module

This module implements a Server-Sent Events (SSE) transport layer for MCP servers.

Example usage:
```
    # Create an SSE transport at an endpoint
    sse = SseServerTransport("/messages/")

    # Create Starlette routes for SSE and message handling
    routes = [
        Route("/sse", endpoint=handle_sse, methods=["GET"]),
        Mount("/messages/", app=sse.handle_post_message),
    ]

    # Define handler functions
    async def handle_sse(request):
        async with sse.connect_sse(
            request.scope, request.receive, request._send
        ) as streams:
            await app.run(
                streams[0], streams[1], app.create_initialization_options()
            )
        # Return empty response to avoid NoneType error
        return Response()

    # Create and run Starlette app
    starlette_app = Starlette(routes=routes)
    uvicorn.run(starlette_app, host="127.0.0.1", port=port)
```

Note: The handle_sse function must return a Response to avoid a "TypeError: 'NoneType'
object is not callable" error when client disconnects. The example above returns
an empty Response() after the SSE connection ends to fix this.

See SseServerTransport class documentation for more details.
    N)asynccontextmanager)Any)quote)UUIDuuid4)MemoryObjectReceiveStreamMemoryObjectSendStream)ValidationError)EventSourceResponse)Request)Response)ReceiveScopeSend)AuthenticatedUserAuthorizationContextauthorization_context)TransportSecurityMiddlewareTransportSecuritySettings)ServerMessageMetadataSessionMessagec                        e Zd ZU dZeed<   eeee	e
z     f   ed<   eeef   ed<   eed<   ddededz  d	df fd
Zedededefd       Zdededed	dfdZ xZS )SseServerTransporta  
    SSE server transport for MCP. This class provides _two_ ASGI applications,
    suitable to be used with a framework like Starlette and a server like Hypercorn:

        1. connect_sse() is an ASGI application which receives incoming GET requests,
           and sets up a new SSE stream to send server messages to the client.
        2. handle_post_message() is an ASGI application which receives incoming POST
           requests, which should contain client messages that link to a
           previously-established SSE session.
    	_endpoint_read_stream_writers_session_owners	_securityNendpointsecurity_settingsreturnc                     t         |           d|v s|j                  d      sd|v sd|v rt        d| d      |j                  d      sd|z   }|| _        i | _        i | _        t        |      | _        t        j                  d|        y	)
a  
        Creates a new SSE server transport, which will direct the client to POST
        messages to the relative path given.

        Args:
            endpoint: A relative path where messages should be posted
                    (e.g., "/messages/").
            security_settings: Optional security settings for DNS rebinding protection.

        Note:
            We use relative paths instead of full URLs for several reasons:
            1. Security: Prevents cross-origin requests by ensuring clients only connect
               to the same origin they established the SSE connection with
            2. Flexibility: The server can be mounted at any path without needing to
               know its full URL
            3. Portability: The same endpoint configuration works across different
               environments (development, staging, production)

        Raises:
            ValueError: If the endpoint is a full URL instead of a relative path
        z://z//?#zGiven endpoint: z] is not a relative path (e.g., '/messages/'), expecting a relative path (e.g., '/messages/')./z.SseServerTransport initialized with endpoint: N)super__init__
startswith
ValueErrorr   r   r   r   r   loggerdebug)selfr   r   	__class__s      F/root/tools/cai/cai_env/lib/python3.12/site-packages/mcp/server/sse.pyr&   zSseServerTransport.__init__T   s    . 	 H 3 3D 9SH_PSW_P_"8* -B B  ""3'X~H!$&!!45FGEhZPQ    scopereceivesendc                  K   |d   dk7  r t         j                  d       t        d      t        ||      }| j                  j                  |d       d {   }|r ||||       d {    t        d      t         j                  d       t        j                  d	      \  }t        j                  d	      \  }t               |j                  d
      }t        |t              rt        |      | j                  <   | j                  <   t         j                  d        |j                  dd      }	|	j!                  d      | j"                  z   }
t%        |
       dj&                   t        j                  t(        t*        t,        f      d	      \  fd	 t        j.                         4 d {   }dt0        dt2        dt4        ffd}t         j                  d       |j7                  ||||       t         j                  d       ||f d d d       d {    | j                  j9                  d        | j                  j9                  d        y 7 7 7 7 E# 1 d {  7  sw Y   UxY w# | j                  j9                  d        | j                  j9                  d        w xY ww)Ntypehttpz%connect_sse received non-HTTP requestz)connect_sse can only handle HTTP requestsFis_postzRequest validation failedzSetting up SSE connectionr   userzCreated new session with ID: 	root_path r$   z?session_id=c            
      2  K   t         j                  d       4 d {    4 d {    j                  dd       d {    t         j                  d        2 3 d {   } t         j                  d|         j                  d| j                  j	                  dd      d       d {    Y7 7 7 {7 Z7 6 d d d       d {  7   n# 1 d {  7  sw Y   nxY wd d d       d {  7   y # 1 d {  7  sw Y   y xY ww)	NzStarting SSE writerr   )eventdatazSent endpoint event: zSending message via SSE: messageT)by_aliasexclude_none)r)   r*   r1   r=   model_dump_json)session_messageclient_post_uri_datasse_stream_writerwrite_stream_readers    r-   
sse_writerz2SseServerTransport.connect_sse.<locals>.sse_writer   s    LL./(  *=  ',,zK_-`aaa45I4JKL-@  /LL#<_<M!NO+00%.$3$;$;$K$KUYhl$K$m   a .A	         s   DB>DDC DCCC%C)C
*C-AC8C
9C>D DCCCC	DCDC-	!C$"C-	)D0D;C><DDD	DDr/   r0   r1   c                   K    t              | ||       d{    j                          d{    j                          d{    j                          d{    t        j                  d        y7 e7 O7 97 #w)a   
                    The EventSourceResponse returning signals a client close / disconnect.
                    In this case we close our side of the streams to signal the client that
                    the connection has been closed.
                    )contentdata_sender_callableNzClient session disconnected )r   acloseloggingr*   )r/   r0   r1   read_stream_writer
session_idsse_stream_readerrE   rD   s      r-   response_wrapperz8SseServerTransport.connect_sse.<locals>.response_wrapper   s      j-6G^hiw   -33555-44666+22444MM$@"MN 664sC   B
BB
BB
BB
$B%B
B
B
B
zStarting SSE response taskzYielding read and write streams)r)   errorr(   r   r   validate_requestr*   anyiocreate_memory_object_streamr   get
isinstancer   r   r   r   rstripr   r   hexdictstrr   create_task_groupr   r   r   
start_soonpop)r+   r/   r0   r1   requesterror_responseread_streamwrite_streamr7   r8   full_message_path_for_clienttgrN   rB   rK   rL   rM   rC   rE   rD   s                @@@@@@@r-   connect_ssezSseServerTransport.connect_sse~   s    =F"LL@AHII %)#~~>>wPU>VV 66689901 +0*K*KA*N'K,1,M,Ma,P))W
yy d-./DT/JD  ,0B!!*-4ZLAB IIk2.	 (1'7'7'<t~~'M$ #((D"E!FlS]SaSaRbc/4/P/PQUVY[^V^Q_/`ab/c,,		7..0 2 2BO% O' OQU O O 9:.wE>?"L11)2 22 %%))*d;  $$Z6c W6j2 2 2 2 22 %%))*d;  $$Z6s   AKI6K2I93D;K/J I<J A"J -J 8I>9J =:K9K<J >J  JJ	JJ :KKc                 |  K   t         j                  d       t        ||      }| j                  j	                  |d       d {   }|r ||||       d {   S |j
                  j                  d      }|4t         j                  d       t        dd      } ||||       d {   S 	 t        |	      }t         j                  d
|        | j                  j                  |      }	|	s7t         j                  d|        t        dd      } ||||       d {   S |j                  d      }
t        |
t              rt        |
      nd }|| j                  j                  |      k7  r5t         j                  d|       t        dd      } ||||       d {   S |j!                          d {   }t         j                  d|        	 t"        j$                  j'                  |      }t         j                  d|        t/        |      }t1        ||      }t         j                  d|        t        dd      } ||||       d {    |	j-                  |       d {    y 7 67 %7 # t        $ r; t         j                  d|        t        dd      } ||||       d {  7  cY S w xY w7 7 *7 # t(        $ rY}t         j+                  d       t        dd      } ||||       d {  7   |	j-                  |       d {  7   Y d }~y d }~ww xY w7 7 ŭw)NzHandling POST messageTr5   rL   z#Received request without session_idzsession_id is requiredi  )status_code)rV   zParsed session ID: zReceived invalid session ID: zInvalid session IDzCould not find session for ID: zCould not find sessioni  r7   z;Rejecting message for session %s: credential does not matchzReceived JSON: zValidated client message: zFailed to parse messagezCould not parse message)request_context)metadataz#Sending session message to writer: Accepted   )r)   r*   r   r   rP   query_paramsrS   warningr   r   r(   r   rT   r   r   r   bodytypesJSONRPCMessagemodel_validate_jsonr
   	exceptionr1   r   r   )r+   r/   r0   r1   r\   r]   session_id_paramresponserL   writerr7   	requestorrk   r=   errrf   rA   s                    r-   handle_post_messagez&SseServerTransport.handle_post_message   s    ,-%)  $~~>>wPT>UU'w==="//33LA#NN@A 8cJH!%$777	8"23JLL.zl;< **..z:NN<ZLIJ 8cJH!%$777yy 3=dDU3V)$/\`	,,00<< NNXZde 8cJH!%$777\\^#tf-.	**>>tDGLL5gY?@ )A(8D:?:KLMJC8ugt,,,kk/***i V= 8
  	8NN:;K:LMN 4#FH!%$7777	8 8 8#  	67 9sKH5'4000++c"""	 	-*s   AL<I:L<I=AL<)J *L</$J AL<"K
#B L<#K$L<;K<L<7K AL<L8L<4L:5L<=L< L<;K>K?KL<KL<L<L<	L5/L0LL0%L(&L0+L<0L55L<:L<)N)__name__
__module____qualname____doc__rX   __annotations__rW   r   r	   r   	Exceptionr   r   r   r&   r   r   r   r   rb   ru   __classcell__)r,   s   @r-   r   r   A   s    	 Nt%;NY<V%WWXX $ 4455**(R (R9RUY9Y (Rei (RT X7u X7w X7d X7 X7t9+u 9+w 9+d 9+W[ 9+r.   r   )+ry   rJ   
contextlibr   typingr   urllib.parser   uuidr   r   rQ   anyio.streams.memoryr   r	   pydanticr
   sse_starletter   starlette.requestsr   starlette.responsesr   starlette.typesr   r   r   	mcp.typesrl   &mcp.server.auth.middleware.bearer_authr   r   r   mcp.server.transport_securityr   r   mcp.shared.messager   r   	getLoggerrv   r)   r    r.   r-   <module>r      sf   %N  *     R $ - & ( 0 0  q q E			8	$Q+ Q+r.   