§
    ‰eîi‚Ö ã                   ó8
  — U d Z ddlZddlZddlZddlZddlZddlZddlZ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mZmZmZ  ej        e¦  «        Zdaee         ed<    ej        ¦   «         Zdefd„Zdeddfd	„Zd
Zd
Zd
Z d
Z!d
Z"dZ#	 ddl$m%Z%m&Z& ddl'm(Z( dZ	 ddl)m*Z* dZn# e+$ r d
ZY nw xY w	 ddl)m,Z, dZ-n# e+$ r d
Z-Y nw xY w	 ddl.m#Z# n # e+$ r e /                    d¦  «         Y nw xY w	 ddl.m0Z0m1Z1m2Z2m3Z3m4Z4m5Z5m6Z6 dZ n # e+$ r e /                    d¦  «         Y nw xY w	 ddl.m7Z7m8Z8m9Z9m:Z: dZ!n # e+$ r e /                    d¦  «         Y nw xY wn # e+$ r e /                    d¦  «         Y nw xY wde;fd„Z< e<¦   «         Z"ere"se /                    d¦  «         dZ=dZ>dZ?dZ@dZA eBh d£¦  «        ZC e	jD        de	jE        ¦  «        ZFd eeG         deGfd!„ZHd"edefd#„ZI e	jD        d$e	jJ        ¦  «        d%f e	jD        d&e	jJ        ¦  «        d'f e	jD        d(e	jJ        ¦  «        d)f e	jD        d*e	jJ        ¦  «        d+f e	jD        d,e	jJ        ¦  «        d-f e	jD        d.e	jJ        ¦  «        d/f e	jD        d0e	jJ        ¦  «        d1f e	jD        d2e	jJ        ¦  «        d3f e	jD        d4e	jJ        ¦  «        d5f e	jD        d6e	jJ        ¦  «        d7fg
ZKded8ed9edee         fd:„ZLd;eGd<edeGfd=„ZMd>ed;eGdeNeeGf         fd?„ZOd@ePdefdA„ZQeRdBfdC„ZS G dD„ dE¦  «        ZT G dF„ dG¦  «        ZUi ZVeeeUf         edH<   i ZWeeeRf         edI<   i ZXeeeYf         edJ<   dZZdKZ[deddfdL„Z\deddfdM„Z]dNa^eNedO<   deNfdP„Z_d@ePde;fdQ„Z`ded@ePdRefdS„ZadTZbeNedU<   d@ePde;fdV„Zcded@ePdRefdW„Zddaeeejf                 edX<   dageejh                 edY<    ej        ¦   «         Zii ZjeeRef         edZ<   dekfd[„Zld\„ Zmd]„ ZndŠd_eYfd`„Zodefda„Zpdb„ ZqdeeeGf         fdc„ZrddedeeGdeUfdf„Zsded8edgeYfdh„ZtdedgeYfdi„ZudedgeYfdj„ZvdedgeYfdk„ZwdedgeYfdl„Zxdefdm„ZydneGdz  deGfdo„Zzdpedefdq„Z{dedeGfdr„Z|dedeeG         fds„Z}dpedtedeke         fdu„Z~d‹dpedve;de;fdw„Zdxdydzd{d|œZ€ded}eUdeeGdeeG         fd~„Z�dee         fd„Z‚dded}eUdeeGdee         fd€„ZƒddedeeGdee         fd�„Z„d‚eeeGf         dee         fdƒ„Z…dee         fd„„Z†deeG         fd…„Z‡deeeeN         f         fd†„Zˆd‡„ Z‰dŒdˆ„ZŠd‰„ Z‹dS )�a×  
MCP (Model Context Protocol) Client Support

Connects to external MCP servers via stdio or HTTP/StreamableHTTP transport,
discovers their tools, and registers them into the hermes-agent tool registry
so the agent can call them like any built-in tool.

Configuration is read from ~/.hermes/config.yaml under the ``mcp_servers`` key.
The ``mcp`` Python package is optional -- if not installed, this module is a
no-op and logs a debug message.

Example config::

    mcp_servers:
      filesystem:
        command: "npx"
        args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
        env: {}
        timeout: 120         # per-tool-call timeout in seconds (default: 120)
        connect_timeout: 60  # initial connection timeout (default: 60)
      github:
        command: "npx"
        args: ["-y", "@modelcontextprotocol/server-github"]
        env:
          GITHUB_PERSONAL_ACCESS_TOKEN: "ghp_..."
      remote_api:
        url: "https://my-mcp-server.example.com/mcp"
        headers:
          Authorization: "Bearer sk-..."
        timeout: 180
      analysis:
        command: "npx"
        args: ["-y", "analysis-server"]
        sampling:                    # server-initiated LLM requests
          enabled: true              # default: true
          model: "gemini-3-flash"    # override model (optional)
          max_tokens_cap: 4096       # max tokens per request
          timeout: 30                # LLM call timeout (seconds)
          max_rpm: 10                # max requests per minute
          allowed_models: []         # model whitelist (empty = all)
          max_tool_rounds: 5         # tool loop limit (0 = disable)
          log_level: "info"          # audit verbosity

Features:
    - Stdio transport (command + args) and HTTP/StreamableHTTP transport (url)
    - Automatic reconnection with exponential backoff (up to 5 retries)
    - Environment variable filtering for stdio subprocesses (security)
    - Credential stripping in error messages returned to the LLM
    - Configurable per-server timeouts for tool calls and connections
    - Thread-safe architecture with dedicated background event loop
    - Sampling support: MCP servers can request LLM completions via
      sampling/createMessage (text and tool-use responses)

Architecture:
    A dedicated background event loop (_mcp_loop) runs in a daemon thread.
    Each MCP server runs as a long-lived asyncio Task on this loop, keeping
    its transport context alive. Tool call coroutines are scheduled onto the
    loop via ``run_coroutine_threadsafe()``.

    On shutdown, each server Task is signalled to exit its ``async with``
    block, ensuring the anyio cancel-scope cleanup happens in the *same*
    Task that opened the connection (required by anyio).

Thread safety:
    _servers and _mcp_loop/_mcp_thread are accessed from both the MCP
    background thread and caller threads.  All mutations are protected by
    _lock so the code is safe regardless of GIL presence (e.g. Python 3.13+
    free-threading).
é    N)Údatetime)ÚAnyÚDictÚListÚOptionalÚ_mcp_stderr_log_fhÚreturnc                  ó  — t           5  t          �t          cddd¦  «         S 	 ddlm}   | ¦   «         dz  }|                     dd¬¦  «         |dz  }t          |dd	d
d¬¦  «        }|                     ¦   «          |anl# t          $ r_}t           	                    d|¦  «         	 t          t          j        dd	¬¦  «        an# t          $ r t          j        aY nw xY wY d}~nd}~ww xY wt          cddd¦  «         S # 1 swxY w Y   dS )a^  Return a shared append-mode file handle for MCP subprocess stderr.

    Opened once per process and reused for every stdio server.  Must have a
    real OS-level file descriptor (``fileno()``) because asyncio's subprocess
    machinery wires the child's stderr directly to that fd.  Falls back to
    ``/dev/null`` if opening the log file fails.
    Nr   )Úget_hermes_homeÚlogsT)ÚparentsÚexist_okzmcp-stderr.logÚazutf-8Úreplaceé   )ÚencodingÚerrorsÚ	bufferingz0Failed to open MCP stderr log, using devnull: %sÚw)r   )Ú_mcp_stderr_log_lockr   Úhermes_constantsr   ÚmkdirÚopenÚfilenoÚ	ExceptionÚloggerÚdebugÚosÚdevnullÚsysÚstderr)r   Úlog_dirÚlog_pathÚfhÚexcs        ú0/home/div/.hermes/hermes-agent/tools/mcp_tool.pyÚ_get_mcp_stderr_logr'   o   s¢  € õ 
ð "ð "ÝÐ)Ý%ð"ð "ð "ð "ñ "ô "ð "ð "ð	0Ø8Ð8Ð8Ð8Ð8Ð8Ø%�oÑ'Ô'¨&Ñ0ˆGØ�MŠM $°ˆMÑ6Ô6Ð6ØÐ!1Ñ1ˆHõ �h ¨g¸iÐSTÐUÑUÔUˆBà�IŠI‰KŒKˆKØ!#ÐÐøÝð 	0ð 	0ð 	0Ý�LŠLÐKÈSÑQÔQÐQð0Ý%)­"¬*°cÀGÐ%LÑ%LÔ%LÐ"Ð"øÝð 0ð 0ð 0õ &)¤ZÐ"Ð"Ð"ð0øøøøøøøøøøøøð		0øøøõ "ð/"ð "ð "ð "ñ "ô "ð "ð "ð "ð "ð "ð "øøøð "ð "ð "ð "ð "ð "s_   ˆC=¤AA>Á=C=Á>
C'ÂC"Â$CÃ C"ÃCÃC"ÃCÃC"ÃC=Ã"C'Ã'	C=Ã=DÄDÚserver_namec                 óò   — t          ¦   «         }	 t          j        ¦   «                              d¦  «        }|                     d|› d| › d�¦  «         |                     ¦   «          dS # t          $ r Y dS w xY w)a  Write a human-readable session marker before launching a server.

    Gives operators a way to find each server's output in the shared
    ``mcp-stderr.log`` file without needing per-line prefixes (which would
    require a pipe + reader thread and complicate shutdown).
    z%Y-%m-%d %H:%M:%Sz
===== [z] starting MCP server 'z' =====
N)r'   r   ÚnowÚstrftimeÚwriteÚflushr   )r(   r$   Útss      r&   Ú_write_stderr_log_headerr/   ’   s‡   € õ 
Ñ	Ô	€BðÝŒ\‰^Œ^×$Ò$Ð%8Ñ9Ô9ˆØ
�ŠÐN˜RÐNÐN¸ÐNÐNÐNÑOÔOÐOØ
�Š‰
Œ
ˆ
ˆ
ˆ
øÝð ð ð Øˆˆðøøøs   �AA( Á(
A6Á5A6Fz
2025-03-26)ÚClientSessionÚStdioServerParameters)Ústdio_clientT)Ústreamablehttp_client)Ústreamable_http_client)ÚLATEST_PROTOCOL_VERSIONzRmcp.types.LATEST_PROTOCOL_VERSION not available -- using fallback protocol version)ÚCreateMessageResultÚCreateMessageResultWithToolsÚ	ErrorDataÚSamplingCapabilityÚSamplingToolsCapabilityÚTextContentÚToolUseContentz5MCP sampling types not available -- sampling disabled)ÚServerNotificationÚToolListChangedNotificationÚPromptListChangedNotificationÚResourceListChangedNotificationzGMCP notification types not available -- dynamic tool discovery disabledz6mcp package not installed -- MCP tool support disabledc                  ó†   — t           sdS 	 dt          j        t          ¦  «        j        v S # t
          t          f$ r Y dS w xY w)zËCheck if ClientSession accepts ``message_handler`` kwarg.

    Inspects the constructor signature for backward compatibility with older
    MCP SDK versions that don't support notification handlers.
    FÚmessage_handler)Ú_MCP_AVAILABLEÚinspectÚ	signaturer0   Ú
parametersÚ	TypeErrorÚ
ValueError© ó    r&   Ú_check_message_handler_supportrK   ß   sV   € õ ð ØˆuðØ ¥GÔ$5µmÑ$DÔ$DÔ$OÐOÐOøÝ•zÐ"ð ð ð Øˆuˆuðøøøs   ‹+ «A ¿A zKMCP SDK does not support message_handler -- dynamic tool discovery disabledéx   é<   é   é   >   ÚHOMEÚLANGÚPATHÚTERMÚUSERÚSHELLÚLC_ALLÚTMPDIRzÀ(?:ghp_[A-Za-z0-9_]{1,255}|sk-[A-Za-z0-9_]{1,255}|Bearer\s+\S+|token=[^\s&,;\"']{1,255}|key=[^\s&,;\"']{1,255}|API_KEY=[^\s&,;\"']{1,255}|password=[^\s&,;\"']{1,255}|secret=[^\s&,;\"']{1,255})Úuser_envc                 óÆ   — i }t           j                             ¦   «         D ](\  }}|t          v s|                     d¦  «        r|||<   Œ)| r|                     | ¦  «         |S )a„  Build a filtered environment dict for stdio subprocesses.

    Only passes through safe baseline variables (PATH, HOME, etc.) and XDG_*
    variables from the current process environment, plus any variables
    explicitly specified by the user in the server config.

    This prevents accidentally leaking secrets like API keys, tokens, or
    credentials to MCP server subprocesses.
    ÚXDG_)r   ÚenvironÚitemsÚ_SAFE_ENV_KEYSÚ
startswithÚupdate)rX   ÚenvÚkeyÚvalues       r&   Ú_build_safe_envrc     so   € ð €CÝ”j×&Ò&Ñ(Ô(ð ð ‰
ˆˆUØ•.Ð Ð  C§N¢N°6Ñ$:Ô$:Ð ØˆC�‰HøØð Ø�
Š
�8ÑÔÐØ€JrJ   Útextc                 ó8   — t                                d| ¦  «        S )zÑStrip credential-like patterns from error text before returning to LLM.

    Replaces tokens, keys, and other secrets with [REDACTED] to prevent
    accidental credential exposure in tool error responses.
    z
[REDACTED])Ú_CREDENTIAL_PATTERNÚsub©rd   s    r&   Ú_sanitize_errorri   '  s   € õ ×"Ò" <°Ñ6Ô6Ð6rJ   z)ignore\s+(all\s+)?previous\s+instructionsz8prompt override attempt ('ignore previous instructions')zyou\s+are\s+now\s+az.identity override attempt ('you are now a...')z1your\s+new\s+(task|role|instructions?)\s+(is|are)ztask override attemptzsystem\s*:\s*zsystem prompt injection attemptz <\s*(system|human|assistant)\s*>zrole tag injection attemptz'do\s+not\s+(tell|inform|mention|reveal)zconcealment instructionz(curl|wget|fetch)\s+https?://znetwork command in descriptionzbase64\.(b64decode|decodebytes)zbase64 decode referencezexec\s*\(|eval\s*\(zcode execution referencez&import\s+(subprocess|os|shutil|socket)zdangerous import referenceÚ	tool_nameÚdescriptionc                 óæ   — g }|s|S t           D ]/\  }}|                     |¦  «        r|                     |¦  «         Œ0|r1t                               d| |d                     |¦  «        |¦  «         |S )zxScan an MCP tool description for prompt injection patterns.

    Returns a list of finding strings (empty = clean).
    uU   MCP server '%s' tool '%s': suspicious description content â€” %s. Description: %.200sú; )Ú_MCP_INJECTION_PATTERNSÚsearchÚappendr   ÚwarningÚjoin)r(   rj   rk   ÚfindingsÚpatternÚreasons         r&   Ú_scan_mcp_descriptionrv   O  s�   € ð
 €HØð ØˆÝ2ð $ð $‰ˆ�Ø�>Š>˜+Ñ&Ô&ð 	$Ø�OŠO˜FÑ#Ô#Ð#øØð 
Ý�Šð"à˜ D§I¢I¨hÑ$7Ô$7Øñ		
ô 	
ð 	
ð €OrJ   r`   Ú	directoryc                 ó  — t          | pi ¦  «        }|s|S |                     dd¦  «        }d„ |                     t          j        ¦  «        D ¦   «         }||vr|g|¢}|rt          j                             |¦  «        n||d<   |S )z=Prepend *directory* to env PATH if it is not already present.rR   Ú c                 ó   — g | ]}|¯|‘ŒS rI   rI   )Ú.0Úparts     r&   ú
<listcomp>z!_prepend_path.<locals>.<listcomp>k  s   € ÐAÐAÐA�d¸DÐAˆTÐAÐAÐArJ   )ÚdictÚgetÚsplitr   Úpathseprr   )r`   rw   ÚupdatedÚexistingÚpartss        r&   Ú_prepend_pathr…   d  s�   € å�3�9˜"‰oŒo€GØð Øˆà�{Š{˜6 2Ñ&Ô&€HØAÐA˜hŸnšn­R¬ZÑ8Ô8ÐAÑAÔA€EØ˜ÐÐØÐ#˜UÐ#ˆØ05ÐD•b”j—o’o eÑ,Ô,Ð,¸9€GˆF�OØ€NrJ   Úcommandc           
      ó°  — t           j                             t          | ¦  «                             ¦   «         ¦  «        }t          |pi ¦  «        }t           j        |v�rDd|v r|d         nd}t          j        ||¬¦  «        }|r|}�n|dv �rt           j                             t          j	        dt           j         
                    t           j                             d¦  «        d¦  «        ¦  «        ¦  «        }t           j         
                    |dd	|¦  «        t           j         
                    t           j                             d¦  «        d
d	|¦  «        g}|D ]D}t           j                             |¦  «        r#t          j        |t           j        ¦  «        r|} nŒEt           j                             |¦  «        }	|	rt          ||	¦  «        }||fS )zÜResolve a stdio MCP command against the exact subprocess environment.

    This primarily exists to make bare ``npx``/``npm``/``node`` commands work
    reliably even when MCP subprocesses run under a filtered PATH.
    rR   N)Úpath>   ÚnpmÚnpxÚnodeÚHERMES_HOMEÚ~z.hermesr‹   Úbinz.local)r   rˆ   Ú
