
    kKjU                     ~   U d Z ddlZddlmZ ddlmZ ddlmZ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 dd
lmZ ddlmZ ddlmZ ddlmZmZmZ ddlmZm Z m!Z! ddl"m#Z#m$Z$m%Z% ddl&m'Z' ddl(m)Z)m*Z*m+Z+ ddl,m-Z-m.Z. ddl/m0Z0 ddl1m2Z2  e0e3      Z4ee5d<   dZ6dZ7dZ8dZ9 G d de2      Z: G d de2      Z; G d d e2      Z< G d! d"e2      Z= G d# d$e2      Z> G d% d&e      Z? G d' d(e?      Z@ G d) d*e?      ZA G d+ d,e?      ZB G d- d.e?      ZC G d/ d0e?      ZD G d1 d2e?      ZE G d3 d4e2      ZF G d5 d6e*      ZGd7eHeIef   dz  d8eIfd9ZJd:eId8eIfd;ZKd8eIfd<ZLe9fd=e
j                  j                  d>eId8eIfd?ZOe9fd=e
j                  j                  d>eId8eIfd@ZQe9fd=e
j                  j                  d>eId8eIfdAZSy)Bz"A middleware for response caching.    N)Sequence)Logger)Any	TypedDict)PydanticAdapter)AsyncKeyValue)MemoryStore)LimitSizeWrapper)StatisticsWrapper)KVStoreCollectionStatistics)Field)NotRequiredSelfoverride)MessagePromptPromptResult)ResourceResourceContentResourceResult)get_access_token)CallNext
MiddlewareMiddlewareContext)Tool
ToolResult)
get_logger)FastMCPBaseModel)nameloggeri  i,  i   __anonymous__c                   T    e Zd ZU dZeez  ed<   dZedz  ed<   dZe	ee
f   dz  ed<   y)CachableResourceContentz1A wrapper for ResourceContent that can be cached.contentN	mime_typemeta)__name__
__module____qualname____doc__strbytes__annotations__r%   r&   dictr        r/Users/ahmed/devFolder/Ultron/claude-voice/.venv/lib/python3.12/site-packages/fastmcp/server/middleware/caching.pyr#   r#   (   s4    ;5[ IsTz "&D$sCx.4
&r0   r#   c                   r    e Zd ZU dZee   ed<   dZee	e
f   dz  ed<   defdZededefd       Zdefd	Zy)
CachableResourceResultz0A wrapper for ResourceResult that can be cached.contentsNr&   returnc                 4    t        | j                               S Nlenmodel_dump_jsonselfs    r1   get_sizezCachableResourceResult.get_size6       4'')**r0   valuec           
           | |j                   D cg c].  }t        |j                  |j                  |j                        0 c}|j                        S c c}w N)r$   r%   r&   )r4   r&   )r4   r#   r$   r%   r&   )clsr?   items      r1   wrapzCachableResourceResult.wrap9   sZ    
 "NN	 +D ( LLDNN +	 
 	
s   3Ac           
          t        | j                  D cg c].  }t        |j                  |j                  |j
                        0 c}| j
                        S c c}w rA   )r   r4   r   r$   r%   r&   )r<   rC   s     r1   unwrapzCachableResourceResult.unwrapE   sZ    
 !MM	 *D   LLDNN *	 
 	
s   3A)r'   r(   r)   r*   listr#   r-   r&   r.   r+   r   intr=   classmethodr   r   rD   rF   r/   r0   r1   r3   r3   0   sb    :*++"&D$sCx.4
&+# + 	
 	
D 	
 	
	
 	
r0   r3   c                       e Zd ZU eej
                  j                     ed<   ee	e
f   dz  ed<   ee	e
f   dz  ed<   dZeed<   ededefd	       Zdefd
Zy)CachableToolResultr$   Nstructured_contentr&   Fis_errorr?   r5   c                 j     | |j                   |j                  |j                  |j                        S Nr$   rL   r&   rM   rP   )rB   r?   s     r1   rD   zCachableToolResult.wrapW   s-    MM$77^^	
 	
