xjCUdZddlmZddlZddlZddlZddlmZddlm Z ddl m Z m Z m Z mZddlZddlZddlmZmZmZmZmZmZddlmZgd Zej6eZe d Z d Zd e d < e ddGddZ!e ddGddZ"GddeZ#e ddGddZ$GddZ%dZ&d e d< dZ'de d< Gdd Z(y)!zQClient-side response caching primitives (SEP-2549, protocol revision 2026-07-28).) annotationsN)Callable) dataclass)AnyFinalLiteralProtocol)CacheableResultPromptListChangedNotificationResourceListChangedNotificationResourceUpdatedNotificationServerNotificationToolListChangedNotification)MODERN_PROTOCOL_VERSIONS) MAX_TTL_MS CacheConfig CacheEntryCacheKey CacheModeInMemoryResponseCacheStoreResponseCacheStore)userefreshbypassi\&z Final[int]rT)frozenslotsc:eZdZUdZded<dZded< dZded<y)rziIdentity of one cached response; compare as the field tuple, never a flattened string (collision hazard).strmethod params_key partitionN)__name__ __module__ __qualname____doc____annotations__r!r"f/mnt/ssd/data/Dropbox/adrian/sandbox/mcp-query/venv/lib/python3.12/site-packages/mcp/client/caching.pyrr,s$s KJiIs@r)rc4eZdZUdZded< ded< ded<y) rzrAr(r)r*rrGsAF6&r)rceZdZUdZdZded< dZded< dZded < d Zd ed < e jZ d ed< dZ ded< ddZ y)rzConfiguration for a `Client`'s response cache. Raises: ValueError: On a custom `store` without `partition`, an empty `target_id`, or a negative `default_ttl_ms`. NzResponseCacheStore | Nonestorer rr"z str | None target_idrintdefault_ttl_msCallable[[], float]clockFbool share_publicc|j|js td|jdk(r td|jdkrtd|jy)Nz-a custom store requires an explicit partitionr z/target_id must be a non-empty string or omittedrz!default_ttl_ms must be >= 0, got )rIr" ValueErrorrJrLr@s r* __post_init__zCacheConfig.__post_init__~sc :: !$..LM M >>R NO O    "@ATAT@UVW W #r)rG) r#r$r%r&rIr'r"rJrLtimerNrPrSr(r)r*rr[st (,E $+8IsF !Iz JNCi!%E *QL$R Xr)rc>eZdZdZddd dZd dZd dZd dZddZy )raDefault in-process `ResponseCacheStore`. Method bodies are synchronous, so concurrent tasks never observe a torn write. `max_entries` caps the whole store, evicting least-recently-used at the cap (`0` disables it); `get` and `set` both refresh recency, so a hot entry survives churn from other keys. Raises: ValueError: If `max_entries` is negative. i) max_entriescF|dkrtd|||_i|_y)Nrzmax_entries must be >= 0, got )rR _max_entries_entries)r4rVs r*__init__z#InMemoryResponseCacheStore.__init__s+ ?=k]KL L'46 r)cK|jj|}|(|jj||j|<|Swr2)rYr6popr:s r*r6zInMemoryResponseCacheStore.getsB !!#&  !%!2!23!7DMM#  sAA cK|jj|d||j|<|jrMt|j|jkDr*|jt t |j=yyywr2)rYr\rXlennextiterr:s r*r<zInMemoryResponseCacheStore.setsj #t$" c   T]]!3d6G6G!G d4 #678"H sBBcDK|jj|dywr2)rYr\r3s r*r>z!InMemoryResponseCacheStore.deletes #t$s c@K|jjywr2)rYrAr@s r*rAz InMemoryResponseCacheStore.clears sN)rVrKrCrErBrDrFrG) r#r$r%r&rZr6r<r>rAr(r)r*rrs% .27 9 %r)ri_GENERATION_MAP_CAPz Final[float]_STORE_CLEANUP_TIMEOUTceZdZdZeed ddZddZddZddZ ddZ ddZ dd Z dd Z dd Zdd Zdd ZddZddZd dZd!dZy)"ClientResponseCachezhCoordinates the `Client` caching verbs with a `ResponseCacheStore`: keys, era gate, TTL/scope, eviction.)generation_map_capstore_cleanup_timeoutc ||_||_||_||_||_||_||_i|_||_| |_ t|_ yr2) _store _partition_arm_id _share_public_default_ttl_ms_clock_negotiated_version _generations_generation_map_cap_store_cleanup_timeoutr<_warned_store_ops) r4rIr"arm_idrLrNrPnegotiated_versionrhris r*rZzClientResponseCache.__init__sZ # )- #5 8:#5 &;#+.5r)c||j|jg}|dk(s |js|j|jt j |S)Nprivate)rqrmrnappendrljsondumps)r4r.fieldss r*_armzClientResponseCache._armsL %*4+C+C+Et||#T I T%7%7 MM$// *zz&!!r)c Ktjjd{ |jt |||j dd{}|F|jt |||j dd{}||j dk7rd}|dn|jjd}|jjd|S777X#t$r|jdYywxYww)zMServe a fresh entry for the key, or `None`; the served result is a deep copy.NrypublicTdeepr6) anyiolowlevel checkpoint _get_freshrr~r.r, model_copy Exception_warn_store_failurerudiscard)r4rr!r;copieds r*readzClientResponseCache.readsnn''))) //(6:tyyQZG[*\]]E}"oohvz499U]K^._``$)@ E5:]T H^H^dhH^HiF &&u-  *^a    $ $U + sV"DC"D.C(C$4C( C&7C(D$C(&C((DDDDcK|jj|d{}|)|j|j|jkry|S72wr2)rkr6r/rpr:s r*rzClientResponseCache._get_freshsKkkooc** =E,,48H8HDKKM8Y +sAA3Ac||f}||jvrZt|j|jk\r)|jtt |j=d|j|<|j|S)zeRegister the key for eviction-race detection before the fetch; `write` takes the returned generation.r)rrr^rsr_r`r4rr!gen_keys r*capturezClientResponseCache.capturesr:& $++ +4$$%)A)AA%%d40A0A+B&CD)*D  g &  ))r)cBK||f}|j||ry|j|\}}t|||jd} t|||jd} |dkr |dk(r|j | | d{y|dk(r| | fn| | f\} } |j | d{s|j | d{yt |jd||j|dz z } |j| | d{s|j | d{|j||r|j | d{yy7777P797#|j||r|j | d{7wwxYww) z@Store a fetched result under the arm its resolved scope selects.NryrrrTri)r,r.r/) _generation_moved_resolverr~_cleanup_delete_deleterrrp_set)r4rr!resultgen_at_capturemoderttl_msr. private_key public_keyownoppositer;s r*writezClientResponseCache.writes:&  ! !'> :  f- vz499Y3GH fj$))H2EF Q;y **; CCC 5:h5F[1[ZdLe X\\(+++&&s+ + + !2!2!2!=UW[WbWbWdgmptgtWtu 03...**3/// %%g~>**3///?%D, +/0 0%%g~>**3///?sBFE!)F/E#0FE% 7FE-E'E-/E)0E-4&FE+F#F%F'E-)E-+F-'FFFFcDK|j|dd{y7w)z%Evict the method's cursor-less entry.r N) evict_key)r4rs r* evict_methodz ClientResponseCache.evict_method)snnVR(((s   c K||f}||jvr|j|xxdz cc<|jt|||jdt|||jdd{y7w)zEvict one key from both arms. Only the current era's arms are touched; other-era entries in a persistent store age out by TTL. ryrN)rrrrr~rs r*rzClientResponseCache.evict_key-sz :& d'' '   g &! + &"" VZ9)= > VZ8)< =   sA3A=5A;6A=cK|xtdx\|jdd{yxtdx\|jdd{yxtdx6\|jdd{|jdd{ytdx1\|j d|j jd{y y777`7I7w)zMap a server notification to the entries it makes stale. Eviction is eventual (spawned-task dispatch): the generation bump closes the write-back race; a racing read may briefly serve the old entry. r(Nz tools/listz prompts/listzresources/listzresources/templates/listzresources/read)rrr r r rparamsuri)r4 notifications r*evict_for_notificationz*ClientResponseCache.evict_for_notification>s .,.'' 555/0.0''7771202''(8999''(BCCC3-.nn%5|7J7J7N7NOOO/67:COsW#CC'C C'C5C6CC:C C CCCCCc|jtv}|rd|jvr |j}n |j}|r|j dk(rdnd}t |t|fS)Nrrry)rqrmodel_fields_setrro cache_scopeminr)r4rmodernrr.s r*rzClientResponseCache._resolveRsh))+/GG h&"9"99]]F))F:@VEWEW[cEchir6:&--r)c@|jj|||k7Sr2)rrr6)r4rrs r*rz%ClientResponseCache._generation_moved_s   $$Wn=OOr)cK |jj||d{|jj dy7 #t$r|jdYywxYww)Nr<FT)rkr<rrrurr:s r*rzClientResponseCache._setcs` ++//#u- - - &&u- .   $ $U + s7A&AAAA&AA# A&"A##A&cKtj|jd5}|D]}|j|d{ dddjrt j dyy72#1swY.xYww)NT)shieldzDResponse cache store delete timed out; the entry will age out by TTL)r move_on_afterrtrcancelled_caughtloggerwarning)r4keysr.r5s r*rz#ClientResponseCache._cleanup_deletelsx !FT)rkr>rrrurr3s r*rzClientResponseCache._deleteus` ++$$S) ) ) &&x0 *   $ $X . s7A%AAAA%AA"A%!A""A%c||jvr3|jj|tjddyy)NzCResponse cache store operation failed; continuing without the cacheT)exc_info)ruaddrr)r4kinds r*rz'ClientResponseCache._warn_store_failure~s= t-- -  " " & &t , NN`koN p .r)N)rIrr"rrvrrLrKrNrMrPrOrwzCallable[[], str | None]rhrKrifloatrCrE)r.r-rCr)rrr!rrCzCacheableResult | NonerB)rrr!rrCrK) rrr!rrr rrKrzLiteral['use', 'refresh']rCrE)rrrCrE)rrr!rrCrE)rrrCrE)rr rCz(tuple[int, Literal['public', 'private']])rztuple[str, str]rrKrCrO)r5rr;rrCrO)rrrCrE)r5rrCrO)rzLiteral['get', 'set', 'delete']rCrE)r#r$r%r&rcrerZr~rrrrrrrrrrrrrr(r)r*rgrgsr#6'=1"1 1  1  1#1151 1 %1 14 "* *%0%0%0 %0  %0 ( %0 %0N) "( .Pcqr)rg))r& __future__rr{loggingrTcollections.abcr dataclassesrtypingrrrr ranyio.lowlevel mcp_typesr r r r rrmcp_types.versionr__all__ getLoggerr#rrrr'rrrrrrcrergr(r)r*rsW"  $!00 7    8 $ . / 9- J,j $d# A A$ A $d# O O$ O''( $d#(X(X$(XV##L#'Z&c'( (FNqNqr)