Cruxly › AI engineering › Agentic Systems
Designing Tools an Agent Can Actually Use
a tool is an interface whose user can't ask you what you meant
Open the interactive lessonPrompt: a team gives its calendar agent one tool per REST endpoint — list_users, list_events, get_event, create_event, update_event — each returning the raw JSON the API returns. The agent books meetings at the wrong time, runs out of context on busy calendars, and sometimes calls the same endpoint thirty times in a row. Redesign the tool layer.
30 minutes first. The naive fix is a better system prompt. The actual problem is that the tools were designed for a programmer reading documentation, and the user here is a model reading a tool description once, mid-task, with limited context.
Fewer, bigger tools — not one per endpoint
- Wrapping every API endpoint as a tool is the default mistake. It pushes the work of chaining calls onto the agent, and every extra step is another chance to go wrong and another chunk of context spent.
- Build tools around tasks, not endpoints. Anthropic's guidance on writing agent tools uses exactly this example: instead of
list_users+list_events+create_event, oneschedule_eventtool that finds a free slot and books it. - Every tool you add is one more thing the model has to choose between. A long list of overlapping tools makes picking the right one harder, so cut tools that the agent does not need for its actual tasks.
- Namespace related tools by service and by resource (
calendar_search,calendar_book,crm_contacts_search) so the model can tell at a glance which system a tool belongs to — especially once tools from several systems (for example several MCP servers) are loaded together. The exact scheme matters more than you'd guess: Anthropic reports that choosing prefix- versus suffix-based namespacing had "non-trivial effects" on their tool-use evaluations, so test yours.
list_users, list_events, get_event, create_event, update_event
→ the agent must chain 3-4 calls, and hold every intermediate result in context
calendar_find_slot(attendees, duration, window)
calendar_book(slot, title, attendees)
→ two task-shaped tools; the chaining happens in your code, not in the model's head
Return meaning, and cap the size
What a tool returns goes straight into the model's context, so treat the response as part of the prompt.
- Prefer names over opaque IDs. Anthropic reports that agents handle natural-language names and identifiers much more reliably than arbitrary UUIDs. Return
"Priya Sharma (Design)", not"usr_8f3a9c2e"— keep the ID too if a later call needs it. - Return only the fields the task needs. A raw API response with forty fields fills context with noise the model then has to read past.
- Offer a concise and a detailed mode. A
response_formatparameter with"concise"and"detailed"options lets the agent ask for detail only when it needs it. In Anthropic's Slack example the concise version used 72 tokens against 206 for the detailed one — about a third. - Paginate, filter and truncate by default, with sensible defaults. A search that can return 5,000 events will, eventually. Claude Code, for comparison, caps a tool response at 25,000 tokens by default.
- When you truncate, say so and say what to do next. "Showing 20 of 340 results. Narrow the date range or add an attendee filter." A silent cut makes the agent think it saw everything.
:::warn Errors are instructions too "Error 400" teaches the model nothing. "date must be YYYY-MM-DD, got '7 Oct'" lets it fix the call on the next try. Write tool errors for the reader who has to recover from them. :::
Separate tools that read from tools that act. A search can be retried freely; calendar_book cannot. For any tool that changes state:
- Make it idempotent. Take an idempotency key, so a retry after a timeout returns the original booking instead of making a second one — the same discipline as a payment API.
- Offer a dry run or confirmation step for destructive actions, and gate the dangerous ones in code — see the approval gates in Guardrails for an Agent That Takes Real Actions.
The description is a prompt
- The description and input schema are the main documentation the model gets, and it reads them on every call. Anthropic calls refining tool descriptions one of the most effective ways to improve a tool — in 2024 it reported that Claude 3.5 Sonnet reached state-of-the-art on SWE-bench Verified after precise refinements to its tool descriptions (a historical data point; that model and result are long superseded).
Dated note (Anthropic tool-use docs, read 2026-10-22): forced tool choice is not universal. On Claude Opus 5.5, Sonnet 5.5, Fable 5.1 and Mythos 5.1, tool_choice of any or tool returns a 400 error, and manual extended thinking also rejects it. The documented pattern is auto plus strict tool use (so inputs are schema-valid) plus an instruction in the prompt naming the tool to call. Check your model's current restriction before designing around a forced call.
- Write it for a capable new teammate: what the tool is for, when to use it instead of a similar tool, what each parameter means, and what comes back. Anything you would explain out loud belongs in the description.
- Make parameter names unambiguous.
user_idbeatsuser;start_time_utcbeatstime. A model guessing what a field means is a model that will sometimes guess wrong. - State the limits. "Returns at most 50 events", "times are in UTC" — the things a developer would only find by testing.
- Let the schema enforce what the description asks for. Use enums for fixed choices, mark required fields, and specify formats such as ISO-8601 dates, then validate inputs before running the tool. A bad call rejected with a clear error is far cheaper than a bad call executed.
- Third-party tool descriptions are part of your prompt — review them like code. A description loaded from an MCP server you don't control can carry injected instructions; see MCP Servers, Prompt Injection, and Tamper-Evident Audit.
Evaluate tools the way you test code
You can't tell whether a tool design is good by reading it. Measure it on tasks:
@@ 1 | Write realistic tasks Use real requests that need several steps, with a known correct outcome — "move Tuesday's design review to the first free slot on Thursday with the same attendees."
@@ 2 | Run the agent and record more than pass/fail Track task success, number of tool calls, tokens used, and tool errors. A design that succeeds but needs thirty calls is a cost and latency problem waiting to happen.
@@ 3 | Read the transcripts The numbers show that something is wrong; the transcript shows why — a description the model misread, a field it kept asking for, a result too long to use.
@@ 4 | Change one thing, keep a held-out set Improve descriptions or merge tools, then re-run on tasks you didn't tune on, so you know the gain is real and not overfitting to your test set. Anthropic's write-up describes pasting the evaluation transcripts into Claude Code so it can propose improvements to the tools and their descriptions, and relying on held-out test sets to make sure the gains weren't overfitting.
:::key The interview signal Saying "I'd evaluate the tools on held-out tasks and read the transcripts" separates someone who has built an agent from someone who has only prompted one. :::
How to say it in the interview
"An API is designed for a developer who reads the docs once and writes code against it. A tool is read by a model on every call, inside a limited context window, with no chance to ask what a field means. So I would design fewer, higher-level tools, return meaning instead of raw IDs, cap how much each call can return, and then evaluate the tools on real tasks the same way I would test code."
Checklist
- Replaced one-tool-per-endpoint with a few task-shaped tools
- Namespaced related tools by system
- Returned human-readable names alongside IDs, and only the fields the task needs
- Capped output with pagination or truncation, and said explicitly when results were cut
- Wrote error messages that tell the model how to fix the call
- Treated tool descriptions as prompts: purpose, when to use, unambiguous parameter names, stated limits
- Made state-changing tools idempotent and gated destructive ones
- Enforced inputs with the schema (enums, required fields, formats) and validated before executing
- Evaluated tools on realistic held-out tasks, tracking calls and tokens as well as success, and read the transcripts
Related lessons
- The Agent Loop in Depth: ReAct, Plan-and-Execute, Reflection and Stop Conditions
- Agent Memory: Working, Episodic, Semantic and Procedural, Without the Rot
- Frameworks, Protocols and Durable Execution: MCP, A2A and Long-Running Agents
- MCP Servers, Prompt Injection, and Tamper-Evident Audit
- Guardrails for an Agent That Takes Real Actions
- Coding Agents and Computer-Use Agents: Harness, Sandbox and Verification