Mindket

Claude tool use: define tools and handle tool calls in Python

A black banner titled "Claude API" over the line "Calls, tools, caching and an agent loop".

Claude tool use lets the model ask your code to run a function. You describe each tool with a name, a description and a JSON Schema. When Claude wants one, the response ends with stop_reason tool_use. You run the function, then send a tool_result in your next user message. The model never runs anything itself.

In this lesson

  • Describe each tool with a name, a long description and a JSON Schema.
  • Answer every tool_use block with a tool_result that carries the same id.
  • Send parallel results together, and report failures with is_error.
  • Know which tool_choice values current models reject.
All courses
On this page
  1. Before you start
  2. Build the tool_use and tool_result round trip
  3. Write tool definitions Claude can use
  4. Steer the call with tool_choice
  5. Several tool calls in one response
  6. Report errors so Claude can recover
  7. What Anthropic and Alex Albert posted about designing tools
  8. Common mistakes
  9. Try it yourself
  10. Next
  11. Check yourself
  12. Frequently asked questions
  13. Sources

Before you start

Finish lesson 1 first: this lesson reuses its client, its key and its loop over content blocks. Tool use runs on the same Messages endpoint, with a tools list added to the request.

The model never runs anything. For client tools, the ones you define, your code runs the function and reports back. Server tools such as web search, web fetch and code execution run on Anthropic's side, so a response can arrive with their results already inside. This lesson covers client tools. The tool use overview draws the same line.

Build the tool_use and tool_result round trip

One request, one tool, two calls. The code below defines get_weather, asks a question that needs it and handles a single round trip. Lesson 4 wraps the same steps in a loop. The weather function is a stand-in written for this lesson, so replace it with a real lookup.

Two rules decide whether the second request is accepted. The user message with the results must come right after the assistant message that holds the tool_use blocks, and the tool_result blocks must come first in its content, before any text. Break either one and the API returns a 400.

import json
import anthropic

client = anthropic.Anthropic()

tools = [
    {
        "name": "get_weather",
        "description": (
            "Get the current weather for a city. Use it when the user asks about "
            "weather, temperature or whether to bring an umbrella. It returns the "
            "temperature in Celsius and a short condition. It does not forecast."
        ),
        "input_schema": {
            "type": "object",
            "properties": {
                "city": {"type": "string", "description": "A city name, for example Lisbon"},
            },
            "required": ["city"],
        },
    }
]


def get_weather(city: str) -> str:
    # Stand-in for a real weather API call.
    return json.dumps({"city": city, "temp_c": 18, "condition": "light rain"})


messages = [{"role": "user", "content": "Do I need an umbrella in Lisbon today?"}]

response = client.messages.create(
    model="claude-opus-5-5", max_tokens=1024, tools=tools, messages=messages
)

if response.stop_reason == "tool_use":
    messages.append({"role": "assistant", "content": response.content})
    results = []
    for block in response.content:
        if block.type == "tool_use":
            results.append(
                {
                    "type": "tool_result",
                    "tool_use_id": block.id,
                    "content": get_weather(**block.input),
                }
            )
    messages.append({"role": "user", "content": results})
    response = client.messages.create(
        model="claude-opus-5-5", max_tokens=1024, tools=tools, messages=messages
    )

for block in response.content:
    if block.type == "text":
        print(block.text)
  1. Define the tool with a name, a description and an input_schema, then pass the list as tools.
  2. Send the user message. Claude replies with stop_reason set to tool_use and one or more tool_use blocks, each with an id, a name and an input.
  3. Append response.content to the history as the assistant message, whole and unedited. The docs want every thinking block back unchanged when tools are in play.
  4. Run your function for each tool_use block and build a tool_result block with the same id as tool_use_id.
  5. Send all the results in one user message and call the API again. Claude now writes the final answer.

Write tool definitions Claude can use

The description decides most of the outcome. The docs call it the most important factor in tool performance. They ask for at least three or four sentences that say what the tool does, when to use it, what each parameter means and what it returns.

Fewer, broader tools work better than many narrow ones, so fold related operations into one tool with an action parameter. Prefix names by service when several tools sit side by side, as in github_list_prs. Return only high-signal data from the function, because everything it returns is input tokens on the next call.

Tool fields from the define tools page, read on 5 November 2026.
FieldNeededWhat to know
nameYesMust match ^[a-zA-Z0-9_-]{1,128}$
descriptionStrongly advisedPlain text, three or four sentences at least
input_schemaYesA JSON Schema object with properties and required
input_examplesNoSample inputs that must validate against the schema, about 20 to 50 tokens each for a simple tool and 100 to 200 for a nested one
strictNoSet to true to make Claude's inputs follow the schema
cache_controlNoA cache breakpoint on the tool list, covered in lesson 3

Steer the call with tool_choice

By default Claude decides for itself whether a request needs a tool. tool_choice overrides that. Its four values behave differently on current models, and the release notes show the forced ones being turned off one model at a time since September.

Parallel calls are controlled from the same field. With auto, setting disable_parallel_tool_use to true limits Claude to at most one tool call per turn.

Tool use changes in the Claude release notes
  1. Tool use leaves beta

    No beta header on the Claude API, Bedrock or Vertex AI.

  2. disable_parallel_tool_use arrives

    Set it inside tool_choice to keep Claude to at most one tool per turn.

  3. tool_choice gains none

    You can stop Claude from calling any tool.

  4. Tool helpers and the tool runner in beta

    The Python and TypeScript SDKs can run the loop for you.

  5. Tool use examples drop the beta header

    So do tool search, memory, code execution and web fetch.

  6. Fable 5.1 rejects forced tool_choice

    On Fable 5.1 and Mythos 5.1, any and tool return an error.

  7. Opus 5.5 rejects it too

    Tools can also be defined in a mid-conversation system message, in beta.

  8. Sonnet 5.5 follows

    Forced tool use returns an error here as well.

Source: Claude Docs: Release notes (read November 5, 2026)

From the define tools page, read on 5 November 2026.
tool_choiceBehaviorWatch for
{"type": "auto"}Claude decides whether to call a toolThe default when you pass tools
{"type": "any"}Claude must call one of your toolsA 400 on the models in the box below
{"type": "tool", "name": "get_weather"}Claude must call that toolThe same 400, and a forced call skips thinking
{"type": "none"}Claude may not call a toolThe default when you pass no tools

Several tool calls in one response

Ask about the weather in two cities and Claude can return two tool_use blocks in the same response. Your code decides whether to run them one after the other or at the same time. The reply matters more. Put every tool_result into a single user message.

Sending each result as its own user message works at first, but the parallel tool use page warns that it teaches Claude to stop making parallel calls. Each result still needs the id of its own call. The API matches them by id, not by position.

{
  "role": "user",
  "content": [
    { "type": "tool_result", "tool_use_id": "toolu_01", "content": "{\"temp_c\": 18}" },
    { "type": "tool_result", "tool_use_id": "toolu_02", "content": "{\"temp_c\": 24}" }
  ]
}

Report errors so Claude can recover

A tool fails in two ways: your function raises, or Claude sent input that does not fit. Report both as a tool_result with is_error set to true and a message that says how to fix the call. For a call with invalid or missing parameters, the docs say Claude retries two or three times with corrections before it apologizes. A message such as the one below gives it something to correct with, and a bare "Error" does not.

A call you decide not to run still needs a tool_result, with is_error and the reason. Leave one out and the next request fails.

Treat everything a tool returns as untrusted. A web page or a file can carry text written to steer the model, which the docs call indirect prompt injection. The handle tool calls page is why you enforce what a tool may touch in your own code, not in the prompt.

{
  "type": "tool_result",
  "tool_use_id": "toolu_01",
  "is_error": true,
  "content": "City not found. Pass a city name such as Lisbon, not a country."
}

What Anthropic and Alex Albert posted about designing tools

Anthropic posted on X on 11 September 2025 to share a guide from its engineering blog, writing effective tools for agents. The guide holds that more tools do not always mean better results. Its example: a search_logs tool that returns the matching lines beats a read_logs tool that returns everything. The define tools page still links to it for naming and response shape, so give get_weather the same treatment and return two fields, not the whole weather API response.

Alex Albert, who works in research at Anthropic, posted on 17 February 2026 that tool use examples, tool search and programmatic tool calling had become generally available. Tool use examples are the input_examples field in the table of tool fields, and they need no beta header now. Get the description right first. Then add two or three examples to any tool with nested input.

code execution, web fetch, memory, programmatic tool calling, tool search, and tool use examples are now generally available.

Alex Albert, Research at Anthropic · X (read November 5, 2026)
Anthropic (@AnthropicAI) on X, 11 September 2025, announcing a new Anthropic Engineering blog post on writing effective tools for LLM agents, with tips for developers on making tools more effective.
Anthropic on X, 11 September 2025
Alex Albert (@alexalbert__) on X, 17 February 2026: code execution, web fetch, memory, programmatic tool calling, tool search, and tool use examples are now generally available.
Alex Albert on X, 17 February 2026

Screenshots of X's own embeds of the posts, taken on 5 November 2026, with the time in UTC. Select one to open the post on X. Both embeds leave out the link that ends the post.

Common mistakes

  • Sending each tool_result in a separate user message, which cuts down parallel calls.
  • Putting text before the tool_result blocks in the same message.
  • Adding a text block right after the results, which can make Claude end the turn with an empty reply.
  • Rebuilding the assistant message from the text blocks only, and so dropping the thinking blocks the API wants back.
  • Writing a one-line description and wondering why Claude picks the wrong tool.
  • Forcing a tool with tool_choice on a model that rejects it.
  • Returning a whole database row when Claude needs two fields.