expanduserÚstrÚstripr~   ÚsepÚshutilÚwhichÚgetenvrr   ÚisfileÚaccessÚX_OKÚdirnamer…   )
r†   r`   Úresolved_commandÚresolved_envÚpath_argÚ	which_hitÚhermes_homeÚ
candidatesÚ	candidateÚcommand_dirs
             r&   Ú_resolve_stdio_commandr¢   r  s§  € õ ”w×)Ò)­#¨g©,¬,×*<Ò*<Ñ*>Ô*>Ñ?Ô?ÐÝ˜˜	˜r‘?”?€Lå	„vÐ%Ð%Ñ%Ø+1°\Ð+AÐ+A�< Ô'Ð'ÀtˆÝ”LÐ!1¸ÐAÑAÔAˆ	Øð 	Ø(ÐÑØÐ!7Ð7Ñ7Ýœ'×,Ò,Ý”	Ø!¥2¤7§<¢<µ´×0BÒ0BÀ3Ñ0GÔ0GÈÑ#SÔ#Sñô ñô ˆKõ ”—’˜[¨&°%Ð9IÑJÔJÝ”—’�RœW×/Ò/°Ñ4Ô4°hÀÐGWÑXÔXðˆJð (ð ð �	Ý”7—>’> )Ñ,Ô,ð µ´¸9ÅbÄgÑ1NÔ1Nð Ø'0Ð$Ø�Eøå”'—/’/Ð"2Ñ3Ô3€KØð @Ý$ \°;Ñ?Ô?ˆà˜\Ð)Ð)rJ   r%   c                 ó¸  ‡‡— dt           dt          t                   fˆfd„Šdt           dt          t                   fˆfd„Š ‰| ¦  «        }|r;d|› d�}t          j                             |¦  «        dv r|dz  }t          |¦  «        S g } ‰| ¦  «        D ]}||vr|                     |¦  «         Œt          d	 	                    |d
d…         ¦  «        ¦  «        S )zERender nested MCP connection errors into an actionable short message.Úcurrentr	   c                 ó¼  •— t          | dd ¦  «        }|r|D ]} ‰|¦  «        }|r|c S Œd S t          | t          ¦  «        r^t          | dd ¦  «        rt          | j        ¦  «        S t          j        dt          | ¦  «        ¦  «        }|r|                     d¦  «        S dD ]9}t          | |d ¦  «        }t          |t          ¦  «        r ‰|¦  «        }|r|c S Œ:d S )NÚ
exceptionsÚfilenamez$No such file or directory: '([^']+)'r   ©Ú	__cause__Ú__context__)	ÚgetattrÚ
isinstanceÚFileNotFoundErrorr�   r§   Úrero   ÚgroupÚBaseException)r¤   ÚnestedÚchildÚmissingÚmatchÚattrÚ
nested_excÚ_find_missings          €r&   r·   z,_format_connect_error.<locals>._find_missing™  s  ø€ Ý˜ ,°Ñ5Ô5ˆØð 	Øð #ð #�Ø'˜-¨Ñ.Ô.�Øð #Ø"�N�N�Nð#à�4Ý�gÕ0Ñ1Ô1ð 	&Ý�w 
¨DÑ1Ô1ð -Ý˜7Ô+Ñ,Ô,Ð,Ý”IÐEÅsÈ7Á|Ä|ÑTÔTˆEØð &Ø—{’{ 1‘~”~Ð%Ø0ð 	#ð 	#ˆDÝ  ¨$°Ñ5Ô5ˆJÝ˜*¥mÑ4Ô4ð #Ø'˜-¨
Ñ3Ô3�Øð #Ø"�N�N�NøØˆtrJ   c                 óœ  •— t          | dd ¦  «        }|r'g }|D ] }|                      ‰|¦  «        ¦  «         Œ!|S g }t          | ¦  «                             ¦   «         }|r|                     |¦  «         dD ]F}t          | |d ¦  «        }t          |t          ¦  «        r|                      ‰|¦  «        ¦  «         ŒG|p| j        j        gS )Nr¦   r¨   )	r«   Úextendr�   r‘   rp   r¬   r°   Ú	__class__Ú__name__)	r¤   r±   Ú	flattenedr²   Úmessagesrd   rµ   r¶   Ú_flatten_messagess	           €r&   r¾   z0_format_connect_error.<locals>._flatten_messages¯  sô   ø€ Ý˜ ,°Ñ5Ô5ˆØð 	Ø#%ˆIØð ;ð ;�Ø× Ò Ð!2Ð!2°5Ñ!9Ô!9Ñ:Ô:Ð:Ð:ØÐØˆÝ�7‰|Œ|×!Ò!Ñ#Ô#ˆØð 	"Ø�OŠO˜DÑ!Ô!Ð!Ø0ð 	?ð 	?ˆDÝ  ¨$°Ñ5Ô5ˆJÝ˜*¥mÑ4Ô4ð ?Ø—’Ð 1Ð 1°*Ñ =Ô =Ñ>Ô>Ð>øØÐ7˜GÔ-Ô6Ð7Ð7rJ   zmissing executable 'ú'>   r‰   rŠ   r‹   z³ (ensure Node.js is installed and PATH includes its bin directory, or set mcp_servers.<name>.command to an absolute path and include that directory in mcp_servers.<name>.env.PATH)rm   NrO   )
r°   r   r�   r   r   rˆ   Úbasenameri   rp   rr   )r%   r³   ÚmessageÚdedupedÚitemr·   r¾   s        @@r&   Ú_format_connect_errorrÄ   –  s(  øø€ ð�}ð µ½#´ð ð ð ð ð ð ð,8¥=ð 8µT½#´Yð 8ð 8ð 8ð 8ð 8ð 8ð" ˆm˜CÑ Ô €GØð (Ø3¨Ð3Ð3Ð3ˆÝŒ7×Ò˜GÑ$Ô$Ð(>Ð>Ð>ØðAñˆGõ
 ˜wÑ'Ô'Ð'à€GØ!Ð! #Ñ&Ô&ð !ð !ˆØ�wÐÐØ�NŠN˜4Ñ Ô Ð øÝ˜4Ÿ9š9 W¨R¨a¨R¤[Ñ1Ô1Ñ2Ô2Ð2rJ   r   c                 óÎ   — 	  || ¦  «        }t          |t          ¦  «        rt          j        |¦  «        s|S t	          ||¦  «        S # t
          t          t          f$ r |cY S w xY w)zÈCoerce a config value to a numeric type, returning *default* on failure.

    Handles string values from YAML (e.g. ``"10"`` instead of ``10``),
    non-finite floats, and values below *minimum*.
    )r¬   ÚfloatÚmathÚisfiniteÚmaxrG   rH   ÚOverflowError)rb   ÚdefaultÚcoerceÚminimumÚresults        r&   Ú_safe_numericrÏ   Ö  sw   € ðØ�˜‘”ˆÝ�f�eÑ$Ô$ð 	­T¬]¸6Ñ-BÔ-Bð 	ØˆNÝ�6˜7Ñ#Ô#Ð#øÝ•z¥=Ð1ð ð ð Øˆˆˆðøøøs   ‚5A ¸A ÁA$Á#A$c                   óÆ   — e Zd ZdZddddœZdedefd„Zd	efd
„Z	d	e
e         fd„Zed	efd„¦   «         Zd	ee         fd„Zeddedefd„¦   «         Zd„ Zd„ Zd	efd„Zd„ ZdS )ÚSamplingHandlera+  Handles sampling/createMessage requests for a single MCP server.

    Each MCPServerTask that has sampling enabled creates one SamplingHandler.
    The handler is callable and passed directly to ``ClientSession`` as
    the ``sampling_callback``.  All state (rate-limit timestamps, metrics,
    tool-loop counters) lives on the instance -- no module-level globals.

    The callback is async and runs on the MCP background event loop.  The
    sync LLM call is offloaded to a thread via ``asyncio.to_thread()`` so
    it doesn't block the event loop.
    ÚendTurnÚ	maxTokensÚtoolUse)ÚstopÚlengthÚ
tool_callsr(   Úconfigc                 ó&  — || _         t          |                     dd¦  «        dt          ¦  «        | _        t          |                     dd¦  «        dt
          ¦  «        | _        t          |                     dd¦  «        dt          ¦  «        | _        t          |                     dd¦  «        dt          d	¬
¦  «        | _        |                     d¦  «        | _	        |                     dg ¦  «        | _
        t          j        t          j        t          j        dœ}|                     t          |                     dd¦  «        ¦  «                             ¦   «         t          j        ¦  «        | _        g | _        d	| _        d	d	d	d	dœ| _        d S )NÚmax_rpmé
   Útimeouté   Úmax_tokens_capi   Úmax_tool_roundsrN   r   )rÍ   ÚmodelÚallowed_models)r   Úinforq   Ú	log_levelrâ   )Úrequestsr   Útokens_usedÚtool_use_count)r(   rÏ   r   ÚintrÚ   rÆ   rÜ   rÞ   rß   Úmodel_overriderá   ÚloggingÚDEBUGÚINFOÚWARNINGr�   ÚlowerÚaudit_levelÚ_rate_timestampsÚ_tool_loop_countÚmetrics)Úselfr(   rØ   Ú_log_levelss       r&   Ú__init__zSamplingHandler.__init__ô  sM  € Ø&ˆÔÝ$ V§Z¢Z°	¸2Ñ%>Ô%>ÀÅCÑHÔHˆŒÝ$ V§Z¢Z°	¸2Ñ%>Ô%>ÀÅEÑJÔJˆŒÝ+¨F¯JªJÐ7GÈÑ,NÔ,NÐPTÕVYÑZÔZˆÔÝ,Ø�JŠJÐ(¨!Ñ,Ô,¨aµ¸að 
ñ  
ô  
ˆÔð %Ÿjšj¨Ñ1Ô1ˆÔØ$ŸjšjÐ)9¸2Ñ>Ô>ˆÔå '¤µw´|ÕPWÔP_Ð`Ð`ˆØ&Ÿ?š?Ý�—
’
˜;¨Ñ/Ô/Ñ0Ô0×6Ò6Ñ8Ô8½'¼,ñ
ô 
ˆÔð
 .0ˆÔØ !ˆÔØ$%°À1ÐXYÐZÐZˆŒˆˆrJ   r	   c                 óä   ‡— t          j         ¦   «         }|dz
  Šˆfd„| j        D ¦   «         | j        dd…<   t          | j        ¦  «        | j        k    rdS | j                             |¦  «         dS )zASliding-window rate limiter.  Returns True if request is allowed.rM   c                 ó    •— g | ]
}|‰k    ¯|‘ŒS rI   rI   )r{   ÚtÚwindows     €r&   r}   z5SamplingHandler._check_rate_limit.<locals>.<listcomp>  s   ø€ Ð#SÐ#SÐ#S¨!ÈÈFÊ
È
 AÈ
È
È
rJ   NFT)Útimerï   ÚlenrÚ   rp   )rò   r*   rø   s     @r&   Ú_check_rate_limitz!SamplingHandler._check_rate_limit  sx   ø€ åŒi‰kŒkˆØ�r‘ˆØ#SÐ#SÐ#SÐ#S¨tÔ/DÐ#SÑ#SÔ#SˆÔ˜a˜a˜aÑ ÝˆtÔ$Ñ%Ô%¨¬Ò5Ð5Ø�5ØÔ×$Ò$ SÑ)Ô)Ð)ØˆtrJ   c                 ó¨   — | j         r| j         S |rAt          |d¦  «        r1|j        r*|j        D ]"}t          |d¦  «        r|j        r	|j        c S Œ#dS )z3Config override > server hint > None (use default).ÚhintsÚnameN)rè   Úhasattrrý   rþ   )rò   ÚpreferencesÚhints      r&   Ú_resolve_modelzSamplingHandler._resolve_model  sz   € àÔð 	'ØÔ&Ð&Øð 	%�7 ;°Ñ8Ô8ð 	%¸[Ô=Nð 	%Ø#Ô)ð %ð %�Ý˜4 Ñ(Ô(ð %¨T¬Yð %Øœ9Ð$Ð$Ð$øØˆtrJ   c                 óÄ   — t          | d¦  «        r| j        €dS t          | j        t          ¦  «        r| j        n| j        g}d                     d„ |D ¦   «         ¦  «        S )z,Extract text from a ToolResultContent block.ÚcontentNry   Ú
c              3   óD   K  — | ]}t          |d ¦  «        ¯|j        V — ŒdS )rd   N©rÿ   rd   ©r{   rÃ   s     r&   ú	<genexpr>z<SamplingHandler._extract_tool_result_text.<locals>.<genexpr>)  s3   è è € ÐNÐN t½ÀÀfÑ8MÔ8MÐN˜œÐNÐNÐNÐNÐNÐNrJ   )rÿ   r  r¬   Úlistrr   )Úblockr\   s     r&   Ú_extract_tool_result_textz)SamplingHandler._extract_tool_result_text#  sc   € õ �u˜iÑ(Ô(ð 	¨E¬MÐ,AØ�2Ý!+¨E¬M½4Ñ!@Ô!@ÐU�”�ÀuÄ}ÀoˆØ�yŠyÐNÐN¨uÐNÑNÔNÑNÔNÐNrJ   c                 óH  — g }|j         D �]–}t          |d¦  «        r|j        n(t          |j        t
          ¦  «        r|j        n|j        g}d„ |D ¦   «         }d„ |D ¦   «         }d„ |D ¦   «         }|D ]3}|                     d|j        |                      |¦  «        dœ¦  «         Œ4|rÕg }	|D ]‰}
|	                     t          |
ddt          |	¦  «        › �¦  «        d	|
j        t          |
j        t          ¦  «        rt          j        |
j        d
¬¦  «        nt!          |
j        ¦  «        dœdœ¦  «         ŒŠ|j        |	dœ}d„ |D ¦   «         }|rd                     |¦  «        |d<   |                     |¦  «         �Œt|�rt          |¦  «        dk    r@t          |d         d¦  «        r*|                     |j        |d         j        dœ¦  «         �ŒÊg }|D ]¨}t          |d¦  «        r|                     d|j        dœ¦  «         Œ0t          |d¦  «        r;t          |d¦  «        r+|                     ddd|j        › d|j        › �idœ¦  «         Œ{t,                               dt1          |¦  «        j        ¦  «         Œ©|r|                     |j        |dœ¦  «         �Œ˜|S )aL  Convert MCP SamplingMessages to OpenAI format.

        Uses ``msg.content_as_list`` (SDK helper) so single-block and
        list-of-blocks are handled uniformly.  Dispatches per block type
        with ``isinstance`` on real SDK types when available, falling back
        to duck-typing via ``hasattr`` for compatibility.
        Úcontent_as_listc                 ó2   — g | ]}t          |d ¦  «        ¯|‘ŒS )Ú	toolUseId©rÿ   ©r{   Úbs     r&   r}   z5SamplingHandler._convert_messages.<locals>.<listcomp>:  s'   € ÐIÐIÐI !µ¸¸KÑ1HÔ1HÐI˜AÐIÐIÐIrJ   c                 ór   — g | ]4}t          |d ¦  «        ¯t          |d¦  «        ¯"t          |d¦  «        °2|‘Œ5S )rþ   Úinputr  r  r  s     r&   r}   z5SamplingHandler._convert_messages.<locals>.<listcomp>;  sI   € ÐyÐyÐy˜q­g°a¸Ñ.@Ô.@ÐyÅWÈQÐPWÑEXÔEXÐyÕahÐijÐlwÑaxÔaxÐy˜ÐyÐyÐyrJ   c                 ór   — g | ]4}t          |d ¦  «        °t          |d¦  «        rt          |d¦  «        °2|‘Œ5S )r  rþ   r  r  r  s     r&   r}   z5SamplingHandler._convert_messages.<locals>.<listcomp><  sr   € ð  Eð  Eð  E Aµw¸qÀ+Ñ7NÔ7Nð  EÕX_Ð`aÐciÑXjÔXjð  EÕovÐwxð  {Bñ  pCô  pCð  E˜að  Eð  Eð  ErJ   Útool)ÚroleÚtool_call_idr  ÚidÚcall_ÚfunctionF©Úensure_ascii©rþ   Ú	arguments)r  Útyper  )r  r×   c                 ó<   — g | ]}t          |d ¦  «        ¯|j        ‘ŒS rh   r  r  s     r&   r}   z5SamplingHandler._convert_messages.<locals>.<listcomp>T  s)   € ÐSÐSÐS¨ÅÈÈ6Ñ@RÔ@RÐS˜aœfÐSÐSÐSrJ   r  r  r   r   rd   ©r  r  ©r!  rd   ÚdataÚmimeTypeÚ	image_urlÚurlzdata:z;base64,)r!  r'  z5Unsupported sampling content block type: %s (skipped))r½   rÿ   r  r¬   r  r
  rp   r  r  r«   rú   rþ   r  r~   ÚjsonÚdumpsr�   r  rr   rd   r&  r%  r   rq   r!  r»   )rò   Úparamsr½   ÚmsgÚblocksÚtool_resultsÚ	tool_usesÚcontent_blocksÚtrÚtc_listÚtuÚmsg_dictÚ
text_partsr„   r  s                  r&   Ú_convert_messagesz!SamplingHandler._convert_messages+  si  € ð  "ˆØ”?ð 8	Nñ 8	NˆCÝ,3°CÐ9JÑ,KÔ,Kð �SÔ(Ð(Ý)¨#¬+µtÑ<Ô<ÐO�”�À3Ä;À-ð ð
 JÐI vÐIÑIÔIˆLØyÐy FÐyÑyÔyˆIð Eð  E¨ð  Eñ  Eô  EˆNð #ð ð �Ø—’Ø"Ø$&¤LØ#×=Ò=¸bÑAÔAð!ð !ñ ô ð ð ð ð %NØ�Ø#ð ð �BØ—N’NÝ% b¨$Ð0F½¸G¹¼Ð0FÐ0FÑGÔGØ *à$&¤GÝU_Ð`bÔ`hÕjnÑUoÔUoð  *C­¬°B´HÈ5Ð)QÑ)QÔ)QÐ)QÕuxÐy{ô  zBñ  vCô  vCð%ð %ð$ð $ñ ô ð ð ð +.¬(À'Ð!JÐ!J�àSÐS¨nÐSÑSÔS�
Øð @Ø*.¯)ª)°JÑ*?Ô*?�H˜YÑ'Ø—’ Ñ)Ô)Ð)Ñ)Øñ Nå�~Ñ&Ô&¨!Ò+Ð+µ¸ÀqÔ8IÈ6Ñ0RÔ0RÐ+Ø—O’O¨S¬XÀ.ÐQRÔBSÔBXÐ$YÐ$YÑZÔZÐZÑZà�EØ!/ð ð ˜Ý" 5¨&Ñ1Ô1ð Ø!ŸLšL°&À%Ä*Ð)MÐ)MÑNÔNÐNÐNÝ$ U¨FÑ3Ô3ð 	½ÀÀzÑ8RÔ8Rð 	Ø!ŸLšLØ(3Ø.3Ð5a¸U¼^Ð5aÐ5aÐUZÔU_Ð5aÐ5aÐ-bð*ð *ñ ô ð ð õ
 #ŸNšNØ WÝ $ U¡¤Ô 4ñô ð ð ð ð NØ Ÿš°´ÀeÐ(LÐ(LÑMÔMÐMùàˆrJ   éÿÿÿÿrÁ   Úcodec                 óP   — t           rt          || ¬¦  «        S t          | ¦  «        ‚)z1Return ErrorData (MCP spec) or raise as fallback.)r8  rÁ   )Ú_MCP_SAMPLING_TYPESr8   r   )rÁ   r8  s     r&   Ú_errorzSamplingHandler._errorr  s-   € õ ð 	9Ý $°Ð8Ñ8Ô8Ð8Ý˜Ñ Ô Ð rJ   c                 óÔ  — | j         dxx         dz  cc<   | j        dk    r%d| _        |                      d| j        › d�¦  «        S | xj        dz  c_        | j        | j        k    r-d| _        |                      d| j        › d| j        › d�¦  «        S g }|j        j        D ]×}|j        j        }t          |t          ¦  «        rW	 t          j        |¦  «        }ni# t          j        t          f$ r( t                               d	| j        |¦  «         d
|i}Y n,w xY wt          |t"          ¦  «        r|nd
t          |¦  «        i}|                     t'          d|j        |j        j        |¬¦  «        ¦  «         ŒØt                               | j        d| j        |j        t3          t3          |dd¦  «        dd¦  «        t5          |¦  «        ¦  «         t7          d||j        d¬¦  «        S )zEBuild a CreateMessageResultWithTools from an LLM tool_calls response.ræ   r   r   z Tool loops disabled for server 'z' (max_tool_rounds=0)z%Tool loop limit exceeded for server 'z' (max z rounds)zRMCP server '%s': malformed tool_calls arguments from LLM (wrapping as raw): %.100sÚ_rawÚtool_use)r!  r  rþ   r  zEMCP server '%s' sampling response: model=%s, tokens=%s, tool_calls=%dÚusageNÚtotal_tokensú?Ú	assistantrÔ   ©r  r  rà   Ú
stopReason)rñ   rß   rð   r;  r(   rÁ   r×   r  r   r¬   r�   r)  ÚloadsÚJSONDecodeErrorrH   r   rq   r~   rp   r<   r  rþ   Úlogrî   rà   r«   rú   r7   )rò   ÚchoiceÚresponser0  ÚtcÚargsÚparseds          r&   Ú_build_tool_use_resultz&SamplingHandler._build_tool_use_result{  sO  € àŒÐ%Ð&Ð&Ô&¨!Ñ+Ð&Ð&Ñ&ð Ô 1Ò$Ð$Ø$%ˆDÔ!Ø—;’;ØZ°4Ô3CÐZÐZÐZñô ð ð 	ÐÔ Ñ"ÐÔØÔ  4Ô#7Ò7Ð7Ø$%ˆDÔ!Ø—;’;ð7¸Ô8Hð 7ð 7ØÔ,ð7ð 7ð 7ñô ð ð
 ˆØ”.Ô+ð 	ð 	ˆBØ”;Ô(ˆDÝ˜$¥Ñ$Ô$ð Qð,Ý!œZ¨Ñ-Ô-�F�FøÝÔ,­jÐ9ð ,ð ,ð ,Ý—N’Nð=àÔ(¨$ñô ð ð
 % d˜^�F�F�Fð,øøøõ ",¨Dµ$Ñ!7Ô!7ÐP˜˜¸fÅcÈ$ÁiÄiÐ=P�à×!Ò!¥.ØØ”5Ø”[Ô%Øð	#ñ #ô #ñ ô ð ð õ 	�
Š
ØÔØSØÔ˜hœnÝ•G˜H g¨tÑ4Ô4°nÀcÑJÔJÝ�ÑÔñ	
ô 	
ð 	
õ ,ØØ"Ø”.Ø ð	
ñ 
ô 
ð 	
s   ÃCÃ;DÄDc                 óf  — d| _         |j        j        pd}t                               | j        d| j        |j        t          t          |dd¦  «        dd¦  «        ¦  «         t          dt          d	t          |¦  «        ¬
¦  «        |j        | j                             |j        d¦  «        ¬¦  «        S )z8Build a CreateMessageResult from a normal text response.r   ry   z6MCP server '%s' sampling response: model=%s, tokens=%sr?  Nr@  rA  rB  rd   r$  rÒ   rC  )rð   rÁ   r  r   rG  rî   r(   rà   r«   r6   r;   ri   Ú_STOP_REASON_MAPr   Úfinish_reason)rò   rH  rI  Úresponse_texts       r&   Ú_build_text_resultz"SamplingHandler._build_text_result´  s¯   € à !ˆÔØœÔ.Ð4°"ˆå�
Š
ØÔØDØÔ˜hœnÝ•G˜H g¨tÑ4Ô4°nÀcÑJÔJñ		
ô 	
ð 	
õ #ØÝ Vµ/À-Ñ2PÔ2PÐQÑQÔQØ”.ØÔ,×0Ò0°Ô1EÀyÑQÔQð	
ñ 
ô 
ð 	
rJ   c                 ó@   — | t          t          ¦   «         ¬¦  «        dœS )z<Return kwargs to pass to ClientSession for sampling support.)Útools)Úsampling_callbackÚsampling_capabilities)r9   r:   ©rò   s    r&   Úsession_kwargszSamplingHandler.session_kwargsÉ  s1   € ð "&Ý%7Ý-Ñ/Ô/ð&ñ &ô &ð
ð 
ð 	
rJ   c           
   ƒ   ó  ‡ ‡
‡‡‡‡‡K  — ‰                       ¦   «         sat                               d‰ j        ‰ j        ¦  «         ‰ j        dxx         dz  cc<   ‰                      d‰ j        › d‰ j        › d�¦  «        S ‰                      t          |dd¦  «        ¦  «        }d	d
l	m
Š
 |p‰ j        pdŠ‰ j        r|‰rz‰‰ j        vrqt                               d‰ j        ‰¦  «         ‰ j        dxx         dz  cc<   ‰                      d‰› d‰ j        › dd                     ‰ j        ¦  «        › �¦  «        S ‰                      |¦  «        Št          |d¦  «        r%|j        r‰                     d	d|j        dœ¦  «         t%          |j        ‰ j        ¦  «        ŠdŠt          |d¦  «        r|j        �|j        ŠdŠt          |dd¦  «        }|rd„ |D ¦   «         Št                               ‰ j        d‰ j        ‰‰t1          ‰¦  «        ¦  «         ˆ
ˆˆˆˆˆˆ fd„}	 t3          j        t3          j        |¦  «        ‰ j        ¬¦  «        ƒ d{V —†}n©# t2          j        $ r> ‰ j        dxx         dz  cc<   ‰                      d‰ j        › d‰ j        › d�¦  «        cY S t<          $ rQ}‰ j        dxx         dz  cc<   ‰                      dt?          tA          |¦  «        ¦  «        › �¦  «        cY d}~S d}~ww xY wt          |dd¦  «        s3‰ j        dxx         dz  cc<   ‰                      d‰ j        › d�¦  «        S |j!        d	         }‰ j        d xx         dz  cc<   t          t          |d!d¦  «        d"d	¦  «        }	tE          |	tF          ¦  «        r‰ j        d#xx         |	z  cc<   |j$        d$k    r7t          |j%        d$¦  «        r"|j%        j&        r‰  '                    ||¦  «        S ‰  (                    ||¦  «        S )%zÇSampling callback invoked by the MCP SDK.

        Conforms to ``SamplingFnT`` protocol.  Returns
        ``CreateMessageResult``, ``CreateMessageResultWithTools``, or
        ``ErrorData``.
        z5MCP server '%s' sampling rate limit exceeded (%d/min)r   r   z)Sampling rate limit exceeded for server 'z' (z requests/minute)ÚmodelPreferencesNr   )Úcall_llmry   z:MCP server '%s' requested model '%s' not in allowed_modelszModel 'z' not allowed for server 'z'. Allowed: ú, ÚsystemPromptÚsystemr#  ÚtemperaturerT  c                 ó˜   — g | ]G}d t          |dd¦  «        t          |dd¦  «        pdt          t          |dd¦  «        ¦  «        dœdœ‘ŒHS )r  rþ   ry   rk   ÚinputSchemaN©rþ   rk   rF   )r!  r  )r«   Ú_normalize_mcp_input_schema)r{   r÷   s     r&   r}   z,SamplingHandler.__call__.<locals>.<listcomp>
  s}   € ð ð ð ð ð 'å '¨¨6°2Ñ 6Ô 6Ý'.¨q°-ÀÑ'DÔ'DÐ'JÈÝ&AÝ# A }°dÑ;Ô;ñ'ô 'ð!ð !ð	ð 	ðð ð rJ   zFMCP server '%s' sampling request: model=%s, max_tokens=%d, messages=%dc            	      ó6   •—  ‰ d‰pd ‰‰‰‰‰j         ¬¦  «        S )NÚmcp)Útaskrà   r½   r_  Ú
max_tokensrT  rÜ   ©rÜ   )r[  Úcall_temperatureÚ
call_toolsrg  r½   Úresolved_modelrò   s   €€€€€€€r&   Ú
_sync_callz,SamplingHandler.__call__.<locals>._sync_call  s8   ø€ Ø�8ØØ$Ð,¨Ø!Ø,Ø%Ø Øœðñ ô ð rJ   rh  z"Sampling LLM call timed out after zs for server 'r¿   zSampling LLM call failed: Úchoicesz5LLM returned empty response (no choices) for server 'rä   r?  r@  rå   r×   ))rû   r   rq   r(   rÚ   rñ   r;  r  r«   Úagent.auxiliary_clientr[  rè   rá   rr   r6  rÿ   r]  ÚinsertÚminrÓ   rÞ   r_  rG  rî   rú   ÚasyncioÚwait_forÚ	to_threadrÜ   ÚTimeoutErrorr   ri   r�   rm  r¬   rç   rP  rÁ   r×   rM  rR  )rò   Úcontextr+  rà   Úserver_toolsrl  rI  r%   rH  r@  r[  ri  rj  rg  r½   rk  s   `         @@@@@@r&   Ú__call__zSamplingHandler.__call__Ô  st  øøøøøøøè è € ð ×%Ò%Ñ'Ô'ð 		Ý�NŠNØGØÔ  $¤,ñô ð ð ŒL˜Ð"Ð"Ô" aÑ'Ð"Ð"Ñ"Ø—;’;ð4¸DÔ<Lð 4ð 4Ø”Lð4ð 4ð 4ñô ð ð ×#Ò#¥G¨FÐ4FÈÑ$MÔ$MÑNÔNˆð 	4Ð3Ð3Ð3Ð3Ð3ð Ð; $Ô"5Ð;¸ˆàÔð 		 >ð 		°nÈDÔL_Ð6_Ð6_Ý�NŠNØLØÔ  .ñô ð ð ŒL˜Ð"Ð"Ô" aÑ'Ð"Ð"Ñ"Ø—;’;ðS˜.ð Sð SØÔ$ðSð SØ26·)²)¸DÔ<OÑ2PÔ2PðSð Sñô ð ð ×)Ò)¨&Ñ1Ô1ˆÝ�6˜>Ñ*Ô*ð 	S¨vÔ/Bð 	SØ�OŠO˜A¨¸VÔ=PÐQÐQÑRÔRÐRõ ˜Ô)¨4Ô+>Ñ?Ô?ˆ
ØÐÝ�6˜=Ñ)Ô)ð 	2¨fÔ.@Ð.LØ%Ô1Ðð ˆ
Ý˜v w°Ñ5Ô5ˆØð 	ðð ð &ðñ ô ˆJõ 	�
Š
ØÔØTØÔ˜n¨j½#¸h¹-¼-ñ	
ô 	
ð 	
ð		ð 		ð 		ð 		ð 		ð 		ð 		ð 		ð 		ð 		ð 		ð	Ý$Ô-ÝÔ! *Ñ-Ô-°t´|ðñ ô ð ð ð ð ð ð ˆHˆHøõ Ô#ð 	ð 	ð 	ØŒL˜Ð"Ð"Ô" aÑ'Ð"Ð"Ñ"Ø—;’;ð3°T´\ð 3ð 3Ø#Ô/ð3ð 3ð 3ñô ð ð ð õ ð 	ð 	ð 	ØŒL˜Ð"Ð"Ô" aÑ'Ð"Ð"Ñ"Ø—;’;ØH­_½SÀ¹X¼XÑ-FÔ-FÐHÐHñô ð ð ð ð ð ð øøøøð	øøøõ �x ¨DÑ1Ô1ð 	ØŒL˜Ð"Ð"Ô" aÑ'Ð"Ð"Ñ"Ø—;’;ð(ØÔ$ð(ð (ð (ñô ð ð Ô! !Ô$ˆØŒ�ZÐ Ð Ô  AÑ%Ð Ð Ñ Ý�w x°¸$Ñ?Ô?ÀÐQRÑSÔSˆÝ�l¥CÑ(Ô(ð 	8ØŒL˜Ð'Ð'Ô'¨<Ñ7Ð'Ð'Ñ'ð Ô  LÒ0Ð0Ý˜œ¨Ñ5Ô5ð 1à”Ô)ð 1ð ×.Ò.¨v°xÑ@Ô@Ð@à×&Ò& v¨xÑ8Ô8Ð8s&   È3I ÉA
K8Ê	K8Ê'AK3Ë-K8Ë3K8N)r7  )r»   Ú
__module__Ú__qualname__Ú__doc__rO  r�   r~   rô   Úboolrû   r   r  Ústaticmethodr  r   r6  rç   r;  rM  rR  rX  rw  rI   rJ   r&   rÑ   rÑ   å  se  € € € € € ð
ð 
ð !*°[ÐPYÐZÐZÐð[ Cð [°ð [ð [ð [ð [ð. 4ð ð ð ð ð¨X°c¬]ð ð ð ð ð ðO¨Cð Oð Oð Oñ „\ðOðC¨4°¬:ð Cð Cð Cð CðN ð!ð !˜ð ! 3ð !ð !ð !ñ „\ð!ð7
ð 7
ð 7
ðr
ð 
ð 
ð*
 ð 
ð 
ð 
ð 
ð}9ð }9ð }9ð }9ð }9rJ   rÑ   c                   ó‚   — e Zd ZdZdZdefd„Zdefd„Zd„ Z	d„ Z
defd	„Zd
efd„Zd
efd„Zd„ Zd
efd„Zd
efd„Zd„ ZdS )ÚMCPServerTaskac  Manages a single MCP server connection in a dedicated asyncio Task.

    The entire connection lifecycle (connect, discover, serve, disconnect)
    runs inside one asyncio Task so that anyio cancel-scopes created by
    the transport client are entered and exited in the same Task context.

    Supports both stdio and HTTP/StreamableHTTP transports.
    )rþ   ÚsessionÚtool_timeoutÚ_taskÚ_readyÚ_shutdown_eventÚ_reconnect_eventÚ_toolsr;  Ú_configÚ	_samplingÚ_registered_tool_namesÚ
