createmcps.com

Spec explainer

What are ttlMs and cacheScope in MCP?

Last verified: 10 August 2026 · spec 2026-07-28 · ruleset 1.4.2

ttlMs and cacheScope are required fields on five MCP result types as of 2026-07-28. ttlMs is a freshness hint in milliseconds telling clients how long they may reuse a result; cacheScope is exactly "public" or "private" and decides whether a shared intermediary may cache it.

The short answer

Before — 2025-11-25 (legacy)
{
  "jsonrpc": "2.0", "id": 1,
  "result": {
    "tools": [ … ]
  }
}
After — 2026-07-28 (modern)
{
  "jsonrpc": "2.0", "id": 1,
  "result": {
    "resultType": "complete",
    "tools": [ … ],
    "ttlMs": 60000,
    "cacheScope": "public"
  }
}
Require ttlMs and cacheScope fields on results returned by tools/list, prompts/list, resources/list, resources/read, and resources/templates/list via a new CacheableResult interface.
MCP-CAC-001 MUST · spec 2026-07-28

Both fields are required, not optional hints — omitting either is a MUST-level failure. Mechanically it is one of the smallest changes in the revision, which is exactly why it is worth doing early: it is a few lines per list handler and it clears two of the most common validator failures.

Which methods carry them

Five, grouped by the spec under a new CacheableResult interface:

  • tools/list
  • prompts/list
  • resources/list
  • resources/read
  • resources/templates/list

Note what is not on that list. tools/call does not carry caching metadata — a tool invocation is an action, not a lookup, and the spec does not invite intermediaries to cache one. The five above are the discovery and read surface, which is the part a client calls repeatedly with identical arguments.

ttlMs in detail

ttlMs is a freshness hint (in milliseconds) allowing clients to cache responses.
MCP-CAC-004 MUST · spec 2026-07-28

It is a hint, not a contract. A client may re-fetch sooner, and it may not cache at all. What the server is promising is narrower: that reusing the result for up to this long is a reasonable thing to do.

Picking a value from how often the list actually changes
// Tools are defined in code and ship with the deploy —
// they cannot change between requests to the same build.
{ "ttlMs": 3600000, "cacheScope": "public" }     // 1 hour

// Resource list assembled from a database that users write to.
{ "ttlMs": 5000, "cacheScope": "private" }       // 5 seconds

// A list you cannot reason about — be conservative, not clever.
{ "ttlMs": 0, "cacheScope": "private" }          // no reuse
Our recommendation, not a spec quote: ttlMs: 0 is a legitimate answer and a much better one than guessing. Zero is a non-negative number, so it satisfies MCP-CAC-004, and it says “don't reuse this” explicitly rather than by omission. Reach for a real number once you can justify it.

cacheScope in detail

cacheScope ("public" or "private") controls whether shared intermediaries may cache the response.
MCP-CAC-002 MUST · spec 2026-07-28
cacheScope ("public" or "private").
MCP-CAC-003 MUST · spec 2026-07-28

The value set is closed. "public" and "private" are the only two valid values — not "no-cache", "none", true, or any HTTP Cache-Control token borrowed by analogy. MCP-CAC-003 exists because that borrowing is a real and easy mistake for anyone who has written HTTP caching before.

Why this arrived in the same revision as statelessness

The two changes are one design. Removing sessions means a client can no longer learn a tool list once during a handshake and hold it for the life of a connection — it re-asks, potentially on every request, and each of those calls is a round trip that the legacy protocol did not have to make.

Caching is what pays for that. And caching only became sound because of statelessness: once list endpoints stopped varying per connection, two identical requests genuinely have the same answer, so an intermediary can serve one from the other.

A `cacheScope` of `"public"` indicates that the response does not contain user-specific data and can be safely shared.
MCP-CAC-005 MAY · spec 2026-07-28

Read the two rules together and the dependency is explicit. If your tools/list still varies per connection — the failure MCP-STL-008 catches — then no cacheScope value you write is honest, because the premise the field rests on is false.

The public/private mistake worth avoiding

This is the one place in the caching rules where getting it wrong is a security problem rather than a performance one.

The failure: A server returns a per-user tool list — tools gated by the caller's permissions — and marks it cacheScope: "public". A shared proxy caches the first response and serves it to the next user, who now sees a tool list that was filtered for someone else.

MCP-CAC-005 is the rule that flags this, and it is the only caching rule marked security-relevant. It is graded as a warning rather than a failure because detecting personalisation from outside is inference, not certainty — but a security-relevant finding caps the report grade at D regardless.

Our recommendation, not a spec quote: the test to apply is not “is this data sensitive?” but “could two different callers get different bytes here?” If yes, it is private — even if the difference looks harmless today, because the caching layer that acts on the field has no way to re-check that judgement later.

The 5 caching rules we check

RuleWhat we checkLevelIf it fails
MCP-CAC-001ttlMs present on all five cacheable resultsMUSTfail
MCP-CAC-002cacheScope present on all five cacheable resultsMUSTfail
MCP-CAC-003cacheScope is exactly "public" or "private"MUSTfail
MCP-CAC-004ttlMs is a non-negative numberMUSTfail
MCP-CAC-005Authenticated or personalised results are not marked cacheScope: publicMAYwarn

All five carry a verbatim spec sentence. MCP-CAC-005 is the security-relevant one.

Check your list responses

The validator calls each of the five cacheable methods and reports whether ttlMs and cacheScope are present, correctly typed, and consistent with what the response actually contains.

Validate a server →

Frequently asked

What is ttlMs in MCP?

ttlMs is a freshness hint, in milliseconds, that a server attaches to a cacheable result so clients know how long they may reuse it before re-fetching. It became required in the 2026-07-28 revision on tools/list, prompts/list, resources/list, resources/read and resources/templates/list, via a new CacheableResult interface.

What is cacheScope in MCP?

cacheScope is a required field on the same five results whose value is exactly "public" or "private". It controls whether shared intermediaries may cache the response: "public" asserts the response contains no user-specific data and can be safely shared, while "private" restricts caching to the requesting client.

Which MCP methods require ttlMs and cacheScope?

Five: tools/list, prompts/list, resources/list, resources/read and resources/templates/list. They are the methods the spec groups under the CacheableResult interface. Other results, including tools/call, do not carry these fields.

What value should I use for ttlMs?

The spec defines the field's meaning but does not prescribe a number, so this is an engineering decision rather than a conformance one. Base it on how often the underlying list actually changes: a static tool list can afford a long hint, while a list assembled from a fast-moving external source should use a short one. The field must be a non-negative number.

Is it safe to set cacheScope to public?

Only when the response genuinely contains no user-specific data. Marking a personalised result public invites a shared intermediary to serve one user's response to another, which is a data-leak class rather than a mere caching inefficiency. If a tool list, resource list or resource body varies by who asked, it must be private.

Why did MCP add caching metadata in 2026-07-28?

Because the same revision made the protocol stateless. Once list responses stopped varying per connection, they became genuinely cacheable — and a stateless protocol re-sends the context a handshake used to establish once, so caching the repeated list calls is what keeps that trade cheap.