← Retour au blog
Analyse

Claude en cours de conversation : input_schema dans le message, le tableau tools ne bouge pas

Publié le 09/10/2026 Mis à jour le 09/10/2026 Environ 13 min Boîte à outils JSON

Le fil de cette note

Au 09/10/2026, les notes de version de la plateforme Claude datent cette capacité du 22/09/2026 : un outil peut se définir dans un message system en cours de conversation. L'en-tête bêta est inline-tools-2026-09-15. La doc consultée ce jour-là liste les modèles jusqu'à Claude Haiku 5.5, sorti le 07/10/2026. Claude Sonnet 5 n'y figure pas. Les outils déjà connus restent dans tools. Un outil découvert plus tard, ou un input_schema qui doit changer, va dans tool_addition avec la définition complète. L'URL et le jeton MCP restent dans mcp_servers. La liste se fige avec mcp_tool_listing. Pourquoi le contrat est un objet : pourquoi l'IA aime JSON. Comment les agents se passent des objets : comment les agents Claude échangent du JSON.

Dans un long échange, la base d'analyse arrive à mi-parcours. Insérer db_query en tête de tools change le préfixe mis en cache dès le premier octet. Le contrat que le modèle voit au tour suivant doit être l'input_schema que vous venez d'ajouter, et rester cet objet si le serveur publie plus tard une autre liste.

Ce que la doc écrit vraiment

Au 09/10/2026, suivre les notes de version et la page Mid-conversation system messages. Les messages système sans en-tête et la définition encore en bêta sont deux choses :

  • Messages système : ajouter {"role":"system"} en cours de route, sur l'API Claude, Amazon Bedrock et Google Cloud. Pas d'en-tête bêta. Modèles documentés : Claude Fable 5.1, Mythos 5.1, Fable 5, Mythos 5, Opus 5.5, Opus 4.8, Opus 5, Sonnet 5.5 et Haiku 5.5. Claude Sonnet 5 utilise le champ system de premier niveau.
  • Définir un outil par valeur : toujours en bêta. Sur l'API Claude, envoyer anthropic-beta: inline-tools-2026-09-15. Un bloc tool_addition peut porter la définition complète, pour un outil inconnu au départ ou un Schema qui change ensuite. Le même en-tête couvre l'ajout et le retrait par référence : inutile d'envoyer aussi mid-conversation-tool-changes-2026-07-01.
  • Référence par nom seulement : l'ancien en-tête mid-conversation-tool-changes-2026-07-01 marche encore sur l'API Claude, Bedrock et Google Cloud. Il ne porte pas de définition complète dans le bloc.
  • Ajouter MCP en cours de route : envoyer aussi mcp-client-2026-09-15. La définition peut être un mcp_toolset. La page documente cet en-tête pour l'API Claude. Il inclut ce que faisait mcp-client-2025-11-20, donc il le remplace.

Une ligne. Le tableau tools du préfixe mis en cache reste identique octet pour octet. Le nouveau contrat apparaît dans un message système plus tard, et le champ s'appelle toujours input_schema.

Pourquoi le tableau tools reste en place

La doc dit que le tableau tools est plus tôt dans le préfixe haché de la requête que le champ system de premier niveau. Le modifier invalide le cache de prompt de toute la conversation. Les outils déjà connus sont déclarés dans tools. Ensuite, tool_addition et tool_removal décident à partir de quel message le modèle voit un outil, ou ne le voit plus. Le tableau lui-même ne change pas.

Par référence, {"type":"tool_reference","name":"..."} nomme un outil déjà dans tools. Un outil du connecteur MCP peut être une mcp_tool_reference (server_name plus name) ou un mcp_toolset_reference entier. Un nom absent renvoie 400 sur l'API Claude, avec error.details.error_code égal à tool_reference_unresolved.

Un outil avec defer_loading: true reste caché jusqu'à un tool_addition. tool_addition repropose aussi un outil qu'un tool_removal antérieur avait retiré. Un outil connu dès la première requête va dans tools, avec defer_loading si le modèle ne doit pas encore le voir. On ne définit par valeur que ce qui est inconnu au départ, ou ce qui change ensuite.

Garder au moins un outil non différé dans tools. Une requête dont tous les outils sont différés est acceptée, mais la première définition par valeur change le début du prompt rendu et coûte un raté de cache complet. Un outil de recherche d'outils compte comme non différé.

Porter input_schema dans tool_definition

La définition est enveloppée dans un objet dont tool.type vaut tool_definition. definition est une entrée tools ordinaire : outil personnalisé, outil client ou outil serveur, y compris cache_control et defer_loading. Pendant la bêta, certains types ne peuvent pas encore se définir dans un message. La doc cite computer use, qui renvoie un 400 explicite. Ces types restent déclarés dans tools et s'ajoutent par référence.

L'exemple documenté db_query :

{
  "role": "system",
  "content": [
    {
      "type": "tool_addition",
      "tool": {
        "type": "tool_definition",
        "definition": {
          "name": "db_query",
          "description": "Run a read-only SQL query against the analytics database.",
          "input_schema": {
            "type": "object",
            "properties": { "sql": { "type": "string" } },
            "required": ["sql"]
          }
        }
      }
    }
  ]
}

À partir de ce message, le modèle l'appelle comme un outil de tools. Renvoyer une définition identique ne change rien : un nouvel essai peut la renvoyer telle quelle. Les en-têtes restent anthropic-version: 2023-06-01 et anthropic-beta: inline-tools-2026-09-15. L'exemple documenté laisse get_weather dans tools et place db_query après le premier tour utilisateur.

Le modèle renvoie un tool_use ordinaire. L'input documenté :

{
  "type": "tool_use",
  "id": "toolu_01A09q90qw90lq917835lq9",
  "name": "db_query",
  "input": {
    "sql": "SELECT COUNT(*) FROM orders WHERE shipped_at::date = CURRENT_DATE - 1"
  }
}

Cet input_schema officiel ne pose pas additionalProperties: false. Des clés en trop peuvent rester un JSON Schema valide. Pour les refuser localement, ajouter le mot-clé puis vérifier le vrai input. La note de bêta ne range pas strict sur l'outil dans cette capacité. strict reste un interrupteur séparé sur la définition.

Renvoyer un Schema sous le même nom

Pour changer un Schema, ou passer un outil serveur à une version plus récente, envoyer une définition différente sous le même name. La nouvelle définition remplace l'ancienne à partir de cette position. Réutiliser le nom d'un autre type d'outil renvoie 400 avec tool_name_conflict. Une version plus récente du même outil ne compte pas comme un autre type. tool_removal prend toujours une référence. Un outil retiré peut être redéfini ou reproposé plus tard.

Le champ limit ci-dessous est un échantillon local de « même nom, définition différente ». Ce n'est pas un second extrait officiel. L'exemple documenté n'a que sql.

{
  "role": "system",
  "content": [
    {
      "type": "tool_addition",
      "tool": {
        "type": "tool_definition",
        "definition": {
          "name": "db_query",
          "description": "Run a read-only SQL query. Reject extra keys locally before execution.",
          "input_schema": {
            "type": "object",
            "properties": {
              "sql": { "type": "string" },
              "limit": { "type": "integer", "minimum": 1, "maximum": 100 }
            },
            "required": ["sql"],
            "additionalProperties": false
          }
        }
      }
    }
  ]
}

Ne pas modifier ni supprimer un message système déjà envoyé. Cela invalide le cache à partir de ce point, comme toute modification antérieure. La doc indique que, sur Claude Fable 5.1, Opus 5.5, Sonnet 5.5 et Haiku 5.5, les blocs thinking des tours assistant suivants échouent aussi au contrôle de conversation. Si l'instruction doit changer, ajouter un nouveau message système.

