
    Ki1                    V   d dl mZ d dlZd dlZd dlmZ d dlmZ d dlZd dl	Z	d dl
mZ d dlmZ d dlmZ d dlmZmZ d d	lmZ d d
lmZmZmZ d dlmZ d dlmZ d dlmZ d dlm Z m!Z! d dl"m#Z# d dl$m%Z% dgZ& e%e'      Z( G d de)      Z*	 d	 	 	 	 	 ddZ+ G d de      Z, G d de      Z-y)    )annotationsN)AsyncGenerator)Any)PydanticAdapter)AsyncKeyValue)MemoryStore)OAuthClientProviderTokenStorage)McpHttpClientFactory)OAuthClientInformationFullOAuthClientMetadata
OAuthToken)
AnyHttpUrl)override)Server)OAuthCallbackResultcreate_oauth_callback_server)find_available_port)
get_loggerOAuthc                      e Zd ZdZy)ClientNotFoundErrorzARaised when OAuth client credentials are not found on the server.N)__name__
__module____qualname____doc__     e/home/jay/workspace/scripts/.codegraph-venv/lib/python3.12/site-packages/fastmcp/client/auth/oauth.pyr   r   $   s    Kr   r   c                  K   t        j                  di |xs i 4 d{   }	 |j                  | d       d{   }|j                  dv r	 ddd      d{    yd|j                  v r	 ddd      d{    y	 ddd      d{    y7 r7 X7 ;7 7 # t         j
                  $ r Y ddd      d{  7   yw xY w# 1 d{  7  sw Y   yxY ww)	z
    Check if the MCP endpoint requires authentication by making a test request.

    Returns:
        True if auth appears to be required, False otherwise
    Ng      @)timeout)i  i  TzWWW-AuthenticateFr   )httpxAsyncClientgetstatus_codeheadersRequestError)mcp_urlhttpx_kwargsclientresponses       r   check_if_auth_requiredr,   (   s        8L$6B8  F	#ZZZ==H ##z1   "X%5%55      >    !! 	%   	!  s   CBCCBBBCBC!B0C;B<CCBCBCCCC0C1C<B?=CCCCCCCc                      e Zd ZU ded<   ded<   ded<   ded<   dd	Zdd
ZddZddZedd       Z	edd       Z
edd       Zedd       Zy)TokenStorageAdapterstr_server_urlr   _key_value_storezPydanticAdapter[OAuthToken]_storage_oauth_tokenz+PydanticAdapter[OAuthClientInformationFull]_storage_client_infoc                    || _         || _        t        t           d|t        d      | _        t        t
           d|t
        d      | _        y )Nzmcp-oauth-tokenT)default_collection	key_valuepydantic_modelraise_on_validation_errorzmcp-oauth-client-info)r0   r1   r   r   r2   r   r3   )selfasync_key_value
server_urls      r   __init__zTokenStorageAdapter.__init__L   sQ    % /$3J$?0%%&*	%
! %44N$O6%5&*	%
!r   c                     | j                    dS )Nz/tokensr0   r9   s    r   _get_token_cache_keyz(TokenStorageAdapter._get_token_cache_key\   s    ""#7++r   c                     | j                    dS )Nz/client_infor>   r?   s    r   _get_client_info_cache_keyz.TokenStorageAdapter._get_client_info_cache_key_   s    ""#<00r   c                   K   | j                   j                  | j                                d {    | j                  j                  | j	                                d {    y 7 77 wN)key)r2   deleter@   r3   rB   r?   s    r   clearzTokenStorageAdapter.clearb   s\     ''..43L3L3N.OOO''..43R3R3T.UUU 	PUs!   .A,A(1A,"A*#A,*A,c                r   K   | j                   j                  | j                                d {   S 7 wrD   )r2   r$   r@   r?   s    r   
get_tokenszTokenStorageAdapter.get_tokensf   s/     ..22t7P7P7R2SSSS   .757c                x   K   | j                   j                  | j                         |d       d {    y 7 w)Ni3rE   valuettl)r2   putr@   )r9   tokenss     r   
set_tokenszTokenStorageAdapter.set_tokensj   s=     
 ''++))+" , 
 	
 	
s   0:8:c                r   K   | j                   j                  | j                                d {   S 7 wrD   )r3   r$   rB   r?   s    r   get_client_infoz#TokenStorageAdapter.get_client_infou   s:     ..22//1 3 
 
 	
 
