Sampling MCP déprécié : sampling ou elicitation, et que faut-il utiliser désormais ?

Le sampling MCP a été déprécié le 2026-07-28 (SEP-2577), mais pas l’elicitation. Cet article compare les deux, explique le nouveau flux Multi Round-Trip Requests et indique quoi utiliser à la place du sampling, avec une checklist de migration datée pour les serveurs.

Sampling MCP déprécié : sampling ou elicitation, et que faut-il utiliser désormais ?
Cristian Da Conceicao
Fondateur de Picasso IA

Si votre serveur MCP appelle sampling/createMessage, la spécification vous demande désormais d’arrêter d’en dépendre. Le 2026-07-28, le Model Context Protocol a déprécié le Sampling (SEP-2577), ainsi que Roots et Logging. Elicitation, la fonctionnalité que beaucoup confondent avec lui, n’a pas été dépréciée. Elle a été reconstruite sur un nouveau mécanisme de livraison. Cet article sépare ce qui disparaît de ce qui reste, avec les dates, les noms de champs et les pistes de remplacement dont vous avez besoin avant votre prochaine version.

💡 En bref : le sampling est déprécié, et la spec recommande d’intégrer directement les API des fournisseurs de LLM. Elicitation est active et passe désormais par Multi Round-Trip Requests. Rien ne peut être supprimé avant une révision publiée à partir du 2027-07-28.

Un développeur devant un tableau blanc lumineux couvert de cases et de flèches dessinées à la main, en train de préparer une évolution du protocole MCP

Ce qui a changé le 2026-07-28

La révision du 2026-07-28 réécrit la manière dont clients et serveurs communiquent, et la dépréciation du sampling n’est qu’une entrée d’un long journal des modifications. Trois changements comptent ici :

  • Cœur sans état. La poignée de main initialize et l’en-tête Mcp-Session-Id disparaissent. Chaque requête transporte sa version du protocole et les capacités du client dans _meta.
  • Multi Round-Trip Requests (MRTR). Un serveur ne peut plus envoyer sampling/createMessage ou elicitation/create sur une connexion ouverte. Il renvoie un résultat intermédiaire, et le client relance l’appel d’origine avec la réponse jointe.
  • Un registre des dépréciations. Une nouvelle politique de cycle de vie définit les états Active, Deprecated et Removed, avec une fenêtre minimale de douze mois avant toute suppression.

Le premier changement explique le deuxième. Sans session persistante, il n’existe pas de canal où pousser une requête, donc les requêtes du serveur vers le client ont dû être repensées. Le sampling a été repensé et déprécié dans la même version. Elicitation a seulement été repensée.

Ce qui est déprécié en un coup d’œil

FonctionnalitéStatutRemplacementSuppression au plus tôt
SamplingDépréciéAppeler directement les API des fournisseurs de LLMPremière révision à partir du 2027-07-28
RootsDépréciéParamètres d’outil, URI de ressources ou configuration du serveurPremière révision à partir du 2027-07-28
LoggingDépréciéstderr pour stdio, OpenTelemetry pour l’observabilitéPremière révision à partir du 2027-07-28
Valeurs includeContext "thisServer" et "allServers"DépréciéesOmettre le champ ou utiliser "none"Au plus tard avec le Sampling
Dynamic Client RegistrationDépréciéClient ID Metadata DocumentsPremière révision à partir du 2027-07-28
ElicitationActiveReste, désormais livrée via MRTRNon planifiée

Ce que « déprécié » signifie ici

« Déprécié » ne veut pas dire « supprimé ». Pendant la fenêtre, le comportement sur le fil reste inchangé, la négociation des capacités fonctionne toujours et les implémentations existantes continuent de tourner. Les nouvelles implémentations ne devraient pas adopter la fonctionnalité, et les anciennes devraient migrer. La suppression relève d’une décision des Core Maintainers lors de la préparation de la version, elle peut donc arriver plus tard que la date au plus tôt. Le SEP demande aussi aux implémentations d’émettre un avertissement chaque fois qu’une capacité dépréciée est négociée, ce qui explique que les SDK aient commencé à afficher des notices de dépréciation. Considérez ces avertissements comme votre liste de tâches.

