Skip to content

Claude Agent SDK Integration

Build your own applications using the Claude Agent SDK.

What You'll Learn

  • What the Claude Agent SDK is
  • Basic SDK usage
  • Building custom agents
  • Integrating with your applications

What is the Claude Agent SDK?

The Claude Agent SDK is a TypeScript library for building AI agents powered by Claude. It provides:

  • Tool definition and execution
  • Conversation management
  • Multi-turn interactions
  • Streaming responses

While Claude Code is a ready-to-use CLI, the SDK lets you build custom applications with similar capabilities.

Getting Started

Installation

npm install @anthropic-ai/claude-agent-sdk

Basic Usage

import Anthropic from '@anthropic-ai/sdk';

const client = new Anthropic();

async function chat(userMessage: string) {
  const response = await client.messages.create({
    model: 'claude-sonnet-4-20250514',
    max_tokens: 1024,
    messages: [
      { role: 'user', content: userMessage }
    ]
  });

  return response.content[0].text;
}

Defining Tools

Tools let Claude take actions in your application:

const tools = [
  {
    name: 'get_weather',
    description: 'Get current weather for a location',
    input_schema: {
      type: 'object',
      properties: {
        location: {
          type: 'string',
          description: 'City name'
        }
      },
      required: ['location']
    }
  }
];

const response = await client.messages.create({
  model: 'claude-sonnet-4-20250514',
  max_tokens: 1024,
  tools,
  messages: [
    { role: 'user', content: 'What\'s the weather in Tokyo?' }
  ]
});

Handling Tool Calls

When Claude wants to use a tool, you execute it:

async function runAgent(userMessage: string) {
  let messages = [{ role: 'user', content: userMessage }];

  while (true) {
    const response = await client.messages.create({
      model: 'claude-sonnet-4-20250514',
      max_tokens: 1024,
      tools,
      messages
    });

    // Check if Claude wants to use a tool
    if (response.stop_reason === 'tool_use') {
      const toolUse = response.content.find(c => c.type === 'tool_use');

      // Execute the tool
      const result = await executeToolCall(toolUse.name, toolUse.input);

      // Add the interaction to messages
      messages.push({ role: 'assistant', content: response.content });
      messages.push({
        role: 'user',
        content: [{
          type: 'tool_result',
          tool_use_id: toolUse.id,
          content: JSON.stringify(result)
        }]
      });
    } else {
      // Claude is done, return the response
      return response.content[0].text;
    }
  }
}

async function executeToolCall(name: string, input: any) {
  switch (name) {
    case 'get_weather':
      return await fetchWeather(input.location);
    default:
      throw new Error(`Unknown tool: ${name}`);
  }
}

Building an Agent

A complete agent example:

import Anthropic from '@anthropic-ai/sdk';
import * as fs from 'fs';
import * as path from 'path';

const client = new Anthropic();

// Define available tools
const tools = [
  {
    name: 'read_file',
    description: 'Read contents of a file',
    input_schema: {
      type: 'object',
      properties: {
        path: { type: 'string', description: 'File path to read' }
      },
      required: ['path']
    }
  },
  {
    name: 'write_file',
    description: 'Write content to a file',
    input_schema: {
      type: 'object',
      properties: {
        path: { type: 'string', description: 'File path to write' },
        content: { type: 'string', description: 'Content to write' }
      },
      required: ['path', 'content']
    }
  },
  {
    name: 'list_directory',
    description: 'List files in a directory',
    input_schema: {
      type: 'object',
      properties: {
        path: { type: 'string', description: 'Directory path' }
      },
      required: ['path']
    }
  }
];

// Tool implementations
async function executeTool(name: string, input: any): Promise<string> {
  switch (name) {
    case 'read_file':
      return fs.readFileSync(input.path, 'utf-8');

    case 'write_file':
      fs.writeFileSync(input.path, input.content);
      return `File written: ${input.path}`;

    case 'list_directory':
      const files = fs.readdirSync(input.path);
      return files.join('\n');

    default:
      throw new Error(`Unknown tool: ${name}`);
  }
}

