+
    jHàj×[  ã                   ób  € R t ^ RIt^ RIt^ RIHt ^ RIt^ RIt^ RIt^ RIt^ RI	H
t
HtHt ^ RIHtHtHt ^ RIHt ^ RIHt ^ RIHtHtHt ^ RIHtHtHtHt ^ R	IHtH t H!t!H"t"H#t#H$t%H&t& ]! 4       t']! R
R4      t(]! R4      t)]! RR4      t*]! RR4      t+]! RR4      t,]! RR4      t-]P\                  ! 4       t/R@t0^t1]R R l4       t2R R lt3R R lt4R R lt5R R lt6]'Po                  R4      RAR R ll4       t8]'Ps                  R4      RAR  R! ll4       t:]'Pw                  R4      RAR" R# ll4       t<]'P{                  R$4      RAR% R& ll4       t>]'Ps                  R'4      RAR( R) ll4       t?]'Ps                  R*4      RAR+ R, ll4       t@]'Po                  R-4      R. R/ l4       tA]'P{                  R-4      R0 R1 l4       tB]'Po                  R24      RBR3 R4 ll4       tC]'Pw                  R54      RAR6 R7 ll4       tDR8 R9 ltE]'Po                  R:4      RAR; R< ll4       tF]'Ps                  R=4      RAR> R? ll4       tGR# )Cuô   MCP dashboard routes.

The OAuth flow registry (``_mcp_oauth_flows``) and the worker/helpers stay in
web_server â€” reached via the late-binding seam so tests that mutate
``web_server._mcp_oauth_flows`` or monkeypatch its helpers keep working.
N)Úcontextmanager)ÚAnyÚDictÚOptional)Ú	APIRouterÚHTTPExceptionÚRequest)ÚHTMLResponse)Úlate)Ú_mcp_oauth_flowsÚ_mcp_server_summaryÚ_normalize_mcp_server_create)ÚMCPCatalogInstallÚMCPEnabledToggleÚMCPServerCreateÚMCPServersReplace)Ú_profile_cli_argsÚ_profile_scopeÚ_spawn_hermes_actionÚconfig_write_scopeÚhttp_failureÚlogÚscoped_to_threadÚ_config_profile_scopezhermes_cli.web_server_profilesÚ_require_tokenÚ_run_dashboard_mcp_oauthzhermes_cli.web_server_mcpÚload_configzhermes_cli.configÚsave_configÚsave_env_valuec                ó:   € V ^8„  d   QhR\         \        ,          /# ©é   Úprofile©r   Ústr)Úformats   "Ú?/home/ubuntu/.hermes/hermes-agent/hermes_cli/web_routers/mcp.pyÚ__annotate__r'   +   s   € ÷ ñ ¤8¬C¥=ñ ó    c              #  óv   "  € \        V 4      ;_uu_ 4        Rx € RRR4       R#   + '       g   i     R# ; i5i)a  Home + secret scope for a probe-class request (#109901). ``_config_profile_scope`` now binds
the secret scope itself; this stays the probe/OAuth callers' name. Home-only, NOT
``_profile_scope``: the body can block for seconds and the latter holds the process-global
skills lock.N)r   )r"   s   &r&   Ú_profile_secret_scoper*   *   s#   é € ô 
˜w×	'Õ	'Û÷ 
(×	'×	'Ò	'üs   ‚9–%›
9¥6	°	9c                ó:   € V ^8„  d   QhR\         \        ,          /# r    r#   )r%   s   "r&   r'   r'   4   s   € ÷ ñ œH¤S�Mñ r(   c                 ó   a a€ VV 3R  lpV# )c                  óv   <€ \        S4      ;_uu_ 4        S ! 4       uuR R R 4       #   + '       g   i     R # ; i©N)r*   )Úfnr"   s   €€r&   Ú_runÚ_secret_scoped.<locals>._run5   s"   ø€ Ü" 7×+Õ+Ù“4÷ ,×+×+Ó+ús   •'§8	© )r"   r/   r0   s   ff r&   Ú_secret_scopedr3   4   s   ù€ öð €Kr(   c                ó   € V ^8„  d   QhRR/# )r!   ÚreturnNr2   )r%   s   "r&   r'   r'   ;   s   € ÷ 0ñ 0˜Tñ 0r(   c                  ó`  € \         P                   ! 4       \        ,
          p \        ;_uu_ 4        \        P                  ! 4        UUu. uF  w  r\        VR ^ 4      V 8  g   K  VNK  	  pppV F  p\        P                  ! VR4       K  	  RRR4       R# u uppi   + '       g   i     R# ; i)Ú
created_atN)ÚtimeÚ_MCP_DASHBOARD_OAUTH_TTLÚ_mcp_oauth_flows_lockr   ÚitemsÚgetattrÚpop)ÚcutoffÚfidÚflowÚstaleÚflow_ids        r&   Ú_gc_mcp_oauth_flowsrC   ;   s€   € Ü�YŠY‹[Ô3Õ3€Fß	Ö	Ü&6×&<Ò&<Ô&>ÔjÑ&>™˜Ä'È$ÐP\Ð^_ÓB`ÐciÑBi—�Ñ&>ˆÑjÛˆGÜ× Ò  ¨$Ö/ñ ÷ 
Ñ	ùÛj÷ 
×	Ð	ús#   ¯BÁB
Á#B
Á)#BÂBÂB-	c                ó<   € V ^8„  d   QhR\         R\        R\        /# )r!   ÚrequestÚserver_namer5   )r   r$   )r%   s   "r&   r'   r'   C   s&   € ÷ añ a¤Wð a¼3ð aÄ3ñ ar(   c           	     óî   € ^ RI HpHpHp ^ RIHpHp RV! VRR7       2pV! 4       pV'       d   V V 2# V! \        V P                  4      4      p	V! V 4      p
V! V	P                  V
 V 2RRRR7      4      # )z7Externally reachable callback URL for a dashboard flow.)ÚquoteÚurlparseÚ
