Tool Use & MCP Reference

Reference intermediate

A working reference for giving agents hands: the JSON tool-schema template, naming conventions, error-handling patterns, and when to use the Model Context Protocol (MCP) versus wiring tools by hand. Examples use Anthropic's Claude tool use API; the patterns carry to any function-calling model. Concepts: Tool Use — Giving Agents Hands.

Tool Definition: Anatomy

Each client tool is a JSON object with three required fields.

Field Type Required Notes
name string yes Must match ^[a-zA-Z0-9_-]{1,64}$. The identifier the model emits.
description string yes Plaintext: what it does, when to use it, when NOT to. The biggest lever on quality.
input_schema object yes A JSON Schema object; top level must be "type": "object".
input_examples array no Schema-valid example inputs; helps with nested/format-sensitive params.

Top-level input_schema does not support oneOf / allOf / anyOf — keep the root an object.

Clean Schema Template

Per-parameter description strings are read by the model — write them.

{
  "name": "search_orders",
  "description": "Search a customer's orders by status and date. Use when the user asks about past or pending orders. Returns up to 50 orders with id, status, and total. Does NOT return line items or issue refunds.",
  "input_schema": {
    "type": "object",
    "properties": {
      "customer_id": {"type": "string", "description": "Customer UUID, e.g. 'cus_8a31'."},
      "status": {"type": "string",
        "enum": ["pending", "shipped", "delivered", "cancelled"],
        "description": "Filter to one status. Omit for all."},
      "since": {"type": "string", "format": "date",
        "description": "ISO-8601 date (YYYY-MM-DD); orders on or after this date."}
    },
    "required": ["customer_id"]
  }
}

Naming & Description Conventions

Rule Bad Good
Namespace by service send chat_send_message
Consolidate related actions create_pr, merge_pr github_pr with an action enum
Verb-first and concrete data query_database
Describe behaviour, not just name "Gets the price." "Returns the latest USD trade price for a US-listed ticker."

Vendor guidance: 3-4 sentences per description; fewer high-capability tools over many narrow ones; namespace across services; return only high-signal fields and stable IDs.

The Agentic Loop

Each turn: call messages.create(..., tools=TOOLS); if stop_reason == "tool_use", run each tool_use block via dispatch_tool (below), append the assistant turn plus a user message of tool_result blocks, and re-call. Loop until end_turn.

Each tool_result.tool_use_id MUST echo the id of the tool_use it answers; that is how the model correlates call and response. Set is_error: true on failure (see below).

Error Handling: Return, Don't Raise

The key discipline: when a tool fails, catch the exception and return it as a tool_result with is_error: true rather than letting it kill the loop. A clear message lets the model understand the failure and retry.

Failure Anti-pattern Pattern
Tool raises Exception kills the loop Catch; return is_error: true with the message
Bad input Silent wrong answer Validate; return which field was invalid
Upstream 500 Retry forever Return the error; let the model decide
Empty result Return null Return text ("No orders matched.") for signal
def dispatch_tool(block):
    try:
        if block.name != "search_orders":
            return _error(block.id, f"Unknown tool: {block.name}")
        content = json.dumps(search_orders(**block.input))
        return {"type": "tool_result", "tool_use_id": block.id, "content": content}
    except Exception as exc:                  # never let this escape the loop
        return _error(block.id, f"{type(exc).__name__}: {exc}")

def _error(tid, msg):
    return {"type": "tool_result", "tool_use_id": tid, "content": msg, "is_error": True}

Error messages are read by the model: state what failed and what a valid call looks like ("since must be YYYY-MM-DD; got '03/2026'").

Controlling When Tools Fire

The tool_choice parameter has four modes:

  • {"type": "auto"} — model decides per turn (default when tools present)
  • {"type": "any"} — must call some tool, model picks which
  • {"type": "tool", "name": "..."} — forces a specific tool
  • {"type": "none"} — no tools (default when no tools)

any and tool prefill the turn, so no preamble precedes the call.

Model Context Protocol (MCP)

MCP is an open standard for connecting AI applications to external systems — its maintainers call it "a USB-C port for AI applications." Build a server once and any MCP-capable client (Claude, ChatGPT, VS Code, Cursor) can use it.

Architecture & Primitives

A host (the AI app) spins up one client per server, each a dedicated connection. The data layer is JSON-RPC 2.0; transport is pluggable — stdio (local process, one client, no network overhead) or Streamable HTTP (remote, HTTP POST plus optional Server-Sent Events, OAuth/bearer auth). A server exposes three primitives, each discovered via a */list method.

Primitive What it is Example
Tools Functions invoked via tools/call Run a query, send a message
Resources Read-only context (resources/read) A DB schema, a file's contents
Prompts Reusable interaction templates A few-shot workflow template

An MCP tool mirrors a Claude tool (name, description, inputSchema). Discovery is dynamic: servers emit notifications/tools/list_changed to make clients re-fetch.

MCP vs Ad-Hoc Function Calling

Ad-hoc function calling when... MCP when...
Tools private to one app Tools reused across clients/hosts
Few tools, coupled to your code A growing, shareable surface
Lowest latency, no extra process You want standard discovery/lifecycle
Prototyping a single agent Distributing for others to install

Rule of thumb: start with direct function calling in one agent; adopt MCP when a capability must be shared or distributed. The two coexist in the same loop.

Quick Checklist

  • [ ] 3-4 sentence description per tool, covering when NOT to use it.
  • [ ] Each parameter has a description; enums constrain choices; root schema is object.
  • [ ] Names namespaced; related actions consolidated under an action enum.
  • [ ] Execution catches exceptions, returns is_error: true — the loop never crashes.
  • [ ] Responses return only high-signal fields and stable IDs.
  • [ ] Right model: direct calls for one app, MCP for shared/distributed surfaces.

Related: Building Your First Agent and Agent Safety & Guardrails.