Summary
CacheableResult (introduced in v2026-07-28) defines cacheScope: "public" | "private". When cacheScope: "public" is set, the spec explicitly allows any intermediary (shared gateway, caching proxy) to cache the response and serve it across authorization contexts. This enables a cache poisoning attack: a malicious server can return poisoned tool/prompt/resource lists with cacheScope: "public", and the shared cache will serve this poisoned content to other users.
Affected endpoints
All list/read results that extend CacheableResult:
tools/list → ListToolsResult
prompts/list → ListPromptsResult
resources/list → ListResourcesResult
resources/read → ReadResourceResult
Attack scenario
- An attacker deploys a malicious MCP server that returns
cacheScope: "public" with a poisoned tool list (e.g., system_exec, read_any_file)
- A shared cache proxy (CDN, enterprise gateway) respects the
cacheScope: "public" directive and caches the response
- Victim B requests
tools/list through the same proxy — gets the poisoned tool list from cache
- The LLM client sees
system_exec as a legitimate tool and may invoke it automatically
Root cause
The spec says: "public: The response does not contain user-specific data. Any client or intermediary (e.g., shared gateway, caching proxy) MAY cache the response and serve it across authorization contexts."
There is no mechanism to verify that the cached content actually came from a trusted server. The cacheScope field is server-authored metadata — the attacker controls it entirely.
PoC
A working proof-of-concept is available at:
https://github.com/shunfeng8421/mcp-pocs/blob/main/poc_cache_poisoning.py
Additional observation
The mcp Python SDK (v2.0.0) does not implement CacheableResult at all — none of ListToolsResult, ListPromptsResult, ListResourcesResult, or ReadResourceResult include ttlMs or cacheScope fields, despite the specification requiring them. This means:
- SDK-generated servers cannot produce compliant responses
- SDK-based clients cannot benefit from caching
- There is a gap between spec and implementation
Suggested mitigations
- Remove
cacheScope: "public" or make it opt-in with explicit server identity verification
- Add a mechanism for clients to verify the origin of cached responses (e.g., signature over the cache entry)
- Require that
cacheScope: "public" responses include a verifiable server identity
- Update the SDK to implement
CacheableResult so the spec and implementation are aligned
Summary
CacheableResult(introduced in v2026-07-28) definescacheScope: "public" | "private". WhencacheScope: "public"is set, the spec explicitly allows any intermediary (shared gateway, caching proxy) to cache the response and serve it across authorization contexts. This enables a cache poisoning attack: a malicious server can return poisoned tool/prompt/resource lists withcacheScope: "public", and the shared cache will serve this poisoned content to other users.Affected endpoints
All list/read results that extend
CacheableResult:tools/list→ListToolsResultprompts/list→ListPromptsResultresources/list→ListResourcesResultresources/read→ReadResourceResultAttack scenario
cacheScope: "public"with a poisoned tool list (e.g.,system_exec,read_any_file)cacheScope: "public"directive and caches the responsetools/listthrough the same proxy — gets the poisoned tool list from cachesystem_execas a legitimate tool and may invoke it automaticallyRoot cause
The spec says: "public: The response does not contain user-specific data. Any client or intermediary (e.g., shared gateway, caching proxy) MAY cache the response and serve it across authorization contexts."
There is no mechanism to verify that the cached content actually came from a trusted server. The
cacheScopefield is server-authored metadata — the attacker controls it entirely.PoC
A working proof-of-concept is available at:
https://github.com/shunfeng8421/mcp-pocs/blob/main/poc_cache_poisoning.py
Additional observation
The mcp Python SDK (v2.0.0) does not implement
CacheableResultat all — none ofListToolsResult,ListPromptsResult,ListResourcesResult, orReadResourceResultincludettlMsorcacheScopefields, despite the specification requiring them. This means:Suggested mitigations
cacheScope: "public"or make it opt-in with explicit server identity verificationcacheScope: "public"responses include a verifiable server identityCacheableResultso the spec and implementation are aligned