CodeGym /Cours /ChatGPT Apps /Architecture de la pile des applications ChatGPT

Architecture de la pile des applications ChatGPT

ChatGPT Apps
Niveau 1 , Leçon 1
Disponible

1. Introduction

Si l’on considère une ChatGPT App comme « un autre serveur Web », on aboutit très vite à un zoo architectural : un Next.js ici, un serveur MCP là, un agent ailleurs, un backend commerce — et tout cela se mélange dans la tête en un grand « serveur » unique.

Il est bien plus utile d’adopter dès le départ l’idée d’un mille‑feuille :

  • au‑dessus — l’UI ChatGPT, que nous ne contrôlons pas, mais à laquelle nous nous adaptons ;
  • en dessous — notre widget sur l’Apps SDK (Next.js 16, React 19), rendu dans le chat ;
  • plus bas — un serveur MCP avec des outils (tools/resources/prompts) ;
  • facultatif — une couche d’agents qui orchestre des scénarios complexes ;
  • et tout en bas — vos services « terrestres » : BD, API externes, commerce/ACP (protocole pour les scénarios de commerce), etc.

Dans le mémo du cours, ce chemin peut se dessiner comme une chaîne :

User ChatGPT Widget Apps SDK MCP Gateway (Auth) Agent Service ACP / Stripe.

Notre objectif maintenant est de transformer cette chaîne en un modèle mental clair.

2. Schéma d’ensemble de la pile

Commençons par la vue d’ensemble, puis passons couche par couche.

flowchart TD
    U[Utilisateur dans ChatGPT] --> C["ChatGPT UI chat + panneau Apps"]
    C --> W["Widget de votre app (Apps SDK, Next.js)"]
    W --> M["Serveur MCP (tools/resources/prompts)"]
    M --> AG["Agent(s) (Agents SDK, orchestration)"]
    AG --> B["Backends et ACP BD, services, paiement"]

Il est important de noter plusieurs points.

Premièrement, l’utilisateur ne voit que deux niveaux : l’UI de ChatGPT et votre widget. Tout ce qui est en dessous — les « coulisses ».

Deuxièmement, le protocole MCP n’est pas un acronyme aléatoire, mais un standard officiel par lequel l’Apps SDK communique avec vos outils : le serveur doit savoir énumérer les tools, accepter call_tool et retourner un lien vers une ressource UI à rendre dans ChatGPT.

Troisièmement, les couches Agents et ACP sont formellement optionnelles, mais dans des applications commerciales réelles elles apparaissent presque toujours : il faut parfois planifier un scénario multi‑étapes, ailleurs — encaisser des paiements.

Voyons maintenant chaque couche séparément.

Insight: ChatGPT est un framework

L’intégration avec ChatGPT n’est pas située en un seul endroit — elle est répartie sur un grand nombre de points d’intégration. Pour un développeur, cela rappelle fortement le travail avec un framework. Le framework décide lui‑même quand et où appeler votre code ; vous n’avez qu’à écrire les bonnes choses aux bons endroits.

Avec ChatGPT, c’est exactement ainsi :

  • les widgets — se déclarent via mcp-resources, GPT décide lui‑même quand les afficher
  • mcp-tools — GPT décide lui‑même quand les appeler
  • product feed — peut être ajouté au modèle via un mcp-tool, mais la variante standard — via site register merchant
  • ACP/InstantCheckout — API séparée
  • Authentification — serveur d’authentification MCP séparé.

3. Couche 1 — ChatGPT UI : notre « hôte »

ChatGPT UI est l’interface Web (et mobile) d’OpenAI, où l’utilisateur conduit la conversation principale. On y trouve le champ de saisie habituel, l’historique des messages, les boutons de sélection de modèle et l’onglet des applications (Store/Composer).

Cette couche, nous ne la programmons pas. Nous n’avons pas accès à son code, ni au DOM, ni aux styles. Mais elle impose un cadre :

  • c’est ici que l’utilisateur « choisit » explicitement votre application (via le Store/Composer) ou implicitement (le modèle propose lui‑même l’App) ;
  • c’est ici que ChatGPT décide : répondre en texte, appeler votre tool, rendre un widget ou faire tout cela à la fois ;
  • c’est ici que vivent les patterns UX de base : widget inline, mode plein écran, fenêtre PiP, etc. (détails au module 8).

