Aller au contenu principal

Le sampling

Le sampling permet à un serveur MCP d’accéder à un modèle de langage comme Claude via le client MCP connecté. Au lieu que le serveur appelle directement Claude, il demande au client de faire l’appel en son nom. Cela transfère la responsabilité et le coût de la génération de texte du serveur vers le client.

Le problème que résout le sampling

Imaginez que vous avez un serveur MCP avec un outil de recherche qui récupère des informations depuis Wikipedia. Après avoir rassemblé toutes ces données, vous devez les résumer en un rapport cohérent. Vous avez deux options :

Option 1 : Donner au serveur MCP un accès direct à Claude. Le serveur aurait besoin de sa propre clé API, de gérer l’authentification, les coûts, et d’implémenter tout le code d’intégration Claude. Ça fonctionne mais ajoute une complexité significative.

Option 2 : Utiliser le sampling. Le serveur génère un prompt et demande au client : “Peux-tu appeler Claude pour moi ?” Le client, qui a déjà une connexion à Claude, fait l’appel et retourne les résultats.

Comment fonctionne le sampling

Le flux est simple :

1. Le serveur complète son travail (ex: récupère des articles Wikipedia)
2. Le serveur crée un prompt demandant la génération de texte
3. Le serveur envoie une requête de sampling au client
4. Le client appelle Claude avec le prompt fourni
5. Le client retourne le texte généré au serveur
6. Le serveur utilise le texte généré dans sa réponse

Implémentation

Côté serveur

Dans votre fonction d’outil, utilisez create_message pour demander la génération de texte :

@mcp.tool()
async def summarize(text_to_summarize: str, ctx: Context):
    prompt = f"""
    Veuillez résumer le texte suivant :
    {text_to_summarize}
    """
    
    result = await ctx.session.create_message(
        messages=[
            SamplingMessage(
                role="user",
                content=TextContent(
                    type="text",
                    text=prompt
                )
            )
        ],
        max_tokens=4000,
        system_prompt="You are a helpful research assistant",
    )
    
    if result.content.type == "text":
        return result.content.text
    else:
        raise ValueError("Sampling failed")

Côté client

Créez un callback de sampling qui gère les requêtes du serveur :

async def sampling_callback(
    context: RequestContext, params: CreateMessageRequestParams
):
    # Appeler Claude via le SDK Anthropic
    text = await chat(params.messages)
    
    return CreateMessageResult(
        role="assistant",
        model=model,
        content=TextContent(type="text", text=text),
    )

Passez ensuite ce callback lors de l’initialisation de votre session client :

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

Avantages du sampling

AvantageExplication
Réduit la complexité serveurLe serveur n’a pas besoin d’intégrer directement les LLM
Transfère les coûtsC’est le client qui paie l’utilisation des tokens
Pas de clés APILe serveur n’a pas besoin de credentials pour Claude
Idéal pour les serveurs publicsÉvite que les utilisateurs publics génèrent des coûts illimités

Quand utiliser le sampling

Le sampling est plus précieux quand vous construisez des serveurs MCP accessibles publiquement. Vous ne voulez pas que des utilisateurs aléatoires génèrent du texte illimité à vos frais. En utilisant le sampling, chaque client paie pour sa propre utilisation de l’IA tout en bénéficiant des fonctionnalités de votre serveur.

La technique déplace essentiellement la complexité de l’intégration IA de votre serveur vers le client, qui a souvent déjà les connexions et credentials nécessaires en place.