Rightshold™ Sign up

Answers · MCP security

How do I cache MCP tool results safely?

Last updated

TL;DR: Cache only calls that read, and key every entry on everything that can change the answer: the server (its URL and the serverInfo.version it reported at initialize), the tool name, a hash of the tool definition you saw in tools/list, the canonicalized arguments, and who is asking (user, tenant or credential scope). Give entries a short TTL, never cache results with isError set, and never cache tools that change things: replaying a cached "sent" or "deleted" result means the action silently didn't happen. Don't let the server's hints decide this on their own. MCP tool annotations such as readOnlyHint and idempotentHint are hints; the specification says clients must treat them as untrusted unless they come from trusted servers and should never make tool use decisions based on annotations from untrusted servers. Keep your own allowlist of cacheable tools, and drop the cache when the server's tool list changes (notifications/tools/list_changed) or its version does. Caching the tool list is a separate, safer optimization: the OpenAI Agents SDK's cache_tools_list caches list_tools() only, and its docs say to enable it only if the tool definitions don't change often.

What should I check, step by step?

1. Decide per tool, from your own allowlist: cache read-only lookups (search, fetch, get); never cache tools that send, write, pay, delete or deploy.

  1. Treat annotations as input to that decision only for servers you trust. readOnlyHint defaults to false and destructiveHint to true, so a tool with no annotations should be treated as one that changes things.
  2. Build the key from: server URL, serverInfo.version, tool name, a hash of the tool's definition (description, inputSchema and outputSchema), the canonicalized arguments, and the caller's identity or tenant.
  3. Canonicalize arguments before hashing: RFC 8785 (JCS) sorts object keys recursively, keeps array order and serializes numbers one way, so {"a":1,"b":2} and {"b":2,"a":1} produce the same key. JCS does not normalize Unicode, so normalize strings yourself first if your inputs need it.
  4. Never cache results with isError: true; those are execution errors meant for the model to read and retry.
  5. Set a short TTL that matches how fast the underlying data changes. Tools that reach an open world (web search, live prices, inboxes) go stale fastest.
  6. Invalidate on notifications/tools/list_changed, on a new serverInfo.version, and when the tool definition hash changes.
  7. Keep the cache per user or per credential scope, so one person's results are never served to another.
  8. Mark cached results as cached (with their age) in what you hand the model or the user, so a stale answer can be recognized.

What the MCP specification gives you to work with

In the 2025-11-25 schema, ToolAnnotations are all hints: readOnlyHint (the tool does not modify its environment, default false), destructiveHint (default true), idempotentHint (calling repeatedly with the same arguments has no additional effect on its environment, default false) and openWorldHint (default true). The schema says they are not guaranteed to describe tool behavior faithfully.

Why caching a side-effecting tool is dangerous

If a send_email or create_invoice call is answered from cache, the model sees a success message while nothing was sent or created. Retrying the same request is how agents recover from errors, so a cache in front of a write tool quietly turns retries into no-ops.

How do I ask Rightshold about this (free, no key)?

Add the MCP server https://www.rightshold.com/mcp to Claude, Cursor, ChatGPT, Grok or VS Code, then ask: “This MCP server just shipped an update. Have its tool definitions changed since they were recorded, so I know whether to drop my cached results?”

One-click setup

{
  "tool": "check_tool_integrity",
  "arguments": {
    "server": "<the server's Rightshold slug or id>"
  }
}

Rightshold does not see or store your tool calls, arguments or cached results. It compares the tool definitions a server serves now with a recorded fingerprint. Not legal advice.

What are the sources?

Related

Not legal advice. JSON · Markdown · All answers

Get a free API key in one call

No card and no email needed. 100 free credits; the license and policy checks stay free without a key.

curl -s -X POST https://www.rightshold.com/v1/accounts/signup -H "Content-Type: application/json" -d '{"accept_terms":true}'
export RIGHTSHOLD_API_KEY=rs_...   # the api_key from the reply (shown once)
curl -s https://www.rightshold.com/v1/licenses/check -H "Authorization: Bearer $RIGHTSHOLD_API_KEY" \
  -H "Content-Type: application/json" -d '{"license":"MIT","intended_use":{"commercial_use":true}}'