Tools: how it touches the world
A model that can only talk is a consultant. A model with tools is a worker. The tool layer is where agents become useful — and where they become dangerous.
- You can write a tool definition that a model will actually use correctly, and spot one that it will misuse.
- You know the four risk tiers of an action, and why the default for "run shell command" should never be "yes".
Tools are the agent's hands. Each one is a small function with three parts: a name, a description of when to use it, and a strict schema for its inputs. The model never runs your code. It emits a structured request — "call search_web with this query" — and the harness decides whether to honour it.
4.1The definition is the interface
Tool descriptions are prompt engineering with consequences. A vague description produces wrong calls, and wrong calls produce confident nonsense. Compare:
| Weak | Strong |
|---|---|
"name": "search""Search for stuff." |
"name": "search_web""Search the public web for current information. Use when the answer may have changed since training or when the user cites a URL. Do not use for private documents — use search_docs instead." |
| Free-text arguments, no validation | JSON schema with types, enums, defaults, and required fields; rejected before execution if invalid |
| Returns a raw dump of 200 results | Returns the top 5 with title, URL, date and a trimmed snippet — everything the model needs, nothing it doesn't |
| Failure returns an exception | Failure returns a structured message the model can act on: "rate limited, retry in 30s", "no results for that query" |
{
"name": "read_invoice",
"description": "Read one invoice PDF and return its line items. Use when the user
references an invoice number or an uploaded PDF. Read-only.",
"parameters": {
"type": "object",
"properties": {
"path": { "type": "string", "description": "Path under /invoices/" },
"format": { "type": "string", "enum": ["table", "json"], "default": "json" }
},
"required": ["path"],
"additionalProperties": false
}
}
4.2Four tiers of risk
Not all tools are equal, and the difference is not technical — it's about what happens when the agent is wrong. Every serious harness classifies actions, then applies a policy per tier.
low Read-only · auto-approve
Watch for: a "read" that leaks data — reading the secrets file is technically read-only and completely unacceptable.
medium Writes to your own workspace
high Irreversible or outward-facing
critical System & secrets
Write the permission policy before the tool. If you can't say in one sentence what the worst outcome of a wrong call is, the tool is too powerful — split it into smaller ones. "Delete invoice" is a bad tool; "mark invoice as voided" is a good one, because it is reversible and auditable.
4.3Sandboxes: where dangerous code goes
Code execution is the single most useful agent tool and the most dangerous. The answer is not "don't" — it's "not on your machine". Options range from a container to a micro-VM with no network:
| Isolation | Startup | Use it when |
|---|---|---|
| Local subprocess | instant | Only for code you wrote. Never for model-generated code. |
| Container (Docker) | ~100 ms | Standard workloads; no host filesystem, explicit network policy, resource limits. |
| Cloud sandbox VM | ~1 s | Long-running analysis, packages to install, data that must not touch your laptop. |
| Micro-VM / gVisor | ~100 ms | Multi-tenant or untrusted code; strongest isolation without a full VM per task. |
| WebAssembly | ~1 ms | Edge execution, plugins, small deterministic transforms. |
Whatever you choose, the non-negotiables are the same: no ambient credentials (mount only what the task needs), a timeout, a memory and CPU cap, no inbound network unless the task requires it, and a fresh environment per task so one run cannot influence the next.
4.4MCP: one plug for all tools
Before MCP (the Model Context Protocol, released in 2024), every framework had its own tool format, so a tool written for one agent had to be rewritten for the next. MCP standardises the plug: a small server exposes tools (actions), resources (data with a URI) and prompts (templates), and any compatible client can discover and call them over JSON-RPC.
A web page, an email, or a PDF that your agent reads can contain instructions. When that text lands in the context, the model cannot reliably tell "data I retrieved" from "instructions from my operator". This is prompt injection, and the only dependable defenses are structural: a permission gate on dangerous tools, never letting tool output trigger an irreversible action without approval, and treating every external string as hostile. Module 08 shows what it looks like in practice.
Your agent reads supplier emails and can also issue purchase orders. What is the correct control?
60-second recap
- A tool is a contract: name, when-to-use description, strict input schema, small useful output, structured failures.
- Classify before you grant. Read-only auto-approves; irreversible and outward-facing actions need a human gate; system-level access is denied by default.
- Model-generated code runs in a sandbox — no ambient credentials, timeouts, resource caps, fresh environment.
- MCP makes tools portable. Write once, expose to any client that speaks the protocol.
- Tool output is hostile input. Prompt injection is defeated by permissions, not by politely asking the model to behave.