Figer une liste MCP

Un serveur MCP peut changer ses outils à tout moment. Avec mcp-client-2026-09-15, quand l'API demande ses outils à un serveur, la réponse commence par un bloc mcp_tool_listing, un par serveur interrogé. L'exemple documenté :

{
  "type": "mcp_tool_listing",
  "mcp_server_name": "example-mcp",
  "tools": [
    {
      "name": "echo",
      "description": "Returns the text it receives.",
      "input_schema": {
        "type": "object",
        "properties": { "text": { "type": "string" } },
        "required": ["text"]
      }
    }
  ]
}

Si le code lit content[0] comme texte, il saute ces blocs. Renvoyer le message assistant inchangé, blocs compris, et continuer d'envoyer mcp-client-2026-09-15 sur chaque requête suivante qui en porte un. Les requêtes suivantes utilisent la liste enregistrée et ne redemandent pas à ce serveur.

Pour figer soi-même, copier le tools du bloc dans le champ tools du mcp_toolset de ce serveur. L'API ne demande plus la liste. L'ensemble est exactement ces entrées, avec default_config et configs. Chaque entrée porte le name tel que le serveur le liste (sans le nom du serveur), description et input_schema :

{
  "type": "mcp_toolset",
  "mcp_server_name": "example-mcp",
  "tools": [
    {
      "name": "echo",
      "description": "Returns the text it receives.",
      "input_schema": {
        "type": "object",
        "properties": { "text": { "type": "string" } },
        "required": ["text"]
      }
    }
  ]
}

Une requête suivante avec cette liste figée n'a pas de mcp_tool_listing, parce que l'API n'a pas redemandé au serveur.

Un serveur qui devient disponible à mi-parcours garde ses données de connexion dans mcp_servers. Le bloc ajouté ne fait que le nommer. Les deux en-têtes : inline-tools-2026-09-15,mcp-client-2026-09-15.

{
  "role": "system",
  "content": [
    {
      "type": "tool_addition",
      "tool": {
        "type": "tool_definition",
        "definition": { "type": "mcp_toolset", "mcp_server_name": "calendar" }
      }
    }
  ]
}

L'objet mcp_toolset est le même que celui qu'on mettrait dans tools, y compris default_config et configs. Un bloc tool_addition ne contient jamais d'URL de serveur ni de jeton. L'exemple documenté place le serveur calendrier dans mcp_servers avec type: "url", name calendar et authorization_token à côté.

Place, taille et codes d'erreur

Un message system qui porte du contenu (text, tool_addition ou tool_removal) doit suivre immédiatement un tour utilisateur, y compris un tour qui porte des tool_result, ou un tour assistant qui se termine par un résultat d'outil serveur. Il précède le tour assistant suivant ou termine le tableau. Il ne peut pas se placer entre un tool_use et son tool_result. Mauvaise place : 400. Juste après un tour assistant en pause (qui se termine par un résultat d'outil serveur), tool_addition et tool_removal ne sont pas acceptés ; les blocs texte le sont. Reprendre d'abord le tour en pause, puis envoyer le changement d'outil.

cache_control va sur le bloc ou dans la définition, pas les deux, et compte dans la limite de points d'arrêt de la requête. Une définition différée ne peut pas porter cache_control. Si un outil serveur défini par valeur exige son propre en-tête bêta, l'envoyer sur chaque requête suivante de la conversation.

Chacun de ces dépassements renvoie 400 avec available_tools_limit_exceeded :

  • Plus de 10 000 outils différés disponibles après un message.
  • Plus de 10 000 outils définis après le premier message utilisateur restent disponibles après un message.
  • Les définitions envoyées après le premier message utilisateur et encore disponibles après un message totalisent plus de 4 Mo (4 194 304 octets).
  • Le texte d'outil rendu dépasse 4 Mo (4 194 304 octets).

Vérifier dans la boîte à outils