r0   c                 p    t        | j                  | j                  | j                  | j                        S rO   )r   r$   rL   r&   rM   r;   s    r1   rF   zCachableToolResult.unwrap`   s-    LL#66]]	
 	
r0   )r'   r(   r)   rG   mcptypesContentBlockr-   r.   r+   r   rM   boolrI   r   r   rD   rF   r/   r0   r1   rK   rK   Q   ss    #))(())S#X--
sCx.4
Hd
 
 
 


 
r0   rK   c                       e Zd ZU dZeed<   ej                  j                  ej                  j                  z  ej                  j                  z  ej                  j                  z  ed<   y)CachableMessagez)A wrapper for Message that can be cached.roler$   N)r'   r(   r)   r*   r+   r-   rR   rS   TextContentImageContentAudioContentEmbeddedResourcer/   r0   r1   rW   rW   i   sT    3
I		
))
 
 	!
))
 
 	! ))
$
$	%r0   rW   c                       e Zd ZU dZee   ed<   dZedz  ed<   dZ	e
eef   dz  ed<   defdZededefd	       Zdefd
Zy)CachablePromptResultz.A wrapper for PromptResult that can be cached.messagesNdescriptionr&   r5   c                 4    t        | j                               S r7   r8   r;   s    r1   r=   zCachablePromptResult.get_size|   r>   r0   r?   c           	           | |j                   D cg c]#  }t        |j                  |j                        % c}|j                  |j
                        S c c}w )N)rX   r$   r_   r`   r&   )r_   rW   rX   r$   r`   r&   )rB   r?   ms      r1   rD   zCachablePromptResult.wrap   sP    INIWAQVVQYY? ))
 	
s   (Ac           	          t        | j                  D cg c]#  }t        |j                  |j                        % c}| j
                  | j                        S c c}w )N)r$   rX   rc   )r   r_   r   r$   rX   r`   r&   )r<   rd   s     r1   rF   zCachablePromptResult.unwrap   sV     &A 		7& ((
 	
s   (A)r'   r(   r)   r*   rG   rW   r-   r`   r+   r&   r.   r   rH   r=   rI   r   r   rD   rF   r/   r0   r1   r^   r^   u   so    8?##"Kt""&D$sCx.4
&+# + 
 
$ 
 

 
r0   r^   c                   2    e Zd ZU dZee   ed<   ee   ed<   y)SharedMethodSettingsz!Shared config for a cache method.ttlenabledN)r'   r(   r)   r*   r   rH   r-   rU   r/   r0   r1   rg   rg      s    +	S	r0   rg   c                       e Zd ZdZy)ListToolsSettings/Configuration options for Tool-related caching.Nr'   r(   r)   r*   r/   r0   r1   rk   rk      s    9r0   rk   c                       e Zd ZdZy)ListResourcesSettings3Configuration options for Resource-related caching.Nrm   r/   r0   r1   ro   ro          =r0   ro   c                       e Zd ZdZy)ListPromptsSettings1Configuration options for Prompt-related caching.Nrm   r/   r0   r1   rs   rs          ;r0   rs   c                   >    e Zd ZU dZeee      ed<   eee      ed<   y)CallToolSettingsrl   included_toolsexcluded_toolsN)r'   r(   r)   r*   r   rG   r+   r-   r/   r0   r1   rw   rw      s#    9S	**S	**r0   rw   c                       e Zd ZdZy)ReadResourceSettingsrp   Nrm   r/   r0   r1   r{   r{      rq   r0   r{   c                       e Zd ZdZy)GetPromptSettingsrt   Nrm   r/   r0   r1   r}   r}      ru   r0   r}   c                       e Zd ZU  ed      Zedz  ed<    ed      Zedz  ed<    ed      Zedz  ed<    ed      Z	edz  ed<    ed      Z
edz  ed<    ed      Zedz  ed<   y)	ResponseCachingStatisticsN)default
list_toolslist_resourceslist_promptsread_resource
get_prompt	call_tool)r'   r(   r)   r   r   r   r-   r   r   r   r   r   r/   r0   r1   r   r      s    5:45HJ+d2H9>t9LN/$6L7<T7JL-4J8=d8KM.5K5:45HJ+d2H49$4GI*T1Gr0   r   c                      e Zd ZdZdddddddefdedz  dedz  dedz  dedz  de	dz  de
dz  d	edz  d
efdZedeej"                  j$                     deej"                  j$                  ee   f   dee   fd       Zedeej"                  j.                     deej"                  j.                  ee   f   dee   fd       Zedeej"                  j4                     deej"                  j4                  ee   f   dee   fd       Zedeej"                  j:                     deej"                  j:                  ef   defd       Zedeej"                  j@                     deej"                  j@                  e!f   de!fd       Z"edeej"                  jF                     deej"                  jF                  e$f   de$fd       Z%de&de'fdZ(de)fdZ*y)ResponseCachingMiddlewarea   The response caching middleware offers a simple way to cache responses to mcp methods. The Middleware
    supports cache invalidation via notifications from the server. The Middleware implements TTL-based caching
    but cache implementations may offer additional features like LRU eviction, size limits, and more.

    When items are retrieved from the cache they will no longer be the original objects, but rather no-op objects
    this means that response caching may not be compatible with other middleware that expects original subclasses.

    Notes:
    - Caches `tools/call`, `resources/read`, `prompts/get`, `tools/list`, `resources/list`, and `prompts/list` requests.
    - Cache keys are derived from the method name, arguments, and the caller's
      access token. Entries are partitioned per-token so that responses filtered
      by per-component authorization (e.g. `auth=require_scopes(...)`) cannot
      leak across users with different permissions. Unauthenticated callers
      (including STDIO) share a single anonymous partition.
    Ncache_storagelist_tools_settingslist_resources_settingslist_prompts_settingsread_resource_settingsget_prompt_settingscall_tool_settingsmax_item_sizec	                 4   |xs
 t               | _        t        | j                  |d      | _        t	        | j                        | _        |xs
 t               | _        |xs
 t               | _	        |xs
 t               | _        |xs
 t               | _        |xs
 t               | _        |xs
 t!               | _        t%        | j
                  t&        t(           d      | _        t%        | j
                  t&        t,           d      | _        t%        | j
                  t&        t0           d      | _        t%        | j
                  t4        d      | _        t%        | j
                  t8        d	      | _        t%        | j
                  t<        d
      | _        y)a  Initialize the response caching middleware.

        Args:
            cache_storage: The cache backend to use. If None, an in-memory cache is used.
            list_tools_settings: The settings for the list tools method. If None, the default settings are used (5 minute TTL).
            list_resources_settings: The settings for the list resources method. If None, the default settings are used (5 minute TTL).
            list_prompts_settings: The settings for the list prompts method. If None, the default settings are used (5 minute TTL).
            read_resource_settings: The settings for the read resource method. If None, the default settings are used (1 hour TTL).
            get_prompt_settings: The settings for the get prompt method. If None, the default settings are used (1 hour TTL).
            call_tool_settings: The settings for the call tool method. If None, the default settings are used (1 hour TTL).
            max_item_size: The maximum size of items eligible for caching. Defaults to 1MB.
        F)	key_valuemax_sizeraise_on_too_large)r   
