Chapter 5 · Part 2

Give Claude a tool

So far Claude can only talk. Tool use lets it act — call functions you write, to fetch live data, do math, hit other APIs, or change things in the world. This is the single idea behind every "AI agent." The mechanism is a simple back-and-forth, and you'll walk the whole loop by hand.

The four steps

  1. You describe a tool (name, what it does, what inputs it takes).
  2. Claude, if it decides the tool would help, replies with a tool_use request instead of a final answer.
  3. You run the actual function and send the result back as a tool_result.
  4. Claude uses that result to write its real answer.

Define a tool and make the first call

We'll give Claude a pretend weather function. The input_schema is JSON Schema — it tells Claude exactly what arguments the tool expects. Create tools.py:

tools.py
from anthropic import Anthropic

client = Anthropic()

tools = [
  {
      "name": "get_weather",
      "description": "Get the current weather for a city.",
      "input_schema": {
          "type": "object",
          "properties": {
              "city": {"type": "string", "description": "City name, e.g. Paris"}
          },
          "required": ["city"],
      },
  }
]

def get_weather(city):                       # the real function Claude can't run itself
  return f"18°C and sunny in {city}."

messages = [{"role": "user", "content": "What's the weather in Tokyo? Should I take a jacket?"}]

reply = client.messages.create(
  model="claude-opus-4-8",
  max_tokens=1024,
  tools=tools,
  messages=messages,
)

print(reply.stop_reason)   # 'tool_use' — Claude wants to call get_weather

Because the question needs live data, Claude doesn't answer — it stops with stop_reason == "tool_use", and its content includes a tool_use block naming the tool and the arguments it chose ({"city": "Tokyo"}).

Run the tool and hand back the result

Now do Claude's bidding: find the tool_use block, run the matching function, and send a tool_result back — carrying the tool_use_id so Claude knows which call it answers:

tools.py (continued)
messages.append({"role": "assistant", "content": reply.content})   # remember the tool request

tool_results = []
for block in reply.content:
  if block.type == "tool_use":
      result = get_weather(**block.input)          # actually run it
      tool_results.append({
          "type": "tool_result",
          "tool_use_id": block.id,
          "content": result,
      })

messages.append({"role": "user", "content": tool_results})   # send results back

final = client.messages.create(
  model="claude-opus-4-8",
  max_tokens=1024,
  tools=tools,
  messages=messages,
)
print(final.content[0].text)
It's 18°C and sunny in Tokyo right now — mild and clear. You probably
won't need a jacket, though you might want a light layer for the evening.

Claude asked for the tool, you ran it, and it wove the result into a natural answer. That request → tool_use → run → tool_result → answer cycle is the entire foundation of AI agents — real ones just loop it, with tools that search the web, run code, or query a database.

The shortcut for real apps

Doing that loop by hand is worth it once, to see the gears. In a real app, the SDK's tool runner (client.beta.messages.tool_runner(...)) runs the whole cycle for you — you just supply the tool functions and it handles the calls and results until Claude is done. Now that you know what it's automating, you can reach for it freely.

Your app can talk, remember, stream, and act. Last chapter: make it robust and ship-ready.