D’un point de vue pratique, retenez que ChatGPT UI est notre application hôte. Nous nous y intégrons, et non l’inverse. Le serveur GPT chargera le code de votre widget sur son propre serveur, le nettoiera de tout superflu et ne l’intègrera dans son chat que depuis son propre domaine.

4. Couche 2 — Apps SDK et widget (Next.js 16 dans le chat)

La couche suivante est votre code UI, écrit en React/Next.js avec l’Apps SDK.

Le modèle mental est simple : c’est comme un mini‑SPA, rendu en widget intégré dans le chat. Mais avec quelques réserves :

  • votre code s’exécute dans un bac à sable : DOM limité, règles spécifiques pour les requêtes réseau, objet particulier window.openai pour communiquer avec ChatGPT (cours séparé à ce sujet) ;
  • le widget ne contrôle pas le flux du dialogue : l’utilisateur écrit dans le chat global, le modèle décide quand appeler votre App, et vous répondez uniquement dans votre « cadre » ;
  • l’Apps SDK prend tout en charge : synchronisation de l’état du widget avec l’historique du dialogue, traitement des résultats de tools, travail avec MCP, etc.

Pour un développeur Next.js, cela paraît assez familier : vous avez des pages/composants, des hooks, des props. Mais au lieu d’un fetch('/api/...') classique, vous vous appuierez plus souvent sur des outils (tools) décrits dans le serveur MCP et sur des hooks spécifiques de l’Apps SDK (vus plus tard dans le cours).

Pour concrétiser un peu, rappelons notre projet — un GiftGenius fictif. Cette App aide à choisir des cadeaux selon des paramètres : pour qui, quel budget, à quelle occasion, etc.

Un tout petit bout d’UI futur (sans spécificités SDK pour l’instant, juste l’idée) :

// GiftSummary.tsx — un composant React simple de notre app
type GiftIdea = {
  id: string;
  title: string;
  price: number;
};

interface GiftSummaryProps {
  ideas: GiftIdea[];
}

export function GiftSummary({ ideas }: GiftSummaryProps) {
  return (
    <ul>
      {ideas.map((idea) => (
        <li key={idea.id}>
          {idea.title} — ${idea.price}
        </li>
      ))}
    </ul>
  );
}

Plus tard, ce composant recevra les ideas non pas de nulle part, mais du résultat d’un outil du serveur MCP (ToolOutput). Au niveau de l’architecture, l’important est ailleurs : tout ce code vit dans la « deuxième couche » et s’occupe uniquement de l’affichage de l’état.

5. Couche 3 — serveur MCP : l’univers des outils et des données

Descendons maintenant dans la partie serveur.

Model Context Protocol (MCP) est un standard qui décrit comment un client LLM (ChatGPT, Apps SDK, Agents) communique avec votre serveur. Il définit quels outils sont disponibles, leurs schémas d’entrée/sortie, comment les appeler et quelles autres ressources/prompts charger.

Un serveur MCP minimal pour l’Apps SDK doit savoir faire trois choses :

  • renvoyer la liste des outils (List tools) avec leurs JSON Schema et métadonnées ;
  • gérer les appels d’outils (Call tools) — accepter une requête call_tool, exécuter la logique métier et renvoyer un résultat structuré ;
  • renvoyer du html, js, css, … — facultatif, si le tool est lié à un widget spécifique à afficher.

Point important : MCP est un protocole indépendant du transport. Pour les ChatGPT Apps, nous nous intéressons à sa variante HTTP avec implémentation streamable/flux, mais les détails de transport et le format des messages relèvent du module MCP (niveau 6). Pour l’instant, retenez que l’Apps SDK s’adresse « en dessous » au serveur MCP, et non à des endpoints REST arbitraires.

Architecturalement, la couche MCP ressemble souvent à un microservice séparé :

flowchart LR
    subgraph App["Votre ChatGPT App"]
      W["Widget (Next.js + Apps SDK)"]
      M["Serveur MCP (@modelcontextprotocol/sdk)"]
    end

    W <-- JSON-RPC over HTTP/SSE --> M
    M --> DB[(Catalogue de cadeaux)]
    M --> EXT[API externes]

