Tutoriel : les racines en pratique
Sur cette page
Mise à jour du 2 novembre 2026 — roots. La spécification MCP 2026-07-28 déprécie les Roots. La recommandation officielle est de transmettre les répertoires ou fichiers par les paramètres des outils, par des URI de ressources ou par la configuration du serveur. Ce que vous apprenez ici reste utile pour maintenir des serveurs existants. SDK Python v2 : le code de ce tutoriel suit la branche 1.x ; en v2, la forme recommandée est le résolveur
ListRoots()reçu parAnnotated[ListRootsResult, Resolve(fonction)]. Source : Sampling and roots (SDK Python v2).
Ce tutoriel montre comment implémenter les roots dans une application de conversion vidéo. À la fin, votre client déclarera les dossiers autorisés au lancement, et vos outils y chercheront les fichiers sans jamais en sortir. Avant d’entrer dans les étapes, rappelez-vous le point établi dans la leçon théorique, car il commande tout le code qui suit : le SDK ne fait rien appliquer. Déclarer des roots ne protège aucun fichier — c’est un canal d’information entre le client et le serveur, et la vérification d’accès reste entièrement à votre charge, à l’étape 6. Un serveur qui oublie cette vérification fonctionne parfaitement… en accédant à tout.
Étape 1 : Définir les roots
Idéalement, c’est l’utilisateur qui dicte quels fichiers et dossiers le serveur MCP peut atteindre — et ce choix de conception n’est pas anodin. Des chemins codés en dur dans le serveur obligeraient chaque utilisateur à adapter le code à sa machine ; des chemins passés au lancement font de la permission un acte explicite, visible dans la ligne de commande. C’est le même modèle mental que le montage de volumes : on donne accès à ce qu’on nomme, rien d’autre.
Dans cet exemple, le programme accepte des arguments CLI qui sont interprétés comme les chemins auxquels l’utilisateur veut accorder l’accès :
# L'utilisateur spécifie les dossiers accessibles au démarrage
uv run main.py /Users/alice/Videos /Users/alice/Desktop
Ces chemins sont passés au MCPClient lors de l’initialisation.
Étape 2 : Créer des objets Root
Convertissez les chemins en objets Root du SDK MCP :
from mcp.types import Root
from pathlib import Path
def create_roots(paths: list[str]) -> list[Root]:
roots = []
for path in paths:
abs_path = Path(path).resolve()
roots.append(Root(
uri=f"file://{abs_path}",
name=abs_path.name
))
return roots
Étape 3 : Callback de roots
Le serveur peut demander la liste des roots via un callback. Définissez ce callback côté client :
async def roots_callback() -> list[Root]:
# Retourne la liste des roots que l'utilisateur a approuvées
return client_roots # défini au démarrage de l'application
Passez-le lors de la création de la session :
async with ClientSession(
read,
write,
roots_callback=roots_callback # ← ici
) as session:
await session.initialize()
Étape 4 : Utiliser les roots dans les outils
Côté serveur, vos outils peuvent récupérer les roots et les utiliser :
@mcp.tool()
async def list_accessible_files(
ctx: Context,
extension: str = Field(description="Extension de fichier (ex: mp4)")
) -> list[str]:
# Récupérer les roots disponibles
roots_result = await ctx.session.list_roots()
files = []
for root in roots_result.roots:
root_path = Path(root.uri.replace("file://", ""))
# Trouver tous les fichiers avec l'extension demandée
for f in root_path.rglob(f"*.{extension}"):
files.append(str(f))
return files
Étape 5 : Accéder aux roots
Pour accéder aux roots dans un outil, utilisez ctx.session.list_roots() :
@mcp.tool()
async def convert_video(
ctx: Context,
filename: str = Field(description="Nom du fichier vidéo à convertir")
) -> str:
roots_result = await ctx.session.list_roots()
# Chercher le fichier dans les roots
video_path = find_file_in_roots(filename, roots_result.roots)
if not video_path:
return f"Fichier '{filename}' introuvable dans les dossiers accessibles"
# Convertir...
return await do_convert(video_path)
Étape 6 : Autoriser l’accès
Voici l’étape qui fait la différence entre une application sûre et une application qui semble l’être. La vérification doit travailler sur des chemins résolus — c’est ce que fait le code ci-dessous — car un chemin relatif contenant .. peut désigner n’importe quel point du disque tout en paraissant anodin. Comparer des chaînes de caractères ne suffit pas ; on compare des chemins canoniques.
def find_file_in_roots(filename: str, roots) -> Path | None:
for root in roots:
root_path = Path(root.uri.replace("file://", ""))
# Chercher récursivement
matches = list(root_path.rglob(filename))
if matches:
return matches[0]
return None
def is_path_in_roots(path: Path, roots) -> bool:
for root in roots:
root_path = Path(root.uri.replace("file://", "")).resolve()
if path.resolve().is_relative_to(root_path):
return True
return False
Flux complet
Utilisateur: "Convertis biking.mp4 en MOV"
↓
Claude appelle list_accessible_files(extension="mp4")
↓
Serveur → list_roots() → roots_callback → ["/Users/alice/Videos", ...]
↓
Serveur parcourt les roots → trouve "/Users/alice/Videos/biking.mp4"
↓
Claude appelle convert_video(filename="biking.mp4")
↓
Serveur trouve le fichier dans les roots → convertit
↓
"biking.mov créé dans /Users/alice/Videos/"
À vous de jouer
- Lancez votre client avec deux dossiers en arguments et appelez
list_accessible_files(extension="md"): la liste doit se limiter à ces dossiers. - Appelez
convert_videoavec un nom de fichier situé hors des roots : le message doit dire « introuvable dans les dossiers accessibles », pas lever une exception brute. - Écrivez un test unitaire de
is_path_in_roots()avec un chemin contenant..et un lien symbolique.
Sources officielles : Roots walkthrough (Claude Academy) · Roots (spécification 2026-07-28) · Sampling and roots (SDK Python v2)
Points clés à retenir
- Les roots sont définies par l’utilisateur au démarrage de l’application, converties en objets
Root(uri="file://…")et servies par unroots_callbacksur la session. - Côté serveur,
ctx.session.list_roots()renvoie la liste ; le SDK ne les applique pas automatiquement. - Toujours vérifier
is_path_in_roots()sur des chemins résolus avant tout accès au système de fichiers. - Les roots rendent l’expérience fluide : les utilisateurs n’ont pas à taper des chemins complets.