A model on its own can only produce text. It cannot read a file, run a test or open a pull request. Yet coding agents do all three, every day. The bridge between "writes text" and "does things" is tool use, and once you see how simple the mechanism is, agents stop feeling like magic and start feeling like software you can design, limit and debug.
Tool use: the model asks, the program acts
Article 1 introduced the agent harness: the ordinary program wrapped around the model. Tool use is the contract between the two.
It works in three steps:
- The harness describes the tools. Along with the prompt, it sends the model a list of tools it may use, each with a name, a plain-language description, and a schema for its inputs.
- The model writes a tool call. Instead of answering in prose, the model generates structured text that means "please run this tool with these inputs". This is still next-token prediction. The model has been trained (Article 7) to produce this format when a tool would help.
- The harness runs it. The harness checks the request, executes the real function, and adds the result to the conversation. Then it calls the model again.
This is usually called function calling or tool calling. The model never executes anything itself. It only asks. That distinction is the foundation of agent safety, which Article 19 covers.
Worked example: one tool call in JSON
Here is a simplified tool definition the harness might send. The exact field names differ between model providers, so treat this as an illustration of the shape, not any one vendor's format.
{
"name": "search_code",
"description": "Search the repository for a text pattern. Returns matching lines with file paths.",
"input_schema": {
"type": "object",
"properties": {
"pattern": { "type": "string" }
},
"required": ["pattern"]
}
}
Given the ticket "Login fails when the email has uppercase letters", the model might respond with:
{
"type": "tool_use",
"name": "search_code",
"input": { "pattern": "find_user_by_email" }
}
The harness runs the search and sends back the result as a new message:
{
"type": "tool_result",
"content": "auth/login.py:2: user = db.find_user_by_email(email)"
}
Now the model has a file path it did not have before, and its next prediction can be a call to read_file on auth/login.py. Notice that the description field does real work. The model chooses tools largely by reading those descriptions, so a vague description leads to a confused agent.
The agent loop
An agent is a model plus tools plus a loop that keeps going until the job is done. In code, the core of almost every agent harness looks like this:
messages = [system_prompt, ticket]
for step in range(MAX_STEPS):
reply = model.generate(messages, tools=TOOLS)
messages.append(reply)
if reply.tool_calls:
for call in reply.tool_calls:
result = run_tool(call) # the harness acts, not the model
messages.append(result)
else:
break # no tool call means the model is done
That is genuinely most of it. Everything else, permissions, retries, logging, summarising long histories, is built around this loop.
The diagram shows the loop as a flow.
flowchart TD
A["Messages so far"]:::io --> B["LLM predicts reply"]:::model
B --> C{"Tool call?"}:::warn
C -->|"yes"| D["Harness runs tool"]:::infra
D --> E["Append result"]:::io
E --> A
C -->|"no"| F["Final answer"]:::io
classDef model fill:#2a2140,stroke:#a78bfa,color:#ece5ff
classDef infra fill:#12302d,stroke:#2dd4bf,color:#d5fbf5
classDef io fill:#1f1d1a,stroke:#8a8275,color:#ece5d8
classDef warn fill:#3a1d18,stroke:#fb7a5e,color:#ffe1d9Figure 16.1: The agent loop. The model proposes, the harness acts, the result goes back in, and the loop repeats until no tool is requested.
Note the MAX_STEPS limit. An agent that misunderstands its task can loop for a long time, and every pass is another model call that costs money. A step limit, a token budget, or a wall-clock timeout is not optional in production.
How agents decide
There is no separate planning module deciding what to do. The decision is the next-token prediction itself, shaped by everything in the context:
- The system prompt sets the goal and rules: "Fix the bug, add a test, open a PR. Never push to main."
- The tool descriptions tell the model what actions exist and when each is useful.
- The history shows what has already happened: which files were read, which tests failed.
Given all that, the model predicts the most sensible next move, the same way it predicts the next word of a sentence. If the last tool result was a failing test, the likely continuation is reading the failure and editing the code. Models trained heavily on agent tasks also tend to write a short plan before acting, and that plan, being in the context, steers later steps.
This is also why agents fail in recognisable ways. If a tool result is confusing, the next prediction is confused. If the history gets very long, early instructions carry less weight. Good harness design is mostly about keeping the context clear.
The full BUG-1423 run, step by step
Here is a realistic trace. The number of steps is illustrative, real runs vary.
- Read the ticket. The model writes a one-line plan: find the login code, reproduce the bug with a test, fix it, open a PR.
search_code("find_user_by_email")returnsauth/login.py.read_file("auth/login.py")returns thelogin()function. The model sees the email goes to the database unchanged, while the comment says emails are stored in lowercase.read_file("tests/test_login.py")shows how existing tests are written.edit_fileaddstest_login_with_uppercase_email, which logs in asMaria@Example.com.run_tests()reports the new test failing. Good: the bug is reproduced.edit_fileaddsemail = email.strip().lower()as the first line oflogin().run_tests()reports everything passing.open_pull_requestwith the title "Normalise email case on login (BUG-1423)" and a summary.- No tool call. The model writes a final message with the PR link, and the loop ends.
That is ten model calls, each one a full pass through Articles 1 to 8: tokenize, attend, predict, sample.
The diagram zooms in on steps 6 and 7, showing what passes between the harness, the model and the test runner.
flowchart TD
H["Harness sends history, tools"]:::infra --> M1["LLM: call run_tests"]:::model
M1 --> T["Test runner: pytest"]:::infra
T --> R["Result: 1 failed"]:::warn
R --> M2["LLM: call edit_file"]:::model
classDef model fill:#2a2140,stroke:#a78bfa,color:#ece5ff
classDef infra fill:#12302d,stroke:#2dd4bf,color:#d5fbf5
classDef io fill:#1f1d1a,stroke:#8a8275,color:#ece5d8
classDef warn fill:#3a1d18,stroke:#fb7a5e,color:#ffe1d9Figure 16.2: The model never talks to the test runner. Every action goes through the harness.
MCP: one standard plug for tools
In the loop above, someone had to write search_code, run_tests and open_pull_request and wire them into this particular harness. Now imagine a company with five AI applications and twenty internal systems. Without a standard, that is potentially a hundred custom integrations.
The Model Context Protocol (MCP) is an open protocol that Anthropic introduced in November 2024 to solve this. It defines one standard way for AI applications to discover and use tools and data. Write an integration once as an MCP server, and any MCP-compatible application can use it.
MCP has three roles:
- Host: the AI application the user works with, such as an IDE, a desktop chat app, or our bug-fix agent.
- Client: a connector inside the host. The host creates one client per server it connects to.
- Server: a program that exposes capabilities. A GitHub MCP server, a database MCP server, a ticketing MCP server.
Servers can offer three kinds of things:
- Tools: actions the model can call, like
open_pull_request. - Resources: data the application can read and add to context, like a file or a ticket.
- Prompts: reusable prompt templates, like "summarise this incident".
Under the hood, messages use JSON-RPC, a simple standard for remote procedure calls. Local servers usually talk over standard input and output, remote ones over HTTP. In December 2025, Anthropic donated MCP to the Agentic AI Foundation, a fund under the Linux Foundation that it co-founded with Block and OpenAI. By then MCP had been adopted well beyond Anthropic, in tools such as ChatGPT, Gemini, Cursor, Microsoft Copilot and Visual Studio Code.
The diagram shows how our agent would reach its tools through MCP.
flowchart TD
H["Bug-fix agent, host"]:::infra --> C1["MCP client"]:::infra
H --> C2["MCP client"]:::infra
C1 --> S1["Git and GitHub server"]:::infra
C2 --> S2["Ticket tracker server"]:::infra
S1 --> R["Repo and pull requests"]:::io
S2 --> K["BUG-1423"]:::io
classDef model fill:#2a2140,stroke:#a78bfa,color:#ece5ff
classDef infra fill:#12302d,stroke:#2dd4bf,color:#d5fbf5
classDef io fill:#1f1d1a,stroke:#8a8275,color:#ece5d8
classDef warn fill:#3a1d18,stroke:#fb7a5e,color:#ffe1d9Figure 16.3: One host, one client per server. Each server wraps a real system behind a standard interface.
MCP does not change the agent loop at all. The model still sees a list of tools and writes tool calls. MCP only standardises where those tools come from.
Where this shows up in our bug-fix agent
This article is where the agent becomes an agent. Everything it does to the outside world is a tool call:
- reading the ticket through a ticket tracker tool or MCP server;
- finding and reading code with
search_codeandread_file; - changing code with
edit_file; - proving the fix with
run_tests; - delivering the result with
open_pull_request.
The model's job at every step is to choose the next call and its inputs. The harness's job is to run it safely: only inside the repository, never pushing directly to main, stopping after a step limit.
Common misconceptions
"The model runs the code." The model only writes a request. The harness decides whether and how to run it. That is exactly where you put permissions, sandboxes and approval prompts.
"Agents have a separate reasoning engine." The decisions come from the same next-token prediction as everything else, guided by the prompt, the tool descriptions and the history.
"MCP is an AI model or an agent framework." It is a protocol, like HTTP is a protocol. It defines how applications and tool servers talk, not how the agent thinks.
"More tools make a better agent." Every tool description takes up context and adds a choice the model can get wrong. A small set of clearly described tools usually beats a large vague one.
Key takeaways
- Tool use is a contract: the model writes a structured request, the harness executes it and returns the result.
- An agent is a loop: call the model, run any tools it asks for, append results, repeat until no tool is requested.
- Agents decide by next-token prediction over the prompt, tool descriptions and history, so clear context means better decisions.
- Always cap agents with step limits, budgets and timeouts.
- MCP standardises how tools and data are exposed to AI applications through hosts, clients and servers.
Glossary
- Tool use (function calling): a model producing a structured request to run a named tool with specific inputs.
- Tool definition: the name, description and input schema the harness gives the model for each tool.
- Input schema: a description of the inputs a tool accepts and their types.
- Tool result: the output of a tool, sent back to the model as a new message.
- Agent: a model, a set of tools and a loop that runs until the task is done.
- Agent loop: the repeated cycle of model call, tool execution and appending results.
- MCP (Model Context Protocol): an open protocol for connecting AI applications to tools, data and prompts through servers.
- MCP host: the AI application that uses MCP servers.
- MCP client: the connector inside a host that talks to one server.
- MCP server: a program that exposes tools, resources and prompts over MCP.
- JSON-RPC: a simple standard for sending requests and responses as JSON.
Next up
Our agent now makes ten or more model calls per ticket. Multiply that by every team and every app, and you have a cost, reliability and security problem. In Article 17: The LLM gateway, we look at the piece of infrastructure that sits between your applications and the model providers, handling routing, fallbacks, caching, budgets, logging and PII filtering in one place.