ServicesÀ proposNotesContact Me contacter →
EN FR
Note

Patterns de conception d'outils MCP

Comment concevoir des outils MCP qui fonctionnent bien avec l'IA — docstrings comme descriptions, modèles Pydantic pour les sorties structurées, et validation des entrées avec des schémas.

Planté
mcpdata engineering

Les outils sont la façon dont les serveurs MCP exposent des fonctionnalités aux assistants IA. Un bon outil a une description claire, des paramètres typés et une sortie prévisible. Un mauvais outil perturbe l’IA sur le moment de l’utiliser, accepte des entrées incorrectes et retourne des blobs non structurés. La différence tient à la conception de l’interface.

Les docstrings comme descriptions

FastMCP extrait les descriptions des outils directement des docstrings Python. C’est le texte que l’IA voit pour décider quel outil appeler :

@mcp.tool()
def get_table_schema(table_name: str) -> str:
"""Get the schema definition for a database table.
Returns column names, data types, and constraints for the specified table.
Useful for understanding table structure before writing queries.
Args:
table_name: Fully qualified table name (e.g., 'analytics.orders')
Returns:
Schema definition as formatted text
"""
# Implementation here
return f"Schema for {table_name}: id INT PRIMARY KEY, name VARCHAR(255)..."

Rédigez des descriptions qui aident le modèle à comprendre quand et pourquoi utiliser l’outil, pas seulement ce qu’il fait. « Get the schema definition for a database table » dit à l’IA ce que l’outil fait. « Useful for understanding table structure before writing queries » lui dit quand l’utiliser. Les deux comptent.

Incluez des exemples dans les descriptions de paramètres — 'analytics.orders' indique à l’IA le format attendu bien plus efficacement qu’une longue spécification de format. L’IA généralise à partir des exemples.

Modèles Pydantic pour les sorties structurées

Pour les valeurs de retour complexes, utilisez des modèles Pydantic pour garantir une structure cohérente :

from pydantic import BaseModel, Field
class ValidationResult(BaseModel):
"""Result of a data quality validation check."""
table_name: str
row_count: int = Field(description="Total rows examined")
null_count: int = Field(description="Number of null values found")
duplicate_count: int = Field(description="Number of duplicate rows")
is_valid: bool = Field(description="Whether the table passed validation")
@mcp.tool()
def run_data_quality_check(table_name: str) -> ValidationResult:
"""Run comprehensive data quality checks on a table.
Validates completeness, uniqueness, and data integrity.
Args:
table_name: The table to validate
Returns:
Detailed validation results
"""
# Run actual checks against your database
return ValidationResult(
table_name=table_name,
row_count=10000,
null_count=5,
duplicate_count=0,
is_valid=True
)

FastMCP sérialise automatiquement les modèles Pydantic en JSON, et les descriptions Field enrichissent le schéma de sortie. L’IA sait qu’elle obtiendra en retour un objet structuré avec des champs spécifiques, ce qui la rend fiable pour extraire des valeurs individuelles et raisonner à leur sujet.

L’alternative — retourner une chaîne formatée — fonctionne pour les outils simples mais échoue quand l’IA doit comparer des valeurs entre plusieurs appels d’outils ou alimenter les résultats dans un autre outil. La sortie structurée rend la composition des outils possible.

Validation des entrées avec des schémas

Les annotations de type définissent le schéma d’entrée. Utilisez le système de types de Python et Pydantic pour la validation :

from enum import Enum
from typing import Optional
from pydantic import BaseModel, Field
class Environment(str, Enum):
PRODUCTION = "production"
STAGING = "staging"
DEVELOPMENT = "development"
class QueryParams(BaseModel):
"""Parameters for database queries."""
limit: int = Field(default=100, ge=1, le=10000, description="Maximum rows to return")
timeout_seconds: int = Field(default=30, ge=1, le=300, description="Query timeout")
@mcp.tool()
def run_query(
query: str,
environment: Environment = Environment.PRODUCTION,
params: Optional[QueryParams] = None
) -> str:
"""Execute a read-only SQL query.
Args:
query: SQL SELECT statement to execute
environment: Target environment
params: Optional query parameters
Returns:
Query results as JSON
"""
effective_params = params or QueryParams()
# Execute with validated parameters
return f"Results from {environment.value} (limit: {effective_params.limit})"

Trois patterns à noter ici :

Les enums contraignent les choix. L’enum Environment signifie que l’IA ne peut passer que « production », « staging » ou « development ». Dans les interfaces d’outils, les enums s’affichent comme des listes déroulantes. Cela empêche l’IA d’inventer des noms d’environnement.

Les contraintes Pydantic Field empêchent les entrées invalides. ge=1, le=10000 sur le champ limit signifie que la validation rejette une limite de 0 ou 50000 avant que votre code ne s’exécute. Le message d’erreur est automatique et clair.

Les valeurs par défaut encodent le comportement sûr. limit=100 signifie que l’IA n’a pas besoin de spécifier une limite pour les requêtes occasionnelles. timeout_seconds=30 signifie qu’une requête bloquée ne bloquera pas indéfiniment. Les valeurs par défaut devraient être le choix sûr, l’IA optant explicitement pour des paramètres plus agressifs lorsque la demande de l’utilisateur le justifie.

Principes de conception

Principes qui affectent la fiabilité des outils en pratique :

Un outil, une action. Un outil qui recherche des tables et effectue également des contrôles de qualité est plus difficile à raisonner pour l’IA que deux outils séparés. Divisez les opérations composites en outils individuels avec des noms clairs.

Échouez avec des erreurs utiles. Quand une table n’existe pas ou qu’une requête échoue, retournez un message d’erreur structuré, pas une trace d’exception. L’IA doit comprendre ce qui s’est mal passé pour décider de son prochain pas — réessayer avec des paramètres différents, demander des éclaircissements à l’utilisateur, ou essayer une approche différente.

Nommez pour l’intention, pas l’implémentation. search_tables est mieux que query_catalog_api. get_pipeline_status est mieux que call_airflow_rest_endpoint. L’IA associe l’intention de l’utilisateur aux noms des outils ; les détails d’implémentation dans le nom ajoutent du bruit.

Testez avec l’IA, pas seulement en isolation. Un outil qui fonctionne dans les tests unitaires peut confondre l’IA en raison d’une description ambiguë ou d’une structure de paramètres trop complexe. La note MCP Server Testing and Debugging couvre le workflow de test complet ; testez avec un vrai client IA le plus tôt possible.