Try it yourself

  • Add a second tool, get_time, and ask a question that needs both. How many tool_use blocks come back, and do you reply in one user message?
  • Make get_weather raise for the city "Atlantis" and return the error JSON from this lesson. Does Claude retry with a different city or tell the user?
  • Delete all but one sentence of the description and compare which questions still trigger the tool.
  • Set disable_parallel_tool_use to true and repeat the two-city question.

Next

The loop in this lesson stops after one round, and every extra round resends the same tool list and system prompt. Lesson 3 caches them. If you would rather connect tools that already exist than write the schemas, the MCP lesson on connecting servers shows how.

Check yourself

  1. A response ends with stop_reason "tool_use". What do you send next?

    Show answer

    C. A user message with tool_result blocks that carry the tool_use ids Claude never runs the tool, so your code runs it and answers in a user message, one tool_result per tool_use id.

  2. Claude returns two tool_use blocks in one response. How should you send the results?

    Show answer

    A. In one user message holding both tool_result blocks Separate user messages teach Claude to stop making parallel calls, so every result goes into a single message.

  3. A tool raises an exception in your code. What should the tool_result carry?

    Show answer

    D. is_error true and a message that says how to fix the call An instructive error says what went wrong and what to try next, so Claude can recover without guessing.

  4. A request with tool_choice set to type "tool" returns a 400 on Opus 5.5. What do the docs suggest?

    Show answer

    B. Use auto with strict set to true on the tool, or structured outputs Forced tool_choice is rejected on those models, so the docs point to auto with strict or to structured outputs.

Frequently asked questions

Should I use the tool runner or write the loop myself?

The tool runner is in beta in the Python and TypeScript SDKs and runs the loop for you, turning a tool exception into an is_error result. The docs recommend a manual loop when you need human approval, custom logging or conditional execution.

What error do I get if a tool_result is missing?

An invalid_request_error that reads tool_use ids were found without tool_result blocks immediately after. Check that the results sit in the next user message and that every tool_use id has a match.

Why does the API want my thinking blocks back?

With tool use, the docs require every thinking and redacted_thinking block from the assistant turn to go back exactly as received, empty ones included. Editing, reordering or filtering them makes the request fail, so append the whole response content.

Do tool definitions cost tokens?

Yes. Definitions, tool_use blocks and tool_result blocks all count toward your tokens. On Opus 5.5 the docs also list a 286-token tool-use system prompt, added when tool_choice is auto or none.

Can I cache my tool definitions?

Yes. The cache order is tools, then system, then messages, and a cache_control breakpoint can sit on the last tool. Changing any tool definition resets the whole cache, which lesson 3 covers.

Sources

  1. Anthropic Docs: Tool use with Claude (read November 5, 2026)https://platform.claude.com/docs/en/agents-and-tools/tool-use/overview
  2. Anthropic Docs: Define tools (read November 5, 2026)https://platform.claude.com/docs/en/agents-and-tools/tool-use/define-tools
  3. Anthropic Docs: Handle tool calls (read November 4, 2026)https://platform.claude.com/docs/en/agents-and-tools/tool-use/handle-tool-calls
  4. Anthropic Docs: Parallel tool use (read November 4, 2026)https://platform.claude.com/docs/en/agents-and-tools/tool-use/parallel-tool-use
  5. Anthropic Docs: How tool use works (read November 4, 2026)https://platform.claude.com/docs/en/agents-and-tools/tool-use/how-tool-use-works
  6. Anthropic Docs: Tool runner (read November 4, 2026)https://platform.claude.com/docs/en/agents-and-tools/tool-use/tool-runner
  7. Anthropic Docs: Stop reasons and fallback (read November 4, 2026)https://platform.claude.com/docs/en/build-with-claude/handling-stop-reasons
  8. Anthropic Docs: Prompt caching (read November 4, 2026)https://platform.claude.com/docs/en/build-with-claude/prompt-caching
  9. Anthropic Docs: Claude API errors (read November 4, 2026)https://platform.claude.com/docs/en/api/errors
  10. Claude Docs: Release notes (read November 5, 2026)https://platform.claude.com/docs/en/release-notes/overview
  11. Anthropic Engineering: Writing effective tools for agents (read November 5, 2026)https://www.anthropic.com/engineering/writing-tools-for-agents
  12. X: Anthropic shares its guide to writing tools for agents (read November 5, 2026)https://x.com/AnthropicAI/status/1966236220868247701
  13. X: Alex Albert on tool use examples and tool search becoming generally available (read November 5, 2026)https://x.com/alexalbert__/status/2023834875678298535

Share this lesson

Browse AI agents that use tools

See how finished agents on Mindket describe their tools and setup, then list your own.

Browse AI agents

This lesson as Markdown · Claude API course: build an AI agent from scratch · All courses