urlunparse)Úprefix_from_requestÚresolve_public_urlz/api/mcp/oauth/callback/Ú )Úsafe)ÚpathÚparamsÚqueryÚfragment)
Úurllib.parserH   rI   rJ   Ú hermes_cli.dashboard_auth.prefixrK   rL   r$   Úbase_urlÚ_replace)rE   rF   rH   rI   rJ   rK   rL   ÚsuffixÚ
public_urlÚbaseÚprefixs   &&         r&   Ú_mcp_oauth_callback_urlr[   C   s~   € ç8Ñ8çXà'©¨kÀÔ(CÐ'DÐE€FÙ#Ó%€JßØ�˜f˜XÐ&Ð&Ù”C˜×(Ñ(Ó)Ó*€DÙ  Ó)€FÙ�d—m‘m¨F¨8°F°8Ð)<ÀRÈrÐ\^�mÓ_Ó`Ð`r(   c                ó0   € V ^8„  d   QhR\         R\         /# )r!   Únamer5   ©r$   )r%   s   "r&   r'   r'   R   s   € ÷ 	ñ 	¤3ð 	¬3ñ 	r(   c                óL  € ^ RI Hp \        P                  ! RRV P	                  4       4      P                  R4      R,          ;'       g    Rp\        P                  ! V P                  4       4      P                  4       R,          pRV RV 2pVP                  VRV R	24       V# )
zÃUnique per-entry mcp-install action name (+ registered log file), so a
re-click or a second catalog install doesn't overwrite the first's tracked
process/log while its git clone is still running.)Ú_ACTION_LOG_FILESz
[^a-z0-9]+Ú-:Né0   NÚserver:Né   Nzmcp-install-zaction-z.log)Úhermes_cli.web_server_gatewayr`   ÚreÚsubÚlowerÚstripÚhashlibÚsha1ÚencodeÚ	hexdigestÚ
setdefault)r]   r`   ÚslugÚdigestÚactions   &    r&   Ú_mcp_install_action_namerr   R   sŠ   € õ @Ü�6Š6�-  d§j¡j£lÓ3×9Ñ9¸#Ó>¸sÕC×OÐOÀx€DÜ�\Š\˜$Ÿ+™+›-Ó(×2Ñ2Ó4°RÕ8€FØ˜D˜6  6 (Ð+€FØ× Ñ  ¨7°6°(¸$Ð)?Ô@Ø€Mr(   z/api/mcp/serversc                ó:   € V ^8„  d   QhR\         \        ,          /# r    r#   )r%   s   "r&   r'   r'   _   s   € ÷ ñ ¤H¬S¥Mñ r(   c              ƒ   ó  a"  € ^ RI Ho V3R lp\        P                  ! \	        W4      4      G Rj  x€L
 w  r#R\        VP                  4       4       UUu. uF  w  rE\        WEW4,          4      NK  	  upp/#  LEu uppi 5i)é    ©Ú_get_mcp_serversc                  ó.   <€ S! 4       p ^ RI Hp V! V 4      # ©ru   ©Úserver_configs_with_sources©Útui_gateway.mcp_rpc_helpersr{   ©Úconfig_serversr{   rw   s     €r&   Ú_readÚlist_mcp_servers.<locals>._readb   s   ø€ Ù)Ó+ˆÝKá*¨>Ó:Ð:r(   NÚservers)Úhermes_cli.mcp_configrw   ÚasyncioÚ	to_threadr3   Úsortedr;   r   )r"   r€   r‚   Úpluginsr]   Úcfgrw   s   &     @r&   Úlist_mcp_serversr‰   ^   sr   øé € å6õ;ô %×.Ò.¬~¸gÓ/MÓN×NÑ€GØÜGMÈgÏmÉmËoÔG^ôÙG^¹)¸$Ô˜D w¥}Ö5ÑG^òð ð ñ Oùóùs!   ƒ/B ²A8³#B ÁA:Á3B Á:B c                óF   € V ^8„  d   QhR\         R\        \        ,          /# ©r!   Úbodyr"   )r   r   r$   )r%   s   "r&   r'   r'   o   s   € ÷ .4ñ .4œð .4¼Ä#½ñ .4r(   c           	   ƒ   óØ  a aaaaaaa	a
a"  € ^ RI Ho
 ^ RIHoHoHo  \        S 4      w  o	ooR TTTTT T	TT3R lloTT T	TT
T3R lp \        P                  ! T4      G Rj  x€L
  \        S	S4      #   \         d   p\        R\        T4      R7      ThRp?ii ; i L:  \         d    h \         d3   p\        P                  ! R	4       \        R\        T4      R7      ThRp?ii ; i5i)
ru   )Úrecord_mcp_install)rw   Ú_save_bearer_auth_tokenÚ_save_mcp_serveré�  ©Ústatus_codeÚdetailNc                ó$   € V ^8„  d   QhR\         /# ©r!   r5   )Úbool)r%   s   "r&   r'   Ú$add_mcp_server.<locals>.__annotate__x   s   € ÷ 9ñ 9”4ñ 9r(   c            
      óz  <€ \        S	P                  ;'       g    S4      ;_uu_ 4        S! 4       p ^ RIHp V! V 4      w  r#VP	                  S
4      ;p'       d   \        RRS
 RV R2R7      hS
V9   d   \        RRS
 R2R7      hSe   S! S
