Tool Use 101: The Request/Response Shape and the Loop That Drives It


Tool Use 101: The Request/Response Shape and the Loop That Drives It

Tool use is how you give Claude the ability to do things — search the web, query a database, run a calculation — rather than just generate text. Once you understand the shape of the exchange, every agentic pattern starts to make sense.

The jargon

Tool definition — A JSON description you write that tells Claude a tool exists, what it does, and what inputs it expects.
Tool call — Claude's response when it decides to use a tool. It's structured JSON, not prose.
Tool result — What you send back to Claude after running the tool on your side.
Agentic loop — The cycle of: Claude responds → you check if it called a tool → you run it → you feed the result back → repeat until Claude returns plain text.

The lesson

Claude never runs your tools itself. It just asks you to run them.

When Claude decides it needs, say, today's exchange rate, it stops generating prose and instead outputs a structured request: "call the get_exchange_rate tool with these arguments." Your code catches that, calls the real API, and sends the result back in the next message. Claude then continues as if it always knew the answer.

This matters because it means you control execution. Claude can't reach out to the internet on its own. The loop lives in your code, not inside the model.

How it works

You send Claude a list of tool definitions alongside your messages:

tools = [
    {
        "name": "get_exchange_rate",
        "description": "Returns the current exchange rate between two currencies.",
        "input_schema": {
            "type": "object",
            "properties": {
                "from": {"type": "string"},
                "to":   {"type": "string"}
            },
            "required": ["from", "to"]
        }
    }
]

Claude's response may have stop_reason: "tool_use" and a content block like this:

{
  "type": "tool_use",
  "id": "toolu_01XYZ",
  "name": "get_exchange_rate",
  "input": {"from": "USD", "to": "SGD"}
}

Your code runs the real lookup, then sends a new message with role: "user" containing a tool_result block:

{
  "type": "tool_result",
  "tool_use_id": "toolu_01XYZ",
  "content": "1 USD = 1.34 SGD"
}

Claude then picks up from there. If it needs another tool, it asks again. When it's done, stop_reason changes to "end_turn" and you get prose.

The loop in pseudocode:

while response.stop_reason == "tool_use":
    result = run_my_tool(response.tool_call)
    response = client.messages.create(..., tool_result=result)
return response.text

When to reach for it / when not to

Reach for tool use when Claude needs live or external data, needs to write to a system, or when you want an auditable record of what it did and why. Skip it when a single prompt with pre-fetched context does the job — adding a loop adds latency and complexity.

Try it

Open the Anthropic tool-use quickstart and run the weather example as written. Then change the tool's description to something deliberately vague. Watch how often Claude gets the argument names wrong. That's your intuition for why good descriptions matter.


Don't miss what's next. Subscribe to My Claude Daily Learning: