Tutoriel : les racines en pratique
Ce tutoriel montre comment implémenter les roots dans une application de conversion vidéo.
Étape 1 : Définir les roots
Idéalement, c’est l’utilisateur qui dicte quels fichiers et dossiers le serveur MCP peut accéder.
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(
extension: str = Field(description="Extension de fichier (ex: mp4)"),
ctx: Context
) -> 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(
filename: str = Field(description="Nom du fichier vidéo à convertir"),
ctx: Context
) -> 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
Implémentez la vérification de sécurité pour tout accès aux fichiers :
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/"
Points clés
- Les roots sont définies par l’utilisateur lors du démarrage de l’application
- Le SDK ne les applique pas automatiquement — vous devez vérifier vous-même
- Toujours vérifier
is_path_in_roots()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