usefulcheatsheets.com
Technology ยท AI

Claude API Tool Use

A quick reference for defining tools, running the agentic loop, and using the SDK tool runner with Claude.

Intermediate
usefulcheatsheets.com/technology/ai/claude-api-tool-use01 / 25
Technology/AI/Claude API Tool Use

TL;DR

  1. 01Define tools with a name, description, and JSON Schema input_schema.
  2. 02When stop_reason is tool_use, run the tool and send results back.
  3. 03Use the SDK's tool runner to handle the agentic loop automatically.
usefulcheatsheets.com/technology/ai/claude-api-tool-use02 / 25
Technology/AI/Claude API Tool Use

Define a Tool

input_schema Defines a tool's inputs as JSON Schema with a name and description.
tools = [{
    "name": "get_weather",
    "description": "Returns current weather for a given city.",
    "input_schema": {
        "type": "object",
        "properties": {"city": {"type": "string"}},
        "required": ["city"]
    }
}]
usefulcheatsheets.com/technology/ai/claude-api-tool-use03 / 25
Technology/AI/Claude API Tool Use

Define a Tool

(cont.)
tools parameter Passes the tools array to messages.create() alongside the prompt.
message = client.messages.create(
    model="claude-opus-4-8",
    max_tokens=1024,
    tools=tools,
    messages=[{"role": "user", "content": "Weather in Tokyo?"}]
)
usefulcheatsheets.com/technology/ai/claude-api-tool-use04 / 25
Technology/AI/Claude API Tool Use

Define a Tool

(cont.)
description field Tells Claude exactly when to call the tool, not just what it does.
"description": "Call this when the user asks about current weather."
usefulcheatsheets.com/technology/ai/claude-api-tool-use05 / 25
Technology/AI/Claude API Tool Use

Define a Tool

(cont.)
required array Marks which input fields Claude must always provide.
"required": ["city"]
usefulcheatsheets.com/technology/ai/claude-api-tool-use06 / 25
Technology/AI/Claude API Tool Use

The Agentic Loop

tool_use stop_reason Signals Claude wants to call a tool instead of finishing the reply.
if message.stop_reason == "tool_use":
    # extract tool calls, run them, send results back
usefulcheatsheets.com/technology/ai/claude-api-tool-use07 / 25
Technology/AI/Claude API Tool Use

The Agentic Loop

(cont.)
extract tool calls Filters the response content for tool_use blocks to find what Claude called.
tool_calls = [b for b in message.content if b.type == "tool_use"]
usefulcheatsheets.com/technology/ai/claude-api-tool-use08 / 25
Technology/AI/Claude API Tool Use

The Agentic Loop

(cont.)
tool_result block Packages a tool's output with the matching tool_use_id to send back.
tool_results.append({
    "type": "tool_result",
    "tool_use_id": call.id,
    "content": str(result)
})
usefulcheatsheets.com/technology/ai/claude-api-tool-use09 / 25
Technology/AI/Claude API Tool Use

The Agentic Loop

(cont.)
loop until end_turn Repeats the call-execute-respond cycle until Claude stops calling tools.
while message.stop_reason == "tool_use":
    message = client.messages.create(...)
usefulcheatsheets.com/technology/ai/claude-api-tool-use10 / 25
Technology/AI/Claude API Tool Use

SDK Tool Runner

@beta_tool Turns a plain Python function into a tool with an auto-generated schema.
from anthropic.lib.beta import beta_tool

@beta_tool
def get_weather(city: str) -> str:
    """Returns current weather for a given city."""
    return f"Sunny, 22C in {city}"
usefulcheatsheets.com/technology/ai/claude-api-tool-use11 / 25
Technology/AI/Claude API Tool Use

SDK Tool Runner

(cont.)
tool_runner() Runs the full call-execute-loop cycle automatically until Claude is done.
runner = client.beta.messages.tool_runner(
    model="claude-opus-4-8",
    max_tokens=1024,
    tools=[get_weather],
    messages=[{"role": "user", "content": "Weather in Tokyo?"}]
)
usefulcheatsheets.com/technology/ai/claude-api-tool-use12 / 25
Technology/AI/Claude API Tool Use

SDK Tool Runner

(cont.)
until_done() Blocks until the loop finishes and returns Claude's final response.
final_message = runner.until_done()
print(final_message.content[0].text)
usefulcheatsheets.com/technology/ai/claude-api-tool-use13 / 25
Technology/AI/Claude API Tool Use

Tool Choice Control

tool_choice: auto Lets Claude decide whether to call a tool; this is the default.
tool_choice={"type": "auto"}
usefulcheatsheets.com/technology/ai/claude-api-tool-use14 / 25
Technology/AI/Claude API Tool Use

Tool Choice Control

