By Sagar Shankaran, Founder of CallSphere
Make Claude tool use and MCP servers cache-friendly: deterministic schemas, host-side auth, well-formed error results, and idempotent side effects.
Key takeaways
Tool use is where prompt caching gets subtle. A static document at the front of a prompt is easy to cache and forget. A live tool surface backed by MCP servers is not: the schemas render at position zero, the auth flow can leak per-request data into the prefix, error results change the message stream, and a non-idempotent tool can corrupt a conversation that caching has made cheap to replay. Getting caching and tools to coexist means treating the tool layer with the same byte-level discipline you apply to the system prompt, plus a few rules that are specific to wiring external servers in.
This post is the practical guide to that intersection. We will cover how to keep MCP-backed tool schemas deterministic, where authentication credentials are allowed to live, how to structure tool results and errors so they do not silently invalidate the cache, and why idempotency matters more when caching makes replays nearly free. The throughline: tools are cacheable infrastructure, and you wire them so they stay byte-stable.
is_error: true) change the message stream — expected, and they only invalidate from that turn forward, not the cached tools-plus-system prefix.Recall the render order: tools, then system, then messages. Tools occupy the very front of the hashed stream, which means any instability in how they are defined or serialized invalidates everything downstream — the system prompt and the entire conversation included. A document buried in the system prompt can change without touching the messages cache; a single reordered tool property cannot. That asymmetry is why the tool surface deserves the most attention.
The definition of "stable" here is byte-level. Two tool lists that are semantically identical but serialized with different JSON key orders produce different bytes and therefore different cache keys. MCP servers make this easy to get wrong, because the tool definitions arrive from an external process and you convert them into Anthropic's tool format on the fly. If that conversion is nondeterministic — iterating a dict whose order varies, or letting the server's ordering leak through — your position-zero block changes shape between requests and caching never engages.
When you bring tools in from an MCP server, normalize them into a canonical, sorted shape before they ever reach the request. The pattern is to fetch the server's tool list once, convert each tool deterministically, and sort the result by name.
Hear it before you finish reading
Talk to a live CallSphere AI voice agent in your browser — 60 seconds, no signup.
def normalize_mcp_tools(mcp_tools):
out = []
for t in mcp_tools:
out.append({
"name": t.name,
"description": t.description or "",
"input_schema": t.inputSchema, # already a JSON schema object
})
return sorted(out, key=lambda x: x["name"]) # canonical order
tools = normalize_mcp_tools(mcp_client_tools) # build once, reuse every requestTwo rules make this safe. First, build the normalized list once at startup and reuse the same object across requests rather than reconverting per call — reconversion reintroduces nondeterminism. Second, if a server's schema includes objects whose property order is not guaranteed, serialize those with sorted keys. The Python SDK's MCP conversion helpers produce stable tool types you can pass to the tool runner, but the moment you hand-roll the conversion, sorting becomes your responsibility.
flowchart TD
A["MCP server tool list"] --> B["Normalize + sort by name"]
B --> C["Frozen tools block (position 0)"]
C --> D["System prompt + breakpoint"]
D --> E["Claude requests a tool"]
E --> F{"Tool succeeds?"}
F -->|Yes| G["tool_result appended to messages"]
F -->|No| H["tool_result is_error:true appended"]
G --> I["Cache holds tools+system; only messages tail changes"]
H --> IThe diagram makes the boundary explicit: whether the tool succeeds or errors, only the tail of the messages array changes. The frozen tools-plus-system prefix stays cached, so the cost of a tool round trip is just the new result block, not a re-processing of the whole prompt.
The dangerous instinct with MCP auth is to put credentials somewhere convenient — a token in the system prompt, an API key in a tool description "so the model knows." Both place per-request or per-tenant secrets into the cached prefix, which not only breaks caching across users but is a genuine security problem because prompt content is durably stored in conversation history.
The correct pattern keeps credentials entirely out of the model-visible prompt. For remote MCP servers, auth travels in the transport layer — the connection's headers or an OAuth credential the runtime injects after the request leaves your code. For tools you execute yourself, the credential lives in your host-side handler: the model emits a tool call with no secret, your handler reads the credential from its own environment, performs the authenticated call, and returns only the result. The model never sees the key, the prefix stays identical across tenants, and one cached tools-plus-system block serves every user.
Tool results are appended to the messages array as tool_result blocks, each carrying the tool_use_id that matches the originating call. This is expected message growth and it only invalidates the cache from that turn forward — the tools-plus-system prefix is untouched. So you do not need to fear tool results breaking caching; you need to keep them well-formed so the message cache for prior turns stays valid.
tool_results = []
for block in response.content:
if block.type == "tool_use":
try:
data = execute(block.name, block.input)
tool_results.append({"type": "tool_result",
"tool_use_id": block.id, "content": data})
except ToolError as e:
tool_results.append({"type": "tool_result",
"tool_use_id": block.id,
"content": f"Error: {e}", "is_error": True})
messages.append({"role": "user", "content": tool_results})Mark genuine failures with is_error: true and a description the model can act on; it will typically retry differently or ask for clarification. The caching implication is mild: an error result is just another message block, so it invalidates only the cache from that turn on, exactly like a successful result. Keep results deterministic where you can — a tool that returns timestamps or random ordering in its result will, on a replayed turn, change the bytes and reduce downstream hits.
Caching makes it cheap to replay a conversation prefix — for retries, for forked sub-agents, for re-running a turn after an error. That cheapness is exactly why idempotency matters more once caching is in play. If a tool performs a non-idempotent side effect — charging a card, sending an email, creating a record — and the turn that calls it gets replayed, you double the real-world action even though the model and cache happily reuse state.
Still reading? Stop comparing — try CallSphere live.
CallSphere ships complete AI voice agents per industry — 14 tools for healthcare, 10 agents for real estate, 4 specialists for salons. See how it actually handles a call before you book a demo.
The pattern is to give every side-effecting tool an idempotency key derived from the request, and to have the handler deduplicate on it. A send_email tool takes a stable message ID; a create_order tool takes a client-supplied order key. The handler checks whether that key was already processed and returns the prior result instead of acting twice. This keeps replays — which caching actively encourages — safe. Read-only tools need no such guard, which is another reason to promote dangerous actions to dedicated, gated tools rather than running them through an opaque bash call.
Only if the tool definitions it contributes change between requests. A server whose tool list is fetched once, normalized, sorted, and reused produces a byte-stable position-zero block, so the cache holds. Invalidation comes from the schemas changing or being reordered, not from the mere presence of an MCP connection.
Out of the prompt entirely. For hosted MCP servers, credentials are supplied through the connection or a vault the runtime injects after the request leaves your code; for self-executed tools, they live in your host-side handler's environment. Either way the model-visible prefix is identical across users, which is what keeps one cached entry serving everyone.
Yes. Each tool_use and tool_result is a content block, so a turn with many tool round trips can exceed the twenty-block window a breakpoint searches backward. In long agent turns, add an intermediate breakpoint roughly every fifteen blocks so the next request still finds the prior cache.
Caching lowers the cost of replaying a prefix, which makes retries and forks routine. A non-idempotent tool that runs during a replayed turn performs its side effect twice. Idempotency keys plus handler-side deduplication make those caching-encouraged replays safe without changing the cached prefix.
CallSphere wires tools and MCP servers into voice and chat agents the same careful way — assistants that answer every call and message, call external systems mid-conversation, and book work 24/7 while keeping the cached prefix intact. See it live at callsphere.ai.
Source & attribution: This is an independent, original explainer inspired by Anthropic's coverage on the Claude blog. Claude, Claude Code, Claude Cowork, Claude Opus, and the Model Context Protocol are products and trademarks of Anthropic. CallSphere is not affiliated with or endorsed by Anthropic.