rJ   c                   K   d }|j                   r*|j                   t        t        j                               z
  }| j                  j	                  | j                         ||       d {    y 7 w)NrL   )client_secret_expires_atinttimer3   rO   rB   )r9   client_inforN   s      r   set_client_infoz#TokenStorageAdapter.set_client_info{   sd     //66TYY[9IIC''++//1 , 
 	
 	
s   A(A2*A0+A2N)r:   r   r;   r/   )returnr/   rZ   None)rZ   zOAuthToken | None)rP   r   rZ   r\   )rZ   z!OAuthClientInformationFull | None)rX   r   rZ   r\   )r   r   r   __annotations__r<   r@   rB   rG   r   rI   rQ   rS   rY   r   r   r   r.   r.   F   s    ##55EE
 ,1V T T 
 
 
 

 

 

r   r.   c                  |     e Zd ZdZ	 	 	 	 	 	 d	 	 	 	 	 	 	 	 	 	 	 	 	 d fdZd	 fdZd
dZddZ	 	 	 	 d fdZ xZ	S )r   z
    OAuth client provider for MCP servers with browser-based authentication.

    This class provides OAuth authentication for FastMCP clients by opening
    a browser for user authorization and running a local callback server.
    c           	     :   |j                  d      }|xs t        j                  | _        |xs
 t	               | _        d| j
                   d}t        |t              rdj                  |      }	n|t        |      }	nd}	t        d|t        |      gddgd	g|	d
|xs i }
|xs
 t               }t        |t              rddlm}  |dd       t        ||      | _        || _        t$        | M  ||
| j                   | j(                  | j*                         y)al  
        Initialize OAuth client provider for an MCP server.

        Args:
            mcp_url: Full URL to the MCP endpoint (e.g. "http://host/mcp/sse/")
            scopes: OAuth scopes to request. Can be a
            space-separated string or a list of strings.
            client_name: Name for this client during registration
            token_storage: An AsyncKeyValue-compatible token store, tokens are stored in memory if not provided
            additional_client_metadata: Extra fields for OAuthClientMetadata
            callback_port: Fixed port for OAuth callback (default: random available port)
        /zhttp://localhost:z	/callback N authorization_coderefresh_tokencode)client_nameredirect_urisgrant_typesresponse_typesscoper   )warnzUsing in-memory token storage -- tokens will be lost when the client restarts. For persistent storage across multiple MCP servers, provide an encrypted AsyncKeyValue backend. See https://gofastmcp.com/clients/auth/oauth#token-storage for details.   )message
stacklevel)r:   r;   )r;   client_metadatastorageredirect_handlercallback_handlerr   )rstripr"   r#   httpx_client_factoryr   redirect_port
isinstancelistjoinr/   r   r   r   warningsrk   r.   token_storage_adapterr(   superr<   rq   rr   )r9   r(   scopesrf   token_storageadditional_client_metadatacallback_portrt   redirect_uri
scopes_strro   rk   	__class__s               r   r<   zOAuth.__init__   s9   . ..% %9$ME<M<M!*C.A.C*4+=+=*>iH fd#&)JVJJ- 
#%l34-?"8
 */R
 &6m[1%\ 	 ;N)g;
"
  	+..!22!22 	 	
r   c                  K   t         |           d{    | j                  j                  rQ| j                  j                  j                  r0| j                  j                  | j                  j                         yyy7 lw)zBLoad stored tokens and client info, properly setting token expiry.N)r{   _initializecontextcurrent_tokens
expires_inupdate_token_expiry)r9   r   s    r   r   zOAuth._initialize   se      g!### <<&&4<<+F+F+Q+QLL,,T\\-H-HI ,R& 	$s   BBA-Bc                  K   | j                         4 d{   }|j                  |d       d{   }|j                  dk(  rt        d      |j                  dvrt	        d|j                         ddd      d{    t
        j                  d|        t        j                  |       y7 7 7 6# 1 d{  7  sw Y   FxY ww)	zIOpen browser for authorization, with pre-flight check for invalid client.NF)follow_redirectsi  z8OAuth client not found - cached credentials may be stale)   i.  i/  i3  i4  z#Unexpected authorization response: zOAuth authorization URL: )	rt   r$   r%   r   RuntimeErrorloggerinfo