⚠️ Piège : la page de dépréciation du SDK Python indique que les anciens appels de style session, comme ctx.session.create_message(), fonctionnent encore sur les sessions négociées en 2025-11-25 ou avant. Sur une connexion en 2026-07-28, ils avertissent puis lèvent une erreur, car il n’existe plus de canal de retour pour envoyer quoi que ce soit.

Pourquoi le sampling a été déprécié

Le SEP-2577 donne trois raisons. Elles se cumulent.

Un cadenas en laiton patiné sur le loquet rouillé d’un vieux portail en chêne, avec des gouttes de pluie sur le métal

Trop lourd pour la plupart des clients

Le sampling permet à un serveur de demander au modèle du client de générer un contenu. Le faire correctement suppose une approbation humaine, une logique de sélection de modèle, une gestion de la sécurité et, depuis le SEP-1577, une boucle d’outils. C’est beaucoup à construire pour une fonctionnalité que le serveur n’appellera peut-être jamais. Le SEP souligne que peu de clients prennent en charge le sampling, alors qu’il figure dans la spec depuis la révision de novembre 2024.

Une large surface d’attaque

Le SEP considère le sampling comme le plus sensible des trois éléments dépréciés en matière de sécurité. Un serveur capable de faire exécuter ses prompts par le modèle du client ouvre la porte à l’injection de prompt et à l’exfiltration de données. Chaque client doit donc bien gérer les écrans de validation et les limites de débit.

Les API directes donnent plus de contrôle

Un serveur qui a besoin d’un modèle peut appeler lui-même un fournisseur. Il choisit le modèle, règle les paramètres et diffuse la sortie. L’argument historique du sampling était que les serveurs n’avaient pas besoin de leurs propres identifiants. Le compromis est désormais clair : vous détenez les identifiants, vous payez la facture et vous décidez de ce qui advient des données. Prévoyez des nouvelles tentatives, des limites de débit et un modèle de secours, car ces éléments relèvent désormais de votre exploitation et non de celle du client.

Elicitation n’a pas été dépréciée

Une femme attablée dans une cuisine ensoleillée, sur le point d’appuyer sur un bouton de confirmation d’une tablette affichant un formulaire simple

Vérifiez les preuves dans la spec elle-même. Le registre des fonctionnalités dépréciées liste Roots, Sampling, Logging, Dynamic Client Registration, les valeurs includeContext et HTTP+SSE. Elicitation n’y figure pas. La page d’elicitation ne comporte aucun avertissement de dépréciation, et le journal des modifications range elicitation sous MRTR. Certains articles regroupent toutes les fonctionnalités serveur-vers-client ensemble, alors vérifiez le registre avant de reprendre cette affirmation.

Elicitation a toutefois perdu deux détails : la notification de fin hors bande et le champ elicitationId en mode URL. Un serveur qui doit associer une nouvelle tentative à une requête antérieure encode désormais son propre identifiant dans requestState.

Mode formulaire

Le mode formulaire collecte des données structurées en bande, le client voit donc la réponse. Le requestedSchema est un objet plat ne contenant que des propriétés primitives :

  • des chaînes, avec les formats email, uri, date ou date-time
  • des nombres et des entiers
  • des booléens
  • des énumérations à choix unique et à choix multiples

Les objets imbriqués et les tableaux d’objets ne sont volontairement pas pris en charge. L’utilisateur répond par l’une des trois actions : accept avec du contenu, decline ou cancel. Un serveur doit gérer les trois, y compris en proposant des alternatives en cas de refus.

⚠️ Les serveurs ne doivent pas demander de mots de passe, de jetons d’API, de jetons d’accès ou de coordonnées de paiement en mode formulaire.

Mode URL

Le mode URL envoie l’utilisateur vers une page hors bande, et les données ne transitent jamais par le client. C’est la voie à privilégier pour les transmissions sensibles et l’OAuth tiers. Le client doit afficher l’URL complète, mettre le domaine en évidence, demander le consentement de l’utilisateur et ne jamais précharger la page. Une réponse accept signifie seulement que l’utilisateur a accepté de l’ouvrir. Elle ne signifie pas que l’interaction est terminée.

Mon avis sur les raisons de sa survie : le sampling permet à un serveur d’éviter un travail qu’il pourrait faire lui-même en appelant un fournisseur. Elicitation est la seule voie vers la personne. Les étapes de confirmation avant une suppression, une publication ou un paiement n’ont pas d’API de fournisseur de repli, donc retirer la fonctionnalité laisserait les serveurs dans le flou.

Sampling ou elicitation côte à côte

Une vue aérienne d’un sentier forestier qui se sépare en deux à une fourche, avec des poteaux de signalisation en bois vierges

QuestionSamplingElicitation
Qui répond ?Le modèle du client, un humain pouvant refuserL’utilisateur humain
Méthodesampling/createMessageelicitation/create
Statut au 2026-07-28DépréciéActif
Forme du résultatUn message du modèle, éventuellement avec des blocs tool_useaccept, decline ou cancel, plus du contenu
Livré viainputRequests dans un InputRequiredResultinputRequests dans un InputRequiredResult
Idéal pourLa génération de texte côté serveurLes décisions, les entrées manquantes, les transferts sensibles
RemplacementAPI du fournisseur, ou laisser le modèle hôte raisonnerAucun n’est nécessaire

On dit souvent que les deux sont interchangeables, ce qui est faux. Le sampling délègue la génération de texte. Elicitation obtient une réponse d’une personne. Remplacer un appel de sampling « résume cette page » par un formulaire serait une mauvaise solution, car l’utilisateur ne voulait jamais rédiger ce résumé. L’inverse est tout aussi faux : utiliser une supposition du modèle là où une décision humaine est nécessaire.

Prenons un serveur d’images comme cas pratique. Avant de consommer une génération, il a besoin d’un style et d’un feu vert. Ce sont deux choix humains, donc il utilise elicitation. Il veut aussi un prompt plus riche que ce qu’a tapé l’utilisateur. Réécrire est de la génération de texte, qui passait autrefois par un appel de sampling. Désormais, le serveur appelle lui-même un fournisseur, ou la description de l’outil demande au modèle hôte d’envoyer un prompt plus complet dès le départ.

Dans cette révision, les deux passent toujours par le même mécanisme, car chacun apparaît sous forme d’entrée dans inputRequests. La différence tient à qui lit l’entrée et à ce que la spec dit de sa durée de vie.

Comment fonctionne le nouvel aller-retour

Deux mains se passant une enveloppe crème scellée de cire rouge sur un comptoir en noyer

Le flux comporte quatre étapes. Le client appelle tools/call. Le serveur renvoie un InputRequiredResult avec resultType: "input_required". Le client recueille la réponse et relance l’appel d’origine avec inputResponses jointe. Le serveur produit alors le résultat réel. Comme la nouvelle tentative contient tout ce dont le serveur a besoin, n’importe quelle instance derrière un répartiteur de charge peut la traiter.

Voici la réponse intermédiaire du serveur pour un outil d’image qui a besoin d’un format :

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "resultType": "input_required",
    "inputRequests": {
      "aspect": {
        "method": "elicitation/create",
        "params": {
          "mode": "form",
          "message": "Which aspect ratio should the image use?",
          "requestedSchema": {
            "type": "object",
            "properties": {
              "ratio": { "type": "string", "enum": ["16:9", "1:1", "9:16"] }
            },
            "required": ["ratio"]
          }
        }
      }
    },
    "requestState": "<signed blob>"
  }
}

Et la nouvelle tentative du client, avec la réponse et l’état renvoyé :

{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/call",
  "params": {
    "name": "generate_image",
    "arguments": { "prompt": "A foggy harbor at dawn" },
    "inputResponses": {
      "aspect": { "action": "accept", "content": { "ratio": "16:9" } }
    },
    "requestState": "<signed blob>"
  }
}

Les champs _meta obligatoires (version du protocole, informations sur le client, capacités du client) sont omis ici par souci de concision. Notez que le id JSON-RPC change entre la requête d’origine et la nouvelle tentative, car ce sont des requêtes indépendantes.

Règles pour les clients

  • Renvoyez requestState à l’identique, exactement. Ne l’inspectez, ne l’analysez et ne le modifiez jamais.
  • Si le résultat ne contient pas requestState, n’en envoyez pas dans la nouvelle tentative.
  • Utilisez un nouveau id JSON-RPC pour la nouvelle tentative.
  • S’il n’y a pas de inputRequests, le client peut relancer immédiatement.
  • Les champs ne concernent que la nouvelle tentative de cette seule requête, jamais les appels parallèles.

Règles pour les serveurs

Traitez requestState comme une entrée contrôlée par un attaquant, car elle transite par le client. Lorsqu’elle influence l’autorisation, l’accès aux ressources ou la logique métier, protégez son intégrité avec un HMAC ou un AEAD et rejetez tout ce qui échoue à la vérification. Placez l’utilisateur authentifié, une courte expiration et un identifiant de la requête d’origine dans la charge protégée. Cela limite le rejeu, sans rendre un état à usage unique : appliquez donc les rachats à usage unique côté serveur.

Deux contraintes s’ajoutent. Chaque InputRequiredResult exige au moins l’un de inputRequests ou requestState, et un serveur ne doit pas envoyer un type de requête que le client n’a jamais déclaré prendre en charge. MRTR ne fonctionne que sur prompts/get, resources/read et tools/call.

Ce qu’il faut utiliser à la place du sampling

Une main branchant un câble Ethernet bleu directement dans un port de routeur, dans un local technique bien rangé

La réponse de la spec tient en une ligne : intégrer directement les API des fournisseurs de LLM. En pratique, le bon remplacement dépend de la raison pour laquelle vous utilisiez le sampling.

Ce que le serveur voulaitÀ utiliser désormais
Réécrire, résumer ou classer du texteUn appel à l’API d’un fournisseur, ou renvoyer les données brutes au modèle hôte
Demander à l’utilisateur de choisir ou de confirmerElicitation en mode formulaire
Transmettre un secret ou exécuter un OAuthElicitation en mode URL
Lire les chemins de l’espace de travail (Roots)Arguments d’outil ou URI de ressources
Envoyer des lignes de journal au clientstderr ou OpenTelemetry

Appeler directement une API de fournisseur

Quand vous avez besoin d’une vraie génération de texte, appelez le fournisseur depuis le serveur. Comparez les candidats avant d’en intégrer un à votre code. Sur PicassoIA, vous pouvez tester Claude Sonnet 5, GPT 5.6 Terra et Gemini 3.5 Flash côte à côte, et voir lequel traite le mieux vos prompts à la vitesse dont vous avez besoin. Stockez ensuite l’identifiant comme un secret serveur classique, définissez un délai d’attente et journalisez la consommation de tokens.

Laisser le modèle hôte raisonner

Beaucoup d’appels de sampling n’étaient jamais nécessaires. Le résultat d’un outil alimente déjà le modèle qui a appelé l’outil. Renvoyez la page brute, une description claire et une structure raisonnable, et le modèle hôte fait le résumé, sans aller-retour supplémentaire ni identifiants en plus. Un serveur de documentation qui utilisait le sampling pour résumer un long journal des modifications peut renvoyer ce journal par sections et laisser le modèle appelant choisir ce qui compte. C’est ma propre recommandation, pas un texte de la spec, mais cela supprime le plus grand nombre d’appels.

Demander à l’humain de décider

Lorsque l’élément manquant est une décision, passez à elicitation. Dans le SDK Python, un article montre le schéma avec un choix affirmatif :

CONFIRM = ["cancel", "confirm"]
result = await ctx.elicit("Delete 42 drafts?", response_type=CONFIRM)

Le même article prévient que passer response_type=None envoie un schéma vide, si bien qu’une acceptation automatique ressemble sur le fil à une approbation humaine. Proposez à l’utilisateur une vraie valeur à choisir. Vérifiez la signature actuelle de votre SDK avant de la copier.

