
    iۺ                    $   U d Z ddlmZ ddlZddlZddlZddlZddlmZm	Z	 ddlm
Z
mZ ddlmZ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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% ddl&m'Z' ddl(m)Z)m*Z* ddl+m,Z, ddl-m.Z. ddl/m"Z" ddl0m1Z1 ddl2m3Z3 ddl4m5Z5m6Z6  ejn                  e8      Z9erddl:m;Z; ddl<m=Z= ddl>m?Z? ddl@mAZA ddlBmCZC g dZD edd       G d d             ZEdkd ZFi ZGd!eHd"<   dld#ZIdmd$ZJ ed%d&      ZKd'eHd(<    ed)d&      ZLd*eHd+<    ed,d&      ZMd-eHd.<    ed/d&      ZNd0eHd1<   daOd2eHd3<   dnd4ZPdod5ZQ	 dd6lRmSZT dpd7ZVdqd8ZWdrd:ZXdsd<ZYdtd=ZZ	 	 du	 	 	 	 	 dvd>Z[dwd?Z ed@A      dpdB       Z\e	 	 	 	 	 	 dxdC       Z]e	 	 	 	 	 	 dxdD       Z^	 	 	 	 	 	 dydEZ_dzdFZ` G dG dHe)d9         Za G dI dJe)dK         ZbdrdLZcd{dMZd G dN dOe)dP         Zed|dQZf G dR dSe)dT         Zgd}dUZh G dV dWe)d;         ZidsdXZj G dY dZe)e'         Zkdtd[Zl G d\ d]e)emenenf            Zod~d^Zpe G d_ d`e             Zq G da db      Zr G dc dde)dd         ZS G de dfe)e"         ZsddgZt G dh die)en         ZuddjZvy# eU$ r dZTY :w xY w)a  Dependency injection for FastMCP.

DI features (Depends, CurrentContext, CurrentFastMCP) work without pydocket
using the uncalled-for DI engine. Only task-related dependencies (CurrentDocket,
CurrentWorker) and background task execution require fastmcp[tasks].
    )annotationsN)AsyncGeneratorCallable)AsyncExitStackasynccontextmanager)
ContextVarToken)	dataclass)datetimetimezone)	lru_cache)TYPE_CHECKINGAnyProtocolcastget_type_hintsruntime_checkable)get_access_token)AuthenticatedUser)AccessToken)request_ctx)Request)
Dependencyget_dependency_parameters)_Depends)FastMCPError)_current_http_request)call_sync_fn_in_threadpool)find_kwarg_by_typeis_class_member_of_type)Docket)Worker)ServerSessionContextFastMCP)r   CurrentAccessTokenCurrentContextCurrentDocketCurrentFastMCPCurrentHeadersCurrentRequestCurrentWorkerProgressTaskContextInfo
TokenClaimr   get_contextget_http_headersget_http_request
get_serverget_task_contextget_task_sessionis_docket_availableregister_task_sessionrequire_docketresolve_dependenciestransform_context_annotationswithout_injected_parametersT)frozenslotsc                  (    e Zd ZU dZded<   	 ded<   y)r0   zInformation about the current background task context.

    Returned by ``get_task_context()`` when running inside a Docket worker.
    Contains identifiers needed to communicate with the MCP session.
    strtask_id
session_idN)__name__
__module____qualname____doc____annotations__     k/Users/bowang/.openclaw/workspace/ChatDev/.venv/lib/python3.12/site-packages/fastmcp/server/dependencies.pyr0   r0   R   s     L2O2rJ   r0   c                     t               syddlm}  	 | j                         }ddlm}  ||j                        }t        |d   |d         S # t        $ r Y yt        t        f$ r Y yw xY w)aJ  Get the current task context if running inside a background task worker.

    This function extracts task information from the Docket execution context.
    Returns None if not running in a task context (e.g., foreground execution).

    Returns:
        TaskContextInfo with task_id and session_id, or None if not in a task.
    Nr   )current_execution)parse_task_keyclient_task_idrC   )rB   rC   )r8   docket.dependenciesrM   getfastmcp.server.tasks.keysrN   keyr0   LookupError
ValueErrorKeyError)rM   	executionrN   	key_partss       rK   r6   r6   a   sv      5%))+	<"9==1	./ .
 	
  ! s   :A 	A*A*)A*z%dict[str, weakref.ref[ServerSession]]_task_sessionsc                <    t        j                  |      t        | <   y)aP  Register a session for Context access in background tasks.

    Called automatically when a task is submitted to Docket. The session is
    stored as a weakref so it doesn't prevent garbage collection when the
    client disconnects.

    Args:
        session_id: The session identifier
        session: The ServerSession instance
    N)weakrefrefrY   )rC   sessions     rK   r9   r9      s     ")W!5N:rJ   c                t    t         j                  |       }|y |       }|t         j                  | d       |S )zGet a registered session by ID if still alive.

    Args:
        session_id: The session identifier

    Returns:
        The ServerSession if found and alive, None otherwise
    N)rY   rQ   pop)rC   r\   r]   s      rK   r7   r7      s=     