tools/list)r   pydantic_modeldefault_collectionresources/listprompts/listresources/readprompts/get
tools/callN) r	   _backendr
   _size_limiterr   _statsrk   _list_tools_settingsro   _list_resources_settingsrs   _list_prompts_settingsr{   _read_resource_settingsr}   _get_prompt_settingsrw   _call_tool_settingsr   rG   r   _list_tools_cacher   _list_resources_cacher   _list_prompts_cacher3   _read_resource_cacher^   _get_prompt_cacherK   _call_tool_cache)	r<   r   r   r   r   r   r   r   r   s	            r1   __init__z"ResponseCachingMiddleware.__init__   s   0 (5'E 0@mmmPU0
 *;TEWEW)X  6#4#6 	! $>'<'> 	% ":%8%: 	#
 #<&:&< 	$  6#4#6 	! 4"2"4 	  ?Nkk:+?
 GVkk>/G
" CRkk<-C
  ++5#3 	! IXkk/,I
 FUkk-+F
r0   context	call_nextr5   c                 n  K   | j                   j                  d      du r ||       d{   S t               }| j                  j                  |       d{   x}r|S  ||       d{   }|D cg c]e  }t	        |j
                  |j                  |j                  |j                  |j                  |j                  |j                  |j                        g }}| j                  j                  ||| j                   j                  dt                     d{    |S 7 7 7 c c}w 7 w)zList tools from the cache, if caching is enabled, and the result is in the cache. Otherwise,
        otherwise call the next middleware and store the result in the cache if caching is enabled.ri   FNkey)r   titler`   
parametersoutput_schemaannotationsr&   tagsrh   r   r?   rh   )r   get_get_auth_partition_keyr   r   r   r   r`   r   r   r   r&   r   putFIVE_MINUTES_IN_SECONDS)r<   r   r   	cache_keycached_valuetoolstoolcachable_toolss           r1   on_list_toolsz'ResponseCachingMiddleware.on_list_tools*  s;     $$((3u<"7+++02	!%!7!7!;!;	!;!JJJ<J&/&8 8 &
  YYjj ,,??"00 ,,YYYY	  	 &
 $$(( ))--e5LM ) 
 	
 	
 = , K !9&
	