Written by
Sagar Shankaran· Founder, CallSphere
LinkedInSagar Shankaran is the founder of CallSphere, where he builds production AI voice and chat agents deployed across healthcare, hospitality, real estate, and home services. He writes about agentic AI, LLM engineering, and shipping voice agents that handle real calls in production.
See how AI voice agents work for your industry. Live demo available -- no signup required.
One reschedule text hits your scheduler, package balance, tutor shift and invoice. Here is what MCP changed for tutoring and test-prep center owners in 2026.
Anthropic's Claude Fable 5 and Mythos 5 explained: pricing, availability, frontier benchmarks, the dual-model safeguard architecture, and what they mean for AI agents.
Where Claude Code, MCP, and multi-agent systems are taking GTM engineering next, and how to prepare your team now for standing and multi-agent workflows.
Where Claude Cowork and the Claude agent ecosystem are heading next — standing agents, MCP, skills as a moat — and the concrete moves to prepare your team now.
The metrics, leading signals, and anti-metrics that prove Claude Cowork is working — acceptance rate, time-to-outcome, and why usage counts mislead.
Shipping an agentic GTM workflow is easy; proving it works is hard. The metrics, signals, and eval loops that show a Claude Code rebuild is paying off.
© 2026 CallSphere Inc. All rights reserved.
Made within San Francisco
Watch how CallSphere handles real customer calls, schedules appointments, and processes payments — live.
Try Live DemoBook a DemoCalculate Your ROI