skip to content

Why must an MCP DiscoverResult carry ttlMs and cacheScope, and what does cacheScope mean?

level: middleimportance: should knowfreq 42%

answer

  1. no handshake means discovery repeats
  2. required, not optional hints
  3. one number, one sharing rule
  4. depends on who asked?
  5. capabilities may vary by authorization

basics

~20 s

DiscoverResult extends CacheableResult, so both fields are required. ttlMs tells the client how many milliseconds it may reuse the answer; cacheScope is "public" or "private" and says whether the cached copy may be shared across users or must be kept per-authorization.

solid answer

~50 s

In MCP revision 2026-07-28 there is no handshake to amortise, so a client that wants a server's profile has to ask for it — and without a cache rule it would ask again on every interaction. `DiscoverResult` therefore extends `CacheableResult`, which makes `ttlMs` and `cacheScope` **required** rather than optional hints. `ttlMs` is the server's statement of how long the answer stays valid; after it elapses the client re-calls `server/discover`. `cacheScope` is the safety half: `"public"` means the answer does not depend on who asked, so a host may share one cached copy across all its users, while `"private"` means the answer is specific to the authorization presented and must be cached per-caller. That distinction matters because a server's advertised capability set MAY vary by the authorization on the request, so publishing a privileged view of a server to every user would be a real leak.

go deeper

for a junior

Remember the two fields and their jobs: ttlMs is how long the answer may be reused, and cacheScope says whether that cached answer may be shared between users.

for a middle

Explain that DiscoverResult extends CacheableResult so both fields are required, and that public versus private turns on whether the answer depends on the caller's authorization.

for a senior

Show the leak you are preventing: capabilities may vary by the authorization presented, so a wrongly public scope lets one privileged discovery expose privileged capabilities to every user of the host.

for a principal

Own the caching design across a host — cache keys that include authorization identity, refresh on version rejections and change notifications, and the operational cost of a fleet whose servers all declare short TTLs.

## Why the fields exist Statelessness has a cost. Under the removed `initialize` handshake, a client paid once per connection to learn what a server was and then reused that knowledge for the life of the connection. In revision 2026-07-28 there is no connection-scoped knowledge at all — every request is self-contained — so the only way to keep discovery from becoming per-interaction chatter is an explicit cache contract. `CacheableResult` is that contract, and `DiscoverResult` extends it. Both `ttlMs` and `cacheScope` are **required** on the result; a server cannot decline to state a cache policy. ## ttlMs `ttlMs` is a duration in milliseconds: how long a client may reuse this answer without asking again. It is the server's own estimate of how stable its profile is. A server whose capability set is fixed at build time can name a long TTL; one whose capabilities depend on a fast-moving upstream should name a short one. A client that honours the TTL calls `server/discover` when it first meets a server, keeps the result, and re-fetches once the window elapses. Nothing forces a client to *use* the cache — it may re-discover on every interaction, or never discover at all, since the call is optional for clients — but honouring the TTL is what makes discovery cheap at scale. ## cacheScope `cacheScope` takes one of two values: - **`"public"`** — the answer does not depend on who asked. Every caller would get the same versions, capabilities and instructions. A host may keep one shared copy for all its users, and an intermediary could in principle cache it too. - **`"private"`** — the answer is specific to the authorization the request carried, so it must be cached per-caller and never handed to a different one. The reason `"private"` has to exist is a rule elsewhere in the same revision: the tool, prompt and resource sets MUST NOT vary per connection, but they MAY vary by the authorization presented. An admin token and a read-only token can legitimately see different views of the same server. If such a server declared `"public"`, the first admin to discover it would seed a cache that every other user then reads — leaking the existence and shape of privileged capabilities. ## How a server should choose The safe default for any server whose answer can differ by caller is `"private"`. `"public"` is a claim, and it should only be made when the discovery answer is genuinely identical for anonymous and authorized callers alike. Note the scope covers the whole result: if only one field varies by caller, the result is private. ## How a client should implement it Key the cache by the server *and*, when the scope is private, by the authorization identity the request carried — not merely by server URL, and certainly not by the reported server name, which is untrusted and not unique. Expire on `ttlMs`. Re-discover early whenever something suggests the profile moved: a request rejected for an unsupported protocol version, or a change notification arriving on an opted-in `subscriptions/listen` stream indicating the tool, prompt or resource set changed. ## The shape of a wrong answer Two mistakes recur. The first is treating `ttlMs` and `cacheScope` as optional hints — they are required fields of `CacheableResult`, and a discovery result without them is malformed. The second is reading `cacheScope` as an HTTP caching directive that browsers or proxies enforce. It is an MCP-level instruction to the client about how it may reuse and share the value; the protocol cannot enforce it, and the same holds for the many other results in the specification that extend `CacheableResult`.

  • When would a server be wrong to declare cacheScope "public" on its discovery result?
    Whenever any part of the answer depends on the caller. In revision 2026-07-28 a server's tool, prompt and resource sets MAY vary by the authorization presented, so a server that shows extra capabilities to an admin token must say "private" — otherwise one privileged discovery seeds a shared cache that reveals those capabilities to everyone.
  • How should a client key its cache of discovery results?
    By the server it talked to plus, for a private scope, the authorization identity the request carried. Never key on the reported serverInfo name — it is untrusted and not unique across servers. Expire the entry when ttlMs elapses, and re-discover early if a request is rejected for an unsupported version.
  • Does honouring ttlMs mean a client must call server/discover at all?
    No. Discovery is mandatory for servers to implement but optional for clients to call, because every request carries its own protocol version and capabilities in _meta. ttlMs governs how long a client that did discover may reuse the answer; it does not create an obligation to fetch one.

saying these in an interview costs you the question

  • Calls ttlMs and cacheScope optional hints on the result
  • Says cacheScope is an HTTP Cache-Control directive proxies enforce
  • Assumes every server's discovery answer is identical for all callers
  • Caches a private discovery result across different users
  • Thinks a cached result removes the need to send version metadata per request

context