S   )D5D(-D5D*D5-D,.D56A*D. AD5!D3"D5*D5,D5.D5c                 n  K   | j                   j                  d      du r ||       d{   S t               }| j                  j                  |       d{   x}r|S  ||       d{   }|D cg c]e  }t	        |j
                  |j                  |j                  |j                  |j                  |j                  |j                  |j                        g }}| j                  j                  ||| j                   j                  dt                     d{    |S 7 7 7 c c}w 7 w)zList resources from the cache, if caching is enabled, and the result is in the cache. Otherwise,
        otherwise call the next middleware and store the result in the cache if caching is enabled.ri   FNr   )r   r   r`   r   r&   r%   r   urirh   r   )r   r   r   r   r   r   r   r`   r   r&   r%   r   r   r   r   )r<   r   r   r   r   	resourcesresourcecachable_resourcess           r1   on_list_resourcesz+ResponseCachingMiddleware.on_list_resourcesS  s<     ((,,Y75@"7+++02	!%!;!;!?!?I!?!NNN<N.7.@(@	 &.
 & ]]nn$00]]]]",,$00LL	 & 	 .
 ((,,$--11%9PQ - 
 	
 	
 "!= , O )A.
	
r   c                 B  K   | j                   j                  d      du r ||       d{   S t               }| j                  j                  |       d{   x}r|S  ||       d{   }|D cg c]O  }t	        |j
                  |j                  |j                  |j                  |j                  |j                        Q }}| j                  j                  ||| j                   j                  dt                     d{    |S 7 7 7 c c}w 7 w)zList prompts from the cache, if caching is enabled, and the result is in the cache. Otherwise,
        otherwise call the next middleware and store the result in the cache if caching is enabled.ri   FNr   )r   r   r`   r   r&   	argumentsrh   r   )r   r   r   r   r   r   r   r`   r   r&   r   r   r   )r<   r   r   r   r   promptspromptcachable_promptss           r1   on_list_promptsz)ResponseCachingMiddleware.on_list_prompts|  s+     &&**95>"7+++02	!%!9!9!=!=)!=!LLL<L*3G*<$< "