_auth_typeÚ_refresh_lockrþ   c                 ó\  — || _         d | _        t          | _        d | _        t          j        ¦   «         | _        t          j        ¦   «         | _        t          j        ¦   «         | _	        g | _
        d | _        i | _        d | _        g | _        d| _        t          j        ¦   «         | _        d S )Nry   )rþ   r  Ú_DEFAULT_TOOL_TIMEOUTr€  r�  rq  ÚEventr‚  rƒ  r„  r…  r;  r†  r‡  rˆ  r‰  ÚLockrŠ  )rò   rþ   s     r&   rô   zMCPServerTask.__init__i  s‰   € ØˆŒ	Ø&*ˆŒÝ#8ˆÔØ-1ˆŒ
Ý”m‘o”oˆŒÝ&œ}™œˆÔõ !(¤¡¤ˆÔØˆŒØ+/ˆŒØˆŒØ48ˆŒØ13ˆÔ#Ø!ˆŒÝ$œ\™^œ^ˆÔÐÐrJ   r	   c                 ó   — d| j         v S )z)Check if this server uses HTTP transport.r(  )r†  rW  s    r&   Ú_is_httpzMCPServerTask._is_http~  s   € à˜œÐ$Ð$rJ   c                 ó   ‡ — ˆ fd„}|S )a  Build a ``message_handler`` callback for ``ClientSession``.

        Dispatches on notification type.  Only ``ToolListChangedNotification``
        triggers a refresh; prompt and resource change notifications are
        logged as stubs for future work.
        c              “   ó„  •K  — 	 t          | t          ¦  «        r#t                               d‰j        | ¦  «         d S t
          rÉt          | t          ¦  «        r¶| j        xt          d˜ x�?\    t           	                    d‰j        ¦  «         ‰ 
                    ¦   «         ƒ d {V —† d S  xt          d˜ x�%\    t                               d‰j        ¦  «         d S  t          d˜ x�$\   t                               d‰j        ¦  «         d S  	 d S d S d S # t          $ r$ t                               d‰j        ¦  «         Y d S w xY w)Nz'MCP message handler (%s): exception: %srI   z9MCP server '%s': received tools/list_changed notificationz/MCP server '%s': prompts/list_changed (ignored)z1MCP server '%s': resources/list_changed (ignored)z%Error in MCP message handler for '%s')r¬   r   r   r   rþ   Ú_MCP_NOTIFICATION_TYPESr=   Úrootr>   râ   Ú_refresh_toolsr?   r@   Ú	exception)rÁ   rò   s    €r&   Ú_handlerz5MCPServerTask._make_message_handler.<locals>._handler‹  s—  øè è € ðUÝ˜g¥yÑ1Ô1ð Ý—L’LÐ!JÈDÌIÐW^Ñ_Ô_Ð_Ø�FÝ*ð !­z¸'ÕCUÑ/VÔ/Vð !Ø!œ,Ø:Õ8Ð:Ð:Ð:Ð:Ñ:Ð:Ý"ŸKšKØ [Ø $¤	ñô ð ð #'×"5Ò"5Ñ"7Ô"7Ð7Ð7Ð7Ð7Ð7Ð7Ð7Ð7Ð7ð ;ð =Õ:Ð<Ð<Ð<Ð<Ñ<Ð<Ý"ŸLšLÐ)ZÐ\`Ô\eÑfÔfÐfÐfÐfð =å<Ð>Ð>Ð>Ð>Ñ>Ý"ŸLšLÐ)\Ð^bÔ^gÑhÔhÐhÐhÐhð ?àØ ˜Dð!ð !ð !ð !øõ ð Uð Uð UÝ× Ò Ð!HÈ$Ì)ÑTÔTÐTÐTÐTÐTðUøøøs)   …6D ½A*D Â)/D Ã-D Ä	D Ä*D?Ä>D?rI   )rò   r—  s   ` r&   Ú_make_message_handlerz#MCPServerTask._make_message_handler„  s(   ø€ ð	Uð 	Uð 	Uð 	Uð 	Uð* ˆrJ   c           	   ƒ   óš  K  — ddl m} | j        4 ƒd{V —† t          | j        ¦  «        }| j                             ¦   «         ƒ d{V —†}t          |d¦  «        r|j        ng }| j        D ]}| 	                    |¦  «         Œ|| _
        t          | j        | | j        ¦  «        | _        t          | j        ¦  «        }||z
  }||z
  }g }	|r8|	                     dd                     t!          |¦  «        ¦  «        › �¦  «         |r8|	                     dd                     t!          |¦  «        ¦  «        › �¦  «         |	r5t"                               d| j        d	                     |	¦  «        ¦  «         n3t"                               d
| j        t)          | j        ¦  «        ¦  «         ddd¦  «        ƒd{V —† dS # 1 ƒd{V —†swxY w Y   dS )ua  Re-fetch tools from the server and update the registry.

        Called when the server sends ``notifications/tools/list_changed``.
        The lock prevents overlapping refreshes from rapid-fire notifications.
        After the initial ``await`` (list_tools), all mutations are synchronous
        â€” atomic from the event loop's perspective.
        r   ©ÚregistryNrT  zadded: r\  z	removed: uU   MCP server '%s': tools changed dynamically â€” %s. Verify these changes are expected.rm   z>MCP server '%s': dynamically refreshed %d tool(s) (no changes))Útools.registryr›  rŠ  Úsetrˆ  r  Ú
list_toolsrÿ   rT  Ú
deregisterr…  Ú_register_server_toolsrþ   r†  rp   rr   Úsortedr   rq   râ   rú   )
rò   r›  Úold_tool_namesÚtools_resultÚnew_mcp_toolsÚprefixed_nameÚnew_tool_namesÚaddedÚremovedÚchangess
             r&   r•  zMCPServerTask._refresh_tools¢  s†  è è € ð 	,Ð+Ð+Ð+Ð+Ð+àÔ%ð %	ð %	ð %	ð %	ð %	ð %	ð %	ð %	å  Ô!<Ñ=Ô=ˆNð "&¤×!8Ò!8Ñ!:Ô!:Ð:Ð:Ð:Ð:Ð:Ð:ˆLÝ29¸,ÈÑ2PÔ2PÐX˜LÔ.Ð.ÐVXˆMð "&Ô!<ð 3ð 3�Ø×#Ò# MÑ2Ô2Ð2Ð2ð (ˆDŒKÝ*@Ø”	˜4 ¤ñ+ô +ˆDÔ'õ
 ! Ô!<Ñ=Ô=ˆNØ" ^Ñ3ˆEØ$ ~Ñ5ˆGØˆGØð EØ—’ÐC¨¯ªµ6¸%±=´=Ñ)AÔ)AÐCÐCÑDÔDÐDØð IØ—’ÐG¨4¯9ª9µV¸G±_´_Ñ+EÔ+EÐGÐGÑHÔHÐHØð 
Ý—’ð9à”I˜tŸyšy¨Ñ1Ô1ñô ð ð õ —’ØTØ”I�s 4Ô#>Ñ?Ô?ñô ð ðE%	ð %	ð %	ñ %	ô %	ð %	ð %	ð %	ð %	ð %	ð %	ð %	ð %	ð %	ð %	ð %	ð %	ð %	ð %	ð %	ð %	ð %	ð %	ð %	øøøð %	ð %	ð %	ð %	ð %	ð %	s   –FF:Æ:
GÇGc              ƒ   óÐ  K  — t          j        | j                             ¦   «         ¦  «        }t          j        | j                             ¦   «         ¦  «        }	 t          j        ||ht           j        ¬¦  «        ƒ d{V —† ||fD ]P}|                     ¦   «         s:|                     ¦   «          	 |ƒ d{V —† Œ4# t           j        t          f$ r Y ŒLw xY wŒQnZ# ||fD ]P}|                     ¦   «         s:|                     ¦   «          	 |ƒ d{V —† Œ4# t           j        t          f$ r Y ŒLw xY wŒQw xY w| j         
                    ¦   «         rdS | j                             ¦   «          dS )a<  Block until either _shutdown_event or _reconnect_event fires.

        Returns:
            "shutdown"  if the server should exit the run loop entirely.
            "reconnect" if the server should tear down the current MCP
                        session and re-enter the transport (fresh OAuth
                        tokens, new session ID, etc.). The reconnect event
                        is cleared before return so the next cycle starts
                        with a fresh signal.

        Shutdown takes precedence if both events are set simultaneously.
        )Úreturn_whenNÚshutdownÚ	reconnect)rq  Úcreate_taskrƒ  Úwaitr„  ÚFIRST_COMPLETEDÚdoneÚcancelÚCancelledErrorr   Úis_setÚclear)rò   Úshutdown_taskÚreconnect_taskr÷   s       r&   Ú_wait_for_lifecycle_eventz'MCPServerTask._wait_for_lifecycle_eventÓ  sÃ  è è € õ  Ô+¨DÔ,@×,EÒ,EÑ,GÔ,GÑHÔHˆÝ Ô,¨TÔ-B×-GÒ-GÑ-IÔ-IÑJÔJˆð	Ý”,Ø Ð/Ý#Ô3ðñ ô ð ð ð ð ð ð ð ð
 $ ^Ð4ð ð �Ø—v’v‘x”xð Ø—H’H‘J”J�JðØ˜˜˜˜˜˜˜˜øÝ#Ô2µIÐ>ð ð ð Ø˜ðøøøð	ðø�m ^Ð4ð ð �Ø—v’v‘x”xð Ø—H’H‘J”J�JðØ˜˜˜˜˜˜˜˜øÝ#Ô2µIÐ>ð ð ð Ø˜ðøøøð	ðøøøð Ô×&Ò&Ñ(Ô(ð 	Ø�:ØÔ×#Ò#Ñ%Ô%Ð%Øˆ{sB   Á(C Â1B:Â:CÃCÃ/D/ÄDÄD/ÄD*	Ä'D/Ä)D*	Ä*D/rØ   c              ƒ   óX  K  — |                      d¦  «        }|                      dg ¦  «        }|                      d¦  «        }|st          d| j        › d�¦  «        ‚t          |¦  «        }t	          ||¦  «        \  }}ddlm}  |||¦  «        }|rt          d| j        › d|› �¦  «        ‚t          |||r|nd	¬
¦  «        }| j        r| j         	                    ¦   «         ni }	t          rt          r|                      ¦   «         |	d<   t          ¦   «         }
t          | j        ¦  «         t          ¦   «         }t!          ||¬¦  «        4 ƒd	{V —†\  }}t          ¦   «         |
z
  }|r4t"          5  |D ]}| j        t$          |<   Œ	 d	d	d	¦  «         n# 1 swxY w Y   t'          ||fi |	¤Ž4 ƒd	{V —†}|                     ¦   «         ƒ d	{V —† || _        |                      ¦   «         ƒ d	{V —† | j                             ¦   «          |                      ¦   «         ƒ d	{V —† d	d	d	¦  «        ƒd	{V —† n# 1 ƒd	{V —†swxY w Y   d	d	d	¦  «        ƒd	{V —† n# 1 ƒd	{V —†swxY w Y   |rCt"          5  |D ]}t$                               |d	¦  «         Œ	 d	d	d	¦  «         d	S # 1 swxY w Y   d	S d	S )z%Run the server using stdio transport.r†   rK  r`   úMCP server 'z' has no 'command' in configr   )Úcheck_package_for_malwarez': N)r†   rK  r`   rB   )Úerrlog)r   rH   rþ   rc   r¢   Útools.osv_checkr»  r1   r‡  rX  r“  Ú_MCP_MESSAGE_HANDLER_SUPPORTEDr˜  Ú_snapshot_child_pidsr/   r'   r2   Ú_lockÚ_stdio_pidsr0   Ú
initializer  Ú_discover_toolsr‚  r�  r¸  Úpop)rò   rØ   r†   rK  rX   Úsafe_envr»  Úmalware_errorÚserver_paramsÚsampling_kwargsÚpids_beforeÚ_errlogÚread_streamÚwrite_streamÚnew_pidsÚ_pidr  s                    r&   Ú
_run_stdiozMCPServerTask._run_stdioõ  sÍ  è è € à—*’*˜YÑ'Ô'ˆØ�zŠz˜& "Ñ%Ô%ˆØ—:’:˜eÑ$Ô$ˆàð 	ÝØF˜tœyÐFÐFÐFñô ð õ # 8Ñ,Ô,ˆÝ2°7¸HÑEÔEÑˆ�ð 	>Ð=Ð=Ð=Ð=Ð=Ø1Ð1°'¸4Ñ@Ô@ˆØð 	ÝØ<˜tœyÐ<Ð<¨]Ð<Ð<ñô ð õ .ØØØ$Ð.��¨$ð
ñ 
ô 
ˆð >B¼^ÐS˜$œ.×7Ò7Ñ9Ô9Ð9ÐQSˆÝ"ð 	NÕ'Eð 	NØ15×1KÒ1KÑ1MÔ1MˆOÐ-Ñ.õ +Ñ,Ô,ˆõ
 	! ¤Ñ+Ô+Ð+Ý%Ñ'Ô'ˆÝ °gÐ>Ñ>Ô>ð 	7ð 	7ð 	7ð 	7ð 	7ð 	7ð 	7ÑB]À;ÐP\å+Ñ-Ô-°Ñ;ˆHØð 6Ýð 6ð 6Ø (ð 6ð 6˜Ø,0¬I� DÑ)Ð)ð6ð6ð 6ð 6ñ 6ô 6ð 6ð 6ð 6ð 6ð 6ð 6øøøð 6ð 6ð 6ð 6õ % [°,ÐRÐRÀ/ÐRÐRð 7ð 7ð 7ð 7ð 7ð 7ð 7ÐV]Ø×(Ò(Ñ*Ô*Ð*Ð*Ð*Ð*Ð*Ð*Ð*Ø&�”Ø×*Ò*Ñ,Ô,Ð,Ð,Ð,Ð,Ð,Ð,Ð,Ø”—’Ñ!Ô!Ð!ð ×4Ò4Ñ6Ô6Ð6Ð6Ð6Ð6Ð6Ð6Ð6ð7ð 7ð 7ñ 7ô 7ð 7ð 7ð 7ð 7ð 7ð 7ð 7ð 7ð 7ð 7ð 7ð 7ð 7ð 7ð 7ð 7ð 7ð 7øøøð 7ð 7ð 7ð 7ð	7ð 	7ð 	7ñ 	7ô 	7ð 	7ð 	7ð 	7ð 	7ð 	7ð 	7ð 	7ð 	7ð 	7ð 	7ð 	7ð 	7ð 	7ð 	7ð 	7ð 	7ð 	7ð 	7øøøð 	7ð 	7ð 	7ð 	7ð" ð 	0Ýð 0ð 0Ø$ð 0ð 0�DÝ—O’O D¨$Ñ/Ô/Ð/Ð/ð0ð0ð 0ð 0ñ 0ô 0ð 0ð 0ð 0ð 0ð 0ð 0ð 0øøøð 0ð 0ð 0ð 0ð 0ð 0ð	0ð 	0sm   ÅIÅ/FÆIÆF	ÆIÆF	ÆIÆ0A/H1ÈIÈ1
H;	È;IÈ>H;	È?IÉ
IÉ!IÉ.!JÊJ!Ê$J!c              ƒ   óf  ‡K  — t           st          d| j        › d�¦  «        ‚|d         }t          |                     d¦  «        pi ¦  «        }t          d„ |D ¦   «         ¦  «        s
t          |d<   |                     dt          ¦  «        }|                     dd	¦  «        }d
}| j        dk    rs	 ddl	m
}  |¦   «                              | j        ||                     d¦  «        ¦  «        }n4# t          $ r'}t                               d| j        |¦  «         ‚ d
}~ww xY w| j        r| j                             ¦   «         ni }	t"          rt$          r|                      ¦   «         |	d<   t(          �r�dd
l}
|
                     |¦  «        Šˆfd„}d	|
                     t1          |¦  «        d¬¦  «        |d|gidœ}|r||d<   |�||d<    |
