MCP Tasks vs tool calls synchrones : exécuter des opérations longues
Un choix pratique entre MCP tools/call standard et MCP Tasks expérimentales pour les opérations longues : capability negotiation, états, polling, annulation, sécurité, tests et rollout.
Sommaire de l’article
- 01Réponse courte : utilisez les Tasks pour une exécution durable, pas pour chaque tool lent
- 02Deux niveaux de negotiation empêchent une compatibilité imaginaire
- 03La state machine du Task ne remplace pas l’état de l’opération métier
- 04Polling, progress et backoff ont besoin d’un budget borné
- 05Authorization lie le Task au contexte, pas seulement à un ID difficile à deviner
- 06La matrice de tests valide transitions, répétitions et résultats incertains
- 07Rollout : adapter expérimental, canary étroit et fallback vérifié
Réponse courte : utilisez les Tasks pour une exécution durable, pas pour chaque tool lent
Conservez un tools/call normal lorsque l’opération tient dans un timeout de requête borné, que le résultat peut être renvoyé immédiatement et qu’une perte de connexion ne nécessite pas de récupération séparée. Envisagez un MCP Task lorsque le travail est long, doit survivre à une requête unique ou nécessite du polling, un résultat différé, une annulation ou un état intermédiaire input_required. Les Tasks font partie de la spécification MCP 2025-11-25 mais sont marquées experimental ; elles doivent donc être isolées derrière un capability gate plutôt que traitées comme une baseline universelle.
Un Task n’est ni une queue, ni un workflow engine, ni une garantie exactly-once. Il standardise l’enveloppe visible par le client autour d’une opération longue : le receiver crée un task ID et publie l’état, tandis que le requestor vérifie le status et récupère le résultat. L’opération métier a toujours besoin de son propre operation ID, de l’autorisation, de l’idempotence, d’un état durable et d’une reconciliation avec le system of record. Si le processus peut se terminer en sécurité dans un appel court, un Task n’ajoute que des états et du cleanup.
- Lecture courte ou compute borné → tools/call normal.
- Travail long avec résultat différé → candidat à un Task.
- Décision utilisateur supplémentaire nécessaire → Task avec input_required.
- Action à conséquences → ledger d’opération métier indépendant du wrapper de protocole.
- Le peer n’a pas annoncé la capability → ne pas envoyer de task augmentation.
Deux niveaux de negotiation empêchent une compatibilité imaginaire
La prise en charge des Tasks est négociée pendant initialization. Pour un tool call augmenté par un Task, le server annonce tasks.requests.tools.call ; sans cette capability, le client ne doit pas exécuter le tool sous forme de Task. Ensuite, le tool concerné précise le contrat via execution.taskSupport : forbidden est la valeur par défaut, optional autorise les deux modes et required impose un Task. Vérifiez les deux niveaux à chaque session et ne mettez pas en cache la conclusion uniquement d’après le nom du server ou la version du SDK.
Construisez un capability manifest avec la version du protocole, la version d’implémentation du server, les preuves de session, les opérations Task list/get/result/cancel et le mode au niveau du tool. Le router compare ce manifest aux besoins du workflow avant le premier appel. Si une capability nécessaire manque, le fallback doit être explicite : chemin synchrone court, job API séparé, human handoff ou refus contrôlé. Transformer silencieusement un Task required en longue requête HTTP crée d’autres sémantiques de timeout et de recovery.
La state machine du Task ne remplace pas l’état de l’opération métier
Un MCP Task commence en working et peut passer à input_required, completed, failed ou cancelled selon les transitions autorisées par la spécification. Le receiver génère taskId ; TTL détermine quand l’enregistrement peut être supprimé ; pollInterval suggère la fréquence de vérification. Le requestor récupère le résultat réel via tasks/result uniquement après une terminaison terminale. Conservez le dernier status observé, lastUpdatedAt, correlation ID et le prochain poll autorisé afin qu’un reconnect reprenne l’observation au lieu de relancer le travail.
Maintenez en parallèle une DomainOperation avec idempotency key stable, actor, tenant, object version, intended effect, downstream receipt et outcome autoritatif. completed sur le Task signifie que le protocol result est disponible ; cela ne prouve pas qu’un système externe a accepté un paiement, une publication ou un deployment. cancelled ne garantit pas non plus la compensation d’un effet déjà exécuté. L’UI doit distinguer transport/task state et domain outcome confirmé ; un unknown outcome doit passer par reconciliation avant tout retry.
- Task state → ce que le receiver rapporte sur l’exécution de la requête.
- Domain state → ce que le system of record confirme sur l’effet métier.
- Cancellation → demande d’arrêter le travail restant, pas rollback automatique.
- TTL expiry → cycle de vie du registre de protocole, pas permission d’oublier les preuves d’audit.
Polling, progress et backoff ont besoin d’un budget borné
Le client respecte pollInterval, ajoute du jitter, limite la durée totale et arrête le polling après un état terminal. Interroger plus souvent n’accélère pas le job ; cela augmente seulement la charge et le risque de rate limit. Les progress notifications peuvent améliorer l’UX, mais elles ne doivent pas repousser indéfiniment la deadline absolue. Après une perte réseau, le client reprend l’observation du taskId connu au lieu de répéter le tool call initial.
Définissez des budgets séparés pour create, les lectures de status, result retrieval et business reconciliation. Ne conservez que le response envelope minimal : status, version, timestamps, message nettoyé et evidence handles. Un échec de tasks/get peut signifier expiry, authorization failure ou server loss ; il ne transforme pas un unknown domain outcome en failed. Pour de gros artifacts, retournez des metadata bornées et un handle autorisé plutôt qu’un payload illimité dans le contexte du modèle.
La matrice de tests valide transitions, répétitions et résultats incertains
La contract suite couvre initialize, capability absente, chaque valeur taskSupport, create, get, list, result, cancel, transition invalide, TTL expiré et pagination. La fault injection coupe le transport avant et après CreateTaskResult, entre completed et result retrieval, pendant input_required et après une demande de cancel. Les assertions vérifient que l’appel initial n’est pas répété automatiquement, que le status ne change que par des transitions autorisées et qu’une duplicate delivery ne crée pas un second domain effect.
Les security cases tentent de lire ou cancel un Task d’un autre tenant, deviner un ID, récupérer result après perte de scope, falsifier les related-task metadata et injecter des prompts dans status ou result. Les load tests mesurent les jobs concurrents bornés, la polling amplification, le cleanup et la downstream backpressure. L’évaluation model-in-the-loop n’est nécessaire que lorsque le modèle décide d’invoquer le tool ou interprète son result ; protocol conformance et authorization restent des gates déterministes.
- Hard gate → accès cross-tenant, transition invalide, effet dupliqué ou fuite de secret.
- Recovery gate → reconnect reprend le Task connu sans second start.
- Cancellation gate → terminal semantics et domain reconciliation sont vérifiées séparément.
- Compatibility gate → le fallback fonctionne avec un peer sans capability Tasks.
Rollout : adapter expérimental, canary étroit et fallback vérifié
Commencez par un workflow read-only ou réversible où un Task apporte une valeur opérationnelle mesurable : il survit à un request timeout, réduit la récupération manuelle ou rend une opération longue observable. Épinglez les versions du protocole et du SDK, le capability manifest, les tools autorisés, le TTL maximal, la concurrence, la rétention du status, les owners et le kill switch. Le shadow mode peut comparer la projection d’état avec un job API existant, mais il ne doit pas exécuter deux fois l’opération métier.
Promouvez le canary uniquement après réussite des gates contract, security, load et recovery. Le rollback bloque les nouveaux starts Task-augmented, conserve un watcher pour les Tasks déjà créés, reconcilie les opérations métier in-flight et restaure le chemin synchrone ou job-API vérifié. Retestez après une modification de la spécification MCP, du statut experimental des Tasks, du SDK, du transition schema, du authorization context, du transport ou de la downstream idempotency. Il s’agit d’un verdict local de compatibilité, pas d’une affirmation que Tasks est meilleur pour tous les MCP servers.
Exemples pratiques
Export long avec récupération sûre
Un tool crée un export read-only et renvoie un Task. Le client conserve taskId et le domain exportId, effectue le polling selon l’intervalle recommandé et, après completed, récupère un manifest avec checksum et download handle à courte durée de vie. Une coupure réseau reprend le polling ; elle ne crée pas un second export.
Deployment où cancelled ne signifie pas rolled back
Un Task encapsule un deployment job. Cancel arrête les étapes suivantes, mais le controller vérifie séparément si une partie des changements a déjà été appliquée. L’UI affiche un Task cancelled et un domain outcome reconciliation_required jusqu’à ce que le system of record confirme un rollback ou un release stable.
FAQ
Les MCP Tasks sont-ils déjà stables pour la production ?
Tasks est défini dans MCP 2025-11-25, mais la spécification le marque experimental. Utilisez une capability negotiation explicite, une compatibilité épinglée, un canary et un fallback ; revérifiez le statut actuel avant le rollout.
Un Task rend-il tools/call asynchrone automatiquement ?
Non. Le server et le tool concerné doivent annoncer leur support, et le receiver doit implémenter durable execution, status, result retrieval, cancellation, authorization et cleanup.
Quand vaut-il mieux conserver un job API maison ?
Lorsque les clients ne supportent pas Tasks, que le workflow exige une orchestration plus riche ou que le job API existant fournit déjà les SLA, audit et recovery requis. Un MCP Task peut servir d’adapter au-dessus de cet API plutôt que le remplacer.
Peut-on répéter tools/call si la create response est perdue ?
Pas aveuglément. Reconciliez d’abord avec un client operation ID ou une idempotency key. Sinon, une réponse perdue après un start réussi peut créer une opération dupliquée.