+
    Q(i.                     F   R t ^ RIt^ RIt^ RIt^ RIHt ^ RIHt ^ RIH	t	 ^ RI
t
^ RIHt ^ RIHtHtHtHt ^ RIHt ]! R4      t]! R	R
7       ! R R4      4       tR R ltR R ltR R ltR R ltR R ltR R ltR R ltR R ltR R ltR#R R  lltR#R! R" llt R# )$a\  Discover MCP servers configured in editor config files.

Scans filesystem-readable config files from editors like Claude Desktop,
Claude Code, Cursor, Gemini CLI, and Goose, as well as project-level
``mcp.json`` files. Each discovered server can be resolved by name
(or ``source:name``) so the CLI can connect without requiring a URL
or file path.
N)	dataclass)Path)Any)ClientTransport)	MCPConfigMCPServerTypesRemoteMCPServerStdioMCPServer)
get_loggerzcli.discoveryT)frozenc                   h   a  ] tR t^$t o Rt]V 3R lR l4       t]V 3R lR l4       tV 3R ltRt	V t
R# )	DiscoveredServerz9A single MCP server found in an editor or project config.c                    < V ^8  d   QhRS[ /#    returnstr)format__classdict__s   "[/Users/agent/.openclaw/workspace/venv/lib/python3.14/site-packages/fastmcp/cli/discovery.py__annotate__DiscoveredServer.__annotate__.   s     , , ,    c                8    V P                    RV P                   2# )z+Fully qualified ``source:name`` identifier.:)sourcename)selfs   &r   qualified_nameDiscoveredServer.qualified_name-   s     ++a		{++r   c                    < V ^8  d   QhRS[ /# r   r   )r   r   s   "r   r   r   3   s     	' 	'3 	'r   c                V   V P                   p\        V\        4      '       d.   VP                  .VP                  OpRRP                  V4       2# \        V\        4      '       d(   VP                  ;'       g    RpV RVP                   2# \        \        V4      P                  4      # )z2Human-readable one-liner describing the transport.zstdio:  httpz: )config
isinstancer	   commandargsjoinr   	transporturlr   type__name__)r   cfgpartsr*   s   &   r   transport_summary"DiscoveredServer.transport_summary2   s     kkc>**[[,388,ESXXe_-..c?++//I[377),,49%%&&r   c                J   < V ^8  d   Qh/ S[ ;R&   S[ ;R&   S[;R&   S[;R&   # )r   r   r   r%   config_path)r   r   r   )r   r   s   "r   r   r   $   s7      I	 
 K     r    N)r-   
__module____qualname____firstlineno____doc__propertyr   r0   __annotate_func____static_attributes____classdictcell__)r   s   @r   r   r   $   s7     C , , 	' 	'  r   r   c                t    V ^8  d   QhR\         \        \        3,          R\         \        \        3,          /# )r   entryr   )dictr   r   )r   s   "r   r   r   D   s*      4S> d38n r   c                    RV 9   d   RV 9  d   / V CRV R,          /Cp V R RV 9   dH   RV 9   dA   RV 9  d:   V R,          pV P                  4        UUu/ uF  w  r#VR8w  g   K  W#bK  	  p ppWR&   V # u uppi )zNormalize editor-specific server config fields to MCPConfig format.

Handles two known differences:
- Claude Code uses ``type`` where MCPConfig uses ``transport`` for
  remote servers.
- Gemini CLI uses ``httpUrl`` where MCPConfig uses ``url``.
httpUrlr+   r,   r*   )items)r>   r*   kvs   &   r   _normalize_server_entryrE   D   s     Ee50252%y!12) ~&E/k.F&M	"'++-?-$!1;-?&kL @s   A1"A1c          	          V ^8  d   QhR\         \        \        3,          R\        R\        R\        \
        ,          /# )r   servers_dictr   r3   r   )r?   r   r   r   listr   )r   s   "r   r   r   Z   s@      sCx.  	
 

r   c                  V '       g   . # V P                  4        UUu/ uF)  w  r4\        V\        4      '       g   K  V\        V4      bK+  	  ppp \        P
                  ! RV/4      pTP                  P                  4        UUu. uF  w  r8\        Y1YR7      NK  	  upp# u uppi   \         d#   p\        P                  RY'4       . u Rp?# Rp?ii ; iu uppi )z;Parse an ``mcpServers``-style dict into discovered servers.
