Claude for Developers

Build Scalable AI Agents with Claude's New Tool Calling in 2025

Unlock the power of Claude's enhanced tool calling to build scalable AI agents that autonomously handle complex workflows. This guide provides TypeScript code examples for developers ready to deploy p

A

Andrew Snyder

AI & Automation Editor

December 14, 2025 min read
Share:

Build Scalable AI Agents with Claude's New Tool Calling in 2025

Introduction

In 2025, Anthropic's Claude models, powered by Claude 3.5 Sonnet and upcoming iterations, have revolutionized AI agent development with advanced tool calling capabilities. Tool calling allows Claude to intelligently invoke external functions, process results, and iterate autonomously—perfect for building scalable agents that tackle real-world workflows like research, automation, and decision-making.

This step-by-step guide focuses on Claude's API specifics: parallel tool execution, structured outputs, and robust error handling. We'll use TypeScript for type safety, building a scalable trip-planning agent. By the end, you'll have production-ready code to integrate into your apps.

Why Claude for Agents?

  • Native support for multiple tools in a single response (parallel calling in 3.5+).
  • Superior reasoning for tool selection and chaining.
  • XML-based tool schemas for precision.
  • Cost-effective compared to agent frameworks like LangChain.

Prerequisites

  • Node.js 20+
  • Anthropic API key (from console.anthropic.com)
  • Basic TypeScript knowledge

Install dependencies:

npm init -y
npm install @anthropic-ai/sdk zod
npm install -D typescript @types/node tsx

Create tsconfig.json:

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "strict": true,
    "esModuleInterop": true
  }
}

Step 1: Setting Up the Claude Client

Initialize the Anthropic SDK with streaming for real-time responses.

// agent.ts
import { Anthropic } from '@anthropic-ai/sdk';
import { z } from 'zod';

const client = new Anthropic({
  apiKey: process.env.ANTHROPIC_API_KEY!,
});

Step 2: Defining Tools with Zod Schemas

Claude uses JSON schemas derived from Zod for tool definitions. Define tools for our trip-planning agent: flight search, hotel lookup, and weather check.

const flightSearchSchema = z.object({
  query: z.string().describe('Search query for flights'),
  from: z.string().describe('Departure city'),
  to: z.string().describe('Destination city'),
  date: z.string().describe('Travel date (YYYY-MM-DD)'),
}).describe('Search for available flights');

const hotelSearchSchema = z.object({
  city: z.string().describe('Destination city'),
  checkin: z.string().describe('Check-in date'),
  checkout: z.string().describe('Check-out date'),
}).describe('Find hotels');

const weatherSchema = z.object({
  city: z.string().describe('City name'),
}).describe('Get current weather');

const tools = {
  flight_search: {
    name: 'flight_search',
    description: 'Search for flights',
    inputSchema: flightSearchSchema,
  },
  hotel_search: {
    name: 'hotel_search',
    description: 'Search for hotels',
    inputSchema: hotelSearchSchema,
  },
  get_weather: {
    name: 'get_weather',
    description: 'Check weather',
    inputSchema: weatherSchema,
  },
};

Convert Zod to Anthropic's JSON schema format:

function zodToJsonSchema(schema: z.ZodSchema): object {
  return schema._def.schema ?? {};
}

const toolDefs = Object.values(tools).map(t => ({
  name: t.name,
  description: t.description,
  input_schema: zodToJsonSchema(t.inputSchema),
}));

Step 3: Implementing Tool Execution

Mock external APIs for demo (replace with real ones like Amadeus or OpenWeather).

async function executeTool(toolName: string, args: any): Promise<string> {
  switch (toolName) {
    case 'flight_search':
      // Mock API call
      return JSON.stringify({
        flights: [
          { id: 1, price: 250, airline: 'Delta', time: '10:00 AM' },
        ],
      });
    case 'hotel_search':
      return JSON.stringify({
        hotels: [{ id: 1, name: 'Grand Hotel', price: 150 }],
      });
    case 'get_weather':
      return 'Sunny, 72°F';
    default:
      throw new Error(`Unknown tool: ${toolName}`);
  }
}

Step 4: The Agent Loop

Core logic: Send user query, parse tools/content, execute, loop until Claude decides to respond.

