Est.

Tool Use Patterns for Autonomous AI Agents

Open protocols let teams build tool integrations that survive model upgrades and vendor changes.

Contributing Editor · · 12 min read
Cover illustration for “Tool Use Patterns for Autonomous AI Agents”
Agentic Workflows · September 18, 2026 · 12 min read · 2,738 words

A single LLM call is a function. Text goes in, text comes out, and the transaction is over. An agent loop is a different animal entirely: a program that keeps running for however many steps it takes, calling the model repeatedly, each time armed with new information from the last step. A function has a bounded cost. A loop doesn't, unless someone bounds it. A function fails in one way, but a loop can fail at any of its steps, and those failures compound.

Without tools, a model can only generate text. It can describe what it would do, but it can't actually do it. Tools are the bridge: they let the model read a database, hit an API, write a file, send a message. Plan, act, observe, verify, repair, and the tools live in that "act" step, but the other three steps exist because tools break, return garbage, or do something nobody expected. Everything below is about designing that bridge so it holds weight under real load.

The stakes stopped being theoretical a while back. Agents running in production is the norm at large companies now, not some edge case, and task-specific agents are expected to show up in a large share of enterprise software within the next year or two. Tool-use design used to sit in the research-curiosity pile. Now it's closer to plumbing: unglamorous, load-bearing, and the thing that breaks when nobody was watching.

The shared standard that makes tool calls portable: MCP

None of the patterns below matter if they only work inside one vendor's SDK. That's the gap MCP, an open protocol for connecting models to tools and data, was built to close. It runs JSON-RPC 2.0 over standard transports, so any language, any runtime, can build a client or a server without special-casing anything. Boring and portable beats clever and proprietary, especially when the goal is getting an entire industry to agree on one thing.

The license terms did their part too. MIT license, no fees, and early reference servers for GitHub, Slack, PostgreSQL, and Google Drive gave developers something to copy instead of something to build from scratch. Anthropic, OpenAI, Google, and Microsoft all shipped native support. LangChain, CrewAI, LangGraph, and LlamaIndex moved MCP from an experimental flag to the default path. By the time Anthropic handed MCP over to the Linux Foundation on December 9, 2025, placing it under the Agentic AI Foundation (a fund co-founded by Anthropic, Block, and OpenAI), the protocol had already crossed 97 million monthly SDK downloads and more than 10,000 active public servers. By the time it moved under the Agentic AI Foundation, the protocol had already crossed 97 million monthly SDK downloads and more than 10,000 active public servers, functioning as infrastructure rather than a spec. That's infrastructure.

Teams build tooling around one model's function-calling quirks, and the day a better model ships, it's a migration project, rewriting schemas, retesting edge cases, hoping nothing quietly breaks. MCP splits the tooling layer from the model layer, so the integration work someone did last year is still worth something today.

One more thing anyone running MCP in production needs to know. The maintainers finalized a major spec revision on July 28, 2026, that strips out protocol-level session tracking. MCP is now stateless at the protocol layer; protocol version, client identity, and capabilities travel in a _meta parameter on each request instead. Anthropic's David Soria Parra called it the biggest change since authorization was added to the spec. Anyone still running servers built against the old session model has real work ahead.

This isn't a full tour of MCP, and it doesn't need to be. More narrowly: because the protocol is shared, everything that follows is a direct consequence of that protocol rather than a framework trick. It's a pattern that transfers.

Single-tool invocation: the atomic unit every other pattern builds on

Every pattern in this piece is the same basic move, repeated and recombined. The agent hands the model a task plus a list of tool schemas, each one carrying a name, a description, and an input schema. The model responds with a tool_use block naming which tool and what arguments. The framework runs the actual function, appends the result as a tool_result, and the model checks its own stop_reason. end_turn means done. Anything else means the loop keeps going.

Simple mechanism. The schema is where it gets interesting, and where most teams get sloppy.

The model picks tools based on descriptions, not on what the code underneath actually does. A vague description like "handles user data" produces vague, often wrong selection. A precise one, "retrieves a user's order history given a user ID", doesn't. Mark required versus optional parameters clearly, because a loose schema is an open invitation for the model to invent an argument that sounds plausible and isn't real. And whatever the tool hands back needs to be something the model can actually read: structured text or JSON, never a binary blob it has no way to parse.

None of this looks like a cost problem at the single-call level. It becomes one fast. Token costs grow linearly with steps, because the full conversation history rides along on every iteration. One tool call is cheap. Twenty tool calls chained together, each one dragging the last nineteen results behind it, is not. Tight schemas and clean returns are the discipline that keeps a ten-step chain from turning into a token bill nobody budgeted for.