S4      SR	&   S! S
S4      uuRRR4       #   + '       g   i     R# ; i)
ru   rz   é™  úServer 'ú' is provided by plugin 'ú' and cannot be modifiedr’   z' already existsNÚheaders)r   r"   r}   r{   Úgetr   )r   r{   r‚   r‡   Úpluginrw   r�   r�   Úbearer_tokenrŒ   r]   r"   Úserver_configs        €€€€€€€€r&   Ú_saveÚadd_mcp_server.<locals>._savex   s½   ø€ ô   §¡× 7Ð 7°×8Õ8Ù-Ó/ˆNÝOá:¸>ÓJÑˆGØ Ÿ™ TÓ*Ð*ˆvÖ*Ü#Ø #¨h°t°fÐ<UÐV\ÐU]Ð]uÐ,vôð ð �wŒÜ#°¸hÀtÀfÐL\Ð<]Ô^Ð^ØÒ'Ù+BÀ4ÈÓ+V�˜iÑ(Ù# D¨-Ó8÷ 9×8×8Ó8ús   ©A5B)Â)B:	c            	      ó@  <€ S! 4       p \        SP                  ;'       g    S4      ;_uu_ 4        S! SP                  R 4      '       d   R MRRV '       d   RMRV '       d   RMRR7       RRR4       V '       g   \        RRS R	2R
7      hR#   + '       g   i     L+; i)ÚurlÚlocalNÚsuccessÚfailedÚconfig_rejected)Úfailure_classr‘   r›   z1' rejected: suspicious command/args configurationr’   )r   r"   rŸ   r   )Úsavedr£   rŒ   r]   r"   rŽ   r¢   s    €€€€€€r&   r0   Úadd_mcp_server.<locals>._run‹   sƒ   ø€ Ù“ˆä˜DŸL™L×3Ð3¨G×4Õ4Ù¨×(9Ñ(9¸%×(@Ò(@™uÀgÈtß,1™y°x×W\ÉtÐbsõu÷ 5÷ ÜØ¨(°4°&Ð8iÐ(jôð ñ ÷ 5×4ús   °%BÁ
BÁ!	BÂB	zPOST /api/mcp/servers failed)Úhermes_cli.mcp_catalogrŽ   rƒ   rw   r�   r�   r   Ú
ValueErrorr   r$   r„   r…   Ú	ExceptionÚ_logÚ	exceptionr   )rŒ   r"   Úexcr0   rw   r£   r�   r�   r¡   r]   rŽ   r¢   s   ff  @@@@@@@@r&   Úadd_mcp_serverr´   n   sÎ   ÿùé € å9ßaÑaðGÜ,HÈÓ,NÑ)ˆˆm˜\÷9÷ 9÷&	ò 	ðGÜ×Ò Ó%×%Ð%ô ˜t ]Ó3Ð3øôQ ô GÜ¨´C¸³HÔ=À3ÐFûðGúñD 	&øÜô ØÜô GÜ�ŠÐ5Ô6Ü¨´C¸³HÔ=À3ÐFûðGüsc   ŒC*žA3 ­C*Á	B Á"BÁ#B Á'C*Á3BÁ>BÂBÂC*ÂB ÂC'Â4C'Â5-C"Ã"C'Ã'C*c                óF   € V ^8„  d   QhR\         R\        \        ,          /# r‹   )r   r   r$   )r%   s   "r&   r'   r'   ¡   s   € ÷ ñ Ô$5ð ÄÌÅñ r(   c              ƒ  óÀ   a aa"  € ^ RI Ho VV V3R lp\        P                  ! V4      G Rj  x€L
 w  r4V'       g   \	        RRP                  V4      R7      hRR/#  L.5i)	uÇ   Replace the entire ``mcp_servers`` map (the mcp.json editor's save) â€”
