
    {h"*                        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 ddl m!Z!m"Z"  ejF                  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)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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	_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 | _        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   loggerdebug)selfr   r   	__class__s      O/var/www/html/hubwallet-dev/venv/lib/python3.12/site-packages/mcp/server/sse.pyr"   zSseServerTransport.__init__P   s    . 	 H 3 3D 9SH_PSW_P_"8* -B B  ""3'X~H!$&!45FGEhZPQ    scopereceivesendc                J  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                  <   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t(        dt*        dt,        ffd}t         j                  d       |
j/                  ||||       t         j                  d       ||f d d d       d {    y 7 7 7 |7 # 1 d {  7  sw Y   y 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   z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&   r-   r8   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+   r,   r-   c                    K    t              | ||       d{    j                          d{    j                          d{    t        j                  d        y7 M7 77 !w)z
                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+   r,   r-   read_stream_writer
session_idsse_stream_readerr@   r?   s      r)   response_wrapperz8SseServerTransport.connect_sse.<locals>.response_wrapper   sx      f)2CZde7D   )//111)00222 <ZLIJ 22s1   A0A*A0A,A0A.A0,A0.A0zStarting SSE response taskzYielding read and write streams)r%   errorr$   r   r   validate_requestr&   anyiocreate_memory_object_streamr   r   getrstripr   r   hexdictstrr   create_task_groupr   r   r   
start_soon)r'   r+   r,   r-   requesterror_responseread_streamwrite_streamr3   full_message_path_for_clienttgrI   r=   rF   rG   rH   r>   r@   r?   s               @@@@@@@r)   connect_ssezSseServerTransport.connect_ssey   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
0B!!*-4ZLAB IIk2.	 (1'7'7'<t~~'M$ #((D"E!FlS]SaSaRbc/4/P/PQUVY[^V^Q_/`ab/c,,	 **, 	. 	.Ke Kg KT K K LL56MM*E7DALL:;--'	. 	. 	.g W6b	. 	. 	. 	. 	.sn   AH#HH#2H3DH#H
H#A"H3H#>H?H#H#
H#H#H HH H#c                 t  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         j                  d|
        	 t        j                  j                  |
      }t         j                  d|        t'        |      }t)        ||      }t         j                  d|        t        dd      } ||||       d {    |	j%                  |       d {    y 7 7 7 V# t        $ r; t         j                  d|        t        dd      } ||||       d {  7  cY S w xY w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 messageTr1   rG   z#Received request without session_idzsession_id is requiredi  )status_code)rP   zParsed session ID: zReceived invalid session ID: zInvalid session IDzCould not find session for ID: zCould not find sessioni  z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   rK   query_paramsrN   warningr   r   r$   r   bodytypesJSONRPCMessagemodel_validate_jsonr
   	exceptionr-   r   r   )r'   r+   r,   r-   rU   rV   session_id_paramresponserG   writerrd   r8   errr_   r<   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\\^#tf-.	**>>tDGLL5gY?@ )A(8D:?:KLMJC8ugt,,,kk/***W V= 8
  	8NN:;K:LMN 4#FH!%$7777	8 8#  	67 9sKH5'4000++c"""	 	-*s   AJ8G9J8G<AJ8)G?*J8/$H AJ8"I	#J8:I;J87I AJ8J4J83J64J8<J8?J8;I=I >IJ8IJ8J8	J1/J,J
J,!J$"J,'J8,J11J86J8)N)__name__
__module____qualname____doc__rR   __annotations__rQ   r   r	   r   	Exceptionr   r   r"   r   r   r   r   r[   rm   __classcell__)r(   s   @r)   r   r   @   s    	 Nt%;NY<V%WWXX**'R 'R9RUY9Y 'Rei 'RR M.u M.w M.d M. M.^0+u 0+w 0+d 0+W[ 0+r*   r   )'rq   rE   
contextlibr   typingr   urllib.parser   uuidr   r   rL   anyio.streams.memoryr   r	   pydanticr
   sse_starletter   starlette.requestsr   starlette.responsesr   starlette.typesr   r   r   	mcp.typesre   mcp.server.transport_securityr   r   mcp.shared.messager   r   	getLoggerrn   r%   r    r*   r)   <module>r      s`   %N  *     R $ - & ( 0 0  E			8	$y+ y+r*   