Writing Effective Tools
Tool descriptions as prompts: clear contracts, meaningful errors, and token-efficient responses that agents can act on.
A tool is a contract with a non-deterministic caller
Traditional API design assumes a deterministic caller: code that always passes the right types in the right order. An agent is a non-deterministic caller — it reads your tool's name, description, and parameters as prompt text and decides, fresh each time, whether and how to call it. That changes everything about good design.
The core mistake is wrapping your existing API endpoints one-to-one and calling it done. Endpoints were designed for developers with documentation open in another tab. Tools must be designed for an agent with limited context, mid-task — which Anthropic calls designing the agent-computer interface with the same care as a UI.
Consolidate: fewer, workflow-shaped tools
Agents string granular tools together badly — each extra call is another chance to pass a wrong ID or waste tokens re-reading intermediate results. Merge steps that always occur together:
| Instead of | Provide | Why |
|---|---|---|
list_users + list_events + create_event | schedule_event | one call handles find-people-find-slot-book |
read_logs (returns everything) | search_logs | returns only relevant entries |
get_customer + get_orders + get_tickets | get_customer_context | one call, one coherent summary |
When tool counts grow anyway, namespace related tools under common prefixes — asana_projects_search, asana_tasks_create — so boundaries stay visible among hundreds of tools. Prefix versus suffix schemes measurably differ in agent performance, so test rather than assume.
Return context an agent can act on
What a tool returns is prompt text too.
- Semantic names over opaque IDs. Returning
"Q3 Planning Deck" (id: 8f3a...)instead of a bare UUID measurably cuts hallucinations — natural-language handles are what models are good at holding onto. - Offer response formats. A
response_formatparameter withconciseanddetailedoptions let Claude choose;concisesaved about a third of the tokens with no accuracy loss on Anthropic's evals. - Design truncation to steer. Claude Code caps tool responses at 25k tokens. When you truncate, say what to do next: "Results truncated. Make several small, targeted searches instead of one broad search." A truncation message is a free micro-prompt — spend it.
Add pagination, filtering, and sensible default limits so the well-behaved path is the default path.
Errors are prompts too
An agent hitting Error: 400 learns nothing and retries blind. An instructive error teaches the fix inside the failure:
Bad: Error 400: invalid parameter
Good: Invalid value for "date": got "tomorrow".
Use ISO format, e.g. date="2026-08-02".
One well-written error message converts a failure loop into a one-retry recovery. The same idea works preventively — poka-yoke (mistake-proofing) the arguments themselves: during Anthropic's SWE-bench work, changing a file tool to require absolute paths instead of accepting relative ones eliminated an entire error class. The team spent more time optimizing tools than the overall prompt, and it paid.
Descriptions: docstrings for a brand-new hire
Write every description as if onboarding someone smart who knows nothing about your system:
- Unambiguous parameter names:
user_id, notuser(name? email? ID?). - Explicit formats: "query uses Lucene syntax," "date is ISO 8601."
- A usage example in the description when the call shape isn't obvious.
- When to use it — and when not to, if a sibling tool overlaps.
This is high-leverage: small description refinements alone produced state-of-the-art SWE-bench results. And it can be automated — Anthropic ran a tool-testing agent that used each tool repeatedly and rewrote the descriptions based on where it stumbled; agents using the rewritten descriptions finished tasks 40% faster.
Evaluate like it's a product
You can't design tools well from the armchair. The loop:
- Build realistic multi-step tasks — "schedule a meeting with the design team next week and attach the latest mockups," not single-call unit tests.
- Measure everything: accuracy, runtime, tool-call counts, token consumption, error rates.
- Read the transcripts. This is where the design flaws are: redundant calls (the agent pages through
list_transactionstwelve times — it neededsearch_transactions), invalid parameters (your names are ambiguous), abandoned tools (your description doesn't say when to use it). - Let Claude refactor the tools. Feed it the transcripts and ask what confused it — models are startlingly good at diagnosing their own failure modes.
A concrete before/after: an agent kept paging through list_transactions on every task. Replacing it with search_transactions(query, limit, response_format) plus an instructive truncation message cut tool calls per task from 12 to 3.
The checklist
Before shipping a tool, ask: Would a new hire understand the description alone? Does it match a workflow, not an endpoint? Are responses concise by default and token-bounded? Do errors teach the fix? Could an argument's design prevent the mistake instead of reporting it? And have you actually watched an agent use it? Every "no" is a known failure mode waiting to fire.