1. MCP et JSON‑RPC : le « socle » un peu ennuyeux à comprendre une bonne fois pour toutes
Dans le cours précédent, nous avons parlé de l’utilité de MCP et de la manière dont il s’insère dans la pile Apps SDK. Ici, nous resserrons le focus sur la couche la plus « ennuyeuse » — le format des messages MCP — afin que vous puissiez lire sereinement des logs JSON bruts et comprendre ce que ChatGPT envoie à votre serveur et ce que celui‑ci répond.
MCP utilise JSON‑RPC 2.0 comme transport de données : toutes les requêtes, réponses et notifications sont de simples objets JSON avec un schéma prévisible.
Autrement dit, au lieu de « chaque service invente son propre format », on a un contrat de base :
- une requête possède le champ obligatoire jsonrpc (généralement "2.0"), un id unique, un nom de méthode method sous forme de chaîne, et un objet params avec les paramètres ;
- la réponse se rattache à la requête via id et contient soit result, soit error ;
- les notifications ressemblent aux requêtes, mais sans id, et il n’y aura pas de réponse.
Voici à quoi cela ressemble :
{
"jsonrpc": "2.0",
"id": 42,
"method": "tools/list",
"params": {
"cursor": null
}
}
Ceci est une request. Et la réponse en cas de succès :
{
"jsonrpc": "2.0",
"id": 42,
"result": {
"tools": [],
"nextCursor": null
}
}
Si vous vous dites « c’est du RPC classique », c’est exactement ça. MCP fixe simplement quelles méthodes existent (tools/list, tools/call, resources/list, prompts/list, …) et dans quel format elles attendent les paramètres et renvoient les données.
L’essentiel à sentir : JSON‑RPC est l’ossature « requête–réponse–notification ». MCP, c’est « quelles requêtes exactement existent et ce qu’elles contiennent ».
2. Request : comment MCP demande d’exécuter quelque chose
Commençons par les requêtes. Elles vont toujours dans le sens « quelqu’un veut faire quelque chose ». En général, client → serveur (ChatGPT → votre serveur MCP), mais MCP autorise aussi des requêtes inverses, quand le serveur demande au client de faire du sampling ou de l’elicitation. Dans ce cours, nous nous intéressons d’abord au cas classique : le client demande au serveur.
Toute requête MCP possède trois champs clés :
- jsonrpc — la version du protocole JSON‑RPC, généralement "2.0".
- id — l’identifiant de la requête ; n’importe quel type JSON, mais en pratique le plus souvent un nombre ou une chaîne. L’important, c’est que les id soient uniques pour les requêtes actives.
- method — une chaîne de la forme "tools/list" ou "tools/call". MCP spécifie l’ensemble des méthodes autorisées.
Et il y a l’objet params, qui contient les paramètres spécifiques à la méthode.
Exemple : demander la liste des outils
Imaginons que ChatGPT vient de se connecter à votre serveur MCP et souhaite savoir quels tools il peut appeler. Il enverra une requête de ce type :
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list",
"params": {
"cursor": null
}
}
Le champ cursor est utilisé pour la pagination — si les outils sont nombreux, le serveur peut les renvoyer par lots.
Pour notre application d’exemple (sélection de cadeaux), ce sera encore un peu monotone : un ou deux outils, mais le protocole reste le même. Considérez ceci comme un exemple intuitif ; nous verrons les structures formelles plus tard dans la section sur les tools.
Exemple : appel d’un outil (tools/call)
Un peu plus intéressant maintenant. Supposons que nous avons déjà un MCP‑tool suggest_gifts, que vous prévoyez d’implémenter dans le cours sur le serveur MCP. Il attend les paramètres suivants :
- occasion — l’occasion (Birthday, Wedding, …),
- budget — un nombre en dollars,
- recipient — une chaîne décrivant la personne à qui l’on offre.
Lorsque ChatGPT décide d’utiliser cet outil, il forme une requête MCP comme suit :
{
"jsonrpc": "2.0",
"id": 7,
"method": "tools/call",
"params": {
"name": "suggest_gifts",
"arguments": {
"occasion": "birthday",
"budget": 100,
"recipient": "friend who loves board games"
}
}
}
Notez plusieurs détails.
Premièrement, le nom de l’outil vient de ce que vous avez déclaré côté serveur (server.registerTool("suggest_gifts", …)). Deuxièmement, l’objet arguments doit respecter la JSON Schema que vous joignez à la description de l’outil.
Si GPT essaie d’envoyer des arguments non conformes au schéma (par exemple, budget : "cent dollars"), le serveur est en droit de renvoyer une erreur au niveau du protocole ou de la logique métier, selon l’implémentation. Pour l’instant, retenez surtout la forme générale de ce type de requête ; dans la section tools ci‑dessous, nous regarderons ces mêmes messages de manière plus systématique.
Requêtes pour les ressources et les prompts
Les requêtes vers les ressources et les prompts sont analogues. La spécification MCP définit les méthodes :
- resources/list — énumérer les ressources disponibles ;
- resources/read (ou resources/get) — lire une ressource spécifique via son URI ;
- prompts/list — obtenir la liste des prompts disponibles ;
- prompts/get — obtenir le contenu d’un prompt précis.
Exemple de requête de lecture d’une ressource contenant un catalogue de cadeaux :
{
"jsonrpc": "2.0",
"id": 15,
"method": "resources/read",
"params": {
"uri": "mcp://gift-server/resources/gift_catalog"
}
}
Retenez deux choses pour l’instant. Premièrement, pour chaque primitive il existe des méthodes */list et */get/*/read. Deuxièmement, le nom de la méthode se trouve toujours dans le champ chaîne method, et tout le contenu est dans l’objet params.
3. Reply : comment MCP répond — result et error
La réponse (reply) est toujours corrélée à la requête via le champ id. C’est comme un correlationId dans de nombreux systèmes distribués : vous regardez les logs et voyez que la requête avec id=7 a reçu une réponse avec id=7, donc c’est une paire.
JSON‑RPC pose une règle simple : la réponse contient soit result, soit error, mais pas les deux. MCP précise par‑dessus la structure du result selon les méthodes (tools/list, tools/call, etc.) et recommande des codes d’erreur.
Réponse réussie (result)
Regardons un exemple de réponse réussie à tools/call de notre suggest_gifts. Le serveur a tout exécuté, a trouvé des idées de cadeaux et renvoie la liste dans le champ result :
{
"jsonrpc": "2.0",
"id": 7,
"result": {
"content": [
{
"type": "text",
"text": "Here are some gift ideas for your friend..."
}
],
"structuredContent": {
"gifts": [
{ "name": "Board game: Catan", "price": 45 },
{ "name": "Dice set", "price": 20 }
]
},
"isError": false
}
}
Plusieurs points sont importants ici.
- Premièrement, content et structuredContent sont justement les parties de la réponse des MCP‑tools que vous avez déjà vues dans le Apps SDK. Le modèle utilise le texte de content, et votre widget affiche proprement les données de structuredContent.
- Deuxièmement, le drapeau isError se rapporte au résultat métier. Du point de vue du protocole, tout s’est bien passé : JSON valide, méthode existante, arguments parsés. Mais la logique métier peut dire : « je n’ai trouvé aucune idée de cadeau, du point de vue UX on considère cela comme une erreur ». Dans ce cas, vous mettez isError : true et décrivez le problème dans content.
- Troisièmement, la spécification MCP pour les différentes méthodes (tools/list, tools/call, */list, */get) détaille les champs qui doivent se trouver dans result. Par exemple, pour tools/list le serveur renvoie un tableau de descriptions d’outils avec noms, titres, descriptions et JSON Schema des arguments d’entrée.
Réponse en erreur (error)
Si quelque chose ne va pas au niveau du protocole ou du serveur, au lieu de result on renvoie un objet error. Il contient en général :
- code — le code numérique d’erreur ;
- message — une description lisible par un humain ;
- data — des données additionnelles optionnelles (stack trace, détails, …).
Exemple : le modèle a appelé une méthode inexistante :
{
"jsonrpc": "2.0",
"id": 99,
"error": {
"code": -32601,
"message": "Method not found: tools/col"
}
}
Le code -32601 est le classique JSON‑RPC « method not found ».
Il existe une nuance importante entre deux types d’erreurs.
Erreur de protocole — quand les règles MCP/JSON‑RPC sont violées : méthode inconnue, type incorrect dans params, JSON invalide. Dans ce cas, il est pertinent de renvoyer un error au niveau supérieur.
Erreur métier — lorsque le protocole est respecté, mais que l’opération échoue pour une raison métier : catalogue vide, pas de droits sur une ressource, identifiant métier invalide. MCP recommande alors de renvoyer un result valide, mais de le marquer isError : true et de décrire le problème dans le contenu.
Cette distinction aide beaucoup ChatGPT et les outils de débogage : en regardant les logs, vous voyez tout de suite s’il s’agit d’une panne technique ou d’un refus métier assumé.
4. Notifications : messages unidirectionnels
Une notification est un « courrier sans attente de réponse ». En JSON‑RPC, les notifications ressemblent à des requêtes sans le champ id. Le client ne doit pas y répondre.
Dans MCP, les notifications servent aux événements : changements dans les listes tools/resources/prompts, progression des opérations longues, messages de log, etc.
L’exemple le plus simple que vous rencontrerez sûrement : une notification indiquant que la liste des outils a changé. La spécification MCP pour tools décrit la capacité listChanged et la notification tools/list_changed, que le serveur envoie si l’ensemble des tools disponibles a changé.
Une notification peut ressembler à ceci :
{
"jsonrpc": "2.0",
"method": "tools/list_changed",
"params": {
"reason": "New tool 'suggest_gift_cards' was added"
}
}
Aucune réponse n’est nécessaire. Le client, en la recevant, peut décider : « ok, je dois rappeler tools/list et mettre à jour le cache des outils ».
Autres notifications MCP typiques (nous en parlerons en détail dans le module sur les flux et événements) :
- événements de progression (notifications/progress) pour les opérations longues ;
- logs du serveur (notifications/logging/message) ;
- changements de ressources (resources/list_changed) et de prompts (prompts/list_changed).
À retenir pour l’instant : notification = requête sans id et sans réponse attendue. Si vous voyez dans les logs un JSON sans id, c’est très probablement une notification.
Insight
Il a été constaté expérimentalement que l’app ChatGPT ignore les messages qui lui sont envoyés (MCP‑notification). Cependant, étant donné que les ChatGPT Apps n’en sont qu’à leurs débuts, la probabilité d’un support complet de tout le spectre du protocole MCP dans un avenir proche est très élevée. Je recommande donc d’étudier malgré tout cet aspect du protocole MCP.
5. À quoi ressemblent tools/resources/prompts dans les messages
Passons au plus intéressant : comment sont décrits, à l’intérieur des messages MCP, ces fameux tools, resources et prompts dont nous parlons tant.
Tools : description et appel
Au niveau protocole, les tools ont deux processus principaux :
- discovery — le client découvre quels outils existent ;
- invocation — le client appelle un outil précis.
Nous avons déjà aperçu tools/list et tools/call plus haut. Voyons‑les maintenant plus systématiquement : quels processus ils couvrent et ce qui est exactement renvoyé dans le result.
5.1.1. Liste des outils — tools/list
Nous avons déjà vu la requête pour tools/list. Regardons la structure de la réponse. La spécification MCP dit : dans result.tools doit revenir un tableau d’objets, chacun décrivant un outil. Un outil possède obligatoirement :
- name — un nom unique, via lequel on appellera ensuite tools/call ;
- title — un court titre (vu par l’humain et par le modèle) ;
- description — une description plus détaillée de ce que fait le tool, comme si vous l’expliquiez à un collègue ;
- inputSchema — la JSON Schema pour les arguments de l’outil.
Pour notre suggest_gifts, la réponse tools/list peut ressembler à ceci (fortement simplifié) :
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"tools": [
{
"name": "suggest_gifts",
"title": "Gift ideas generator",
"description": "Suggests gift ideas for a given occasion and budget.",
"inputSchema": {
"type": "object",
"properties": {
"occasion": { "type": "string" },
"budget": { "type": "number" },
"recipient": { "type": "string" }
},
"required": ["occasion", "budget"]
}
}
],
"nextCursor": null
}
}
Si vous avez déjà écrit inputSchema dans Apps SDK lors de l’enregistrement de l’outil, vous avez pratiquement déjà vu cet objet, simplement « par le haut » — sous forme d’objet TypeScript. MCP le transmet juste au client via le protocole.
5.1.2. Appeler un outil — tools/call
Nous avons déjà abordé le format de l’appel. La spécification MCP décrit que params doit contenir :
- name — le nom de l’outil ;
- arguments — un objet conforme à inputSchema.
Par exemple :
{
"jsonrpc": "2.0",
"id": 7,
"method": "tools/call",
"params": {
"name": "suggest_gifts",
"arguments": {
"occasion": "wedding",
"budget": 150,
"recipient": "coworker from marketing"
}
}
}
Et en réponse, le serveur renvoie un result avec content, structuredContent et, optionnellement, _meta (par exemple avec openai/outputTemplate, si vous voulez lier ce tool à un widget particulier).
Ce couple tools/list → tools/call est le cycle de base des MCP‑tools : d’abord la découverte, puis l’utilisation.
Resources : des données adressables
Les resources dans MCP sont n’importe quels blocs de données auxquels le client peut accéder via un URI : fichiers, enregistrements de BD, configs, catalogues, etc.
Leur jeu d’opérations standard :
- resources/list — pour découvrir quelles ressources existent ;
- resources/read — pour lire une ressource précise (ou une partie).
Imaginons une ressource gift_catalog, qui décrit un catalogue de cadeaux de base : catégories, marques, prix minimum et maximum. Le serveur peut l’annoncer avec l’URI "mcp://gift-server/resources/gift_catalog".
La réponse à resources/list peut être (simplifiée) :
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"resources": [
{
"uri": "mcp://gift-server/resources/gift_catalog", // simple chaîne unique. MCP n'est pas un protocole.
"name": "gift_catalog",
"description": "Base catalog of gifts with categories and prices",
"mimeType": "application/json"
}
],
"nextCursor": null
}
}
Et la lecture de la ressource — resources/read :
{
"jsonrpc": "2.0",
"id": 4,
"method": "resources/read",
"params": {
"uri": "mcp://gift-server/resources/gift_catalog"
}
}
La réponse peut contenir le contenu lui‑même et des métadonnées :
{
"jsonrpc": "2.0",
"id": 4,
"result": {
"contents": [
{
"uri": "mcp://gift-server/resources/gift_catalog",
"mimeType": "application/json",
"text": "{\"categories\":[\"boardgames\",\"books\"]}"
}
]
}
}
L’idée principale : une ressource, ce sont des données adressables, alors que les tools sont des opérations. MCP rend explicites l’un et l’autre dans le protocole.
Prompts : des modèles réutilisables
Les prompts sont des « amorces pré‑prêtes » ou des modèles que le serveur peut proposer au client. MCP les traite comme une primitive qui possède :
- un nom ;
- un titre/une description lisible par un humain ;
- un contenu (souvent un modèle de system‑prompt, ou un ensemble d’exemples few‑shot).
Et, sans surprise, il y a deux méthodes :
- prompts/list — découvrir quels prompts existent ;
- prompts/get — obtenir le contenu d’un prompt.
Par exemple, vous voulez définir un style particulier pour générer des messages de félicitations à joindre au cadeau. Vous pouvez alors déclarer dans votre serveur MCP un prompt gift_congrats_style.
La réponse à prompts/list peut ressembler à ceci :
{
"jsonrpc": "2.0",
"id": 10,
"result": {
"prompts": [
{
"name": "gift_congrats_style",
"description": "Style guide for birthday congratulations in a friendly tone"
}
]
}
}
Et prompts/get renverra le texte (ou un contenu structuré) que le client pourra ensuite transmettre au LLM comme partie du system‑prompt. Exemple de requête et réponse :
{
"jsonrpc": "2.0",
"id": 11,
"method": "prompts/get",
"params": {
"name": "gift_congrats_style"
}
}
{
"jsonrpc": "2.0",
"id": 11,
"result": {
"prompt": {
"name": "gift_congrats_style",
"messages": [
{
"role": "system",
"content": [
{
"type": "text",
"text": "You are a friendly assistant that writes short, warm birthday congratulations..."
}
]
}
]
}
}
}
6. Lien avec Apps SDK et notre widget
À ce stade, le MCP‑JSON vous paraît peut‑être encore un peu verbeux. Reliions‑le à ce que vous avez déjà fait via Apps SDK.
Rappelons qu’au frontend du widget, vous pouvez avoir ce code :
// à l'intérieur d’un composant React dans le bac à sable de ChatGPT
async function fetchGifts() {
const result = await window.openai.callTool("suggest_gifts", {
occasion: "birthday",
budget: 50,
recipient: "friend who loves sci-fi"
});
console.log(result);
}
Au niveau Apps SDK, c’est une fonction pratique qui :
- connaît l’URL du serveur MCP (depuis la configuration de l’application) ;
- sait trouver la description de l’outil par son nom suggest_gifts ;
- emballe votre appel en une requête MCP tools/call ;
- l’envoie via le transport choisi (HTTP/SSE) ;
- attend le reply MCP, dépile le result et vous le renvoie comme result en JavaScript.
Schématiquement, cela donne :
sequenceDiagram
participant Widget
participant AppsSDK as Apps SDK
participant MCP as serveur MCP
Widget->>AppsSDK: window.openai.callTool("suggest_gifts", {...})
AppsSDK->>MCP: JSON { id:7, method:"tools/call", params:{...} }
MCP-->>AppsSDK: JSON { id:7, result:{ content, structuredContent } }
AppsSDK-->>Widget: result (ToolOutput)
Widget->>Widget: setState(toolOutput)
Comprendre le format MCP vous donne deux excellentes compétences.
Premièrement, vous pouvez lire intelligemment les logs MCP bruts (par exemple dans MCP Inspector, dont nous parlerons dans un cours séparé) et voir : quel tools/call est parti, quels arguments il contenait, ce qui est revenu dans le result ou l’error.
Deuxièmement, lors de la conception d’outils et de ressources, vous pouvez penser non seulement en termes de types TypeScript, mais aussi en termes de schémas MCP : à quoi cela ressemblera en JSON, et dans quelle mesure c’est commode pour d’autres clients (par exemple, des agents qui pourraient aussi se connecter à votre serveur MCP).
7. Mini‑pratique : lire et « réparer » le MCP‑JSON
Pour apprivoiser le format MCP, rien ne vaut le fait de décortiquer à la main quelques messages. Prenons l’exemple d’un dialogue complet tools/list → tools/call → résultat.
Le client veut la liste des outils
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list",
"params": {}
}
Ce que nous voyons :
- c’est une request (il y a un id) ;
- la méthode est tools/list, il s’agit donc de la découverte des outils ;
- les paramètres sont vides, sans pagination.
Le serveur répond :
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"tools": [
{
"name": "suggest_gifts",
"title": "Gift ideas generator",
"description": "Suggests gift ideas",
"inputSchema": { "type": "object", "properties": { "occasion": { "type": "string" } } }
}
]
}
}
On voit immédiatement que c’est la réponse à cette requête (même id : 1), que le protocole a réussi (result présent, pas d’error), et que le client sait désormais qu’il existe un tool suggest_gifts.
Le client appelle l’outil
Ensuite, le client appelle tools/call :
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "suggest_gifts",
"arguments": {
"occasion": "anniversary"
}
}
}
Si le serveur attend aussi budget, mais que le modèle ne l’a pas fourni, le serveur peut :
- soit renvoyer une erreur de protocole (par exemple, un error avec le code « invalid params ») ;
- soit appliquer une valeur par défaut (par exemple, un budget moyen) et renvoyer un result normal.
Dans les termes introduits plus haut, la première option est une erreur de protocole (error au niveau supérieur), la seconde relève de la logique métier : vous renvoyez quand même un result valide et vous décidez de considérer la situation comme une erreur métier (isError : true) ou comme un comportement normal.
La réponse en cas d’arguments invalides pourrait ressembler à ceci :
{
"jsonrpc": "2.0",
"id": 2,
"error": {
"code": -32602,
"message": "Missing required property 'budget' in arguments"
}
}
Là encore, à distinguer d’une erreur métier : le protocole est violé (les arguments ne respectent pas le schéma), il est donc pertinent de renvoyer un error.
Exemple cassé : cherchons le bug
Voici un JSON que l’on rencontre parfois chez les débutants :
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"tool": "suggest_gifts",
"args": {
"occasion": "birthday",
"budget": 100
}
}
}
À première vue, cela a l’air plausible, mais si vous comparez avec la spécification MCP, vous noterez que les champs tool et args ne correspondent pas aux name et arguments attendus.
Un client/serveur MCP‑SDK ne générera sans doute jamais ce JSON, mais si, sans connaître la spécification, vous intégrez « à la main », un tel bug est parfaitement possible. C’est précisément pour cela que, dans ce cours, nous abordons le protocole « à nu » et pas seulement les wrappers SDK.
8. Erreurs courantes avec les messages MCP
Erreur n°1 : confusion entre erreurs de protocole et erreurs métier.
Les développeurs ont souvent tendance à emballer tout ce qui « ne marche pas » dans un error de haut niveau — absence de ressource, arguments invalides, panne de base, etc. Dans le contexte MCP, il est utile de distinguer : si la structure JSON et le schéma d’appel sont violés (mauvaise méthode, mauvais champs, types incorrects), c’est une raison de renvoyer un error. Si l’outil n’a simplement pas réussi l’opération métier (pas de cadeaux pour ce budget, utilisateur introuvable), mieux vaut renvoyer un result valide avec isError : true et un message clair dans content. Ainsi, la LLM ChatGPT et les outils de débogage pourront distinguer « le canal est cassé » de « le serveur a refusé intentionnellement ».
Erreur n°2 : ignorer le champ id et la corrélation des requêtes.
Il arrive de voir dans les logs du serveur MCP des sorties manuelles sans id ou avec des valeurs id dupliquées pour différentes requêtes actives. Dans un hello‑world mono‑thread, ça peut encore passer, mais dès que vous avez des appels parallèles ou des retries, il devient difficile de savoir quelle réponse correspond à quelle requête. JSON‑RPC exige explicitement un id unique pendant la durée de vie d’une requête, et MCP s’appuie sur cette règle. Si vous utilisez les SDK officiels, vous n’avez pas à penser à id, mais dès que vous écrivez vous‑même le transport ou le logging, n’oubliez pas de conserver et d’afficher id — c’est la première chose avec laquelle vous déboguerez des bugs étranges.
Erreur n°3 : structures result instables pour une même méthode.
La tentation est grande de « légèrement » changer le format de la réponse selon la situation : parfois renvoyer un tableau de cadeaux, parfois un objet avec une seule chaîne, parfois seulement un text sans structuredContent. Le modèle s’en remettra peut‑être, mais vos widgets et tout autre client MCP — probablement pas. La spécification MCP décrit, pour chaque méthode, une structure result prévisible ; essayez de vous y tenir. Si vous avez besoin d’un autre format, mieux vaut déclarer un tool séparé ou une version, plutôt que de changer le schéma à la volée.
Erreur n°4 : champs superflus ou manquants dans params.
Problème typique des implémentations custom : ajouter dans params ce que MCP n’attend pas, ou oublier un champ obligatoire. Par exemple, envoyer toolName au lieu de name dans tools/call, ou resourceId au lieu de uri dans resources/read. MCP‑SDK valide généralement ces choses et lève une exception claire, mais si vous travaillez plus près du protocole, vous pouvez mettre longtemps à comprendre pourquoi « le serveur ne me comprend pas ». Une bonne pratique : garder à portée de main, à côté du handler, un exemple de requête JSON correcte tirée de la spécification ou des logs d’un client fonctionnel, et comparer avec ce que vous envoyez.
Erreur n°5 : essayer d’utiliser les notifications comme « second canal de réponse ».
Parfois, en découvrant les notifications, des développeurs commencent à envoyer des résultats d’opérations via des notifications au lieu des replies habituels : « nous sommes déjà en MCP et nous avons SSE, poussons tout en notifications ». Le problème, c’est que, par définition, les notifications JSON‑RPC ne sont pas liées à un id spécifique et ne sont pas perçues par le client comme une réponse à une requête. Il en résulte un débogage plus difficile et l’impossibilité de savoir à quel appel d’outil se rapporte un message donné. Les notifications conviennent très bien aux événements (changement des tools/resources/prompts, nouvelle progression, log reçu), mais pas aux réponses classiques à tools/call et consorts.
Erreur n°6 : ne pas regarder les logs et inspecteurs MCP.
L’erreur la plus humaine — essayer de déboguer l’intégration uniquement via l’UI de ChatGPT : « j’ai cliqué, rien n’est arrivé, je verrai plus tard ». Tant que vous ne voyez pas les messages MCP bruts (requests, replies, notifications), il est difficile de comprendre à quel niveau se situe le problème : le modèle n’a pas appelé le tool, Apps SDK n’a pas atteint le serveur MCP, le serveur a renvoyé un JSON incorrect, ou tout a cassé lors du rendu du widget. MCP Inspector / Jam et un logging structuré des messages MCP sont vos meilleurs alliés. Après avoir vu une fois un tools/call et un tools/list en conditions réelles dans les logs, le format des messages MCP cessera d’être de la « magie » et deviendra une simple routine d’ingénierie.
GO TO FULL VERSION