๐Ÿ”ง Tool: how agents take action

On its own, Claude can only read text and write text. Tools let it look things up and get things done: search documents, read files, call other services and query databases.

What is it?

A tool is a job you allow the AI to request, such as "look up an order" or "read a file". You describe the tool to Claude in plain language. When Claude decides it needs the tool, it doesn't run anything itself. It sends back a structured request saying which tool to use and what details to use it with. Your program does the work and returns the result to Claude.

AI model
The trained system that understands and writes text. Claude is an AI model.
Agent
A program in which the model works towards a goal: it decides which steps to take, uses tools and checks results, in a loop, until the job is done.
Tool
A named capability with a description and a list of inputs that the agent can ask to use.
Parameter (input)
A piece of information the tool needs, such as an order_id.
Tool call
Claude's request to use a tool. In the Claude API this is a tool_use block.
Tool result
What your code sends back after running the tool. In the API this is a tool_result block.
API
"Application Programming Interface": a way for one program to ask another program to do something.
JSON
A common text format for structured data, such as {"order_id": "A1001"}.
Schema
A description of what shape the data must have: which fields exist, their types, and which ones are required.

Model, agent and tool: what's the difference?

๐Ÿง  Model

The brain. It understands the request and decides what to do, but it can't touch anything outside the conversation.

๐Ÿค– Agent

The worker. The model plus your code running in a loop: think, act, look at the result, repeat.

๐Ÿงฐ Tool

The hands. Specific actions the agent may use, such as search, read, calculate or send.

Without tools, an agent can only talk. Without a model, tools are just functions that nobody chooses when to call. An agent needs both.

Why is it important?

Real-world analogy

The expert at a desk with a stack of request forms

Imagine a very knowledgeable assistant who can't leave their desk. On the desk is a pile of forms: "Order lookup form", "File request form", "Database search form". Each form has a title (the tool name), a short note explaining when to use it (the description) and blank boxes to fill in (the parameters).

When a customer asks "Where's my parcel?", the assistant fills in an order lookup form with the order number and hands it to a runner. The runner is your code. It goes to the warehouse system, comes back with the answer and hands it over. The assistant then replies to the customer. The assistant never walks into the warehouse, and that's what keeps the system safe.

How does it work?

  1. You describe the tools. Each tool has a name, a description and an input_schema that lists its parameters.
  2. The user asks something. You send the question and the list of tools to Claude.
  3. Claude decides. If a tool would help, Claude replies with a tool_use block (for example get_order_status with {"order_id": "A1001"}) and the response's stop_reason is "tool_use". If no tool is needed, it simply answers.
  4. Your code checks and runs the tool. Confirm the tool is allowed and the inputs make sense, then run it.
  5. You send back the result in a tool_result block linked to the call by its tool_use_id. If something went wrong, send the error with is_error: true.
  6. Claude continues. It may call another tool or write the final answer using the result.
Two kinds of tools in the Claude API

Client tools are tools you define and run in your own code, like everything on this page. Server tools are tools Anthropic runs for you, such as web search and code execution. You switch a server tool on in your request and its results come back automatically. See the tool use overview.

Workflow diagram

Simple overview

The agent can go around the loop several times, for example look up an order, then look up the delivery company, before it writes the final response.

Detailed workflow

If no tool is needed at the decision point, Claude answers straight away. Every tool call goes through your code's checks before anything runs.

Try it: simulated tool call

Interactive demoA simulation in your browser. No AI is called and no API key is needed.

