
    [ǻiQ                        d 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mZmZ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 dd	lmZ dd
lmZm Z  ddl!m"Z"m#Z#m$Z$m%Z%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/m0Z0m1Z1 ddl2m3Z3m4Z4m5Z5 ddl6m7Z7m8Z8 	 ddl9m:Z: dZ;eez  ez  Z=e;re>e=   e
z  e:z  Z?ne>e=   e
z  Z?dZ@ G d de      ZAde$de=fdZBde4deCe?eAdz  f   fdZDdee3gee4   f   de>e5   dz  dee3gee4   f   fdZEdede>e*   fd ZFdddddd!dedz  d"e*d#e7dz  d$e0dz  de>e5   dz  d%eGdz  d&eHdefd'ZIdddddd!dedz  d#e7dz  d$e0dz  de>e5   dz  d%eGdz  d&eHde>e   fd(ZJd"ede>eG   fd)ZKd"edefd*ZLy# e<$ r dZ;Y w xY w)+zTools adapter for converting MCP tools to LangChain tools.

This module provides functionality to convert MCP tools into LangChain-compatible
tools, handle tool execution, and manage tool conversion between the two formats.
    )	AwaitableCallable)	AnnotatedAny	TypedDictget_args)ToolMessage)FileContentBlockImageContentBlockTextContentBlockcreate_file_blockcreate_image_blockcreate_text_block)BaseToolInjectedToolArgStructuredToolToolException)get_all_basemodel_annotations)ClientSession)Tool)ArgModelBaseFuncMetadata)AudioContentBlobResourceContentsContentBlockEmbeddedResourceImageContentResourceLinkTextContentTextResourceContents)	BaseModelcreate_model)CallbackContext	Callbacks_MCPCallbacks)MCPToolCallRequestMCPToolCallResultToolCallInterceptor)
Connectioncreate_session)CommandTFi  c                   &    e Zd ZU dZeeef   ed<   y)MCPToolArtifactaf  Artifact returned from MCP tool calls.

    This TypedDict wraps the structured content from MCP tool calls,
    allowing for future extension if MCP adds more fields to tool results.

    Attributes:
        structured_content: The structured content returned by the MCP tool,
            corresponding to the structuredContent field in CallToolResult.
    structured_contentN)__name__
__module____qualname____doc__dictstrr   __annotations__     Z/opt/lhia/marcimex/agent/venv/lib/python3.12/site-packages/langchain_mcp_adapters/tools.pyr-   r-   F   s     S#X&r7   r-   contentreturnc                    t        | t              rt        | j                        S t        | t              r!t        | j                  | j                        S t        | t              rd| j                   }t        |      t        | t              rc| j                  xs d}|r1|j                  d      r t        t        | j                        |      S t        t        | j                        |      S t        | t              r| j                   }t        |t"              rt        |j                        S t        |t$              rQ|j                  xs d}|r(|j                  d      rt        |j&                  |      S t        |j&                  |      S dt)        |      j*                   }t-        |      dt)        |       j*                   }t-        |      )	a|  Convert any MCP content block to a LangChain content block.

    Args:
        content: MCP content object (TextContent, ImageContent, AudioContent,
            ResourceLink, or EmbeddedResource).

    Returns:
        LangChain content block dict.

    Raises:
        NotImplementedError: If AudioContent is passed.
        ValueError: If an unknown content type is passed.
    )text)base64	mime_typeziAudioContent conversion to LangChain content blocks is not yet supported. Received audio with mime type: Nzimage/)urlr>   z Unknown embedded resource type: zUnknown MCP content type: )
isinstancer   r   r<   r   r   datamimeTyper   NotImplementedErrorr   
startswithr4   urir   r   resourcer    r   blobtyper/   
ValueError)r9   msgr>   rF   s       r8    _convert_mcp_content_to_lc_blockrK   T   s     ';' gll33'<(!AQAQRR'<(99@9I9I8JL 	 "#&&'<($$,	--h7%#gkk*:iPP S%5KK'+,##h 45$(--88h 45 ))1TIY11(;))TT$HMMYOO0h1H1H0IJo&tG}'='=&>
?C
S/r7   call_tool_resultNc                 J   t        | t              r| dfS t        rt        | t              r| dfS | j                  D cg c]  }t        |       }}| j                  rg }|D ]k  }t        |t              r|j                  |       %t        |t              s6|j                  d      dk(  sK|j                  |j                  dd             m |rdj                  |      n
t        |      }t        |      d}| j                  t        | j                        }||fS c c}w )a  Convert MCP MCPToolCallResult to LangChain tool result format.

    Converts MCP content blocks to LangChain content blocks:
    - TextContent -> {"type": "text", "text": ...}
    - ImageContent -> {"type": "image", "base64": ..., "mime_type": ...}
    - ResourceLink (image/*) -> {"type": "image", "url": ..., "mime_type": ...}
    - ResourceLink (other) -> {"type": "file", "url": ..., "mime_type": ...}
    - EmbeddedResource (text) -> {"type": "text", "text": ...}
    - EmbeddedResource (blob) -> {"type": "image", ...} or {"type": "file", ...}
    - AudioContent -> raises NotImplementedError

    Args:
        call_tool_result: The result from calling an MCP tool. Can be either
            a CallToolResult (MCP format), a ToolMessage (LangChain format),
            or a Command (LangGraph format, if langgraph is installed).

    Returns:
        A tuple containing:
        - The content: either a string (single text), list of content blocks,
          ToolMessage, or Command
        - The artifact: MCPToolArtifact with structured_content if present,
          otherwise None

    Raises:
        ToolException: If the tool call resulted in an error.
        NotImplementedError: If AudioContent is encountered.
    NrH   r<    
)r.   )r@   r	   LANGGRAPH_PRESENTr+   r9   rK   isErrorr4   appendr3   getjoinr   structuredContentr-   )rL   r9   tool_contenterror_partsitem	error_msgartifacts          r8   _convert_call_tool_resultr[      s%   @ "K0%% Z(8'B%%
 (//3 	)13L 3
   	9D$$""4(D$'DHHV,<,F""488FB#78		9
 /:DIIk*s<?P	I&& (,H))5"/AA
 !!/3s   D base_handlertool_interceptorsc                     | }|rHt        |      D ]:  }|}||fdt        dt        dt        t        gt        t
           f   dt
        fd}|}< |S )ag  Build composed handler chain with interceptors in onion pattern.

    Args:
        base_handler: Innermost handler executing the actual tool call.
        tool_interceptors: Optional list of interceptors to wrap the handler.

    Returns:
        Composed handler with all interceptors applied. First interceptor
        in list becomes outermost layer.
    req_interceptor_handlerr:   c                 0   K    || |       d {   S 7 wNr6   )r_   r`   ra   s      r8   wrapped_handlerz1_build_interceptor_chain.<locals>.wrapped_handler   s      *#x8888s   )reversedr&   r(   r   r   r'   )r\   r]   handlerinterceptorcurrent_handlerrd   s         r8   _build_interceptor_chainri      s~     G#$56 	&K%O 5@ $9'919 #'()4E*FF9 #9 &G	& Nr7   sessionc                   K   d}g }d}	 |dz  }|t         kD  rd}t        |      | j                  |       d{   }|j                  r|j	                  |j                         |j
                  s	 |S |j
                  }x7 Gw)a  List all available tools from an MCP session with pagination support.

    Args:
        session: The MCP client session.

    Returns:
        A list of all available MCP tools.

    Raises:
        RuntimeError: If maximum iterations exceeded while listing tools.
    Nr      z3Reached max of 1000 iterations while listing tools.)cursor)MAX_ITERATIONSRuntimeError
list_toolstoolsextend
nextCursor)rj   current_cursor	all_tools
iterationsrJ   list_tools_page_results         r8   _list_all_toolsrx      s      "&N!IJ
a
&GCs##'.'9'9'9'P!P!''399: &00  0::!  "Qs   8BBAB
connection	callbacksr]   server_nametool_name_prefixtoolrz   r{   r|   r}   c          
           d}t        |      	 ddt        t        dz  t               f   dt        t
        t        f   dt        t        t        dz  f   f fd}t        dd      }	j                  j                  j                         ni }
|	d|	ini }	i |
|	xs d}j                  }|rr d	j                   }t        |j                  xs d
j                   |d|      S )a  Convert an MCP tool to a LangChain tool.

    NOTE: this tool can be executed only in a context of an active MCP client session.

    Args:
        session: MCP client session
        tool: MCP tool to convert
        connection: Optional connection config to use to create a new session
                    if a `session` is not provided
        callbacks: Optional callbacks for handling notifications and events
        tool_interceptors: Optional list of interceptors for tool call processing
        server_name: Name of the server this tool belongs to
        tool_name_prefix: If `True` and `server_name` is provided, the tool name will be
            prefixed w/ server name (e.g., `"weather_search"` instead of `"search"`)

    Returns:
        a LangChain tool

    N8Either a session or a connection config must be providedruntime	argumentsr:   c                 *  K   'j                  t        	j                              n	t               dt        dt
        f
fd}t        |      }t	        j                  |	xs dd|       } ||       d{   }t        |      S 7 w)	a  Execute tool call with interceptor chain and return formatted result.

        Args:
            runtime: LangGraph tool runtime if available, otherwise None.
            **arguments: Tool arguments as keyword args.

        Returns:
            A tuple of (content, artifact) where:
            - content: string, list of strings/content blocks, ToolMessage, or Command
            - artifact: MCPToolArtifact with structured_content if present, else None
        N)r|   	tool_namecontextrequestr:   c                 x  K   | j                   }| j                  }}| j                  }|1/t              }d   dv rj	                  di       }i |||d<   |}d}z|d}t        |      t        |      4 d{   }	|	j                          d{    	 |	j                  ||j                         d{   }
ddd      d{    ||
S j                  ||j                         d{   }
|
S 7 7 k7 F# t        $ r}|}Y d}~Td}~ww xY w7 P# 1 d{  7  sw Y   `xY w7 ;w)a  Execute the actual MCP tool call with optional session creation.

            Args:
                request: Tool call request with name, args, headers, and context.

            Returns:
                MCPToolCallResult from MCP SDK.

            Raises:
                ValueError: If neither session nor connection provided.
                RuntimeError: If tool call returns None.
            N	transport)ssehttpstreamable_httpzstreamable-httpheaders-Either session or connection must be providedmcp_callbacks)progress_callback)nameargsr   r3   rS   rI   r*   
initialize	call_toolr   	Exception)r   r   	tool_argseffective_connectionmodified_headersupdated_connectionexisting_headerscaptured_exceptionrJ   tool_sessionrL   erz   r   rj   s               r8   execute_toolzKconvert_mcp_tool_to_langchain_tool.<locals>.call_tool.<locals>.execute_toolI  s      II#-   '+
0F%)*%5"k* /  (2~~i'D$5*5*5&y1 ,>(!%'/IC$S/))( / /!&11333/1=1G1G%%.;.M.M 2H 2 ,(/ /( &1,, $# *1):):&3&E&E *; * $  $#;/ 4,
 % /-.*// / / /.$s   A>D:DD:D#DD#!D	 DD	D:D!+D:<D8=D:D#D			DDD#DD#!D:#D5)D,*D51D:unknown)r   r   r|   r   r   )to_mcp_formatr#   r   r%   r&   r'   ri   r[   )r   r   r   rf   r   rL   r   r{   rz   r|   rj   r~   r]   s         @r8   r   z5convert_mcp_tool_to_langchain_tool.<locals>.call_tool1  s     & $ ##'K499U $   	H	$(: H	$?P H	$V +<9JK$#0y
 ")!11()9:: 2s   A=BBBmeta_meta_rN   content_and_artifact)r   descriptionargs_schema	coroutineresponse_formatmetadatarc   )rI   r   objectr   r3   r4   r   tupleConvertedToolResultr-   getattrannotations
model_dumpr   r   r   inputSchema)rj   r~   rz   r{   r]   r|   r}   rJ   r   r   baser   lc_tool_names   ``````       r8   "convert_mcp_tool_to_langchain_toolr     s!   : :-Ho @Dm;6D=/*;;<m;#s(^m; 
"Od$::	;m; m;^ 4&D,0,<,<,H4&&(bD".GT?BD$$'4H 99LK%a		{3$$*$$. r7   c                  K   | |d}t        |      ||j                  t        |            n	t               }| a|d}t        |      t	        ||      4 d{   }|j                          d{    t        |       d{   }	ddd      d{    nt        |        d{   }		D 
cg c]  }
t        | |
|||||       c}
S 7 s7 ]7 L7 ># 1 d{  7  sw Y   :xY w7 Ac c}
w w)a  Load all available MCP tools and convert them to LangChain [tools](https://docs.langchain.com/oss/python/langchain/tools).

    Args:
        session: The MCP client session. If `None`, connection must be provided.
        connection: Connection config to create a new session if session is `None`.
        callbacks: Optional `Callbacks` for handling notifications and events.
        tool_interceptors: Optional list of interceptors for tool call processing.
        server_name: Name of the server these tools belong to.
        tool_name_prefix: If `True` and `server_name` is provided, tool names will be
            prefixed w/ server name (e.g., `"weather_search"` instead of `"search"`).

    Returns:
        List of LangChain [tools](https://docs.langchain.com/oss/python/langchain/tools).
            Tool annotations are returned as part of the tool metadata object.

    Raises:
        ValueError: If neither session nor connection is provided.
    Nr   )r|   r   r   r   ry   )rI   r   r#   r%   r*   r   rx   r   )rj   rz   r{   r]   r|   r}   rJ   r   r   rq   r~   s              r8   load_mcp_toolsr     s'    6 :-Ho   	K(PQ_  ACS/!!m
 	8 	8))+++),77E		8 	8 	8 &g..   	+!/#-	
 	8 ,7		8 	8 	8 	8 /s   AC6CC6"C6C7C	C