j        di |¤Ž4 ƒd
{V —†}t5          ||¬¦  «        4 ƒd
{V —†\  }}}t7          ||fi |	¤Ž4 ƒd
{V —†}|                     ¦   «         ƒ d
{V —† || _        |                      ¦   «         ƒ d
{V —† | j                              ¦   «          |  !                    ¦   «         ƒ d
{V —†}|dk    r t           "                    d| j        ¦  «         d
d
d
¦  «        ƒd
{V —† n# 1 ƒd
{V —†swxY w Y   d
d
d
¦  «        ƒd
{V —† n# 1 ƒd
{V —†swxY w Y   d
d
d
¦  «        ƒd
{V —† d
S # 1 ƒd
{V —†swxY w Y   d
S |t1          |¦  «        |dœ}|�||d<   tG          |fi |¤Ž4 ƒd
{V —†\  }}}t7          ||fi |	¤Ž4 ƒd
{V —†}|                     ¦   «         ƒ d
{V —† || _        |                      ¦   «         ƒ d
{V —† | j                              ¦   «          |  !                    ¦   «         ƒ d
{V —†}|dk    r t           "                    d| j        ¦  «         d
d
d
¦  «        ƒd
{V —† n# 1 ƒd
{V —†swxY w Y   d
d
d
¦  «        ƒd
{V —† d
S # 1 ƒd
{V —†swxY w Y   d
S )z3Run the server using HTTP/StreamableHTTP transport.rº  zw' requires HTTP transport but mcp.client.streamable_http is not available. Upgrade the mcp package to get HTTP support.r(  Úheadersc              3   óF   K  — | ]}|                      ¦   «         d k    V — ŒdS )úmcp-protocol-versionN)rí   )r{   ra   s     r&   r	  z*MCPServerTask._run_http.<locals>.<genexpr>B  s0   è è € ÐLÐL¸S�3—9’9‘;”;Ð"8Ò8ÐLÐLÐLÐLÐLÐLrJ   rÓ  Úconnect_timeoutÚ
ssl_verifyTNÚoauthr   ©Úget_managerz#MCP OAuth setup failed for '%s': %srB   c              “   ó   •K  — | j         r| j        rz| j        j        }|j        |j        |j        f‰j        ‰j        ‰j        fk    rF| j        j                             dd¦  «         | j        j                             dd¦  «         dS dS dS dS )zBStrip Authorization headers when redirected to a different origin.ÚauthorizationNÚAuthorization)Úis_redirectÚnext_requestr(  ÚschemeÚhostÚportrÑ  rÄ  )rI  ÚtargetÚ_original_urls     €r&   Ú$_strip_auth_on_cross_origin_redirectzEMCPServerTask._run_http.<locals>._strip_auth_on_cross_origin_redirectc  s»   øè è € àÔ'ð Q¨HÔ,Að QØ%Ô2Ô6�FØœ v¤{°F´KÐ@Ø%Ô,¨mÔ.@À-ÔBTðEò ð ð !Ô-Ô5×9Ò9¸/È4ÑPÔPÐPØ Ô-Ô5×9Ò9¸/È4ÑPÔPÐPÐPÐPðQð Qð Qð Qðð rJ   g     Àr@)ÚreadrI  )Úfollow_redirectsrÜ   ÚverifyÚevent_hooksÚauth)Úhttp_clientr­  uB   MCP server '%s': reconnect requested â€” tearing down HTTP session)rÑ  rÜ   ræ  uI   MCP server '%s': reconnect requested â€” tearing down legacy HTTP sessionrI   )$Ú_MCP_HTTP_AVAILABLEÚImportErrorrþ   r~   r   Úanyr5   Ú_DEFAULT_CONNECT_TIMEOUTr‰  Útools.mcp_oauth_managerrØ  Úget_or_build_providerr   r   rq   r‡  rX  r“  r¾  r˜  Ú_MCP_NEW_HTTPÚhttpxÚURLÚTimeoutrÆ   ÚAsyncClientr4   r0   rÂ  r  rÃ  r‚  r�  r¸  râ   r3   )rò   rØ   r(  rÑ  rÔ  rÕ  Ú_oauth_authrØ  r%   rÈ  rñ  rã  Úclient_kwargsré  rË  rÌ  Ú_get_session_idr  ru   Ú_http_kwargsrâ  s                       @r&   Ú	_run_httpzMCPServerTask._run_http3  sÓ  øè è € å"ð 	Ýð?˜tœyð ?ð ?ð ?ñô ð ð �UŒmˆÝ�v—z’z )Ñ,Ô,Ð2°Ñ3Ô3ˆõ
 ÐLÐLÀGÐLÑLÔLÑLÔLð 	FÝ.EˆGÐ*Ñ+Ø Ÿ*š*Ð%6Õ8PÑQÔQˆØ—Z’Z ¨dÑ3Ô3ˆ
ð ˆØŒ?˜gÒ%Ð%ðØ?Ð?Ð?Ð?Ð?Ð?Ø)˜k™mœm×AÒAØ”I˜s F§J¢J¨wÑ$7Ô$7ñô ��øõ ð ð ð Ý—’ÐDÀdÄiÐQTÑUÔUÐUØøøøøðøøøð >B¼^ÐS˜$œ.×7Ò7Ñ9Ô9Ð9ÐQSˆÝ"ð 	NÕ'Eð 	NØ15×1KÒ1KÑ1MÔ1MˆOÐ-Ñ.åñ C	ð ˆLˆLˆLà!ŸIšI c™NœNˆMðQð Qð Qð Qð Qð %)Ø Ÿ=š=­¨Ñ)?Ô)?Àe˜=ÑLÔLØ$Ø *Ð-QÐ,RÐSð	#ð #ˆMð ð 3Ø+2�˜iÑ(ØÐ&Ø(3�˜fÑ%ð )�uÔ(Ð9Ð9¨=Ð9Ð9ð ð ð ð ð ð ð ¸[Ý1°#À;ÐOÑOÔOð ð ð ð ð ð ð ñ TØ ¨å,¨[¸,ÐZÐZÈ/ÐZÐZð 
ð 
ð 
ð 
ð 
ð 
ð 
Ð^eØ%×0Ò0Ñ2Ô2Ð2Ð2Ð2Ð2Ð2Ð2Ð2Ø'.˜œØ"×2Ò2Ñ4Ô4Ð4Ð4Ð4Ð4Ð4Ð4Ð4ØœŸšÑ)Ô)Ð)Ø'+×'EÒ'EÑ'GÔ'GÐ!GÐ!GÐ!GÐ!GÐ!GÐ!G˜Ø! [Ò0Ð0Ý"ŸKšKð!<Ø=A¼Yñô ð ð
ð 
ð 
ñ 
ô 
ð 
ð 
ð 
ð 
ð 
ð 
ð 
ð 
ð 
ð 
ð 
ð 
ð 
ð 
ð 
ð 
ð 
ð 
øøøð 
ð 
ð 
ð 
ðð ð ñ ô ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð øøøð ð ð ð ðð ð ñ ô ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð øøøð ð ð ð ð ð ð$ #Ý  Ñ1Ô1Ø$ð"ð "ˆLð
 Ð&Ø'2�˜VÑ$Ý,¨SÐAÐA°LÐAÐAð ð ð ð ð ð ð ñ FØ˜\¨?å(¨°lÐVÐVÀoÐVÐVð 
ð 
ð 
ð 
ð 
ð 
ð 
ÐZaØ!×,Ò,Ñ.Ô.Ð.Ð.Ð.Ð.Ð.Ð.Ð.Ø#*�D”LØ×.Ò.Ñ0Ô0Ð0Ð0Ð0Ð0Ð0Ð0Ð0Ø”K—O’OÑ%Ô%Ð%Ø#'×#AÒ#AÑ#CÔ#CÐCÐCÐCÐCÐCÐC�FØ Ò,Ð,ÝŸšð?Ø@DÄ	ñô ð ð
ð 
ð 
ñ 
ô 
ð 
ð 
ð 
ð 
ð 
ð 
ð 
ð 
ð 
ð 
ð 
ð 
ð 
ð 
ð 
ð 
ð 
ð 
øøøð 
ð 
ð 
ð 
ðð ð ñ ô ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð øøøð ð ð ð ð ð sª   Â1=C/ Ã/
D Ã9"DÄD ÇK<Ç5KÈBJ5Ê#KÊ5
J?Ê?KËJ?ËKËK<Ë
K"	Ë"K<Ë%K"	Ë&K<Ë<
LÌ	LÌ<P ÍBO<Ï*P Ï<
P	ÐP Ð	P	Ð
P Ð 
P*Ð-P*c              ƒ   ó–   K  — | j         €dS | j                              ¦   «         ƒ d{V —†}t          |d¦  «        r|j        ng | _        dS )z*Discover tools from the connected session.NrT  )r  rž  rÿ   rT  r…  )rò   r£  s     r&   rÃ  zMCPServerTask._discover_tools¡  sb   è è € àŒ<ÐØˆFØ!œ\×4Ò4Ñ6Ô6Ð6Ð6Ð6Ð6Ð6Ð6ˆõ �| WÑ-Ô-ðˆLÔÐàð 	ŒˆˆrJ   c           	   ƒ   óö  K  — || _         |                     dt          ¦  «        | _        |                     d¦  «        pd                     ¦   «                              ¦   «         | _        |                     di ¦  «        }|                     dd¦  «        r"t          rt          | j	        |¦  «        | _
        nd| _
        d|v r$d	|v r t                               d
| j	        ¦  «         d}d}d}	 	 |                      ¦   «         r|                      |¦  «        ƒ d{V —† n|                      |¦  «        ƒ d{V —† | j                             ¦   «         r
	 d| _        dS t                               d| j	        ¦  «         d| _        	 d| _        Œ # t(          $ �rI}d| _        | j                             ¦   «         �s|dz  }|t,          k    rTt                               d| j	        t,          |¦  «         || _        | j                             ¦   «          Y d}~d| _        dS t                               d| j	        |t,          ||¦  «         t3          j        |¦  «        ƒ d{V —† t7          |dz  t8          ¦  «        }| j                             ¦   «         r-|| _        | j                             ¦   «          Y d}~d| _        dS Y d}~d| _        �ŒÞ| j                             ¦   «         r.t                               d| j	        |¦  «         Y d}~d| _        dS |dz  }|t<          k    r4t                               d| j	        t<          |¦  «         Y d}~d| _        dS t                               d| j	        |t<          ||¦  «         t3          j        |¦  «        ƒ d{V —† t7          |dz  t8          ¦  «        }| j                             ¦   «         rY d}~d| _        dS Y d}~nd}~ww xY w	 d| _        n# d| _        w xY w�Œ)zÙLong-lived coroutine: connect, discover tools, wait, disconnect.

        Includes automatic reconnection with exponential backoff if the
        connection drops unexpectedly (unless shutdown was requested).
        rÜ   rè  ry   ÚsamplingÚenabledTNr(  r†   zMCP server '%s' has both 'url' and 'command' in config. Using HTTP transport ('url'). Remove 'command' to silence this warning.r   g      ð?z@MCP server '%s': reconnecting (OAuth recovery or manual refresh)r   zJMCP server '%s' failed initial connection after %d attempts, giving up: %szPMCP server '%s' initial connection failed (attempt %d/%d), retrying in %.0fs: %sé   z0MCP server '%s' disconnected during shutdown: %szDMCP server '%s' failed after %d reconnection attempts, giving up: %szJMCP server '%s' connection lost (attempt %d/%d), reconnecting in %.0fs: %s)r†  r   rŒ  r€  rí   r‘   r‰  r:  rÑ   rþ   r‡  r   rq   r�  rù  rÏ  rƒ  r´  r  râ   r   r‚  Ú_MAX_INITIAL_CONNECT_RETRIESr;  r�  rq  Úsleeprp  Ú_MAX_BACKOFF_SECONDSr   Ú_MAX_RECONNECT_RETRIES)rò   rØ   Úsampling_configÚretriesÚinitial_retriesÚbackoffr%   s          r&   ÚrunzMCPServerTask.run¬  s¬  è è € ð ˆŒØ"ŸJšJ yÕ2GÑHÔHˆÔØ!Ÿ:š: fÑ-Ô-Ð3°×:Ò:Ñ<Ô<×BÒBÑDÔDˆŒð !Ÿ*š* Z°Ñ4Ô4ˆØ×Ò˜y¨$Ñ/Ô/ð 	"Õ4Gð 	"Ý,¨T¬Y¸ÑHÔHˆDŒNˆNà!ˆDŒNð �Fˆ?ˆ?˜y¨FÐ2Ð2Ý�NŠNð ð ”	ñ	ô ð ð ˆØˆØˆðZ	$ðY$Ø—=’=‘?”?ð 2ØŸ.š.¨Ñ0Ô0Ð0Ð0Ð0Ð0Ð0Ð0Ð0Ð0àŸ/š/¨&Ñ1Ô1Ð1Ð1Ð1Ð1Ð1Ð1Ð1ð Ô'×.Ò.Ñ0Ô0ð Øð\  $�”��õ[ —’ð&à”Iñô ð ð  $�”ð ðD  $�”�øõC ð ?ñ ?ð ?Ø#�”ð ”{×)Ò)Ñ+Ô+ñ Ø# qÑ(�OØ&Õ)EÒEÐEÝŸšð9à œIÕ'CÀSñô ð ð
 '*˜œØœŸšÑ)Ô)Ð)Ø˜˜˜ð`  $�”��õ] —N’NðAàœ	 ?Ý4°g¸sñ	ô ð õ "œ-¨Ñ0Ô0Ð0Ð0Ð0Ð0Ð0Ð0Ð0Ý! '¨A¡+Õ/CÑDÔD�Gð Ô+×2Ò2Ñ4Ô4ð Ø&)˜œØœŸšÑ)Ô)Ð)Ø˜˜˜ðB  $�”��ðA �H�H�Hð@  $�”‘ð; Ô'×.Ò.Ñ0Ô0ð Ý—L’LØJØœ	 3ñô ð ð �F�F�Fð0  $�”��ð- ˜1‘�ØÕ3Ò3Ð3Ý—N’Nð(àœ	Õ#9¸3ñô ð ð
 �F�F�Fð  $�”��õ —’ð0à”I˜wÕ(>Ø˜Sñ	ô ð õ ”m GÑ,Ô,Ð,Ð,Ð,Ð,Ð,Ð,Ð,Ý˜g¨™kÕ+?Ñ@Ô@�ð Ô'×.Ò.Ñ0Ô0ð Ø�F�F�Fà#�”��ðð ð ð ð øøøøð}?øøøð|ð  $�”�ø˜t�”Ð#Ð#Ð#Ð#ñuZ	$sp   Ã/A$F Å'F ÆO!ÆA8OÈO- ÈBOÊ1O- Ê>O- Ë:OÌO- Ì7OÍ	O- ÍA4OÏ
O- ÏO- ÏO!Ï!O- Ï-	O6c              ƒ   ó¼   K  — t          j        |                      |¦  «        ¦  «        | _        | j                             ¦   «         ƒ d{V —† | j        r| j        ‚dS )z<Create the background Task and wait until ready (or failed).N)rq  Úensure_futurer  r�  r‚  r¯  r;  )rò   rØ   s     r&   ÚstartzMCPServerTask.start%  sf   è è € åÔ*¨4¯8ª8°FÑ+;Ô+;Ñ<Ô<ˆŒ
ØŒk×ÒÑ Ô Ð Ð Ð Ð Ð Ð Ð ØŒ;ð 	Ø”+Ðð	ð 	rJ   c              ƒ   ól  K  — ddl m} | j                             ¦   «          | j                             ¦   «          | j        r®| j                             ¦   «         s•	 t          j        | j        d¬¦  «        ƒ d{V —† nr# t          j	        $ r` t                               d| j        ¦  «         | j                             ¦   «          	 | j        ƒ d{V —† n# t          j        $ r Y nw xY wY nw xY wt          t!          | dg ¦  «        ¦  «        D ]}|                     |¦  «         Œg | _        d| _        dS )z=Signal the Task to exit and wait for clean resource teardown.r   rš  rÛ   rh  Nz3MCP server '%s' shutdown timed out, cancelling taskrˆ  )rœ  r›  rƒ  r�  r„  r�  r±  rq  rr  rt  r   rq   rþ   r²  r³  r
  r«   rŸ  rˆ  r  )rò   r›  rj   s      r&   r¬  zMCPServerTask.shutdown,  s|  è è € à+Ð+Ð+Ð+Ð+Ð+àÔ× Ò Ñ"Ô"Ð"ð 	Ô×!Ò!Ñ#Ô#Ð#ØŒ:ð 	˜dœjŸošoÑ/Ô/ð 	ðÝÔ& t¤z¸2Ð>Ñ>Ô>Ð>Ð>Ð>Ð>Ð>Ð>Ð>Ð>øÝÔ'ð 	ð 	ð 	Ý—’ØIØ”Iñô ð ð ”
×!Ò!Ñ#Ô#Ð#ðØœ*Ð$Ð$Ð$Ð$Ð$Ð$Ð$Ð$øÝÔ-ð ð ð Ø�Dðøøøøøð	øøøõ �g dÐ,DÀbÑIÔIÑJÔJð 	+ð 	+ˆIØ×Ò 	Ñ*Ô*Ð*Ð*Ø&(ˆÔ#ØˆŒˆˆs7   Á!A> Á>AC-ÃCÃC-ÃC'Ã$C-Ã&C'Ã'C-Ã,C-N)r»   rx  ry  rz  Ú	__slots__r�   rô   r{  r�  r˜  r•  r¸  r~   rÏ  rù  rÃ  r  r
  r¬  rI   rJ   r&   r~  r~  X  s-  € € € € € ðð ð€Ið,˜Sð ,ð ,ð ,ð ,ð*%˜$ð %ð %ð %ð %ðð ð ð</ð /ð /ðb °ð  ð  ð  ð  ðD<0 tð <0ð <0ð <0ð <0ð|l dð lð lð lð lð\	
ð 	
ð 	
ðw$ ð w$ð w$ð w$ð w$ðr $ð ð ð ð ðð ð ð ð rJ   r~  Ú_serversÚ_server_error_countsÚ_server_breaker_opened_atg      N@c                 ó¦   — t                                | d¦  «        dz   }|t           | <   |t          k    rt          j        ¦   «         t
          | <   dS dS )a  Increment the consecutive-failure count for ``server_name``.

    When the count crosses :data:`_CIRCUIT_BREAKER_THRESHOLD`, stamp the
    breaker-open timestamp so the cooldown clock starts (or re-starts,
    for probe failures in the half-open state).
    r   r   N)r  r   Ú_CIRCUIT_BREAKER_THRESHOLDrù   Ú	monotonicr  )r(   Úns     r&   Ú_bump_server_errorr  g  sV   € õ 	× Ò  ¨aÑ0Ô0°1Ñ4€AØ()Õ˜Ñ%ØÕ&Ò&Ð&Ý15´Ñ1AÔ1AÕ! +Ñ.Ð.Ð.ð 'Ð&rJ   c                 óP   — dt           | <   t                               | d¦  «         dS )zëFully close the breaker for ``server_name``.

    Clears both the failure count and the breaker-open timestamp. Call
    this on any unambiguous success signal (successful tool call,
    successful reconnect, manual /mcp refresh).
    r   N)r  r  rÄ  )r(   s    r&   Ú_reset_server_errorr  t  s+   € ð )*Õ˜Ñ%Ý×!Ò! +¨tÑ4Ô4Ð4Ð4Ð4rJ   rI   Ú_AUTH_ERROR_TYPESc                  óÄ  — t           rt           S g } 	 ddlm}m} |                      ||g¦  «         n# t
          $ r Y nw xY w	 ddlm} |                      |¦  «         n# t
          $ r Y nw xY w	 ddlm	} |                      |¦  «         n# t
          $ r Y nw xY w	 ddl
}|                      |j        ¦  «         n# t
          $ r Y nw xY wt          | ¦  «        a t           S )u¨  Return a tuple of exception types that indicate MCP OAuth failure.

    Cached after first call. Includes:
      - ``mcp.client.auth.OAuthFlowError`` / ``OAuthTokenError`` â€” raised by
        the SDK's auth flow when discovery, refresh, or full re-auth fails.
      - ``mcp.client.auth.UnauthorizedError`` (older MCP SDKs) â€” kept as an
        optional import for forward/backward compatibility.
      - ``tools.mcp_oauth.OAuthNonInteractiveError`` â€” raised by our callback
        handler when no user is present to complete a browser flow.
      - ``httpx.HTTPStatusError`` â€” caller must additionally check
        ``status_code == 401`` via :func:`_is_auth_error`.
    r   )ÚOAuthFlowErrorÚOAuthTokenError)ÚUnauthorizedError)ÚOAuthNonInteractiveErrorN)r  Úmcp.client.authr  r  r¹   rë  r  rp   Útools.mcp_oauthr  rñ  ÚHTTPStatusErrorÚtuple)Útypesr  r  r  r  rñ  s         r&   Ú_get_auth_error_typesr"  ‡  s`  € õ ð !Ý Ð Ø€EðØCÐCÐCÐCÐCÐCÐCÐCØ�Š�n oÐ6Ñ7Ô7Ð7Ð7øÝð ð ð Øˆðøøøðà5Ð5Ð5Ð5Ð5Ð5Ø�ŠÐ&Ñ'Ô'Ð'Ð'øÝð ð ð ØˆðøøøðØ<Ð<Ð<Ð<Ð<Ð<Ø�ŠÐ-Ñ.Ô.Ð.Ð.øÝð ð ð ØˆðøøøðØˆˆˆØ�Š�UÔ*Ñ+Ô+Ð+Ð+øÝð ð ð Øˆðøøøå˜e™œÐÝÐsB   ’2 ²
?¾?ÁA Á
A,Á+A,Á0B Â
BÂBÂB< Â<
C	ÃC	c                 óÔ   — t          ¦   «         }|rt          | |¦  «        sdS 	 ddl}t          | |j        ¦  «        rt	          | j        dd¦  «        dk    S n# t          $ r Y nw xY wdS )z÷Return True if ``exc`` indicates an MCP OAuth failure.

    ``httpx.HTTPStatusError`` is only treated as auth-related when the
    response status code is 401. Other HTTP errors fall through to the
    generic error path in the tool handlers.
    Fr   NÚstatus_codei‘  T)r"  r¬   rñ  r  r«   rI  rë  )r%   r!  rñ  s      r&   Ú_is_auth_errorr%  ±  s•   € õ "Ñ#Ô#€EØð �
 3¨Ñ.Ô.ð ØˆuðØˆˆˆÝ�c˜5Ô0Ñ1Ô1ð 	EÝ˜3œ<¨¸Ñ=Ô=ÀÒDÐDð	Eøåð ð ð Øˆðøøøàˆ4s   ¤2A Á
A%Á$A%Úop_descriptionc                 ó¨  ‡ ‡— t          |¦  «        sdS ddlm}  |¦   «         Šˆˆ fd„}	 t           |¦   «         d¬¦  «        }n5# t          $ r(}t
                               d‰ |¦  «         d}Y d}~nd}~ww xY w|�r§t          5  t           	                    ‰ ¦  «        }ddd¦  «         n# 1 swxY w Y   |�Åt          |d	¦  «        rµt          }	|	�¬|	                     ¦   «         r˜|	                     |j        j        ¦  «         t!          j        ¦   «         d
z   }
t!          j        ¦   «         |
k     rL|j        �|j                             ¦   «         rn+t!          j        d¦  «         t!          j        ¦   «         |
k     °Lt-          ‰ ¦  «         	  |¦   «         }	 t/          j        |¦  «        }d|vrt-          ‰ ¦  «         |S n-# t.          j        t4          f$ r t-          ‰ ¦  «         |cY S w xY wn4# t          $ r'}t
                               d‰ ||¦  «         Y d}~nd}~ww xY wt7          ‰ ¦  «         t/          j        d‰ › d‰ › d�d‰ dœd¬¦  «        S )aQ  Attempt auth recovery and one retry; return None to fall through.

    Called by the 5 MCP tool handlers when ``session.<op>()`` raises an
    auth-related exception. Workflow:

      1. Ask :class:`tools.mcp_oauth_manager.MCPOAuthManager.handle_401` if
         recovery is viable (i.e., disk has fresh tokens, or the SDK can
         refresh in-place).
      2. If yes, set the server's ``_reconnect_event`` so the server task
         tears down the current MCP session and rebuilds it with fresh
         credentials. Wait briefly for ``_ready`` to re-fire.
      3. Retry the operation once. Return the retry result if it produced
         a non-error JSON payload. Otherwise return the ``needs_reauth``
         error dict so the model stops hallucinating manual refresh.
      4. Return None if ``exc`` is not an auth error, signalling the
         caller to use the generic error path.

    Args:
        server_name: Name of the MCP server that raised.
        exc: The exception from the failed tool call.
        retry_call: Zero-arg callable that re-runs the tool call, returning
            the same JSON string format as the handler.
        op_description: Human-readable name of the operation (for logs).

    Returns:
        A JSON string if auth recovery was attempted, or None to fall
        through to the caller's generic error path.
    Nr   r×  c               “   ó@   •K  — ‰                       ‰d ¦  «        ƒ d {V —†S ©N)Ú