the deep-merging ``/api/config`` can never delete a key or drop an
``enabled: false``, so removals wouldn't persist through it.)Ú_replace_mcp_serversc            	      ó\  <€ \        SP                  ;'       g    S4      ;_uu_ 4        ^ RIHp  V ! / 4      w  rSP                   F4  pVP                  V4      ;p'       g   K  RRV RV R2.3u uuRRR4       # 	  S! SP                  4      uuRRR4       #   + '       g   i     R# ; i)ru   rz   Fr›   rœ   r�   N)r   r"   r}   r{   r‚   rŸ   )r{   Ú_serversr‡   r]   r    r·   rŒ   r"   s        €€€r&   r0   Ú!replace_mcp_servers.<locals>._run§   s“   ø€ Ü §¡× 7Ð 7°×8Õ8ÝOá ;¸BÓ ?ÑˆHØŸœ�Ø$Ÿ[™[¨Ó.Ð.�6×.Ð.Ø  X¨d¨VÐ3LÈVÈHÐTlÐ#mÐ"nÐnÑn÷ 9Ò8ñ %ñ (¨¯©Ó5÷ 9×8×8Ó8ús   ©6BÁ$BÁ<BÂB+	Nr‘   z; r’   ÚokT)rƒ   r·   r„   r…   r   Újoin)rŒ   r"   r0   r»   Úissuesr·   s   ff   @r&   Úreplace_mcp_serversr¾       sO   úé € õ
 ;÷6ô ×(Ò(¨Ó.×.�J€BßÜ¨°D·I±I¸fÓ4EÔFÐFØ�$ˆ<Ðñ /ùs   …(A­A®/Az/api/mcp/servers/{name}c                óF   € V ^8„  d   QhR\         R\        \         ,          /# ©r!   r]   r"   ©r$   r   )r%   s   "r&   r'   r'   ¸   s   € ÷ ñ ¤#ð ´¼µñ r(   c              ƒ   óª   a aaa"  € ^ RI HoHo VVV V3R lp\        P                  ! V4      G Rj  x€L
 '       g   \        RRS  R2R7      hRR	/#  L5i)
ru   )rw   Ú_remove_mcp_serverc            
      ó   <€ \        S4      ;_uu_ 4        S! 4       p ^ RIHp V! V 4      w  r#VP                  S4      ;p'       d   \	        RRS RV R2R7      hS! S4      uuRRR4       #   + '       g   i     R# ; i)ru   rz   rš   r›   rœ   r�   r’   N)r   r}   r{   rŸ   r   )	r   r{   r¹   r‡   r    rw   rÃ   r]   r"   s	        €€€€r&   r0   Úremove_mcp_server.<locals>._run»   sx   ø€ Ü ×(Õ(Ù-Ó/ˆNÝOá ;¸NÓ KÑˆHØ Ÿ™ TÓ*Ð*ˆvÖ*Ü#Ø #¨h°t°fÐ<UÐV\ÐU]Ð]uÐ,vôð ñ & dÓ+÷ )×(×(Ó(ús   •AA,Á,A=	Né”  r›   ú' not foundr’   r»   T)rƒ   rw   rÃ   r„   r…   r   )r]   r"   r0   rw   rÃ   s   ff @@r&   Úremove_mcp_serverrÈ   ·   sN   ûé € çJ÷
,ð 
,ô ×"Ò" 4Ó(×(Ö(Ü¨°h¸t¸fÀKÐ4PÔQÐQØ�$ˆ<Ðñ )ùs   †+A±A²	A¼Az/api/mcp/servers/{name}/testc                óF   € V ^8„  d   QhR\         R\        \         ,          /# rÀ   rÁ   )r%   s   "r&   r'   r'   Í   s   € ÷ .ñ .¤ð .¬h´s­mñ .r(   c              ƒ  ó  a aaaaaa"  € ^ RI HoHoHo V3R lp\        P
                  ! \        W4      4      G Rj  x€L
 oS S9  d   \        RRS  R2R7      h/ oSS ,          P                  R4      R	8H  oVVVV VV3R
 lp \        P
                  ! \        W4      4      G Rj  x€L
 w  rET'       g	   RRRRR. /# SP                  R4      ;'       g    / pRRRT U	U
u. uF<  w  ršRT	RT
/\        TP                  T	4      \        4      '       d   RY‰,          /M/ CNK>  	  up
p	RSP                  R^ 4      RSP                  R^ 4      /#  EL L§  \         d   p^ RI H
p RRRT! T4      R. /u Rp?# Rp?ii ; iu up
p	i 5i)z2Connect to the server, list its tools, disconnect.)rw   Ú_oauth_tokens_presentÚ_probe_single_serverc                  ó<   <€ S! 4       p ^ RI Hp V! V 4      ^ ,          # ry   r|   r~   s     €r&   r€   Útest_mcp_server.<locals>._readÑ   s   ø€ Ù)Ó+ˆÝKá*¨>Ó:¸1Õ=Ð=r(   NrÆ   r›   rÇ   r’   ÚauthÚoauthc                  óR   <€ S! SSS,          SR 7      p T S'       d
   S! S4      3# R3# ))ÚdetailsTr2   )ÚtoolsrË   rÌ   rÒ   r]   Úneeds_oauth_tokenr‚   s    €€€€€€r&   Ú_probeÚtest_mcp_server.<locals>._probeà   s1   ø€ Ù$ T¨7°4­=À'ÔJˆØ×6GÑ,¨TÓ2ÐRÐRÈTÐRÐRr(   )Úredact_mcp_probe_textr»   FÚerrorrÓ   u1   OAuth authentication required â€” no token found.Úschema_charsTr]   ÚdescriptionÚpromptsÚ	resources)rƒ   rw   rË   rÌ   r„   r…   r3   r   rŸ   r°   r×   Ú
isinstanceÚint)r]   r"   r€   rÕ   rÓ   Útoken_presentr³   r×   rÙ   ÚtÚdrw   rË   rÌ   rÒ   rÔ   r‚   s   f&         @@@@@@r&   Útest_mcp_serverrâ   Ì   sœ  þé € ÷ dÑcõ>ô ×%Ò%¤n°WÓ&DÓE×E€GØ�7ÔÜ¨°h¸t¸fÀKÐ4PÔQÐQà €Gð   �×)Ñ)¨&Ó1°WÑ<Ð÷Sò SðOÜ%,×%6Ò%6´~ÀgÓ7VÓ%W×WÑˆ÷
 Ø�e˜WÐ&YÐ[bÐdfÐgÐgð —;‘;˜~Ó.×4Ð4°"€LàˆdØñ ô
ñ ‘�ð	 ˜Ø˜qðô 9CÀ<×CSÑCSÐTUÓCVÔX[×8\Ò8\�N L¥OÑ4Ðbdóñ
 ò
ð 	�7—;‘;˜y¨!Ó,Ø�W—[‘[ ¨aÓ0ðð ò1 Fñ  XøÜô OÝ?à�e˜WÑ&;¸CÓ&@À'È2ÐNÕNûðOüó
ùsk   ‰3F ¼E	½AF Â"E Â$EÂ%E Â+F Â3F ÃF ÃAE:Ä *F ÅE ÅE7ÅE2Å,E7Å-F Å2E7Å7	F z/api/mcp/servers/{name}/authc                óR   € V ^8„  d   QhR\         R\        R\        \         ,          /# )r!   r]   rE   r"   )r$   r   r   )r%   s   "r&   r'   r'   ÿ   s%   € ÷ 7ñ 7¤ð 7¬gð 7ÄÌÅñ 7r(   c           
   ƒ  ó  a aaaaa"  € ^ RI Ho ^ RIHo ^ RIHpHp \        V4       \        4        R V3R lloS! 4       pVVV3R lp\        P                  ! V4      G Rj  x€L
 w  rxoS V9  d   \        RR	S  R
2R7      hVP                  S 4      ;p	'       d   \        RR	S  RV	 R2R7      h\        VS ,          4      p
V
P                  R4      '       g   \        RRR7      hV
P                  R4      '       d$   V
P                  R4      R8w  d   \        RRR7      hRV
R&   \        P                  ! ^4      pT! TS SSV
P                  R4      ;'       g    / P                  R4      ;'       g    \!        VS 4      SV8H  R7      p\"        ;_uu_ 4        \$        P&                  ! 4        Uu. uF  qÝP(                  '       d   K  VNK  	  pp\+        V4      \,        8¼  d   \        RRR7      h\.        ;QJ d     VV 3R lV 4       F  '       g   K   RM	  RM! VV 3R lV 4       4      '       d   \        RRS  R2R7      hV\$        V&   RRR4       \0        P2                  ! \4        WÊ3RRS  2R 7      P7                  4         VP9                  ^R!7      G Rj  x€L
  VP?                  4       #  ELKu upi   + '       g   i     Ls; i L/  \:         d1   pTP=                  T! T4      4        Rp?TP?                  4       # Rp?ii ; i5i)"zHStart MCP OAuth and hand the authorization URL to the dashboard browser.rv   ©Úget_hermes_home)ÚDashboardOAuthFlowÚexception_messagec                ó$   € V ^8„  d   QhR\         /# r–   r^   )r%   s   "r&   r'   Ú%auth_mcp_server.<locals>.__annotate__  s   € ÷ Iñ I”3ñ Ir(   c                  ó`   <€ \        S ! 4       P                  4       P                  R R7      4      # )F)Ústrict)r$   Ú
expanduserÚresolverå   s   €r&   Ú_homeÚauth_mcp_server.<locals>._home  s(   ø€ Ü‘?Ó$×/Ñ/Ó1×9Ñ9ÀÐ9ÓGÓHÐHr(   c                  ó¨   <€ \        S4      ;_uu_ 4        S! 4       p ^ RIHp V! V 4      w  r#W#S! 4       3uuRRR4       #   + '       g   i     R# ; i)ru   rz   N)r*   r}   r{   )r   r{   r‚   r‡   rw   rï   r"   s       €€€r&   r€   Úauth_mcp_server.<locals>._read  s?   ø€ Ü" 7×+Õ+Ù-Ó/ˆNÝOá:¸>ÓJÑˆGØ¡U£WÐ,÷ ,×+×+Ó+ús   • A Á A	NrÆ   r›   rÇ   r’   rš   rœ   r�   r¦   r‘   z2stdio servers authenticate via env keys, not OAuthrž   rÏ   rÐ   z/This server uses header/API-key auth, not OAuthÚredirect_uri)rB   rF   r"   Úhermes_homeró   Úreconnect_livei­  z0Too many MCP OAuth flows are already in progressc              3   ón   <"  € T F*  qP                   S8H  ;'       d    VP                  S8H  x € K,  	  R # 5ir.   )rF   rô   )Ú.0ÚfÚ	flow_homer]   s   & €€r&   Ú	<genexpr>Ú"auth_mcp_server.<locals>.<genexpr>.  s,   øé € ÐRÉTÈ�}‰} Ñ$×CÐC¨¯©¸)Ñ)CÔCËTùs   ƒ5�5TFzMCP OAuth for 'z' is already in progressz
mcp-oauth-)ÚtargetÚargsÚdaemonr]   )Útimeout) rƒ   rw   Úhermes_constantsræ   Útools.mcp_dashboard_oauthrç   rè   r   rC   r„   r…   r   rŸ   ÚdictÚsecretsÚtoken_urlsafer[   r:   r   ÚvaluesÚworker_doneÚlenÚ_MAX_PENDING_MCP_OAUTH_FLOWSÚanyÚ	threadingÚThreadr   ÚstartÚwait_for_authorization_urlr°   Ú
mark_errorÚsnapshot)r]   rE   r"   rç   rè   Úprocess_homer€   r‚   r‡   r    rˆ   rB   r@   rø   Úliver³   rw   rï   rù   ræ   s   f&f             @@@@r&   Úauth_mcp_serverr  þ   s“  ýé € õ 7Ý0ßOä�7ÔÜÔ÷Ið Iñ “7€L÷-ô )0×(9Ò(9¸%Ó(@×"@Ñ€G�iØ�7ÔÜ¨°h¸t¸fÀKÐ4PÔQÐQØ—‘˜TÓ"Ð"€vÖ"Ü¨°h¸t¸fÐD]Ð^dÐ]eÐe}Ð4~ÔÐÜ
ˆw�t�}Ó
€CØ�7‰7�5�>Š>Ü¨Ð4hÔiÐiØ
‡w�wˆy×Ò˜cŸg™g f›o°Ô8Ü¨Ð4eÔfÐfØ€Cˆ�Kä×#Ò# BÓ'€GÙØØØØØ—g‘g˜gÓ&×,Ð,¨"×1Ñ1°.ÓA×kÐkÔE\Ð]dÐfjÓEkØ  LÑ0ô€D÷ 
Ö	Ü+×2Ò2Ô4ÓJÑ4�a¿M½M—�Ñ4ˆÐJÜˆt‹9Ô4Ô4Ü¨CÐ8jÔkÐkß‹3ÕRÉTÓR�3�3Š3ÕRÉTÓR×RÒRÜ¨C¸/È$ÈÐOgÐ8hÔiÐiØ$(Ô˜Ñ!÷ 
ô ×ÒÔ4¸D¸;ÈtÐ\fÐgkÐflÐZmÔn×tÑtÔvð0Ø×-Ñ-°bÐ-Ó9×9Ð9ð �=‰=‹?ÐòC #Aùò, K÷ 
×	úñ 	:øÜô 0Ø�‰Ñ)¨#Ó.×/Ð/Ø�=‰=‹?Ðûð0üsª   ˆAL	Á#J.Á$7L	ÂA L	Ã=AL	ÅL	Å2$L	ÆJ6Æ.J1ÇJ1Ç-J6Ç:J6ÈJ6È1J6É8L	ÊK ÊK	ÊK ÊL	Ê1J6Ê6K	ËL	Ë	K ËLËLË-L	ÌLÌL	z/api/mcp/oauth/flows/{flow_id}c                ó0   € V ^8„  d   QhR\         R\        /# ©r!   rB   rE   ©r$   r   )r%   s   "r&   r'   r'   :  s   € ÷ ñ ¬ð ´wñ r(   c              ƒ   óÄ   "  € \        V4       \        4        \        P                  ! V 4      pVf   \	        RRR7      hVP                  4       pVP                  VR&   V# 5i)NrÆ   zOAuth flow not found or expiredr’   rÓ   )r   rC   r   rŸ   r   r  rÓ   )rB   rE   r@   r  s   &&  r&   Úmcp_oauth_flow_statusr  9  sT   é € ä�7ÔÜÔÜ×Ò Ó(€DØ‚|Ü¨Ð4UÔVÐVØ�}‰}‹€HØŸ
™
€HˆWÑØ€Oùs   ‚AA c                ó0   € V ^8„  d   QhR\         R\        /# r  r  )r%   s   "r&   r'   r'   F  s   € ÷ 
=ñ 
=¬ð 
=´wñ 
=r(   c              ƒ  ó¼   "  € \        V4       \        P                  ! V 4      pVf   RRRR/# VP                  RRR7       RRRVP	                  4       R,          /# 5i)u  Cancel an in-flight flow. mark_error unblocks the worker so it frees the
per-server "already in progress" slot â€” otherwise a renderer that stops
polling leaves the flow squatting until the 300s callback timeout and every
retry 409s. Idempotent: a settled flow is left as-is.r»   TÚstatusÚexpiredzCancelled by user)Ú	cancelled)r   r   rŸ   r  r  )rB   rE   r@   s   && r&   Úcancel_mcp_oauth_flowr  E  s^   é € ô �7ÔÜ×Ò Ó(€DØ‚|Ø�d˜H iÐ0Ð0Ø‡O�OÐ'°4€OÔ8Ø�$˜ $§-¡-£/°(Õ";Ð<Ð<ùs   ‚AAz*/api/mcp/oauth/callback/{server_name:path}c                ó¬   € V ^8„  d   QhR\         R\        \         ,          R\        \         ,          R\        \         ,          R\        \         ,          /# )r!   rF   ÚcodeÚstaterØ   ÚissrÁ   )r%   s   "r&   r'   r'   T  sQ   € ÷ nñ nÜðnä
”3�-ðnô ”C�=ðnô ”C�=ð	nô
 
”#�ñnr(   c              ƒ   ó8  a"  € \        4        \        ;_uu_ 4        \        P                  ! 4        Uu. uF+  pVP                  V 8X  g   K  VP
                  R 8X  g   K)  VNK-  	  ppRRR4       \        V3R lX 4       R4      pVf   \        RRR7      #  VP                  VSW4R7       T'       d   \        RR
