Benutzerdefinierte Tools ermöglichen es Ihnen, Claudes Code-Funktionen mit Ihrer eigenen Funktionalität durch In-Process-MCP-Server zu erweitern, wodurch Claude mit externen Diensten, APIs interagieren oder spezialisierte Operationen durchführen kann.

Erstellen benutzerdefinierter Tools

Verwenden Sie die Hilfsfunktionen createSdkMcpServer und tool, um typsichere benutzerdefinierte Tools zu definieren:
import { query, tool, createSdkMcpServer } from "@anthropic-ai/claude-code";
import { z } from "zod";

// Erstellen Sie einen SDK MCP-Server mit benutzerdefinierten Tools
const customServer = createSdkMcpServer({
  name: "my-custom-tools",
  version: "1.0.0",
  tools: [
    tool(
      "get_weather",
      "Aktuelle Wetterdaten für einen Standort abrufen",
      {
        location: z.string().describe("Stadtname oder Koordinaten"),
        units: z.enum(["celsius", "fahrenheit"]).default("celsius").describe("Temperatureinheiten")
      },
      async (args) => {
        // Wetter-API aufrufen
        const response = await fetch(
          `https://api.weather.com/v1/current?q=${args.location}&units=${args.units}`
        );
        const data = await response.json();
        
        return {
          content: [{
            type: "text",
            text: `Temperatur: ${data.temp}°\nBedingungen: ${data.conditions}\nLuftfeuchtigkeit: ${data.humidity}%`
          }]
        };
      }
    )
  ]
});

Verwenden benutzerdefinierter Tools

Übergeben Sie den benutzerdefinierten Server an die query-Funktion über die mcpServers-Option als Dictionary/Objekt.

Tool-Namensformat

Wenn MCP-Tools Claude zur Verfügung gestellt werden, folgen ihre Namen einem spezifischen Format:
  • Muster: mcp__{server_name}__{tool_name}
  • Beispiel: Ein Tool namens get_weather im Server my-custom-tools wird zu mcp__my-custom-tools__get_weather

Konfigurieren erlaubter Tools

Sie können über die allowedTools-Option steuern, welche Tools Claude verwenden kann:
import { query } from "@anthropic-ai/claude-code";

// Verwenden Sie die benutzerdefinierten Tools in Ihrer Abfrage
for await (const message of query({
  prompt: "Wie ist das Wetter in San Francisco?",
  options: {
    mcpServers: {
      "my-custom-tools": customServer  // Als Objekt/Dictionary übergeben, nicht als Array
    },
    // Optional angeben, welche Tools Claude verwenden kann
    allowedTools: [
      "mcp__my-custom-tools__get_weather",  // Das Wetter-Tool erlauben
      // Weitere Tools nach Bedarf hinzufügen
    ],
    maxTurns: 3
  }
})) {
  if (message.type === "result" && message.subtype === "success") {
    console.log(message.result);
  }
}

Beispiel für mehrere Tools

Wenn Ihr MCP-Server mehrere Tools hat, können Sie sie selektiv erlauben:
const multiToolServer = createSdkMcpServer({
  name: "utilities",
  version: "1.0.0",
  tools: [
    tool("calculate", "Berechnungen durchführen", { /* ... */ }, async (args) => { /* ... */ }),
    tool("translate", "Text übersetzen", { /* ... */ }, async (args) => { /* ... */ }),
    tool("search_web", "Das Web durchsuchen", { /* ... */ }, async (args) => { /* ... */ })
  ]
});

// Nur bestimmte Tools erlauben
for await (const message of query({
  prompt: "Berechne 5 + 3 und übersetze 'hello' ins Spanische",
  options: {
    mcpServers: {
      utilities: multiToolServer
    },
    allowedTools: [
      "mcp__utilities__calculate",   // Rechner erlauben
      "mcp__utilities__translate",   // Übersetzer erlauben
      // "mcp__utilities__search_web" ist NICHT erlaubt
    ]
  }
})) {
  // Nachrichten verarbeiten
}

Typsicherheit mit Python

Der @tool-Dekorator unterstützt verschiedene Schema-Definitionsansätze für Typsicherheit:
import { z } from "zod";

