
    "<i                         d Z ddlZddlmZmZ ddlmZ ddlmZ ddl	Z	ddl
mZ ddlmZ dd	lmZmZmZ  G d
 de          Z G d d          Z G d d          Z G d de          Z G d de          ZdS )zCRate limiting middleware for protecting FastMCP servers from abuse.    N)defaultdictdeque)Callable)Any)McpError)	ErrorData   )CallNext
MiddlewareMiddlewareContextc                   *     e Zd ZdZddef fdZ xZS )RateLimitErrorz)Error raised when rate limit is exceeded.Rate limit exceededmessagec                 h    t                                          t          d|                     d S )Ni )coder   )super__init__r   )selfr   	__class__s     /Users/kimhansen/Desktop/03 Workspace/ceo-agents/chl-effectiveness/mcp-servers/whoop/.venv/lib/python3.11/site-packages/fastmcp/server/middleware/rate_limiting.pyr   zRateLimitError.__init__   s.    @@@AAAAA    )r   )__name__
__module____qualname____doc__strr   __classcell__)r   s   @r   r   r      s[        33B B B B B B B B B B B Br   r   c                   4    e Zd ZdZdedefdZd
dedefdZd	S )TokenBucketRateLimiterz.Token bucket implementation for rate limiting.capacityrefill_ratec                     || _         || _        || _        t          j                    | _        t          j                    | _        dS )zInitialize token bucket.

        Args:
            capacity: Maximum number of tokens in the bucket
            refill_rate: Tokens added per second
        N)r!   r"   tokenstimelast_refillanyioLock_lock)r   r!   r"   s      r   r   zTokenBucketRateLimiter.__init__   s9     !&9;;Z\\


r   r	   r$   returnc                 j  K   | j         4 d{V  t          j                    }|| j        z
  }t          | j        | j        || j        z  z             | _        || _        | j        |k    r$| xj        |z  c_        	 ddd          d{V  dS 	 ddd          d{V  dS # 1 d{V swxY w Y   dS )zTry to consume tokens from the bucket.

        Args:
            tokens: Number of tokens to consume

        Returns:
            True if tokens were available and consumed, False otherwise
        NTF)r)   r%   r&   minr!   r$   r"   )r   r$   nowelapseds       r   consumezTokenBucketRateLimiter.consume&   s}      : 	 	 	 	 	 	 	 	)++CD,,G dmT[7TEU;U-UVVDK"D{f$$v%	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	s   A+B"B""
B,/B,N)r	   )	r   r   r   r   intfloatr   boolr/    r   r   r    r       sc        88" "5 " " " " C       r   r    c                   .    e Zd ZdZdedefdZdefdZdS )SlidingWindowRateLimiterz+Sliding window rate limiter implementation.max_requestswindow_secondsc                 x    || _         || _        t                      | _        t	          j                    | _        dS )zInitialize sliding window rate limiter.

        Args:
            max_requests: Maximum requests allowed in the time window
            window_seconds: Time window in seconds
        N)r6   r7   r   requestsr'   r(   r)   )r   r6   r7   s      r   r   z!SlidingWindowRateLimiter.__init__@   s0     ),Z\\


r   r*   c                   K   | j         4 d{V  t          j                    }|| j        z
  }| j        rB| j        d         |k     r1| j                                         | j        r| j        d         |k     1t          | j                  | j        k     r.| j                            |           	 ddd          d{V  dS 	 ddd          d{V  dS # 1 d{V swxY w Y   dS )zCheck if a request is allowed.Nr   TF)r)   r%   r7   r9   popleftlenr6   append)r   r-   cutoffs      r   
is_allowedz#SlidingWindowRateLimiter.is_allowedL   s     : 	 	 	 	 	 	 	 	)++C4..F - (DM!$4v$=$=%%''' - (DM!$4v$=$= 4=!!D$555$$S)))	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	s   BCC
C #C N)r   r   r   r   r0   r   r2   r?   r3   r   r   r5   r5   =   sW        55
"S 
"# 
" 
" 
" 
"$      r   r5   c            	       v    e Zd ZdZ	 	 	 	 ddededz  deegef         dz  de	fd	Z
d
edefdZd
ededefdZdS )RateLimitingMiddlewareaK  Middleware that implements rate limiting to prevent server abuse.

    Uses a token bucket algorithm by default, allowing for burst traffic
    while maintaining a sustainable long-term rate.

    Example:
        ```python
        from fastmcp.server.middleware.rate_limiting import RateLimitingMiddleware

        # Allow 10 requests per second with bursts up to 20
        rate_limiter = RateLimitingMiddleware(
            max_requests_per_second=10,
            burst_capacity=20
        )

        mcp = FastMCP("MyServer")
        mcp.add_middleware(rate_limiter)
        ```
          $@NFmax_requests_per_secondburst_capacityget_client_idglobal_limitc                      | _         |pt          |dz             _        | _        | _        t           fd           _         j        r!t           j         j                    _        dS dS )a  Initialize rate limiting middleware.

        Args:
            max_requests_per_second: Sustained requests per second allowed
            burst_capacity: Maximum burst capacity. If None, defaults to 2x max_requests_per_second
            get_client_id: Function to extract client ID from context. If None, uses global limiting
            global_limit: If True, apply limit globally; if False, per-client
           c                  8    t           j         j                  S N)r    rD   rC   r   s   r   <lambda>z1RateLimitingMiddleware.__init__.<locals>.<lambda>   s    *#T%A  r   N)	rC   r0   rD   rE   rF   r   limitersr    global_limiter)r   rC   rD   rE   rF   s   `    r   r   zRateLimitingMiddleware.__init__q   s     (?$,P4Ka4O0P0P*( <G   <
 <
  	"8#T%A# #D	 	r   contextr*   c                 >    | j         r|                      |          S dS z(Get client identifier for rate limiting.globalrE   r   rO   s     r   _get_client_identifierz-RateLimitingMiddleware._get_client_identifier   &     	/%%g...xr   	call_nextc                 8  K   | j         r1| j                                         d{V }|st          d          nP|                     |          }| j        |         }|                                 d{V }|st          d|            ||           d{V S )z Apply rate limiting to requests.NzGlobal rate limit exceededz Rate limit exceeded for client: )rF   rN   r/   r   rU   rM   )r   rO   rW   allowed	client_idlimiters         r   
