Lesson 1 of 3 in Tool Design & MCP Integration
4.1 · Tool design fundamentals
Tool design is where the most-overlooked exam points hide. Tool descriptions are the PRIMARY mechanism Claude uses to pick which tool to call — not an afterthought. This lesson covers the description structure that makes tools discoverable, the schema patterns that make them safe, and the design rules that keep them from blowing up in production.
The description is the interface
Claude picks which tool to call based on names and descriptions. A vague name ('process_data') or a marketing-style description ('a powerful tool for data') gets misused. Descriptions should say what the tool does, when to use it, when NOT to use it, and what it returns.
Good: 'Fetch order details by order_id. Use for order lookups; do not use for search — use search_orders for that. Returns {status, total, items[], customer}.'
Bad: 'Gets orders.'Schema design principles
Required vs optional should match real usage. Use enums to constrain choices rather than free-form strings. Every field gets a description. Fewer, well-named parameters beat many overlapping ones.
# BAD — vague, no constraints
{
"name": "update_ticket",
"description": "Updates a ticket",
"input_schema": {
"type": "object",
"properties": {
"id": {"type": "string"},
"status": {"type": "string"}, # any string!
"data": {"type": "object"} # what fields?
}
}
}
# GOOD — enums, required, described
{
"name": "update_ticket_status",
"description": "Change a ticket's status. Use for status
transitions only. Do NOT use to change assignees or
priority — use update_ticket_assignment for that.",
"input_schema": {
"type": "object",
"required": ["ticket_id", "new_status"],
"properties": {
"ticket_id": {
"type": "string",
"description": "Ticket ID, e.g. 'TKT-1234'"
},
"new_status": {
"type": "string",
"enum": ["open", "in_progress", "resolved", "closed"],
"description": "Target status"
},
"resolution_note": {
"type": "string",
"description": "Required when new_status is 'resolved'"
}
}
}
}Idempotency and safe retry
Tools should be safe to retry when possible. Design mutating tools to accept an idempotency key. Read tools should be pure. This lets the agent retry on transient failures without doubling side effects.
Errors are an interface
Return structured errors the model can reason about: {error: 'rate_limited', retry_after_seconds: 30} instead of a generic exception. The model can use structured errors to decide intelligently: wait, retry, escalate, choose a different tool.
tool_choice — how you control tool calling
The tool_choice parameter tells Claude how to handle tools. Three modes: 'auto' (default — the model decides whether to call a tool or return text), 'any' (must call SOME tool, model picks which), or a forced name like {type: 'tool', name: 'extract_invoice'} which requires that specific tool. Forced tool use is how you get reliable structured output.
# auto: model may return text or call a tool
tool_choice = {"type": "auto"}
# any: must call some tool, model chooses which
tool_choice = {"type": "any"}
# forced: must call this specific tool
tool_choice = {"type": "tool", "name": "extract_invoice"}
# → structured output guaranteed against that schemaLeast privilege
Each tool should have the narrowest capability that does the job. A 'read customer' tool shouldn't be able to write. A 'search products' tool shouldn't return prices unless the caller needs them. Reduce the blast radius of any single misuse.
Takeaways
- Tool description = selection logic (what, when, when-not, returns)
- Use enums; describe every field
- Structured errors enable model self-recovery
- Least privilege per tool
Exam traps
Practice scenario
A code-review prompt says 'be conservative and only flag high-confidence issues.' Reviewers still get lots of trivial style flags. What's the highest-leverage first fix?