(cont.)
tool_choice: tool Forces Claude to call one specific named tool on this turn.
tool_choice={"type": "tool", "name": "get_weather"}
usefulcheatsheets.com/technology/ai/claude-api-tool-use15 / 25
Technology/AI/Claude API Tool Use

Tool Choice Control

(cont.)
tool_choice: none Disables tool calls mid-conversation once you have the data you need.
tool_choice={"type": "none"}
usefulcheatsheets.com/technology/ai/claude-api-tool-use16 / 25
Technology/AI/Claude API Tool Use

Tool Choice Control

(cont.)
disable_parallel_tool_use Forces exactly one tool call per turn when call order matters.
tool_choice={"type": "auto", "disable_parallel_tool_use": True}
usefulcheatsheets.com/technology/ai/claude-api-tool-use17 / 25
Technology/AI/Claude API Tool Use
In Practice: Build a Weather Tool Loop
  1. 01Defining input_schema up front lets Claude know exactly what arguments the tool expects.
  2. 02Checking stop_reason for tool_use avoids treating a tool call as a finished answer.
  3. 03Sending back a tool_result with the matching tool_use_id tells Claude which call the output belongs to.
  4. 04Looping until end_turn handles the case where Claude chains more than one tool call.
import anthropic

client = anthropic.Anthropic()
tools = [{
    "name": "get_weather",
    "description": "Call this when the user asks about current weather in a city.",
    "input_schema": {"type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"]}
}]

messages = [{"role": "user", "content": "What's the weather in Tokyo?"}]
message = client.messages.create(model="claude-opus-4-8", max_tokens=1024, tools=tools, messages=messages)

while message.stop_reason == "tool_use":
    tool_calls = [b for b in message.content if b.type == "tool_use"]
    messages.append({"role": "assistant", "content": message.content})
    results = [{"type": "tool_result", "tool_use_id": c.id, "content": "Sunny, 22C"} for c in tool_calls]
    messages.append({"role": "user", "content": results})
    message = client.messages.create(model="claude-opus-4-8", max_tokens=1024, tools=tools, messages=messages)

print(message.content[0].text)
usefulcheatsheets.com/technology/ai/claude-api-tool-use18 / 25
Technology/AI/Claude API Tool Use
FAQ 01 / 05

Give the tool a name, a clear description of when to use it, and an input_schema written as JSON Schema. Claude reads the description to decide whether and when to call the tool, so be specific about the trigger condition, not just what the tool does.

usefulcheatsheets.com/technology/ai/claude-api-tool-use19 / 25
Technology/AI/Claude API Tool Use
FAQ 02 / 05

The response comes back with stop_reason: "tool_use" and one or more tool_use content blocks containing the tool name, input, and an ID. Execute the tool yourself, then send the result back as a tool_result block with a matching tool_use_id.

usefulcheatsheets.com/technology/ai/claude-api-tool-use20 / 25
Technology/AI/Claude API Tool Use
FAQ 03 / 05

Use the tool runner for most custom-tool agents โ€” it handles the call-execute-loop cycle automatically and still gives you hooks for approval gates and logging. Write a manual loop only when you need full control over the request shape or want to avoid the beta dependency.

usefulcheatsheets.com/technology/ai/claude-api-tool-use21 / 25
Technology/AI/Claude API Tool Use
FAQ 04 / 05

Set tool_choice to {"type": "tool", "name": "your_tool"} to require that exact tool on the next turn. Use {"type": "any"} to require some tool call, or {"type": "none"} to disable tools mid-conversation.

usefulcheatsheets.com/technology/ai/claude-api-tool-use22 / 25
Technology/AI/Claude API Tool Use
FAQ 05 / 05

Yes โ€” by default Claude can request multiple tool calls in a single turn, and your code should execute them and return every result in one combined message. Set disable_parallel_tool_use: true on tool_choice if your workflow needs exactly one tool call per turn.

tool_calls = [b for b in message.content if b.type == "tool_use"]
for call in tool_calls:
    print(call.name, call.input, call.id)
usefulcheatsheets.com/technology/ai/claude-api-tool-use23 / 25
Technology/AI/Claude API Tool Use

Tips

  1. 01Use tool_choice: {type: "tool"} to force a specific tool call instead of asking Claude for structured JSON.
  2. 02Write clear, prescriptive tool descriptions that say exactly when Claude should call them, not just what they do.

Warnings

  1. 01Always send the full assistant content block, including tool_use blocks, back in the next turn or you'll get a validation error.
  2. 02Return every tool_result for a turn in a single message โ€” splitting them across messages trains Claude to stop making parallel calls.
usefulcheatsheets.com/technology/ai/claude-api-tool-use24 / 25
Useful Cheatsheets

Fast, clear reference sheets for technology, finance, health, and everyday adulting.

usefulcheatsheets.com