handle_401)Úmanagerr(   s   €€r&   Ú_recoverz._handle_auth_error_and_retry.<locals>._recoverì  s/   øè è € Ø×'Ò'¨°TÑ:Ô:Ð:Ð:Ð:Ð:Ð:Ð:Ð:rJ   rÛ   rh  z+MCP OAuth '%s': recovery attempt failed: %sFr„  é   ç      Ð?Úerrorz.MCP %s/%s retry after auth recovery failed: %srº  z4' requires re-authentication. Run `hermes mcp login u‚   ` (or delete the tokens file under ~/.hermes/mcp-tokens/ and restart). Do NOT retry this tool â€” ask the user to re-authenticate.T)r/  Úneeds_reauthÚserverr  )r%  rî  rØ  Ú_run_on_mcp_loopr   r   rq   rÀ  r  r   rÿ   Ú	_mcp_loopÚ
is_runningÚcall_soon_threadsafer„  r�  rù   r  r  r‚  r´  r   r  r)  rE  rF  rG   r  r*  )r(   r%   Ú
retry_callr&  rØ  r,  Ú	recoveredÚrec_excÚsrvÚloopÚdeadlinerÎ   rL  Ú	retry_excr+  s   `             @r&   Ú_handle_auth_error_and_retryr=  Ä  sA  øø€ õD ˜#ÑÔð Øˆtà3Ð3Ð3Ð3Ð3Ð3Øˆk‰mŒm€Gð;ð ;ð ;ð ;ð ;ð ;ðÝ$ X X¡Z¤Z¸Ð<Ñ<Ô<ˆ	ˆ	øÝð ð ð Ý�ŠØ9Ø˜ñ	
ô 	
ð 	
ð ˆ	ˆ	ˆ	ˆ	ˆ	ˆ	øøøøðøøøð ñ (Ýð 	,ð 	,Ý—,’,˜{Ñ+Ô+ˆCð	,ð 	,ð 	,ñ 	,ô 	,ð 	,ð 	,ð 	,ð 	,ð 	,ð 	,øøøð 	,ð 	,ð 	,ð 	,àˆ?�w sÐ,>Ñ?Ô?ˆ?ÝˆDØÐ D§O¢OÑ$5Ô$5ÐØ×)Ò)¨#Ô*>Ô*BÑCÔCÐCõ  œ>Ñ+Ô+¨bÑ0�Ý”nÑ&Ô&¨Ò1Ð1Ø”{Ð.°3´:×3DÒ3DÑ3FÔ3FÐ.ØÝ”J˜tÑ$Ô$Ð$õ ”nÑ&Ô&¨Ò1Ð1õ 	˜KÑ(Ô(Ð(ð	Ø�Z‘\”\ˆFðÝœ FÑ+Ô+�Ø &Ð(Ð(Ý'¨Ñ4Ô4Ð4Ø!�Mð )øõ Ô(­)Ð4ð ð ð Ý# KÑ0Ô0Ð0Ø���ðøøøð )øõ ð 	ð 	ð 	Ý�NŠNØ@Ø˜^¨Yñô ð ð ð ð ð ð øøøøð	øøøõ �{Ñ#Ô#Ð#ÝŒ:ð>˜;ð >ð >Ø%0ð>ð >ð >ð
 Øð	ð 	ð ð	ñ 	ô 	ð 	se   «A Á
A7ÁA2Á2A7ÂB+Â+B/Â2B/Æ
G0 Æ(G ÇG0 Ç'G,Ç)G0 Ç+G,Ç,G0 Ç0
H!Ç:HÈH!)zinvalid or expired sessionzexpired sessionzsession expiredzsession not foundzunknown sessionÚ_SESSION_EXPIRED_MARKERSc                 ó¼   ‡— t          | t          ¦  «        rdS t          | ¦  «                             ¦   «         Š‰sdS t	          ˆfd„t
          D ¦   «         ¦  «        S )uç  Return True if ``exc`` looks like an MCP transport session expiry.

    Streamable HTTP MCP servers may garbage-collect server-side session
    state while the OAuth token remains valid â€” idle TTL, server
    restart, horizontal-scaling pod rotation, etc.  The SDK surfaces
    this as a JSON-RPC error whose message contains phrases like
    ``"Invalid or expired session"``.  This class of failure is
    distinct from :func:`_is_auth_error`: re-running the OAuth refresh
    flow would be pointless because the access token is fine.  What's
    needed is a transport reconnect â€” tear down and rebuild the
    ``streamablehttp_client`` + ``ClientSession`` pair, which is
    exactly what ``MCPServerTask._reconnect_event`` triggers.
    Fc              3   ó    •K  — | ]}|‰v V — Œ	d S r)  rI   )r{   Úmarkerr,  s     €r&   r	  z,_is_session_expired_error.<locals>.<genexpr>V  s'   øè è € ÐDÐD ˆv˜ˆ}ÐDÐDÐDÐDÐDÐDrJ   )r¬   ÚInterruptedErrorr�   rí   rì  r>  )r%   r,  s    @r&   Ú_is_session_expired_errorrC  ?  se   ø€ õ �#Õ'Ñ(Ô(ð Øˆuõ
 ˆc‰(Œ(�.Š.Ñ
Ô
€CØð ØˆuÝÐDÐDÐDÐDÕ+CÐDÑDÔDÑDÔDÐDrJ   c                 óÌ  — t          |¦  «        sdS t          5  t                               | ¦  «        }ddd¦  «         n# 1 swxY w Y   |�t	          |d¦  «        sdS t
          }|�|                     ¦   «         sdS t                               d| ||¦  «         | 	                    |j
        j        ¦  «         t          j        ¦   «         dz   }d}t          j        ¦   «         |k     rN|j        �|j                             ¦   «         rd}n+t          j        d¦  «         t          j        ¦   «         |k     °N|st                               d| ¦  «         dS 	  |¦   «         }	 t'          j        |¦  «        }	d	|	vrd
t*          | <   |S n(# t&          j        t.          f$ r d
t*          | <   |cY S w xY wn4# t0          $ r'}
t                               d| ||
¦  «         Y d}
~
nd}
~
ww xY wdS )uO  Trigger a transport reconnect and retry once on session expiry.

    Unlike :func:`_handle_auth_error_and_retry`, this does **not** call
    the OAuth manager's ``handle_401`` â€” the access token is still
    valid, only the server-side session state is stale.  Setting
    ``_reconnect_event`` causes the server task's lifecycle loop to
    tear down the current ``streamablehttp_client`` + ``ClientSession``
    and rebuild them, reusing the existing OAuth provider instance.
    See #13383.

    Args:
        server_name: Name of the MCP server that raised.
        exc: The exception from the failed call.
        retry_call: Zero-arg callable that re-runs the operation,
            returning the same JSON string format as the handler.
        op_description: Human-readable name of the operation (logs).

    Returns:
        A JSON string if reconnect + retry was attempted and produced
        a response, or ``None`` to fall through to the caller's
        generic error path (not a session-expired error, no server
        record, reconnect didn't ready in time, or retry also failed).
    Nr„  zmMCP server '%s': %s failed with session-expired error (%s); signalling transport reconnect and retrying once.r-  FTr.  zsMCP server '%s': reconnect did not ready within 15s after session-expired error; falling through to error response.r/  r   z2MCP %s/%s retry after session reconnect failed: %s)rC  rÀ  r  r   rÿ   r3  r4  r   râ   r5  r„  r�  rù   r  r  r‚  r´  r   rq   r)  rE  r  rF  rG   r   )r(   r%   r6  r&  r9  r:  r;  ÚreadyrÎ   rL  r<  s              r&   Ú!_handle_session_expired_and_retryrF  Y  s~  € õ: % SÑ)Ô)ð Øˆtå	ð (ð (Ý�lŠl˜;Ñ'Ô'ˆð(ð (ð (ñ (ô (ð (ð (ð (ð (ð (ð (øøøð (ð (ð (ð (à
€{�' #Ð'9Ñ:Ô:€{Øˆtå€DØ€|˜4Ÿ?š?Ñ,Ô,€|Øˆtå
‡K‚Kð	<à�^ Sñô ð ð 	×Ò˜cÔ2Ô6Ñ7Ô7Ð7ÝŒ~ÑÔ "Ñ$€HØ€EÝ
Œ.Ñ
Ô
˜XÒ
%Ð
%ØŒ;Ð" s¤z×'8Ò'8Ñ':Ô':Ð"ØˆEØÝŒ
�4ÑÔÐõ	 Œ.Ñ
Ô
˜XÒ
%Ð
%ð
 ð Ý�ŠðHàñ	
ô 	
ð 	
ð
 ˆtð
Ø�‘”ˆð	Ý”Z Ñ'Ô'ˆFØ˜fÐ$Ð$Ø45Õ$ [Ñ1Ø�ð %øõ Ô$¥iÐ0ð 	ð 	ð 	Ø01Õ  Ñ-ØˆMˆMˆMð	øøøð %øõ ð 
ð 
ð 
Ý�ŠØ@Ø˜¨ñ	
ô 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
øøøøð
øøøð
 ˆ4sM   ™A Á AÁAÅ
F0 Å"#F ÆF0 Æ"F,Æ)F0 Æ+F,Æ,F0 Æ0
G!Æ:GÇG!r3  Ú_mcp_threadrÁ  c                  óÎ  — t          j        ¦   «         } 	 d| › d| › d�}t          |¦  «        5 }d„ |                     ¦   «                              ¦   «         D ¦   «         cddd¦  «         S # 1 swxY w Y   n# t
          t          t          f$ r Y nw xY w	 ddl}d„ | 	                    | ¦  «         
                    ¦   «         D ¦   «         S # t          $ r Y nw xY wt          ¦   «         S )z»Return a set of current child process PIDs.

    Uses /proc on Linux, falls back to psutil, then empty set.
    Used by _run_stdio to identify the subprocess spawned by stdio_client.
    z/proc/z/task/z	/childrenc                 óT   — h | ]%}|                      ¦   «         ¯t          |¦  «        ’Œ&S rI   )r‘   rç   )r{   Úps     r&   ú	<setcomp>z'_snapshot_child_pids.<locals>.<setcomp>Æ  s+   € ÐBÐBÐB˜q¸¿º¹	¼	ÐB•C˜‘F”FÐBÐBÐBrJ   Nr   c                 ó   — h | ]	}|j         ’Œ
S rI   )Úpid)r{   Úcs     r&   rK  z'_snapshot_child_pids.<locals>.<setcomp>Í  s   € ÐAÐAÐA˜!�”ÐAÐAÐArJ   )r   Úgetpidr   rä  r€   r­   ÚOSErrorrH   ÚpsutilÚProcessÚchildrenr   r�  )Úmy_pidÚchildren_pathÚfrQ  s       r&   r¿  r¿  º  sW  € õ ŒY‰[Œ[€FðØ@ Ð@Ð@¨vÐ@Ð@Ð@ˆÝ�-Ñ Ô ð 	C AØBÐB A§F¢F¡H¤H§N¢NÑ$4Ô$4ÐBÑBÔBð	Cð 	Cð 	Cð 	Cñ 	Cô 	Cð 	Cð 	Cð 	Cð 	Cð 	Cð 	Cøøøð 	Cð 	Cð 	Cð 	Cð 	Cøå�w­
Ð3ð ð ð ØˆðøøøðØˆˆˆØAÐA˜vŸ~š~¨fÑ5Ô5×>Ò>Ñ@Ô@ÐAÑAÔAÐAøÝð ð ð Øˆðøøøõ ‰5Œ5€LsF   •A6 ­0A*ÁA6 Á*A.Á.A6 Á1A.Á2A6 Á6BÂBÂ4C	 Ã	
CÃCc                 óª   — |                      d¦  «        }t          |t          ¦  «        rdt          |¦  «        v rdS |                      |¦  «         dS )aœ  Suppress benign 'Event loop is closed' noise during shutdown.

    When the MCP event loop is stopped and closed, httpx/httpcore async
    transports may fire __del__ finalizers that call call_soon() on the
    dead loop.  asyncio catches that RuntimeError and routes it here.
    We silence it because the connection is being torn down anyway; all
    other exceptions are forwarded to the default handler.
    r–  zEvent loop is closedN)r   r¬   ÚRuntimeErrorr�   Údefault_exception_handler)r:  ru  r%   s      r&   Ú_mcp_loop_exception_handlerrZ  Ô  sW   € ð �+Š+�kÑ
"Ô
"€CÝ�#•|Ñ$Ô$ð Ð)?Å3ÀsÁ8Ä8Ð)KÐ)KØˆØ×"Ò" 7Ñ+Ô+Ð+Ð+Ð+rJ   c                  óz  — t           5  t          �'t                               ¦   «         r	 ddd¦  «         dS t          j        ¦   «         at                               t          ¦  «         t          j        t          j	        dd¬¦  «        a
t                               ¦   «          ddd¦  «         dS # 1 swxY w Y   dS )z>Start the background event loop thread if not already running.Nzmcp-event-loopT)rá  rþ   Údaemon)rÀ  r3  r4  rq  Únew_event_loopÚset_exception_handlerrZ  Ú	threadingÚThreadÚrun_foreverrG  r
  rI   rJ   r&   Ú_ensure_mcp_looprb  ã  s  € õ 
ð 
ð 
ÝÐ ¥Y×%9Ò%9Ñ%;Ô%;Ð Øð
ð 
ð 
ñ 
ô 
ð 
ð 
ð 
õ Ô*Ñ,Ô,ˆ	Ý×'Ò'Õ(CÑDÔDÐDÝÔ&ÝÔ(Ø!Øð
ñ 
ô 
ˆõ
 	×ÒÑÔÐð
ð 
ð 
ñ 
ô 
ð 
ð 
ð 
ð 
ð 
ð 
ð 
øøøð 
ð 
ð 
ð 
ð 
ð 
s   ˆ"B0·A,B0Â0B4Â7B4rÝ   rÜ   c                 óL  — ddl m} t          5  t          }ddd¦  «         n# 1 swxY w Y   |�|                     ¦   «         st          d¦  «        ‚t          j        | |¦  «        }|€dnt          j	        ¦   «         |z   }	  |¦   «         r#| 
                    ¦   «          t          d¦  «        ‚d}|�B|t          j	        ¦   «         z
  }|dk    r|                     d¬¦  «        S t          ||¦  «        }	 |                     |¬¦  «        S # t          j        j        $ r Y Œ¡w xY w)	zØSchedule a coroutine on the MCP event loop and block until done.

    Poll in short intervals so the calling agent thread can honor user
    interrupts while the MCP work is still running on the background loop.
    r   )Úis_interruptedNzMCP event loop is not runningTzUser sent a new messagegš™™™™™¹?rh  )Útools.interruptrd  rÀ  r3  r4  rX  rq  Úrun_coroutine_threadsaferù   r  r²  rB  rÎ   rp  Ú
concurrentÚfuturesrt  )ÚcororÜ   rd  r:  Úfuturer;  Úwait_timeoutÚ	remainings           r&   r2  r2  ó  s}  € ð /Ð.Ð.Ð.Ð.Ð.å	ð ð Ýˆðð ð ñ ô ð ð ð ð ð ð øøøð ð ð ð à€|˜4Ÿ?š?Ñ,Ô,€|ÝÐ:Ñ;Ô;Ð;ÝÔ-¨d°DÑ9Ô9€FØ�ˆtˆt­D¬NÑ,<Ô,<¸wÑ,F€HðØˆ>ÑÔð 	>Ø�MŠM‰OŒOˆOÝ"Ð#<Ñ=Ô=Ð=àˆØÐØ ¥4¤>Ñ#3Ô#3Ñ3ˆIØ˜AŠ~ˆ~Ø—}’}¨Q�}Ñ/Ô/Ð/Ý˜|¨YÑ7Ô7ˆLð	Ø—=’=¨�=Ñ6Ô6Ð6øÝÔ!Ô.ð 	ð 	ð 	ØˆHð	øøøs   Ž"¢&©&Ã6D ÄD#Ä"D#c                  ó2   — t          j        ddid¬¦  «        S )z=Standardized JSON error for a user-interrupted MCP tool call.r/  z-MCP call interrupted: user sent a new messageFr  )r)  r*  rI   rJ   r&   Ú_interrupted_call_resultrn    s)   € åŒ:ØÐ@ðàðñ ô ð rJ   c                 ó
  — t          | t          ¦  «        rd„ }t          j        d|| ¦  «        S t          | t          ¦  «        rd„ |                      ¦   «         D ¦   «         S t          | t          ¦  «        rd„ | D ¦   «         S | S )z@Recursively resolve ``${VAR}`` placeholders from ``os.environ``.c                 óŽ   — t           j                             |                      d¦  «        |                      d¦  «        ¦  «        S )Nr   r   )r   r[   r   r¯   )Úms    r&   Ú_replacez'_interpolate_env_vars.<locals>._replace"  s,   € Ý”:—>’> !§'¢'¨!¡*¤*¨a¯gªg°a©j¬jÑ9Ô9Ð9rJ   z\$\{([^}]+)\}c                 ó4   — i | ]\  }}|t          |¦  «        “ŒS rI   ©Ú_interpolate_env_vars©r{   ÚkÚvs      r&   ú
<dictcomp>z)_interpolate_env_vars.<locals>.<dictcomp>&  s'   € ÐFÐFÐF±°°1�Õ(¨Ñ+Ô+ÐFÐFÐFrJ   c                 ó,   — g | ]}t          |¦  «        ‘ŒS rI   rt  )r{   rx  s     r&   r}   z)_interpolate_env_vars.<locals>.<listcomp>(  s!   € Ð8Ð8Ð8¨QÕ% aÑ(Ô(Ð8Ð8Ð8rJ   )r¬   r�   r®   rg   r~   r\   r
  )rb   rr  s     r&   ru  ru    s’   € å�%�ÑÔð 9ð	:ð 	:ð 	:åŒvÐ&¨°%Ñ8Ô8Ð8Ý�%�ÑÔð GØFÐF¸¿º¹¼ÐFÑFÔFÐFÝ�%�ÑÔð 9Ø8Ð8°%Ð8Ñ8Ô8Ð8Ø€LrJ   c                  óh  — 	 ddl m}   | ¦   «         }|                     d¦  «        }|rt          |t          ¦  «        si S 	 ddlm}  |¦   «          n# t          $ r Y nw xY wd„ |                     ¦   «         D ¦   «         S # t          $ r'}t           
                    d|¦  «         i cY d}~S d}~ww xY w)aÜ  Read ``mcp_servers`` from the Hermes config file.

    Returns a dict of ``{server_name: server_config}`` or empty dict.
    Server config can contain either ``command``/``args``/``env`` for stdio
    transport or ``url``/``headers`` for HTTP transport, plus optional
    ``timeout``, ``connect_timeout``, and ``auth`` overrides.

    ``${ENV_VAR}`` placeholders in string values are resolved from
    ``os.environ`` (which includes ``~/.hermes/.env`` loaded at startup).
    r   )Úload_configÚmcp_servers)Úload_hermes_dotenvc                 ó4   — i | ]\  }}|t          |¦  «        “ŒS rI   rt  ©r{   rþ   Úcfgs      r&   ry  z$_load_mcp_config.<locals>.<dictcomp>C  s'   € ÐRÐRÐR±Y°T¸3�Õ+¨CÑ0Ô0ÐRÐRÐRrJ   zFailed to load MCP config: %sN)Úhermes_cli.configr|  r   r¬   r~   Úhermes_cli.env_loaderr~  r   r\   r   r   )r|  rØ   Úserversr~  r%   s        r&   Ú_load_mcp_configr…  ,  sû   € ðØ1Ð1Ð1Ð1Ð1Ð1Ø�‘”ˆØ—*’*˜]Ñ+Ô+ˆØð 	�j¨µ$Ñ7Ô7ð 	ØˆIð	Ø@Ð@Ð@Ð@Ð@Ð@ØÐÑ Ô Ð Ð øÝð 	ð 	ð 	ØˆDð	øøøàRÐRÀ'Ç-Â-Á/Ä/ÐRÑRÔRÐRøÝð ð ð Ý�ŠÐ4°cÑ:Ô:Ð:Øˆ	ˆ	ˆ	ˆ	ˆ	ˆ	øøøøðøøøsA   ‚=B  ÁA ÁB  Á
AÁB  ÁAÁ B  Â 
B1Â
B,Â&B1Â,B1rþ   rØ   c              ƒ   ó^   K  — t          | ¦  «        }|                     |¦  «        ƒ d{V —† |S )a�  Create an MCPServerTask, start it, and return when ready.

    The server Task keeps the connection alive in the background.
    Call ``server.shutdown()`` (on the same event loop) to tear it down.

    Raises:
        ValueError: if required config keys are missing.
        ImportError: if HTTP transport is needed but not available.
        Exception: on connection or initialization failure.
    N)r~  r
  )rþ   rØ   r1  s      r&   Ú_connect_serverr‡  M  s>   è è € õ ˜4Ñ Ô €FØ
�,Š,�vÑ
Ô
ÐÐÐÐÐÐÐØ€MrJ   r€  c                 ó8   ‡ ‡‡— dt           dt          fˆ ˆˆfd„}|S )z¶Return a sync handler that calls an MCP tool via the background loop.

    The handler conforms to the registry's dispatch interface:
    ``handler(args_dict, **kwargs) -> str``
    rK  r	   c           
      óî  •‡ ‡
‡— t                                ‰d¦  «        t          k    rŽt                               ‰d¦  «        }t	          j        ¦   «         |z
  }|t          k     rRt          dt          t          |z
  ¦  «        ¦  «        }t          j
        dd‰› dt           ‰         › d|› d�id	¬
¦  «        S t          5  t                               ‰¦  «        Šd d d ¦  «         n# 1 swxY w Y   ‰r‰j        s+t          ‰¦  «         t          j
        dd‰› d�id	¬
¦  «        S ˆ ˆˆfd„Š
ˆ
ˆfd„}	  |¦   «         }	 t          j        |¦  «        }d|v rt          ‰¦  «         nt!          ‰¦  «         n+# t          j        t$          f$ r t!          ‰¦  «         Y nw xY w|S # t&          $ r t)          ¦   «         cY S t*          $ r¯}t-          ‰||d‰› �¦  «        }	|	�|	cY d }~S t/          ‰||d‰› �¦  «        }	|	�|	cY d }~S t          ‰¦  «         t0                               d‰‰|¦  «         t          j
        dt5          dt7          |¦  «        j        › d|› �¦  «        id	¬
¦  «        cY d }~S d }~ww xY w)Nr   g        r   r/  rº  z' is unreachable after z0 consecutive failures. Auto-retry available in ~ue   s. Do NOT retry this tool yet â€” use alternative approaches or ask the user to check the MCP server.Fr  ú' is not connectedc               “   óV  •K  — ‰j                              ‰‰¬¦  «        ƒ d {V —†} | j        rOd}| j        pg D ]}t	          |d¦  «        r
||j        z  }Œt          j        dt          |pd¦  «        id¬¦  «        S g }| j        pg D ],}t	          |d¦  «        r| 	                    |j        ¦  «         Œ-|rd 
                    |¦  «        nd}t          | d	d ¦  «        }|�3|rt          j        ||d
œd¬¦  «        S t          j        d|id¬¦  «        S t          j        d|id¬¦  «        S )N©r   ry   rd   r/  zMCP tool returned an errorFr  r  ÚstructuredContent)rÎ   r�  rÎ   )r  Ú	call_toolÚisErrorr  rÿ   rd   r)  r*  ri   rp   rr   r«   )	rÎ   Ú
error_textr  r„   Útext_resultÚ
structuredrK  r1  rj   s	         €€€r&   Ú_callz3_make_tool_handler.<locals>._handler.<locals>._call‹  s—  øè è € Ø!œ>×3Ò3°IÈÐ3ÑNÔNÐNÐNÐNÐNÐNÐNˆFàŒ~ð 	'Ø�
Ø$œnÐ2°ð 1ð 1�EÝ˜u fÑ-Ô-ð 1Ø" e¤jÑ0˜
øÝ”zØ�_Ø"ÐBÐ&Bñô ð#ð !&ð	'ñ 'ô 'ð 'ð  "ˆEØ œ.Ð.¨Bð -ð -�Ý˜5 &Ñ)Ô)ð -Ø—L’L ¤Ñ,Ô,Ð,øØ.3Ð;˜$Ÿ)š) EÑ*Ô*Ð*¸ˆKõ ! Ð)<¸dÑCÔCˆJØÐ%Øð +Ýœ:Ø"-Ø-7ð'ð 'ð %*ð+ñ +ô +ð +õ ”z 8¨ZÐ"8ÀuÐMÑMÔMÐMÝ”:˜x¨Ð5ÀEÐJÑJÔJÐJrJ   c                  ó6   •— t           ‰ ¦   «         ‰¬¦  «        S ©Nrh  ©r2  ©r“  r€  s   €€r&   Ú
_call_oncez8_make_tool_handler.<locals>._handler.<locals>._call_once®  ó   ø€ Ý# E E¡G¤G°\ÐBÑBÔBÐBrJ   ztools/call zMCP tool %s/%s call failed: %súMCP call failed: ú: )r  r   r  r  rù   r  Ú_CIRCUIT_BREAKER_COOLDOWN_SECrÉ   rç   r)  r*  rÀ  r  r  r  rE  r  rF  rG   rB  rn  r   r=  rF  r   r/  ri   r!  r»   )rK  ÚkwargsÚ	opened_atÚagerl  r˜  rÎ   rL  r%   r7  r“  r1  r(   rj   r€  s   `         @@€€€r&   r—  z$_make_tool_handler.<locals>._handlerh  sÊ  øøøø€ õ  ×#Ò# K°Ñ3Ô3Õ7QÒQÐQÝ1×5Ò5°kÀ3ÑGÔGˆIÝ”.Ñ"Ô" YÑ.ˆCØÕ2Ò2Ð2Ý ¥3Õ'DÀsÑ'JÑ#KÔ#KÑLÔL�	Ý”zØðO {ð Oð OÝ/°Ô<ðOð Oà>GðOð Oð Oð#ð !&ð'ñ 'ô 'ð 'õ ð 	/ð 	/Ý—\’\ +Ñ.Ô.ˆFð	/ð 	/ð 	/ñ 	/ô 	/ð 	/ð 	/ð 	/ð 	/ð 	/ð 	/øøøð 	/ð 	/ð 	/ð 	/àð 	#˜Vœ^ð 	#Ý˜{Ñ+Ô+Ð+Ý”:ØÐG¨ÐGÐGÐGðà!ð#ñ #ô #ð #ð!	Kð !	Kð !	Kð !	Kð !	Kð !	Kð !	KðF	Cð 	Cð 	Cð 	Cð 	Cð 	Cð,	#Ø�Z‘\”\ˆFð1Ýœ FÑ+Ô+�Ø˜fÐ$Ð$Ý& {Ñ3Ô3Ð3Ð3å'¨Ñ4Ô4Ð4øøÝÔ(­)Ð4ð 1ð 1ð 1Ý# KÑ0Ô0Ð0Ð0Ð0ð1øøøàˆMøÝð 	.ð 	.ð 	.Ý+Ñ-Ô-Ð-Ð-Ð-Ýð 	#ð 	#ð 	#õ 5Ø˜S *Ø)˜iÐ)Ð)ñô ˆIð Ð$Ø Ð Ð Ð Ð Ð Ð õ
 :Ø˜S *Ø)˜iÐ)Ð)ñô ˆIð Ð$Ø Ð Ð Ð Ð Ð Ð å˜{Ñ+Ô+Ð+Ý�LŠLØ0Ø˜Y¨ñô ð õ ”:Ø�ØC­¨S©	¬	Ô(:ÐCÐC¸cÐCÐCñô ðð "ð	#ñ #ô #ð #ð #ð #ð #ð #ð #øøøøð5	#øøøss   Â>C%Ã%C)Ã,C)Ä2
F" Ä=7E5 Å4F" Å5%FÆF" ÆFÆF" Æ"I4Æ<	I4ÇI/ÇI4Ç#I/Ç;I4ÈA(I/É)I4É/I4©r~   r�   )r(   rj   r€  r—  s   ``` r&   Ú_make_tool_handlerr¡  a  sM   øøø€ ðu#•tð u#­#ð u#ð u#ð u#ð u#ð u#ð u#ð u#ð u#ðn €OrJ   c                 ó4   ‡ ‡— dt           dt          fˆ ˆfd„}|S )z>Return a sync handler that lists resources from an MCP server.rK  r	   c           
      ón  •‡‡— t           5  t                               ‰¦  «        Šd d d ¦  «         n# 1 swxY w Y   ‰r‰j        st	          j        dd‰› d�id¬¦  «        S ˆfd„Šˆˆfd„}	  |¦   «         S # t          $ r t          ¦   «         cY S t          $ r™}t          ‰||d¦  «        }|�|cY d }~S t          ‰||d¦  «        }|�|cY d }~S t                               d	‰|¦  «         t	          j        dt          d
t          |¦  «        j        › d|› �¦  «        id¬¦  «        cY d }~S d }~ww xY w)Nr/  rº  rŠ  Fr  c               “   óæ  •K  — ‰j                              ¦   «         ƒ d {V —†} g }t          | d¦  «        r| j        ng D ]œ}i }t          |d¦  «        rt	          |j        ¦  «        |d<   t          |d¦  «        r
|j        |d<   t          |d¦  «        r|j        r
|j        |d<   t          |d¦  «        r|j        r
|j        |d<   | 	                    |¦  «         Œ�t          j        d|id¬¦  «        S )NÚ	resourcesÚurirþ   rk   r&  Fr  )r  Úlist_resourcesrÿ   r¥  r�   r¦  rþ   rk   r&  rp   r)  r*  )rÎ   r¥  ÚrÚentryr1  s       €r&   r“  z=_make_list_resources_handler.<locals>._handler.<locals>._callí  s  øè è € Ø!œ>×8Ò8Ñ:Ô:Ð:Ð:Ð:Ð:Ð:Ð:ˆFØˆIÝ*1°&¸+Ñ*FÔ*FÐN�fÔ&Ð&ÈBð 
(ð 
(�Ø�Ý˜1˜eÑ$Ô$ð .Ý#& q¤u¡:¤:�E˜%‘LÝ˜1˜fÑ%Ô%ð +Ø$%¤F�E˜&‘MÝ˜1˜mÑ,Ô,ð 9°´ð 9Ø+,¬=�E˜-Ñ(Ý˜1˜jÑ)Ô)ð 3¨a¬jð 3Ø()¬
�E˜*Ñ%Ø× Ò  Ñ'Ô'Ð'Ð'Ý”:˜{¨IÐ6ÀUÐKÑKÔKÐKrJ   c                  ó6   •— t           ‰ ¦   «         ‰¬¦  «        S r•  r–  r—  s   €€r&   r˜  zB_make_list_resources_handler.<locals>._handler.<locals>._call_onceý  r™  rJ   zresources/listz MCP %s/list_resources failed: %srš  r›  ©rÀ  r  r   r  r)  r*  rB  rn  r   r=  rF  r   r/  ri   r!  r»   ©	rK  r�  r˜  r%   r7  r“  r1  r(   r€  s	        @@€€r&   r—  z._make_list_resources_handler.<locals>._handlerå  s<  øøø€ Ýð 	/ð 	/Ý—\’\ +Ñ.Ô.ˆFð	/ð 	/ð 	/ñ 	/ô 	/ð 	/ð 	/ð 	/ð 	/ð 	/ð 	/øøøð 	/ð 	/ð 	/ð 	/àð 	#˜Vœ^ð 	#Ý”:ØÐG¨ÐGÐGÐGðà!ð#ñ #ô #ð #ð	Lð 	Lð 	Lð 	Lð 	Lð 	Cð 	Cð 	Cð 	Cð 	Cð 	Cð	#Ø�:‘<”<ÐøÝð 	.ð 	.ð 	.Ý+Ñ-Ô-Ð-Ð-Ð-Ýð 	#ð 	#ð 	#Ý4Ø˜S *Ð.>ñô ˆIð Ð$Ø Ð Ð Ð Ð Ð Ð Ý9Ø˜S *Ð.>ñô ˆIð Ð$Ø Ð Ð Ð Ð Ð Ð Ý�LŠLØ2°KÀñô ð õ ”:Ø�ØC­¨S©	¬	Ô(:ÐCÐC¸cÐCÐCñô ðð "ð	#ñ #ô #ð #ð #ð #ð #ð #ð #øøøøð	#øøøóI   ‹2²6¹6Á.	A8 Á8D4Â	D4ÂD/Â0D4Â6D/ÃD4ÃAD/Ä)D4Ä/D4r   ©r(   r€  r—  s   `` r&   Ú_make_list_resources_handlerr¯  â  s=   øø€ ð1#•tð 1#­#ð 1#ð 1#ð 1#ð 1#ð 1#ð 1#ð 1#ðf €OrJ   c                 ó4   ‡ ‡— dt           dt          fˆ ˆfd„}|S )zFReturn a sync handler that reads a resource by URI from an MCP server.rK  r	   c           
      óÂ  •‡‡‡— ddl m} t          5  t                               ‰	¦  «        Šd d d ¦  «         n# 1 swxY w Y   ‰r‰j        st          j        dd‰	› d�id¬¦  «        S |                      d¦  «        Š‰s |d	¦  «        S ˆˆfd
„Šˆˆ
fd„}	  |¦   «         S # t          $ r t          ¦   «         cY S t          $ r™}t          ‰	||d¦  «        }|�|cY d }~S t          ‰	||d¦  «        }|�|cY d }~S t                               d‰	|¦  «         t          j        dt          dt!          |¦  «        j        › d|› �¦  «        id¬¦  «        cY d }~S d }~ww xY w)Nr   ©Ú
tool_errorr/  rº  rŠ  Fr  r¦  z Missing required parameter 'uri'c               “   ó²  •K  — ‰j                              ‰¦  «        ƒ d {V —†} g }t          | d¦  «        r| j        ng }|D ]h}t          |d¦  «        r|                     |j        ¦  «         Œ-t          |d¦  «        r+|                     dt          |j        ¦  «        › d�¦  «         Œit          j	        d|rd 
                    |¦  «        ndid	¬
