LLM Systems Engineering · Chapter 5 of 20
Agents, at the token level
How tool calling actually works, what MCP became in 2026, the measured failure taxonomy, and a bug where a correctly-configured agent silently stops calling tools.
Agent frameworks are taught at the level of decorators and YAML. This chapter is what is happening underneath — because the failures are all at that level, and they are invisible from above.
Tool calling is a parser over token output
There is no special function-calling pathway inside the model. Mechanically:
- Tool definitions are serialised into the prompt, usually by a chat template that renders them into a system section. They are billed as input tokens, and they sit at position zero of your cache prefix — which is why changing your tool list invalidates everything.
- The model emits delimiter tokens it was fine-tuned to produce — a special token or an XML-ish tag — followed by JSON.
- The serving layer parses those tokens back into a structured tool-use block and reports a tool-use stop reason. The ‘API’ is a parser.
- Strict mode adds grammar-constrained decoding. A JSON schema is compiled into a finite-state machine, and at each decoding step any token that would violate the grammar has its logit set to negative infinity. The model physically cannot emit invalid JSON — which is a much stronger guarantee than prompting for it, and worth knowing is the actual mechanism.
The token cost is not trivial and is worth budgeting. An auto-injected tool-use system prompt runs to a few hundred tokens; individual tool families add hundreds more; and a full computer-use or browser toolset can add several thousand tokens to every single request. Tool definitions are not free, and pruning the toolset a given agent can see is one of the cheapest cost reductions available.
A failure mode worth knowing by name: constraint priority inversion.
Published research in 2026 found that when tool calling and a JSON schema output constraint are enabled simultaneously, several open-weight models stop calling tools entirely while maintaining perfect schema compliance.
The mechanism follows directly from the paragraph above: the schema is compiled into grammar-based token masks, and those masks make the tool-call delimiter tokens unreachable during decoding. The model cannot emit a tool call because the grammar forbids the token that starts one.
It is a beautiful teaching example because the bug is invisible in every log. The output is valid JSON. Nothing errors. The agent has silently become a chatbot that confidently answers from parametric knowledge.
The fix is two-pass execution — an unconstrained tool phase, then a schema-constrained response phase — and the general lesson is that constrained decoding and tool calling compete for the same output channel.
MCP in 2026, and what changed
The Model Context Protocol has moved from an Anthropic project to multi-vendor governance under a foundation, and the mid-2026 specification is a substantial breaking release. The changes are worth knowing because they are all about making it deployable on ordinary infrastructure:
- The core became stateless. The initialise handshake and the session header are gone; each request carries its own protocol version, client identity and capabilities. The consequence is that any request can land on any server instance behind a plain round-robin load balancer with no shared state, which is what turns MCP from a desktop-integration protocol into something you can run at scale.
- Header-based routing lets a gateway route, meter and rate-limit without parsing JSON bodies.
- Multi round-trip requests replace server-initiated calls that previously required a held-open stream, so a server asking for more input returns a status and the client retries.
- Cacheable list results with a TTL, so tool and resource listings stop being re-fetched constantly.
- Authorization hardening, with dynamic client registration formally deprecated in favour of client-ID metadata documents.
- Twelve-month deprecation offramps for session-based auth, sampling, roots, logging and the legacy transport.
MCP's security problem, which is real and under-appreciated
The documented attack classes are tool poisoning — instructions hidden inside a tool's description or help text, which the agent reads as part of its prompt and obeys — cross-tool poisoning, hidden parameter exploitation, and the confused deputy, where a server acting with its own broad privileges performs an action on behalf of a much less privileged user.
Security researchers documented in 2026 that several leading development environments auto-execute project-defined MCP servers with developer-level operating-system privileges and no process isolation, with multiple high-severity vulnerabilities disclosed over the preceding year.
The practical reading: an MCP server definition checked into a repository is executable code that your editor may run with your privileges. Treat adding one exactly as you would treat adding a dependency with a post-install script — because that is what it is.
And the architectural point that generalises beyond MCP: tool descriptions are part of the prompt, so anything that can edit a tool description can inject instructions. The defence is at the authorisation layer — what the agent is permitted to do — not at the text layer.
Loop patterns, and when each earns its complexity
| Pattern | Shape | Adopt it when |
|---|---|---|
| ReAct | think → act → observe → repeat | The default. Most battle-tested, right for anything interactive |
| Plan-and-Execute | plan up front, dispatch steps, replan on failure | You notice ReAct re-deriving the same plan every request. Enables parallel independent steps |
| Reflection | self-critique after completion, stored and re-injected | There is a checkable failure signal to reflect on |
| ReWOO | plan all tool calls without interleaving observations | Cheapest in tokens, most brittle. Only when steps are genuinely independent |
Production systems in 2026 typically compose these — a plan-and-execute outer loop where each step is a ReAct agent, wrapped in a reflection pass. But the counterweight is worth stating as firmly as the pattern: most tasks that appear to need multi-agent collaboration are handled by one ReAct agent with good tools and a well-structured prompt. Specialise against an identified failure, not in anticipation of one.
The measured failure taxonomy
A study of over 1,600 execution traces across seven multi-agent frameworks produced a taxonomy with high inter-annotator agreement, and the distribution is instructive:
- Specification issues — about 42%. The task, the role or the termination condition was underspecified. This is the largest category and it is a prompt and design problem, not a model problem.
- Inter-agent misalignment — about 37%. Agents disagreeing, duplicating work, or losing information at handoffs.
- Task verification — about 21%. Nothing checked whether the work was actually correct.
Two further findings deserve emphasis. Self-conditioning: when an agent's context contains its own previous errors, it becomes measurably more likely to produce further errors. One wrong step does not fail in isolation — it poisons the context for every step after it, which is the mechanistic argument for aggressively pruning failed attempts out of the trajectory rather than leaving them for the model to learn from. And multi-agent variants degraded sequential reasoning by a large margin in some settings: more agents is not monotonically better.
A caution on the numbers you will see quoted: widely-repeated figures about production failure rates in the eighties come from secondary blogs rather than from the study. The taxonomy and the distribution above are the parts with evidence behind them.
Context management and compaction
Four families exist: truncation by position, threshold-triggered compression, rolling recurrent summarisation, and agent-controlled compression exposed to the model as a tool. Current practice is overwhelmingly content-agnostic heuristics — fire when the token budget is nearly reached, or every k turns.
Distinguish two primitives that get conflated: context editing clears content, such as old tool results or thinking blocks, while compaction summarises and returns a block you must echo back or you silently lose the state.
And a genuine gap worth naming: there is very little published measurement of token-savings against task degradation for compaction strategies. Everyone does it, and almost nobody has measured what it costs in capability. If you are building agents, that is an experiment worth running on your own workload — and it is a good answer to ‘what would you measure that nobody is measuring?’
Check yourself