Loading...
    • Developer Guide
    • API Reference
    • MCP
    • Resources
    • Release Notes
    Search...
    ⌘K
    First steps
    Intro to ClaudeQuickstart
    Models & pricing
    Models overviewChoosing a modelWhat's new in Claude 4.5Migrating to Claude 4.5Model deprecationsPricing
    Build with Claude
    Features overviewUsing the Messages APIContext windowsPrompting best practices
    Capabilities
    Prompt cachingContext editingExtended thinkingEffortStreaming MessagesBatch processingCitationsMultilingual supportToken countingEmbeddingsVisionPDF supportFiles APISearch resultsStructured outputs
    Tools
    OverviewHow to implement tool useFine-grained tool streamingBash toolCode execution toolProgrammatic tool callingComputer use toolText editor toolWeb fetch toolWeb search toolMemory toolTool search tool
    Agent Skills
    OverviewQuickstartBest practicesUsing Skills with the API
    Agent SDK
    OverviewQuickstartTypeScript SDKTypeScript V2 (preview)Python SDKMigration Guide
    Streaming InputHandling PermissionsControl execution with hooksSession ManagementFile checkpointingStructured outputs in the SDKHosting the Agent SDKSecurely deploying AI agentsModifying system promptsMCP in the SDKCustom ToolsSubagents in the SDKSlash Commands in the SDKAgent Skills in the SDKTracking Costs and UsageTodo ListsPlugins in the SDK
    MCP in the API
    MCP connectorRemote MCP servers
    Claude on 3rd-party platforms
    Amazon BedrockMicrosoft FoundryVertex AI
    Prompt engineering
    OverviewPrompt generatorUse prompt templatesPrompt improverBe clear and directUse examples (multishot prompting)Let Claude think (CoT)Use XML tagsGive Claude a role (system prompts)Prefill Claude's responseChain complex promptsLong context tipsExtended thinking tips
    Test & evaluate
    Define success criteriaDevelop test casesUsing the Evaluation ToolReducing latency
    Strengthen guardrails
    Reduce hallucinationsIncrease output consistencyMitigate jailbreaksStreaming refusalsReduce prompt leakKeep Claude in character
    Administration and monitoring
    Admin API overviewUsage and Cost APIClaude Code Analytics API
    Console
    Log in
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...
    Loading...

    Solutions

    • AI agents
    • Code modernization
    • Coding
    • Customer support
    • Education
    • Financial services
    • Government
    • Life sciences

    Partners

    • Amazon Bedrock
    • Google Cloud's Vertex AI

    Learn

    • Blog
    • Catalog
    • Courses
    • Use cases
    • Connectors
    • Customer stories
    • Engineering at Anthropic
    • Events
    • Powered by Claude
    • Service partners
    • Startups program

    Company

    • Anthropic
    • Careers
    • Economic Futures
    • Research
    • News
    • Responsible Scaling Policy
    • Security and compliance
    • Transparency

    Learn

    • Blog
    • Catalog
    • Courses
    • Use cases
    • Connectors
    • Customer stories
    • Engineering at Anthropic
    • Events
    • Powered by Claude
    • Service partners
    • Startups program

    Help and security

    • Availability
    • Status
    • Support
    • Discord

    Terms and policies

    • Privacy policy
    • Responsible disclosure policy
    • Terms of service: Commercial
    • Terms of service: Consumer
    • Usage policy
    Guides

    Custom Tools

    Build and integrate custom tools to extend Claude Agent SDK functionality

    Custom tools allow you to extend Claude Code's capabilities with your own functionality through in-process MCP servers, enabling Claude to interact with external services, APIs, or perform specialized operations.

    Creating Custom Tools

    Use the createSdkMcpServer and tool helper functions to define type-safe custom tools:

    import { query, tool, createSdkMcpServer } from "@anthropic-ai/claude-agent-sdk"; import { z } from "zod";  // Create an SDK MCP server with custom tools const customServer = createSdkMcpServer({  name: "my-custom-tools",  version: "1.0.0",  tools: [  tool(  "get_weather",  "Get current temperature for a location using coordinates",  {  latitude: z.number().describe("Latitude coordinate"),  longitude: z.number().describe("Longitude coordinate")  },  async (args) => {  const response = await fetch(`https://api.open-meteo.com/v1/forecast?latitude=${args.latitude}&longitude=${args.longitude}&current=temperature_2m&temperature_unit=fahrenheit`);  const data = await response.json();   return {  content: [{  type: "text",  text: `Temperature: ${data.current.temperature_2m}°F`  }]  };  }  )  ] });

    Using Custom Tools

    Pass the custom server to the query function via the mcpServers option as a dictionary/object.

    Important: Custom MCP tools require streaming input mode. You must use an async generator/iterable for the prompt parameter - a simple string will not work with MCP servers.

    Tool Name Format

    When MCP tools are exposed to Claude, their names follow a specific format:

    • Pattern: mcp__{server_name}__{tool_name}
    • Example: A tool named get_weather in server my-custom-tools becomes mcp__my-custom-tools__get_weather

    Configuring Allowed Tools

    You can control which tools Claude can use via the allowedTools option:

    import { query } from "@anthropic-ai/claude-agent-sdk";  // Use the custom tools in your query with streaming input async function* generateMessages() {  yield {  type: "user" as const,  message: {  role: "user" as const,  content: "What's the weather in San Francisco?"  }  }; }  for await (const message of query({  prompt: generateMessages(), // Use async generator for streaming input  options: {  mcpServers: {  "my-custom-tools": customServer // Pass as object/dictionary, not array  },  // Optionally specify which tools Claude can use  allowedTools: [  "mcp__my-custom-tools__get_weather", // Allow the weather tool  // Add other tools as needed  ],  maxTurns: 3  } })) {  if (message.type === "result" && message.subtype === "success") {  console.log(message.result);  } }

    Multiple Tools Example

    When your MCP server has multiple tools, you can selectively allow them:

    const multiToolServer = createSdkMcpServer({  name: "utilities",  version: "1.0.0",  tools: [  tool("calculate", "Perform calculations", { /* ... */ }, async (args) => { /* ... */ }),  tool("translate", "Translate text", { /* ... */ }, async (args) => { /* ... */ }),  tool("search_web", "Search the web", { /* ... */ }, async (args) => { /* ... */ })  ] });  // Allow only specific tools with streaming input async function* generateMessages() {  yield {  type: "user" as const,  message: {  role: "user" as const,  content: "Calculate 5 + 3 and translate 'hello' to Spanish"  }  }; }  for await (const message of query({  prompt: generateMessages(), // Use async generator for streaming input  options: {  mcpServers: {  utilities: multiToolServer  },  allowedTools: [  "mcp__utilities__calculate", // Allow calculator  "mcp__utilities__translate", // Allow translator  // "mcp__utilities__search_web" is NOT allowed  ]  } })) {  // Process messages }

    Type Safety with Python

    The @tool decorator supports various schema definition approaches for type safety:

    import { z } from "zod";  tool(  "process_data",  "Process structured data with type safety",  {  // Zod schema defines both runtime validation and TypeScript types  data: z.object({  name: z.string(),  age: z.number().min(0).max(150),  email: z.string().email(),  preferences: z.array(z.string()).optional()  }),  format: z.enum(["json", "csv", "xml"]).default("json")  },  async (args) => {  // args is fully typed based on the schema  // TypeScript knows: args.data.name is string, args.data.age is number, etc.  console.log(`Processing ${args.data.name}'s data as ${args.format}`);    // Your processing logic here  return {  content: [{  type: "text",  text: `Processed data for ${args.data.name}`  }]  };  } )

    Error Handling

    Handle errors gracefully to provide meaningful feedback:

    tool(  "fetch_data",  "Fetch data from an API",  {  endpoint: z.string().url().describe("API endpoint URL")  },  async (args) => {  try {  const response = await fetch(args.endpoint);    if (!response.ok) {  return {  content: [{  type: "text",  text: `API error: ${response.status} ${response.statusText}`  }]  };  }    const data = await response.json();  return {  content: [{  type: "text",  text: JSON.stringify(data, null, 2)  }]  };  } catch (error) {  return {  content: [{  type: "text",  text: `Failed to fetch data: ${error.message}`  }]  };  }  } )

    Example Tools

    Database Query Tool

    const databaseServer = createSdkMcpServer({  name: "database-tools",  version: "1.0.0",  tools: [  tool(  "query_database",  "Execute a database query",  {  query: z.string().describe("SQL query to execute"),  params: z.array(z.any()).optional().describe("Query parameters")  },  async (args) => {  const results = await db.query(args.query, args.params || []);  return {  content: [{  type: "text",  text: `Found ${results.length} rows:\n${JSON.stringify(results, null, 2)}`  }]  };  }  )  ] });

    API Gateway Tool

    const apiGatewayServer = createSdkMcpServer({  name: "api-gateway",  version: "1.0.0",  tools: [  tool(  "api_request",  "Make authenticated API requests to external services",  {  service: z.enum(["stripe", "github", "openai", "slack"]).describe("Service to call"),  endpoint: z.string().describe("API endpoint path"),  method: z.enum(["GET", "POST", "PUT", "DELETE"]).describe("HTTP method"),  body: z.record(z.any()).optional().describe("Request body"),  query: z.record(z.string()).optional().describe("Query parameters")  },  async (args) => {  const config = {  stripe: { baseUrl: "https://api.stripe.com/v1", key: process.env.STRIPE_KEY },  github: { baseUrl: "https://api.github.com", key: process.env.GITHUB_TOKEN },  openai: { baseUrl: "https://api.openai.com/v1", key: process.env.OPENAI_KEY },  slack: { baseUrl: "https://slack.com/api", key: process.env.SLACK_TOKEN }  };    const { baseUrl, key } = config[args.service];  const url = new URL(`${baseUrl}${args.endpoint}`);    if (args.query) {  Object.entries(args.query).forEach(([k, v]) => url.searchParams.set(k, v));  }    const response = await fetch(url, {  method: args.method,  headers: { Authorization: `Bearer ${key}`, "Content-Type": "application/json" },  body: args.body ? JSON.stringify(args.body) : undefined  });    const data = await response.json();  return {  content: [{  type: "text",  text: JSON.stringify(data, null, 2)  }]  };  }  )  ] });

    Calculator Tool

    const calculatorServer = createSdkMcpServer({  name: "calculator",  version: "1.0.0",  tools: [  tool(  "calculate",  "Perform mathematical calculations",  {  expression: z.string().describe("Mathematical expression to evaluate"),  precision: z.number().optional().default(2).describe("Decimal precision")  },  async (args) => {  try {  // Use a safe math evaluation library in production  const result = eval(args.expression); // Example only!  const formatted = Number(result).toFixed(args.precision);    return {  content: [{  type: "text",  text: `${args.expression} = ${formatted}`  }]  };  } catch (error) {  return {  content: [{  type: "text",  text: `Error: Invalid expression - ${error.message}`  }]  };  }  }  ),  tool(  "compound_interest",  "Calculate compound interest for an investment",  {  principal: z.number().positive().describe("Initial investment amount"),  rate: z.number().describe("Annual interest rate (as decimal, e.g., 0.05 for 5%)"),  time: z.number().positive().describe("Investment period in years"),  n: z.number().positive().default(12).describe("Compounding frequency per year")  },  async (args) => {  const amount = args.principal * Math.pow(1 + args.rate / args.n, args.n * args.time);  const interest = amount - args.principal;    return {  content: [{  type: "text",  text: `Investment Analysis:\n` +  `Principal: $${args.principal.toFixed(2)}\n` +  `Rate: ${(args.rate * 100).toFixed(2)}%\n` +  `Time: ${args.time} years\n` +  `Compounding: ${args.n} times per year\n\n` +  `Final Amount: $${amount.toFixed(2)}\n` +  `Interest Earned: $${interest.toFixed(2)}\n` +  `Return: ${((interest / args.principal) * 100).toFixed(2)}%`  }]  };  }  )  ] });

    Related Documentation

    • TypeScript SDK Reference
    • Python SDK Reference
    • MCP Documentation
    • SDK Overview
    • Creating Custom Tools
    • Using Custom Tools
    • Tool Name Format
    • Configuring Allowed Tools
    • Multiple Tools Example
    • Type Safety with Python
    • Error Handling
    • Example Tools
    • Database Query Tool
    • API Gateway Tool
    • Calculator Tool
    • Related Documentation