A model inventing a tool name that isn't in the registry, arguments that don't match the expected type, and a tool returning an error the agent has no plan for are three failure modes that appear here and never really leave. They don't disappear as the system gets more complex. They just get harder to spot.

Chained tool calls: sequencing actions where each step depends on the last

Chaining earns its place when step two genuinely needs the output of step one, no way around it. Fetch a URL, pull structured fields out of what comes back, write those fields to a database. Look up a user, pull their account history, generate a summary from it. Each step is blocked on the one before it, so parallelism isn't even on the table: the second call doesn't have its inputs until the first one finishes.

State management across a chain is almost automatic. The model doesn't need a variable-passing scheme, since it can just read the prior tool_result messages sitting in the conversation history. Convenient, but it means the conversation is doing double duty as a log and a database at once, and that dual role causes confusion when something goes sideways three steps in.

A few rules keep chains from turning fragile. Keep each tool narrow, one action, one return value, so when something breaks, it's obvious which link broke. Validate before moving forward: confirm the result from step N is actually good before firing step N+1, instead of assuming success and finding out later it wasn't. And cap the loop with a hard max_steps ceiling. Skipping that means a chain stuck retrying the same failing step will happily burn through the API budget on its own.

Pinterest's production MCP deployment is a solid real-world case for what chaining looks like at scale. Domain-specific MCP servers sit behind a central registry for Presto, Spark, Airflow, and an internal knowledge base, handling roughly 66,000 invocations a month from 844 active users, and the company estimates the setup saves around 7,000 hours of manual work monthly. Human-in-the-loop approval gates get inserted for sensitive operations inside that pipeline, and that's the right instinct: autonomy for the routine steps, a checkpoint before anything touches a system where a mistake actually costs money.

Parallel tool calls: running independent actions simultaneously

Parallelism works under exactly one condition: nothing in the batch depends on anything else in the batch. If call B doesn't need what call A returns, there's no reason to make it wait around.

Mechanically, the model returns multiple tool_use blocks in a single response, the framework fires them off at once, and it waits to collect every result before handing anything back. The model sees the whole batch of tool_result messages together and synthesizes across them in its next turn. Same building block as single-tool invocation, just fanned out wider.

This pattern earns its keep in research tasks (pulling three competitor pages at once instead of one after another), in data enrichment (looking up five entities at the same time instead of in sequence), and in anything latency-sensitive, where cutting wall-clock time matters even if the total token cost is roughly the same either way.

It also brings failure modes sequential calls don't have. Firing five requests at the same API simultaneously hits a rate limit far more easily than sending them one at a time, so concurrency controls and back-off logic aren't optional, they're part of the design from day one. Partial failure needs an explicit policy too: two of five calls fail, does the agent proceed with what it has, retry just the failures, or throw out the whole batch? That decision belongs in the design, made deliberately rather than left to whatever the system stumbles into by accident. Results don't come back in a guaranteed order either, so whatever synthesizes them afterward has to handle any sequence without falling over.

Fetching live web content is a natural home for this pattern: multiple URLs, multiple domains, zero dependency between them. That's exactly where anti-bot defenses and per-domain rate limits start to bite. Firing concurrent requests without accounting for those constraints doesn't throw errors so much as it produces silence, empty returns at scale that look like success until someone actually checks.

Tool selection under ambiguity: how agents choose when multiple tools could apply

With a handful of tools in the registry, the model almost always picks right. Grow the registry, and overlapping descriptions start producing wrong picks quietly, with no error to flag it. This is one of the least visible failure points in agent design, because nothing crashes. The agent just does the wrong thing with total confidence.

Most production registries skew narrow by nature: empirical research on MCP shows tools clustering overwhelmingly around software development work, a large majority of both what gets published and what gets downloaded. So ambiguity turns into a real problem specifically for agents that cross functional boundaries, where a general-purpose registry mixes tools from different domains that all sound vaguely alike.

A handful of fixes actually move the needle. Write descriptions around user intent: "retrieves the current price of a stock ticker" beats "calls the finance API," because the model is matching a need. Where two tools could plausibly answer the same question, merge them or rename one so they stop competing. In large registries, group or namespace related tools so the model isn't choosing among five things that all sound the same. And negative examples in a description, "use this for structured extraction, not for fetching raw HTML," do real work ruling out the wrong choice before it ever gets made.

Sometimes the right move is to stop trusting the model's judgment at all for a given step. Forced-tool patterns, where the orchestrator names exactly which tool must run, make sense for anything safety-critical. Tool routing layers, a lightweight classifier that hands off to a sub-agent with a narrower toolset, shrink the selection surface so no single call has to choose from a giant menu.