¦  «        S )NÚcontentsrd   Úblobz[binary data, z bytes]rÎ   r  ry   Fr  )r  Úread_resourcerÿ   rµ  rp   rd   rú   r¶  r)  r*  rr   )rÎ   r„   rµ  r  r1  r¦  s       €€r&   r“  z<_make_read_resource_handler.<locals>._handler.<locals>._call,  só   øè è € Ø!œ>×7Ò7¸Ñ<Ô<Ð<Ð<Ð<Ð<Ð<Ð<ˆFà!ˆEÝ*1°&¸*Ñ*EÔ*EÐM�v”�È2ˆHØ!ð Lð L�Ý˜5 &Ñ)Ô)ð LØ—L’L ¤Ñ,Ô,Ð,Ð,Ý˜U FÑ+Ô+ð LØ—L’LÐ!Jµ#°e´j±/´/Ð!JÐ!JÐ!JÑKÔKÐKøÝ”:˜x¸UÐ)J¨¯ª°5Ñ)9Ô)9Ð)9ÈÐKÐZ_Ð`Ñ`Ô`Ð`rJ   c                  ó6   •— t           ‰ ¦   «         ‰¬¦  «        S r•  r–  r—  s   €€r&   r˜  zA_make_read_resource_handler.<locals>._handler.<locals>._call_once8  r™  rJ   zresources/readzMCP %s/read_resource failed: %srš  r›  ©rœ  r³  rÀ  r  r   r  r)  r*  rB  rn  r   r=  rF  r   r/  ri   r!  r»   )rK  r�  r³  r˜  r%   r7  r“  r1  r¦  r(   r€  s         @@@€€r&   r—  z-_make_read_resource_handler.<locals>._handler  s€  øøøø€ Ø-Ð-Ð-Ð-Ð-Ð-åð 	/ð 	/Ý—\’\ +Ñ.Ô.ˆFð	/ð 	/ð 	/ñ 	/ô 	/ð 	/ð 	/ð 	/ð 	/ð 	/ð 	/øøøð 	/ð 	/ð 	/ð 	/àð 	#˜Vœ^ð 	#Ý”:ØÐG¨ÐGÐGÐGðà!ð#ñ #ô #ð #ð �hŠh�u‰oŒoˆØð 	BØ�:Ð@ÑAÔAÐAð
	að 
	að 
	að 
	að 
	að 
	að	Cð 	Cð 	Cð 	Cð 	Cð 	Cð	#Ø�:‘<”<ÐøÝð 	.ð 	.ð 	.Ý+Ñ-Ô-Ð-Ð-Ð-Ýð 	#ð 	#ð 	#Ý4Ø˜S *Ð.>ñô ˆIð Ð$Ø Ð Ð Ð Ð Ð Ð Ý9Ø˜S *Ð.>ñô ˆIð Ð$Ø Ð Ð Ð Ð Ð Ð Ý�LŠLØ1°;Àñô ð õ ”:Ø�ØC­¨S©	¬	Ô(:ÐCÐC¸cÐCÐCñô ðð "ð	#ñ #ô #ð #ð #ð #ð #ð #ð #øøøøð	#øøøsJ   ’9¹=Á =Â	B" Â"EÂ<	EÃEÃEÃ EÃ5EÃ;AEÅEÅEr   r®  s   `` r&   Ú_make_read_resource_handlerrº    s=   øø€ ð3#•tð 3#­#ð 3#ð 3#ð 3#ð 3#ð 3#ð 3#ð 3#ðj €OrJ   c                 ó4   ‡ ‡— dt           dt          fˆ ˆfd„}|S )z<Return a sync handler that lists prompts from an MCP server.rK  r	   c           
      ón  •‡‡— t           5  t                               ‰¦  «        Šd d d ¦  «         n# 1 swxY w Y   ‰r‰j        st	          j        dd‰› d�id¬¦  «        S ˆfd„Šˆˆfd„}	  |¦   «         S # t          $ r t          ¦   «         cY S t          $ r™}t          ‰||d¦  «        }|�|cY d }~S t          ‰||d¦  «        }|�|cY d }~S t                               d	‰|¦  «         t	          j        dt          d
t          |¦  «        j        › d|› �¦  «        id¬¦  «        cY d }~S d }~ww xY w)Nr/  rº  rŠ  Fr  c               “   ó¬  •K  — ‰j                              ¦   «         ƒ d {V —†} g }t          | d¦  «        r| j        ng D ]}i }t          |d¦  «        r
|j        |d<   t          |d¦  «        r|j        r
|j        |d<   t          |d¦  «        r|j        rd„ |j        D ¦   «         |d<   |                     |¦  «         Œ€t          j	        d|id¬¦  «        S )NÚpromptsrþ   rk   r   c                 óš   — g | ]H}d |j         it          |d¦  «        r|j        r	d|j        ini ¥t          |d¦  «        r	d|j        ini ¥‘ŒIS )rþ   rk   Úrequired)rþ   rÿ   rk   rÀ  )r{   r   s     r&   r}   zO_make_list_prompts_handler.<locals>._handler.<locals>._call.<locals>.<listcomp>k  s‡   € ð *ð *ð *ð ð	 # A¤FðåAHÈÈMÑAZÔAZÐtÐ_`Ô_lÐt ¨q¬}Ð=Ð=Ðrtðõ <CÀ1ÀjÑ;QÔ;QÐY 
¨A¬JÐ7Ð7ÐWYðð*ð *ð *rJ   Fr  )
r  Úlist_promptsrÿ   r¾  rþ   rk   r   rp   r)  r*  )rÎ   r¾  rJ  r©  r1  s       €r&   r“  z;_make_list_prompts_handler.<locals>._handler.<locals>._calla  s  øè è € Ø!œ>×6Ò6Ñ8Ô8Ð8Ð8Ð8Ð8Ð8Ð8ˆFØˆGÝ(/°¸	Ñ(BÔ(BÐJ�f”n�nÈð &ð &�Ø�Ý˜1˜fÑ%Ô%ð +Ø$%¤F�E˜&‘MÝ˜1˜mÑ,Ô,ð 9°´ð 9Ø+,¬=�E˜-Ñ(Ý˜1˜kÑ*Ô*ð ¨q¬{ð ð*ð *ð "#¤ð*ñ *ô *�E˜+Ñ&ð —’˜uÑ%Ô%Ð%Ð%Ý”:˜y¨'Ð2ÀÐGÑGÔGÐGrJ   c                  ó6   •— t           ‰ ¦   «         ‰¬¦  «        S r•  r–  r—  s   €€r&   r˜  z@_make_list_prompts_handler.<locals>._handler.<locals>._call_oncev  r™  rJ   zprompts/listzMCP %s/list_prompts failed: %srš  r›  r«  r¬  s	        @@€€r&   r—  z,_make_list_prompts_handler.<locals>._handlerY  s:  øøø€ Ýð 	/ð 	/Ý—\’\ +Ñ.Ô.ˆFð	/ð 	/ð 	/ñ 	/ô 	/ð 	/ð 	/ð 	/ð 	/ð 	/ð 	/øøøð 	/ð 	/ð 	/ð 	/àð 	#˜Vœ^ð 	#Ý”:ØÐG¨ÐGÐGÐGðà!ð#ñ #ô #ð #ð	Hð 	Hð 	Hð 	Hð 	Hð*	Cð 	Cð 	Cð 	Cð 	Cð 	Cð	#Ø�:‘<”<ÐøÝð 	.ð 	.ð 	.Ý+Ñ-Ô-Ð-Ð-Ð-Ýð 	#ð 	#ð 	#Ý4Ø˜S *¨nñô ˆIð Ð$Ø Ð Ð Ð Ð Ð Ð Ý9Ø˜S *¨nñô ˆIð Ð$Ø Ð Ð Ð Ð Ð Ð Ý�LŠLØ0°+¸sñô ð õ ”:Ø�ØC­¨S©	¬	Ô(:ÐCÐC¸cÐCÐCñô ðð "ð	#ñ #ô #ð #ð #ð #ð #ð #ð #øøøøð	#øøør­  r   r®  s   `` r&   Ú_make_list_prompts_handlerrÃ  V  s=   øø€ ð6#•tð 6#­#ð 6#ð 6#ð 6#ð 6#ð 6#ð 6#ð 6#ðp €OrJ   c                 ó4   ‡ ‡— dt           dt          fˆ ˆfd„}|S )zDReturn a sync handler that gets a prompt by name from an MCP server.rK  r	   c           
      óò  •‡‡‡‡	— ddl m} t          5  t                               ‰
¦  «        Š	d d d ¦  «         n# 1 swxY w Y   ‰	r‰	j        st          j        dd‰
› d�id¬¦  «        S |                      d¦  «        Š‰s |d	¦  «        S |                      d
i ¦  «        Šˆˆˆ	fd„Šˆˆfd„}	  |¦   «         S # t          $ r t          ¦   «         cY S t          $ r™}t          ‰
||d¦  «        }|�|cY d }~S t          ‰
||d¦  «        }|�|cY d }~S t                               d‰
|¦  «         t          j        dt          dt!          |¦  «        j        › d|› �¦  «        id¬¦  «        cY d }~S d }~ww xY w)Nr   r²  r/  rº  rŠ  Fr  rþ   z!Missing required parameter 'name'r   c               “   ó  •K  — ‰j                              ‰‰¬¦  «        ƒ d {V —†} g }t          | d¦  «        r| j        ng D ]’}i }t          |d¦  «        r
|j        |d<   t          |d¦  «        rO|j        }t          |d¦  «        r|j        |d<   n-t          |t          ¦  «        r||d<   nt          |¦  «        |d<   | 	                    |¦  «         Œ“d|i}t          | d¦  «        r| j
        r
| j
        |d<   t          j        |d¬¦  «        S )	NrŒ  r½   r  r  rd   rk   Fr  )r  Ú
get_promptrÿ   r½   r  r  rd   r¬   r�   rp   rk   r)  r*  )	rÎ   r½   r,  r©  r  Úrespr   rþ   r1  s	         €€€r&   r“  z9_make_get_prompt_handler.<locals>._handler.<locals>._call¦  sD  øè è € Ø!œ>×4Ò4°TÀYÐ4ÑOÔOÐOÐOÐOÐOÐOÐOˆFàˆHÝ+2°6¸:Ñ+FÔ+FÐN˜œ˜ÈBð 'ð '�Ø�Ý˜3 Ñ'Ô'ð -Ø$'¤H�E˜&‘MÝ˜3 	Ñ*Ô*ð 8Ø!œk�GÝ˜w¨Ñ/Ô/ð 8Ø+2¬<˜˜iÑ(Ð(Ý# G­SÑ1Ô1ð 8Ø+2˜˜iÑ(Ð(å+.¨w©<¬<˜˜iÑ(Ø—’ Ñ&Ô&Ð&Ð&Ø Ð)ˆDÝ�v˜}Ñ-Ô-ð 9°&Ô2Dð 9Ø&,Ô&8��]Ñ#Ý”:˜d°Ð7Ñ7Ô7Ð7rJ   c                  ó6   •— t           ‰ ¦   «         ‰¬¦  «        S r•  r–  r—  s   €€r&   r˜  z>_make_get_prompt_handler.<locals>._handler.<locals>._call_once¼  r™  rJ   zprompts/getzMCP %s/get_prompt failed: %srš  r›  r¹  )rK  r�  r³  r˜  r%   r7  r“  r   rþ   r1  r(   r€  s         @@@@€€r&   r—  z*_make_get_prompt_handler.<locals>._handler—  s“  øøøøø€ Ø-Ð-Ð-Ð-Ð-Ð-åð 	/ð 	/Ý—\’\ +Ñ.Ô.ˆFð	/ð 	/ð 	/ñ 	/ô 	/ð 	/ð 	/ð 	/ð 	/ð 	/ð 	/øøøð 	/ð 	/ð 	/ð 	/àð 	#˜Vœ^ð 	#Ý”:ØÐG¨ÐGÐGÐGðà!ð#ñ #ô #ð #ð �xŠx˜ÑÔˆØð 	CØ�:ÐAÑBÔBÐBØ—H’H˜[¨"Ñ-Ô-ˆ	ð	8ð 	8ð 	8ð 	8ð 	8ð 	8ð 	8ð,	Cð 	Cð 	Cð 	Cð 	Cð 	Cð	#Ø�:‘<”<ÐøÝð 	.ð 	.ð 	.Ý+Ñ-Ô-Ð-Ð-Ð-Ýð 	#ð 	#ð 	#Ý4Ø˜S *¨mñô ˆIð Ð$Ø Ð Ð Ð Ð Ð Ð Ý9Ø˜S *¨mñô ˆIð Ð$Ø Ð Ð Ð Ð Ð Ð Ý�LŠLØ.°¸Sñô ð õ ”:Ø�ØC­¨S©	¬	Ô(:ÐCÐC¸cÐCÐCñô ðð "ð	#ñ #ô #ð #ð #ð #ð #ð #ð #øøøøð	#øøøsJ   “:º>Á>Â0	B: Â:E6Ã	E6ÃE1Ã2E6Ã8E1ÄE6ÄAE1Å+E6Å1E6r   r®  s   `` r&   Ú_make_get_prompt_handlerrÊ  ”  s=   øø€ ð>#•tð >#­#ð >#ð >#ð >#ð >#ð >#ð >#ð >#ð@ €OrJ   c                 ó"   ‡ — dt           fˆ fd„}|S )zBReturn a check function that verifies the MCP connection is alive.r	   c                  ó�   •— t           5  t                               ‰¦  «        } d d d ¦  «         n# 1 swxY w Y   | d uo| j        d uS r)  )rÀ  r  r   r  )r1  r(   s    €r&   Ú_checkz_make_check_fn.<locals>._checkÝ  s†   ø€ Ýð 	/ð 	/Ý—\’\ +Ñ.Ô.ˆFð	/ð 	/ð 	/ñ 	/ô 	/ð 	/ð 	/ð 	/ð 	/ð 	/ð 	/øøøð 	/ð 	/ð 	/ð 	/à˜TÐ!Ð@ f¤n¸DÐ&@Ð@s   ‰0°4·4)r{  )r(   rÍ  s   ` r&   Ú_make_check_fnrÎ  Ú  s6   ø€ ðA•Dð Að Að Að Að Að Að
 €MrJ   Úschemac                 óÖ   ‡‡— | sdi dœS ˆfd„Šˆfd„Š ‰| ¦  «        } ‰|¦  «        }t          |t          ¦  «        sdi dœS |                     d¦  «        dk    rd|vri |¥di i¥}|S )a  Normalize MCP input schemas for LLM tool-calling compatibility.

    MCP servers can emit plain JSON Schema with ``definitions`` /
    ``#/definitions/...`` references.  Kimi / Moonshot rejects that form and
    requires local refs to point into ``#/$defs/...`` instead.  Normalize the
    common draft-07 shape here so MCP tool schemas remain portable across
    OpenAI-compatible providers.

    Additional MCP-server robustness repairs applied recursively:

    * Missing or ``null`` ``type`` on an object-shaped node is coerced to
      ``"object"`` (some servers omit it).  See PR #4897.
    * When an ``object`` node lacks ``properties``, an empty ``properties``
      dict is added so ``required`` entries don't dangle.
    * ``required`` arrays are pruned to only names that exist in
      ``properties``; otherwise Google AI Studio / Gemini 400s with
      ``property is not defined``.  See PR #4651.

    All repairs are provider-agnostic and ideally produce a schema valid on
    OpenAI, Anthropic, Gemini, and Moonshot in one pass.
    Úobject©r!  Ú
propertiesc                 óœ  •— t          | t          ¦  «        r’i }|                      ¦   «         D ]\  }}|dk    rdn|} ‰|¦  «        ||<   Œ|                     d¦  «        }t          |t          ¦  «        r2|                     d¦  «        rd|t          d¦  «        d …         z   |d<   |S t          | t          ¦  «        rˆfd„| D ¦   «         S | S )NÚdefinitionsz$defsz$refz#/definitions/z#/$defs/c                 ó&   •— g | ]} ‰|¦  «        ‘ŒS rI   rI   )r{   rÃ   Ú_rewrite_local_refss     €r&   r}   zL_normalize_mcp_input_schema.<locals>._rewrite_local_refs.<locals>.<listcomp>	  s%   ø€ Ð?Ð?Ð?°$Ð'Ð'¨Ñ-Ô-Ð?Ð?Ð?rJ   )r¬   r~   r\   r   r�   r^   rú   r
  )r‹   Ú
normalizedra   rb   Úout_keyÚrefr×  s         €r&   r×  z8_normalize_mcp_input_schema.<locals>._rewrite_local_refs	  sö   ø€ Ý�d�DÑ!Ô!ð 	ØˆJØ"Ÿjšj™lœlð Að A‘
��UØ%(¨MÒ%9Ð%9˜'˜'¸s�Ø&9Ð&9¸%Ñ&@Ô&@�
˜7Ñ#Ð#Ø—.’. Ñ(Ô(ˆCÝ˜#�sÑ#Ô#ð N¨¯ªÐ7GÑ(HÔ(Hð NØ%/°#µcÐ:JÑ6KÔ6KÐ6LÐ6LÔ2MÑ%M�
˜6Ñ"ØÐÝ�d�DÑ!Ô!ð 	@Ø?Ð?Ð?Ð?¸$Ð?Ñ?Ô?Ð?ØˆrJ   c                 ó"  •‡— t          | t          ¦  «        rˆfd„| D ¦   «         S t          | t          ¦  «        s| S ˆfd„|                      ¦   «         D ¦   «         }|                     d¦  «        sd|v sd|v rd|d<   |                     d¦  «        dk    r÷d|vs(t          |                     d¦  «        t          ¦  «        s>d|vri n|d         |d<   t          |                     d¦  «        t          ¦  «        si |d<   |                     d¦  «        }t          |t          ¦  «        rc|                     d¦  «        pi Šˆfd„|D ¦   «         }t          |¦  «        t          |¦  «        k    r|r||d<   n|                     dd¦  «         |S )	zBRecursively repair object-shaped nodes: fill type, prune required.c                 ó&   •— g | ]} ‰|¦  «        ‘ŒS rI   rI   )r{   rÃ   Ú_repair_object_shapes     €r&   r}   zM_normalize_mcp_input_schema.<locals>._repair_object_shape.<locals>.<listcomp>	  s%   ø€ Ð@Ð@Ð@°4Ð(Ð(¨Ñ.Ô.Ð@Ð@Ð@rJ   c                 ó.   •— i | ]\  }}| ‰|¦  «        “ŒS rI   rI   )r{   rw  rx  rÝ  s      €r&   ry  zM_normalize_mcp_input_schema.<locals>._repair_object_shape.<locals>.<dictcomp>	  s+   ø€ ÐHÐHÐH±4°1°a�AÐ+Ð+¨AÑ.Ô.ÐHÐHÐHrJ   r!  rÓ  rÀ  rÑ  c                 óF   •— g | ]}t          |t          ¦  «        ¯|‰v ¯|‘ŒS rI   )r¬   r�   )r{   r¨  Úpropss     €r&   r}   zM_normalize_mcp_input_schema.<locals>._repair_object_shape.<locals>.<listcomp>-	  s-   ø€ ÐRÐRÐR˜qµ
¸1½cÑ0BÔ0BÐRÀqÈEÀzÀz˜ÀzÀzÀzrJ   N)r¬   r
  r~   r\   r   rú   rÄ  )r‹   ÚrepairedrÀ  Úvalidrà  rÝ  s       @€r&   rÝ  z9_normalize_mcp_input_schema.<locals>._repair_object_shape	  sÂ  øø€ å�d�DÑ!Ô!ð 	AØ@Ð@Ð@Ð@¸4Ð@Ñ@Ô@Ð@Ý˜$¥Ñ%Ô%ð 	ØˆKàHÐHÐHÐH¸4¿:º:¹<¼<ÐHÑHÔHˆð �|Š|˜FÑ#Ô#ð 	(Ø˜HÐ$Ð$¨
