Claude API Tool Use

Connect Claude to external tools with JSON schemas, tool_use blocks, and tool_result response payloads.

TL;DR

  1. Define each tool with a name, description, and input_schema.
  2. Run the requested tool when stop_reason equals tool_use.
  3. Reply with a tool_result block matching the tool call ID.

Tool Definition Schema

    Schema Declaration

    Declare 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 Mode

    Let 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 Array

    Pass 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 Check

    Detect 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 Arguments

    Access 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 Parsing

    Extract 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 Block

    Format 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 Block

    Signal 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 Dispatch

    Append 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 Guard

    Validate 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 Wrapper

    Prevent 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 Hook

    Record all tool invocations and outputs for observability.

    logger.info('tool_dispatched', {
      name: block.name,
      id: block.id,
      args: block.input,
    });

Tips

  1. Provide rich field descriptions in your input_schema so Claude understands exactly when and how to invoke each tool parameter.
  2. Set the is_error flag to true within tool results when external API calls fail to let Claude self-correct gracefully.

Warnings

  1. Never execute tool call arguments directly without runtime schema validation using zod to prevent malicious injection attacks.
  2. Do not omit tool results from conversational history because Claude requires every tool_use_id to have a matching result block.

In Practice

FAQ