ChatGPT MCP Events : créez pas à pas votre première automatisation de plugin déclenchée par événement
Les ChatGPT MCP Events permettent à ChatGPT de s'abonner aux changements de vos systèmes et d'y réagir. Ce guide présente la construction sous forme de boucle Advertise-Subscribe-Verify-Deliver (ASVD). Vous déclarez la capacité et events/list, rendez les abonnements idempotents, vérifiez les callbacks, signez les livraisons au format Standard Webhooks et testez avant la mise en production. Il signale aussi les points où la spécification provisoire et les SDK évoluent encore.
Avec MCP Events, ChatGPT s'abonne aux mises à jour de votre serveur MCP, et les utilisateurs choisissent ce qu'ils veulent surveiller et ce que ChatGPT doit faire à l'arrivée d'une mise à jour. Si votre équipe exploite déjà un serveur MCP ou une API SaaS, vous constaterez peut-être qu'un connecteur peut désormais lancer une automatisation de lui-même au lieu d'attendre un prompt.
Nous allons suivre la construction dans l'ordre où vous écrirez le code. Nous l'appelons la boucle Advertise-Subscribe-Verify-Deliver (ASVD) : déclarer les événements que vous émettez, rendre les abonnements idempotents, vérifier chaque callback avant sa mise en service, puis livrer des événements signés avec des relances qui savent quand s'arrêter. Nous signalerons aussi les endroits où la spécification reste à l'état de brouillon, car certains de ces détails non tranchés se retrouvent dans votre code.
Ce que sont les MCP Events et ce que ChatGPT prend réellement en charge
La documentation développeur d'OpenAI reste brève : ChatGPT s'abonne aux mises à jour de votre serveur MCP, comme de nouveaux messages, des mises à jour de contenu ou des changements de statut, et l'utilisateur décide de la suite. L'esquisse de conception provisoire vise plus haut. Elle veut qu'un client MCP puisse s'abonner à des événements d'un système en amont, comme un message Slack, un push GitHub ou un incident PagerDuty, afin que l'agent puisse réagir sans que l'utilisateur soit présent.
Le point de conception le plus important est ce que ChatGPT laisse de côté. ChatGPT prend en charge la livraison par webhook et la vérification des callbacks issues de la spécification provisoire MCP Events. Le polling, le streaming et les notifications de contrôle gap et terminated du brouillon ne sont pas pris en charge par cette intégration.
| Fonctionnalité de la spécification provisoire | Prise en charge par ChatGPT | Ce qu'il faut construire pour ChatGPT |
|---|---|---|
| Livraison par webhook | Oui | La construire, la signer, la relancer |
| Vérification des callbacks | Oui | La construire avant d'activer tout abonnement |
| Polling | Non | À ignorer pour cette intégration |
| Streaming (mode push) | Non | À ignorer pour cette intégration |
| Notifications de contrôle gap et terminated | Non | À ignorer pour cette intégration |
Svix, une entreprise d'infrastructure de webhooks, qualifie ChatGPT de premier client majeur à prendre en charge MCP Events. Elle précise aussi que votre serveur livre les événements à ChatGPT au format Standard Webhooks. Un guide de construction tiers publié sur DEV Community indique que la prise en charge par ChatGPT a commencé lors de l'OpenAI DevDay du 29 septembre 2026, avec la version de protocole 2026-07-28. Confirmez ces deux éléments dans la documentation d'OpenAI avant de coder quoi que ce soit en dur autour d'eux.
Construisez donc pour les webhooks et rien d'autre. Des chemins de code pour le polling et le push en streaming demanderaient de la maintenance tant qu'ils existeraient, sans rien apporter à cette intégration.
Avant de construire : la réalité des SDK et l'état de la spécification
Après le DevDay, un développeur a signalé sur l'OpenAI Developer Community que le SDK Python officiel (mcp 2.2.0) ne prenait pas encore en charge MCP Events, et que le SDK TypeScript non plus. Cela a pu changer, alors lisez les notes de version actuelles. Nous prévoirions malgré tout du temps pour un peu de plomberie écrite à la main.
Go est mieux loti. Un ticket ouvert sur le SDK Go note que sa prise en charge des méthodes personnalisées permet déjà d'implémenter events/list, events/subscribe et events/unsubscribe. Ce qui manque, c'est un moyen de déclarer la capacité events de premier niveau.
La spécification elle-même continue d'évoluer. La charte du groupe de travail indique que les clients apprennent actuellement les mises à jour côté serveur en faisant du polling ou en maintenant une connexion SSE ouverte, et que le groupe prévoit de spécifier un mécanisme de callback standardisé pour que les serveurs puissent plutôt pousser des notifications. Le 2026-10-16, le groupe a été renommé Tasks and Events WG et a repris le périmètre Tasks de l'Agents WG. Attendez-vous à d'autres révisions.
Notre conseil est d'écrire dès maintenant des handlers personnalisés légers et de bien les isoler. Donnez aux handlers des méthodes JSON-RPC leur propre module, et faites de même pour le stockage des abonnements ainsi que pour la signature et la livraison. Quand la prise en charge par les SDK arrivera, vous remplacerez la couche protocolaire et votre logique métier ne bougera pas.
Étape 1 de l'ASVD (Advertise) : déclarer la capacité et définir events/list
Déclarer la capacité events
Votre serveur doit déclarer la capacité events de premier niveau lors de l'initialisation. Nous suggérons de traiter cette déclaration comme un élément bloquant pour le lancement plutôt que comme un détail à régler plus tard. Dans le SDK Go, c'est précisément la lacune décrite par le ticket ouvert, alors vérifiez où il en est avant de choisir un contournement.
Concevoir chaque type d'événement pour deux lecteurs
Nous suggérons de concevoir chaque entrée de events/list autour de ces éléments :
- Un nom clair qui reste stable dans le temps.
- Une description qui convient aussi bien à l'utilisateur qu'au modèle. L'utilisateur la lit en choisissant ce qu'il veut surveiller ; le modèle la lit en décidant quoi faire.
- Un inputSchema définissant les filtres qu'un abonné peut fixer.
- Un payloadSchema décrivant exactement ce que vous enverrez.
L'exemple ci-dessous est illustratif. Vérifiez les noms de champs exacts dans la documentation d'OpenAI avant de le copier.
{
"name": "ticket.status_changed",
"description": "A support ticket in a project you can access changed status.",
"inputSchema": {
"type": "object",
"properties": {
"project_id": { "type": "string" },
"status": { "type": "string", "enum": ["open", "pending", "closed"] }
},
"required": ["project_id"]
},
"payloadSchema": {
"type": "object",
"properties": {
"ticket_id": { "type": "string" },
"new_status": { "type": "string" },
"summary": { "type": "string" }
}
}
}Gardez des filtres étroits et parlants pour l'utilisateur. Un projet ou un statut de ticket fonctionne bien : les gens reçoivent les événements qu'ils ont demandés et peu d'autres. Traitez le payloadSchema comme un contrat public : versionnez-le, ne le cassez pas et gardez des payloads légers.
Limiter les événements à l'utilisateur authentifié
Le brouillon précise que l'autorisation utilise le même principal MCP que vos outils. En pratique, ne listez que les types d'événements que l'utilisateur authentifié a le droit de voir, et n'acceptez que les filtres qui pointent vers des ressources auxquelles cet utilisateur a accès.
Étape 2 de l'ASVD (Subscribe) : events/subscribe et events/unsubscribe idempotents
Les clients relancent. Les réseaux perdent des réponses. Si une requête d'abonnement répétée crée un second abonnement, chaque événement part en double et l'automatisation de quelqu'un se déclenche deux fois. Concevez les deux méthodes de sorte qu'un nouvel appel ne change rien.
Subscribe
Stockez chaque abonnement avec son type d'événement, ses filtres normalisés, son URL de callback, son secret de signature et son propriétaire. Construisez une clé déterministe à partir du propriétaire, du type d'événement, des filtres normalisés et de l'URL de callback. Quand un utilisateur autorisé répète la requête, il récupère l'abonnement existant.
authorize(owner_id, event_name, filters) // always first, even on repeats
key = hash(owner_id, event_name, canonical_json(filters), callback_url)
if store.exists(key): return store.get(key)
verify_callback(callback_url) // ASVD Step 3
sub = store.create(key, secret=new_secret(), status="active")
return subL'autorisation passe volontairement avant la vérification d'existence. Inversez-les, et un utilisateur dont l'accès a été révoqué pourrait renvoyer un ancien appel subscribe et récupérer discrètement l'abonnement.
Unsubscribe
Unsubscribe doit pouvoir être appelé deux fois sans risque. Si l'abonnement n'existe déjà plus, renvoyez un succès, pas une erreur. L'appelant voulait qu'il soit supprimé, et c'est le cas.
Persistance et autorisation
Conservez les abonnements dans un stockage durable. Une map en mémoire perd tout au déploiement suivant, et les livraisons s'arrêtent sans la moindre erreur visible. Vérifiez l'autorisation au moment de l'abonnement puis de nouveau au moment de la livraison, car l'accès peut être révoqué entre-temps.
Il vous faut aussi un chemin de nettoyage. La documentation d'OpenAI indique de ne pas relancer une livraison qui renvoie 410. Selon notre lecture, le destinataire ne veut plus de l'abonnement : marquez-le donc comme retiré plutôt que de le laisser échouer à chaque événement futur.
Étape 3 de l'ASVD (Verify) : confirmer le callback avec le défi signé
Avant qu'un abonnement ne devienne actif, envoyez un défi de vérification signé (challenge) à l'URL de callback et confirmez la réponse attendue. Ainsi, votre serveur ne pousse jamais d'événements vers un endpoint qui n'a pas prouvé qu'il est bien le destinataire prévu.
Si la vérification échoue, la documentation d'OpenAI indique de renvoyer l'erreur JSON-RPC -32015 (CallbackEndpointError) avec un data.reason catégorisé, comme challenge_failed ou timeout.
Soyez attentif aux divergences ici. L'esquisse provisoire actuelle indique que ses révisions antérieures utilisaient la plage -32011 à -32015, une sous-plage que la spécification n'attribue jamais, et que les implémentations de ces révisions doivent renuméroter. Autrement dit, le code figurant dans la documentation d'OpenAI provient d'une ancienne révision de l'esquisse. Suivez pour l'instant la documentation d'OpenAI, puisque ChatGPT est le client pour lequel vous construisez, et définissez le code une seule fois sous forme de constante nommée pour qu'un futur changement se résume à une modification d'une ligne.
Donnez à la requête de défi un délai d'expiration borné et journalisez la catégorie de raison à chaque échec. Quand un utilisateur vous dit que son automatisation n'a jamais démarré, cette ligne de log est le premier endroit à consulter. Si vous instrumentez déjà les exécutions d'agents, notre playbook de traçage OpenTelemetry GenAI est l'endroit naturel pour la télémétrie de vérification et de livraison.
Étape 4 de l'ASVD (Deliver) : signer et envoyer les événements au format Standard Webhooks
Les livraisons suivent la spécification Standard Webhooks. Selon Svix, X-MCP-Subscription-Id est le seul en-tête propre à MCP, et il indique au destinataire avec quel abonnement, et donc quel secret, vérifier la signature.
Taille et forme
La documentation d'OpenAI indique d'envoyer un événement par requête, avec un corps de requête complet ne dépassant pas 256 KiB (262,144 octets). ChatGPT peut regrouper des événements livrés séparément dans une même exécution de tâche, selon les paramètres de regroupement de la tâche. Ne considérez pas 256 KiB comme un objectif. Standard Webhooks recommande de garder des payloads petits, généralement sous 20 KB. Envoyez des identifiants et un court résumé, et laissez ChatGPT appeler vos outils quand il a besoin de l'enregistrement complet.
Relances et conditions d'arrêt
La documentation d'OpenAI indique de relancer les échecs transitoires avec un backoff exponentiel et un nombre de tentatives borné, en conservant l'ID d'événement et en générant un nouvel horodatage de signature et une nouvelle signature à chaque tentative. Conserver le même ID d'événement donne au destinataire de quoi dédupliquer, et le nouvel horodatage ainsi que la nouvelle signature évitent que la requête soit rejetée comme périmée.
La documentation d'OpenAI indique aussi de ne pas relancer les livraisons qui renvoient 410 ou 413. Quand une livraison est refusée de cette façon, nous suggérons de revoir l'état de vos abonnements et la conception de vos payloads plutôt que de renvoyer la requête.
| Résultat de la livraison | Ce que votre serveur doit faire |
|---|---|
| 2xx | Marquer comme livré |
| Timeout ou 5xx transitoire | Relancer avec backoff exponentiel, même ID d'événement, nouvel horodatage et nouvelle signature, tentatives bornées, selon la documentation d'OpenAI |
| 410 | Ne pas relancer, selon la documentation d'OpenAI ; retirer l'abonnement est une réponse raisonnable |
| 413 | Ne pas relancer, selon la documentation d'OpenAI ; le traiter comme un bug de conception du payload |
Standard Webhooks recommande un délai d'expiration de requête de 15 à 30 secondes. Choisissez votre valeur délibérément au lieu d'hériter de celle livrée par défaut avec votre bibliothèque HTTP.
Utiliser une bibliothèque officielle
Signez avec une bibliothèque Standard Webhooks officielle, comme la bibliothèque JavaScript Standard Webhooks ou la bibliothèque officielle de votre stack, au lieu d'écrire votre propre code HMAC. Une bibliothèque construite selon la spécification est le moyen le plus sûr de produire des signatures que les destinataires peuvent vérifier.
Tester avant de livrer : une checklist ASVD avant mise en production
Parcourez cette liste en préproduction, connecté à un véritable abonnement ChatGPT, avant la mise en production. Chaque élément sollicite une étape de la boucle.
Les relances conservent l'ID d'événement, renouvellent la signature et s'arrêtent sur 410 et 413.
- [ ] Advertise, filtres : les événements hors des filtres d'un abonnement ne sont jamais livrés. Testez avec des événements qui correspondent à certains filtres mais pas à tous.
- [ ] Subscribe, doublons : répéter un appel subscribe renvoie l'abonnement existant et ne crée rien de nouveau.
- [ ] Subscribe, désabonnement : après un désabonnement, plus rien ne part, y compris les relances déjà en file d'attente. Un second appel unsubscribe renvoie un succès.
- [ ] Subscribe, redémarrages : après un redémarrage et un redéploiement, les abonnements et les secrets persistent et les livraisons reprennent.
- [ ] Subscribe, autorisation : révoquez l'accès d'un utilisateur à une ressource filtrée. Les livraisons la concernant s'arrêtent, et un appel subscribe répété est refusé.
- [ ] Verify, défi de callback : exécutez un défi qui réussit et un qui échoue. L'échec renvoie le code d'erreur documenté avec un data.reason.
- [ ] Deliver, événements rejoués : rejouez le même ID d'événement et notez ce qu'en fait ChatGPT. Ne supposez pas une déduplication que vous n'avez pas observée.
- [ ] Deliver, limites de taille : les payloads juste en dessous et juste au-dessus de 256 KiB sont chacun traités comme vous l'aviez prévu.
Erreurs courantes lors de la construction de serveurs MCP Events
- Construire des modes que personne n'appelle. Le polling, le streaming et les notifications gap ou terminated ne font pas partie de l'intégration de ChatGPT. Les heartbeats entrent dans la même catégorie. Le brouillon indique qu'un serveur doit envoyer un heartbeat au moins toutes les 30 secondes, mais cela s'applique au streaming en mode push, que ChatGPT ne prend pas en charge.
- Faire les relances à l'envers. Un nouvel ID d'événement à chaque relance prive le destinataire de sa clé de déduplication. Réutiliser l'ancien horodatage et l'ancienne signature expose à un rejet pour péremption.
- Relancer des impasses. La documentation d'OpenAI indique de ne pas relancer les livraisons qui renvoient 410 ou 413. Le même corps sera de nouveau rejeté.
- Envoyer des enregistrements entiers. Des documents complets font grossir les payloads vers 256 KiB alors que Standard Webhooks suggère de rester sous 20 KB.
- Garder les abonnements en mémoire. Ils disparaissent au redémarrage, et rien ne vous avertit.
- Faire confiance au texte des payloads. Quand un événement transporte du texte généré par un utilisateur, par exemple un message client, ce texte peut contenir des instructions destinées au modèle. Traitez les payloads comme des entrées non fiables, de la même façon que les résultats d'outils, et supprimez ce texte ou délimitez-le clairement.
Mises en garde : dérive de la spécification et limites opérationnelles
La spécification est un brouillon. Le code d'erreur d'OpenAI et la renumérotation de l'esquisse actuelle divergent déjà, et le groupe de travail ajuste encore son périmètre. Construisez en vous appuyant sur la documentation d'OpenAI et relisez-la régulièrement.
Votre code personnalisé est temporaire. La prise en charge par les SDK est inégale. Prévoyez de remplacer les handlers une fois la prise en charge officielle disponible.
L'automatisation sans surveillance a besoin de garde-fous. Avant qu'une tâche déclenchée par un événement ne touche des systèmes de production, décidez quelles actions elle peut effectuer sans validation humaine. Ajoutez des journaux d'audit et des limites de débit, et donnez à chaque abonnement son propre coupe-circuit. Pour en savoir plus sur la réduction de ce qu'une tâche déclenchée peut atteindre, consultez notre note sur la manière de contenir la portée d'un agent compromis. Si le travail déclenché se transforme en tâches multi-étapes, notre checklist de sélection d'un runtime pour agents IA durables peut vous aider à décider où cet état doit résider.
Confirmez les informations de seconde main. La date de lancement et la version de protocole mentionnées plus haut proviennent en partie de guides tiers. Vérifiez-les dans la documentation d'OpenAI.
Points clés
- 1Construisez selon la boucle Advertise-Subscribe-Verify-Deliver (ASVD) : déclarez les événements, abonnez de façon idempotente, vérifiez les callbacks, puis livrez des événements signés.
- 2ChatGPT ne prend en charge que la livraison par webhook et la vérification des callbacks de la spécification provisoire MCP Events : ignorez le polling, le streaming et les notifications gap et terminated.
- 3Exécutez l'autorisation avant de renvoyer un abonnement existant, rendez subscribe et unsubscribe idempotents et conservez les abonnements dans un stockage durable.
- 4Vérifiez chaque URL de callback avec un défi signé avant activation. Gardez le code d'erreur d'échec dans une seule constante, car le brouillon l'a renuméroté.
- 5La documentation d'OpenAI plafonne chaque corps de requête à un seul événement à 256 KiB, mais Standard Webhooks recommande des payloads sous 20 KB.
- 6La documentation d'OpenAI indique de ne pas relancer un 410 ou un 413, et de relancer les échecs transitoires avec le même ID d'événement et une nouvelle signature.
- 7Les SDK officiels Python et TypeScript ne prenaient pas en charge MCP Events au lancement et le SDK Go ne peut pas encore déclarer la capacité : isolez les handlers personnalisés.
Conclusion
Svix qualifie ChatGPT de premier client majeur à prendre en charge MCP Events. Pour les équipes qui exploitent déjà un serveur MCP ou une API SaaS, c'est donc un moment raisonnable pour laisser les changements de vos propres systèmes déclencher du travail dans ChatGPT, au lieu d'attendre des prompts saisis à la main. L'essentiel de la construction relève de l'ingénierie de webhooks que vous avez probablement déjà pratiquée, organisée selon la boucle ASVD.
Les parties délicates sont celles qui bougent encore. Les codes d'erreur du brouillon ont déjà changé une fois, et la prise en charge par les SDK est inégale. Il reste aussi une question de sécurité qui mérite une vraie réflexion : que doit-on autoriser une tâche sans surveillance à faire avec un texte de payload qu'elle n'a pas écrit ?
Notre approche suggérée est modeste. Livrez un seul type d'événement, étroit et bien filtré. Faites-le passer par la checklist avant mise en production, puis surveillez-le en production avec des logs et un coupe-circuit prêt à l'emploi. Gardez le code protocolaire personnalisé léger et séparé de la logique métier, pour qu'un futur changement de spécification coûte une petite modification plutôt qu'une réécriture. Ajoutez d'autres types d'événements une fois que le premier s'est montré fiable pendant un certain temps.
Questions fréquentes
Que sont les ChatGPT MCP Events ?
Les MCP Events permettent à ChatGPT de s'abonner aux mises à jour de votre serveur MCP, comme de nouveaux messages, des mises à jour de contenu ou des changements de statut. La documentation d'OpenAI indique que ChatGPT prend en charge la livraison par webhook et la vérification des callbacks issues de la spécification provisoire MCP Events. Les utilisateurs choisissent ce qu'ils surveillent et ce que ChatGPT doit faire à l'arrivée d'une mise à jour, de sorte qu'un connecteur peut lancer une automatisation sans attendre un prompt.
ChatGPT prend-il en charge le polling ou le streaming pour les MCP Events, ou uniquement les webhooks ?
Uniquement les webhooks. La documentation d'OpenAI indique que ChatGPT prend en charge la livraison par webhook et la vérification des callbacks issues de la spécification provisoire MCP Events. Le polling, le streaming et les notifications de contrôle gap et terminated du brouillon ne sont pas pris en charge par cette intégration : vous pouvez donc laisser ces chemins de code de côté.
Quelle est la taille maximale de payload d'événement acceptée par ChatGPT, et quelle taille les payloads devraient-ils réellement avoir ?
La documentation d'OpenAI indique que ChatGPT accepte un événement par requête avec un corps complet ne dépassant pas 256 KiB (262,144 octets). Considérez cela comme un plafond. La spécification Standard Webhooks recommande de garder des payloads petits, généralement sous 20 KB. En pratique, envoyez des identifiants et de courts résumés, et laissez ChatGPT récupérer les enregistrements complets via vos outils.
Comment les relances doivent-elles fonctionner, et quelles réponses HTTP signifient que je dois arrêter de relancer ?
La documentation d'OpenAI indique de ne pas relancer les livraisons qui renvoient 410 ou 413. Nous suggérons de traiter l'une ou l'autre de ces réponses comme une invitation à modifier quelque chose de votre côté, comme le statut de l'abonnement ou la conception de vos payloads, plutôt que de réessayer. La documentation d'OpenAI indique aussi de relancer les échecs transitoires avec un backoff exponentiel et un nombre de tentatives borné, en conservant l'ID d'événement et en générant un nouvel horodatage de signature et une nouvelle signature à chaque tentative.
Quelle erreur mon serveur doit-il renvoyer quand la vérification du callback échoue, et pourquoi le code pourrait-il changer ?
La documentation d'OpenAI indique de renvoyer l'erreur JSON-RPC -32015 (CallbackEndpointError) avec un data.reason catégorisé, comme challenge_failed ou timeout. L'esquisse provisoire actuelle indique toutefois que les révisions antérieures utilisaient la plage -32011 à -32015 et que les implémentations doivent renuméroter. Suivez la documentation d'OpenAI pour ChatGPT, gardez le code dans une seule constante et revérifiez régulièrement la documentation.
Puis-je utiliser les SDK MCP officiels Python, TypeScript ou Go pour construire des MCP Events aujourd'hui ?
En partie. Un développeur de la communauté a signalé que le SDK Python officiel (mcp 2.2.0) et le SDK TypeScript ne prenaient pas en charge MCP Events au lancement. Dans le SDK Go, vous pouvez implémenter events/list, events/subscribe et events/unsubscribe comme méthodes personnalisées, mais la déclaration de la capacité events de premier niveau manque encore. Vérifiez les versions actuelles et gardez les handlers personnalisés isolés pour pouvoir les remplacer plus tard.
Sources
- https://developers.openai.com/plugins/build/mcp-events
- https://github.com/modelcontextprotocol/experimental-ext-triggers-events/blob/main/docs/design-sketch-proposal.md
- https://modelcontextprotocol.io/community/working-groups/tasks-events
- https://github.com/standard-webhooks/standard-webhooks/blob/main/spec/standard-webhooks.md
- https://github.com/standard-webhooks/standard-webhooks/tree/main/libraries/javascript
- https://www.svix.com/blog/mcp-events/
- https://dev.to/hassann/mcp-events-explained-build-and-test-a-webhook-emitting-mcp-server-chatgpt-can-subscribe-to-4od8
- https://community.openai.com/t/mcp-events-for-the-official-python-mcp-sdk-tested-end-to-end-with-chatgpt/1402999
- https://github.com/modelcontextprotocol/go-sdk/issues/1325
- https://community.openai.com/t/devday-2026-announcements-and-developer-resources/1402006
Rédigé par
Hamza DiazHamza Diaz est le fondateur d’Optijara, où il conçoit des agents IA pratiques, des systèmes d’automatisation et des workflows Copilot pour les entreprises de services. Il écrit sur les opérations IA, la stratégie d’agents et la mise en œuvre concrète pour les équipes qui veulent des systèmes utiles plutôt que du battage médiatique.
