Claude API Tool Use
Connect Claude to external tools with JSON schemas, tool_use blocks, and tool_result response payloads.
TL;DR
- Define each tool with a name, description, and
input_schema. - Run the requested tool when
stop_reasonequalstool_use. - Reply with a
tool_resultblock matching the tool call ID.
Tool Definition Schema
Schema DeclarationDeclare tool metadata and JSON Schema input contracts.
const weatherTool = {
name: 'get_weather',
description: 'Fetch current weather for a city.',
input_schema: {
type: 'object',
properties: {
city: { type: 'string', description: 'City' },
},
required: ['city'],
},
};Tool Choice And Strict ModeLet the model choose, and guarantee arguments match your schema.
tool_choice: { type: 'auto' },
// Newer models reject forced tool_choice
// ('any' / 'tool'): name the tool in the prompt
// and set strict: true on the tool instead.
const strictTool = { ...weatherTool, strict: true };Multi-Tool ArrayPass array of diverse operational tools to Messages API.
const res = await anthropic.messages.create({
model: 'claude-sonnet-5-5',
max_tokens: 1024,
tools: [weatherTool, databaseTool],
messages: [{ role: 'user', content: 'Paris' }],
});Response Block Handling
Stop Reason CheckDetect when model yields control for tool execution.
if (res.stop_reason === 'tool_use') {
const toolCalls = res.content.filter(
b => b.type === 'tool_use'
);
}Extract Input ArgumentsAccess pre-parsed strongly typed argument payloads.
for (const block of toolCalls) {
const { id, name, input } = block;
console.log(`Call: ${name} with ID: ${id}`);
const result = await executeTool(name, input);
}Mixed Content ParsingExtract explanatory text along with tool call request.
const b = res.content.find(x => x.type === 'text');
if (b) {
console.log(`Assistant note: ${b.text}`);
}Tool Result Payloads
Success Result BlockFormat successful tool execution data for dialogue resumption.
const resultBlock = {
type: 'tool_result',
tool_use_id: block.id,
content: JSON.stringify({ temp: 18, unit: 'C' }),
};Error Feedback BlockSignal tool execution failure so model can self-correct.
const errorBlock = {
type: 'tool_result',
tool_use_id: block.id,
content: 'City not found. Did you mean Paris, FR?',
is_error: true,
};Turn Resumption DispatchAppend tool use and tool results to continue conversation.
const followUp = await anthropic.messages.create({
model: 'claude-sonnet-5-5',
max_tokens: 1024,
messages: [
...history,
{ role: 'assistant', content: res.content },
{ role: 'user', content: [resultBlock] },
],
});Production Tool Hygiene
Zod Schema GuardValidate LLM tool inputs before invoking business logic.
import { z } from 'zod';
const CitySchema = z.object({
city: z.string().min(1),
});
const args = CitySchema.parse(block.input);Execution Timeout WrapperPrevent hanging external APIs from stalling conversational loop.
const timer = new Promise((_, rej) =>
setTimeout(() => rej(new Error('Timeout')), 5000)
);
const p = [fetchData(), timer];
const res = await Promise.race(p);Audit Logging HookRecord all tool invocations and outputs for observability.
logger.info('tool_dispatched', {
name: block.name,
id: block.id,
args: block.input,
});Tips
- Provide rich field descriptions in your
input_schemaso Claude understands exactly when and how to invoke each tool parameter. - Set the
is_errorflag to true within tool results when external API calls fail to let Claude self-correct gracefully.
Warnings
- Never execute tool call arguments directly without runtime schema validation using
zodto prevent malicious injection attacks. - Do not omit tool results from conversational history because Claude requires every
tool_use_idto have a matching result block.
In Practice
Declares a tool, handles Claude tool_use stop reason, executes calculation, and delivers tool_result.
- Define tool schema with name and input specifications.
- Dispatch user message and check for tool_use stop reason.
- Execute local business function matching requested tool name.
- Return tool_result block to Claude to receive final answer.
import Anthropic from '@anthropic-ai/sdk';
const client = new Anthropic();
const tools = [{
name: 'tip',
description: 'Calc tip',
input_schema: {
type: 'object',
properties: { bill: { type: 'number' } },
},
}];
const r = await client.messages.create({
model: 'claude-sonnet-5-5',
max_tokens: 100, tools,
messages: [{ role: 'user', content: 'Tip on $50' }],
});
const call = r.content.find(
b => b.type === 'tool_use'
);
console.log(call?.name, call?.input);FAQ
Claude evaluates user queries against the descriptions in your tool schema definitions. When it identifies that external data or operations are necessary, it pauses generation and emits a tool_use block.
A tool_result block requires type: 'tool_result', the corresponding tool_use_id, and a content field containing stringified JSON or plain text output.
Yes, Claude can request several tools in one turn. Run them all, then return every matching tool_result block together in a single user message.