Cacheable Results
Servers MUST include caching hints on results returned by the following operations:server/discovertools/listprompts/listresources/listresources/templates/listresources/read
Cacheable Model
Cacheable Results in MCP use two fields to provide caching hints to clients:- The Time-to-live (TTL) Field,
ttlMs, is an integer value in milliseconds specifying how long the client MAY consider the result fresh. - The Cache Scope Field,
cacheScope, indicates the intended scope of the cached response, either"public"or"private".
Time-to-Live (TTL) Field
ThettlMs field is a hint from the server indicating how long, in
milliseconds, the client MAY consider the result fresh. Semantics are
analogous to HTTP Cache-Control: max-age.
- If
ttlMsis0, the response SHOULD be considered immediately stale. The client MAY re-fetch every time the result is needed. - If
ttlMsis positive, the client SHOULD consider the result fresh for that many milliseconds after receiving the response. - If
ttlMsis absent, clients SHOULD assume a default of0(immediately stale) and rely on their own caching heuristics or notifications. This should only occur in older server versions. - If
ttlMsis negative, clients SHOULD ignore it and treat it as0.
ttlMs value that is >= 0.
TTL is a freshness hint, not a guarantee. Servers MAY change the
underlying data before the TTL expires. The TTL tells the client how long it
can reasonably avoid re-fetching, not how long the data is guaranteed to
remain unchanged.
Freshness Calculation
A client records the local time at which the response was received (t_received). The
response is considered fresh while:
Cache Scope Field
ThecacheScope field controls who may cache a response, analogous to HTTP
Cache-Control: public vs Cache-Control: private.
Choosing a Cache Scope
"public"is appropriate for lists of tools, prompts, and resource templates when they are identical for all users."private"is appropriate forresources/readresults that depend on the authenticated user, or for filtered list results that vary per user.
Interaction with Notifications
TTL and server-push notifications are complementary:- A server MAY provide
ttlMswithout advertisinglistChanged: truein its capabilities. In this case, the client relies entirely on TTL-based freshness. - A server MAY advertise
listChanged: trueand providettlMs. In this case, the client can use the TTL to avoid unnecessary refetches between notifications, and the notification acts as an immediate invalidation signal.
Interaction with Pagination
When a list result is paginated, each page is an independently cacheable response—consistent with how HTTPCache-Control treats paginated resources.
- Each page response carries its own
ttlMsvalue. The freshness clock for each page starts at the time that page was received. - Servers MAY return different
ttlMsvalues on different pages (e.g., a longer TTL for early pages of a stable list, a shorter TTL for the final page). - When a cached page expires, the client SHOULD re-fetch that page using its cursor.
- There is no cross-page consistency guarantee. If the underlying data changes between page fetches, clients may observe duplicates or gaps.
- Clients that require a consistent snapshot of the full list SHOULD re-fetch from the beginning (without a cursor).
- If a cursor becomes invalid (e.g., the server returns an error for a previously valid cursor), the client SHOULD discard all cached pages and re-fetch from the beginning.
cacheScope to all response pages for a given list
request. For example, if the first page of a tools/list response has
cacheScope: "private", all subsequent pages for that request MUST also be
"private".
Security Considerations
AcacheScope of "public" indicates that the response does not contain user-specific data and can be safely shared. Servers MUST be aware that responses with a "public" cacheScope may be shared between callers even if the Result is coming from an authenticated endpoint. For example, the Result from an authenticated tools/list call with a "public" cacheScope may be cached by a client and may be shared outside of the initial requests authorization context. (i.e. different access tokens can leverage the same cache).
Server implementors:
- should ensure that the
cacheScopecorrectly reflects the intended visibility of the primitive. - MUST apply appropriate per-primitive access controls, and MUST NOT rely on
cacheScopealone to prevent unauthorized access to primitives.