Z
(C
{eG:t,NrJ   serverdefaultz'ContextVar[weakref.ref[FastMCP] | None]_current_serverdocketzContextVar[Docket | None]_current_docketworkerzContextVar[Worker | None]_current_workertask_access_tokenzContextVar[AccessToken | None]_task_access_tokenzbool | None_DOCKET_AVAILABLEc                 `    t         	 ddl} da t         S t         S # t        $ r
 da Y t         S w xY w)zCheck if pydocket is installed.Nr   TF)rj   rd   ImportError)rd   s    rK   r8   r8      sC      	& $   	& %	&s    --c                6    t               st        d|  d      y)zRaise ImportError with install instructions if docket not available.

    Args:
        feature: Description of what requires docket (e.g., "`task=True`",
                 "CurrentDocket()"). Will be included in the error message.
    znFastMCP background tasks require the `tasks` extra. Install with: pip install 'fastmcp[tasks]'. (Triggered by )N)r8   rl   )features    rK   r:   r:      s-      $IQ(
 	
 !rJ   r/   c                   ddl m} 	 t        j                  |       }	 t        | d      }t               }t               }|j                  j                         D ]x  \  }}|j                  ||j                        }t        ||      s/t        |j                   t"              rJ|j%                  |       |j                   h|j%                  |       z |s| S t        j&                  }	g }
g }g }g }g }g }g }|j                  j                         D ]q  \  }}||v r9||v r|j)                  t+                     }n|j)                  t-                     }|j.                  |	j0                  k(  r<|j                   |	j2                  u r|
j5                  |       |j5                  |       |j.                  |	j6                  k(  r<|j                   |	j2                  u r|j5                  |       |j5                  |       |j.                  |	j8                  k(  r|j5                  |       |j.                  |	j:                  k(  r|j5                  |       F|j.                  |	j<                  k(  sa|j5                  |       t |
|z   |z   |z   |z   |z   |z   }t        j>                  |       rrt        j                  | j@                        }tC        tE        |j                  jG                                     }|j)                  |g|      }|| j@                  _$        n|j)                  |      }|| _$        tK        |        | S # t        t
        f$ r | cY S w xY w# t        $ r t        | di       }Y Kw xY w)a  Transform ctx: Context into ctx: Context = CurrentContext().

    Transforms ALL params typed as Context to use Docket's DI system,
    unless they already have a Dependency-based default (like CurrentContext()).

    This unifies the legacy type annotation DI with Docket's Depends() system,
    allowing both patterns to work through a single resolution path.

    Note: Only POSITIONAL_OR_KEYWORD parameters are reordered (params with defaults
    after those without). KEYWORD_ONLY parameters keep their position since Python
    allows them to have defaults in any order.

    Args:
        fn: Function to transform

    Returns:
        Function with modified signature (same function object, updated __signature__)
    r   r$   Tinclude_extrasrH   ra   )
parameters)&fastmcp.server.contextr%   inspect	signaturerU   	TypeErrorr   	Exceptiongetattrsetrt   itemsrQ   
annotationr    
isinstancerb   r   add	ParameterreplaceOptionalCurrentContextr)   kindPOSITIONAL_ONLYemptyappendPOSITIONAL_OR_KEYWORDVAR_POSITIONALKEYWORD_ONLYVAR_KEYWORDismethod__func__nextitervalues__signature___clear_signature_caches)fnr%   sig
type_hintsparams_to_transformoptional_context_paramsnameparamr}   Ppositional_only_no_defaultpositional_only_with_default positional_or_keyword_no_default"positional_or_keyword_with_defaultvar_positionalkeyword_onlyvar_keyword
new_paramsfunc_sig
self_paramnew_sigs                        rK   r<   r<      s+   & /#
8#Bt<

 %(E(+~~++-e^^D%*:*:;
":w7emmZ8#''-==(+//5 . 	 	A +-,. 02$24& NLK~~++-e&& ...D.FGn.>? ::***}}'*11%8,33E:ZZ1222}}'077>299%@ZZ1+++!!%(ZZ1>>)&ZZ1==(u%7 .> 	#
&	'
*	+ -	- 		
 	 	  $$R[[1$x2299;<=
""z.GJ.G"H$+!+++4"
 BIE 	" 	  8R!2B7
8s"   M M MMM76M7c                    ddl m}m} |j                  | d       |j                  | d       t	        j
                  |       r9|j                  | j                  d       |j                  | j                  d       yy)zClear signature-related caches for a function.

    Called after modifying a function's signature to ensure downstream
    code sees the updated signature.
    r   )_parameter_cache_signature_cacheN)uncalled_for.introspectionr   r   r_   rv   r   r   )r   r   r   s      rK   r   r   \  sc     NT"T"R[[$/R[[$/ rJ   r%   c                 L    ddl m}  | j                         }|t        d      |S )z2Get the current FastMCP Context instance directly.r   )_current_contextzNo active context found.)ru   r   rQ   RuntimeError)r   contexts     rK   r2   r2   l  s)    7""$G566NrJ   r'   c                 p    t         j                         } | t        d       |        }|t        d      |S )zGet the current FastMCP server instance directly.

    Returns:
        The active FastMCP server

    Raises:
        RuntimeError: If no server in context
    %No FastMCP server instance in context.FastMCP server instance is no longer availablerc   rQ   r   )
