A one-page reference for the Messages API tool-use loop: request shape, response blocks, stop_reason, tool_choice, schema rules, server tools, and common gotchas.

Minimal Request

client.messages.create(
  model="claude-opus-4-7",
  max_tokens=1024,
  tools=[{"name":"...","description":"...",
          "input_schema":{...}}],
  tool_choice={"type":"auto"},   # optional
  messages=[{"role":"user","content":"..."}])

Response (Message object)

{
  "id": "msg_01ABC...",
  "type": "message",
  "role": "assistant",
  "model": "claude-opus-4-7",
  "stop_reason": "tool_use",   // see table below
  "stop_sequence": null,
  "content": [
    {"type":"text","text":"I'll check the weather."},
    {"type":"tool_use",
     "id":"toolu_01A09q90qw90lq917835lq9",
     "name":"get_weather",
     "input":{"location":"San Francisco, CA"}}
  ],
  "usage": {
    "input_tokens": 472,
    "output_tokens": 89,
    "cache_read_input_tokens": 0,
    "cache_creation_input_tokens": 0
  }
}

Access in SDK: resp.content (list of blocks), resp.stop_reason, resp.usage.input_tokens. Iterate blocks and check b.type == "tool_use" to find calls; use b.id, b.name, b.input.

tool_choice

ValueUse when
{"type":"auto"}Default; tool optional
{"type":"any"}Must call some tool
{"type":"tool","name":"X"}Must call this tool
{"type":"none"}Disable tools this turn

any / tool block text preamble and are incompatible with extended thinking.

stop_reason → Action

ValueAction
end_turnDone
tool_useRun tool, send tool_result, loop
max_tokensRaise cap
pause_turnRe-send to continue server-tool loop
refusalSurface to user

Content Blocks

Assistant (response)User (request)
texttext
thinking / redacted_thinkingimage
tool_use (id, name, input)document
server_tool_usetool_result (tool_use_id, content, is_error?)
web_search_tool_result
code_execution_tool_result

Order: tool_result must come before any text in a user message, and immediately after the assistant's tool_use turn.

The Loop (6 lines)

while True:
  resp = client.messages.create(model, tools=tools,
           messages=messages, max_tokens=1024)
  messages.append({"role":"assistant","content":resp.content})
  if resp.stop_reason != "tool_use": break
  results = [{"type":"tool_result","tool_use_id":b.id,
              "content": run(b.name, b.input)}
             for b in resp.content if b.type=="tool_use"]
  messages.append({"role":"user","content":results})

input_schema Keywords (supported)

KeywordWhereExample
typeanystring, integer, number, boolean, null, array, object
descriptionany"Stock ticker"
enum / constscalars["celsius","fahrenheit"]
defaultany"celsius"
formatstringdate, date-time, email, uri, uuid, ipv4
itemsarray{"type":"string"}
properties, requiredobject
additionalPropertiesobjectfalse (strict mode)
minItemsarray0 or 1 only
patternstring"^[A-Z]{1,5}$"
anyOf / allOfanycomposition

NOT supported (strict): minimum, maximum, minLength, maxLength, maxItems, uniqueItems, oneOf, not, recursion, regex lookaheads / backrefs. Put these in description.

Full Tool Schema Example

