o
    h h                     @  s  d dl mZ d dlZd dlZd dlZd dlmZ d dlmZm	Z	 d dl
mZ d dlmZ d dlmZmZmZmZmZ d dlmZmZ d d	lmZmZmZmZ d d
lmZ d dlm Z m!Z! d dl"m#Z# d dl$m%Z%m&Z&m'Z'm(Z( d dl)m*Z*m+Z+ ddl,m-Z- ddl.m.Z. ddl/m0Z0 ddl1m2Z2m3Z3m4Z4 edZ5erddl6m7Z7 G dd dej8Z9G dd de9ej8Z:G dd de+Z;G dd de:Z<G dd  d e+Z=G d!d" d"e:Z>G d#d$ d$e+Z?G d%d& d&e:Z@dS )'    )annotationsN)	Awaitable)AbstractAsyncContextManagerAsyncExitStack)	timedelta)Path)TYPE_CHECKINGAnyCallableLiteralTypeVar)MemoryObjectReceiveStreamMemoryObjectSendStream)ClientSessionStdioServerParametersToolstdio_client)
sse_client)GetSessionIdCallbackstreamablehttp_client)SessionMessage)CallToolResultGetPromptResultInitializeResultListPromptsResult)NotRequired	TypedDict   )	UserError)logger)RunContextWrapper   )
ToolFilterToolFilterContextToolFilterStaticT)	AgentBasec                   @  s   e Zd ZdZd$d%ddZejdd Zeejd&ddZ	ejdd Z
ej		d'd(ddZejd)ddZejd*ddZej	d+d,d"d#ZdS )-	MCPServerz.Base class for Model Context Protocol servers.Fuse_structured_contentboolc                 C  s
   || _ dS )a  
        Args:
            use_structured_content: Whether to use `tool_result.structured_content` when calling an
                MCP tool.Defaults to False for backwards compatibility - most MCP servers still
                include the structured content in the `tool_result.content`, and using it by
                default will cause duplicate content. You can set this to True if you know the
                server will not duplicate the structured content in the `tool_result.content`.
        Nr(   )selfr(    r,   R/var/www/html/openai_agents/venv/lib/python3.10/site-packages/agents/mcp/server.py__init__"   s   
	zMCPServer.__init__c                      dS )zConnect to the server. For example, this might mean spawning a subprocess or
        opening a network connection. The server is expected to remain connected until
        `cleanup()` is called.
        Nr,   r+   r,   r,   r-   connect-   s   zMCPServer.connectreturnstrc                 C     dS )A readable name for the server.Nr,   r0   r,   r,   r-   name5   s   zMCPServer.namec                   r/   )zwCleanup the server. For example, this might mean closing a subprocess or
        closing a network connection.
        Nr,   r0   r,   r,   r-   cleanup;      zMCPServer.cleanupNrun_contextRunContextWrapper[Any] | NoneagentAgentBase | Nonelist[MCPTool]c                   r/   )'List the tools available on the server.Nr,   )r+   r9   r;   r,   r,   r-   
list_toolsB   s   zMCPServer.list_tools	tool_name	argumentsdict[str, Any] | Noner   c                   r/   )Invoke a tool on the server.Nr,   r+   r@   rA   r,   r,   r-   	call_toolK   s   zMCPServer.call_toolr   c                   r/   ))List the prompts available on the server.Nr,   r0   r,   r,   r-   list_promptsP   r8   zMCPServer.list_promptsr6   r   c                   r/   )&Get a specific prompt from the server.Nr,   r+   r6   rA   r,   r,   r-   
get_promptW   r8   zMCPServer.get_prompt)F)r(   r)   r2   r3   NNr9   r:   r;   r<   r2   r=   r@   r3   rA   rB   r2   r   r2   r   Nr6   r3   rA   rB   r2   r   )__name__
__module____qualname____doc__r.   abcabstractmethodr1   propertyr6   r7   r?   rE   rG   rJ   r,   r,   r,   r-   r'      s*    

r'   c                      s   e Zd ZdZ				dFdG fddZdHddZdIddZdHd d!Zej	dJd#d$Z
d%d& Zd'd( Zd)d* ZdKd.d/Zd0d1 Z		dLdMd4d5ZdNd;d<ZdOd>d?Z	dPdQdBdCZdDdE Z  ZS )R_MCPServerWithClientSessionzUBase class for MCP servers that use a `ClientSession` to communicate with the server.NFr         ?cache_tools_listr)   client_session_timeout_secondsfloat | Nonetool_filterr"   r(   max_retry_attemptsintretry_backoff_seconds_basefloatc                   sZ   t  j|d d| _t | _t | _|| _d| _	|| _
|| _|| _d| _d| _|| _dS )a  
        Args:
            cache_tools_list: Whether to cache the tools list. If `True`, the tools list will be
            cached and only fetched from the server once. If `False`, the tools list will be
            fetched from the server on each call to `list_tools()`. The cache can be invalidated
            by calling `invalidate_tools_cache()`. You should set this to `True` if you know the
            server will not change its tools list, because it can drastically improve latency
            (by avoiding a round-trip to the server every time).

            client_session_timeout_seconds: the read timeout passed to the MCP ClientSession.
            tool_filter: The tool filter to use for filtering tools.
            use_structured_content: Whether to use `tool_result.structured_content` when calling an
                MCP tool. Defaults to False for backwards compatibility - most MCP servers still
                include the structured content in the `tool_result.content`, and using it by
                default will cause duplicate content. You can set this to True if you know the
                server will not duplicate the structured content in the `tool_result.content`.
            max_retry_attempts: Number of times to retry failed list_tools/call_tool calls.
                Defaults to no retries.
            retry_backoff_seconds_base: The base delay, in seconds, used for exponential
                backoff between retries.
        r*   NT)superr.   sessionr   
exit_stackasyncioLock_cleanup_lockr[   server_initialize_resultr\   r_   ra   _cache_dirty_tools_listr^   )r+   r[   r\   r^   r(   r_   ra   	__class__r,   r-   r.   b   s   

z$_MCPServerWithClientSession.__init__toolsr=   r9   RunContextWrapper[Any]r;   r&   r2   c                   s>   | j du r|S t| j tr| || j S | |||I dH S )z+Apply the tool filter to the list of tools.N)r^   
isinstancedict_apply_static_tool_filter_apply_dynamic_tool_filter)r+   rn   r9   r;   r,   r,   r-   _apply_tool_filter   s   
z._MCPServerWithClientSession._apply_tool_filterstatic_filterr$   c                   sL   |}d|v r|d   fdd|D }d|v r$|d fdd|D }|S )z=Apply static tool filtering based on allowlist and blocklist.allowed_tool_namesc                   s   g | ]	}|j  v r|qS r,   r6   .0t)allowed_namesr,   r-   
<listcomp>       zI_MCPServerWithClientSession._apply_static_tool_filter.<locals>.<listcomp>blocked_tool_namesc                   s   g | ]	}|j  vr|qS r,   rw   rx   )blocked_namesr,   r-   r|      r}   r,   )r+   rn   ru   filtered_toolsr,   )r{   r   r-   rr      s   z5_MCPServerWithClientSession._apply_static_tool_filterc                   s   t | js
td| j}t||| jd}g }|D ]?}z|||}t|r,|I dH }	n|}	|	r5|| W q tyX }
 zt	
d|j d| j d|
  W Y d}
~
qd}
~
ww |S )z>Apply dynamic tool filtering using a callable filter function.z2Tool filter must be callable for dynamic filtering)r9   r;   server_nameNz$Error applying tool filter to tool 'z' on server 'z': )callabler^   
ValueErrorr#   r6   inspectisawaitableappend	Exceptionr   error)r+   rn   r9   r;   tool_filter_funcfilter_contextr   toolresultshould_includeer,   r,   r-   rs      s6   
	


z6_MCPServerWithClientSession._apply_dynamic_tool_filterAbstractAsyncContextManager[tuple[MemoryObjectReceiveStream[SessionMessage | Exception], MemoryObjectSendStream[SessionMessage], GetSessionIdCallback | None]]c                 C  r4   )"Create the streams for the server.Nr,   r0   r,   r,   r-   create_streams   s   z*_MCPServerWithClientSession.create_streamsc                   s   |   I d H  | S rP   )r1   r0   r,   r,   r-   
__aenter__   s   z&_MCPServerWithClientSession.__aenter__c                   s   |   I d H  d S rP   )r7   )r+   exc_type	exc_value	tracebackr,   r,   r-   	__aexit__   s   z%_MCPServerWithClientSession.__aexit__c                 C  s
   d| _ dS )zInvalidate the tools cache.TN)rj   r0   r,   r,   r-   invalidate_tools_cache   s   
z2_MCPServerWithClientSession.invalidate_tools_cachefuncCallable[[], Awaitable[T]]r%   c                   sl   d}	 z| I d H W S  t y4   |d7 }| jdkr!|| jkr! | jd|d   }t|I d H  Y nw q)Nr   Tr!   r   )r   r_   ra   rf   sleep)r+   r   attemptsbackoffr,   r,   r-   _run_with_retries   s   z-_MCPServerWithClientSession._run_with_retriesc              
     s   z6| j |  I dH }|^}}}| j t||| jr!t| jdndI dH }| I dH }|| _|| _W dS  t	yS } zt
d|  |  I dH   d}~ww )zConnect to the server.N)secondszError initializing MCP server: )re   enter_async_contextr   r   r\   r   
initializeri   rd   r   r   r   r7   )r+   	transportreadwrite_rd   server_resultr   r,   r,   r-   r1     s,   

	z#_MCPServerWithClientSession.connectr:   r<   c                   s   | j std| j   dusJ | jr| js| jr| j}n|  fddI dH }|j| _d| _| j}|}| jdurQ|du sC|du rGtd| |||I dH }|S )r>   =Server not initialized. Make sure you call `connect()` first.Nc                     s      S rP   )r?   r,   rd   r,   r-   <lambda>-  s    z8_MCPServerWithClientSession.list_tools.<locals>.<lambda>Fz=run_context and agent are required for dynamic tool filtering)	rd   r   r[   rj   rk   r   rn   r^   rt   )r+   r9   r;   rn   r   r   r,   r   r-   r?     s"   
z&_MCPServerWithClientSession.list_toolsr@   r3   rA   rB   r   c                   s>   | j std| j dusJ |  fddI dH S )rC   r   Nc                     s     S rP   )rE   r,   rA   rd   r@   r,   r-   r   A  s    z7_MCPServerWithClientSession.call_tool.<locals>.<lambda>)rd   r   r   rD   r,   r   r-   rE   :  s   z%_MCPServerWithClientSession.call_toolr   c                   s    | j std| j  I dH S )rF   r   N)rd   r   rG   r0   r,   r,   r-   rG   C  s   z(_MCPServerWithClientSession.list_promptsr6   r   c                   s$   | j std| j ||I dH S )rH   r   N)rd   r   rJ   rI   r,   r,   r-   rJ   L  s   z&_MCPServerWithClientSession.get_promptc                   s   | j 4 I dH ; z*z
| j I dH  W n ty. } ztd|  W Y d}~nd}~ww W d| _nd| _w W d  I dH  dS 1 I dH sIw   Y  dS )zCleanup the server.NzError cleaning up server: )rh   re   acloser   r   r   rd   )r+   r   r,   r,   r-   r7   U  s   .z#_MCPServerWithClientSession.cleanup)NFr   rZ   )r[   r)   r\   r]   r^   r"   r(   r)   r_   r`   ra   rb   )rn   r=   r9   ro   r;   r&   r2   r=   )rn   r=   ru   r$   r2   r=   r2   r   )r   r   r2   r%   rL   rM   rN   rO   rP   rQ   )rR   rS   rT   rU   r.   rt   rr   rs   rV   rW   r   r   r   r   r   r1   r?   rE   rG   rJ   r7   __classcell__r,   r,   rl   r-   rY   _   s2    
/

*


	
	rY   c                   @  sL   e Zd ZU dZded< 	 ded< 	 ded< 	 ded	< 	 d
ed< 	 ded< dS )MCPServerStdioParamszkMirrors `mcp.client.stdio.StdioServerParameters`, but lets you pass params without another
    import.
    r3   commandzNotRequired[list[str]]argsNotRequired[dict[str, str]]envzNotRequired[str | Path]cwdzNotRequired[str]encodingz3NotRequired[Literal['strict', 'ignore', 'replace']]encoding_error_handlerNrR   rS   rT   rU   __annotations__r,   r,   r,   r-   r   `  s   
 r   c                      J   e Zd ZdZ							dd  fddZd!ddZed"ddZ  ZS )#MCPServerStdiozMCP server implementation that uses the stdio transport. See the [spec]
    (https://spec.modelcontextprotocol.io/specification/2024-11-05/basic/transports/#stdio) for
    details.
    FN   r   rZ   paramsr   r[   r)   r6   
str | Noner\   r]   r^   r"   r(   r_   r`   ra   rb   c	           	   
     sl   t  |||||| t|d |dg |d|d|dd|ddd	| _|p2d
| jj | _dS )a  Create a new MCP server based on the stdio transport.

        Args:
            params: The params that configure the server. This includes the command to run to
                start the server, the args to pass to the command, the environment variables to
                set for the server, the working directory to use when spawning the process, and
                the text encoding used when sending/receiving messages to the server.
            cache_tools_list: Whether to cache the tools list. If `True`, the tools list will be
                cached and only fetched from the server once. If `False`, the tools list will be
                fetched from the server on each call to `list_tools()`. The cache can be
                invalidated by calling `invalidate_tools_cache()`. You should set this to `True`
                if you know the server will not change its tools list, because it can drastically
                improve latency (by avoiding a round-trip to the server every time).
            name: A readable name for the server. If not provided, we'll create one from the
                command.
            client_session_timeout_seconds: the read timeout passed to the MCP ClientSession.
            tool_filter: The tool filter to use for filtering tools.
            use_structured_content: Whether to use `tool_result.structured_content` when calling an
                MCP tool. Defaults to False for backwards compatibility - most MCP servers still
                include the structured content in the `tool_result.content`, and using it by
                default will cause duplicate content. You can set this to True if you know the
                server will not duplicate the structured content in the `tool_result.content`.
            max_retry_attempts: Number of times to retry failed list_tools/call_tool calls.
                Defaults to no retries.
            retry_backoff_seconds_base: The base delay, in seconds, for exponential
                backoff between retries.
        r   r   r   r   r   zutf-8r   strict)r   r   r   r   r   r   zstdio: N)rc   r.   r   getr   r   _name	r+   r   r[   r6   r\   r^   r(   r_   ra   rl   r,   r-   r.     s"   &	


	zMCPServerStdio.__init__r2   r   c                 C  s
   t | jS )r   )r   r   r0   r,   r,   r-   r     s   

zMCPServerStdio.create_streamsr3   c                 C     | j S r5   r   r0   r,   r,   r-   r6        zMCPServerStdio.nameFNr   NFr   rZ   )r   r   r[   r)   r6   r   r\   r]   r^   r"   r(   r)   r_   r`   ra   rb   r   rK   	rR   rS   rT   rU   r.   r   rX   r6   r   r,   r,   rl   r-   r   }  s    
:r   c                   @  s8   e Zd ZU dZded< 	 ded< 	 ded< 	 ded< d	S )
MCPServerSseParamsz1Mirrors the params in`mcp.client.sse.sse_client`.r3   urlr   headerszNotRequired[float]timeoutsse_read_timeoutNr   r,   r,   r,   r-   r     s   
 r   c                      r   )#MCPServerSsezMCP server implementation that uses the HTTP with SSE transport. See the [spec]
    (https://spec.modelcontextprotocol.io/specification/2024-11-05/basic/transports/#http-with-sse)
    for details.
    FNr   r   rZ   r   r   r[   r)   r6   r   r\   r]   r^   r"   r(   r_   r`   ra   rb   c	           	        6   t  |||||| || _|pd| jd  | _dS )am  Create a new MCP server based on the HTTP with SSE transport.

        Args:
            params: The params that configure the server. This includes the URL of the server,
                the headers to send to the server, the timeout for the HTTP request, and the
                timeout for the SSE connection.

            cache_tools_list: Whether to cache the tools list. If `True`, the tools list will be
                cached and only fetched from the server once. If `False`, the tools list will be
                fetched from the server on each call to `list_tools()`. The cache can be
                invalidated by calling `invalidate_tools_cache()`. You should set this to `True`
                if you know the server will not change its tools list, because it can drastically
                improve latency (by avoiding a round-trip to the server every time).

            name: A readable name for the server. If not provided, we'll create one from the
                URL.

            client_session_timeout_seconds: the read timeout passed to the MCP ClientSession.
            tool_filter: The tool filter to use for filtering tools.
            use_structured_content: Whether to use `tool_result.structured_content` when calling an
                MCP tool. Defaults to False for backwards compatibility - most MCP servers still
                include the structured content in the `tool_result.content`, and using it by
                default will cause duplicate content. You can set this to True if you know the
                server will not duplicate the structured content in the `tool_result.content`.
            max_retry_attempts: Number of times to retry failed list_tools/call_tool calls.
                Defaults to no retries.
            retry_backoff_seconds_base: The base delay, in seconds, for exponential
                backoff between retries.
        zsse: r   Nrc   r.   r   r   r   rl   r,   r-   r.     s   (	zMCPServerSse.__init__r2   r   c                 C  s4   t | jd | jdd| jdd| jdddS )	r   r   r   Nr   r   r   ,  )r   r   r   r   )r   r   r   r0   r,   r,   r-   r     s   
zMCPServerSse.create_streamsr3   c                 C  r   r   r   r0   r,   r,   r-   r6   *  r   zMCPServerSse.namer   )r   r   r[   r)   r6   r   r\   r]   r^   r"   r(   r)   r_   r`   ra   rb   r   rK   r   r,   r,   rl   r-   r     s    
4r   c                   @  sB   e Zd ZU dZded< 	 ded< 	 ded< 	 ded< 	 d	ed
< dS )MCPServerStreamableHttpParamszHMirrors the params in`mcp.client.streamable_http.streamablehttp_client`.r3   r   r   r   zNotRequired[timedelta | float]r   r   zNotRequired[bool]terminate_on_closeNr   r,   r,   r,   r-   r   0  s   
 r   c                      r   )#MCPServerStreamableHttpzMCP server implementation that uses the Streamable HTTP transport. See the [spec]
    (https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#streamable-http)
    for details.
    FNr   r   rZ   r   r   r[   r)   r6   r   r\   r]   r^   r"   r(   r_   r`   ra   rb   c	           	        r   )a  Create a new MCP server based on the Streamable HTTP transport.

        Args:
            params: The params that configure the server. This includes the URL of the server,
                the headers to send to the server, the timeout for the HTTP request, and the
                timeout for the Streamable HTTP connection and whether we need to
                terminate on close.

            cache_tools_list: Whether to cache the tools list. If `True`, the tools list will be
                cached and only fetched from the server once. If `False`, the tools list will be
                fetched from the server on each call to `list_tools()`. The cache can be
                invalidated by calling `invalidate_tools_cache()`. You should set this to `True`
                if you know the server will not change its tools list, because it can drastically
                improve latency (by avoiding a round-trip to the server every time).

            name: A readable name for the server. If not provided, we'll create one from the
                URL.

            client_session_timeout_seconds: the read timeout passed to the MCP ClientSession.
            tool_filter: The tool filter to use for filtering tools.
            use_structured_content: Whether to use `tool_result.structured_content` when calling an
                MCP tool. Defaults to False for backwards compatibility - most MCP servers still
                include the structured content in the `tool_result.content`, and using it by
                default will cause duplicate content. You can set this to True if you know the
                server will not duplicate the structured content in the `tool_result.content`.
            max_retry_attempts: Number of times to retry failed list_tools/call_tool calls.
                Defaults to no retries.
            retry_backoff_seconds_base: The base delay, in seconds, for exponential
                backoff between retries.
        zstreamable_http: r   Nr   r   rl   r,   r-   r.   I  s   )	z MCPServerStreamableHttp.__init__r2   r   c              	   C  s@   t | jd | jdd| jdd| jdd| jdd	d
S )r   r   r   Nr   r   r   r   r   T)r   r   r   r   r   )r   r   r   r0   r,   r,   r-   r   ~  s   
z&MCPServerStreamableHttp.create_streamsr3   c                 C  r   r   r   r0   r,   r,   r-   r6     r   zMCPServerStreamableHttp.namer   )r   r   r[   r)   r6   r   r\   r]   r^   r"   r(   r)   r_   r`   ra   rb   r   rK   r   r,   r,   rl   r-   r   C  s    
5r   )A
__future__r   rV   rf   r   collections.abcr   
contextlibr   r   datetimer   pathlibr   typingr   r	   r
   r   r   anyio.streams.memoryr   r   mcpr   r   r   MCPToolr   mcp.client.sser   mcp.client.streamable_httpr   r   mcp.shared.messager   	mcp.typesr   r   r   r   typing_extensionsr   r   
exceptionsr   r   r9   r    utilr"   r#   r$   r%   r;   r&   ABCr'   rY   r   r   r   r   r   r   r,   r,   r,   r-   <module>   sB    @  RQ