server_refr`   s     rK   r5   r5   v  sA     !$$&JBCC\F~KLLMrJ   c                     d} t        j                  t              5  t        j                         j
                  } ddd       | t        j                         } | t        d      | S # 1 sw Y   .xY w)zuGet the current HTTP request.

    Tries MCP SDK's request_ctx first, then falls back to FastMCP's HTTP context.
    NzNo active HTTP request found.)
contextlibsuppressrT   r   rQ   requestr   r   )r   s    rK   r4   r4     sb     G			[	)//#++ 
*
 '++-:;;N 
*	)s   A((A1c                x   | rt               }nDh d}|r!||D ch c]  }|j                          c}z  }t        d |D              st        d      i }	 t	               }|j
                  j                         D ](  \  }}|j                         }||vst        |      ||<   * |S c c}w # t        $ r i cY S w xY w)a]  Extract headers from the current HTTP request if available.

    Never raises an exception, even if there is no active HTTP request (in which case
    an empty dict is returned).

    By default, strips problematic headers like `content-length` and `authorization`
    that cause issues if forwarded to downstream services. If `include_all` is True,
    all headers are returned.

    The `include` parameter allows specific headers to be included even if they would
    normally be excluded. This is useful for proxy transports that need to forward
    authorization headers to upstream MCP servers.
    >   
keep-alivecontent-typecontent-lengthmcp-session-idproxy-connectiontransfer-encodingproxy-authenticateproxy-authorizationtehostacceptexpectupgrade
connectionauthorizationc              3  B   K   | ]  }|j                         |k(    y wN)lower).0hs     rK   	<genexpr>z#get_http_headers.<locals>.<genexpr>  s     ;?a1779>?s   z"Excluded headers must be lowercase)	r{   r   allrU   r4   headersr|   rA   r   )	include_allincludeexclude_headersr   r   r   r   value
lower_names	            rK   r3   r3     s    " $'E
& 7;7a	7;;O;?;;ABB G"$"??002KD%J0&)%j
# 3   <  	s   B&>B+ B+ +B98B9c            
        d} 	 t               }|j                  j                  d      }t        |t              r|j
                  } | 
t               } | lt        j                         }|V|j                  H|j                  t        t        j                  t        j                        j                               k  ry|S | t        | t               r| S 	 | j#                         }t!        |d   |d   |d   |j                  d      |j                  d      |j                  d      xs i 	      S # t        $ r Y w xY w# t$        $ r(}t'        d
t)        |       j*                   d      |d}~ww xY w)a)  Get the FastMCP access token from the current context.

    This function first tries to get the token from the current HTTP request's scope,
    which is more reliable for long-lived connections where the SDK's auth_context_var
    may become stale after token refresh. Falls back to the SDK's context var if no
    request is available. In background tasks (Docket workers), falls back to the
    token snapshot stored in Redis at task submission time.

    Returns:
        The access token if an authenticated user is available, None otherwise.
    Nusertoken	client_idscopes
expires_atresourceclaims)r   r   r   r   r   r   z3Expected fastmcp.server.auth.auth.AccessToken, got z7. Ensure the SDK is using the correct AccessToken type.)r4   scoperQ   r~   r   access_tokenr   _sdk_get_access_tokenri   r   intr   nowr   utc	timestampr   
model_dumpry   rx   typerD   )r   r   r   
task_tokenaccess_token_as_dictes         rK   r   r     s    ,0L
"$}}  (d-.,,L ,. '++-
!$$0((3x||HLL/I/S/S/U+VVz,D+668&w/*;7'1+//=)--j9'++H5;
 	
=  N  A$|BTB]B]A^ _D D
 	s+   AD/ AD> /	D;:D;>	E/#E**E/i  )maxsizec                :    ddl m} t         |      }t               }t	               }|r|j                  |       |r|j                  |j                                |s S t        j                         }|j                  j                         D cg c]  \  }}||vs| }}}t        j                  |      }	t        j                         d fd}
	 t         d      }|	|
_        |j                         D ci c]  \  }}||vs|dk7  s|| c}}|
_        t!         dd	      |
_        t!         d
d      |
_         j*                  |
_        t!         d|
j,                        |
_        |
S c c}}w # t        $ r t!         di       }Y w xY wc c}}w )ad  Create a wrapper function without injected parameters.

    Returns a wrapper that excludes Context and Docket dependency parameters,
    making it safe to use with Pydantic TypeAdapter for schema generation and
    validation. The wrapper internally handles all dependency resolution and
    Context injection when called.

    Handles:
    - Legacy Context injection (always works)
    - Depends() injection (always works - uses docket or vendored DI engine)

    Args:
        fn: Original function with Context and/or dependencies

    Returns:
        Async wrapper function without injected parameters
    r   r$   returnc                 J  K   t        |       4 d {   }r! di | d {   cd d d       d {    S t        fi | d {   }t        j                  |      r
| d {   }|cd d d       d {    S 7 m7 ]7 O7 <7 7 # 1 d {  7  sw Y   y xY ww)NrI   )r;   r   rv   isawaitable)user_kwargsresolved_kwargsresultr   fn_is_asyncs      rK   wrapperz,without_injected_parameters.<locals>.wrapperH  s     'K88O2/22 988
  :"PPP&&v.#)\F 9882 9
 Q * 9888s   B#BB#BBBB#BB#BBB*B
+B0B#<B=B#BB#B
BB#B BB B#Trr   rH   rD   r   rG   NrF   )r   r   r   r   )ru   r%   r   r   r{   r   updatekeysrv   rw   rt   r|   	Signatureiscoroutinefunctionr   ry   rz   r   rH   rD   rG   rE   rF   )r   r%   context_kwargdependency_paramsexcluder   r   r   user_paramsr   r   resolved_hintskvr   s   `             @rK   r=   r=     s   & / 'r73M1"5eGM"(--/0	 

