Cache hints
A cache hint is metadata the server attaches to a cacheable result. On protocol revision 2026-07-28 the result carries two fields:ttlMs, how many milliseconds the value stays fresh, and cacheScope, either 'public' (shareable across callers) or 'private' (specific to one caller). The client reads these and decides whether to serve a later identical call from its own cache. Cache hints are a modern-era feature — legacy-era responses never carry them.
Set hints per operation through FastMCPOptions.cacheHints, keyed by the method. The cacheable operations are tools/list, prompts/list, resources/list, resources/templates/list, resources/read, and server/discover.
server.ts
ttlMs: 0 and cacheScope: 'private', which tells the client to store the result but never serve it from cache without revalidating. Raise ttlMs only for operations whose results you are comfortable serving stale for that window.
Cache hints apply per operation, not per item. Every resources/read result gets the same hint; a hint per individual resource is not supported, because that override lives only on the SDK’s high-level server registration, which FastMCP does not use. When one TTL cannot fit every resource, choose the shortest safe value for the operation.
The caching middleware
CachingMiddleware is a server-side response cache. It holds each result in a TTL cache and serves a matching later call from the cache, skipping the handler. Register it with server.use(), passing the TTL in milliseconds.
server.ts
anon partition, and an authenticated request is partitioned by the SHA-256 hash of its bearer token. A result computed for one identity is therefore never served to another, in either direction, so auth-filtered results such as a per-caller tools/list stay correct. The key holds the token’s hash, never the raw token.
Custom cache keys
Pass aCacheKeyFn as the second argument to control the key yourself. A custom key function replaces the default entirely — the auth partition is not merged back in. When your cached values depend on who is calling, you must fold identity into the key yourself. Use the same dimension the default uses: the bearer token, hashed. Never place the raw token in a cache key.
server.ts
ctx.mcpContext.auth?.clientId is coarser, and two tokens can share a clientId yet differ in scope, so a clientId key can merge identities that must stay apart. Prefer the hashed token.
What is never cached
Two kinds of request are never served or stored, whatever your key. Resource subscription control —resources/subscribe and resources/unsubscribe — mutates the connection’s subscription set rather than computing a value from its params. Serving a cached acknowledgement would skip the real subscription change, and the next update would never reach the client, so the middleware always runs these.
Input-required rounds are also excluded. A retried call re-sends byte-identical params, so a cache key cannot tell one round from the next; caching would replay the first round’s input_required result forever and the flow could never finish. The middleware skips any request that carries per-round input, and never stores an input_required result, because each embeds a single-use flow token. This keeps the input-required pattern correct even behind a cache. The middleware guide covers the caching middleware alongside the rest of the built-ins.