Available tools: get_order_status, read_file, delete_records (admin only)

    Common kinds of tools

    ๐Ÿ“„ Search documents

    search_docs(query) finds matching passages in your help centre or policies, so Claude answers from your content.

    ๐ŸŒ Call an API

    get_weather(city) or create_ticket(title, body) call another service over the internet.

    ๐Ÿ“ Read files

    read_file(path) returns a file's text. Restrict it to one safe folder.

    ๐Ÿ—„๏ธ Query a database

    find_customer(email) runs a fixed, safe query. Never let the model write raw database commands.

    Practical example: order-status assistant

    A shop wants its chat assistant to answer "Where's my order?" Here is what travels back and forth:

    1. The customer writes: "Hi! Where is my order a1001?"
    2. Claude replies with a tool call: get_order_status with {"order_id": "A1001"}. Notice that it tidied up the lowercase "a1001".
    3. Your code looks up the order and sends back {"status": "shipped", "carrier": "DHL", "eta": "2026-10-20"}.
    4. Claude writes: "Good news, order A1001 has shipped with DHL and should arrive around 20 October."

    If the customer types an ID that doesn't exist, the tool returns an error. Claude then asks the customer to double-check the number instead of making up an answer.

    Code example

    A complete, runnable Python program. It needs the official anthropic package (pip install anthropic) and an API key stored in the ANTHROPIC_API_KEY environment variable on your computer or server. Never put an API key in a web page.

    
    # tool_agent.py: a tiny agent with one tool.
    # Setup: pip install anthropic, then set the ANTHROPIC_API_KEY environment variable.
    import json
    import anthropic
    
    client = anthropic.Anthropic()  # reads ANTHROPIC_API_KEY from the environment
    
    # 1. A pretend database. In a real app this would be your order system.
    ORDERS = {
        "A1001": {"status": "shipped", "carrier": "DHL", "eta": "2026-10-20"},
        "A1002": {"status": "processing", "carrier": None, "eta": None},
    }
    
    # 2. Describe the tool so Claude knows WHEN and HOW to use it.
    TOOLS = [{
        "name": "get_order_status",
        "description": "Look up the shipping status of a customer order by its order ID. "
                       "Use this whenever the user asks where an order is. IDs look like A1001.",
        "input_schema": {
            "type": "object",
            "properties": {
                "order_id": {"type": "string", "description": "The order ID, e.g. A1001"}
            },
            "required": ["order_id"],
        },
    }]
    
    # 3. The real Python function that does the work.
    def get_order_status(order_id: str) -> dict:
        order_id = order_id.strip().upper()
        if not (order_id.startswith("A") and order_id[1:].isdigit()):
            raise ValueError(f"'{order_id}' is not a valid order ID")
        if order_id not in ORDERS:
            raise LookupError(f"No order found with ID {order_id}")
        return {"order_id": order_id, **ORDERS[order_id]}
    
    def run_tool(name: str, tool_input: dict) -> dict:
        # Allowlist: only run tools we have explicitly approved.
        if name == "get_order_status":
            return get_order_status(**tool_input)
        raise PermissionError(f"Tool '{name}' is not allowed")
    
    def ask(question: str) -> str:
        messages = [{"role": "user", "content": question}]
        for _ in range(5):  # safety limit so the loop can never run forever
            response = client.messages.create(
                model="claude-opus-5-5",
                max_tokens=16000,
                tools=TOOLS,
                messages=messages,
            )
            # No tool requested: this is the final answer.
            if response.stop_reason != "tool_use":
                return "".join(b.text for b in response.content if b.type == "text")
    
            # Keep Claude's turn (including its tool_use blocks) in the history.
            messages.append({"role": "assistant", "content": response.content})
            results = []
            for block in response.content:
                if block.type != "tool_use":
                    continue
                print(f"[tool call] {block.name}({block.input})")
                try:
                    output = run_tool(block.name, block.input)
                    results.append({"type": "tool_result", "tool_use_id": block.id,
                                    "content": json.dumps(output)})
                except Exception as err:  # report the problem to Claude instead of crashing
                    results.append({"type": "tool_result", "tool_use_id": block.id,
                                    "content": f"Error: {err}", "is_error": True})
            # All results go back together in ONE user message.
            messages.append({"role": "user", "content": results})
        return "Stopped: too many tool calls."
    
    if __name__ == "__main__":
        print(ask("Hi! Where is my order a1001?"))
    

    Expected output (Claude's exact wording will vary):

    
    [tool call] get_order_status({'order_id': 'A1001'})
    Good news! Order A1001 has shipped with DHL and is expected to arrive on 20 October 2026.
    
    Shortcut: the Tool Runner

    The Python SDK also has a beta Tool Runner (client.beta.messages.tool_runner with the @beta_tool decorator). It writes the loop above for you. We wrote the loop by hand here so you can see every step. See How to implement tool use.

    Step-by-step explanation

    1. anthropic.Anthropic() creates a client. It reads your API key from the environment, so the key never appears in your code.
    2. ORDERS stands in for a real database so the example runs anywhere.
    3. TOOLS is the list of tool descriptions sent to Claude. The description matters most because Claude reads it to decide when to use the tool. input_schema is a JSON Schema that says order_id must be text and is required.
    4. get_order_status is ordinary Python. It validates the input (is it shaped like an order ID?) before using it, and raises a clear error otherwise.
    5. run_tool is an allowlist: if Claude ever asks for a tool you didn't approve, it is refused.
    6. Inside ask, client.messages.create(...) sends the conversation and the tools to the model claude-opus-5-5.
    7. If stop_reason isn't "tool_use", Claude has finished, so we join its text blocks and return them.
    8. Otherwise we save Claude's turn in messages, run each requested tool, and build a tool_result for each one, matched by tool_use_id.
    9. Errors become tool_result blocks with "is_error": True, so Claude can explain the problem or try again instead of the program crashing.
    10. The for _ in range(5) limit stops a confused agent from looping forever and running up costs.

    Inputs, execution, results and errors

    StageWhat happensWhat can go wrongWhat to do
    Input parametersClaude fills in the inputs your schema describesMissing, badly formatted or unexpected valuesValidate everything in your code. Adding "strict": true to a tool definition makes Claude's inputs match the schema exactly.
    ExecutionYour function runsTimeouts, the service is down, not foundCatch the error, set a timeout, retry only when it's safe to do so
    Returned resultYou send text or JSON backHuge results waste tokens and moneyReturn only the fields Claude needs
    Error handlingYou send an error resultCrashing, or hiding the error so Claude guessesSend is_error: true with a clear, helpful message

    Permissions, validation and security

    Treat every tool call as a request, not an order

    Claude can make mistakes, and text it reads (a web page, an email, a file) can contain hidden instructions trying to trick it. This is called prompt injection. Your code is the final gatekeeper.

    Use cases

    Advantages and limitations

    โœ… Advantages

    • Answers based on real, current data
    • Can take real actions
    • Exact results from calculators and databases
    • You decide exactly what is possible

    โš ๏ธ Limitations

    • Each tool call adds time and cost
    • Vague descriptions lead to the wrong tool being picked
    • Tools bring security risks if they aren't guarded
    • Too many similar tools confuse the model

    ๐Ÿšซ Common mistakes

    • One-line descriptions like "gets data"
    • Trusting tool inputs without checking them
    • Returning huge raw results
    • No limit on how many times the loop can run

    Best practices

    Knowledge check

    1. When you define a client tool, who actually runs it?

    2. What does Claude mainly use to decide which tool to call?

    3. Your tool fails because the order ID doesn't exist. What should your code do?

    4. Which statement best describes an agent?

    5. Why should an API key never be placed in website (frontend) code?

    Mini project

    Build an FAQ helper tool.

    1. Copy tool_agent.py. Add a second tool, search_faq(question), that looks up answers in a small Python dictionary (for example shipping times, returns and opening hours).
    2. Write a careful description that says when Claude should use search_faq rather than get_order_status.
    3. If no FAQ entry matches, return an error result.
    4. Test it with: "How long do returns take?", "Where is order A1002?" and "What's your favourite colour?"

    Success: the first question uses search_faq, the second uses get_order_status, and the third uses no tool at all.

    Key takeaways

    Further learning