°hÐ(>Ð(>à'ˆH�VÑà�<Š<˜ÑÔ 8Ò+Ð+à 8Ð+Ð+µ:Ø—’˜\Ñ*Ô*­Dñ4ô 4Ð+ð 0<À8Ð/KÐ/K¨¨ÐQYÐZfÔQg�˜Ñ&Ý! (§,¢,¨|Ñ"<Ô"<½dÑCÔCð 0Ø-/�H˜\Ñ*ð  —|’| JÑ/Ô/ˆHÝ˜(¥DÑ)Ô)ð 7Ø Ÿš \Ñ2Ô2Ð8°b�ØRÐRÐRÐR HÐRÑRÔR�Ý�u‘:”:¥ X¡¤Ò.Ð.Øð 7Ø/4˜ Ñ,Ð,à Ÿš Z°Ñ6Ô6Ð6àˆrJ   r!  rÓ  )r¬   r~   r   )rÏ  rØ  rÝ  r×  s     @@r&   rc  rc  é  sÎ   øø€ ð, ð 4Ø °Ð3Ð3Ð3ðð ð ð ð ð$ð $ð $ð $ð $ðL %Ð$ VÑ,Ô,€JØ%Ð% jÑ1Ô1€Jõ �j¥$Ñ'Ô'ð 4Ø °Ð3Ð3Ð3Ø‡~‚~�fÑÔ Ò)Ð)¨lÀ*Ð.LÐ.LØ5˜
Ð5 L°"Ð5Ð5ˆ
àÐrJ   rb   c                 óL   — t          j        ddt          | pd¦  «        ¦  «        S )a5  Return an MCP name component safe for tool and prefix generation.

    Preserves Hermes's historical behavior of converting hyphens to
    underscores, and also replaces any other character outside
    ``[A-Za-z0-9_]`` with ``_`` so generated tool names are compatible with
    provider validation rules.
    z[^A-Za-z0-9_]Ú_ry   )r®   rg   r�   )rb   s    r&   Úsanitize_mcp_name_componentrå  B	  s%   € õ Œ6Ð" C­¨U¨[°bÑ)9Ô)9Ñ:Ô:Ð:rJ   c           	      óÀ   — t          |j        ¦  «        }t          | ¦  «        }d|› d|› �}||j        pd|j        › d| › �t          t	          |dd¦  «        ¦  «        dœS )aS  Convert an MCP tool listing to the Hermes registry schema format.

    Args:
        server_name: The logical server name for prefixing.
        mcp_tool:    An MCP ``Tool`` object with ``.name``, ``.description``,
                     and ``.inputSchema``.

    Returns:
        A dict suitable for ``registry.register(schema=...)``.
    Úmcp_rä  z	MCP tool z from ra  Nrb  )rå  rþ   rk   rc  r«   )r(   Úmcp_toolÚsafe_tool_nameÚsafe_server_namer¥  s        r&   Ú_convert_mcp_schemarë  M	  s€   € õ 1°´Ñ?Ô?€NÝ2°;Ñ?Ô?ÐØ>Ð+Ð>Ð>¨nÐ>Ð>€MàØÔ+Ð]Ð/]¸8¼=Ð/]Ð/]ÐP[Ð/]Ð/]Ý1µ'¸(ÀMÐSWÑ2XÔ2XÑYÔYðð ð rJ   c                 óä   — t          | ¦  «        }d|› d�d| › d�di dœdœdd	œd|› d
�d| › d�dddddœidgdœdœdd	œd|› d�d| › d�di dœdœdd	œd|› d�d| › d�ddddœddi ddœdœdgdœdœdd	œgS )zµBuild schemas for the MCP utility tools (resources & prompts).

    Returns a list of (schema, handler_factory_name) tuples encoded as dicts
    with keys: schema, handler_key.
    rç  Ú_list_resourcesz*List available resources from MCP server 'r¿   rÑ  rÒ  rb  r§  )rÏ  Úhandler_keyÚ_read_resourcez(Read a resource by URI from MCP server 'r¦  ÚstringzURI of the resource to read)r!  rk   )r!  rÓ  rÀ  r·  Ú_list_promptsz(List available prompts from MCP server 'rÁ  Ú_get_promptz&Get a prompt by name from MCP server 'zName of the prompt to retrievez(Optional arguments to pass to the promptT)r!  rk   rÓ  ÚadditionalPropertiesr  rþ   rÇ  )rå  )r(   Ú	safe_names     r&   Ú_build_utility_schemasrõ  b	  sŒ  € õ ,¨KÑ8Ô8€Ið :˜yÐ9Ð9Ð9ØZÈKÐZÐZÐZà$Ø"$ðð ðð ð ,ð
	
ð 
	
ð 9˜yÐ8Ð8Ð8ØXÈ+ÐXÐXÐXà$àØ$,Ø+Hð ð  ð#ð "' ð	ð 	ðð ð +ð	
ð 	
ð& 8˜yÐ7Ð7Ð7ØXÈ+ÐXÐXÐXà$Ø"$ðð ðð ð *ð
	
ð 
	
ð 6˜yÐ5Ð5Ð5ØVÈÐVÐVÐVà$ð %-Ø+Kð!ð !ð
 %-Ø+UØ*,Ø48ð	&ð &ð#ð #ð "( ðð ðð ð( (ð+	
ð 	
ðQ?ð ?rJ   Úlabelc                 ó  — | €t          ¦   «         S t          | t          ¦  «        r| hS t          | t          t          t           f¦  «        rd„ | D ¦   «         S t
                               d|| ¦  «         t          ¦   «         S )z8Normalize include/exclude config to a set of tool names.Nc                 ó,   — h | ]}t          |¦  «        ’ŒS rI   )r�   r  s     r&   rK  z)_normalize_name_filter.<locals>.<setcomp>²	  s   € Ð,Ð,Ð,˜d•�D‘	”	Ð,Ð,Ð,rJ   z>MCP config %s must be a string or list of strings; ignoring %r)r�  r¬   r�   r
  r   r   rq   )rb   rö  s     r&   Ú_normalize_name_filterrù  «	  sx   € à€}Ý‰uŒuˆÝ�%�ÑÔð ØˆwˆÝ�%�$¥¥sÐ+Ñ,Ô,ð -Ø,Ð, eÐ,Ñ,Ô,Ð,Ý
‡N‚NÐSÐUZÐ\aÑbÔbÐbÝ‰5Œ5€LrJ   rË   c                 ó  — | €|S t          | t          ¦  «        r| S t          | t          ¦  «        r2|                      ¦   «                              ¦   «         }|dv rdS |dv rdS t
                               d| |¦  «         |S )z2Parse a bool-like config value with safe fallback.N>   Ú1ÚonÚyesÚtrueT>   Ú0ÚnoÚoffÚfalseFzAMCP config expected a boolean-ish value, got %r; using default=%s)r¬   r{  r�   r‘   rí   r   rq   )rb   rË   Úlowereds      r&   Ú_parse_boolishr  ·	  sŽ   € à€}ØˆÝ�%�ÑÔð ØˆÝ�%�ÑÔð Ø—+’+‘-”-×%Ò%Ñ'Ô'ˆØÐ0Ð0Ð0Ø�4ØÐ1Ð1Ð1Ø�5Ý
‡N‚NÐVÐX]Ð_fÑgÔgÐgØ€NrJ   r§  r·  rÁ  rÇ  ©r§  r·  rÁ  rÇ  r1  c                 ó2  — |                      d¦  «        pi }t          |                      d¦  «        d¬¦  «        }t          |                      d¦  «        d¬¦  «        }g }t          | ¦  «        D ]¥}|d         }|dv r|st                               d| |¦  «         Œ-|d	v r|st                               d
| |¦  «         ŒPt
          |         }	t          |j        |	¦  «        st                               d| ||	¦  «         Œ�|                     |¦  «         Œ¦|S )z?Select utility schemas based on config and server capabilities.rT  r¥  T©rË   r¾  rî  >   r·  r§  z;MCP server '%s': skipping utility '%s' (resources disabled)>   rÇ  rÁ  z9MCP server '%s': skipping utility '%s' (prompts disabled)z9MCP server '%s': skipping utility '%s' (session lacks %s))	r   r  rõ  r   r   Ú_UTILITY_CAPABILITY_METHODSrÿ   r  rp   )
r(   r1  rØ   Útools_filterÚresources_enabledÚprompts_enabledÚselectedr©  rî  Úrequired_methods
             r&   Ú_select_utility_schemasr  Ï	  s9  € à—:’:˜gÑ&Ô&Ð,¨"€LÝ& |×'7Ò'7¸Ñ'DÔ'DÈdÐSÑSÔSÐÝ$ \×%5Ò%5°iÑ%@Ô%@È$ÐOÑOÔO€Oà€HÝ'¨Ñ4Ô4ð ð ˆØ˜MÔ*ˆØÐ=Ð=Ð=ÐFWÐ=Ý�LŠLÐVÐXcÐepÑqÔqÐqØØÐ8Ð8Ð8ÀÐ8Ý�LŠLÐTÐVaÐcnÑoÔoÐoØå5°kÔBˆÝ�v”~ Ñ7Ô7ð 	Ý�LŠLØKØØØñ	ô ð ð Ø�Š˜ÑÔÐÐØ€OrJ   c                  ó  — g } t                                ¦   «         D ]j\  }}t          |d¦  «        r|                      |j        ¦  «         Œ0|j        D ]2}t          |j        |¦  «        }|                      |d         ¦  «         Œ3Œk| S )z6Return tool names for all currently connected servers.rˆ  rþ   )	r  r\   rÿ   r¹   rˆ  r…  rë  rþ   rp   )ÚnamesÚ_snamer1  rè  rÏ  s        r&   Ú_existing_tool_namesr  ì	  s–   € à€EÝ"Ÿ.š.Ñ*Ô*ð )ð )‰ˆ�Ý�6Ð3Ñ4Ô4ð 	Ø�LŠL˜Ô6Ñ7Ô7Ð7ØØœð 	)ð 	)ˆHÝ(¨¬°hÑ?Ô?ˆFØ�LŠL˜ œÑ(Ô(Ð(Ð(ð	)ð €LrJ   c                 ód  ‡‡— ddl m} g }d| › �}|                     d¦  «        pi }t          |                     d¦  «        d| › d�¦  «        Št          |                     d¦  «        d| › d	�¦  «        Šd
t          dt
          fˆˆfd„}|j        D �]} ||j        ¦  «        s"t           	                    d| |j        ¦  «         Œ5t          | |j        |j        pd¦  «         t          | |¦  «        }	|	d         }
|                     |
¦  «        }|r9|                     d¦  «        s$t                               d| |j        |
|¦  «         Œº|                     |
||	t#          | |j        |j        ¦  «        t'          | ¦  «        d|	d         ¬¦  «         |                     |
¦  «         �Œt*          t,          t.          t0          dœ}t'          | ¦  «        }t3          | ||¦  «        D ]²}|d         }	|d         } ||         | |j        ¦  «        }|	d         }|                     |¦  «        }|r3|                     d¦  «        st                               d| ||¦  «         Œ{|                     |||	||d|	d         ¬¦  «         |                     |¦  «         Œ³|r|                     | |¦  «         |S )a­  Register tools from an already-connected server into the registry.

    Handles include/exclude filtering and utility tools. Toolset resolution
    for ``mcp-{server}`` and raw server-name aliases is derived from the live
    registry, rather than mutating ``toolsets.TOOLSETS`` at runtime.

    Used by both initial discovery and dynamic refresh (list_changed).

    Returns:
        List of registered prefixed tool names.
    r   rš  zmcp-rT  Úincludezmcp_servers.z.tools.includeÚexcludez.tools.excluderj   r	   c                 ó    •— ‰r| ‰v S ‰r| ‰vS dS )NTrI   )rj   Úexclude_setÚinclude_sets    €€r&   Ú_should_registerz0_register_server_tools.<locals>._should_register
  s.   ø€ Øð 	,Ø Ð+Ð+Øð 	0Ø KÐ/Ð/ØˆtrJ   z8MCP server '%s': skipping tool '%s' (filtered by config)ry   rþ   us   MCP server '%s': tool '%s' (â†’ '%s') collides with built-in tool in toolset '%s' â€” skipping to preserve built-inFrk   )rþ   ÚtoolsetrÏ  ÚhandlerÚcheck_fnÚis_asyncrk   r  rÏ  rî  up   MCP server '%s': utility tool '%s' collides with built-in tool in toolset '%s' â€” skipping to preserve built-in)rœ  r›  r   rù  r�   r{  r…  rþ   r   r   rv   rk   rë  Úget_toolset_for_toolr^   rq   Úregisterr¡  r€  rÎ  rp   r¯  rº  rÃ  rÊ  r  Úregister_toolset_alias)rþ   r1  rØ   r›  Úregistered_namesÚtoolset_namer	  r  rè  rÏ  Útool_name_prefixedÚexisting_toolsetÚ_handler_factoriesr  r©  rî  r  Ú	util_namer  r  s                     @@r&   r   r   ù	  s]  øø€ ð (Ð'Ð'Ð'Ð'Ð'à"$ÐØ ˜$�=�=€Lð —:’:˜gÑ&Ô&Ð,¨"€LÝ(¨×)9Ò)9¸)Ñ)DÔ)DÐFiÐUYÐFiÐFiÐFiÑjÔj€KÝ(¨×)9Ò)9¸)Ñ)DÔ)DÐFiÐUYÐFiÐFiÐFiÑjÔj€Kð¥Cð ­Dð ð ð ð ð ð ð ð ”Mð 4ñ 4ˆØÐ ¤Ñ.Ô.ð 	Ý�LŠLÐSÐUYÐ[cÔ[hÑiÔiÐiØõ 	˜d H¤M°8Ô3GÐ3MÈ2ÑNÔNÐNå$ T¨8Ñ4Ô4ˆØ# Fœ^Ðð $×8Ò8Ð9KÑLÔLÐØð 	Ð$4×$?Ò$?ÀÑ$GÔ$Gð 	Ý�NŠNðIà�h”mÐ%7Ð9Iñô ð ð
 à×ÒØ#Ø ØÝ& t¨X¬]¸FÔ<OÑPÔPÝ# DÑ)Ô)ØØ˜}Ô-ð 	ñ 	
ô 	
ð 	
ð 	×ÒÐ 2Ñ3Ô3Ð3Ñ3õ
 7Ý4Ý2Ý.ð	ð Ðõ ˜dÑ#Ô#€HÝ(¨¨v°vÑ>Ô>ð +ð +ˆØ�x”ˆØ˜MÔ*ˆØ1Ð$ [Ô1°$¸Ô8KÑLÔLˆØ˜6”Nˆ	ð $×8Ò8¸ÑCÔCÐØð 	Ð$4×$?Ò$?ÀÑ$GÔ$Gð 	Ý�NŠNðIà�iÐ!1ñô ð ð
 à×ÒØØ ØØØØØ˜}Ô-ð 	ñ 	
ô 	
ð 	
ð 	×Ò 	Ñ*Ô*Ð*Ð*àð <Ø×'Ò'¨¨lÑ;Ô;Ð;àÐrJ   c           	   ƒ   ó¼  K  — |                      dt          ¦  «        }t          j        t	          | |¦  «        |¬¦  «        ƒ d{V —†}t
          5  |t          | <   ddd¦  «         n# 1 swxY w Y   t          | ||¦  «        }t          |¦  «        |_	        d|v rdnd}t                               d| |t          |¦  «        d                     |¦  «        ¦  «         |S )	zsConnect to a single MCP server, discover tools, and register them.

    Returns list of registered tool names.
    rÔ  rh  Nr(  ÚHTTPÚstdioz/MCP server '%s' (%s): registered %d tool(s): %sr\  )r   rí  rq  rr  r‡  rÀ  r  r   r
  rˆ  r   râ   rú   rr   )rþ   rØ   rÔ  r1  r!  Útransport_types         r&   Ú_discover_and_register_serverr+  e
  s?  è è € ð
 —j’jÐ!2Õ4LÑMÔM€OÝÔ#Ý˜˜fÑ%Ô%Øðñ ô ð ð ð ð ð ð €Fõ 
ð  ð  Ø��‰ð ð  ð  ñ  ô  ð  ð  ð  ð  ð  ð  øøøð  ð  ð  ð  õ .¨d°F¸FÑCÔCÐÝ$(Ð)9Ñ$:Ô$:€FÔ!à$¨˜˜�V�V°G€NÝ
‡K‚KØ9Øˆn�cÐ"2Ñ3Ô3Ø�	Š	Ð"Ñ#Ô#ñô ð ð
 Ðs   ÁA&Á&A*Á-A*r„  c                 ó$  ‡‡— t           st                               d¦  «         g S | st                               d¦  «         g S t          5  d„ |                      ¦   «         D ¦   «         Šddd¦  «         n# 1 swxY w Y   ‰st          ¦   «         S t          ¦   «          dt          dt          dt          t                   fd„Šˆˆfd	„}t           |¦   «         d
¬¦  «         t          5  d„ ‰D ¦   «         }t          d„ |D ¦   «         ¦  «        }ddd¦  «         n# 1 swxY w Y   t          ‰¦  «        t          |¦  «        z
  }|s|r;d|› dt          |¦  «        › d�}|r	|d|› d�z  }t                               |¦  «         t          ¦   «         S )a[  Connect to explicit MCP servers and register their tools.

    Idempotent for already-connected server names. Servers with
    ``enabled: false`` are skipped without disconnecting existing sessions.

    Args:
        servers: Mapping of ``{server_name: server_config}``.

    Returns:
        List of all currently registered MCP tool names.
    z;MCP SDK not available -- skipping explicit MCP registrationz No explicit MCP servers providedc                 óv   — i | ]6\  }}|t           v¯t          |                     d d¦  «        d¬¦  «        ¯3||“Œ7S ©rý  Tr  ©r  r  r   rv  s      r&   ry  z(register_mcp_servers.<locals>.<dictcomp>™
  sT   € ð 
ð 
ð 
á��1Ø�Ð Ð ¥^°A·E²E¸)ÀTÑ4JÔ4JÐTXÐ%YÑ%YÔ%YÐ ð ˆqà Ð Ð rJ   Nrþ   r�  r	   c              “   ó2   K  — t          | |¦  «        ƒ d{V —†S )z@Connect to a single server and return its registered tool names.N)r+  )rþ   r�  s     r&   Ú_discover_onez+register_mcp_servers.<locals>._discover_one¥
  s(   è è € å2°4¸Ñ=Ô=Ð=Ð=Ð=Ð=Ð=Ð=Ð=rJ   c            	   “   óÄ  •K  — t          ‰                     ¦   «         ¦  «        } t          j        ˆfd„‰                     ¦   «         D ¦   «         ddiŽƒ d {V —†}t          | |¦  «        D ]u\  }}t          |t          ¦  «        r[‰                     |i ¦  «                             d¦  «        }t           
                    d||rd|› d�ndt          |¦  «        ¦  «         Œvd S )	Nc              3   ó6   •K  — | ]\  }} ‰||¦  «        V — Œd S r)  rI   )r{   rþ   r�  r1  s      €r&   r	  z>register_mcp_servers.<locals>._discover_all.<locals>.<genexpr>­
  s3   øè è € ÐLÐL©9¨4°ˆmˆm˜D #Ñ&Ô&ÐLÐLÐLÐLÐLÐLrJ   Úreturn_exceptionsTr†   z*Failed to connect to MCP server '%s'%s: %sz
 (command=ú)ry   )r
  Úkeysrq  Úgatherr\   Úzipr¬   r   r   r   rq   rÄ   )Úserver_namesÚresultsrþ   rÎ   r†   r1  Únew_serverss        €€r&   Ú_discover_allz+register_mcp_servers.<locals>._discover_all©
  s  øè è € Ý˜K×,Ò,Ñ.Ô.Ñ/Ô/ˆåœØLÐLÐLÐL¸×8IÒ8IÑ8KÔ8KÐLÑLÔLð
à"ð
ð 
ð 
ð 
ð 
ð 
ð 
ð 
ˆõ   ¨gÑ6Ô6ð 	ð 	‰LˆD�&Ý˜&¥)Ñ,Ô,ð Ø%Ÿ/š/¨$°Ñ3Ô3×7Ò7¸	ÑBÔB�Ý—’Ø@ØØ/6Ð>Ð+ Ð+Ð+Ð+Ð+¸BÝ)¨&Ñ1Ô1ñ	ô ð øð	ð 	rJ   rL   rh  c                 ó$   — g | ]}|t           v ¯|‘ŒS rI   ©r  ©r{   r  s     r&   r}   z(register_mcp_servers.<locals>.<listcomp>À
  s   € Ð=Ð=Ð=˜1¨qµH¨}¨}�Q¨}¨}¨}rJ   c              3   óh   K  — | ]-}t          t          t          |         d g ¦  «        ¦  «        V — Œ.dS ©rˆ  N©rú   r«   r  r?  s     r&   r	  z'register_mcp_servers.<locals>.<genexpr>Á
  sO   è è € ð 
ð 
àõ •� œÐ%=¸rÑBÔBÑCÔCð
ð 
ð 
ð 
ð 
ð 
rJ   zMCP: registered ú tool(s) from ú
 server(s)ú (ú failed))rC   r   r   rÀ  r\   r  rb  r�   r~   r   r2  Úsumrú   râ   )r„  r<  Ú	connectedÚnew_tool_countÚfailedÚsummaryr1  r;  s         @@r&   Úregister_mcp_serversrL  ‚
  sq  øø€ õ ð Ý�ŠÐRÑSÔSÐSØˆ	àð Ý�ŠÐ7Ñ8Ô8Ð8Øˆ	õ 
ð 
ð 
ð
ð 
àŸš™œð
ñ 
ô 
ˆð
ð 
ð 
ñ 
ô 
ð 
ð 
ð 
ð 
ð 
ð 
øøøð 
ð 
ð 
ð 
ð ð &Ý#Ñ%Ô%Ð%õ ÑÔÐð>¥#ð >­Dð >µT½#´Yð >ð >ð >ð >ðð ð ð ð ð õ& �]�]‘_”_¨cÐ2Ñ2Ô2Ð2õ 
ð 
ð 
Ø=Ð= Ð=Ñ=Ô=ˆ	Ýð 
ð 
àð
ñ 
ô 
ñ 
ô 
ˆð
ð 
ð 
ñ 
ô 
ð 
ð 
ð 
ð 
ð 
ð 
øøøð 
ð 
ð 
ð 
õ �ÑÔ¥ I¡¤Ñ.€FØð ˜ð Ø] ^Ð]Ð]Å3ÀyÁ>Ä>Ð]Ð]Ð]ˆØð 	-ØÐ,˜FÐ,Ð,Ð,Ñ,ˆGÝ�Š�GÑÔÐåÑ!Ô!Ð!s$   ÁA6Á6A:Á=A:Ã)&DÄDÄ"Dc                  óˆ  — t           st                               d¦  «         g S t          ¦   «         } | st                               d¦  «         g S t          5  d„ |                      ¦   «         D ¦   «         }ddd¦  «         n# 1 swxY w Y   t          | ¦  «        }|s|S t          5  d„ |D ¦   «         }t          d„ |D ¦   «         ¦  «        }ddd¦  «         n# 1 swxY w Y   t          |¦  «        t          |¦  «        z
  }|s|r;d|› dt          |¦  «        › d	�}|r	|d