// Main agent loop
async function agent(userMessage: string): Promise<string> {
  const messages: any[] = [{ role: 'user', content: userMessage }];

  while (true) {
    const response = await client.messages.create({
      model: 'claude-sonnet-4-20250514',
      max_tokens: 4096,
      system: 'You are a helpful coding assistant with access to the filesystem.',
      tools,
      messages
    });

    // Collect text and tool use from response
    let hasToolUse = false;
    const assistantContent = [];
    const toolResults = [];

    for (const block of response.content) {
      assistantContent.push(block);

      if (block.type === 'tool_use') {
        hasToolUse = true;
        try {
          const result = await executeTool(block.name, block.input);
          toolResults.push({
            type: 'tool_result',
            tool_use_id: block.id,
            content: result
          });
        } catch (error) {
          toolResults.push({
            type: 'tool_result',
            tool_use_id: block.id,
            content: `Error: ${error.message}`,
            is_error: true
          });
        }
      }
    }

    messages.push({ role: 'assistant', content: assistantContent });

    if (hasToolUse) {
      messages.push({ role: 'user', content: toolResults });
    } else {
      // No more tool calls, extract final text
      const textBlock = response.content.find(b => b.type === 'text');
      return textBlock?.text || '';
    }
  }
}

// Usage
const result = await agent('List the files in the current directory and read package.json');
console.log(result);

Streaming Responses

For real-time output:

const stream = await client.messages.stream({
  model: 'claude-sonnet-4-20250514',
  max_tokens: 1024,
  messages: [{ role: 'user', content: 'Write a poem' }]
});

for await (const event of stream) {
  if (event.type === 'content_block_delta' &&
      event.delta.type === 'text_delta') {
    process.stdout.write(event.delta.text);
  }
}

Conversation Memory

Maintain conversation history:

class ConversationAgent {
  private messages: any[] = [];

  async send(userMessage: string): Promise<string> {
    this.messages.push({ role: 'user', content: userMessage });

    const response = await client.messages.create({
      model: 'claude-sonnet-4-20250514',
      max_tokens: 1024,
      messages: this.messages
    });

    const assistantMessage = response.content[0].text;
    this.messages.push({ role: 'assistant', content: assistantMessage });

    return assistantMessage;
  }

  clear() {
    this.messages = [];
  }
}

Error Handling

Robust error handling:

async function safeAgent(userMessage: string) {
  try {
    return await agent(userMessage);
  } catch (error) {
    if (error.status === 429) {
      // Rate limited - wait and retry
      await sleep(5000);
      return await agent(userMessage);
    }
    if (error.status === 500) {
      // Server error - retry once
      return await agent(userMessage);
    }
    throw error;
  }
}

Integration Patterns

REST API Wrapper

import express from 'express';

const app = express();
app.use(express.json());

app.post('/chat', async (req, res) => {
  const { message } = req.body;

  try {
    const response = await agent(message);
    res.json({ response });
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

WebSocket for Real-Time

import { WebSocketServer } from 'ws';

const wss = new WebSocketServer({ port: 8080 });

wss.on('connection', (ws) => {
  ws.on('message', async (message) => {
    const stream = await client.messages.stream({
      model: 'claude-sonnet-4-20250514',
      max_tokens: 1024,
      messages: [{ role: 'user', content: message.toString() }]
    });

    for await (const event of stream) {
      if (event.type === 'content_block_delta') {
        ws.send(JSON.stringify(event));
      }
    }
  });
});

Try It Yourself

Exercise: Build a Code Reviewer

Create an agent that can: 1. Read files from a directory 2. Analyze code for issues 3. Suggest improvements

Start with the file tools from the example, then add analysis capabilities.

Exercise: Multi-Tool Agent

Build an agent with multiple tool categories: - File operations (read, write, list) - System info (time, env vars) - Calculations (math operations)

Test it with prompts that require combining tools.

What's Next?

Learn enterprise patterns in 02-enterprise-patterns.


Summary: - The SDK provides programmatic access to Claude with tools - Define tools with schemas, execute them when Claude calls - Agent loop: send message → handle tool calls → repeat until done - Stream for real-time responses - Integrate via REST, WebSocket, or other patterns


Learning Resources

Fireship: MCP & SDK Integration (3M+ subscribers)

Build custom AI agents using the Claude Agent SDK with tool definitions and agent loops.

Additional Resources

Type Resource Description
🎬 Video SDK Workflow Patterns All About AI - SDK integration
📚 Official Docs Agent SDK Reference Official SDK documentation
📖 Tutorial Building Agents Guide Anthropic engineering blog
🎓 Free Course DataCamp SDK Tutorial Free step-by-step guide
💼 Commercial AI Development Course SDK patterns and practices