*
 " [[ll"..[[[[ ** " 	 
*
 &&**"++//7NO + 
 	
 	
  9 , M %=
*
	
sS   )DD-DDD-D.D6AD
ADDDDDDc                 b  K   |j                   j                  }| j                  j                  d      du s| j	                  |      s ||       d{   S t        |j                   t                     }| j                  j                  |       d{   x}r|j                         S  ||       d{   }t        j                  |      }| j                  j                  ||| j                  j                  dt              	       d{    |j                         S 7 7 7 r7 w)
zCall a tool from the cache, if caching is enabled, and the result is in the cache. Otherwise,
        otherwise call the next middleware and store the result in the cache if caching is enabled.ri   F)	tool_nameNmsgauth_keyr   r?   rh   r   )messager   r   r   _matches_tool_cache_settings_make_call_tool_cache_keyr   r   rF   rK   rD   r   ONE_HOUR_IN_SECONDS)r<   r   r   r   r   r   tool_resultcachable_tool_results           r1   on_call_toolz&ResponseCachingMiddleware.on_call_tool  s1     OO((	##''
;;i;P"7+++2*A*C
	 "&!6!6!:!:y!:!III<I&&(((1'(:":3E3J3J 4K 4
 ##''&((,,U4GH ( 
 	
 	
 $**,,) , J #;
	
sJ   AD/D'AD/D)!D/8D+9AD/D-D/)D/+D/-D/c                   K   | j                   j                  d      du r ||       d{   S t        |j                  t	                     }| j
                  j                  |       d{   x}r|j                         S  ||       d{   }t        j                  |      }| j
                  j                  ||| j                   j                  dt                     d{    |j                         S 7 7 7 q7 w)zRead a resource from the cache, if caching is enabled, and the result is in the cache. Otherwise,
        otherwise call the next middleware and store the result in the cache if caching is enabled.ri   FNr   r   rh   r   )r   r   _make_read_resource_cache_keyr   r   r   rF   r3   rD   r   r   r<   r   r   r   r   r?   s         r1   on_read_resourcez*ResponseCachingMiddleware.on_read_resource  s      ''++I6%?"7+++6*A*C
	
 "&!:!:!>!>9!>!MMM<M&&((&/&8 8-2259''++,,008KL , 
 	
 	
 ""$$' , N !9	
G   )DC>AD.D /!DDAD)D*D DDDc                   K   | j                   j                  d      du r ||       d{   S t        |j                  t	                     }| j
                  j                  |       d{   x}r|j                         S  ||       d{   }t        j                  |      }| j
                  j                  ||| j                   j                  dt                     d{    |j                         S 7 7 7 q7 w)zGet a prompt from the cache, if caching is enabled, and the result is in the cache. Otherwise,
        otherwise call the next middleware and store the result in the cache if caching is enabled.ri   FNr   r   rh   r   )r   r   _make_get_prompt_cache_keyr   r   r   rF   r^   rD   r   r   r   s         r1   on_get_promptz'ResponseCachingMiddleware.on_get_prompt  s      $$((3u<"7+++3*A*C
	 "&!7!7!;!;	!;!JJJ<J&&(($-g$66+007$$(())--e5HI ) 
 	
 	
 ""$$% , K 7	
r   r   c                     | j                   j                  d      x}r||vry| j                   j                  d      x}r||v ryy)z<Check if the tool matches the cache settings for tool calls.rx   Fry   T)r   r   )r<   r   rx   ry   s       r1   r   z6ResponseCachingMiddleware._matches_tool_cache_settings  sW     "5599:JKK>K.!5599:JKK>KN*r0   c           
      @   t        | j                  j                  j                  j	                  d      | j                  j                  j                  j	                  d      | j                  j                  j                  j	                  d      | j                  j                  j                  j	                  d      | j                  j                  j                  j	                  d      | j                  j                  j                  j	                  d            S )z!Get the statistics for the cache.r   r   r   r   r   r   )r   r   r   r   r   r   )r   r   