on_requestz!RateLimitingMiddleware.on_request   s       	U /7799999999G C$%ABBBC 33G<<ImI.G#OO--------G U$%S	%S%STTTYw'''''''''r   )rB   NNF)r   r   r   r   r1   r0   r   r   r   r2   r   rU   r
   r   r\   r3   r   r   rA   rA   \   s         , *.%)CG" !& d
  !2 3S 89D@	
    B.? C    ((9 (h (SV ( ( ( ( ( (r   rA   c            	       h    e Zd ZdZ	 	 ddededeegef         dz  fdZded	efd
Z	dede
d	efdZdS )#SlidingWindowRateLimitingMiddlewareaN  Middleware that implements sliding window rate limiting.

    Uses a sliding window approach which provides more precise rate limiting
    but uses more memory to track individual request timestamps.

    Example:
        ```python
        from fastmcp.server.middleware.rate_limiting import SlidingWindowRateLimitingMiddleware

        # Allow 100 requests per minute
        rate_limiter = SlidingWindowRateLimitingMiddleware(
            max_requests=100,
            window_minutes=1
        )

        mcp = FastMCP("MyServer")
        mcp.add_middleware(rate_limiter)
        ```
    r	   Nr6   window_minutesrE   c                 f     | _         |dz   _        | _        t           fd           _        dS )a
  Initialize sliding window rate limiting middleware.

        Args:
            max_requests: Maximum requests allowed in the time window
            window_minutes: Time window in minutes
            get_client_id: Function to extract client ID from context
        <   c                  8    t           j         j                  S rJ   )r5   r6   r7   rK   s   r   rL   z>SlidingWindowRateLimitingMiddleware.__init__.<locals>.<lambda>   s    ,T->@STT r   N)r6   r7   rE   r   rM   )r   r6   r_   rE   s   `   r   r   z,SlidingWindowRateLimitingMiddleware.__init__   sF     ),r1* >ITTTT>
 >
r   rO   r*   c                 >    | j         r|                      |          S dS rQ   rS   rT   s     r   rU   z:SlidingWindowRateLimitingMiddleware._get_client_identifier   rV   r   rW   c                    K   |                      |          }| j        |         }|                                 d{V }|s%t          d| j         d| j        dz   d|            ||           d{V S )z/Apply sliding window rate limiting to requests.NzRate limit exceeded: z requests per ra   z minutes for client: )rU   rM   r?   r   r6   r7   )r   rO   rW   rZ   r[   rY   s         r   r\   z.SlidingWindowRateLimitingMiddleware.on_request   s      //88	-	***,,,,,,,, 	 O(9 O O&",O OCLO O  
 Yw'''''''''r   )r	   N)r   r   r   r   r0   r   r   r   r   rU   r
   r   r\   r3   r   r   r^   r^      s         .  CG	
 

 
  !2 3S 89D@	
 
 
 
,.? C    ((9 (h (SV ( ( ( ( ( (r   r^   )r   r%   collectionsr   r   collections.abcr   typingr   r'   mcpr   	mcp.typesr   
middlewarer
   r   r   r   r    r5   rA   r^   r3   r   r   <module>rk      s   I I  * * * * * * * * $ $ $ $ $ $                    ? ? ? ? ? ? ? ? ? ?B B B B BX B B B$ $ $ $ $ $ $ $N       >K( K( K( K( K(Z K( K( K(\=( =( =( =( =(* =( =( =( =( =(r   