À l’intérieur du serveur MCP, vous écrivez du code TypeScript/Node « normal », utilisez des bases de données, des files, des API tierces, etc. Le SDK TypeScript officiel pour MCP prend en charge la sérialisation JSON‑RPC, la validation des schémas et le routage des appels.

Pour notre GiftGenius, l’un des outils MCP peut s’appeler par exemple search_gifts. En TypeScript, cela peut ressembler à une fonction tout à fait classique :

// Pseudo-code : logique métier dans le serveur MCP
export async function searchGifts(params: {
  recipient: string;
  budget: number;
}) {
  // ici, vous interrogez déjà la BD/le catalogue
  const items = await findGiftsInCatalog(params);
  return items.slice(0, 10);
}

Nous l’envelopperons plus tard dans un tool MCP avec une description de schéma, mais l’essentiel est : cette couche est votre « vrai » backend, qui parle au monde via MCP.

6. Couche 4 — Agents SDK : le cerveau des scénarios complexes

Toutes les applications n’ont pas besoin d’agents, mais dès que le scénario n’est plus « un appel d’outil — une réponse », la couche agent devient très utile.

Un agent est, en substance, un processus LLM piloté, qui :

  • lit la requête de l’utilisateur et les faits issus de l’historique du dialogue ;
  • planifie la séquence d’étapes : quels outils appeler, dans quel ordre, avec quels arguments ;
  • analyse les résultats, peut décider de « ré‑appeler un tool », « demander une précision à l’utilisateur », « construire une réponse plus élaborée » ;
  • parfois conserve un état entre les étapes (mémoire, sessions, checkpoints — niveau 12).

L’Agents SDK fournit une manière structurée de décrire ces scénarios : quels outils sont disponibles pour l’agent, comment stocker et restaurer l’état, comment limiter les boucles, etc. Les agents s’exécutent dans le backend et permettent d’utiliser la puissance d’OpenAI comme vous l’entendez, sans les contraintes des widgets des ChatGPT Apps.

Dans notre pile, l’agent se trouve généralement dans le backend, entre la couche MCP et vos API métiers. Il peut utiliser des API externes, des fonctions internes et des MCP‑tools comme « mains », tout en assurant le « cerveau ».

Par exemple, un scénario GiftGenius peut ressembler à ceci :

  1. L’utilisateur écrit « trouve un cadeau pour ma mère jusqu’à 50 $ ».
  2. ChatGPT appelle le tool search_gifts de votre application.
  3. Derrière le tool search_gifts côté backend se trouve un Agent, qui décide de demander d’abord quelques précisions (centres d’intérêt, occasion).
  4. L’utilisateur ajoute des souhaits supplémentaires.
  5. ChatGPT appelle à nouveau le tool search_gifts de votre application avec des arguments supplémentaires.
  6. L’Agent sur le serveur peut appeler des outils additionnels (par exemple, vérification de disponibilité).
  7. Il renvoie à ChatGPT des options déjà préparées et, éventuellement, un lien vers un widget pour la visualisation.

Nous détaillerons plus tard le cycle d’exécution (run‑cycle) d’un agent, l’idempotence et la sécurité. Pour l’architecture générale, retenez : la couche agent est optionnelle mais très puissante — elle retire une partie de l’orchestration complexe de vos épaules.

7. Couche 5 — ACP/Backend : argent, données et soucis terrestres

La couche la plus basse — vos services habituels :

  • bases de données (catalogues produits, utilisateurs, commandes) ;
  • API externes (prestataires de paiement, logistique, SaaS tiers) ;
  • protocoles spécialisés comme ACP (Agentic Commerce Protocol) pour les scénarios de commerce et Instant Checkout.

ACP décrit comment ChatGPT et les agents dialoguent avec votre backend de commerce : requêtes pour sélectionner des SKU, création de panier, passage de commande, retours, webhooks sur opérations réussies/échouées, etc.

