
    k7i.                         S r SSKrSSKrSSKrSSKJr  SSKJr  SSKrSSK	J
r
  SSKJr  SSKJr  SS	KJrJrJr   " S
 S\5      r " S S\5      rg)zFError handling middleware for consistent error responses and tracking.    N)Callable)Any)McpError)	ErrorData)NotFoundError   )CallNext
MiddlewareMiddlewareContextc            	           \ rS rSrSr    SS\R                  S-  S\S\\	\
/S4   S-  S\4S jjrS	\	S
\
SS4S jrS	\	S\	4S jrS
\
S\S\4S jrS\\\4   4S jrSrg)ErrorHandlingMiddleware   a  Middleware that provides consistent error handling and logging.

Catches exceptions, logs them appropriately, and converts them to
proper MCP error responses. Also tracks error patterns for monitoring.

Example:
    ```python
    from fastmcp.server.middleware.error_handling import ErrorHandlingMiddleware
    import logging

    # Configure logging to see error details
    logging.basicConfig(level=logging.ERROR)

    mcp = FastMCP("MyServer")
    mcp.add_middleware(ErrorHandlingMiddleware())
    ```
Nloggerinclude_tracebackerror_callbacktransform_errorsc                 ~    U=(       d    [         R                  " S5      U l        X l        X0l        X@l        0 U l        g)aM  Initialize error handling middleware.

Args:
    logger: Logger instance for error logging. If None, uses 'fastmcp.errors'
    include_traceback: Whether to include full traceback in error logs
    error_callback: Optional callback function called for each error
    transform_errors: Whether to transform non-MCP errors to McpError
zfastmcp.errorsN)logging	getLoggerr   r   r   r   error_counts)selfr   r   r   r   s        b/home/james-whalen/.local/lib/python3.13/site-packages/fastmcp/server/middleware/error_handling.py__init__ ErrorHandlingMiddleware.__init__%   s6     C 1 12B C!2, 0    errorcontextreturnc                 H   [        U5      R                  nUR                  =(       d    SnU SU 3nU R                  R	                  US5      S-   U R                  U'   SU SU SU< 3nU R
                  (       a4  U R                  R                  U S[        R                  " 5        35        OU R                  R                  U5        U R                  (       a   U R                  X5        g	g	! [         a(  nU R                  R                  SU 35         S	nAg	S	nAff = f)
z(Log error with appropriate detail level.unknown:r   r   z	Error in : 
zError in error callback: N)type__name__methodr   getr   r   r   	traceback
format_excr   	Exception)r   r   r   
error_typer&   	error_keybase_messagecallback_errors           r   
_log_error"ErrorHandlingMiddleware._log_error:   s	   %[))
,9 "l!F8,	'+'8'8'<'<Y'JQ'N)$"6("ZL5)D!!KKb1E1E1G0HIJKKl+ P##E3   P!!$=n=M"NOOPs   C/ /
D!9DD!c                    [        U[        5      (       a  U$ U R                  (       d  U$ [        U5      nU[        [
        4;   a  [        [        SSU< 3S95      $ U[        [        [        4;   a  [        [        SSU< 3S95      $ U[        L a  [        [        SSU< 3S95      $ U[        [        R                  4;   a  [        [        SSU< 3S95      $ [        [        S	S
U< 3S95      $ )z.Transform non-MCP errors to proper MCP errors.izInvalid params: )codemessageizResource not found: i zPermission denied: zRequest timeout: izInternal error: )
isinstancer   r   r$   
ValueError	TypeErrorr   FileNotFoundErrorKeyErrorr   PermissionErrorTimeoutErrorasyncio)r   r   r+   s      r   _transform_error(ErrorHandlingMiddleware._transform_errorQ   s   eX&&L$$L %[
*i00v1A%/KL  -xGGv1EeY/OP  ?*v1DUI/NO  L'*>*>??v1B5)/LM  v1A%/KL r   	call_nextc                    #     U" U5      I Sh  vN $  N! [          a)  nU R                  X15        U R                  U5      nXCeSnAff = f7f)zHandle errors for all messages.N)r*   r/   r<   )r   r   r>   r   transformed_errors        r   
on_message"ErrorHandlingMiddleware.on_messager   sO     	/"7++++ 	/OOE+ !% 5 5e <#.	/s0   A  A 
A	$AA		Ac                 6    U R                   R                  5       $ )z$Get error statistics for monitoring.)r   copy)r   s    r   get_error_stats'ErrorHandlingMiddleware.get_error_stats}   s      %%''r   )r   r   r   r   r   )NFNT)r%   
__module____qualname____firstlineno____doc__r   Loggerboolr   r*   r   r   r/   r<   r	   r   rA   dictstrintrE   __static_attributes__ r   r   r   r      s    ( )-"'PT!%%   !)->!?!EFM	
 *P	 P4E P$ P.i I B	/(9 	/h 	/SV 	/(c3h (r   r   c                       \ rS rSrSrSSSS\\4S4S\S	\S
\S\S\	\
\   S4   S\R                  S-  4S jjrS\S\4S jrS\S\4S jrS\S\S\4S jrSrg)RetryMiddleware   a1  Middleware that implements automatic retry logic for failed requests.

Retries requests that fail with transient errors, using exponential
backoff to avoid overwhelming the server or external dependencies.

Example:
    ```python
    from fastmcp.server.middleware.error_handling import RetryMiddleware

    # Retry up to 3 times with exponential backoff
    retry_middleware = RetryMiddleware(
        max_retries=3,
        retry_exceptions=(ConnectionError, TimeoutError)
    )

    mcp = FastMCP("MyServer")
    mcp.add_middleware(retry_middleware)
    ```
   g      ?g      N@g       @Nmax_retries
base_delay	max_delaybackoff_multiplierretry_exceptions.r   c                     Xl         X l        X0l        X@l        XPl        U=(       d    [
        R                  " S5      U l        g)as  Initialize retry middleware.

Args:
    max_retries: Maximum number of retry attempts
    base_delay: Initial delay between retries in seconds
    max_delay: Maximum delay between retries in seconds
    backoff_multiplier: Multiplier for exponential backoff
    retry_exceptions: Tuple of exception types that should trigger retries
    logger: Logger for retry attempts
zfastmcp.retryN)rV   rW   rX   rY   rZ   r   r   r   )r   rV   rW   rX   rY   rZ   r   s          r   r   RetryMiddleware.__init__   s7    & '$""4 0B 1 1/ Br   r   r   c                 ,    [        XR                  5      $ )z-Determine if an error should trigger a retry.)r4   rZ   )r   r   s     r   _should_retryRetryMiddleware._should_retry   s    %!6!677r   attemptc                 d    U R                   U R                  U-  -  n[        X R                  5      $ )z-Calculate delay for the given attempt number.)rW   rY   minrX   )r   r`   delays      r   _calculate_delay RetryMiddleware._calculate_delay   s*    4#:#:G#CD5..))r   r   r>   c                 ,  #    Sn[        U R                  S-   5       H  n U" U5      I Sh  vN s  $    U(       a  Ueg N! [         a  nUnX@R                  :X  d  U R                  U5      (       d   SnA  MD  U R	                  U5      nU R
                  R                  SUR                   SUS-    SU R                  S-    S[        U5      R                   SU< SUS	 S
35        [        R                  " U5      I Sh  vN     SnAM  SnAff = f7f)z#Implement retry logic for requests.Nr   zRequest z failed (attempt /z): r"   z. Retrying in z.1fzs...)rangerV   r*   r^   rd   r   warningr&   r$   r%   anyiosleep)r   r   r>   
last_errorr`   r   rc   s          r   
on_requestRetryMiddleware.on_request   s    
T--12G)&w/// 3&  # 0 )"
 ...d6H6H6O6O--g6##w~~..?!}AdN^N^abNbMccfE{++,Bui~eC[PTV
 kk%((()sT   DA?ADA
D'D2D9BD DDDDD)rY   rW   r   rX   rV   rZ   )r%   rG   rH   rI   rJ   ConnectionErrorr:   rO   floattupler$   r*   r   rK   r   rL   r^   rd   r   r	   r   rm   rP   rQ   r   r   rS   rS      s    , $'9H,8W(,CC C 	C
 "C  Y 45C %C489 8 8* * *
(9 h SV r   rS   )rJ   r;   r   r(   collections.abcr   typingr   rj   mcpr   	mcp.typesr   fastmcp.exceptionsr   
middlewarer	   r
   r   r   rS   rQ   r   r   <module>rx      sF    L    $     , ? ?m(j m(`Pj Pr   