mcpServersz'Could not parse MCP servers from %s: %sN)r   r   r%   r3   )rB   r&   r?   rE   r   	from_dict	ExceptionloggerwarningrJ   r   )	rG   r   r3   r   r>   
normalizedr%   excservers	   &$$      r   _parse_mcp_serversrR   Z   s     	 (--//KDeT" 	-%e,,/  $$lJ%?@ #--335	 6LD 	V	
 6	   @+S	s.   B"B"B( C(C3C
CCc                R    V ^8  d   QhR\         R\        R\        \        ,          /# )r   pathr   r   )r   r   rH   r   )r   s   "r   r   r   x   s,     S SD S# S$7G2H Sr   c                    V P                  4       p \        P
                  ! T4      p\        T\        4      '       d   RT9  d   . # \        TR,          YR7      #   \         d#   p\        P                  RY4       . u Rp?# Rp?ii ; i  \        P                   d#   p\        P                  RY4       . u Rp?# Rp?ii ; i)z<Parse an mcpServers-style JSON file into discovered servers.zCould not read %s: %sNInvalid JSON in %s: %srJ   r   r3   )	read_textOSErrorrM   debugjsonloadsJSONDecodeErrorrN   r&   r?   rR   )rT   r   textrP   datas   &&   r   _parse_mcp_configr`   x   s    ~~
#zz$/
 dD!!\%=	d<0RR  ,d8	  /;	s:   A B B	'B>B	B	C!B>8C>Cc                :    V ^8  d   QhR\         \        ,          /# r   rH   r   )r   s   "r   r   r      s     5 5d#34 5r   c                    \         P                  R8X  d#   \        \        P                  ! 4       RRR4      p M\         P                  R8X  d#   \        \        P                  ! 4       RRR4      p Ml\         P                  P	                  R4      '       dF   \        \
        P                  P                  R	\        P                  ! 4       R
,          4      R4      p M. # V R,          p\        VR4      # )z$Scan the Claude Desktop config file.win32AppDataRoamingClaudedarwinLibraryzApplication SupportlinuxXDG_CONFIG_HOME.configzclaude_desktop_config.jsonzclaude-desktop)	sysplatformr   home
startswithosenvirongetr`   )
config_dirrT   s     r   _scan_claude_desktopru      s    
||w$))+y)XF
		!$))+y2GR
		 	 	)	)JJNN,diikI.EF

 	44DT#344r   c                F    V ^8  d   QhR\         R\        \        ,          /# r   	start_dirr   r   rH   r   )r   s   "r   r   r      s      , , ,$/?*@ ,r   c                ^   \         P                  ! 4       R,          p VP                  4       p \        P
                  ! T4      p\        T\        4      '       g   . # . pTP                  R4      ;p'       d4   \        T\        4      '       d   TP                  \        TRTR7      4       \        T P                  4       4      pTP                  R/ 4      p\        T\        4      '       du   TP                  T/ 4      p	\        T	\        4      '       dM   T	P                  R4      ;p
'       d4   \        T
\        4      '       d   TP                  \        T
RTR7      4       T#   \         d    . u # i ; i  \        P                   d#   p\        P                  RY4       . u Rp?# Rp?ii ; i)zBScan ``~/.claude.json`` for global and project-scoped MCP servers.z.claude.jsonrV   NrJ   zclaude-coderW   projects)r   ro   rX   rY   r[   r\   r]   rM   rN   r&   r?   rs   extendrR   r   resolve)rx   rT   r^   r_   rP   resultsglobal_serversresolved_dirr{   project_dataproject_serverss   &          r   _scan_claude_coder      se   99;'D~~#zz$/
 dD!!	&(G ,//~/nd++NN""=d y((*+Lxx
B'H(D!!||L"5lD))"."2"2<"@@@ot44NN*+#0(, NO  	
  /;	s.   E" E5 "E21E25F,
F'!F,'F,c                F    V ^8  d   QhR\         R\        \        ,          /# rw   ry   )r   s   "r   r   r      s       d t4D/E r   c                   V P                  4       p\        P                  ! 4       P                  4       p VR,          R,          pVP                  4       '       d   \	        VR4      # VP
                  pWA8X  g   W8X  d    . # TpKR  )z:Walk up from *start_dir* looking for ``.cursor/mcp.json``.z.cursormcp.jsoncursor)r}   r   ro   is_filer`   parent)rx   currentro   	candidater   s   &    r   _scan_cursor_workspacer      sv    !G99; D
i'*4	$Y99 I r   c                F    V ^8  d   QhR\         R\        \        ,          /# rw   ry   )r   s   "r   r   r      s       d t4D/E r   c                x    V P                  4       R,          pVP                  4       '       d   \        VR4      # . # )z&Check for ``mcp.json`` in *start_dir*.r   project)r}   r   r`   )rx   r   s   & r   _scan_project_mcp_jsonr      s6    !!#j0I I66Ir   c                F    V ^8  d   QhR\         R\        \        ,          /# rw   ry   )r   s   "r   r   r      s       D T*:%; r   c                   . p\         P                  ! 4       R,          R,          pVP                  \        VR4      4       V P	                  4       R,          R,          pW28w  d   VP                  \        VR4      4       V# )zScan Gemini CLI settings for MCP servers.

Checks both user-level ``~/.gemini/settings.json`` and project-level
``.gemini/settings.json``.
z.geminizsettings.jsongemini)r   ro   r|   r`   r}   )rx   r~   	user_pathproject_paths   &   r   _scan_geminir      sm     ')G 		i'/9INN$Y9: $$&2_DL (x@ANr   c                :    V ^8  d   QhR\         \        ,          /# r   rb   )r   s   "r   r   r      s     7I 7IT*+ 7Ir   c            
     n   \         P                  R8X  dO   \        \        P                  P                  R\        P                  ! 4       R,          R,          4      RRR4      p MD\        \        P                  P                  R\        P                  ! 4       R	,          4      R4      p V R
,          p VP                  4       p \        P                  ! T4      p\        T\        4      '       g   . # TP                  R/ 4      p\        T\        4      '       g   . # / pTP!                  4        F  w  rx\        T\        4      '       g   K  TP                  RR4      '       g   K7  TP                  RR4      p	T	R8X  d;   RT9   d4   RTR,          RTP                  R. 4      RTP                  R/ 4      /Yg&   K  T	R8X  g   K  RT9   g   K  RTR,          RR/Yg&   K  	  \#        TRTR7      #   \         d    . u # i ; i  \        P                   d#   p\        P                  RY4       . u Rp?# Rp?ii ; i)u   Scan Goose config for MCP server extensions.

Goose uses YAML (``~/.config/goose/config.yaml``) with a different
schema — MCP servers are defined as ``extensions`` with ``type: stdio``.
rd   APPDATAre   rf   Blockgooser%   rk   rl   zconfig.yamlzInvalid YAML in %s: %sN
extensionsenabledTr,    stdiocmdr'   r(   envenvssseurir+   r*   rW   )rm   rn   r   rq   rr   rs   ro   rX   rY   yaml	safe_load	YAMLErrorrM   rN   r&   r?   rB   rR   )
rt   rT   r^   r_   rP   r   serversr   extext_types
             r   _scan_gooser      s    ||wJJNN9diikI&=	&IJ	

 JJNN,diikI.EF


 %D~~~~d#
 dD!!	,+Jj$''	 !G%%'	#t$$wwy$''7762&w5C<3u:+swwvr*GM
 5C<"CJUCGM ( gg4HHC  	
 >> /;	s0   2G* G= *G:9G:=H4H/)H4/H4c                T    V ^8  d   QhR\         R,          R\        \        ,          /# )r   rx   Nr   ry   )r   s   "r   r   r   :  s$      t t<L7M r   c                |   T ;'       g    \         P                  ! 4       p. pVP                  \        4       4       VP                  \	        V4      4       VP                  \        V4      4       VP                  \        V4      4       VP                  \        4       4       VP                  \        V4      4       V# )u   Run all scanners and return the combined results.

Duplicate names across sources are preserved — callers can
use :pyattr:`DiscoveredServer.qualified_name` to disambiguate.
)	r   cwdr|   ru   r   r   r   r   r   )rx   r   r~   s   &  r   discover_serversr   :  s     
!
!txxzC&(GNN')*NN$S)*NN)#./NN<$%NN;=!NN)#./Nr   c                J    V ^8  d   QhR\         R\        R,          R\        /# )r   r   rx   Nr   )r   r   r   )r   s   "r   r   r   K  s%     , ,s ,td{ ,o ,r   c                8   \        V4      pRV 9   d   V P                  R^4      w  r4V Uu. uF*  qUP                  V8X  g   K  VP                  V8X  g   K(  VNK,  	  ppV'       g   \	        RV RV R24      hV^ ,          P
                  P                  4       # V Uu. uF  qUP                  V 8X  g   K  VNK  	  ppV'       gq   V'       dE   RP                  \        V Uu0 uF  qUP                  kK  	  up4      4      p\	        RV  RV 24      h. ROp\	        RV  RRP                  V4       24      h\        V4      ^8X  d"   V^ ,          P
                  P                  4       # RP                  R V 4       4      p	\	        R	V  R
V	 24      hu upi u upi u upi )zResolve a server name (or ``source:name``) to a transport.

Raises :class:`ValueError` when the name is not found or is ambiguous.
r   zNo server named 'z' found in source 'z'.z, z' found. Available: z' found. Searched: c              3   B   "   T F  pR VP                    R 2x  K  	  R# 5i)'N)r   ).0ms   & r   	<genexpr>resolve_name.<locals>.<genexpr>s  s      Fgq!1!1 2!4gs   zAmbiguous server name 'u7   ' — found in multiple sources. Use a qualified name: )zClaude Desktop configz~/.claude.json (Claude Code)z%.cursor/mcp.json (walked up from cwd)z$~/.gemini/settings.json (Gemini CLI)z#~/.config/goose/config.yaml (Goose)z
./mcp.json)
r   splitr   r   
ValueErrorr%   to_transportr)   sortedlen)
r   rx   r   r   server_namesmatches	available	locationsalternativess
   &&        r   resolve_namer   K  s   
 y)G d{"jja0%VgV);1+@U11gV#K=0CF82N  qz  --// "4'QVVt^qq'G4		&')B'Q&&')B"CDI06J9+VWW
	 v%899M8NO
 	
 7|qqz  --// 99FgFFL

!$ (!!-	0 ? W 5 *Cs#   FFFF3FF)N)!r8   r[   rq   rm   dataclassesr   pathlibr   typingr   r   fastmcp.client.transports.baser   fastmcp.mcp_configr   r   r   r	   fastmcp.utilities.loggingr
   rM   r   rE   rR   r`   ru   r   r   r   r   r   r   r   r4   r   r   <module>r      s     	 
 !    :  1	O	$ $' ' '>,<S(5",^&(7I~", ,r   