|› d�z  }t           	                    |¦  «         |S )aŸ  Entry point: load config, connect to MCP servers, register tools.

    Called from ``model_tools`` after ``discover_builtin_tools()``. Safe to call even when
    the ``mcp`` package is not installed (returns empty list).

    Idempotent for already-connected servers. If some servers failed on a
    previous call, only the missing ones are retried.

    Returns:
        List of all registered MCP tool names.
    z4MCP SDK not available -- skipping MCP tool discoveryzNo MCP servers configuredc                 ót   — g | ]5\  }}|t           v¯t          |                     d d¦  «        d¬¦  «        ¯3|‘Œ6S r.  r/  r€  s      r&   r}   z&discover_mcp_tools.<locals>.<listcomp>å
  sR   € ð 
ð 
ð 
á��cØ�8Ð#Ð#­°s·w²w¸yÈ$Ñ7OÔ7OÐY]Ð(^Ñ(^Ô(^Ð#ð à#Ð#Ð#rJ   Nc                 ó$   — g | ]}|t           v ¯|‘ŒS rI   r>  ©r{   rþ   s     r&   r}   z&discover_mcp_tools.<locals>.<listcomp>ð
  s"   € Ð!XÐ!XÐ!X¨4ÀtÍxÐGWÐGW $ÐGWÐGWÐGWrJ   c              3   óh   K  — | ]-}t          t          t          |         d g ¦  «        ¦  «        V — Œ.dS rA  rB  rP  s     r&   r	  z%discover_mcp_tools.<locals>.<genexpr>ñ
  sO   è è € ð 
ð 
àõ •� œÐ(@À"ÑEÔEÑFÔFð
ð 
ð 
ð 
ð 
ð 
rJ   z  MCP: rC  rD  rE  rF  )
rC   r   r   r…  rÀ  r\   rL  rG  rú   râ   )r„  Únew_server_namesÚ
tool_namesÚconnected_server_namesrI  Úfailed_countrK  s          r&   Údiscover_mcp_toolsrV  Ï
  s  € õ ð Ý�ŠÐKÑLÔLÐLØˆ	åÑ Ô €GØð Ý�ŠÐ0Ñ1Ô1Ð1Øˆ	å	ð 
ð 
ð
ð 
à$Ÿ]š]™_œ_ð
ñ 
ô 
Ðð
ð 
ð 
ñ 
ô 
ð 
ð 
ð 
ð 
ð 
ð 
øøøð 
ð 
ð 
ð 
õ & gÑ.Ô.€JØð ØÐå	ð 
ð 
Ø!XÐ!XÐ3CÐ!XÑ!XÔ!XÐÝð 
ð 
à.ð
ñ 
ô 
ñ 
ô 
ˆð
ð 
ð 
ñ 
ô 
ð 
ð 
ð 
ð 
ð 
ð 
øøøð 
ð 
ð 
ð 
õ Ð'Ñ(Ô(­3Ð/EÑ+FÔ+FÑF€LØð ˜ð Øa˜NÐaÐa½#Ð>TÑ:UÔ:UÐaÐaÐaˆØð 	3ØÐ2˜LÐ2Ð2Ð2Ñ2ˆGÝ�Š�GÑÔÐàÐs$   ÁBÂBÂ	BÂ'&CÃCÃ Cc                  ó4  — g } t          ¦   «         }|s| S t          5  t          t          ¦  «        }ddd¦  «         n# 1 swxY w Y   |                     ¦   «         D ]»\  }}d|v rdnd}|                     |¦  «        }|r}|j        �v||t          |d¦  «        rt          |j	        ¦  «        nt          |j
        ¦  «        ddœ}|j        rt          |j        j        ¦  «        |d<   |                      |¦  «         Œ¡|                      ||d	d
dœ¦  «         Œ¼| S )zàReturn status of all configured MCP servers for banner display.

    Returns a list of dicts with keys: name, transport, tools, connected.
    Includes both successfully connected servers and configured-but-failed ones.
    Nr(  Úhttpr)  rˆ  T)rþ   Ú	transportrT  rH  rü  r   F)r…  rÀ  r~   r  r\   r   r  rÿ   rú   rˆ  r…  r‡  rñ   rp   )rÎ   Ú
configuredÚactive_serversrþ   r�  rY  r1  r©  s           r&   Úget_mcp_statusr\     s   € ð €Fõ "Ñ#Ô#€JØð Øˆå	ð (ð (Ý�h™œˆð(ð (ð (ñ (ô (ð (ð (ð (ð (ð (ð (øøøð (ð (ð (ð (ð  ×%Ò%Ñ'Ô'ð ð ‰	ˆˆcØ# s˜l˜l�F�F°ˆ	Ø×#Ò# DÑ)Ô)ˆØð 	�f”nÐ0àØ&Ý?FÀvÐOgÑ?hÔ?hð  A�˜VÔ:Ñ;Ô;Ð;ÕnqÐrxÔrñ  oAô  oAØ!ð	ð ˆEð Ôð CÝ$(¨Ô)9Ô)AÑ$BÔ$B��jÑ!Ø�MŠM˜%Ñ Ô Ð Ð à�MŠMØØ&ØØ"ð	ð ñ ô ð ð ð €Ms   œ=½AÁAc                  ó–  ‡‡‡— t           si S t          ¦   «         } | si S d„ |                      ¦   «         D ¦   «         Š‰si S t          ¦   «          i Šg Šˆˆˆfd„}	 t	           |¦   «         d¬¦  «         n2# t
          $ r%}t                               d|¦  «         Y d}~nd}~ww xY wt          ¦   «          n# t          ¦   «          w xY w‰S )u´  Temporarily connect to configured MCP servers and list their tools.

    Designed for ``hermes tools`` interactive configuration â€” connects to each
    enabled server, grabs tool names and descriptions, then disconnects.
    Does NOT register tools in the Hermes registry.

    Returns:
        Dict mapping server name to list of (tool_name, description) tuples.
        Servers that fail to connect are omitted from the result.
    c                 ód   — i | ]-\  }}t          |                     d d¦  «        d¬¦  «        ¯*||“Œ.S r.  )r  r   rv  s      r&   ry  z*probe_mcp_server_tools.<locals>.<dictcomp>:  sO   € ð ð ð Ù��AÝ˜!Ÿ%š% 	¨4Ñ0Ô0¸$Ð?Ñ?Ô?ðØ	ˆ1ðð ð rJ   c            	   “   óÔ  •K  — t          ‰
                     ¦   «         ¦  «        } g }‰
                     ¦   «         D ]W\  }}|                     dt          ¦  «        }|                     t          j        t          ||¦  «        |¬¦  «        ¦  «         ŒXt          j	        |ddiŽƒ d {V —†}t          | |¦  «        D ]Œ\  }}t          |t          ¦  «        rt                               d||¦  «         Œ7‰                     |¦  «         g }|j        D ]1}t!          |dd¦  «        pd}	|                     |j        |	f¦  «         Œ2|‰|<   Œ�t          j	        d„ ‰D ¦   «         ddiŽƒ d {V —† d S )	NrÔ  rh  r4  Tz$Probe: failed to connect to '%s': %srk   ry   c              3   ó>   K  — | ]}|                      ¦   «         V — Œd S r)  ©r¬  )r{   Úss     r&   r	  z=probe_mcp_server_tools.<locals>._probe_all.<locals>.<genexpr>\  s*   è è € Ð3Ð3˜qˆa�jŠj‰lŒlÐ3Ð3Ð3Ð3Ð3Ð3rJ   )r
  r6  r\   r   rí  rp   rq  rr  r‡  r7  r8  r¬   r   r   r   r…  r«   rþ   )r  Úcorosrþ   r�  ÚctÚoutcomesÚoutcomerT  r÷   Údescrý  Úprobed_serversrÎ   s             €€€r&   Ú
_probe_allz*probe_mcp_server_tools.<locals>._probe_allF  s®  øè è € Ý�W—\’\‘^”^Ñ$Ô$ˆØˆØ Ÿš™œð 	Sð 	S‰IˆD�#Ø—’Ð*Õ,DÑEÔEˆBØ�LŠL�Ô)­/¸$ÀÑ*DÔ*DÈbÐQÑQÔQÑRÔRÐRÐRå œ¨ÐGÀ$ÐGÐGÐGÐGÐGÐGÐGÐGˆå  ¨Ñ1Ô1ð 		!ð 		!‰MˆD�'Ý˜'¥9Ñ-Ô-ð Ý—’ÐCÀTÈ7ÑSÔSÐSØØ×!Ò! 'Ñ*Ô*Ð*ØˆEØ”^ð -ð -�Ý˜q -°Ñ4Ô4Ð:¸�Ø—’˜aœf d˜^Ñ,Ô,Ð,Ð,Ø ˆF�4‰LˆLõ ŒnØ3Ð3 NÐ3Ñ3Ô3ð
à"ð
ð 
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
rJ   rL   rh  zMCP probe failed: %sN)	rC   r…  r\   rb  r2  r   r   r   Ú_stop_mcp_loop)Úservers_configri  r%   rý  rh  rÎ   s      @@@r&   Úprobe_mcp_server_toolsrl  (  s*  øøø€ õ ð Øˆ	å%Ñ'Ô'€NØð Øˆ	ðð Ø'×-Ò-Ñ/Ô/ðñ ô €Gð ð Øˆ	åÑÔÐà%'€FØ*,€Nð
ð 
ð 
ð 
ð 
ð 
ð 
ð4Ý˜˜™œ¨sÐ3Ñ3Ô3Ð3Ð3øÝð 2ð 2ð 2Ý�ŠÐ+¨SÑ1Ô1Ð1Ð1Ð1Ð1Ð1Ð1øøøøð2øøøõ 	ÑÔÐÐø�ÑÔÐÐøøøà€Ms0   ÁA5 Á4B6 Á5
B$Á?BÂB6 ÂB$Â$B6 Â6Cc                  ó"  ‡— t           5  t          t                               ¦   «         ¦  «        Šddd¦  «         n# 1 swxY w Y   ‰st	          ¦   «          dS ˆfd„} t           5  t
          }ddd¦  «         n# 1 swxY w Y   |�{|                     ¦   «         rg	 t          j         | ¦   «         |¦  «        }| 	                    d¬¦  «         n2# t          $ r%}t                               d|¦  «         Y d}~nd}~ww xY wt	          ¦   «          dS )a  Close all MCP server connections and stop the background loop.

    Each server Task is signalled to exit its ``async with`` block so that
    the anyio cancel-scope cleanup happens in the same Task that opened it.
    All servers are shut down in parallel via ``asyncio.gather``.
    Nc               “   óX  •K  — t          j        d„ ‰D ¦   «         ddiŽƒ d {V —†} t          ‰| ¦  «        D ];\  }}t          |t          ¦  «        r!t
                               d|j        |¦  «         Œ<t          5  t           
                    ¦   «          d d d ¦  «         d S # 1 swxY w Y   d S )Nc              3   ó>   K  — | ]}|                      ¦   «         V — Œd S r)  ra  )r{   r1  s     r&   r	  z:shutdown_mcp_servers.<locals>._shutdown.<locals>.<genexpr>{  s,   è è € Ð?Ð? Fˆf�oŠoÑÔÐ?Ð?Ð?Ð?Ð?Ð?rJ   r4  Tz!Error closing MCP server '%s': %s)rq  r7  r8  r¬   r   r   r   rþ   rÀ  r  rµ  )r:  r1  rÎ   Úservers_snapshots      €r&   Ú	_shutdownz'shutdown_mcp_servers.<locals>._shutdowny  s  øè è € ÝœØ?Ð?Ð.>Ð?Ñ?Ô?ð
à"ð
ð 
ð 
ð 
ð 
ð 
ð 
ð 
ˆõ "Ð"2°GÑ<Ô<ð 	ð 	‰NˆF�FÝ˜&¥)Ñ,Ô,ð Ý—’Ø7¸¼Àfñô ð øõ ð 	ð 	Ý�NŠNÑÔÐð	ð 	ð 	ñ 	ô 	ð 	ð 	ð 	ð 	ð 	ð 	ð 	øøøð 	ð 	ð 	ð 	ð 	ð 	s   Á8BÂB#Â&B#r-  rh  zError during MCP shutdown: %s)rÀ  r
  r  Úvaluesrj  r3  r4  rq  rf  rÎ   r   r   r   )rq  r:  rj  r%   rp  s       @r&   Úshutdown_mcp_serversrs  j  s®  ø€ õ 
ð 3ð 3Ý¥§¢Ñ 1Ô 1Ñ2Ô2Ðð3ð 3ð 3ñ 3ô 3ð 3ð 3ð 3ð 3ð 3ð 3øøøð 3ð 3ð 3ð 3ð ð ÝÑÔÐØˆðð ð ð ð õ 
ð ð Ýˆðð ð ñ ô ð ð ð ð ð ð øøøð ð ð ð àÐ˜DŸOšOÑ-Ô-Ðð	?ÝÔ5°i°i±k´kÀ4ÑHÔHˆFØ�MŠM "ˆMÑ%Ô%Ð%Ð%øÝð 	?ð 	?ð 	?Ý�LŠLÐ8¸#Ñ>Ô>Ð>Ð>Ð>Ð>Ð>Ð>øøøøð	?øøøõ ÑÔÐÐÐs9   ‰'<¼A ÁA Á%A9Á9A=Â A=Â3C Ã
C>ÃC9Ã9C>c                  óä  — ddl } ddl}t          5  t          t          ¦  «        }t                               ¦   «          ddd¦  «         n# 1 swxY w Y   |sdS |                     ¦   «         D ]Y\  }}	 t          j        || j	        ¦  «         t                               d||¦  «         Œ=# t          t          t          f$ r Y ŒVw xY w|                     d¦  «         t!          | d| j	        ¦  «        }|                     ¦   «         D ]i\  }}	 t          j        |d¦  «         t          j        ||¦  «         t                               d||¦  «         ŒM# t          t          t          f$ r Y Œfw xY wdS )uj  Graceful shutdown of MCP stdio subprocesses that survived loop cleanup.

    Sends SIGTERM first, waits 2 seconds, then escalates to SIGKILL.
    This prevents shared-resource collisions when multiple hermes processes
    run on the same host (each has its own _stdio_pids dict).

    Only kills PIDs tracked in ``_stdio_pids`` â€” never arbitrary children.
    r   Nz,Sent SIGTERM to orphaned MCP process %d (%s)rþ  ÚSIGKILLz6Force-killed MCP process %d (%s) after SIGTERM timeout)Úsignalrù   rÀ  r~   rÁ  rµ  r\   r   ÚkillÚSIGTERMr   r   ÚProcessLookupErrorÚPermissionErrorrP  r   r«   rq   )Ú_signalÚ_timeÚpidsrM  r(   Ú_sigkills         r&   Ú_kill_orphaned_mcp_childrenr  ’  sÛ  € ð ÐÐÐØÐÐÐå	ð ð Ý•KÑ Ô ˆÝ×ÒÑÔÐðð ð ñ ô ð ð ð ð ð ð øøøð ð ð ð ð ð Øˆð !ŸJšJ™LœLð ð Ñˆˆ[ð	ÝŒG�C˜œÑ)Ô)Ð)Ý�LŠLÐGÈÈkÑZÔZÐZÐZøÝ"¥OµWÐ=ð 	ð 	ð 	ØˆDð	øøøð 
‡K‚K��N„N€Nõ �w 	¨7¬?Ñ;Ô;€HØ ŸJšJ™LœLð 	ð 	Ñˆˆ[ð	ÝŒG�C˜‰OŒOˆOÝŒG�C˜Ñ"Ô"Ð"Ý�NŠNØHØ�[ñô ð ð øõ #¥OµWÐ=ð 	ð 	ð 	ØˆDð	øøøð	ð 	s6   �.A
Á
AÁAÁ36B*Â*CÃCÄAEÅE-Å,E-c                  ó<  — t           5  t          } t          }dadaddd¦  «         n# 1 swxY w Y   | �h|                      | j        ¦  «         |�|                     d¬¦  «         	 |                      ¦   «          n# t          $ r Y nw xY wt          ¦   «          dS dS )z3Stop the background event loop and join its thread.NrN   rh  )	rÀ  r3  rG  r5  rÕ   rr   Úcloser   r  )r:  Úthreads     r&   rj  rj  À  sû   € õ 
ð ð ÝˆÝˆØˆ	Øˆð	ð ð ñ ô ð ð ð ð ð ð øøøð ð ð ð ð
 ÐØ×!Ò! $¤)Ñ,Ô,Ð,ØÐØ�KŠK ˆKÑ"Ô"Ð"ð	Ø�JŠJ‰LŒLˆLˆLøÝð 	ð 	ð 	ØˆDð	øøøõ 	$Ñ%Ô%Ð%Ð%Ð%ð Ðs   ˆ'§+®+Á'A< Á<
B	ÂB	)rÝ   )T)r	   N)Œrz  rq  Úconcurrent.futuresrg  rD   r)  ré   rÇ   r   r®   r“   r    r_  rù   r   Útypingr   r   r   r   Ú	getLoggerr»   r   r   Ú__annotations__rŽ  r   r'   r�   r/   rC   rê  r:  r“  r¾  r5   re  r0   r1   Úmcp.client.stdior2   Úmcp.client.streamable_httpr3   rë  r4   rð  Ú	mcp.typesr   r6   r7   r8   r9   r:   r;   r<   r=   r>   r?   r@   r{  rK   rŒ  rí  r  rÿ  r  Ú	frozensetr]   ÚcompileÚ
IGNORECASErf   r~   rc   ri   ÚIrn   rv   r…   r   r¢   r°   rÄ   rç   rÏ   rÑ   r~  r  r  r  rÆ   r  rœ  r  r  r  r"  r%  r=  r>  rC  rF  r3  ÚAbstractEventLooprG  r`  rÀ  rÁ  r�  r¿  rZ  rb  r2  rn  ru  r…  r‡  r¡  r¯  rº  rÃ  rÊ  rÎ  rc  rå  rë  rõ  rù  r  r  r  r  r   r+  rL  rV  r\  rl  rs  r  rj  rI   rJ   r&   ú<module>r�     s‰  ððDð Dð DðL €€€Ø Ð Ð Ð Ø €€€Ø €€€Ø €€€Ø €€€Ø 	€	€	€	Ø 	€	€	€	Ø €€€Ø 
€
€
€
Ø Ð Ð Ð Ø €€€Ø Ð Ð Ð Ð Ð Ø ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,à	ˆÔ	˜8Ñ	$Ô	$€ð( %)Ð �H˜S”MÐ (Ð (Ñ (Ø%�y”~Ñ'Ô'Ð ð "˜Sð  "ð  "ð  "ð  "ðF¨#ð °$ð ð ð ð ð& €ØÐ ØÐ ØÐ Ø!&Ð ð 'Ð ð.KØ8Ð8Ð8Ð8Ð8Ð8Ð8Ð8Ø-Ð-Ð-Ð-Ð-Ð-Ø€Nð$ØDÐDÐDÐDÐDÐDØ"ÐÐøØð $ð $ð $Ø#ÐÐÐð$øøøðØEÐEÐEÐEÐEÐEØˆˆøØð ð ð ØˆˆˆðøøøðkØ5Ð5Ð5Ð5Ð5Ð5Ð5øØð kð kð kØ�ŠÐiÑjÔjÐjÐjÐjðkøøøðNð	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð #ÐÐøØð Nð Nð NØ�ŠÐLÑMÔMÐMÐMÐMðNøøøð	`ð	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð #'ÐÐøØð `ð `ð `Ø�ŠÐ^Ñ_Ô_Ð_Ð_Ð_ð`øøøøøàð Kð Kð KØ
‡L‚LÐIÑJÔJÐJÐJÐJðKøøøð¨ð ð ð ð ð "@Ð!?Ñ!AÔ!AÐ Øð `Ð8ð `Ø
‡L‚LÐ^Ñ_Ô_Ð_ð Ð ØÐ ØÐ Ø Ð ØÐ ð �ð ð ð ñ ô €ð
 !�b”jð		ð „Mñô Ð ð&˜h tœnð °ð ð ð ð ð&7˜#ð 7 #ð 7ð 7ð 7ð 7ð" €R„ZÐ<¸b¼dÑCÔCØ?ðAà€R„ZÐ&¨¬Ñ-Ô-Ø5ð7à€R„ZÐDÀbÄdÑKÔKØðà€R„ZÐ  "¤$Ñ'Ô'Ø&ð(à€R„ZÐ3°R´TÑ:Ô:Ø!ð#à€R„ZÐ:¸B¼DÑAÔAØð à€R„ZÐ0°"´$Ñ7Ô7Ø%ð'à€R„ZÐ2°B´DÑ9Ô9Øð à€R„ZÐ&¨¬Ñ-Ô-Øð!à€R„ZÐ9¸2¼4Ñ@Ô@Ø!ð#ð'Ð ð0 sð °sð Èð ÐQUÐVYÔQZð ð ð ð ð*�tð ¨ð °ð ð ð ð ð!* Cð !*¨dð !*°u¸SÀ$¸YÔ7Gð !*ð !*ð !*ð !*ðH93˜}ð 93°ð 93ð 93ð 93ð 93ð@ *-°að ð ð ð ðl9ð l9ð l9ð l9ð l9ñ l9ô l9ð l9ðfoð oð oð oð oñ oô oð oðl &(€ˆ$ˆs�MÐ!Ô
"Ð 'Ð 'Ñ 'ð& (*Ð �d˜3 ˜8”nÐ )Ð )Ñ )Ø.0Ð ˜4  U 
Ô+Ð 0Ð 0Ñ 0ØÐ Ø $Ð ð
B Cð 
B¨Dð 
Bð 
Bð 
Bð 
Bð5 Sð 5¨Tð 5ð 5ð 5ð 5ð  Ð �5Ð Ð Ñ ð'˜uð 'ð 'ð 'ð 'ðT˜ð ¨$ð ð ð ð ð&kØðkà	ðkð ð	kð kð kð kðd#Ð ˜%ð ð ñ ðE =ð E°Tð Eð Eð Eð Eð4PØðPà	ðPð ð	Pð Pð Pð Pðh 26€	ˆ8�GÔ-Ô.Ð 5Ð 5Ñ 5Ø*.€ˆX�iÔ&Ô'Ð .Ð .Ñ .ð 	ˆ	ŒÑÔ€ð !€ˆT�#�s�(Œ^Ð  Ð  Ñ  ð˜cð ð ð ð ð4,ð ,ð ,ðð ð ð ð  Eð ð ð ð ðB #ð ð ð ð ð
ð 
ð 
ð˜$˜s D˜yœ/ð ð ð ð ðB ð ¨Tð °mð ð ð ð ð(~ Cð ~°Cð ~Àuð ~ð ~ð ~ð ~ðB6¨cð 6Àð 6ð 6ð 6ð 6ðr8¨Sð 8Àð 8ð 8ð 8ð 8ðv;¨Cð ;¸uð ;ð ;ð ;ð ;ð|C¨#ð C¸Uð Cð Cð Cð CðL ð ð ð ð ðV¨¨t©ð V¸ð Vð Vð Vð Vðr; sð ;¨sð ;ð ;ð ;ð ;ð Sð °tð ð ð ð ð*F¨ð F°°T´
ð Fð Fð Fð FðR	 #ð 	¨cð 	°c¸#´hð 	ð 	ð 	ð 	ðð ˜#ð ¨ð ¸ð ð ð ð ð" 'Ø$Ø"Øð	ð Ð ð¨ð °mð ÈTð ÐVZÐ[_ÔV`ð ð ð ð ð:
˜d 3œið 
ð 
ð 
ð 
ði ð i¨mð iÀTð iÈdÐSVÌið ið ið ið iðX¨cð ¸4ð ÀDÈÄIð ð ð ð ð:J" $ s¨D y¤/ð J"°d¸3´ið J"ð J"ð J"ð J"ðZ.˜D œIð .ð .ð .ð .ðb%˜˜Tœ
ð %ð %ð %ð %ðP?  S¨$¨u¬+Ð%5Ô 6ð ?ð ?ð ?ð ?ðD%ð %ð %ðP+ð +ð +ð +ð\&ð &ð &ð &ð &sÆ   ÂE ÂB' Â&E Â'B1Â.E Â0B1Â1E Â5B> Â=E Â>CÃE ÃCÃE ÃC ÃE ÃC0Ã-E Ã/C0Ã0E Ã4D	 ÄE Ä	D&Ä#E Ä%D&Ä&E Ä*D9 Ä8E Ä9EÅE ÅEÅE ÅE7Å6E7