Pour GiftGenius, ce sera à peu près ainsi :

  • le MCP‑tool search_gifts lit depuis le product feed/la BD ;
  • l’agent, après avoir choisi un produit, initie une intention de commerce (via ACP) ;
  • votre backend compatible ACP dit à PaymentService : « on débite », informe ChatGPT du statut ;
  • l’utilisateur voit dans ChatGPT que la commande est passée, sans aller sur un site externe.

Maintenant que nous avons parcouru les couches, regardons un scénario concret de bout en bout.

8. Scénario de bout en bout : comment la requête de l’utilisateur traverse toutes les couches

Prenons la requête : « Trouve un cadeau pour ma mère jusqu’à 50 dollars, elle aime lire et le thé ».

Décomposons‑la en étapes.

  1. L’utilisateur écrit du texte dans ChatGPT. C’est la première couche — l’UI de ChatGPT. Pour lui, tout ressemble à un chat classique.
  2. Le modèle lit l’historique du dialogue, les métadonnées de votre App (descriptions, catégories, permissions) et décide que GiftGenius est un candidat pertinent. Selon les règles de discovery de l’Apps SDK, le modèle tient compte des descriptions textuelles des tools, de l’usage passé, du contexte et même des mentions de marque.
  3. ChatGPT soit :
    • appelle immédiatement un outil de votre App sans UI (scénario tool‑first) ;
    • soit propose dans la réponse : « Je peux utiliser GiftGenius pour aider à choisir un cadeau » et appelle votre tool.
  4. ChatGPT envoie au serveur MCP une requête call_tool pour l’outil search_gifts. Le serveur MCP exécute alors la logique métier : interroge la BD/le feed, filtre par budget et préférences et retourne un JSON avec des produits adaptés.
  5. Le résultat de l’outil revient à ChatGPT. Il peut :
    • simplement l’utiliser comme données pour une réponse textuelle (« Voici 3 idées de cadeaux… »), sans afficher de widget ;
    • ou afficher un widget en transmettant le ToolOutput à votre composant pour rendre des cartes produit.
  6. C’est seulement à ce moment que votre widget GiftGenius (Apps SDK) démarre et que votre code Next.js est rendu dans le chat. Le widget peut, par exemple, afficher un formulaire avec des champs de précision : « Pour qui ? », « Budget », « Centres d’intérêt ». L’utilisateur peut cliquer ou simplement continuer à écrire — le modèle synchronisera cela avec l’App.
  7. Dès que le widget a besoin de données réelles (catalogue de cadeaux), il ne fait pas fetch('https://my-backend/gifts') directement. À la place, il initie lui‑même l’appel d’un tool MCP : ChatGPT renvoie une requête call_tool au serveur MCP pour l’outil search_gifts.
  8. Si le scénario est multi‑étapes (demander des précisions, classer, vérifier la disponibilité, proposer des alternatives), la couche agent prend en charge la planification, la gestion du workflow et l’orchestration des agents.
  9. Quand l’utilisateur décide « d’acheter » un produit, ChatGPT initie l’achat via le protocole ACP. Le backend commerce, via ACP et Instant Checkout, effectue l’opération, répond sur le statut, déclenche des webhooks, et ChatGPT affiche à l’utilisateur le statut final (« La commande est passée, voici le reçu »).

Pour le développeur, c’est appréciable que chaque niveau ait des frontières de responsabilité claires. Et que toutes les couches soient reliées par de nouveaux protocoles standardisés (MCP, ACP), et non par de vieux appels REST lassants.

Tout cela est une vue logique : quelles couches existent et comment la requête les traverse. Ensuite, nous nous intéresserons au côté physique : comment ces couches peuvent être déployées dans le code et l’infrastructure — en un monolithe Next ou en plusieurs services (il ne s’agit pas ici de l’opposition monolithe vs microservices).

9. Monolithe Next.js vs architecture séparée

Question logique : « Tout cela doit‑il obligatoirement être une multitude de services séparés ? Puis‑je simplement faire un monolithe Next.js et basta ? »

Réponse : oui. Dans le cours, nous irons du simple au complexe. Au départ, il est tout à fait acceptable de rassembler « presque tout » dans un seul dépôt et même un seul runtime :

flowchart LR
    U[ChatGPT] --> W["Next.js App (Apps SDK)"]
    W --> M["MCP endpoint (dans le même Next.js)"]
    M --> DB[(BD/catalogue)]

