← Retour au blog
Analyse

Après Claude Code 2.1.319 (6 nov. 2026) et les tâches MCP en arrière-plan : comment l'hôte Agent interroge le JSON d'état, poll tools/call et valide arguments ?

Publié le 2026-11-07 Dernière mise à jour 2026-11-07 Environ 10 min JSON Toolbox

Objectif de cette note

Au 07/11/2026, Claude Code 2.1.319 (06/11/2026) prend en charge les tasks MCP dans le terminal : quand le serveur marque tools/call comme task, l'hôte déplace l'appel en arrière-plan et réinjecte le résultat après tasks/result. Protocole : SEP-1686 expérimental dans MCP 2025-11-25 (documentation Tasks). Pour un agent maison, l'enjeu n'est pas « savoir interroger », mais séparer JSON d'état de task, validation des arguments et CallToolResult final. Retours d'outils : outputSchema ; contrat Skills : Skills over MCP.

Les outils MCP longs (batch, API de jobs externes, crawling lourd) bloquaient toute la tour de dialogue. La task scinde « accepter la requête » et « livrer le résultat » en deux phases JSON-RPC : la première donne au modèle des métadonnées de task, pas le payload métier. Claude Code en fait le comportement hôte par défaut ; pour votre propre hôte, réutilisez la même machine à états — ne simulez pas un tool result à status: working.

Ce que Claude Code change le 6 nov.

  • Arrière-plan : si le serveur MCP exécute tools/call en task, Claude Code rend la main au modèle tout de suite et attend en arrière-plan — comme le prévoit SEP-1686 pour laisser le modèle continuer.
  • CLAUDE_CODE_DISABLE_MCP_TASK_BACKGROUND : si activé, attente synchrone bloquante dans l'appel d'outil — pratique pour comparer sync et async.
  • CLAUDE_CODE_DISABLE_MCP_TASKS=1 : désactive entièrement le support des tasks MCP.
  • /tasks : l'UI terminal liste les sous-tâches en cours et terminées pour aligner taskId et journaux JSON.

En une phrase. La task change la chronologie, pas le contrat Schema. inputSchema reste dans tools/list ; valider avant l'appel.

Forme JSON dans SEP-1686

Ajoutez task (optionnellement ttl en ms) dans les params de tools/call ; si le serveur accepte, le result est un CreateTaskResult, pas un CallToolResult ordinaire :

{
  "tools_call_with_task": {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "batch_index",
      "arguments": {
        "dataset": "logs-2026-11",
        "shard": 3
      },
      "task": { "ttl": 120000 }
    }
  },
  "create_task_result": {
    "task": {
      "taskId": "786512e2-9e0d-44bd-8f29-789f320fe840",
      "status": "working",
      "statusMessage": "The operation is now in progress.",
      "createdAt": "2026-11-07T02:10:00Z",
      "lastUpdatedAt": "2026-11-07T02:10:05Z",
      "ttl": 120000,
      "pollInterval": 5000
    }
  }
}

États terminaux : completed, failed, cancelled, plus input_required (entrée utilisateur ou hôte). Interrogation via tasks/get, résultat métier via tasks/result — même structure que tools/call synchrone (content, isError, structuredContent optionnel).

{
  "tasks_get_response": {
    "taskId": "786512e2-9e0d-44bd-8f29-789f320fe840",
    "status": "completed",
    "pollInterval": 5000,
    "lastUpdatedAt": "2026-11-07T02:12:00Z"
  },
  "tasks_result_response": {
    "content": [{ "type": "text", "text": "Indexed 1.2M rows in shard 3." }],
    "isError": false,
    "structuredContent": {
      "rows": 1200000,
      "shard": 3
    }
  }
}

Le serveur peut mettre io.modelcontextprotocol/model-immediate-response dans _meta de CreateTaskResult ; sinon message placeholder côté hôte. notifications/tasks/status est optionnel — la spec exige de ne pas se fier qu'au push : continuer tasks/get selon pollInterval.

capabilities et taskSupport

Au handshake, les deux parties déclarent capabilities.tasks. Un tools/call augmenté par task n'est permis que si le client annonce tasks.requests.tools.call et le serveur la supporte.

{
  "server_capabilities_tasks": {
    "capabilities": {
      "tasks": {
        "list": {},
        "cancel": {},
        "requests": {
          "tools": { "call": {} }
        }
      }
    }
  },
  "tool_list_entry": {
    "name": "batch_index",
    "description": "Index one shard of a dataset",
    "inputSchema": {
      "type": "object",
      "properties": {
        "dataset": { "type": "string" },
        "shard": { "type": "integer", "minimum": 0 }
      },
      "required": ["dataset", "shard"],
      "additionalProperties": false
    },
    "execution": {
      "taskSupport": "optional"
    }
  }
}