statisticscollectionsr   r;   s    r1   r   z$ResponseCachingMiddleware.statistics  s    ({{--99==lK;;11==AABRS//;;??O++00<<@@AQR{{--99==mLkk,,88<<\J
 	
r0   )+r'   r(   r)   r*   ONE_MB_IN_BYTESr   rk   ro   rs   r{   r}   rw   rH   r   r   r   rR   rS   ListToolsRequestr   r   r   r   ListResourcesRequestr   r   ListPromptsRequestr   r   CallToolRequestParamsr   r   ReadResourceRequestParamsr   r   GetPromptRequestParamsr   r   r+   rU   r   r   r   r/   r0   r1   r   r      s   $ /38<@D<@>B8<6:,X
$t+X
 /5X
 "7!=	X

  3T9X
 !5t ;X
 /5X
 -t3X
 X
t &"399#=#=>& CII66FG& 
$	& &P &""399#A#AB&" CII::HX<NNO&" 
(		&" &"P $ "399#?#?@$  CII88(6:JJK$  
&		$  $ L  -"399#B#BC - CII;;ZGH - 
	 -  -D %"399#F#FG% CII??OP% 
	% %: %"399#C#CD% CII<<lJK% 
	% %8c d 	
5 	
r0   r   r   r5   c                     | y	 t        j                  | t              j                         S # t        $ r t        |       cY S w xY w)z-Get a string representation of the arguments.null)r?   fallback)pydantic_coreto_jsonr+   decode	TypeErrorrepr)r   s    r1   _get_arguments_strr     sG     $$9sCJJLL Is   (. AAr?   c                 d    t        j                  | j                               j                         S )zBBuild a fixed-length SHA-256 cache key from request-derived input.)hashlibsha256encode	hexdigestr   s    r1   _hash_cache_keyr   '  s"     >>%,,.)3355r0   c                  P    t               } | t        S t        | j                        S )af  Return a stable, hashed identifier for the current access token.

    Cache entries are partitioned by access token so that responses filtered
    by per-component authorization (e.g. `auth=require_scopes(...)`) are not
    leaked across users with different permissions. Unauthenticated callers
    (including STDIO) share a single anonymous partition.
    )r   ANONYMOUS_AUTH_KEYr   token)r   s    r1   r   r   -  s&     E}!!5;;''r0   r   r   c           	      b    t        | d| j                   dt        | j                               S )zKMake a cache key for a tool call using a stable hash of name and arguments.:r   r   r   r   r   s     r1   r   r   <  /    
 hZq
!4Fs}}4U3VWXXr0   c                 6    t        | d| j                         S )z@Make a cache key for a resource read using a stable hash of URI.r  )r   r   r   s     r1   r   r   D  s    
 hZq	233r0   c           	      b    t        | d| j                   dt        | j                               S )zLMake a cache key for a prompt get using a stable hash of name and arguments.r  r  r   s     r1   r   r   L  r  r0   )Tr*   r   collections.abcr   loggingr   typingr   r   	mcp.typesrR   r   key_value.aio.adapters.pydanticr   !key_value.aio.protocols.key_valuer   key_value.aio.stores.memoryr	   !key_value.aio.wrappers.limit_sizer
   !key_value.aio.wrappers.statisticsr   )key_value.aio.wrappers.statistics.wrapperr   pydanticr   typing_extensionsr   r   r   fastmcp.prompts.baser   r   r   fastmcp.resources.baser   r   r   fastmcp.server.dependenciesr   $fastmcp.server.middleware.middlewarer   r   r   fastmcp.tools.baser   r   fastmcp.utilities.loggingr   fastmcp.utilities.typesr   r'   r    r-   r   r   r   r   r#   r3   rK   rW   r^   rg   rk   ro   rs   rw   r{   r}   r   r   r.   r+   r   r   r   rS   r   r   r   r   r   r   r/   r0   r1   <module>r     s   (  $  !   ; ; 3 > ?  9 9 > > L L 8 X X / 0 4* *   $ '. '
- 
B
) 
0	& 	
+ 
>9 :, :>0 ><. <++ +>/ ><, <H 0 HX

 X
v

$sCx.4"7 
C 
63 63 6( (  ;MY		(	(Y47YY ?Q4		,	,48;44 <NY		)	)Y58YYr0   