Définir des outils avec MCP
Mis à jour le 30 juillet 2026
Place au code : construisons le serveur MCP de notre projet de documents. Si vous gardez en mémoire le travail qu’exigeait un outil dans la section tool use — écrire la fonction, puis rédiger à la main son schéma JSON, puis les garder synchronisés —, la bonne nouvelle est immédiate : le SDK Python MCP simplifie énormément la création d’outils grâce aux décorateurs. La fonction et sa déclaration fusionnent en un seul objet.
Initialiser le serveur
Deux lignes créent le serveur :
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("DocumentMCP", log_level="ERROR")
FastMCP est l’interface haut niveau du SDK — c’est elle qui fournira les décorateurs et gérera tout le protocole. Le nom « DocumentMCP » identifie le serveur auprès des clients ; le niveau de log réduit garde la sortie standard propre, un détail qui compte quand le transport passe justement par l’entrée/sortie standard.
Définir un outil avec décorateur
Voici le pattern sur un exemple minimal :
@mcp.tool(
name="add_ints",
description="Additionne deux entiers",
)
def tool_fn(
a=Field(description="Premier nombre"),
b=Field(description="Second nombre"),
) -> int:
return a + b
Comparez mentalement avec la version manuelle de la section outils : le dictionnaire input_schema, les types, les champs requis — tout a disparu du code visible. MCP génère automatiquement le schéma JSON complet en coulisses, à partir de la signature de la fonction : les paramètres deviennent les propriétés, les annotations deviennent les types, les Field(description=...) deviennent les descriptions que Claude lira. Un outil est redevenu ce qu’il aurait toujours dû être : une fonction documentée.
Outil de lecture de documents
Appliquons le pattern au premier vrai outil du projet :
@mcp.tool(
name="read_doc_contents",
description="Lit le contenu d'un document et le retourne sous forme de chaîne."
)
def read_document(
doc_id: str = Field(description="Identifiant du document a lire")
):
if doc_id not in docs:
raise ValueError(f"Document {doc_id} non trouve")
return docs[doc_id]
Les réflexes des fonctions d’outils s’appliquent inchangés : validation de l’entrée en tête, et une erreur explicite — le ValueError avec l’identifiant fautif — plutôt qu’un plantage brut. Cette exception ne tuera pas le serveur : le SDK la convertira en erreur MCP correctement formée, que le client transmettra à Claude pour qu’il se corrige.
Outil d’édition de documents
Le second outil introduit l’écriture, avec trois paramètres :
@mcp.tool(
name="edit_document",
description="Édite un document en remplaçant une chaîne par une autre."
)
def edit_document(
doc_id: str = Field(description="Identifiant du document a éditer"),
old_str: str = Field(description="Texte a remplacer. Doit correspondre exactement."),
new_str: str = Field(description="Nouveau texte.")
):
if doc_id not in docs:
raise ValueError(f"Document {doc_id} non trouve")
docs[doc_id] = docs[doc_id].replace(old_str, new_str)
Vous reconnaissez le mécanisme d’édition par remplacement de chaîne exacte — le même que celui de l’outil text editor d’Anthropic, et de la plupart des agents d’édition. Remarquez le soin des descriptions de Field : « Doit correspondre exactement » n’est pas décoratif, c’est une instruction opérationnelle pour Claude, qui saura qu’il doit fournir le texte à l’identique, espaces compris. Les descriptions restent votre principal levier de fiabilité, SDK ou pas.
Avantages de l’approche SDK
Tout ce que vous écririez à la main disparaît au profit de ce que Python sait déjà faire. Le schéma JSON n’existe plus en tant qu’artefact séparé : il est généré depuis vos annotations de types, qui assurent au passage la validation automatique des paramètres — un int reçu là où un str était attendu échoue proprement, sans code de vérification à écrire. Les descriptions passées dans les Field remplissent le rôle des descriptions de schéma : c’est ce texte que Claude lit pour comprendre quand et comment utiliser l’outil, au même endroit que le code qu’il documente. La gestion d’erreurs suit l’idiome du langage — une exception Python levée dans l’outil devient une erreur MCP correctement formée — et les décorateurs enregistrent l’outil auprès du serveur au moment de sa définition. Résultat : un outil complet tient en une fonction annotée, et le schéma ne peut jamais diverger de l’implémentation puisqu’il en est dérivé.
Points clés à retenir
FastMCP+ décorateur@mcp.tool: la fonction et sa déclaration fusionnent- Le schéma JSON est généré depuis la signature — il ne peut pas diverger du code
- Types annotés = validation automatique des paramètres, sans code de vérification
- Les descriptions
Fieldsont lues par Claude : écrivez-les comme des instructions opérationnelles - Les exceptions Python deviennent des erreurs MCP propres — validez et levez explicites, comme toujours