Aller au contenu principal

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 Field sont lues par Claude : écrivez-les comme des instructions opérationnelles
  • Les exceptions Python deviennent des erreurs MCP propres — validez et levez explicites, comme toujours