Sans tasks.requests.tools.call côté serveur, le client ne doit pas envoyer d'appel avec task, même si taskSupport vaut optional. Avec taskSupport: required, un call sans params.task doit être refusé (la spec suggère -32601).

Interrogation côté hôte et fusion du résultat

  1. Valider les entrées : vérifier arguments contre inputSchema en cache depuis tools/list (JSON Schema 2020-12, SEP-1613).
  2. Envoyer le call : joindre params.task selon taskSupport.
  3. Réponse immédiate au modèle : CreateTaskResult ou model-immediate-response ; enregistrer taskId dans l'état de session (objet JSON, pas seulement une chaîne).
  4. Interroger : tasks/get à intervalle ≥ pollInterval, jusqu'à état terminal ou input_required.
  5. Récupérer le résultat : tasks/result ; si outputSchema, valider structuredContent (article outputSchema).
  6. Réécrire dans le dialogue : le CallToolResult final comme message de résultat d'outil ; pas de faux succès en phase working.
{
  "host_session_tasks": {
    "786512e2-9e0d-44bd-8f29-789f320fe840": {
      "toolName": "batch_index",
      "arguments": { "dataset": "logs-2026-11", "shard": 3 },
      "lastStatus": "working",
      "nextPollAt": "2026-11-07T02:10:10Z"
    }
  }
}

arguments et outputSchema

Erreur fréquente : sauter la validation d'entrée dès status: completed, ou traiter CreateTaskResult comme sortie d'outil dans un pipeline. Chemins sync et task : mêmes fonctions Schema.

{
  "arguments_string": "{\"dataset\":\"logs-2026-11\",\"shard\":3}",
  "inputSchema": {
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "type": "object",
    "properties": {
      "dataset": { "type": "string", "pattern": "^[a-z0-9-]+$" },
      "shard": { "type": "integer", "minimum": 0 }
    },
    "required": ["dataset", "shard"],
    "additionalProperties": false
  }
}

Distinguer : échec Schema (client refuse, pas de call), Tool Execution Error (SEP-1303 : erreurs métier/validation via tool result pour auto-correction du modèle), task failed/cancelled (JSON d'état dans les logs, pas de demi-résultat comme succès).

Variables d'environnement du terminal

  • CLAUDE_CODE_DISABLE_MCP_TASK_BACKGROUND=1 — attente synchrone de la task, pour tests d'intégration.
  • CLAUDE_CODE_DISABLE_MCP_TASKS=1 — tasks désactivées, tools/call bloquant classique.

Un hôte maison n'a pas ces variables ; la couche applicative peut imiter : « arrière-plan par défaut + option pour forcer le blocage » — proche de Claude Code en staging.

Essayer sur JSON Toolbox

  1. Coller inputSchema et arguments_string ci-dessus dans la validation Schema.
  2. Avec l'outil MCP, comparer les noms de champs taskSupport et inputSchema.
  3. Formater create_task_result et tasks_result_response — ne pas les fusionner en un faux tool result.
  4. Pour la sortie structurée finale du modèle : schema sortie structurée séparé de l'objet d'état de task.

Questions fréquentes

En quoi la réponse d'une task MCP diffère-t-elle d'un tools/call classique ?

D'abord les métadonnées de task ; la vraie sortie est dans tasks/result.

Faut-il encore valider arguments quand la task tourne en arrière-plan ?

Oui — contre inputSchema avant le call.

Quelles valeurs pour execution.taskSupport ?

forbidden / optional / required, sous contrainte des capabilities.

À quoi sert CLAUDE_CODE_DISABLE_MCP_TASK_BACKGROUND ?

Force l'attente synchrone de la fin de la task MCP.

Comment tasks/result et outputSchema s'articulent ?

Comme pour un call synchrone — valider structuredContent une fois reçu.

Synthèse

Au 07/11/2026, Claude Code 2.1.319 fait des Tasks MCP le mode hôte par défaut du terminal : les longs tools/call deviennent d'abord CreateTaskResult, puis se terminent via tasks/get / tasks/result. En intégration agent, traiter le JSON d'état de task comme machine à états de session ; garder arguments / structuredContent sous JSON Schema 2020-12. Prochaine étape : un serveur MCP avec taskSupport: optional, comparer avec et sans CLAUDE_CODE_DISABLE_MCP_TASK_BACKGROUND sur les tours du modèle et les messages d'outil.