{
  "name": "search_products",
  "description": (
    "Search the product catalog by keyword and filters. "
    "Returns up to 20 matching products with id, name, price, "
    "and stock. Use when the user asks to find/browse products. "
    "Does NOT place orders, use place_order for that."
  ),
  "strict": true,
  "input_schema": {
    "type": "object",
    "additionalProperties": false,
    "required": ["query"],
    "properties": {
      "query": {
        "type": "string",
        "description": "Search keywords, e.g. 'wireless headphones'.",
        "pattern": "^.{1,200}$"
      },
      "category": {
        "type": "string",
        "enum": ["electronics","apparel","home","books","other"],
        "default": "other",
        "description": "Category filter."
      },
      "max_price": {
        "type": "number",
        "description": "Upper price bound in USD (must be > 0)."
      },
      "in_stock_only": {
        "type": "boolean",
        "default": true,
        "description": "If true, exclude out-of-stock items."
      },
      "tags": {
        "type": "array",
        "description": "Tag filters; products must match ALL.",
        "items": {"type": "string"},
        "minItems": 0
      },
      "sort": {
        "type": "object",
        "description": "Sort config.",
        "additionalProperties": false,
        "required": ["by"],
        "properties": {
          "by":   {"type":"string","enum":["price","rating","newest"]},
          "desc": {"type":"boolean","default": false}
        }
      },
      "released_after": {
        "type": "string",
        "format": "date",
        "description": "ISO date, e.g. '2026-01-01'."
      },
      "contact_email": {
        "type": ["string","null"],
        "format": "email",
        "description": "Optional email for saved-search alerts."
      },
      "id_or_sku": {
        "description": "Either a UUID (id) or SKU string.",
        "anyOf": [
          {"type":"string","format":"uuid"},
          {"type":"string","pattern":"^SKU-[A-Z0-9]{6}$"}
        ]
      }
    }
  }
}

Covers: type, description, enum, default, format, pattern, nested object, array + items, minItems, anyOf, nullable union, required, additionalProperties:false, strict:true.

tool_result Shapes

// Success, string
{"type":"tool_result","tool_use_id":"toolu_01",
 "content":"15°C"}

// Success, multi-block
{"type":"tool_result","tool_use_id":"toolu_01","content":[
  {"type":"text","text":"15°C"},
  {"type":"image","source":{"type":"base64",
   "media_type":"image/jpeg","data":"..."}}]}

// Error
{"type":"tool_result","tool_use_id":"toolu_01",
 "content":"Rate limit. Retry after 60s.",
 "is_error":true}

Where Tools Run

KindWho runsExamples
User-defined clientYour appget_weather, query_db
Anthropic-schema clientYour appbash, text_editor, computer, memory
ServerAnthropicweb_search, web_fetch, code_execution, computer use (beta), bash (beta), tool_search, memory, mcp connector

Server Tools (run by Anthropic)

Tooltype / namePurpose
Web searchweb_search_20250305 / web_searchQuery the live web; returns web_search_tool_result with citations.
Web fetchweb_fetch_20250910 / web_fetchFetch a specific URL (HTML/PDF) as context. Beta header required.
Code executioncode_execution_20250825 / code_executionPython sandbox with numpy, pandas, matplotlib. Files via Files API. Returns code_execution_tool_result.
Computer usecomputer_20250124 / computerScreenshot plus mouse/keyboard on a VM. Beta.
Bash (server)bash_20250124 / bashShell in the code-exec sandbox. Pairs with code_execution.
Text editortext_editor_20250728 / str_replace_based_edit_toolView / create / edit files in sandbox. No undo_edit in latest.
Memorymemory_20250818 / memoryPersistent file-backed memory across turns / sessions.
Tool searchtool_search_tool_regex_20251119 (regex) or ..._20250916 (semantic)Lazy-load tool defs from a large registry. Cuts prompt cost.
MCP connectormcp_servers (top-level, not in tools)Attach remote MCP servers; Claude calls their tools via server.

Usage: declare as {"type":"<versioned>","name":"<name>"} in tools (no input_schema). Many require a beta header (e.g. anthropic-beta: computer-use-2025-01-24, web-fetch-2025-09-10, code-execution-2025-08-25).

Response blocks: server tools emit server_tool_use plus a matching *_tool_result block (e.g. web_search_tool_result). You do not send tool_result back. Expect stop_reason: "pause_turn" on long server-tool loops; re-send the message to continue.

Definition Best Practices

Cost Overhead

Modelauto / noneany / tool
Opus 4.7 / Sonnet 4.6 / Haiku 4.5346 tok313 tok
Haiku 3.5264 tok340 tok

Plus tokens for the tools array, tool_use, and tool_result. Server tools add per-call fees.

Gotchas