Autrement dit, votre serveur Next.js (API routes ou serveur dédié) fait simultanément :

  • servir le widget UI (pages/composants de l’Apps SDK),
  • implémenter l’endpoint MCP (JSON‑RPC sur HTTP),
  • accéder à la BD/aux API externes.

C’est pratique en mode dev et pour les premières versions de l’App : moins de pièces mobiles, déploiement plus simple.

Cependant, à mesure que la fonctionnalité grandit, des raisons d’isoler les couches apparaissent :

  • le serveur MCP doit être scalable séparément (beaucoup d’outils lourds) ;
  • le backend financier vit sur son propre domaine, est régi par d’autres équipes et exige une sécurité particulière ;
  • la logique agent peut être extraite dans une application séparée avec sa supervision et son SLA.

Alors le schéma commence à ressembler à ce que nous avons déjà vu :

flowchart TD
    U[ChatGPT] --> W[Next.js + Apps SDK]
    W --> MG[MCP Gateway]
    MG --> M1[MCP Gifts Server]
    MG --> M2[MCP Analytics Server]
    M1 --> AG[Agent Service]
    AG --> ACP[Commerce/ACP Backend]

On ajoute la notion de MCP Gateway — point d’entrée commun pour ChatGPT. Il achemine les appels vers différents serveurs MCP, travaille avec des API REST, gère l’authentification, le rate limiting, etc.

Nous commencerons à écrire des exemples avec un scénario plutôt monolithique, mais dès le départ nous organiserons le code pour pouvoir le découper relativement sans douleur.

10. Où exactement vous écrirez du code (et ce que vous déléguez aux autres)

Puisque nous avons esquissé comment les couches peuvent être rassemblées en monolithe ou en architecture distribuée, il est utile d’indiquer explicitement les endroits où vous écrirez du code, et ce qui restera à d’autres services/équipes.

Du point de vue d’un développeur TypeScript/Next.js, il est utile de marquer clairement les zones que vous contrôlez.

Dans le widget (Apps SDK + Next.js), vous :

  • écrivez des composants React qui affichent l’état des outils et les saisies utilisateur ;
  • utilisez les hooks de l’Apps SDK pour lire ToolInput/ToolOutput et l’état du widget (widget state) ;
  • paramétrez le mode visuel (inline/fullscreen/PiP, thèmes, tailles — ce sera au niveau 8) ;
  • interagissez avec ChatGPT via window.openai pour des scénarios plus avancés (module séparé du cours).

Dans le serveur MCP, vous :

  • décrivez tools/resources/prompts avec le SDK MCP ;
  • implémentez la logique métier des outils (en pratique des fonctions TypeScript ordinaires qui interrogent BD, API, etc.) ;
  • optimisez les schémas et réponses pour que le modèle les lise facilement (moins d’hallucinations, plus de structure).

Dans la couche agent (si vous utilisez l’Agents SDK), vous :

  • décrivez quels outils sont disponibles pour l’agent et quels sont ses objectifs ;
  • paramétrez le run‑cycle, la mémoire, le contrôle des boucles ;
  • veillez à ce que l’agent ne fasse pas n’importe quoi et n’entre pas dans une planification infinie.

Dans l’ACP/les backends, vous :

  • vous intégrez à des services commerce existants (Stripe, votre boutique avec product feed, etc.) ;
  • ou concevez un backend qui comprend ACP et sait prendre/retourner des commandes.

Important : une seule personne maîtrise rarement toutes les couches dans un produit mûr. Mais au stade du prototype (et dans ce cours), nous espérons que vous pourrez au moins comprendre où vit quel code.

11. Comment l’architecture influence l’UX et la politique de la plateforme

Bien que l’UX et les politiques fassent l’objet de modules séparés, il est déjà important au niveau de l’architecture de comprendre comment votre découpage des couches influe sur l’UX et les exigences de la plateforme. Voici donc quelques remarques en amont.

Premièrement, la sandbox. Le widget ne peut pas aller sur Internet sans contrôle ni collecter des données utilisateur — tout passe par des outils contrôlés et des permissions décrites dans MCP/Store. La plateforme s’attend à ce que vous décriviez honnêtement quelles données et actions sont nécessaires à votre App, et basera le discovery/les suggestions d’App sur ces descriptions.