CC6CC6-C/.C66C1C6CCC6C, C#!C,(C61C6c                     dt         dt        fd}t        | j                        j	                         D cg c]  \  }} ||      r| c}}S c c}}w )zExtract field names with InjectedToolArg annotation from tool schema.

    Args:
        tool: LangChain tool to inspect.

    Returns:
        List of field names marked as injected arguments.
    type_r:   c                 >    t        d t        |       dd D              S )z2Check if type annotation contains InjectedToolArg.c              3      K   | ]8  }t        |t              xs" t        |t              xr t        |t               : y wrc   )r@   r   rH   
issubclass).0args     r8   	<genexpr>zD_get_injected_args.<locals>._is_injected_arg_type.<locals>.<genexpr>   sC      
  sO, L3%J*S/*JL
s   >A rl   N)anyr   )r   s    r8   _is_injected_arg_typez1_get_injected_args.<locals>._is_injected_arg_type  s)     
  qr*
 
 	
r7   )rH   boolr   r   items)r~   r   field
field_infos       r8   _get_injected_argsr     sW    
T 
d 
 "?t?O?O!P!V!V!XE: , 	  s   Ac                 F    t         j                  t              sd}t        |       j                  j                         } j                  j                  j                         D ci c]  \  }}||j                  |f }}}t         j                   dfi |dt        i}t        |      }dt        t        t        f   dt        f fd}t!               }	t#        |	      dkD  rd	}t%        |      t'        | j                   j(                  ||d
      S c c}}w )a  Convert LangChain tool to FastMCP tool.

    Args:
        tool: LangChain tool to convert.

    Returns:
        FastMCP tool equivalent.

    Raises:
        TypeError: If args_schema is not BaseModel subclass.
        NotImplementedError: If tool has injected arguments.
    ziTool args_schema must be a subclass of pydantic.BaseModel. Tools with dict args schema are not supported.	Arguments__base__)	arg_modelr   r:   c                  B   K   j                  |        d {   S 7 wrc   )ainvoke)r   r~   s    r8   fnzto_fastmcp.<locals>.fn-  s     \\),,,,s   r   z9LangChain tools with injected arguments are not supportedT)r   r   r   
parametersfn_metadatais_async)r   r   r!   	TypeErrortool_call_schemamodel_json_schemamodel_fieldsr   
annotationr"   r   r   r   r3   r4   r   r   lenrC   FastMCPToolr   )
r~   rJ   r   r   r   field_definitionsr   r   r   injected_argss
   `         r8   
to_fastmcpr     s0    d&&	2= 	 n&&88:J "&!6!6!C!C!I!I!KE: 	
%%z22  99+Y#4?KI 3K-d38n - - 't,M
=AI!#&&YY$$ 's   *D)Mr2   collections.abcr   r   typingr   r   r   r   langchain_core.messagesr	   langchain_core.messages.contentr
   r   r   r   r   r   langchain_core.toolsr   r   r   r   langchain_core.tools.baser   mcpr   mcp.server.fastmcp.toolsr   r   *mcp.server.fastmcp.utilities.func_metadatar   r   	mcp.typesr   r   r   r   r   r   r   r    MCPToolpydanticr!   r"    langchain_mcp_adapters.callbacksr#   r$   r%   #langchain_mcp_adapters.interceptorsr&   r'   r(   langchain_mcp_adapters.sessionsr)   r*   langgraph.typesr+   rP   ImportErrorToolMessageContentBlocklistr   rn   r-   rK   r   r[   ri   rx   r4   r   r   r   r   r   r6   r7   r8   <module>r      s   0 6 6 /   D  8 Q	 	 	 & , V V 
 G'
 +->>AQQ  67+EO67+E'i '000f?"'?"
$ 667?"D./;L1MMN/047 !"I.?$@@AD"= "T'] "R %)"&:>""aT!a
a T!	a
 4a /047a ta a aN %)"&:>""=T!= T!= 4	=
 /047= t= = 
(^=@X $s) 2/X /+ /m  s   E9 9FF