Claude Certification Guides
CCAR-F/Domain 29 min read

Lesson 2.2

The Tool Use Request/Result Cycle

The exact message shapes Claude and your code exchange when a tool is called, including parallel calls, tool_choice and server-side tools.

Tool use is a protocol layered on ordinary messages. Claude asks for a tool by emitting a content block; you answer with another content block in the next user message. Nothing executes unless your code executes it. The exam tests the block shapes, the pairing rules, and the differences between client-side tools you run and server-side tools Anthropic runs.

Step by step

  1. Request. You send tools (an array of definitions) alongside messages.
  2. Response with stop_reason: "tool_use". The assistant content contains one or more tool_use blocks, often preceded by a text block explaining the intent.
  3. Execute. Your code runs each requested tool with the supplied input.
  4. Return. You append the assistant message, then a user message containing one tool_result block per tool_use, each referencing the originating tool_use_id.
  5. Continue. Claude reads the results and either calls more tools or answers with end_turn.

The two block shapes:

{"type": "tool_use", "id": "toolu_01A", "name": "get_weather",
 "input": {"city": "Antwerp"}}
{"type": "tool_result", "tool_use_id": "toolu_01A",
 "content": "12°C, light rain"}

content on a result may be a string or an array of blocks, which allows images (a screenshot, a chart) to be returned to the model. Add "is_error": true when the tool failed so Claude treats the content as an error message rather than data.

Pairing rules the API enforces

  • Every tool_result must reference a tool_use_id that appears in the immediately preceding assistant message.
  • Every tool_use in that assistant message must receive a result before the conversation continues; an unanswered call is a validation error.
  • The results go in a user message, and tool results should come first in that message if you also include text.

Omitting a result because a tool "did nothing" is a classic bug; return an explicit "ok" instead.

Parallel tool use

By default Claude may emit several tool_use blocks in a single turn when the calls are independent. Execute them concurrently if you can, then return all results in one user message, in any order (the IDs do the matching). Returning them one per message works but teaches the model to serialise its calls. If parallelism causes trouble for a specific tool set, set disable_parallel_tool_use: true inside tool_choice to cap calls at one per turn.

Controlling whether tools are called

tool_choice governs the model's freedom:

ValueEffect
{"type": "auto"}Default. Claude decides whether and which tools to call
{"type": "any"}Claude must call some tool
{"type": "tool", "name": "x"}Claude must call tool x
{"type": "none"}No tool calls this turn

Forced modes (any, tool) were historically the way to guarantee structured output: define one tool whose schema is your desired JSON and force it. Newer model generations reject forced tool choice with a 400 error and expect structured outputs (output_config.format) instead, so check the model documentation before relying on it. Under auto, a tool call is not guaranteed; if your workflow requires one, check the response and retry with a firmer instruction.

Client-side versus server-side tools

Everything above describes client-side tools: you define them, you run them. Anthropic also offers two other kinds.

Anthropic-defined client tools (bash, text editor, computer use, memory) are declared by type and name only; the schema is built into the model. You still execute them locally and return results.

Server-side tools (web search, web fetch, code execution, tool search) run on Anthropic's infrastructure. You declare them in tools, and the results arrive as blocks in the same response (server_tool_use followed by a result block such as web_search_tool_result). There is no round trip for your code to perform. Two consequences follow: errors from server tools are reported inside the result block rather than as HTTP errors, and a long server-side loop may return stop_reason: "pause_turn", which you resume by resending the conversation unchanged.

Streaming tool input

When streaming, a tool_use block arrives as a content_block_start followed by input_json_delta events carrying fragments of partial_json. Accumulate the fragments and parse only when the block stops. Never execute a tool from partially accumulated JSON; a max_tokens cut-off can leave it incomplete.

A compact TypeScript loop

let res = await client.messages.create({ model, max_tokens: 4096, tools, messages });
while (res.stop_reason === "tool_use") {
  messages.push({ role: "assistant", content: res.content });
  const results = await Promise.all(
    res.content.filter(b => b.type === "tool_use").map(async b => ({
      type: "tool_result" as const, tool_use_id: b.id,
      content: await runTool(b.name, b.input),
    })));
  messages.push({ role: "user", content: results });
  res = await client.messages.create({ model, max_tokens: 4096, tools, messages });
}

Exam focus

  • A tool_use block carries id, name and input; the matching tool_result carries tool_use_id and content, and lives in the next user message.
  • Every tool_use in an assistant turn must be answered; results for parallel calls belong in a single user message.
  • is_error: true marks a failed tool so the model treats the content as an error.
  • tool_choice values are auto, any, tool and none; forced modes are rejected by newer models, which use structured outputs instead.
  • Server-side tools run on Anthropic's side with no client round trip and may return pause_turn; client-side tools always need your code to execute them.
  • Streaming delivers tool input as input_json_delta fragments that must be fully accumulated before parsing.

Check yourself

5 questions

  1. 1.After executing a tool that Claude requested, how must the result be sent back to the API?

  2. 2.When Claude decides to call a client-side tool, which stop_reason and content block type appear in the response?

  3. 3.A developer appends only the text portion of Claude's reply to the conversation history (discarding the tool_use blocks), then sends a user message with a tool_result. The API returns a 400 error. Why?

  4. 4.A tool execution fails because a downstream API times out. How should the harness convey this to Claude?

  5. 5.For one particular request a team wants Claude to answer directly without calling any tools, while keeping the tool definitions in the request so that the prompt cache is not invalidated. Which setting achieves this?