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.

Good to know — A 'status' parameter typed as free-form string when it should be an enum is a common exam trap.
# 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.

Good to know — 'Just crash' is worse than 'return a useful error.' Silent failures are worst.

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 schema

Least 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

Using vague confidence instructions instead of categorical criteria
'Only flag high-confidence issues' shifts the model's tone but doesn't reduce false positives. Categorical criteria ('flag only when X') is testable and specific.
Piling negative instructions
'Don't hedge, don't disclaim, don't apologize' is weaker than 'respond with direct declarative statements only.' Positive framings outperform negatives.
Using markdown headers to structure long prompts
Claude is trained on XML tags as delimiters. <instructions>, <example>, <document>, <output_format> partition long prompts unambiguously.

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?

Next →