tool(
  "process_data",
  "Strukturierte Daten mit Typsicherheit verarbeiten",
  {
    // Zod-Schema definiert sowohl Laufzeitvalidierung als auch TypeScript-Typen
    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 ist vollständig typisiert basierend auf dem Schema
    // TypeScript weiß: args.data.name ist string, args.data.age ist number, etc.
    console.log(`Verarbeite ${args.data.name}s Daten als ${args.format}`);
    
    // Ihre Verarbeitungslogik hier
    return {
      content: [{
        type: "text",
        text: `Daten für ${args.data.name} verarbeitet`
      }]
    };
  }
)

Fehlerbehandlung

Behandeln Sie Fehler elegant, um aussagekräftiges Feedback zu geben:
tool(
  "fetch_data",
  "Daten von einer API abrufen",
  {
    endpoint: z.string().url().describe("API-Endpunkt-URL")
  },
  async (args) => {
    try {
      const response = await fetch(args.endpoint);
      
      if (!response.ok) {
        return {
          content: [{
            type: "text",
            text: `API-Fehler: ${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: `Fehler beim Abrufen der Daten: ${error.message}`
        }]
      };
    }
  }
)

Beispiel-Tools

Datenbankabfrage-Tool

const databaseServer = createSdkMcpServer({
  name: "database-tools",
  version: "1.0.0",
  tools: [
    tool(
      "query_database",
      "Eine Datenbankabfrage ausführen",
      {
        query: z.string().describe("Auszuführende SQL-Abfrage"),
        params: z.array(z.any()).optional().describe("Abfrageparameter")
      },
      async (args) => {
        const results = await db.query(args.query, args.params || []);
        return {
          content: [{
            type: "text",
            text: `${results.length} Zeilen gefunden:\n${JSON.stringify(results, null, 2)}`
          }]
        };
      }
    )
  ]
});

API-Gateway-Tool

const apiGatewayServer = createSdkMcpServer({
  name: "api-gateway",
  version: "1.0.0",
  tools: [
    tool(
      "api_request",
      "Authentifizierte API-Anfragen an externe Dienste stellen",
      {
        service: z.enum(["stripe", "github", "openai", "slack"]).describe("Aufzurufender Dienst"),
        endpoint: z.string().describe("API-Endpunkt-Pfad"),
        method: z.enum(["GET", "POST", "PUT", "DELETE"]).describe("HTTP-Methode"),
        body: z.record(z.any()).optional().describe("Anfrage-Body"),
        query: z.record(z.string()).optional().describe("Abfrageparameter")
      },
      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)
          }]
        };
      }
    )
  ]
});

Rechner-Tool

const calculatorServer = createSdkMcpServer({
  name: "calculator",
  version: "1.0.0",
  tools: [
    tool(
      "calculate",
      "Mathematische Berechnungen durchführen",
      {
        expression: z.string().describe("Auszuwertender mathematischer Ausdruck"),
        precision: z.number().optional().default(2).describe("Dezimalgenauigkeit")
      },
      async (args) => {
        try {
          // Verwenden Sie eine sichere Mathematik-Evaluierungsbibliothek in der Produktion
          const result = eval(args.expression); // Nur Beispiel!
          const formatted = Number(result).toFixed(args.precision);
          
          return {
            content: [{
              type: "text",
              text: `${args.expression} = ${formatted}`
            }]
          };
        } catch (error) {
          return {
            content: [{
              type: "text",
              text: `Fehler: Ungültiger Ausdruck - ${error.message}`
            }]
          };
        }
      }
    ),
    tool(
      "compound_interest",
      "Zinseszins für eine Investition berechnen",
      {
        principal: z.number().positive().describe("Anfangsinvestitionsbetrag"),
        rate: z.number().describe("Jährlicher Zinssatz (als Dezimalzahl, z.B. 0,05 für 5%)"),
        time: z.number().positive().describe("Investitionszeitraum in Jahren"),
        n: z.number().positive().default(12).describe("Zinseszinshäufigkeit pro Jahr")
      },
      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: `Investitionsanalyse:\n` +
                  `Kapital: $${args.principal.toFixed(2)}\n` +
                  `Zinssatz: ${(args.rate * 100).toFixed(2)}%\n` +
                  `Zeit: ${args.time} Jahre\n` +
                  `Zinseszins: ${args.n} mal pro Jahr\n\n` +
                  `Endbetrag: $${amount.toFixed(2)}\n` +
                  `Verdiente Zinsen: $${interest.toFixed(2)}\n` +
                  `Rendite: ${((interest / args.principal) * 100).toFixed(2)}%`
          }]
        };
      }
    )
  ]
});

Verwandte Dokumentation