o
    a)iv                     @  s   d Z ddlmZ ddlZddlZddlmZmZmZm	Z	 ddl
Z
G dd deZG dd dZdddZedkr@ee  dS dS )z6
Lightweight MCP SSE client shared by test utilities.
    )annotationsN)AnyDictListOptionalc                   @  s   e Zd ZdZdS )MCPClientErrorz)Generic error raised by the MCPSSEClient.N)__name__
__module____qualname____doc__ r   r   a/Users/divyeshpatel/Desktop/sahana/Recommender/recommender_rl/recommender/tests/mcp_sse_client.pyr      s    r   c                   @  s   e Zd ZdZ		d0d1ddZdd Zdd Zd2ddZed3ddZ	d4d5ddZ
d6dd Zd7d"d#Zd8d&d'Zd6d(d)Zed9d+d,Zed:d.d/ZdS );MCPSSEClientzEMinimal SSE transport client for MCP servers such as api.recomai.one.N      >@base_urlstrauth_keychatbot_keyOptional[str]timeoutfloatc                 C  sr   | d}d|v rdnd}| | d| | _|| _|| _|p || _|| _d| _d | _i | _i | _	g | _
d| _d S )N/?&zauthKey=r   F)rstripurlr   r   r   r   
request_idhttp_clientserver_infocapabilities	mcp_toolsinitialized)selfr   r   r   r   	separatorr   r   r   __init__   s   


zMCPSSEClient.__init__c                   s   |   I d H  | S N)connectr"   r   r   r   
__aenter__,   s   zMCPSSEClient.__aenter__c                   s   |   I d H  d S r%   )
disconnect)r"   exc_typeexctbr   r   r   	__aexit__0   s   zMCPSSEClient.__aexit__returnintc                 C  s   |  j d7  _ | j S )N   )r   r'   r   r   r   _next_id3   s   zMCPSSEClient._next_idtextOptional[Dict[str, Any]]c                 C  s0   |    }dd |D }|sd S t|d S )Nc                 S  s$   g | ]}| d r|d ddqS )zdata:  r0   )
startswithreplace).0liner   r   r   
<listcomp>:   s   $ z4MCPSSEClient._parse_sse_response.<locals>.<listcomp>r   )strip
splitlinesjsonloads)r2   lines
data_linesr   r   r   _parse_sse_response7   s
   z MCPSSEClient._parse_sse_responsemethodparamsDict[str, Any]c                   s   | j stdd|  ||pi d}ddd}| j j| j||dI d H }|jdkr6td	|j d
|j | |j}|d u rHtd|j d|v r`|d }td|d d
|d |di S )NzClient is not connectedz2.0)ZjsonrpcidrA   rB   z#application/json, text/event-streamapplication/json)ZAcceptzContent-Type)r<   headers   zHTTP z: zMalformed SSE payload: errorz
MCP error codemessageresult)	r   r   r1   postr   Zstatus_coder2   r@   get)r"   rA   rB   payloadrF   responseparsedrH   r   r   r   _send_request?   s*   
 zMCPSSEClient._send_requestNonec                   s   | j rd S tj| jd| _td | ddi i ddddd	I d H }|d
i | _|di | _	d| _ | jdd}| jdd}td| d|  d S )N)r   u    🔗 Connecting to MCP server...Z
initializez
2024-11-05)rootsZsamplingzrecommender-data-loaderz0.1.0)nameversion)ZprotocolVersionr   Z
clientInfoZ
serverInfor   TrT   unknownrU   r   u   ✅ Connected to z v)
r!   httpxZAsyncClientr   r   printrQ   rM   r   r   )r"   rK   serverrU   r   r   r   r&   Y   s$   
zMCPSSEClient.connectList[Dict[str, Any]]c                   s6   | j std| di I d H }|dg | _| jS )Nz-connect() must be called before listing toolsz
tools/listtools)r!   r   rQ   rM   r    )r"   rK   r   r   r   
list_toolsn   s   zMCPSSEClient.list_tools	tool_name	argumentsc                   s(   | j std| d||dI d H S )Nz+connect() must be called before using toolsz
tools/call)rT   r^   )r!   r   rQ   )r"   r]   r^   r   r   r   	call_toolu   s   zMCPSSEClient.call_toolc                   s0   | j r| j  I d H  d | _ d| _td d S )NFu"   🔌 Disconnected from MCP server.)r   acloser!   rX   r'   r   r   r   r)   z   s   zMCPSSEClient.disconnectrK   c                 C  sr   |  d}t|tsd S |D ](}t|tsq| d}|r!|  S | ddkr6| d}t|tr6|  S qd S )Ncontentr2   typerE   data)rM   
isinstancelistdictr   )rK   ra   blockr2   rc   r   r   r   extract_text_content   s   





z!MCPSSEClient.extract_text_contentOptional[Any]c                 C  s6   t | }|s	d S zt|W S  tjy   Y d S w r%   )r   rh   r<   r=   JSONDecodeError)rK   r2   r   r   r   extract_json_content   s   
z!MCPSSEClient.extract_json_content)Nr   )r   r   r   r   r   r   r   r   )r.   r/   )r2   r   r.   r3   r%   )rA   r   rB   r3   r.   rC   r.   rR   )r.   rZ   )r]   r   r^   rC   r.   rC   )rK   rC   r.   r   )rK   rC   r.   ri   )r   r	   r
   r   r$   r(   r-   r1   staticmethodr@   rQ   r&   r\   r_   r)   rh   rk   r   r   r   r   r      s&    




r   r.   rR   c                    s   ddl } ddl}| jdd}|jdddd |jd	d
dd | }t|jp)d
}t|	dd|	dd|	dd}z+|
 I dH  ||j|I dH }||}t|p]tj|dd W | I dH  dS | I dH  w )z$Small CLI helper for manual testing.r   NzCall an MCP SSE tool directly.)descriptionz--toolTzTool name to invoke.)requiredhelpz	--payloadz{}zJSON string payload.)defaultrp   MCP_URLzhttps://api.recomai.one/mcpMCP_AUTH_KEYr4   MCP_CHATBOT_KEY)r   r   r      )indent)argparseosArgumentParseradd_argument
parse_argsr<   r=   rN   r   getenvr&   r_   toolrh   rX   dumpsr)   )rw   rx   parserargsrN   clientrK   r2   r   r   r   main   s&   


"r   __main__rl   )r   
__future__r   asyncior<   typingr   r   r   r   rW   RuntimeErrorr   r   r   r   runr   r   r   r   <module>   s    
