Aller au contenu principal

Tutoriel : le sampling en pratique

Ce tutoriel vous guide pas à pas dans l’implémentation du sampling, en expliquant chaque étape du code.

Étape 1 : Initier le sampling côté serveur

Sur le serveur, pendant un appel d’outil, vous lancez le sampling en appelant la méthode create_message() via le contexte. Vous lui passez les messages que vous souhaitez envoyer au modèle de langage.

# Dans votre fonction d'outil
@mcp.tool()
async def research_and_summarize(topic: str, ctx: Context):
    # 1. Faire la recherche
    articles = await fetch_wikipedia(topic)
    
    # 2. Initier le sampling pour résumer
    result = await ctx.session.create_message(
        messages=[
            SamplingMessage(
                role="user",
                content=TextContent(
                    type="text",
                    text=f"Résume ces articles en un rapport concis : {articles}"
                )
            )
        ],
        max_tokens=2000,
        system_prompt="Tu es un assistant de recherche expert.",
    )
    
    return result.content.text

Étape 2 : Callbacks de sampling

Le callback de sampling est la fonction côté client qui sera appelée quand le serveur demande une génération de texte. Elle reçoit :

  • context : le contexte de la requête
  • params : les paramètres incluant les messages à envoyer au LLM
async def sampling_callback(
    context: RequestContext, 
    params: CreateMessageRequestParams
):
    # Votre logique pour appeler Claude
    text = await appeler_claude(params.messages, params.system)
    
    return CreateMessageResult(
        role="assistant",
        model="claude-opus-4-5",
        content=TextContent(type="text", text=text),
    )

Étape 3 : Formats de messages

Les messages envoyés via sampling suivent le même format que l’API Claude standard :

  • role : "user" ou "assistant"
  • content : un objet TextContent avec type="text" et le texte du message

Vous pouvez aussi inclure des messages multi-tours pour fournir du contexte :

messages=[
    SamplingMessage(role="user", content=TextContent(type="text", text="Question initiale")),
    SamplingMessage(role="assistant", content=TextContent(type="text", text="Réponse précédente")),
    SamplingMessage(role="user", content=TextContent(type="text", text="Question de suivi"))
]

Étape 4 : Retourner le texte généré

Le callback doit retourner un CreateMessageResult. Assurez-vous de toujours vérifier que le type de contenu est bien "text" :

if result.content.type == "text":
    return result.content.text
else:
    raise ValueError("Type de contenu inattendu dans la réponse de sampling")

Étape 5 : Connecter le callback

Passez le callback lors de la création de la session client :

async with ClientSession(
    read,
    write,
    sampling_callback=sampling_callback  # ← ici
) as session:
    await session.initialize()

Étape 6 : Obtenir le résultat

Une fois tout connecté, le flux complet fonctionne automatiquement :

Utilisateur → "Recherche et résume Python"

Outil research_and_summarize appelé

fetch_wikipedia("Python") → données brutes

ctx.session.create_message() → requête sampling au client

sampling_callback → appel Claude → texte résumé

Résultat retourné au serveur → retourné à l'utilisateur

Points clés à retenir

  • Le callback est défini côté client, pas côté serveur
  • Le serveur ne connaît pas quelle implémentation Claude le client utilise
  • Plusieurs clients peuvent utiliser le même serveur MCP avec des implémentations de sampling différentes
  • C’est idéal pour les serveurs publics où vous ne voulez pas gérer les coûts des tokens