
If you build long-running Claude agents with more than a handful of tools, you are probably bleeding money on cache misses you have not diagnosed yet. The tools array is hashed before your system prompt, before your messages — it sits at the very front of Claude’s prompt prefix. Modify it mid-session to change which tools are available, and you invalidate the cache for the entire conversation. Anthropic shipped a beta with Claude Opus 5 that fixes this: mid-conversation tool changes. The tools array stays frozen. You add or remove availability using system message blocks instead.
Why Your Tool List Was Breaking the Cache
Claude’s prompt caching hashes the request prefix in order: tools first, then system, then messages. A cache hit requires that prefix to match the previous request byte-for-byte up to the breakpoint. Editing the tools array — even appending one new entry — changes the very front of the hash, and everything downstream misses.
For production agents, this is not a theoretical concern. A typical MCP-connected agent carries 3,000 to 8,000 tokens of tool schemas on every request. A long-running session with 30 turns and 6,000 tool schema tokens, without caching, pays for those schemas 30 times. With caching intact, you pay once to write the cache and then 10% of input price on every subsequent read. The difference on Claude Opus 5 ($5.00 per million input tokens, $0.50 per million on cache hits) works out to roughly 87% savings on tool schema tokens alone — per session.
Teams who noticed high cache_creation_input_tokens and low cache_read_input_tokens in their usage logs were often hitting this exact problem: something was changing the tool list mid-session, collapsing the cache on every turn.
What Mid-Conversation Tool Changes Actually Do
The beta — enabled with the header mid-conversation-tool-changes-2026-07-01 — lets you declare your full tool set in tools once, at the start, and never touch it again. From there, you control tool availability using tool_addition and tool_removal content blocks inside role: "system" messages placed at the relevant point in the conversation. The blocks reference tools by name rather than redefining them, so the frozen tools array stays byte-identical across turns and the cache keeps hitting.
This is available on Claude Fable 5, Mythos 5, Opus 4.8, and Opus 5, across the Claude API, Amazon Bedrock, and Google Cloud. One notable exception: Claude Sonnet 5 does not support this beta. If your production agent runs on Sonnet 5, you are waiting.
How to Implement It
Three changes to your existing code:
- Add the beta header to your request
- Declare every tool your agent might ever use in
toolsat the start — do not modify this array - Use
tool_removalortool_additionblocks in system messages to change what Claude can see
Here is a minimal example in Python:
client = anthropic.Anthropic()
response = client.beta.messages.create(
model="claude-opus-5",
max_tokens=1024,
betas=["mid-conversation-tool-changes-2026-07-01"],
# Declare all tools upfront. This array never changes.
# The cache prefix stays byte-identical across turns.
tools=[
{
"name": "read_file",
"description": "Read file contents.",
"input_schema": {
"type": "object",
"properties": {"path": {"type": "string"}},
"required": ["path"],
},
},
{
"name": "write_file",
"description": "Write content to a file.",
"input_schema": {
"type": "object",
"properties": {
"path": {"type": "string"},
"content": {"type": "string"},
},
"required": ["path", "content"],
},
},
],
messages=[
{"role": "user", "content": "Review main.py for issues."},
# ... (assistant turn with tool use, user turn with tool results) ...
# After the review phase, withdraw write access.
# This references the tool by name — no cache invalidation.
{
"role": "system",
"content": [
{
"type": "tool_removal",
"tool": {"type": "tool_reference", "name": "write_file"},
},
],
},
],
)
Note the placement constraint: a system message must immediately follow a user turn (or an assistant turn ending in a server tool result). Placing it between a tool_use block and its tool_result returns a 400 error. In an agentic loop, insert it after the user message that delivers tool results — that is the natural seam.
defer_loading: The Companion Feature Worth Using
Declare a tool with defer_loading: true and it is hidden from Claude until a tool_addition block explicitly surfaces it. This pairs well with mid-conversation tool changes for agents with large, specialized tool libraries.
A practical pattern: a coding agent starts with read-only tools (read_file, search_code, run_tests). After a review pass completes, a tool_addition block surfaces the write tools (write_file, apply_patch). The full set is declared upfront — the cache prefix is stable — but Claude only sees the subset relevant to the current phase. You get dynamic capability management without paying a cache penalty for it.
When This Is Worth the Complexity
Mid-conversation tool changes are not a one-size fix. Short sessions, static tool sets, or small tool inventories will see minimal benefit and added code complexity. The calculus changes when:
- Sessions run 10 or more turns
- Your tool set carries more than 3,000 tokens of schemas
- Tool availability legitimately changes mid-session (mode switches, capability unlocking, security revocation)
If none of those apply, stick with a static tools array. The feature exists for the class of production agents where these conditions are true — and at scale with Opus 5 pricing, the savings are not marginal.
Placement Rules and Caching Gotchas
System messages have strict placement requirements that will bite you if you ignore them. They must follow a user turn or a tool-result-bearing user turn. They cannot be the first message. And once sent, do not edit or remove them — rewriting a system message already in the cached history invalidates everything after it. If an instruction needs to change, append a new system message rather than modifying the existing one. Later system messages take precedence over earlier ones.
Anthropic’s cache diagnostics tool is useful here: it identifies exactly where two requests diverged when an expected cache hit does not happen. Pair it with the prompt caching docs to verify your breakpoints are placed correctly before blaming the tool change logic.
Bottom Line
Mid-conversation tool changes is a narrow feature with outsized impact for a specific class of production agents. If you are running multi-phase or long-running Claude Opus 5 sessions with dynamic tool requirements, the combination of a frozen tools array, tool_removal and tool_addition blocks, and defer_loading is the architecture you want. The cache math makes the investment clear.
The Sonnet 5 exclusion is the only real friction — if Anthropic extends this beta to Sonnet 5, it becomes the default pattern for production Claude agents. Until then, this belongs in any Opus 5 agent that changes its tool set mid-session.
Beta header: mid-conversation-tool-changes-2026-07-01. Full docs at platform.claude.com.