R7      # \        R4      # u upi   + '       g   i     Lq; i  \         d*   p\        RR\        T4      9   d   R	MR
R7      u Rp?# Rp?ii ; i5i)Úauthorization_requiredNc              3   ó¦   <"  € T FF  pVP                   f   K  Sf   K  \        P                  ! VP                   S4      '       g   KB  Vx € KH  	  R # 5ir.   )Úexpected_stater  Úcompare_digest)r÷   Úcr   s   & €r&   rú   Ú%mcp_oauth_callback.<locals>.<genexpr>b  sG   øé € ð 	t‘JˆqØ×Ñô 
Ø-2ô 
ÜCJ×CYÒCYÐZ[×ZjÑZjÐlq×Cr÷ 
Š“Jùs   ƒA˜Až$AÁ
AzA<h1>OAuth flow expired</h1><p>Return to Hermes and try again.</p>rÆ   )r“   )r  r   rØ   r!  zP<h1>OAuth callback rejected</h1><p>The callback was invalid or already used.</p>zalready receivedrš   r‘   zA<h1>Authorization failed</h1><p>Return to Hermes for details.</p>zR<h1>Authorization received</h1><p>You can close this tab and return to Hermes.</p>)rC   r:   r   r  rF   r  Únextr	   Údeliver_callbackr¯   r$   )rF   r  r   rØ   r!  r@   Ú
candidatesr³   s   &&f&&   r&   Úmcp_oauth_callbackr,  S  s  øé € ô Ôß	Ö	ä-×4Ò4Ô6ó
Ù6�TØ×Ñ ;Ñ.ô Ø37·;±;ÐBZÑ3Z÷ ˆDÑ6ð 	ð 
÷ 
ô
 ô	t‘Jó 	tàó€Dð
 ‚|ÜÐ_ÐmpÔqÐqð