There's also the hallucination risk specific to selection: a model can simply invent a tool name that doesn't exist. The agent loop has to catch that cleanly, check the registry, return a plain error message, instead of letting an unhandled exception take the whole run down with it.

Recovery patterns: what a production agent does when a tool call fails

Failures are at least four different things. Treating them as one problem leaves recovery logic either too aggressive or too passive, with no middle setting.

Transient failures are the easy case: rate limits, network timeouts, a service that's briefly down, recoverable with retry and back-off. Semantic failures are trickier, the tool runs fine but hands back an empty result, a malformed format, or an error buried inside otherwise valid-looking output. Hallucination failures aren't the tool's fault at all; they happen when the model passes bad arguments or calls something that doesn't exist, a breakdown in schema adherence rather than in the tool itself. Then there's the infinite loop, the agent retrying the same failing action over and over with no exit condition, which appears often enough in production logs to deserve its own name.

Retry with exponential back-off and jitter is the baseline fix for transient failures, but it needs a hard ceiling on attempts. Just as important, the agent needs to tell "retry the same tool" apart from "this tool isn't going to work, try something else," and that call gets made based on what kind of error actually came back.

Error handling design decides whether the agent recovers or gets stuck. A tool that returns a clean string like "Error: user 'u_999' not found" gives the model something to reason about: maybe it stops, maybe it tries an alternate lookup. A tool that raises an unhandled exception gives the model a stack trace it has no way to work with. The fix is almost embarrassingly simple: return errors as readable text, never as a crash.

The max_steps ceiling does double duty as a safety mechanism and a cost control. Every agent loop needs an explicit cap, or a stuck agent runs until the API budget hits zero. And hitting that ceiling shouldn't mean silently returning nothing. It should mean displaying whatever partial result exists in the output, with a plain statement of why the loop stopped.

Not every failure should get auto-recovered, either. Writing to a database, sending an email, executing a financial transaction: these need an approval gate before the agent proceeds, not a retry loop that assumes it knows better. Symphony Solutions reported that 88% of organizations have already had an AI-related security incident, while only about 22% treat their agents as identity-bearing entities with real accountability attached. That gap sits mostly invisible until something goes wrong, and human-in-the-loop checkpoints exist to close it. Pinterest's approval-gate pattern from earlier is the reference model: autonomous by default, with a human standing at the door for anything consequential.

One more failure mode belongs here, and it's a security issue as much as a reliability one: prompt injection through tool output. Text coming back from a server is data. It isn't an instruction. But a naive agent will follow "ignore previous instructions" without blinking if that phrase happens to sit inside a web page it just fetched. The MCPTox benchmark, published in 2025, tested 20 prominent LLM agents against 45 real-world MCP servers using 353 authentic tools, and found o1-mini had a 72.8% attack success rate. The unsettling part: more capable models were often more susceptible, not less, because the attack exploits good instruction-following, the trait that makes a model useful. Every tool result needs to be treated as untrusted input, full stop. No exceptions for the ones that look trustworthy on the surface.

Orchestrator-worker topology: when one agent coordinates many

At some point, a single agent juggling every tool for every subtask stops being manageable. That's the job the orchestrator-worker pattern does: one orchestrator agent takes the high-level goal, breaks it into subtasks, and spins up worker agents to handle each piece. Each worker gets a narrow toolset and a specific brief, not the whole registry. The orchestrator collects what comes back and stitches it into a final answer.

When those subtasks are genuinely independent, workers run in parallel, which is really the same parallel-call pattern from earlier lifted up a level: tools running concurrently becomes agents running concurrently.

Narrowing each worker's toolset does more than tidy things up, it contains failure. The tool-selection difficulty from before gets solved structurally instead of through better descriptions. A worker with three tools relevant to its one job makes far fewer wrong choices than a single generalist agent picking from thirty. Smaller surface area, fewer ways to pick wrong, and failures that stay contained to one worker instead of cascading through the entire run. When a worker fails, the orchestrator retries just that piece, reroutes it, or flags it for a human, and the rest of the task keeps moving.

Sources

  1. Agentic Design Patterns: The 2026 Guide to Building Autonomous Systems
  2. AI Agents in 2026: The Future of Autonomous Software
  3. anthropic.com
  4. Model Context Protocol - Wikipedia
  5. Building AI Agents with Tool Use: Patterns That Work in Production (2026)
  6. Agentic Tool Use in Large Language Models
  7. alicelabs.ai
  8. openlayer.com

More in Agentic Workflows