CloudCodeTree LogoCloudCodeTree
AI NewsTutorialsAbout
CloudCodeTree Logo
CloudCodeTree
  • AI News
  • Tutorials
  • About
← Back to AI News
Tool Use from Scratch: Build the Client Loop That Powers Every Claude Agent

Tool Use from Scratch: Build the Client Loop That Powers Every Claude Agent

Chris Harper

4 min read

Jun 27, 2026 · 12:08 UTC

AI
Tutorial
Agents
LLM

TL;DR: Tool use is the API primitive that turns Claude into an agent — define a JSON schema, handle the tool_use block, return a tool_result, repeat until done.

What you'll be able to do after this:

  • Wire up a custom tool with a JSON Schema and call it from the Claude API in ~20 lines of Python
  • Handle the full client-tool loop: request → parse → execute → return result
  • Control when Claude calls tools using tool_choice modes (auto, any, tool, none)

What tool use is

Tool use lets Claude call functions you define. Claude reads your tool descriptions, decides when to call a tool, returns a structured tool_use block, and your code executes the function and sends back the result. The loop repeats until Claude has enough to answer.

There are two kinds:

  • Client tools — you define the schema, your code executes the call. Claude returns stop_reason: "tool_use".
  • Server tools — Anthropic executes them (web search, code execution, web fetch). No handler needed.

This tutorial covers client tools.

Step 1: Define your tool

A tool needs three fields: name, description, and input_schema (JSON Schema).

import anthropic

client = anthropic.Anthropic()

tools = [
    {
        "name": "get_weather",
        "description": (
            "Returns the current weather for a city. Use this when the user asks "
            "about current conditions, temperature, or forecast in a specific location. "
            "Returns temperature in the requested unit and a short condition summary. "
            "Does not return multi-day forecasts or historical data."
        ),
        "input_schema": {
            "type": "object",
            "properties": {
                "location": {
                    "type": "string",
                    "description": "City and state or country, e.g. 'Austin, TX' or 'Tokyo, Japan'"
                },
                "unit": {
                    "type": "string",
                    "enum": ["celsius", "fahrenheit"],
                    "description": "Temperature unit"
                }
            },
            "required": ["location"]
        }
    }
]

The description is the most important part — it tells Claude when and how to call the tool. Write at least 3–4 sentences.

Step 2: Send the request

response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    tools=tools,
    messages=[{"role": "user", "content": "What's the weather like in Austin right now?"}]
)

print(response.stop_reason)   # → "tool_use"

Step 3: Parse and execute

def run_tool(name, inputs):
    if name == "get_weather":
        # call a real weather API in practice
        return {"temperature": 32, "unit": inputs.get("unit", "celsius"), "condition": "sunny"}

tool_calls = [b for b in response.content if b.type == "tool_use"]
results = []

for call in tool_calls:
    output = run_tool(call.name, call.input)
    results.append({
        "type": "tool_result",
        "tool_use_id": call.id,
        "content": str(output)
    })

Step 4: Return the result and continue

messages = [
    {"role": "user", "content": "What's the weather like in Austin right now?"},
    {"role": "assistant", "content": response.content},   # Claude's tool_use block
    {"role": "user", "content": results}                  # your tool_result
]

final = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    tools=tools,
    messages=messages
)

print(final.content[0].text)
# → "The weather in Austin is currently 32°C and sunny."

Controlling when Claude calls tools

tool_choice valueBehavior
auto (default)Claude decides whether to call a tool or respond directly
anyClaude must call one of your tools
{"type": "tool", "name": "..."}Claude must call this specific tool
noneClaude cannot call any tools

For production agents, auto is almost always right — Claude skips the tool when it already has the answer.

Parallel tool calls

Claude may return multiple tool_use blocks in one response. Always iterate — never assume just one:

tool_calls = [b for b in response.content if b.type == "tool_use"]
# Claude may return 1 or more — loop over all of them

Sources: Tool use overview — Claude Platform Docs | Define tools | Handle tool calls | Tutorial: Build a tool-using agent