💡 Règle empirique : si une personne doit décider, utilisez elicitation. Si un modèle doit rédiger, appelez un fournisseur ou laissez le modèle hôte le faire.

Une checklist de migration pour les serveurs

Un technicien tenant un presse-papiers avec une checklist dans une allée de salle serveur

  1. Repérez chaque appel. Recherchez sampling/createMessage, create_message et toute vérification de capacité de sampling.
  2. Triez chaque appel selon son objectif. La génération de texte passe à une API de fournisseur ou au modèle hôte. Les décisions vont à elicitation. Le contexte passe par les arguments d’outil ou les URI de ressources.
  3. Supprimez les valeurs includeContext. Retirez "thisServer" et "allServers". Omettez le champ ou utilisez "none".
  4. Remplacez Roots et Logging. Transmettez les chemins en paramètres d’outil. Journalisez vers stderr sur stdio et utilisez OpenTelemetry ailleurs.
  5. Renvoyez InputRequiredResult. Remplacez les requêtes initiées par le serveur par des résultats intermédiaires et un requestState que vous signez.
  6. Testez sur une connexion en 2026-07-28. Surveillez les avertissements de dépréciation du SDK et les anciens appels de session qui lèvent une erreur.
  7. Conservez un chemin de compatibilité. Les clients en 2025-11-25 ou avant utilisent encore l’ancien comportement pendant la fenêtre.

Calendrier à suivre

DateCe qui se passe
2024-11Le sampling entre dans la spec
2025-11-25Valeurs includeContext soft-dépréciées, elicitation en mode URL introduite
2026-07-28Sampling, Roots et Logging dépréciés, MRTR introduit
2027-07-28Première révision dans laquelle le Sampling peut être supprimé

Trois erreurs à éviter

  1. Confondre déprécié et supprimé. Les anciennes sessions fonctionnent encore, mais les connexions en 2026-07-28 rejettent les anciens appels de style session. Sachez quelles versions vous servez.
  2. Utiliser un formulaire pour un texte qu’un modèle devrait rédiger. Elicitation demande une saisie à une personne. Ce n’est pas un moyen moins coûteux de rédiger des textes.
  3. Négliger l’intégrité de requestState. Un état non signé invite à altérer la logique de votre serveur.

Règles de contrôle qui restent

Deux ingénieurs relisant des pages imprimées avec un surligneur sur une longue table en érable

La supervision humaine est l’élément du sampling qui subsiste. Les clients Elicitation doivent indiquer quel serveur fait la demande, proposer des options claires pour refuser et annuler, et laisser les utilisateurs relire leurs réponses au formulaire avant l’envoi. En mode URL, ils doivent afficher le domaine cible et obtenir le consentement de l’utilisateur avant d’ouvrir quoi que ce soit. Les serveurs doivent lier chaque elicitation à l’identité de l’utilisateur et vérifier qui ouvre une URL, ce qui bloque le schéma de phishing dans lequel un attaquant envoie son propre lien à une victime.

Créez vos propres images avec Picasso IA

Le bureau d’un créateur vu d’en haut, avec des photos imprimées de lacs de montagne et une tablette

Le travail sur le protocole devient plus simple quand on voit ce que l’on construit. Si vous écrivez un serveur MCP qui génère des images, le schéma d’elicitation décrit plus haut lui convient bien : demandez un format ou un style avant de consommer une génération.

Sur PicassoIA, vous pouvez essayer les modèles qui sous-tendent ce type d’outil : PicassoIA Image pour le texte vers image, PicassoIA Image Editor Pro pour les retouches, et GPT Image 2 si vous voulez un autre rendu. PicassoIA propose aussi une API pour développeurs de style Replicate à https://api.picassoia.com/v1 et des connexions MCP, afin que les mêmes générateurs puissent alimenter vos propres outils. Vérifiez les limites actuelles sur sa page API avant de planifier en fonction.

Ouvrez Picasso IA, rédigez un seul prompt et générez votre première image. Relancez ensuite avec un autre format et comparez les deux. Cette petite boucle reprend le schéma demande, réponse, nouvelle tentative décrit dans cet article, avec des pixels à la fin.

Partager cet article

Choisissez votre langue