D'abord resserrer l'input_schema officiel en contrat local. L'exemple officiel n'a pas additionalProperties: false. Celui-ci sert au contrôle :

{
  "type": "object",
  "properties": {
    "sql": { "type": "string" }
  },
  "required": ["sql"],
  "additionalProperties": false
}

Trois objets input :

{
  "ok": {
    "sql": "SELECT COUNT(*) FROM orders WHERE shipped_at::date = CURRENT_DATE - 1"
  },
  "extra_limit": {
    "sql": "SELECT 1",
    "limit": 10
  },
  "missing_sql": {}
}
  1. Coller tool_addition, mcp_tool_listing et les trois entrées dans le formatage JSON et confirmer qu'ils parsent.
  2. Avec JSON → Schema, partir de ok, puis ajouter required et additionalProperties: false. Le Schema officiel, tel qu'il est écrit, ne refuse pas déjà les clés en trop.
  3. Passer extra_limit et missing_sql dans la validation Schema. Contre le contrat resserré, les deux doivent échouer. ok doit passer.
  4. Faire passer mcp_toolset et input_schema par Outil MCP. L'URL et le jeton restent hors de l'objet qui ne nomme que l'outil.
  5. Revérifier tool_use.input avec les appels de fonction avant toute exécution SQL.

Les données restent dans le navigateur. Elles ne sont pas envoyées. Obtenir d'abord un objet qui refuse un sql manquant et un limit en trop, puis modifier le message système en production.

Questions fréquentes

Quelle différence entre modifier le tableau tools et ajouter tool_addition ?

tools est plus tôt dans le préfixe mis en cache. Le modifier invalide tout le cache. Ajouter tool_addition laisse le tableau et les messages précédents tels quels. Seul le nouveau message est une entrée nouvelle.

Faut-il envoyer inline-tools avec l'ancien en-tête mid-conversation-tool-changes ?

Non. inline-tools-2026-09-15 couvre déjà l'ajout et le retrait par référence. L'ancien en-tête ne fait que nommer l'outil et ne porte pas de définition complète. Il fonctionne sur l'API Claude, Bedrock et Google Cloud.

L'URL et le jeton d'un serveur MCP peuvent-ils aller dans tool_addition ?

Non. Le bloc ne porte que mcp_server_name. L'URL et authorization_token restent dans mcp_servers. Ajouter un serveur en cours de route exige aussi mcp-client-2026-09-15, documenté pour l'API Claude.

Que faire de mcp_tool_listing ?

Le sauter en lisant le texte. Renvoyer le message assistant inchangé et garder l'en-tête bêta. Pour figer, copier tools dans le mcp_toolset. Ensuite l'API ne redemande plus au serveur, et la réponse suivante n'a pas ce bloc.

Est-ce le même texte que ChatGPT MCP Events ?

Non. L'autre texte est le filtre d'abonnement et le data du webhook. Celui-ci est Claude qui change input_schema en cours de conversation et fige une liste MCP. La livraison est dans Événements MCP de ChatGPT.

En bref

Au 09/10/2026, Claude écrit un changement d'outil en cours de conversation comme un JSON qu'on peut ajouter : tool_addition enveloppe tool_definition, et le contrat reste input_schema. La note de version est datée du 22/09/2026. L'en-tête bêta est inline-tools-2026-09-15. La liste de modèles lue ce jour-là inclut Haiku 5.5 et laisse Sonnet 5 de côté. Modifier le tableau tools invalide tout le cache. Une seconde définition sous le même nom remplace le Schema à partir de là. Un nom pris par un autre type d'outil donne tool_name_conflict. L'adresse et le jeton MCP restent dans mcp_servers. On renvoie mcp_tool_listing tel quel, ou on le copie dans tools pour le figer. L'exemple officiel ne ferme pas les champs en trop. L'étape suivante est de refuser un sql manquant et un limit en trop, avant de mettre computer use dans le message.