Benutzerdefinierte Tools
Benutzerdefinierte Tools ermöglichen es Ihnen, die Fähigkeiten von Claude Code 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-agent-sdk";
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 Temperatur für einen Standort anhand von Koordinaten abrufen",
{
latitude: z.number().describe("Breitengrad-Koordinate"),
longitude: z.number().describe("Längengrad-Koordinate")
},
async (args) => {
const response = await fetch(`https://api.open-meteo.com/v1/forecast?latitude=${args.latitude}&longitude=${args.longitude}¤t=temperature_2m&temperature_unit=fahrenheit`);
const data = await response.json();
return {
content: [{
type: "text",
text: `Temperatur: ${data.current.temperature_2m}°F`
}]
};
}
)
]
});from claude_agent_sdk import tool, create_sdk_mcp_server, ClaudeSDKClient, ClaudeAgentOptions
from typing import Any
import aiohttp
# Definieren Sie ein benutzerdefiniertes Tool mit dem @tool-Decorator
@tool("get_weather", "Aktuelle Temperatur für einen Standort anhand von Koordinaten abrufen", {"latitude": float, "longitude": float})
async def get_weather(args: dict[str, Any]) -> dict[str, Any]:
# Wetter-API aufrufen
async with aiohttp.ClientSession() as session:
async with session.get(
f"https://api.open-meteo.com/v1/forecast?latitude={args['latitude']}&longitude={args['longitude']}¤t=temperature_2m&temperature_unit=fahrenheit"
) as response:
data = await response.json()
return {
"content": [{
"type": "text",
"text": f"Temperatur: {data['current']['temperature_2m']}°F"
}]
}
# Erstellen Sie einen SDK MCP-Server mit dem benutzerdefinierten Tool
custom_server = create_sdk_mcp_server(
name="my-custom-tools",
version="1.0.0",
tools=[get_weather] # Übergeben Sie die dekorierte Funktion
)Verwenden benutzerdefinierter Tools
Übergeben Sie den benutzerdefinierten Server an die query-Funktion über die mcpServers-Option als Dictionary/Objekt.
Wichtig: Benutzerdefinierte MCP-Tools erfordern den Streaming-Eingabemodus. Sie müssen einen asynchronen Generator/Iterable für den prompt-Parameter verwenden - ein einfacher String funktioniert nicht mit MCP-Servern.
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_weatherim Servermy-custom-toolswird zumcp__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-agent-sdk";
// Verwenden Sie die benutzerdefinierten Tools in Ihrer Abfrage mit Streaming-Eingabe
async function* generateMessages() {
yield {
type: "user" as const,
message: {
role: "user" as const,
content: "Wie ist das Wetter in San Francisco?"
}
};
}
for await (const message of query({
prompt: generateMessages(), // Verwenden Sie asynchronen Generator für Streaming-Eingabe
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 mit Streaming-Eingabe erlauben
async function* generateMessages() {
yield {
type: "user" as const,
message: {
role: "user" as const,
content: "Berechne 5 + 3 und übersetze 'hallo' ins Spanische"
}
};
}
for await (const message of query({
prompt: generateMessages(), // Verwenden Sie asynchronen Generator für Streaming-Eingabe
options: {
mcpServers: {
utilities: multiToolServer
},
allowedTools: [
"mcp__utilities__calculate", // Taschenrechner erlauben
"mcp__utilities__translate", // Übersetzer erlauben
// "mcp__utilities__search_web" ist NICHT erlaubt
]
}
})) {
// Nachrichten verarbeiten
}Typsicherheit mit Python
Der @tool-Decorator 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("Anfragekörper"),
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)
}]
};
}
)
]
});Taschenrechner-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
- TypeScript SDK-Referenz
- Python SDK-Referenz
- MCP-Dokumentation
- SDK-Konfiguration - Konfiguration und Einrichtung