
    Ki                         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y)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.messagec                 :    t         |   t        d|             y )Ni )coder   )super__init__r   )selfr   	__class__s     s/home/jay/workspace/scripts/.codegraph-venv/lib/python3.12/site-packages/fastmcp/server/middleware/rate_limiting.pyr   zRateLimitError.__init__   s    @A    )zRate limit exceeded)__name__
__module____qualname____doc__strr   __classcell__)r   s   @r   r   r      s    3B B Br   r   c                   2    e Zd ZdZdedefdZd	dedefdZy)
TokenBucketRateLimiterz.Token bucket implementation for rate limiting.capacityrefill_ratec                     || _         || _        || _        t        j                         | _        t        j                         | _        y)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__   s5     !&99;ZZ\
r   r#   returnc                   K   | j                   4 d{    t        j                         }|| j                  z
  }t        | j                  | j
                  || j                  z  z         | _        || _        | j
                  |k\  r'| xj
                  |z  c_        	 ddd      d{    y	 ddd      d{    y7 7 7 	# 1 d{  7  sw Y   yxY ww)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 dmmT[[7TEUEU;U-UVDK"D{{f$v%	 	 	 	 	 	 	 	 	 	 	sc   CB?CBCC'C(C-C.C9C:CCCCCCCN)r	   )	r   r   r   r   intfloatr   boolr.    r   r   r   r      s+    8" "5 "C  r   r   c                   ,    e Zd ZdZdedefdZdefdZy)SlidingWindowRateLimiterz+Sliding window rate limiter implementation.max_requestswindow_secondsc                 p    || _         || _        t               | _        t	        j
                         | _        y)zInitialize sliding window rate limiter.

        Args:
            max_requests: Maximum requests allowed in the time window
            window_seconds: Time window in seconds
        N)r5   r6   r   requestsr&   r'   r(   )r   r5   r6   s      r   r   z!SlidingWindowRateLimiter.__init__@   s*     ),ZZ\
r   r)   c                    K   | j                   4 d{    t        j                         }|| j                  z
  }| j                  rK| j                  d   |k  r9| j                  j	                          | j                  r| j                  d   |k  r9t        | j                        | j                  k  r-| j                  j                  |       	 ddd      d{    y	 ddd      d{    y7 7 7 	# 1 d{  7  sw Y   yxY ww)zCheck if a request is allowed.Nr   TF)r(   r$   r6   r8   popleftlenr5   append)r   r,   cutoffs      r   
is_allowedz#SlidingWindowRateLimiter.is_allowedL   s     :: 	 	))+C4...F --DMM!$4v$=%%' --DMM!$4v$= 4==!D$5$55$$S)	 	 	 	 	 	 	 	 	 	 	si   DC3DA:C9>C9DC5D!C9"D-C7.D5D7D9D?D DDN)r   r   r   r   r/   r   r1   r>   r2   r   r   r4   r4   =   s$    5
"S 
"# 
"$ r   r4   c            	       n    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y)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)
        ```
    Nmax_requests_per_secondburst_capacityget_client_idglobal_limitc                      | _         |xs t        |dz         _        | _        | _        t         fd       _         j                  r&t         j                   j                          _        yy)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                  D    t         j                   j                        S N)r   rB   rA   r   s   r   <lambda>z1RateLimitingMiddleware.__init__.<locals>.<lambda>   s    *##T%A%A r   N)	rA   r/   rB   rC   rD   r   limitersr   global_limiter)r   rA   rB   rC   rD   s   `    r   r   zRateLimitingMiddleware.__init__q   sw     (?$,P4Ka4O0P*( <G<
 "8##T%A%A#D r   contextr)   c                 >    | j                   r| j                  |      S yz(Get client identifier for rate limiting.globalrC   r   rM   s     r   _get_client_identifierz-RateLimitingMiddleware._get_client_identifier       %%g..r   	call_nextc                 <  K   | j                   r/| j                  j                          d{   }|sSt        d      | j	                  |      }| j
                  |   }|j                          d{   }|st        d|        ||       d{   S 7 i7 &7 w)z Apply rate limiting to requests.NzGlobal rate limit exceededz Rate limit exceeded for client: )rD   rL   r.   r   rS   rK   )r   rM   rU   allowed	client_idlimiters         r   
on_requestz!RateLimitingMiddleware.on_request   s      //7799G$%ABB 33G<ImmI.G#OO--G$'G	{%STTw''' : . (s4   *BBAB1B2BBBBB)g      $@NNF)r   r   r   r   r0   r/   r   r   r   r1   r   rS   r
   r   rZ   r2   r   r   r@   r@   \   s    , *.%)CG"!& d
  !2 3S 89D@	
 B.? C ((9 (h (SV (r   r@   c            	       `    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y)#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)
        ```
    Nr5   window_minutesrC   c                 \     | _         |dz   _        | _        t         fd       _        y)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                  D    t         j                   j                        S rH   )r4   r5   r6   rI   s   r   rJ   z>SlidingWindowRateLimitingMiddleware.__init__.<locals>.<lambda>   s    ,T->->@S@ST r   N)r5   r6   rC   r   rK   )r   r5   r]   rC   s   `   r   r   z,SlidingWindowRateLimitingMiddleware.__init__   s4     ),r1* >IT>
r   rM   r)   c                 >    | j                   r| j                  |      S yrO   rQ   rR   s     r   rS   z:SlidingWindowRateLimitingMiddleware._get_client_identifier   rT   r   rU   c                    K   | j                  |      }| j                  |   }|j                          d{   }|s+t        d| j                   d| j
                  dz   d|        ||       d{   S 7 A7 w)z/Apply sliding window rate limiting to requests.NzRate limit exceeded: z requests per r_   z minutes for client: )rS   rK   r>   r   r5   r6   )r   rM   rU   rX   rY   rW   s         r   rZ   z.SlidingWindowRateLimitingMiddleware.on_request   s     //8	--	***,, '(9(9':.&&",--B9+O 
 w''' - (s!   4A<A8<A<3A:4A<:A<)r	   N)r   r   r   r   r/   r   r   r   r   rS   r
   r   rZ   r2   r   r   r\   r\      ss    .  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   r4   r@   r\   r2   r   r   <module>ri      sa    I  * $     ? ?BX B$ $N >K(Z K(\=(* =(r   