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":"..."}])
{
"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.
| Value | Use 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 & are incompatible with extended thinking.
| Value | Action |
|---|---|
end_turn | Done |
tool_use | Run tool → send tool_result → loop |
max_tokens | Raise cap |
pause_turn | Re-send to continue server-tool loop |
refusal | Surface to user |
| Assistant (response) | User (request) |
|---|---|
text | text |
thinking / redacted_thinking | image |
tool_use (id, name, input) | document |
server_tool_use | tool_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.
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})
| Keyword | Where | Example |
|---|---|---|
type | any | string, integer, number, boolean, null, array, object |
description | any | "Stock ticker" |
enum / const | scalars | ["celsius","fahrenheit"] |
default | any | "celsius" |
format | string | date, date-time, email, uri, uuid, ipv4 |
items | array | {"type":"string"} |
properties, required | object | — |
additionalProperties | object | false (strict mode) |
minItems | array | 0 or 1 only |
pattern | string | "^[A-Z]{1,5}$" |
anyOf / allOf | any | composition |
NOT supported (strict): minimum, maximum, minLength, maxLength, maxItems, uniqueItems, oneOf, not, recursion, regex lookaheads/backrefs. Put these in description.
{
"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.
// 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}
| Kind | Who runs | Examples |
|---|---|---|
| User-defined client | Your app | get_weather, query_db |
| Anthropic-schema client | Your app | bash, text_editor, computer, memory |
| Server | Anthropic | web_search, web_fetch, code_execution, computer use (beta), bash (beta), tool_search, memory, mcp connector |
| Tool | type / name | Purpose |
|---|---|---|
| Web search | web_search_20250305 / web_search | Query the live web; returns web_search_tool_result with citations. |
| Web fetch | web_fetch_20250910 / web_fetch | Fetch a specific URL (HTML/PDF) as context. Beta header required. |
| Code execution | code_execution_20250825 / code_execution | Python sandbox w/ numpy, pandas, matplotlib. Files via Files API. Returns code_execution_tool_result. |
| Computer use | computer_20250124 / computer | Screenshot + mouse/keyboard on a VM. Beta. |
| Bash (server) | bash_20250124 / bash | Shell in the code-exec sandbox. Pairs with code_execution. |
| Text editor | text_editor_20250728 / str_replace_based_edit_tool | View/create/edit files in sandbox. No undo_edit in latest. |
| Memory | memory_20250818 / memory | Persistent file-backed memory across turns/sessions. |
| Tool search | tool_search_tool_regex_20251119 (regex) or ..._20250916 (semantic) | Lazy-load tool defs from a large registry. Cuts prompt cost. |
| MCP connector | mcp_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 + 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.
github_list_prs, not bare search.manage_pr w/ action param beats three tools."strict":true + "additionalProperties":false → guaranteed schema match.tool_choice:any + strict:true for guaranteed valid calls.| Model | auto / none | any / tool |
|---|---|---|
| Opus 4.7 / Sonnet 4.6 / Haiku 4.5 | 346 tok | 313 tok |
| Haiku 3.5 | 264 tok | 340 tok |
+ tokens for tools array, tool_use, tool_result. Server tools add per-call fees.
tool_choice mid-convo invalidates prompt cache.any/tool + extended thinking → 400 error.tool_result must immediately follow matching tool_use turn.enum/const/pattern/property names (cached separately).