B
C!$!5!5!7!7+$4w;N!7   ,G --b1K
 <'4@ $G'--//A1G3CX1/G r:y9Gb)T2GOG"2~w7K7KLGNM4  < %6;<s0   E5!E5E; FFF;FFc           
    \  K   t        |       }|s| yt        j                  j                  i       }	 t	               4 d{   }t        j
                  j                  |      }	 i }|j                         D ]/  \  }}||v r	||   ||<   	 |j                  |       d{   ||<   1 i ||}| t        j
                  j                  |       ddd      d{    t        j                  j                  |       y7 7 e# t        $ r  t        $ r-}	t        | dt        |             }
t        d| d|
       |	d}	~	ww xY w# t        j
                  j                  |       w xY w7 # 1 d{  7  sw Y   xY w# t        j                  j                  |       w xY ww)a  Resolve Docket dependencies for a FastMCP function.

    Sets up the minimal context needed for Docket's Depends() to work:
    - A cache for resolved dependencies
    - An AsyncExitStack for managing context manager lifetimes

    The Docket instance (for CurrentDocket dependency) is managed separately
    by the server's lifespan and made available via ContextVar.

    Note: This does NOT set up Docket's Execution context. If user code needs
    Docket-specific dependencies like TaskArgument(), TaskKey(), etc., those
    will fail with clear errors about missing context.

    Args:
        fn: The function to resolve dependencies for
        arguments: The arguments passed to the function

    Yields:
        Dictionary of resolved dependencies merged with provided arguments
    NrD   zFailed to resolve dependency 'z' for )r   r   cacher{   r   stackr|   enter_async_contextr   ry   rz   reprr   reset)r   	argumentsr   cache_tokenr   stack_tokenresolved	parameter
dependencyerrorfn_namefinal_argumentss               rK   _resolve_fastmcp_dependenciesr  l  s    0 2"5 ..$$R(K"*!##u"..,,U3K2+-->-D-D-F)Iz I-.7	.B+ %494M4M&5 /+ .G, #<Y";(";%%$$[1? $#B 	[)C $/ (  $ %")"j$r("C*<YKvgYW$%% $$[1? $###B 	[)s   3F,F DF  E3)%ED#D	$D+E8E3F "E1#F ' F,F 	DE
(EE

E!E..E31F 3F9E<:FF !F))F,c                 K   t        |       }|j                         D ci c]  \  }}||vs|| }}}t        | |      4 d{   }| ddd      d{    yc c}}w 7  7 # 1 d{  7  sw Y   yxY ww)aY  Resolve dependencies for a FastMCP function.

    This function:
    1. Filters out any dependency parameter names from user arguments (security)
    2. Resolves Depends() parameters via the DI system

    The filtering prevents external callers from overriding injected parameters by
    providing values for dependency parameter names. This is a security feature.

    Note: Context injection is handled via transform_context_annotations() which
    converts `ctx: Context` to `ctx: Context = Depends(get_context)` at registration
    time, so all injection goes through the unified DI system.

    Args:
        fn: The function to resolve dependencies for
        arguments: User arguments (may contain keys that match dependency names,
                  which will be filtered out)

    Yields:
        Dictionary of filtered user args + resolved dependencies

    Example:
        ```python
        async with resolve_dependencies(my_tool, {"name": "Alice"}) as kwargs:
            result = my_tool(**kwargs)
            if inspect.isawaitable(result):
                result = await result
        ```
    N)r   r|   r  )r   r  r   r   r   	user_argsr   s          rK   r;   r;     sx     H 2"5"+//"3R"3$!Qq@Q7QA"3IR,R;; <;; S;;;;;sV   B A!A!B A'B 
A+B A)B )B +A=1A42A=9B c                  K   t         j                         }|y|j                  d|  d| d      }	 |j                         4 d{   }|j                  |       d{   }ddd      d{    *t	        j
                  |      }t        j                  |      S 	 y7 [7 D7 6# 1 d{  7  sw Y   FxY w# t        $ r t        j                  d| |d       Y yw xY ww)a  Restore the access token snapshot from Redis into a ContextVar.

    Called when setting up context in a Docket worker. The token was stored at
    submit_to_docket() time. The token is restored regardless of expiration;
    get_access_token() checks expiry when reading from the ContextVar.

    Returns:
        The ContextVar token for resetting, or None if nothing was restored.
    Nfastmcp:task::z:access_tokenz-Failed to restore access token for task %s:%sTexc_info)re   rQ   rS   redisr   model_validate_jsonri   r{   ry   _loggerwarning)rC   rB   rd   	token_keyr  
token_datarestoreds          rK   _restore_task_access_tokenr    s        "F~

]:,ayNOI
<<>>U$yy33J ">!"66zBH%))(33 "  "3 ">>>
  
;	 	 	
 
s   0C&B> B#B> B) B%!B)%B> 0B'1/B>  C&"C&#B> %B)'B> )B;/B20B;7B> >"C# C&"C##C&c                  K   t         j                         }|y|j                  d|  d| d      }	 |j                         4 d{   }|j                  |       d{   }ddd      d{    yt	        |t
              r|j                         S t        |      S 7 [7 D7 6# 1 d{  7  sw Y   FxY w# t        $ r t        j                  d| |d       Y yw xY ww)zRestore the origin request ID snapshot for a background task.

    Returns None if no request ID was captured at submission time.
    Nr  r  z:origin_request_idz2Failed to restore origin request ID for task %s:%sTr  )re   rQ   rS   r  r~   bytesdecoderA   ry   r  r  )rC   rB   rd   request_id_keyr  request_id_datas         rK   _restore_task_origin_request_idr     s     
   "F~ZZ

|1WI-?@N<<>>U$)IIn$==O ">"ou-"))++?## "= ">>>  @	 	 	
 s   0C&B> B#B> B) B%!B)%B> 0B'1B> 7C&8B> C&
B> "C&#B> %B)'B> )B;/B20B;7B> >"C# C&"C##C&c                  >    e Zd ZU dZdZded<   dZded<   d	dZd
dZy)_CurrentContexta  Async context manager for Context dependency.

    In foreground (request) mode: returns the active context from _current_context.
    In background (Docket worker) mode: creates a task-aware Context with task_id
    and restores the access token snapshot from Redis.
    NContext | None_context Token[AccessToken | None] | None_access_token_cv_tokenc                  K   ddl m}m} |j                         }||S t	               }|t        |j                        }t               }t        |j                  |j                         d {   } ||||j                  |      | _
        | j                  j                          d {    t        |j                  |j                         d {   | _        | j                  S t        d      7 7 J7 $w)Nr   )r%   r   )fastmcpr]   rB   origin_request_idzNo active context found. This can happen if:
  - Called outside an MCP request handler
  - Called in a background task before session was registered
Check `context.request_context` for None before accessing.)ru   r%   r   rQ   r6   r7   rC   r5   r   rB   r$  
__aenter__r  r&  r   )selfr%   r   r   	task_infor]   r`   r)  s           rK   r*  z_CurrentContext.__aenter__+  s     D #&&(N %&	 &y';';<G\F&E$$i&7&7' ! $!))"3	DM --**,,, 1K$$i&7&71 +D' ==  I
 	
+! -+s6   A+C9-C3.<C9*C5+'C9C7!C95C97C9c                   K   | j                   &t        j                  | j                          d | _         | j                  ) | j                  j                  |  d {    d | _        y y 7 wr   )r&  ri   r  r$  	__aexit__r+  argss     rK   r.  z_CurrentContext.__aexit__V  sa     &&2$$T%@%@A*.D'==$)$--))4000 DM %0s   AA-A+A-r   r%   r0  objectr   None)	rD   rE   rF   rG   r$  rH   r&  r*  r.  rI   rJ   rK   r"  r"     s*      $Hn#?C<C)
V!rJ   r"  c                  0    e Zd ZU dZdZded<   ddZddZy)	_OptionalCurrentContextzContext dependency that degrades to None when no context is active.

    This is implemented as a wrapper (composition), not a subclass of
    `_CurrentContext`, to avoid overriding `__aenter__` with an incompatible
    return type.
    Nz_CurrentContext | None_innerc                   K   t               }	 |j                          d {   }|| _        |S 7 # t        $ r}dt        |      v rY d }~y  d }~ww xY ww)NzNo active context found)r"  r*  r   rA   r7  )r+  innerr   excs       rK   r*  z"_OptionalCurrentContext.__aenter__k  sX     !	!,,..G
  / 	(CH4	s<   A1 /1 	A1 	AAAAAAc                z   K   | j                   y  | j                   j                  |  d {    d | _         y 7 wr   )r7  r.  r/  s     rK   r.  z!_OptionalCurrentContext.__aexit__v  s9     ;;#dkk##T*** 	+s   *;9;r   r#  r2  )rD   rE   rF   rG   r7  rH   r*  r.  rI   rJ   rK   r6  r6  a  s     &*F")	rJ   r6  r#  c                 *    t        dt                     S )ai  Get the current FastMCP Context instance.

    This dependency provides access to the active FastMCP Context for the
    current MCP operation (tool/resource/prompt call).

    Returns:
        A dependency that resolves to the active Context instance

    Raises:
        RuntimeError: If no active context found (during resolution)

    Example:
        ```python
        from fastmcp.dependencies import CurrentContext

        @mcp.tool()
        async def log_progress(ctx: Context = CurrentContext()) -> str:
            ctx.report_progress(50, 100, "Halfway done")
            return "Working"
        ```
    r%   )r   r"  rI   rJ   rK   r)   r)   }  s    , 	?,--rJ   c                 *    t        dt                     S )zCGet the current FastMCP Context, or None when no context is active.r#  )r   r6  rI   rJ   rK   r   r     s     "9";<<rJ   c                       e Zd ZdZddZddZy)_CurrentDocketz,Async context manager for Docket dependency.c                f   K   t        d       t        j                         }|t        d      |S w)NCurrentDocket()zNo Docket instance found. Docket is only initialized when there are task-enabled components (task=True). Add task=True to a component to enable Docket infrastructure.)r:   re   rQ   r   )r+  rd   s     rK   r*  z_CurrentDocket.__aenter__  ;     () $$&>3 
    /1c                   K   y wr   rI   r/  s     rK   r.  z_CurrentDocket.__aexit__  	        Nr   r!   r2  rD   rE   rF   rG   r*  r.  rI   rJ   rK   r@  r@        6	rJ   r@  r!   c                 @    t        d       t        dt                     S )a  Get the current Docket instance managed by FastMCP.

    This dependency provides access to the Docket instance that FastMCP
    automatically creates for background task scheduling.

    Returns:
        A dependency that resolves to the active Docket instance

    Raises:
        RuntimeError: If not within a FastMCP server context
        ImportError: If fastmcp[tasks] not installed

    Example:
        ```python
        from fastmcp.dependencies import CurrentDocket

        @mcp.tool()
        async def schedule_task(docket: Docket = CurrentDocket()) -> str:
            await docket.add(some_function)(arg1, arg2)
            return "Scheduled"
        ```
    rB  r!   )r:   r   r@  rI   rJ   rK   r*   r*     s    . $%.*++rJ   c                       e Zd ZdZddZddZy)_CurrentWorkerz,Async context manager for Worker dependency.c                f   K   t        d       t        j                         }|t        d      |S w)NCurrentWorker()zNo Worker instance found. Worker is only initialized when there are task-enabled components (task=True). Add task=True to a component to enable Docket infrastructure.)r:   rg   rQ   r   )r+  rf   s     rK   r*  z_CurrentWorker.__aenter__  rC  rD  c                   K   y wr   rI   r/  s     rK   r.  z_CurrentWorker.__aexit__  rF  rG  Nr   r"   r2  rI  rI   rJ   rK   rM  rM    rJ  rJ   rM  r"   c                 @    t        d       t        dt                     S )a  Get the current Docket Worker instance managed by FastMCP.

    This dependency provides access to the Worker instance that FastMCP
    automatically creates for background task processing.

    Returns:
        A dependency that resolves to the active Worker instance

    Raises:
        RuntimeError: If not within a FastMCP server context
        ImportError: If fastmcp[tasks] not installed

    Example:
        ```python
        from fastmcp.dependencies import CurrentWorker

        @mcp.tool()
        async def check_worker_status(worker: Worker = CurrentWorker()) -> str:
            return f"Worker: {worker.name}"
        ```
    rO  r"   )r:   r   rM  rI   rJ   rK   r.   r.     s    , $%.*++rJ   c                       e Zd ZdZddZddZy)_CurrentFastMCPz4Async context manager for FastMCP server dependency.c                x   K   t         j                         }|t        d       |       }|t        d      |S w)Nr   r   r   )r+  r   r`   s      rK   r*  z_CurrentFastMCP.__aenter__  sC     $((*
FGG>OPPs   8:c                   K   y wr   rI   r/  s     rK   r.  z_CurrentFastMCP.__aexit__   rF  rG  Nr   r'   r2  rI  rI   rJ   rK   rT  rT    s    >rJ   rT  c                 6    ddl m}  t        | t                     S )a  Get the current FastMCP server instance.

    This dependency provides access to the active FastMCP server.

    Returns:
        A dependency that resolves to the active FastMCP server

    Raises:
        RuntimeError: If no server in context (during resolution)

    Example:
        ```python
        from fastmcp.dependencies import CurrentFastMCP

        @mcp.tool()
        async def introspect(server: FastMCP = CurrentFastMCP()) -> str:
            return f"Server: {server.name}"
        ```
    r   r&   )fastmcp.server.serverr'   r   rT  r&   s    rK   r+   r+     s    ( .*++rJ   c                       e Zd ZdZddZddZy)_CurrentRequestz2Async context manager for HTTP Request dependency.c                   K   t               S wr   )r4   r+  s    rK   r*  z_CurrentRequest.__aenter__   s     !!s   c                   K   y wr   rI   r/  s     rK   r.  z_CurrentRequest.__aexit__#  rF  rG  Nr   r   r2  rI  rI   rJ   rK   r[  r[    s    <"rJ   r[  c                 2    t        t        t                     S )a  Get the current HTTP request.

    This dependency provides access to the Starlette Request object for the
    current HTTP request. Only available when running over HTTP transports
    (SSE or Streamable HTTP).

    Returns:
        A dependency that resolves to the active Starlette Request

    Raises:
        RuntimeError: If no HTTP request in context (e.g., STDIO transport)

    Example:
        ```python
        from fastmcp.server.dependencies import CurrentRequest
        from starlette.requests import Request

        @mcp.tool()
        async def get_client_ip(request: Request = CurrentRequest()) -> str:
            return request.client.host if request.client else "Unknown"
        ```
    )r   r   r[  rI   rJ   rK   r-   r-   '  s    . *++rJ   c                       e Zd ZdZddZddZy)_CurrentHeadersz2Async context manager for HTTP Headers dependency.c                $   K   t        dh      S w)Nr   )r   )r3   r]  s    rK   r*  z_CurrentHeaders.__aenter__D  s     (9::s   c                   K   y wr   rI   r/  s     rK   r.  z_CurrentHeaders.__aexit__G  rF  rG  Nr   dict[str, str]r2  rI  rI   rJ   rK   rb  rb  A  s    <;rJ   rb  c                 L    t        t        t        t        f   t                     S )a  Get the current HTTP request headers.

    This dependency provides access to the HTTP headers for the current request,
    including the authorization header. Returns an empty dictionary when no HTTP
    request is available, making it safe to use in code that might run over any
    transport.

    Returns:
        A dependency that resolves to a dictionary of header name -> value

    Example:
        ```python
        from fastmcp.server.dependencies import CurrentHeaders

        @mcp.tool()
        async def get_auth_type(headers: dict = CurrentHeaders()) -> str:
            auth = headers.get("authorization", "")
            return "Bearer" if auth.startswith("Bearer ") else "None"
        ```
    )r   dictrA   rb  rI   rJ   rK   r,   r,   K  s    * S#X 122rJ   c                  `    e Zd ZdZed	d       Zed
d       Zedd       ZddZdddZ	ddZ
y)ProgressLikezProtocol for progress tracking interface.

    Defines the common interface between InMemoryProgress (server context)
    and Docket's Progress (worker context).
    c                     y)Current progress value.NrI   r]  s    rK   currentzProgressLike.currentn       	rJ   c                     y)Total/target progress value.NrI   r]  s    rK   totalzProgressLike.totals  rn  rJ   c                     y)Current progress message.NrI   r]  s    rK   messagezProgressLike.messagex  rn  rJ   c                   K   yw)1Set the total/target value for progress tracking.NrI   r+  rq  s     rK   	set_totalzProgressLike.set_total}  	     rG  c                   K   yw)0Atomically increment the current progress value.NrI   r+  amounts     rK   	incrementzProgressLike.increment  ry  rG  c                   K   yw#Update the progress status message.NrI   r+  rt  s     rK   set_messagezProgressLike.set_message  ry  rG  Nr   z
int | Noner   r   r   
str | Nonerq  r   r   r4     r}  r   r   r4  rt  r  r   r4  )rD   rE   rF   rG   propertyrm  rq  rt  rx  r~  r  rI   rJ   rK   rj  rj  f  sR          rJ   rj  c                  x    e Zd ZdZddZddZddZedd       Zedd       Z	edd       Z
ddZddd	Zdd
Zy)InMemoryProgressa  In-memory progress tracker for immediate tool execution.

    Provides the same interface as Docket's Progress but stores state in memory
    instead of Redis. Useful for testing and immediate execution where
    progress doesn't need to be observable across processes.
    c                .    d | _         d| _        d | _        y )Nr  )_current_total_messager]  s    rK   __init__zInMemoryProgress.__init__  s    $($(rJ   c                   K   | S wr   rI   r]  s    rK   r*  zInMemoryProgress.__aenter__  s     s   c                   K   y wr   rI   r/  s     rK   r.  zInMemoryProgress.__aexit__  rF  rG  c                    | j                   S r   )r  r]  s    rK   rm  zInMemoryProgress.current      }}rJ   c                    | j                   S r   )r  r]  s    rK   rq  zInMemoryProgress.total  s    {{rJ   c                    | j                   S r   r  r]  s    rK   rt  zInMemoryProgress.message  r  rJ   c                :   K   |dk  rt        d      || _        yw)rv  r  zTotal must be at least 1N)rU   r  rw  s     rK   rx  zInMemoryProgress.set_total  s      19788s   c                ~   K   |dk  rt        d      | j                  || _        y| xj                  |z  c_        yw)r{  r  zAmount must be at least 1N)rU   r  r|  s     rK   r~  zInMemoryProgress.increment  s8     A:899== "DMMMV#Ms   ;=c                   K   || _         ywr  r  r  s     rK   r  zInMemoryProgress.set_message  s        	N)r   r4  )r   r  r2  r  r  r  r  r  r  r  )rD   rE   rF   rG   r  r*  r.  r  rm  rq  rt  rx  r~  r  rI   rJ   rK   r  r    sa    )
      $ rJ   r  c                      e Zd ZU dZdZded<   ddZddZedd       Z	edd       Z
edd	       Zdd
ZdddZddZy)r/   a  FastMCP Progress dependency that works in both server and worker contexts.

    Handles three execution modes:
    - In Docket worker: Uses the execution's progress (observable via Redis)
    - In FastMCP server with Docket: Falls back to in-memory progress
    - In FastMCP server without Docket: Uses in-memory progress

    This allows tools to use Progress() regardless of whether they're called
    immediately or as background tasks, and regardless of whether pydocket
    is installed.
    NzProgressLike | None_implc                  K   t         j                         }| |       t        d      t               r-ddlm} 	  |       }|j                          d {   | _        | S t               | _        | S 7 # t        $ r Y w xY ww)Nz6Progress dependency requires a FastMCP server context.r   rp   )
rc   rQ   r   r8   rP   r/   r*  r  rT   r  )r+  r   DocketProgressdocket_progresss       rK   r*  zProgress.__aenter__  s     $((*
!5WXX F"0"2#2#=#=#??
 &'
 @ s:   9BA5 A3
A5 !B3A5 5	B>B BBc                   K   d | _         y wr   )r  r/  s     rK   r.  zProgress.__aexit__  s     
r  c                T    | j                   J d       | j                   j                  S )rl  %Progress must be used as a dependency)r  rm  r]  s    rK   rm  zProgress.current  *     zz%N'NN%zz!!!rJ   c                T    | j                   J d       | j                   j                  S )rp  r  )r  rq  r]  s    rK   rq  zProgress.total  s*     zz%N'NN%zzrJ   c                T    | j                   J d       | j                   j                  S )rs  r  )r  rt  r]  s    rK   rt  zProgress.message  r  rJ   c                |   K   | j                   J d       | j                   j                  |       d{    y7 w)rv  Nr  )r  rx  rw  s     rK   rx  zProgress.set_total  s4     zz%N'NN%jj""5)))   2<:<c                |   K   | j                   J d       | j                   j                  |       d{    y7 w)r{  Nr  )r  r~  r|  s     rK   r~  zProgress.increment  s4     zz%N'NN%jj""6***r  c                |   K   | j                   J d       | j                   j                  |       d{    y7 w)r  Nr  )r  r  r  s     rK   r  zProgress.set_message  s4     zz%N'NN%jj$$W---r  )r   r/   r2  r  r  r  r  r  r  r  )rD   rE   rF   rG   r  rH   r*  r.  r  rm  rq  rt  rx  r~  r  rI   rJ   rK   r/   r/     si    
 "&E%$ " "
    
 " "
*
+
.rJ   r/   c                  0    e Zd ZU dZdZded<   ddZddZy)	_CurrentAccessTokenz1Async context manager for AccessToken dependency.Nr%  r&  c                   K   t               }|Ct               }|7t        |j                  |j                         d {   | _        t               }|t        d      |S 7 "w)Nz\No access token found. Ensure authentication is configured and the request is authenticated.)r   r6   r  rC   rB   r&  r   )r+  r   r,  s      rK   r*  z_CurrentAccessToken.__aenter__  ss      "
 =(*I$4N(()*;*;5 /+ )*=4  /s   <A#A!#A#c                r   K   | j                   't        j                  | j                          d | _         y y wr   )r&  ri   r  r/  s     rK   r.  z_CurrentAccessToken.__aexit__   s3     &&2$$T%@%@A*.D' 3s   57r   r   r2  )rD   rE   rF   rG   r&  rH   r*  r.  rI   rJ   rK   r  r    s    ;?C<C*/rJ   r  c                 2    t        t        t                     S )a  Get the current access token for the authenticated user.

    This dependency provides access to the AccessToken for the current
    authenticated request. Raises an error if no authentication is present.

    Returns:
        A dependency that resolves to the active AccessToken

    Raises:
        RuntimeError: If no authenticated user (use get_access_token() for optional)

    Example:
        ```python
        from fastmcp.server.dependencies import CurrentAccessToken
        from fastmcp.server.auth import AccessToken

        @mcp.tool()
        async def get_user_id(token: AccessToken = CurrentAccessToken()) -> str:
            return token.claims.get("sub", "unknown")
        ```
    )r   r   r  rI   rJ   rK   r(   r(   &  s    , 0233rJ   c                  (    e Zd ZdZddZddZddZy)	_TokenClaimz@Dependency that extracts a specific claim from the access token.c                    || _         y r   )
claim_name)r+  r  s     rK   r  z_TokenClaim.__init__E  s	    $rJ   c           	     0  K   t               }|t        d| j                   d      |j                  j	                  | j                        }|<t        d| j                   dt        |j                  j                                      t        |      S w)Nz1No access token available. Cannot extract claim 'z'.zClaim 'z/' not found in access token. Available claims: )r   r   r  r   rQ   listr   rA   )r+  r   r   s      rK   r*  z_TokenClaim.__aenter__H  s      "=CDOOCTTVW    1=$//* +%%)%,,*;*;*=%>$?A  5zs   BBc                   K   y wr   rI   r/  s     rK   r.  z_TokenClaim.__aexit__V  rF  rG  N)r  rA   )r   rA   r2  )rD   rE   rF   rG   r  r*  r.  rI   rJ   rK   r  r  B  s    J%rJ   r  c                4    t        t        t        |             S )a|  Get a specific claim from the access token.

    This dependency extracts a single claim value from the current access token.
    It's useful for getting user identifiers, roles, or other token claims
    without needing the full token object.

    Args:
        name: The name of the claim to extract (e.g., "oid", "sub", "email")

    Returns:
        A dependency that resolves to the claim value as a string

    Raises:
        RuntimeError: If no access token is available or claim is missing

    Example:
        ```python
        from fastmcp.server.dependencies import TokenClaim

        @mcp.tool()
        async def add_expense(
            user_id: str = TokenClaim("oid"),  # Azure object ID
            amount: float,
        ):
            # user_id is automatically injected from the token
            await db.insert({"user_id": user_id, "amount": amount})
        ```
    )r   rA   r  )r   s    rK   r1   r1   Z  s    : [&''rJ   )r   zTaskContextInfo | None)rC   rA   r]   r#   r   r4  )rC   rA   r   zServerSession | None)r   bool)ro   rA   r   r4  )r   Callable[..., Any]r   r  )r   r  r   r4  r1  rW  r_  )FN)r   r  r   zset[str] | Noner   rf  )r   zAccessToken | None)r   r  r  zdict[str, Any]r   z$AsyncGenerator[dict[str, Any], None])rC   rA   rB   rA   r   r%  )rC   rA   rB   rA   r   r  r<  rH  rQ  re  r  )r   rA   r   rA   )wrG   
__future__r   r   rv   loggingr[   collections.abcr   r   r   r   contextvarsr   r	   dataclassesr
   r   r   	functoolsr   typingr   r   r   r   r   r   'mcp.server.auth.middleware.auth_contextr   r   &mcp.server.auth.middleware.bearer_authr   mcp.server.auth.providerr   _SDKAccessTokenmcp.server.lowlevel.serverr   starlette.requestsr   uncalled_forr   r   uncalled_for.resolutionr   fastmcp.exceptionsr   fastmcp.server.authfastmcp.server.httpr   fastmcp.utilities.async_utilsr   fastmcp.utilities.typesr   r    	getLoggerrD   r  rd   r!   docket.workerr"   mcp.server.sessionr#   ru   r%   rY  r'   __all__r0   r6   rY   rH   r9   r7   rc   re   rg   ri   rj   r8   r:   rP   r/   r  rl   r<   r   r2   r5   r4   r3   r=   r  r;   r  r   r"  r6  r)   r   r@  r*   rM  r.   rT  r+   r[  r-   rh  rA   rb  r,   rj  r  r  r(   r  r1   rI   rJ   rK   <module>r     sI   #     4 : ) ! '  X X E 3 & > , + + 5 D O
'

H
%$0.-> $d#3 3 $3F 9;5 :6* <Fd<8  .8$-O* O-7$-O* O5?6 2  "& ; %

 >zz0 $* #666 6rAN 4I I^ A*A*'5A*)A* A*H '''5')' '^!%B<>!j+ >!Bj)9: 8.2=
Z) $,6Z) $,4j+  ,2j) ,4jc3h0 36  8    F0  0 fC.z*% C.R/*[1 /@48*S/ 0(E$  Ns   J JJ