Deuxièmement, le flux UX. Comme le modèle peut temporairement « oublier » votre App ou, au contraire, la proposer trop agressivement, l’architecture doit tolérer les interruptions : si l’agent n’a pas fini un workflow long et que l’utilisateur change de sujet, l’application doit l’accepter sans broncher. Les scénarios multi‑étapes et l’orchestration de workflows dans le cours seront justement construits au‑dessus des MCP‑tools et de la couche agent.

Troisièmement, les ventes. Dès que votre App commence à encaisser, des exigences supplémentaires de sécurité, de journalisation, de contrats ACP, etc., s’appliquent. La façon dont vous avez séparé les couches (UI, MCP, Agents, ACP/Backend) influera fortement sur la facilité à passer la revue du Store et l’audit de sécurité.

Premières conclusions

J’espère que vous avez construit une carte d’ensemble dans votre tête :

  • les couches hautes (ChatGPT UI + Apps SDK) déterminent comment l’utilisateur voit et ressent votre App ;
  • la couche médiane (MCP) est le moyen standard d’offrir des outils et des données au modèle ;
  • les couches agent et commerce font de votre App plus qu’un « visualiseur de données » : un produit complet avec logique et paiements.

Au niveau 2, nous commencerons par le plus concret : télécharger le template officiel de l’Apps SDK basé sur Next.js, le lancer en local et le connecter à ChatGPT en Dev Mode. Autrement dit, nous mettrons d’abord les mains dans la couche Apps SDK/widget, tandis que MCP/agents vivront encore comme des stubs ou comme un backend intégré.

Mais gardez le schéma actuel en tête dès maintenant : c’est comme regarder un monorepo et comprendre que le dossier apps/ — c’est l’UI, services/mcp — le protocole, services/agent — l’orchestrateur, et services/commerce — l’argent.

12. Erreurs courantes dans la compréhension de l’architecture de la pile

Erreur n° 1 : penser qu’une ChatGPT App = simplement un « webhook vers mon API REST ».
On peut faire ainsi par habitude du monde des « bots » : le modèle enverrait juste des requêtes POST vers mon URL, et ensuite « advienne que pourra ». En réalité, entre le modèle et votre code se trouvent l’Apps SDK et MCP. Vous devez décrire des outils, leurs schémas et leur comportement, et non simplement « écouter » des requêtes HTTP arbitraires.

Erreur n° 2 : mêler les niveaux UI et logique métier.
Un anti‑pattern courant — tirer une logique métier complexe directement dans le widget, et faire de la couche MCP un mince passe‑plat. Le résultat : une UI lourde, difficile à tester et peu réutilisable hors de ChatGPT. Il est bien plus robuste de garder règles et accès aux données au niveau MCP/agent, et de laisser le widget s’occuper exclusivement d’affichage et d’interactions simples.

Erreur n° 3 : ignorer MCP et écrire « son propre protocole ».
La tentation survient parfois : « pourquoi MCP, je renverrai juste du JSON, le modèle se débrouillera ». Sur des petites démos, cela peut « marcher », mais vous perdez immédiatement les capacités standard de discovery, d’inspection, d’autorisation et de support multi‑clients que MCP et l’Apps SDK offrent « out of the box ».

Erreur n° 4 : construire toute l’App autour d’une seule couche.
Certains font « tout dans l’agent », en lui donnant trop de responsabilités. D’autres, au contraire, tentent de tout mettre dans les MCP‑tools. D’autres encore bâtissent un énorme monolithe Next.js. Il est plus juste d’accepter que chaque couche a son périmètre : UI — affichage, MCP — accès aux données/actions, agent — orchestration, ACP/Backend — invariants métiers et paiements.

Erreur n° 5 : sous‑estimer l’impact de l’architecture sur la revue du Store et la sécurité.
Si vous avez un seul serveur qui est à la fois endpoint MCP, ressource ACP, stocke des secrets et journalise tout « tel quel », la revue de sécurité et de politique de contenu peut devenir interminable. Une architecture séparée avec des frontières et des protocoles explicites simplifie nettement la vie aux étapes avancées.

Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION