
    iK                        d dl Z d dlZd dlZd dlZd dl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mZ d d	lmZ d d
lmZ  ee      Z G d de      Zdedee   de eef   dz  dedz  dee
z  dz  dedejB                  dejB                  de jD                  e   fdZ# G d de      Z$ G d de      Z% G d de      Z& G d de      Z' G d d e      Z( G d! d"e      Z)y)#    N)AsyncIterator)Path)TextIOcast)ClientSessionStdioServerParameters)stdio_client)Unpack)ClientTransportSessionKwargs)
get_logger)UVEnvironmentc                       e Zd ZdZ	 	 	 	 ddedee   deeef   dz  dedz  dedz  dee	z  dz  fd	Z
ej                  d
ee   dee   fd       Zd
ee   dedz  fdZd Zd Zd ZdefdZy)StdioTransportz
    Base transport for connecting to an MCP server via subprocess with stdio.

    This is a base class that can be subclassed for specific command-based
    transports like Python, Node, Uvx, etc.
    Ncommandargsenvcwd
keep_alivelog_filec                     || _         || _        || _        || _        |d}|| _        || _        d| _        d| _        t        j                         | _
        t        j                         | _        y)a  
        Initialize a Stdio transport.

        Args:
            command: The command to run (e.g., "python", "node", "uvx")
            args: The arguments to pass to the command
            env: Environment variables to set for the subprocess
            cwd: Current working directory for the subprocess
            keep_alive: Whether to keep the subprocess alive between connections.
                       Defaults to True. When True, the subprocess remains active
                       after the connection context exits, allowing reuse in
                       subsequent connections.
            log_file: Optional path or file-like object where subprocess stderr will
                   be written. Can be a Path or TextIO object. Defaults to sys.stderr
                   if not provided. When a Path is provided, the file will be created
                   if it doesn't exist, or appended to if it does. When set, server
                   errors will be written to this file instead of appearing in the console.
        NT)r   r   r   r   r   r   _session_connect_taskanyioEvent_ready_event_stop_event)selfr   r   r   r   r   r   s          o/Users/bowang/.openclaw/workspace/ChatDev/.venv/lib/python3.12/site-packages/fastmcp/client/transports/stdio.py__init__zStdioTransport.__init__   sd    6 	J$ .226!KKM ;;=    session_kwargsreturnc                x  K   	  | j                   di | d {    t        t        | j                         | j                  s| j                          d {    y t        j                  d       y 7 \7 # | j                  s| j                          d {  7   w t        j                  d       w xY ww)Nz6Stdio transport has keep_alive=True, not disconnecting )connectr   r   r   r   
disconnectloggerdebug)r   r"   s     r   connect_sessionzStdioTransport.connect_sessionG   s     	W$,,0000}dmm44??oo'''UV 1 ( ??oo'''UVsI   B:A: A6!A: B:A8B:6A: 8B:: B7BB77B:c                 "  K   | j                   y t        j                         }t        j                  t	        | j
                  | j                  | j                  | j                  | j                  || j                  | j                  |	            | _         | j                  j                          d {    | j                   j                         r| j                   j                         }||| d {   | _        | j                  S 7 W7 w)N)	r   r   r   r   r   r"   ready_event
stop_eventsession_future)r   asyncioFuturecreate_task_stdio_transport_connect_taskr   r   r   r   r   r   r   waitdone	exceptionr   )r   r"   r.   r5   s       r   r&   zStdioTransport.connectT   s      )8?8H %00)YYHHHH- --++-
  $$&&& ""$**446I$,,}} 	' -s%   B1D3D4AD5D6DDc                    K   | j                   y | j                  j                          | j                    d {    d | _         t        j                         | _        t        j                         | _        y 7 >wN)r   r   setr   r   r   r   s    r   r'   zStdioTransport.disconnectx   se     % 	      " ;;=!KKM 	!s   7A:A8?A:c                 @   K   | j                          d {    y 7 wr7   )r'   r9   s    r   closezStdioTransport.close   s     oos   c                 n    | j                   j                         s| j                   j                          yy)zcEnsure that we send a disconnection signal to the transport task if we are being garbage collected.N)r   is_setr8   r9   s    r   __del__zStdioTransport.__del__   s+    &&(  " )r!   c                 j    d| j                   j                   d| j                   d| j                   dS )N<z
(command='z', args=z)>)	__class____name__r   r   r9   s    r   __repr__zStdioTransport.__repr__   s3    ''(
4<<.SUV	
r!   )NNNN)rB   
__module____qualname____doc__strlistdictboolr   r   r    
contextlibasynccontextmanagerr
   r   r   r   r*   r&   r'   r;   r>   rC   r%   r!   r   r   r      s     &*"&)-')') 3i') #s(^d"	')
 4Z') 4K') -$&')R ##
W &} 5
W	}	%
W $
W" &} 5"		"H* #

# 
r!   r   r   r   r   r   r   r"   r,   r-   r.   c	           
         K   	 t        j                         4 d{   }		 t        | |||      }
|t        j                  }n3t        |t              r!|	j                  |j                  d            }n|}|	j                  t        |
|             d{   }|\  }}|j                  |	j                  t        ||fi |       d{          t        j                  d       |j                          |j!                          d{    t        j                  d       ddd      d{    y7 7 7 p7 1# t        j                  d       w xY w7 (# 1 d{  7  sw Y   yxY w# t"        $ r |j                           w xY ww)zA standalone connection task for a stdio transport. It is not a part of the StdioTransport class
    to ensure that the connection task does not hold a reference to the Transport object.N)r   r   r   r   a)errlogzStdio transport connectedzStdio transport disconnected)rK   AsyncExitStackr   sysstderr
isinstancer   enter_contextopenenter_async_contextr	   
set_resultr   r(   r)   r8   r3   	Exception)r   r   r   r   r   r"   r,   r-   r.   stackserver_paramslog_file_handle	transportread_streamwrite_streams                  r   r2   r2      sd    ',,..%!= 5#	! #&)jjO$/&+&9&9(--:L&MO '/O"'";"; G# 	 -6)\))33%k<R>R  89! !oo''' ;<E /.."
 ( ;<E /...F  s   FE0 D6E0 EA4D?D93D?
D;
A D?D=D?E%E0 0E1E0 5F6E0 9D?;D?=D??EEE0 E-!E$"E-)E0 ,F-E0 0FFc                        e Zd ZdZdddej
                  ddfdeez  dee   dz  de	eef   dz  dedz  dede
dz  d	eez  dz  f fd
Z xZS )PythonStdioTransportz%Transport for running Python scripts.Nscript_pathr   r   r   
python_cmdr   r   c                 :   t        |      j                         }|j                         st        d|       t	        |      j                  d      st        d|       t	        |      g}|r|j                  |       t        	| %  ||||||       || _
        y)aH  
        Initialize a Python transport.

        Args:
            script_path: Path to the Python script to run
            args: Additional arguments to pass to the script
            env: Environment variables to set for the subprocess
            cwd: Current working directory for the subprocess
            python_cmd: Python command to use (default: "python")
            keep_alive: Whether to keep the subprocess alive between connections.
                       Defaults to True. When True, the subprocess remains active
                       after the connection context exits, allowing reuse in
                       subsequent connections.
            log_file: Optional path or file-like object where subprocess stderr will
                   be written. Can be a Path or TextIO object. Defaults to sys.stderr
                   if not provided. When a Path is provided, the file will be created
                   if it doesn't exist, or appended to if it does. When set, server
                   errors will be written to this file instead of appearing in the console.
        Script not found: .pyNot a Python script: r   r   r   r   r   r   Nr   resolveis_fileFileNotFoundErrorrG   endswith
ValueErrorextendsuperr    ra   )
r   ra   r   r   r   rb   r   r   	full_argsrA   s
            r   r    zPythonStdioTransport.__init__   s    : ;'//1""$#&8$FGG;((/4[MBCC%&	T"! 	 	
 'r!   )rB   rD   rE   rF   rQ   
executablerG   r   rH   rI   rJ   r   r    __classcell__rA   s   @r   r`   r`      s    /
 "&%).."&)-/'4Z/' 3i$/' #s(^d"	/'
 4Z/' /' 4K/' -$&/' /'r!   r`   c                        e Zd ZdZ	 	 	 	 	 d
deez  dee   dz  deeef   dz  dedz  dedz  dee	z  dz  f fd	Z
 xZS )FastMCPStdioTransportz<Transport for running FastMCP servers using the FastMCP CLI.Nra   r   r   r   r   r   c                    t        |      j                         }|j                         st        d|       t	        |      j                  d      st        d|       t        | !  ddt	        |      g||||       || _	        y )Nrd   re   rf   fastmcprunrg   )
r   ri   rj   rk   rG   rl   rm   ro   r    ra   )r   ra   r   r   r   r   r   rA   s          r   r    zFastMCPStdioTransport.__init__  s     ;'//1""$#&8$FGG;((/4[MBCC[)*! 	 	
 'r!   )NNNNNrB   rD   rE   rF   rG   r   rH   rI   rJ   r   r    rr   rs   s   @r   ru   ru     s    F
 "&%)"&)-'4Z' 3i$' #s(^d"	'
 4Z' 4K' -$&' 'r!   ru   c                        e Zd ZdZ	 	 	 	 	 	 ddeez  dee   dz  deeef   dz  dedz  dededz  d	ee	z  dz  f fd
Z
 xZS )NodeStdioTransportz&Transport for running Node.js scripts.Nra   r   r   r   node_cmdr   r   c                 :   t        |      j                         }|j                         st        d|       t	        |      j                  d      st        d|       t	        |      g}|r|j                  |       t        	| %  ||||||       || _
        y)aD  
        Initialize a Node transport.

        Args:
            script_path: Path to the Node.js script to run
            args: Additional arguments to pass to the script
            env: Environment variables to set for the subprocess
            cwd: Current working directory for the subprocess
            node_cmd: Node.js command to use (default: "node")
            keep_alive: Whether to keep the subprocess alive between connections.
                       Defaults to True. When True, the subprocess remains active
                       after the connection context exits, allowing reuse in
                       subsequent connections.
            log_file: Optional path or file-like object where subprocess stderr will
                   be written. Can be a Path or TextIO object. Defaults to sys.stderr
                   if not provided. When a Path is provided, the file will be created
                   if it doesn't exist, or appended to if it does. When set, server
                   errors will be written to this file instead of appearing in the console.
        rd   z.jszNot a JavaScript script: rg   Nrh   )
r   ra   r   r   r   r|   r   r   rp   rA   s
            r   r    zNodeStdioTransport.__init__"  s    : ;'//1""$#&8$FGG;((/8FGG%&	T"! 	 	
 'r!   )NNNnodeNNry   rs   s   @r   r{   r{     s    0
 "&%)"&)-/'4Z/' 3i$/' #s(^d"	/'
 4Z/' /' 4K/' -$&/' /'r!   r{   c                        e Zd ZdZ	 	 	 	 	 	 	 	 ddedee   dz  dededz  dedz  dee   dz  d	edz  d
eeef   dz  dedz  f fdZ	 xZ
S )UvStdioTransportz/Transport for running commands via the uv tool.Nr   r   moduleproject_directorypython_versionwith_packageswith_requirementsenv_varsr   c
                    |r|j                         st        d|       t        ||||d       }
g }|
j                         rsdg}|r|j	                  d|g       |r|j	                  dt        |      g       |xs g D ]  }|j	                  d|g        |r |j	                  dt        |      g       ndg}|r|j                  d       |sg }|j	                  |g|       d }|s|rAt        j                  j                         }|rt        |      |d	<   |r|j                  |       t        | 1  d
||d |	       y )NProject directory not found: )pythondependenciesrequirementsprojecteditablerx   --pythonz--directory--withz--with-requirementsz--moduleUV_PROJECT_DIRuvr   r   r   r   r   )existsNotADirectoryErrorr   _must_run_with_uvrn   rG   appendosenvironcopyupdatero   r    )r   r   r   r   r   r   r   r   r   r   
env_configuv_argspkgr   rA   s                 r   r    zUvStdioTransport.__init__W  sh    %6%=%=%?$/0A/BC 
 #!&*%

   '') gG
N;< s3D/EFG %**#/ +  5s;L7MNO gGNN:&D'$'( &*(**//#C (+,=(>$%

8$! 	 	
r!   )NFNNNNNN)rB   rD   rE   rF   rG   rH   rJ   r   rI   r    rr   rs   s   @r   r   r   T  s    9
 "&)-%)*.)-*."&I
I
 3i$I
 	I

  $;I
 d
I
 Cy4'I
  $;I
 sCx.4'I
 4KI
 I
r!   r   c                        e Zd ZdZ	 	 	 	 	 	 	 ddedee   dz  dedz  dedz  dee   dz  dedz  d	eeef   dz  d
edz  f fdZ xZ	S )UvxStdioTransportz0Transport for running commands via the uvx tool.N	tool_name	tool_argsr   r   r   from_packager   r   c	                    |r't        |      j                         st        d|       g }	|r|	j                  d|g       |r|	j                  d|g       |xs g D ]  }
|	j                  d|
g        |	j	                  |       |r|	j                  |       d}|r/t
        j                  j                         }|j                  |       t        | )  d|	|||       || _        y)a  
        Initialize a Uvx transport.

        Args:
            tool_name: Name of the tool to run via uvx
            tool_args: Arguments to pass to the tool
            project_directory: Project directory (for package resolution)
            python_version: Python version to use
            with_packages: Additional packages to include
            from_package: Package to install the tool from
            env_vars: Additional environment variables
            keep_alive: Whether to keep the subprocess alive between connections.
                       Defaults to True. When True, the subprocess remains active
                       after the connection context exits, allowing reuse in
                       subsequent connections.
        r   r   z--fromr   Nuvxr   )r   r   r   rn   r   r   r   r   r   ro   r    r   )r   r   r   r   r   r   r   r   r   uvx_argsr   r   rA   s               r   r    zUvxStdioTransport.__init__  s    8 T*;%<%C%C%E$/0A/BC 
 !OOZ89OOX|45 &B&COOXsO, ' 		"OOI&%)**//#CJJx !! 	 	
 (r!   )NNNNNNN
rB   rD   rE   rF   rG   rH   rI   rJ   r    rr   rs   s   @r   r   r     s    :
 '+(,%)*.#'*."&;(;( 9t#;( :	;(
 d
;( Cy4';( Dj;( sCx.4';( 4K;( ;(r!   r   c                   p     e Zd ZdZ	 	 	 	 	 d
dedee   dz  dedz  deeef   dz  dededz  f fd	Z xZ	S )NpxStdioTransportz0Transport for running commands via the npx tool.Npackager   r   r   use_package_lockr   c                    t        j                  d      t        d      |r't        |      j	                         st        d|       g }|r|j                  d       |j                  |       |r|j                  |       d}|r/t        j                  j                         }|j                  |       t        	| 5  d||||       || _        y)a  
        Initialize an Npx transport.

        Args:
            package: Name of the npm package to run
            args: Arguments to pass to the package command
            project_directory: Project directory with package.json
            env_vars: Additional environment variables
            use_package_lock: Whether to use package-lock.json (--prefer-offline)
            keep_alive: Whether to keep the subprocess alive between connections.
                       Defaults to True. When True, the subprocess remains active
                       after the connection context exits, allowing reuse in
                       subsequent connections.
        npxNzCommand 'npx' not foundr   z--prefer-offliner   )shutilwhichrm   r   r   r   r   rn   r   r   r   r   ro   r    r   )
r   r   r   r   r   r   r   npx_argsr   rA   s
            r   r    zNpxStdioTransport.__init__  s    0 <<&677 T*;%<%C%C%E$/0A/BC 
 OO./ 	 OOD! **//#CJJx !! 	 	
 r!   )NNNTNr   rs   s   @r   r   r     sy    :
 "&(,*.!%"&88 3i$8 :	8
 sCx.4'8 8 4K8 8r!   r   )*r/   rK   r   r   rQ   collections.abcr   pathlibr   typingr   r   r   mcpr   r   mcp.client.stdior	   typing_extensionsr
   fastmcp.client.transports.baser   r   fastmcp.utilities.loggingr   6fastmcp.utilities.mcp_server_config.v1.environments.uvr   rB   r(   r   rG   rH   rI   r   r0   r2   r`   ru   r{   r   r   r   r%   r!   r   <module>r      s$     	  
 )    4 ) $ I 0 P	H	|
_ |
~55
s)5 
c3h$	5 
t	5
 Vmd"5 "5 5 5 NN=15p2'> 2'j'N ':2' 2'jL
~ L
^>( >(B; ;r!   