webbrowseropen)r9   authorization_urlr*   r+   s       r   rq   zOAuth.redirect_handler   s      ,,. 	 	&#ZZ(9EZRRH ##s*)N 
 ##+DD"9(:N:N9OP 	 	 	/0A/BCD)*!	R	 	 	 	sU   CB5CB;B7AB;7CB93C7B;9C;CCC	Cc                  K   t               }t        j                         }t        | j                  | j
                  ||      }t        j                         4 d{   }|j                  |j                         t        j                  d| j                          d}	 t        j                  |      5  |j                          d{    |j                  r|j                  |j                  |j                  fcddd       d|_        t        j"                  d       d{    |j$                  j'                          cddd      d{    S 7 7 7 47 # 1 sw Y   nxY wn!# t(        $ r}t)        d| d      |d}~ww xY w	 d|_        t        j"                  d       d{  7   |j$                  j'                          nD# d|_        t        j"                  d       d{  7   |j$                  j'                          w xY wddd      d{  7   t+        d	      # 1 d{  7  sw Y   t+        d	      xY ww)
z4Handle OAuth callback and return (auth_code, state).)portr;   result_containerresult_readyNu7   🎧 OAuth callback server started on http://localhost:g     r@Tg?zOAuth callback timed out after z secondsz+OAuth callback handler could not be started)r   anyioEventr   ru   r(   create_task_group
start_soonserver   r   
fail_afterwaiterrorre   stateshould_exitsleepcancel_scopecancelTimeoutErrorr   )r9   resultr   servertgTIMEOUTes          r   rr   zOAuth.callback_handler   s     %&{{} 6##||#%	
 **, 	) 	)MM&,,'KKI$J\J\I]^ G)%%g. 5&++---||$ll*!;;4	5 5 &*"kk#&&&&&()	) 	) 	) . ''	)5 5 5
   "5gYhG5 &*"kk#&&&&&( &*"kk#&&&&&()	) 	) 	), HII-	) 	) 	), HIIs   AIEI A H.!E,6E
E3E>	E,H.&E'H.IEIEH.IE(	$E,+G,	F
5FF

GH.-F0. H. H.G1
/ HH.IH I.I
4H75I
<Ic                 K   	 t         |   |      }d}	 	 |j                  |       d{   }|} 7 
# t        $ r Y yw xY w# t        $ r t
        j                  d       d| _        | j                  j                          d{  7   t         |   |      }d}	 	 |j                  |       d{  7  }|}n# t        $ r Y Y yw xY w2w xY ww)zHTTPX auth flow with automatic retry on stale cached credentials.

        If the OAuth flow fails due to invalid/stale client credentials,
        clears the cache and retries once with fresh registration.
        Nz@OAuth client not found on server, clearing cache and retrying...F)
r{   async_auth_flowasendStopAsyncIterationr   r   debug_initializedrz   rG   )r9   requestgenr+   yielded_requestr   s        r   r   zOAuth.async_auth_flow$  s     	')'2CH,/IIh,?&?O%44H	  '@)  # 	LLR !&D,,22444 ')'2CH,/IIh,?&?&?O%44H) 	 	s   CA 9 7	9 A 9 	AA CAA AC
BC#C7B:8
CC	CCCCCC)NzFastMCP ClientNNNN)r(   r/   r|   zstr | list[str] | Nonerf   r/   r}   zAsyncKeyValue | Noner~   dict[str, Any] | Noner   z
int | Nonert   zMcpHttpClientFactory | Noner[   )r   r/   rZ   r\   )rZ   ztuple[str, str | None])r   zhttpx.RequestrZ   z-AsyncGenerator[httpx.Request, httpx.Response])
r   r   r   r   r<   r   rq   rr   r   __classcell__)r   s   @r   r   r      s     *.+.2<@$(<@L
L
 'L
 	L

 ,L
 %:L
 "L
 :L
\J+*%JN$$$	6$ $r   )N)r(   r/   r)   r   rZ   bool).
__future__r   rW   r   collections.abcr   typingr   r   r"   key_value.aio.adapters.pydanticr   key_value.aio.protocolsr   key_value.aio.stores.memoryr   mcp.client.authr	   r
   mcp.shared._httpx_utilsr   mcp.shared.authr   r   r   pydanticr   typing_extensionsr   uvicorn.serverr   fastmcp.client.oauth_callbackr   r   fastmcp.utilities.httpr   fastmcp.utilities.loggingr   __all__r   r   	Exceptionr   r,   r.   r   r   r   r   <module>r      s    "   *    ; 1 3 = 8 
   & ! 7 0)	H	L) L
 9= 5	<@
, @
F r   