Ø×Ñ 4¨u¸EÐÔK÷ ÜÐ_ÐmpÔqÐqÜÐlÓmÐmùò)
÷ 
×	ûô ô 
ÜØ^Ø1´S¸³XÔ=™À3ô
õ 	
ûð
üso   ƒDœC´CÁCÁCÁ%CÁ'/DÂC# Â+DÂ3DÃCÃC 	ÃDÃ#DÃ.DÄDÄDÄDÄDz/api/mcp/servers/{name}/enabledc                óR   € V ^8„  d   QhR\         R\        R\        \         ,          /# )r!   r]   rŒ   r"   )r$   r   r   )r%   s   "r&   r'   r'   u  s'   € ÷ )ñ )¤sð )Ô2Bð )ÌXÔVYÍ]ñ )r(   c              ƒ  ó`   a aa"  € VV V3R lp\         P                  ! V4      G Rj  x€L
 #  L5i)z†Toggle ``enabled`` (takes effect on next session/gateway); disabled
servers stay in config so they can be re-enabled without re-entry.c            
      ó¦  <€ \        SP                  ;'       g    S4      ;_uu_ 4        \        4       p ^ RIHp T! V P                  R4      ;'       g    / 4      w  r#VP                  S4      ;p'       d   \        RRS RV R2R7      hV P                  R4      p\        V\        4      '       d   SV9  d   \        RRS R	2R7      h\        VS,          \        4      '       g   \        R
RR7      h\        SP                  4      VS,          R&   \        V 4       RRR4       RRRSR\        SP                  4      /#   + '       g   i     L+; i)ru   rz   Úmcp_serversrš   r›   rœ   r�   r’   rÆ   rÇ   r‘   zMalformed server configÚenabledNr»   Tr]   )r   r"   r   r}   r{   rŸ   r   rÝ   r  r—   r1  r   )	rˆ   r{   r¹   r‡   r    r‚   rŒ   r]   r"   s	         €€€r&   r0   Ú$set_mcp_server_enabled.<locals>._runx  s   ø€ Ü §¡× 7Ð 7°×8Õ8Ü“-ˆCÝOá ;¸C¿G¹GÀMÓ<R×<XÐ<XÐVXÓ YÑˆHØ Ÿ™ TÓ*Ð*ˆvÖ*Ü#Ø #¨h°t°fÐ<UÐV\ÐU]Ð]uÐ,vôð ð —g‘g˜mÓ,ˆGÜ˜g¤t×,Ò,°¸GÔ0CÜ#°¸hÀtÀfÈKÐ<XÔYÐYÜ˜g d�m¬T×2Ò2Ü#°Ð<UÔVÐVÜ'+¨D¯L©LÓ'9ˆG�D�M˜)Ñ$Ü˜Ô÷ 9ð  �d˜F D¨)´T¸$¿,¹,Ó5GÐHÐH÷! 9×8ús   ©C4E Å E	N)r„   r…   )r]   rŒ   r"   r0   s   fff r&   Úset_mcp_server_enabledr3  t  s%   úé € ÷Iô& ×"Ò" 4Ó(×(Ð(Ñ(ùs   …".§,¨.c          
      ój   € V ^8„  d   QhR\         R\        R\        R\        \        \         3,          /# )r!   ÚentryÚ	installedr1  r5   )r   r—   r  r$   )r%   s   "r&   r'   r'   Ž  s1   € ÷ &ñ &œsð &¬tð &¼dð &ÄtÌCÔQTÈHÅ~ñ &r(   c                 ó®  € V P                   pV P                  pV P                  p/ R V P                  bRV P                  bRV P
                  bRV P                  bRVP                  bR\        VRR4      bR\        VR	. 4      ;'       g    .  Uu. uF)  pR VP                  R
VP                  RVP                  /NK+  	  upbRVP                  bR\        VP                  ;'       g    . 4      bRVP                  bRV'       d   VP                  MRbRV'       d   VP                  MRbRV'       d   \        VP                   4      M. bRV P"                  P$                  e    \        V P"                  P$                  4      MRbRV P&                  ;'       g    RbRV P(                  '       d˜   R\        V P(                  P*                  4      R\        V P(                  P,                  4      R\        \        V P(                  R. 4      4      R\        \        V P(                  R. 4      4      R\        V P(                  RR4      /MRbRVRJbRVRV/C# u upi ) r]   rÚ   Úconnector_slugÚsourceÚ	transportÚ	auth_typeÚtypeÚnoneÚrequired_envÚenvÚpromptÚrequiredÚcommandrý   r¦   Úinstall_urlNÚinstall_refÚ	bootstrapÚdefault_enabledÚpost_installrM   ÚsuggestÚkeywordsÚhostsÚapplicationsÚexamplesÚrequires_appFÚneeds_installr6  r1  )rÏ   r:  Úinstallr]   rÚ   r8  r9  r<  r<   r@  rA  rB  Úlistrý   r¦   ÚrefrE  rÓ   rF  rG  rH  rI  rJ  )r5  r6  r1  rÏ   r:  rO  Úes   &&&    r&   Ú_catalog_entry_jsonrS  Ž  sX  € Ø�:‰:€DØ—‘€IØ�m‰m€Gð"Ø�—
‘
ð"à�u×(Ñ(ð"ð 	˜%×.Ñ.ð"ð 	�%—,‘,ð	"ð
 	�Y—^‘^ð"ð 	”W˜T 6¨6Ó2ð"ð 	ä˜T 5¨"Ó-×3Ð3°Ð3ó
á3�ð �Q—V‘V˜X q§x¡x°¸Q¿Z¹ZÓHÙ3ñ
ð"ð 	�9×$Ñ$ð"ð 	”�Y—^‘^×)Ð) rÓ*ð"ð  	ˆy�}‰}ð!"ð$ 	§g�w—{’{°4ð%"ð& 	§g�w—{’{°4ð'"ð( 	·”T˜'×+Ñ+Ô,¸Rð)"ð* 	ÀÇÁ×@[Ñ@[Ò@gœ4 §¡× ;Ñ ;Ô<Ðmqð+"ð, 	˜×*Ñ*×0Ð0¨bð-"ð2 	ð
 �]�]ˆ]ð	 œ˜UŸ]™]×3Ñ3Ó4°g¼tÀEÇMÁM×DWÑDWÓ?XØœD¤¨¯©¸ÈÓ!KÓLØœœW U§]¡]°JÀÓCÓDØœG E§M¡M°>À5ÓIñ	
ð
 !%ð="ð> 	˜¨Ð,ð?"ð@ 	�YØ�7ñC"ð "ùò
s   Â/Iz/api/mcp/catalogc                ó:   € V ^8„  d   QhR\         \        ,          /# r    r#   )r%   s   "r&   r'   r'   ¸  s   € ÷ <ñ <¤H¬S¥Mñ <r(   c              ƒ  óV  a a"  € \        RRR4      ;_uu_ 4        ^ RIHo RRR4       . p VV 3R lp\        P                  ! V4      G Rj  x€L
 w  r4V F<  pVP                  VP                  R4      w  rgVP                  \        WVV4      4       K>  	  . p SP                  4        U	U
Uu. uF  w  ršpRT	R	T
R
T/NK  	  pp
p	pRTRT/#   + '       g   i     L±; i L�  \         d    h \         d    \        P                  ! R4        Lxi ; iu upp
p	i   \         d     Lai ; i5i)zƒBrowse the Nous-approved MCP catalog (optional-mcps/ manifests), each
entry annotated with installed/enabled state for ``profile``.zmcp_catalog import failedéô  zCatalog unavailable©Úmcp_catalogNc            
      óH  <€ \        S4      ;_uu_ 4        \        SP                  4       4      p V  Uu/ uFC  qP                  SP	                  VP                  4      SP                  VP                  4      3bKE  	  ppR R R 4       W3# u upi   + '       g   i     X X3# ; ir.   )r   rP  Úlist_catalogr]   Úis_installedÚ
is_enabled)ÚcatalogrR  r   rX  r"   s      €€r&   r€   Úlist_mcp_catalog.<locals>._readÀ  s�   ø€ Ü ×(Õ(Ü˜{×7Ñ7Ó9Ó:�ÙmtÓuÑmtÐhiŸ™ +×":Ñ":¸1¿6¹6Ó"BÀK×DZÑDZÐ[\×[aÑ[aÓDbÐ!cÒcÑmt�Ðu÷ )ð �>Ð!ùò v÷ )Ö(ð ˜E�>Ð!ús   •B³A	B	Á<BÂ	BÂB!	zlist_mcp_catalog failedr]   ÚkindÚmessageÚentriesÚdiagnostics)FF)r   Ú
hermes_clirX  r„   r…   rŸ   r]   ÚappendrS  r   r°   r±   r²   Úcatalog_diagnostics)r"   ra  r€   Úcatalog_entriesÚinstalled_stater5  r6  r1  rb  ÚnÚkÚmrX  s   f           @r&   Úlist_mcp_catalogrk  ·  s  ùé € ô 
Ð1°3Ð8M×	NÕ	NÝ*÷ 
Oð €Gð2ö	"ô 29×1BÒ1BÀ5Ó1I×+IÑ(ˆÛ$ˆEØ!0×!4Ñ!4°U·Z±ZÀÓ!PÑˆIØ�N‰NÔ.¨uÀÓIÖJñ %ð €KðØMX×MlÑMlÔMnÕoÑMnÁ	ÀÀq˜  6¨1¨i¸Ó;ÑMnˆÒoð �w ¨{Ð;Ð;÷3 
O×	Núñ ,Jøô ô ØÜô 2Ü�ŠÐ0Ö1ð2üô
 pøÜô Ùðüs�   „D)šC
¡
D)¬ C ÁCÁAC ÂD)ÂD Â,DÃ D ÃD)Ã
C	ÃD)ÃC ÃDÃ4DÄD)ÄDÄD)ÄD ÄD&Ä#D)Ä%D&Ä&D)z/api/mcp/catalog/installc                óF   € V ^8„  d   QhR\         R\        \        ,          /# r‹   )r   r   r$   )r%   s   "r&   r'   r'   Ø  s#   € ÷ B;ñ B;Ô*;ð B;ÄhÌsÅmñ B;r(   c           	   ƒ  óÂ  a aaa"  € ^ RI Ho ^ RIHp S P                  ;'       g    RP                  4       pSP                  V4      oSf   \        RRV R2R7      hSP                  P                  ;'       g    .  Uu0 uF  qDP                  kK  	  pp\        \        S P                  4      V,
          4      pV'       d#   \        R	R
V RRP                  V4       2R7      h S P                   F  pV! V4       K  	  S P                  ;'       g    ToS P                  '       d'   T TT3R lp	\         P"                  ! T	4      G Rj  x€L
  SP$                  e6   \'        T4      p
 \)        \+        S4      RRT.,           T
4       RRRTRRRT
/#  \/        ST TT3R l4      G Rj  x€L
  RRRTRR/# u upi   \         d   p\        R	\        T4      R7      ThRp?ii ; i L™  \         d    h \,         d   p\        RRT 2R7      hRp?ii ; i Lk  \         d    h \,         d2   p\0        P2                  ! R4       \        R	\        T4      R7      hRp?ii ; i5i)zŠInstall a catalog MCP into config.yaml (declared env vars go to .env
first; git-bootstrap entries run via the background CLI action path).rW  )Úvalidate_env_var_name_for_writerM   NrÆ   zNo catalog entry 'Ú'r’   r‘   zCatalog entry 'z,' does not declare environment variable(s): z, c                  ó|  <€ \        S4      ;_uu_ 4        SP                  P                  ;'       g    .  Ff  p SP                  ;'       g    / P                  V P                  4      pV P
                  '       g   KF  V'       g   KP  \        V P                  V4       Kh  	  R R R 4       R #   + '       g   i     R # ; ir.   )r   rÏ   r?  rŸ   r]   Úsecretr   )ÚspecÚvaluerŒ   Úeffective_profiler5  s     €€€r&   Ú
_write_envÚ-install_mcp_catalog_entry.<locals>._write_envù  st   ø€ ÜÐ 1×2Õ2Ø!ŸJ™JŸN™N×0Ð0¨bÒ0�DØ!ŸX™XŸ^˜^¨×0Ñ0°·±Ó;�EØ—{—{’{§u¡uÜ& t§y¡y°%Ö8ñ 1÷ 3×2×2Ò2ús   •6B*Á+B*Á<B*ÂB*Â*B;	ÚmcprO  rV  zInstall failed: r»   Tr]   Ú
backgroundrq   c                  óh   <€ SP                  SS P                  S P                  ;'       g    R R7      # )N)ÚenableÚpreloaded_env)Úinstall_entryrz  r?  )rŒ   r5  rX  s   €€€r&   Ú<lambda>Ú+install_mcp_catalog_entry.<locals>.<lambda>  s+   ø€ �K×-Ñ-¨e¸D¿K¹KÐW[×W_ÑW_×WgÐWgÐcgÐ-Ôhr(   z install_mcp_catalog_entry failedF)rc  rX  Úhermes_cli.configrn  r]   ri   Ú	get_entryr   rÏ   r?  r†   Úsetr¼   r¯   r$   r"   r„   r…   rO  rr   r   r   r°   r   r±   r²   )rŒ   r"   rn  r]   rr  Údeclared_envÚundeclared_envÚkeyr³   ru  rq   rt  r5  rX  s   f&         @@@r&   Úinstall_mcp_catalog_entryr…  ×  sK  ûé € õ 'ÝAà�I‰I�OˆO˜×"Ñ"Ó$€DØ×!Ñ! $Ó'€EØ‚}Ü¨Ð6HÈÈÈaÐ4PÔQÐQð ,1¯:©:¯>©>×+?Ð+?¸RÐ+?ÓAÑ+? $—I”IÑ+?€LÐAÜœC §¡›M¨LÕ8Ó9€NßÜØØ$ T FÐ*VÐW[×W`ÑW`ÐaoÓWpÐVqÐrô
ð 	
ðGØ—8”8ˆCÙ+¨CÖ0ñ ð
 Ÿ™×/Ð/¨Ðð ‡x‡x€x÷	9ô ×Ò 
Ó+×+Ð+ð ‡}�}Ò Ü)¨$Ó/ˆð	RÜ Ô!2Ð3DÓ!EÈÐPYÐ[_ÐH`Õ!`ÐbhÔið
 �d˜F D¨,¸¸hÈÐOÐOð	>ÜØÞhó
÷ 	
ð 	
ð �$˜  l°EÐ:Ð:ùòk Bøô ô GÜ¨´C¸³HÔ=À3ÐFûðGúñ 	,øô ô 	ØÜô 	RÜ¨CÐ:JÈ3È%Ð8PÔQÐQûð	Rúñ	
øô ô ØÜô >Ü�ŠÐ9Ô:Ü¨´C¸³HÔ=Ð=ûð>üs»   †A3IÁ:IÁ?F4ÂAIÃ%F9 Ä IÄIÄ(!IÅ	G#Å
IÅ(G% Æ
IÆH Æ'HÆ(H Æ,IÆ9G ÇGÇG Ç IÇ%HÇ:HÇ;HÈHÈIÈH ÈIÈ*IÈ+,IÉIÉIi„  r.   )NNNN)HÚ__doc__r„   rj   Ú
contextlibr   rf   r  r
  r8   Útypingr   r   r   Úfastapir   r   r   Úfastapi.responsesr	   Úhermes_cli.web_depsr
   Úhermes_cli.web_server_mcpr   r   r   Úhermes_cli.web_modelsr   r   r   r   Úhermes_cli.web_routers._commonr   r   r   r   r   r   r±   r   Úrouterr   r   r   r   r   r   ÚLockr:   r9   r  r*   r3   rC   r[   rr   rŸ   r‰   Úpostr´   Úputr¾   ÚdeleterÈ   râ   r  r  r  r,  r3  rS  rk  r…  r2   r(   r&   Ú<module>r”     s`  ðñó Û Ý %Û 	Û Û Û ß &Ñ &ç 5Ñ 5Ý *å $ß iÑ iß iÓ i÷÷ ñ ñ
 
‹€áÐ4Ð6VÓWÐ ÙÐ&Ó'€ÙÐ :Ð<WÓXÐ Ù�=Ð"5Ó6€Ù�=Ð"5Ó6€ÙÐ&Ð(;Ó<€à!ŸšÓ(Ð Ø"Ð Ø Ð ð ôó ðõõ0õaõ	ð ‡�ÐÓöó  ðð ‡�ÐÓ ö.4ó !ð.4ðb ‡�ÐÓöó  ðð, ‡�Ð(Ó)öó *ðð( ‡�Ð+Ó,ö.ó -ð.ðb ‡�Ð+Ó,ö7ó -ð7ðt ‡�Ð,Ó-ôó .ðð ‡�Ð/Ó0ô
=ó 1ð
=ð ‡�Ð8Ó9önó :ðnð@ ‡�Ð-Ó.ö)ó /ð)õ2&ðR ‡�ÐÓö<ó  ð<ð> ‡�Ð'Ó(öB;ó )òB;r(   