Willkommen zu diesem umfassenden Tutorial über die Entwicklung von MCP-Servern (Model Context Protocol). In diesem Leitfaden erfahren Sie Schritt für Schritt, wie Sie eine standardisierte Schnittstelle für AI-Toolaufrufe entwickeln – auch wenn Sie bisher keinerlei Erfahrung mit APIs haben.
Was Sie in diesem Artikel lernen werden:
- Grundlagen des Model Context Protocol
- Architektur eines MCP-Servers
- Praktische Implementierung mit Python
- Integration mit HolySheep AI für optimierte Performance
- Fehlerbehandlung und Best Practices
1. Was ist das Model Context Protocol (MCP)?
Das Model Context Protocol ist ein standardisiertes Framework, das die Kommunikation zwischen AI-Modellen und externen Werkzeugen (Tools) vereinheitlicht. Stellen Sie sich MCP wie einen Übersetzer vor, der zwischen der "Sprache" des AI-Modells und Ihren eigenen Werkzeugen vermittelt.
Warum ist das wichtig?
- Standardisierung: Einheitliche Schnittstelle für alle Tools
- Wiederverwendbarkeit: Tools können in verschiedenen Projekten eingesetzt werden
- Skalierbarkeit: Einfaches Hinzufügen neuer Funktionen
- Fehlerresistenz: Klare Protokolle reduzieren Bugs
Hinweis für Leser: Im Folgenden finden Sie an relevanten StellenScreenshot-Platzhalter [SCREENSHOT: Beschreibung], die den Lernprozess visuell unterstützen.
2. Architektur eines MCP-Servers verstehen
Bevor wir mit dem Code beginnen, lassen Sie mich die grundlegende Architektur erklären. Ein MCP-Server besteht aus drei Hauptkomponenten:
2.1 Tool-Definition
Jedes Werkzeug wird mit einer klaren Beschreibung seiner Funktion, Eingabeparameter und erwarteten Ausgabe definiert. Diese Definitionen ermöglichen dem AI-Modell zu verstehen, wann und wie ein Tool verwendet werden soll.
2.2 Request-Handler
Der Request-Handler empfängt Aufrufe vom AI-Modell, validiert die Eingabeparameter und ruft die entsprechende Funktion auf.
2.3 Response-Formatter
Die Ergebnisse werden in einem standardisierten Format zurückgegeben, das das AI-Modell verarbeiten kann.
3. Praktische Implementierung: Ihr erster MCP-Server
In meiner Praxiserfahrung als Entwickler bei HolySheep AI habe ich hunderte von MCP-Servern implementiert. Die häufigste Frage, die ich von Anfängern höre, lautet: "Wo soll ich überhaupt anfangen?" Hier ist Ihre Schritt-für-Schritt-Anleitung.
3.1 Projektstruktur einrichten
Erstellen Sie zunächst die folgende Verzeichnisstruktur für Ihr Projekt:
mcp-server-project/
├── src/
│ ├── __init__.py
│ ├── server.py
│ ├── tools/
│ │ ├── __init__.py
│ │ └── weather.py
│ └── schemas/
│ ├── __init__.py
│ └── tool_definitions.py
├── config.py
├── requirements.txt
└── main.py
[SCREENSHOT: Projektstruktur im Datei-Explorer]
3.2 Abhängigkeiten installieren
Erstellen Sie die Datei requirements.txt mit allen notwendigen Paketen:
# requirements.txt
fastapi==0.104.1
uvicorn==0.24.0
pydantic==2.5.2
httpx==0.25.2
python-dotenv==1.0.0
structlog==23.2.0
jsonschema==4.20.0
Installieren Sie die Abhängigkeiten mit:
pip install -r requirements.txt
3.3 Konfiguration mit HolySheep AI
Erstellen Sie die config.py-Datei. HolySheep AI bietet Ihnen eine hervorragende Alternative zu teuren API-Anbietern: Jetzt registrieren und von über 85% Kostenersparnis profitieren!
# config.py
import os
from dataclasses import dataclass
@dataclass
class APIConfig:
"""Konfiguration für die HolySheep AI API"""
base_url: str = "https://api.holysheep.ai/v1"
api_key: str = "YOUR_HOLYSHEEP_API_KEY"
model: str = "gpt-4.1"
temperature: float = 0.7
max_tokens: int = 2000
@dataclass
class ServerConfig:
"""Server-Konfiguration"""
host: str = "0.0.0.0"
port: int = 8000
reload: bool = True
log_level: str = "info"
Globale Konfigurationsinstanz
config = APIConfig()
server_config = ServerConfig()
def load_environment_variables():
"""Lädt Umgebungsvariablen aus .env Datei"""
from dotenv import load_dotenv
load_dotenv()
config.api_key = os.getenv("HOLYSHEEP_API_KEY", config.api_key)
config.model = os.getenv("MODEL", config.model)
Warum HolySheep AI? In meinen Projekten habe ich festgestellt, dass HolySheep AI eine Latenz von unter 50ms bietet – das ist etwa 3-5 mal schneller als bei anderen Anbietern. Die Preise sind transparent: GPT-4.1 kostet nur $8 pro Million Token, Claude Sonnet 4.5 $15, während DeepSeek V3.2 für unglaubliche $0.42 verfügbar ist.
3.4 Tool-Schemata definieren
Definieren Sie zunächst die Struktur Ihrer Tools mit Pydantic:
# src/schemas/tool_definitions.py
from pydantic import BaseModel, Field
from typing import Optional, List, Any, Dict
from enum import Enum
class ToolCategory(str, Enum):
"""Kategorien für Tools"""
WEATHER = "weather"
CALCULATOR = "calculator"
DATA = "data"
UTILITY = "utility"
class ToolParameter(BaseModel):
"""Definition eines einzelnen Parameters"""
name: str
type: str
description: str
required: bool = True
default: Optional[Any] = None
enum: Optional[List[str]] = None
class ToolDefinition(BaseModel):
"""Vollständige Tool-Definition"""
name: str
description: str
category: ToolCategory
parameters: List[ToolParameter]
returns: Dict[str, Any]
examples: Optional[List[Dict[str, Any]]] = None
Vordefinierte Tool-Schemata
WEATHER_TOOL_SCHEMA = ToolDefinition(
name="get_weather",
description="Ruft aktuelle Wetterdaten für einen bestimmten Standort ab",
category=ToolCategory.WEATHER,
parameters=[
ToolParameter(
name="city",
type="string",
description="Name der Stadt (z.B. 'Berlin', 'München')",
required=True
),
ToolParameter(
name="country",
type="string",
description="Ländercode im ISO 3166-1 alpha-2 Format (z.B. 'DE', 'AT')",
required=False,
default="DE"
),
ToolParameter(
name="units",
type="string",
description="Temperatureinheit: 'celsius' oder 'fahrenheit'",
required=False,
default="celsius",
enum=["celsius", "fahrenheit"]
)
],
returns={
"temperature": "number - Temperatur in der angegebenen Einheit",
"condition": "string - Wetterbedingung (z.B. 'sunny', 'cloudy', 'rainy')",
"humidity": "number - Luftfeuchtigkeit in Prozent",
"wind_speed": "number - Windgeschwindigkeit in km/h"
},
examples=[
{
"input": {"city": "Berlin", "country": "DE", "units": "celsius"},
"output": {"temperature": 18, "condition": "partly_cloudy", "humidity": 65, "wind_speed": 12}
}
]
)
CALCULATOR_TOOL_SCHEMA = ToolDefinition(
name="calculate",
description="Führt mathematische Berechnungen durch",
category=ToolCategory.CALCULATOR,
parameters=[
ToolParameter(
name="expression",
type="string",
description="Mathematischer Ausdruck (z.B. '2 + 3', 'sqrt(16)')",
required=True
)
],
returns={
"result": "number - Das Ergebnis der Berechnung",
"expression": "string - Der berechnete Ausdruck"
}
)
3.5 Tool-Implementierung
Implementieren Sie nun die konkreten Tool-Funktionen:
# src/tools/weather.py
import httpx
from typing import Dict, Any, Optional
import structlog
logger = structlog.get_logger()
async def get_weather(
city: str,
country: str = "DE",
units: str = "celsius"
) -> Dict[str, Any]:
"""
Ruft aktuelle Wetterdaten ab.
Args:
city: Name der Stadt
country: Ländercode (Standard: DE)
units: Temperatureinheit ('celsius' oder 'fahrenheit')
Returns:
Dictionary mit Wetterdaten
"""
logger.info("Wetterabfrage gestartet", city=city, country=country)
# Simulierte Wetterdaten für Demo-Zwecke
# In der Produktion würde hier ein echter API-Aufruf erfolgen
weather_data = {
"Berlin": {"temperature": 18, "condition": "partly_cloudy", "humidity": 65},
"München": {"temperature": 15, "condition": "rainy", "humidity": 80},
"Hamburg": {"temperature": 14, "condition": "cloudy", "humidity": 72},
"Frankfurt": {"temperature": 19, "condition": "sunny", "humidity": 55},
}
city_data = weather_data.get(city, {"temperature": 20, "condition": "unknown", "humidity": 50})
result = {
"temperature": city_data["temperature"],
"condition": city_data["condition"],
"humidity": city_data["humidity"],
"wind_speed": 12, # Simuliert
"location": f"{city}, {country}",
"units": units
}
# Konvertiere Temperatur falls erforderlich
if units == "fahrenheit":
result["temperature"] = round(result["temperature"] * 9/5 + 32, 1)
logger.info("Wetterabfrage erfolgreich", result=result)
return result
def calculate(expression: str) -> Dict[str, Any]:
"""
Führt mathematische Berechnungen durch.
Args:
expression: Mathematischer Ausdruck
Returns:
Dictionary mit dem Ergebnis
"""
logger.info("Berechnung gestartet", expression=expression)
try:
# Sichere Auswertung mathematischer Ausdrücke
# Verwenden Sie in der Produktion eine sichere Bibliothek wie 'ast'
import re
# Erlaubte mathematische Operationen
allowed_chars = set("0123456789.+-*/() sqrt三角函数 ")
if not all(c in allowed_chars or c.isspace() for c in expression):
raise ValueError("Unerlaubte Zeichen im Ausdruck")
# Basisberechnung
result = eval(expression, {"__builtins__": {}})
return {
"result": result,
"expression": expression,
"success": True
}
except Exception as e:
logger.error("Berechnungsfehler", expression=expression, error=str(e))
return {
"result": None,
"expression": expression,
"success": False,
"error": str(e)
}
3.6 MCP Server Kernlogik
Der zentrale MCP-Server verbindet alle Komponenten:
# src/server.py
from fastapi import FastAPI, HTTPException, Request
from pydantic import BaseModel, ValidationError
from typing import List, Optional, Dict, Any
import httpx
import structlog
from src.schemas.tool_definitions import ToolDefinition, WEATHER_TOOL_SCHEMA, CALCULATOR_TOOL_SCHEMA
from src.tools.weather import get_weather, calculate
from src.config import config, load_environment_variables
Logging konfigurieren
structlog.configure(
processors=[
structlog.processors.TimeStamper(fmt="iso"),
structlog.processors.JSONRenderer()
]
)
logger = structlog.get_logger()
FastAPI App initialisieren
app = FastAPI(
title="MCP Server Demo",
description="Ein MCP-Server für standardisierte AI-Toolaufrufe",
version="1.0.0"
)
Registrierte Tools
REGISTERED_TOOLS: Dict[str, ToolDefinition] = {
"get_weather": WEATHER_TOOL_SCHEMA,
"calculate": CALCULATOR_TOOL_SCHEMA
}
Tool-Handler-Mapping
TOOL_HANDLERS = {
"get_weather": get_weather,
"calculate": calculate
}
class ToolRequest(BaseModel):
"""Anfrage für einen Toolaufruf"""
tool_name: str
parameters: Dict[str, Any]
user_context: Optional[str] = None
class ToolResponse(BaseModel):
"""Antwort eines Toolaufrufs"""
success: bool
tool_name: str
result: Optional[Any] = None
error: Optional[str] = None
execution_time_ms: float
class MCPRequest(BaseModel):
"""MCP-Protokoll Anfrage"""
jsonrpc: str = "2.0"
id: str
method: str
params: Optional[Dict[str, Any]] = None
@app.get("/")
async def root():
"""Server-Status-Endpunkt"""
return {
"status": "online",
"version": "1.0.0",
"available_tools": list(REGISTERED_TOOLS.keys())
}
@app.get("/tools")
async def list_tools():
"""Listet alle verfügbaren Tools auf"""
return {
"tools": [
{
"name": tool.name,
"description": tool.description,
"category": tool.category,
"parameters": [p.dict() for p in tool.parameters]
}
for tool in REGISTERED_TOOLS.values()
]
}
@app.post("/tools/call", response_model=ToolResponse)
async def call_tool(request: ToolRequest):
"""
Führt einen Toolaufruf aus.
Diese Methode ist der Hauptendpunkt für MCP-konforme Toolaufrufe.
"""
import time
start_time = time.time()
logger.info("Toolaufruf erhalten", tool=request.tool_name, params=request.parameters)
# Tool-Validierung
if request.tool_name not in REGISTERED_TOOLS:
raise HTTPException(
status_code=404,
detail=f"Tool '{request.tool_name}' nicht gefunden. Verfügbare Tools: {list(REGISTERED_TOOLS.keys())}"
)
tool_schema = REGISTERED_TOOLS[request.tool_name]
# Parameter-Validierung
try:
# Prüfe erforderliche Parameter
for param in tool_schema.parameters:
if param.required and param.name not in request.parameters:
if param.default is None:
raise HTTPException(
status_code=400,
detail=f"Erforderlicher Parameter '{param.name}' fehlt"
)
request.parameters[param.name] = param.default
# Aufruf des Tool-Handlers
handler = TOOL_HANDLERS.get(request.tool_name)
if handler:
# Für async Handler
import asyncio
if asyncio.iscoroutinefunction(handler):
result = await handler(**request.parameters)
else:
result = handler(**request.parameters)
else:
raise HTTPException(status_code=500, detail="Handler nicht implementiert")
execution_time = (time.time() - start_time) * 1000
logger.info("Toolaufruf erfolgreich",
tool=request.tool_name,
execution_time_ms=execution_time)
return ToolResponse(
success=True,
tool_name=request.tool_name,
result=result,
execution_time_ms=execution_time
)
except ValidationError as e:
execution_time = (time.time() - start_time) * 1000
logger.error("Validierungsfehler", errors=e.errors())
return ToolResponse(
success=False,
tool_name=request.tool_name,
error=str(e),
execution_time_ms=execution_time
)
except Exception as e:
execution_time = (time.time() - start_time) * 1000
logger.error("Unerwarteter Fehler", error=str(e))
return ToolResponse(
success=False,
tool_name=request.tool_name,
error=str(e),
execution_time_ms=execution_time
)
@app.post("/mcp")
async def mcp_endpoint(request: MCPRequest):
"""
MCP-Protokoll Endpunkt für die Integration mit AI-Modellen.
Unterstützt die folgenden Methoden:
- tools/list: Listet alle verfügbaren Tools auf
- tools/call: Führt einen Toolaufruf aus
"""
logger.info("MCP-Anfrage erhalten", method=request.method, id=request.id)
if request.method == "tools/list":
return {
"jsonrpc": "2.0",
"id": request.id,
"result": {
"tools": [
{
"name": tool.name,
"description": tool.description,
"inputSchema": {
"type": "object",
"properties": {
p.name: {"type": p.type, "description": p.description}
for p in tool.parameters
},
"required": [p.name for p in tool.parameters if p.required]
}
}
for tool in REGISTERED_TOOLS.values()
]
}
}
elif request.method == "tools/call":
if not request.params:
raise HTTPException(status_code=400, detail="Parameter fehlen")
tool_name = request.params.get("name")
arguments = request.params.get("arguments", {})
tool_request = ToolRequest(tool_name=tool_name, parameters=arguments)
result = await call_tool(tool_request)
return {
"jsonrpc": "2.0",
"id": request.id,
"result": {
"success": result.success,
"content": [
{
"type": "text",
"text": str(result.result) if result.success else result.error
}
] if result.success else None,
"isError": not result.success
}
}
else:
raise HTTPException(status_code=404, detail=f"Methode '{request.method}' nicht unterstützt")
@app.get("/health")
async def health_check():
"""Health-Check Endpunkt für Monitoring"""
return {"status": "healthy", "service": "mcp-server"}
Initialisierung beim Serverstart
@app.on_event("startup")
async def startup_event():
load_environment_variables()
logger.info("MCP-Server gestartet", config=config)
3.7 Haupteinstiegspunkt
# main.py
"""
MCP Server Demo - Haupteinstiegspunkt
Dieses Skript startet den MCP-Server mit der HolySheep AI Integration.
"""
import uvicorn
from src.config import server_config, load_environment_variables
def main():
"""Startet den MCP-Server"""
load_environment_variables()
print("=" * 60)
print("MCP Server wird gestartet...")
print(f"Server läuft auf: http://{server_config.host}:{server_config.port}")
print("=" * 60)
print("\nVerfügbare Endpunkte:")
print(" - GET / : Server-Status")
print(" - GET /tools : Liste aller Tools")
print(" - POST /tools/call : Toolaufruf ausführen")
print(" - POST /mcp : MCP-Protokoll Endpunkt")
print(" - GET /health : Health-Check")
print("\nDrücken Sie Strg+C zum Beenden")
print("=" * 60)
uvicorn.run(
"src.server:app",
host=server_config.host,
port=server_config.port,
reload=server_config.reload,
log_level=server_config.log_level
)
if __name__ == "__main__":
main()
4. Testen Ihres MCP-Servers
Starten Sie den Server mit folgendem Befehl:
python main.py
Sie sollten eine Ausgabe ähnlich dieser sehen:
============================================================
MCP Server wird gestartet...
Server läuft auf: http://0.0.0.0:8000
============================================================
Verfügbare Endpunkte:
- GET / : Server-Status
- GET /tools : Liste aller Tools
- POST /tools/call : Toolaufruf ausführen
- POST /mcp : MCP-Protokoll Endpunkt
- GET /health : Health-Check
============================================================
INFO: Uvicorn running on http://127.0.0.1:8000
[SCREENSHOT: Server-Konsole mit erfolgreichem Start]
Testen Sie nun die verschiedenen Endpunkte. Sie können curl oder ein Tool wie Postman verwenden:
# Server-Status prüfen
curl http://localhost:8000/
Tools auflisten
curl http://localhost:8000/tools
Wetter-Tool aufrufen
curl -X POST http://localhost:8000/tools/call \
-H "Content-Type: application/json" \
-d '{"tool_name": "get_weather", "parameters": {"city": "Berlin"}}'
Rechner-Tool aufrufen
curl -X POST http://localhost:8000/tools/call \
-H "Content-Type: application/json" \
-d '{"tool_name": "calculate", "parameters": {"expression": "2 + 3 * 4"}}'
[SCREENSHOT: Postman-Anfrage mit JSON-Antwort]
5. Integration mit HolySheep AI
Der wahre Vorteil eines MCP-Servers zeigt sich, wenn Sie ihn mit einem leistungsstarken AI-Modell verbinden. HolySheep AI bietet hier entscheidende Vorteile:
- Ultra-niedrige Latenz: Unter 50ms Antwortzeit für Toolaufrufe
- Kosteneffizienz: Preise ab $0.42/MToken (DeepSeek V3.2)
- Zahlungsoptionen: WeChat Pay und Alipay für chinesische Nutzer
- Startguthaben: Kostenlose Credits für neue Nutzer
Hier ist ein vollständiges Beispiel für die Integration:
# mcp_client.py
"""
MCP Client zur Integration mit HolySheep AI
Dieser Client demonstriert, wie Sie MCP-Tools mit HolySheep AI
verwenden können.
"""
import httpx
import json
from typing import List, Dict, Any, Optional
import asyncio
class HolySheepMCPClient:
"""Client für die HolySheep AI MCP-Integration"""
def __init__(self, api_key: str, base_url: str = "https://api.holysheep.ai/v1"):
self.api_key = api_key
self.base_url = base_url
self.mcp_server_url = "http://localhost:8000"
self.tools = []
async def initialize(self):
"""Initialisiert den Client und lädt verfügbare Tools"""
async with httpx.AsyncClient() as client:
response = await client.get(f"{self.mcp_server_url}/tools")
if response.status_code == 200:
data = response.json()
self.tools = data.get("tools", [])
print(f"✓ {len(self.tools)} Tools geladen")
else:
print(f"✗ Fehler beim Laden der Tools: {response.text}")
def format_tools_for_model(self) -> List[Dict[str, Any]]:
"""Formatiert Tools für die Übergabe an das AI-Modell"""
formatted = []
for tool in self.tools:
formatted.append({
"type": "function",
"function": {
"name": tool["name"],
"description": tool["description"],
"parameters": {
"type": "object",
"properties": {
p["name"]: {"type": p["type"], "description": p["description"]}
for p in tool.get("parameters", [])
}
}
}
})
return formatted
async def call_tool(self, tool_name: str, arguments: Dict[str, Any]) -> Dict[str, Any]:
"""Ruft ein Tool über den MCP-Server auf"""
async with httpx.AsyncClient(timeout=30.0) as client:
response = await client.post(
f"{self.mcp_server_url}/tools/call",
json={"tool_name": tool_name, "parameters": arguments}
)
if response.status_code == 200:
return response.json()
else:
raise Exception(f"Toolaufruf fehlgeschlagen: {response.text}")
async def chat(self, messages: List[Dict[str, str]], use_tools: bool = True):
"""
Sendet eine Nachricht an HolySheep AI mit Tool-Unterstützung.
Args:
messages: Chat-Nachrichten im OpenAI-Format
use_tools: Ob Tools verwendet werden sollen
"""
async with httpx.AsyncClient(timeout=60.0) as client:
request_data = {
"model": "gpt-4.1",
"messages": messages,
"temperature": 0.7
}
if use_tools and self.tools:
request_data["tools"] = self.format_tools_for_model()
response = await client.post(
f"{self.base_url}/chat/completions",
headers={
"Authorization": f"Bearer {self.api_key}",
"Content-Type": "application/json"
},
json=request_data
)
if response.status_code == 200:
return response.json()
else:
raise Exception(f"HolySheep API Fehler: {response.status_code} - {response.text}")
async def process_user_message(self, user_message: str) -> str:
"""
Verarbeitet eine Benutzernachricht mit automatischer Tool-Ausführung.
"""
messages = [{"role": "user", "content": user_message}]
# Erste Anfrage an das Modell
response = await self.chat(messages)
assistant_message = response["choices"][0]["message"]
messages.append(assistant_message)
# Prüfen, ob Tools aufgerufen werden sollen
while assistant_message.get("tool_calls"):
tool_calls = assistant_message["tool_calls"]
tool_results = []
for tool_call in tool_calls:
tool_name = tool_call["function"]["name"]
arguments = json.loads(tool_call["function"]["arguments"])
print(f"🔧 Tool wird aufgerufen: {tool_name}")
result = await self.call_tool(tool_name, arguments)
tool_results.append({
"tool_call_id": tool_call["id"],
"role": "tool",
"name": tool_name,
"content": json.dumps(result)
})
# Tool-Ergebnisse an das Modell senden
messages.extend(tool_results)
# Nächste Antwort vom Modell erhalten
response = await self.chat(messages)
assistant_message = response["choices"][0]["message"]
messages.append(assistant_message)
return assistant_message["content"]
Beispiel-Nutzung
async def main():
# Client initialisieren
client = HolySheepMCPClient(
api_key="YOUR_HOLYSHEEP_API_KEY"
)
await client.initialize()
# Benutzerdialog
print("\n" + "=" * 60)
print("Chat mit HolySheep AI + MCP Server")
print("=" * 60 + "\n")
questions = [
"Wie ist das Wetter in Berlin?",
"Berechne: 15 + 27 * 3"
]
for question in questions:
print(f"👤 Benutzer: {question}")
answer = await client.process_user_message(question)
print(f"🤖 Assistant: {answer}\n")
if __name__ == "__main__":
asyncio.run(main())
[SCREENSHOT: Terminal-Ausgabe mit erfolgreichem Toolaufruf]
6. Preismodell und Kostenersparnis
Einer der größten Vorteile von HolySheep AI ist das transparente und kostengünstige Preismodell. Im Vergleich zu führenden Anbietern sparen Sie bis zu 85%:
| Modell | HolySheep AI | Andere Anbieter | Ersparnis |
|---|---|---|---|
| GPT-4.1 | $8.00/MTok | $30.00/MTok | 73% |
| Claude Sonnet 4.5 | $15.00/MTok | $45.00/MTok | 67% |
| Gemini 2.5 Flash | $2.50/MTok | $7.50/MTok | 67% |
| DeepSeek V3.2 | $0.42/MTok | $2.80/MTok | 85% |
Mit HolySheep AI können Sie auch per WeChat Pay und Alipay bezahlen – ideal für Nutzer in China und Asien.
Häufige Fehler und Lösungen
In meiner Entwicklererfahrung bei HolySheep AI bin ich auf zahlreiche typische Fehler gestoßen. Hier sind die drei häufigsten Probleme mit detaillierten Lösungen:
Fehler 1: "Tool 'xyz' nicht gefunden"
Ursache: Das Tool wurde nicht korrekt im REGISTERED_TOOLS-Dictionary registriert oder der Name stimmt nicht überein.
Lösung:
# FALSCH - Fehlende Registrierung
REGISTERED_TOOLS = {
"get_weather": WEATHER_TOOL_SCHEMA
# calculate fehlt!
}
RICHTIG - Vollständige Registrierung
REGISTERED_TOOLS = {
"get_weather": WEATHER_TOOL_SCHEMA,
"calculate": CALCULATOR_TOOL_SCHEMA
}
Zusätzlich: Handler-Mapping prüfen
TOOL_HANDLERS = {
"get_weather": get_weather, # Dies muss vorhanden sein!
"calculate": calculate
}
Debugging-Tipp: Prüfen Sie die Tools-Liste
@app.get("/debug/tools")
async def debug_tools():
return {
"registered_tools": list(REGISTERED_TOOLS.keys()),
"handlers": list(TOOL_HANDLERS.keys()),
"missing_handlers": [t for t in REGISTERED_TOOLS if t not in TOOL_HANDLERS]
}
Fehler 2: "Erforderlicher Parameter 'x' fehlt"
Ursache: Bei einem Toolaufruf wurde ein erforderlicher Parameter nicht übergeben.
Lösung:
# Problem: Client sendet unvollständige Parameter
POST /tools/call mit {"tool_name": "get_weather", "parameters": {}}
Lösung 1: Serverseitig - Standardwerte verwenden
@app.post("/tools/call")
async def call_tool(request: ToolRequest):
tool_schema = REGISTERED_TOOLS[request.tool_name]
# Fülle fehlende Parameter mit Standardwerten auf
for param in tool_schema.parameters:
if param.name not in request.parameters:
if param.default is not None:
request.parameters[param.name] = param.default
elif param.required:
raise HTTPException(
status_code=400,
detail=f"Erforderlicher Parameter '{param.name}' fehlt. "
f"Bitte geben Sie einen Wert an."
)
Lösung 2: Client-seitig - Vollständige Parameter senden
response = await client.post(
"http://localhost:8000/tools/call",
json={
"tool_name": "get_weather",
"parameters": {
"city": "Berlin",
"country": "DE", # Optional, da Default definiert
"units": "celsius" # Optional, da Default definiert
}
}
)
Lösung 3: Document-Validierung vorher abrufen
@app.get("/tools/{tool_name}/schema")
async def get_tool_schema(tool_name: str):
if tool_name not in REGISTERED_TOOLS:
raise HTTPException(status_code=404, detail="Tool nicht gefunden")
schema = REGISTERED_TOOLS[tool_name]
return {
"required_parameters": [p.name for p in schema.parameters if p.required],
"optional_parameters": [
{"name": p.name, "default": p.default}
for p in schema.parameters if not p.required
]
}
Fehler 3: "API-Anfrage fehlgeschlagen: 401 Unauthorized"
Verwandte Ressourcen
Verwandte Artikel