interface AgentState {
  messages: Array<{ role: 'user' | 'assistant'; content: string }>;
}

async function runAgent(query: string, maxIterations = 10): Promise<string> {
  let state: AgentState = { messages: [{ role: 'user', content: query }] };

  for (let i = 0; i < maxIterations; i++) {
    const res = await client.messages.create({
      model: 'claude-3-5-sonnet-20241022',
      max_tokens: 1024,
      messages: state.messages,
      tools: toolDefs,
    });

    const response = res.content[0];

    if (response.type === 'text') {
      return response.text; // Final response
    }

    if (response.type === 'tool_use') {
      const tool = response.id;
      const args = response.input;
      const result = await executeTool(response.name, args);

      state.messages.push({
        role: 'assistant',
        content: [
          {
            type: 'tool_result',
            tool_use_id: tool,
            content: result,
          },
        ] as any,
      });
    }
  }

  return 'Max iterations reached.';
}

Key Claude Features Leveraged:

  • Parallel tools: Claude 3.5 can request multiple in one go.
  • Extend with tools in API call.
  • tool_result feedback loop.

Step 5: Handling Parallel Tool Calls

Update for multi-tool support:

if (response.type === 'tool_use') {
  const toolResults: any[] = [];
  for (const toolUse of res.content.filter((c: any) => c.type === 'tool_use')) {
    const result = await executeTool(toolUse.name, toolUse.input);
    toolResults.push({
      type: 'tool_result',
      tool_use_id: toolUse.id,
      content: result,
    });
  }
  state.messages.push({ role: 'assistant', content: toolResults });
}

Claude automatically handles sequencing based on results.

Step 6: Scaling for Production

Error Handling & Retries:

async function executeToolWithRetry(toolName: string, args: any, retries = 3): Promise<string> {
  for (let i = 0; i < retries; i++) {
    try {
      return await executeTool(toolName, args);
    } catch (error) {
      if (i === retries - 1) throw error;
      await new Promise(r => setTimeout(r, 1000 * (i + 1)));
    }
  }
}

State Management: Use Redis or in-memory for multi-turn sessions.

Async Queues: For high throughput, offload tool calls to BullMQ or similar.

Rate Limiting: Implement SDK wrappers for Anthropic limits (50 RPM for Sonnet).

Monitoring: Log with structured data:

console.log({ event: 'tool_called', tool: toolName, args });

Step 7: Prompt Engineering Best Practices

Claude shines with concise system prompts:

const systemPrompt = `You are a helpful trip planning assistant. Use tools only when necessary. Plan step-by-step: flights first, then hotels, check weather last. Provide a summary at the end.`;

// Add to client.messages.create({ system, ... })

Tips:

  • Describe tools thoroughly in describe().
  • Use few-shot examples in system prompt for complex chaining.
  • Prefer Sonnet for reasoning depth.

Real-World Example: Trip to Paris

Run the agent:

// main.ts
import { runAgent } from './agent';

async function main() {
  const result = await runAgent('Plan a 3-day trip to Paris from NYC starting next Friday.');
  console.log(result);
}

main();

Sample Output: Claude calls flight_search, hotel_search in parallel, then weather. Final plan: Flights at $250, Hotel at Grand ($150/night), Weather sunny.

Advanced Scaling: Multi-Agent Systems

Extend to hierarchies: Orchestrator agent delegates to specialist agents (e.g., budget analyzer).

Use MCP servers for shared tools across agents.

Conclusion

Claude's 2025 tool calling empowers developers to build scalable, autonomous agents without bloated frameworks. Deploy this code today, customize tools, and watch your workflows automate.

Next Steps:

  • Integrate with n8n for no-code triggers.
  • Explore Claude Code for local dev.
  • Check Anthropic docs for latest schema changes.

Word count: ~1450

The #1 Newsletter in AI

Stay ahead of the AI curve

The most important updates, news, and content — delivered in one weekly newsletter.

No spam. Unsubscribe anytime. Privacy policy

claude api
ai agents
tool calling
prompt engineering
typescript
ai-agents
A

About Andrew Snyder

AI & Automation Editor

Andrew covers practical AI automation, workflow design, and the tools teams use to streamline everyday operations.

Comments (0)