1. Introdução
Se você olhar para uma ChatGPT App apenas como “mais um servidor web”, muito rapidamente começa um zoológico arquitetural: em algum lugar Next.js, em outro um servidor MCP, em outro um agente, em outro um backend de commerce — e tudo isso na cabeça vira um grande “servidor”.
É muito mais vantajoso aceitar desde já que isso é um bolo de camadas:
- no topo — o ChatGPT UI, que não controlamos, mas ao qual nos adaptamos;
- abaixo — nosso widget no Apps SDK (Next.js 16, React 19), que é renderizado no chat;
- mais abaixo — o servidor MCP com ferramentas (tools/resources/prompts);
- opcionalmente — a camada de agentes, que orquestra cenários complexos;
- e na base — seus serviços “terrenos”: BD, APIs externas, commerce/ACP (protocolo para cenários de commerce) etc.
No resumo do curso, esse caminho pode ser desenhado como uma cadeia:
User → ChatGPT Widget → Apps SDK → MCP Gateway (Auth) → Agent Service → ACP / Stripe.
Agora nossa tarefa é transformar essa cadeia em um modelo mental claro.
2. Esquema geral do stack
Primeiro olhamos a figura inteira, depois vamos camada por camada.
flowchart TD
U[Usuário no ChatGPT] --> C["ChatGPT UI chat + painel de Apps"]
C --> W["Widget do seu App (Apps SDK, Next.js)"]
W --> M["Servidor MCP (tools/resources/prompts)"]
M --> AG["Agente(s) (Agents SDK, orquestração)"]
AG --> B["Backends e ACP Banco de dados, serviços, pagamentos"]
É importante notar algumas coisas.
Em primeiro lugar, o usuário vê apenas dois níveis: o ChatGPT UI e o seu widget. Tudo o que está abaixo é “bastidor”.
Em segundo lugar, o protocolo MCP não é uma sigla aleatória, mas um padrão oficial pelo qual o Apps SDK se comunica com suas ferramentas: o servidor deve saber listar tools, aceitar call_tool e retornar um link para um recurso de UI a ser renderizado no ChatGPT.
Em terceiro lugar, as camadas Agents e ACP são formalmente opcionais, mas em apps comerciais reais elas quase sempre aparecem: em algum lugar é preciso planejar um cenário de múltiplos passos, em outro — receber pagamentos.
Agora vamos dissecar cada camada separadamente.
Insight: ChatGPT é um framework
A integração com o ChatGPT não está em um único lugar — ela está espalhada por muitos pontos de integração. Para um programador, isso lembra muito trabalhar com um framework. O framework decide quando e onde chamar seu código; você só precisa escrever as coisas certas nos lugares certos.
Com o ChatGPT é exatamente assim:
- widgets — são registrados via mcp-resources, o GPT decide sozinho quando mostrá-los
- mcp-tools — o GPT decide sozinho quando chamá-los
- product feed — pode ser adicionado ao modelo via mcp-tool, mas a opção padrão é por meio de site register merchant
- ACP/InstantCheckout — API separada
- Autorização — servidor mcp auth separado.
3. Camada 1 — ChatGPT UI: nosso “host”
O ChatGPT UI é a interface web (e móvel) da OpenAI, onde o usuário mantém o diálogo principal. Há o campo de entrada, histórico de mensagens, botões de seleção de modelo e a aba com aplicativos (Store/Composer).
Essa camada nós não programamos. Não temos acesso ao código, DOM ou estilos. Mas ela define os limites:
- é aqui que o usuário “escolhe” seu app explicitamente (pela Store/Composer) ou implicitamente (o próprio modelo sugere o App);
- é aqui que o ChatGPT decide: responder só com texto, chamar sua tool, renderizar o widget ou fazer tudo ao mesmo tempo;
- é aqui que vivem os padrões básicos de UX: widget inline, modo fullscreen, janela PiP etc. (detalhes no módulo 8).
Do ponto de vista prático, vale lembrar: o ChatGPT UI é nosso aplicativo host. Nós nos encaixamos dentro dele, e não o contrário. O servidor do GPT carregará o código do seu widget para o servidor deles, vai limpá-lo do que for desnecessário e só então o carregará no chat a partir do próprio domínio.
4. Camada 2 — Apps SDK e widget (Next.js 16 dentro do chat)
A próxima camada é o seu código de UI, escrito em React/Next.js usando o Apps SDK.
O modelo mental é simples: é como um mini SPA, renderizado como um widget embutido no chat. Mas com ressalvas:
- seu código roda em sandbox: DOM limitado, regras próprias para requisições de rede, objeto especial window.openai para se comunicar com o ChatGPT (haverá uma aula específica sobre isso);
- o widget não controla o fluxo do diálogo: o usuário escreve no chat geral, o modelo decide quando chamar seu App, e você responde apenas na sua “moldura”;
- o Apps SDK cuida de tudo: sincronização do estado do widget com o histórico do diálogo, processamento dos resultados das tools, trabalho com MCP etc.
Para o desenvolvedor Next.js isso parece bastante familiar: você tem páginas/componentes, hooks, props. Mas, em vez do fetch('/api/...') clássico, você vai depender mais de ferramentas (tools) descritas no servidor MCP e de hooks especiais do Apps SDK (falaremos deles mais adiante no curso).
Para concretizar um pouco a conversa, vamos lembrar nosso projeto — o hipotético GiftGenius. É um App que ajuda a escolher presentes por parâmetros: para quem, qual orçamento, para qual ocasião etc.
Um mini-trecho do futuro UI (ainda sem especificidades do SDK, só como ideia):
// GiftSummary.tsx — componente React simples do nosso 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>
);
}
Depois, esse componente receberá as ideas não “do nada”, mas do resultado de uma ferramenta do servidor MCP (ToolOutput). Mas, em nível de arquitetura, o que importa é outra coisa: todo esse código vive na “segunda camada” e cuida apenas de exibir estado.
5. Camada 3 — Servidor MCP: mundo de ferramentas e dados
Agora vamos mais abaixo — para a parte de servidor.
Model Context Protocol (MCP) é o padrão que descreve como um cliente de LLM (ChatGPT, Apps SDK, Agents) se comunica com o seu servidor. Ele define quais ferramentas estão disponíveis, seus esquemas de input/output, como chamá-las e quais outros recursos/prompts podem ser carregados.
Um servidor MCP mínimo para o Apps SDK deve saber fazer três coisas:
- retornar a lista de ferramentas (List tools) com seus JSON Schemas e metadados;
- processar chamadas de ferramentas (Call tools) — aceitar a requisição call_tool, executar a lógica de negócio e retornar um resultado estruturado;
- retornar html, js, css,... — opcionalmente, se a ferramenta estiver ligada a um widget específico a ser exibido.
Um ponto importante: MCP é um protocolo independente de transporte. Para ChatGPT Apps, nos interessa a variante HTTP com implementação streamable, mas detalhes de transporte e formato das mensagens ficam para o módulo de MCP (nível 6). Por ora, basta entender que o Apps SDK “por baixo” fala com o servidor MCP, e não com endpoints REST arbitrários.
Arquiteturalmente, a camada MCP costuma parecer um microsserviço separado:
flowchart LR
subgraph App["Seu ChatGPT App"]
W["Widget (Next.js + Apps SDK)"]
M["Servidor MCP (@modelcontextprotocol/sdk)"]
end
W <-- JSON-RPC over HTTP/SSE --> M
M --> DB[(Catálogo de presentes)]
M --> EXT[APIs externas]
Dentro do servidor MCP você escreve código TypeScript/Node normal, usa bancos de dados, filas, APIs de terceiros etc. O SDK oficial de MCP para TypeScript cuida da serialização JSON-RPC, validação de esquemas e roteamento de chamadas.
Para nosso GiftGenius, uma das ferramentas MCP pode se chamar, por exemplo, search_gifts. Em TypeScript pode parecer uma função comum:
// Pseudo-código: lógica de negócio dentro do servidor MCP
export async function searchGifts(params: {
recipient: string;
budget: number;
}) {
// aqui você consulta o BD/catálogo
const items = await findGiftsInCatalog(params);
return items.slice(0, 10);
}
Depois vamos embrulhá-la em uma tool MCP com a descrição do schema, mas o principal é: essa camada é seu “backend normal”, só que falando com o mundo via MCP.
6. Camada 4 — Agents SDK: o cérebro de cenários complexos
Nem todo app precisa de agentes, mas assim que o cenário deixa de ser “uma chamada de ferramenta — uma resposta”, a camada de agentes se torna muito útil.
Um agente é, essencialmente, um processo de LLM gerenciado, que:
- lê a solicitação do usuário e os fatos do histórico do diálogo;
- planeja a sequência de passos: quais ferramentas chamar, em qual ordem, com quais argumentos;
- analisa resultados, pode decidir “chamar a tool de novo”, “pedir esclarecimento ao usuário”, “construir uma resposta mais elaborada”;
- às vezes mantém estado entre os passos (memória, sessões, checkpoints — isso é assunto do nível 12).
O Agents SDK oferece uma forma estruturada de descrever tais cenários: quais tools o agente tem, como armazenar e restaurar estado, como limitar ciclos etc. Os agentes rodam dentro do backend e permitem usar o poder da OpenAI como você quiser: sem as limitações dos widgets de ChatGPT Apps.
No contexto do nosso stack, o agente geralmente fica no backend entre a camada MCP e suas APIs de domínio. Ele pode usar APIs externas, funções internas e tools MCP como “mãos” e cuidar do “cérebro”.
Por exemplo, o cenário do GiftGenius pode ser assim:
- O usuário escreve “escolha um presente para a minha mãe até 50$”.
- O ChatGPT chama a ferramenta search_gifts do seu app.
- Por trás da ferramenta search_gifts no backend há um Agente, que decide antes esclarecer alguns detalhes (interesses, ocasião).
- O usuário detalha preferências adicionais.
- O ChatGPT chama novamente a ferramenta search_gifts do seu app com argumentos adicionais.
- O agente no servidor pode chamar ferramentas adicionais (por exemplo, verificação de disponibilidade).
- Retorna ao ChatGPT as opções preparadas e, possivelmente, um link para um widget para visualização.
Mais adiante no curso veremos em detalhes o ciclo de execução do agente, idempotência e segurança, mas para a arquitetura geral importa: a camada de agentes é opcional, porém muito poderosa, tirando de você parte da orquestração complexa.
7. Camada 5 — ACP/Backend: dinheiro, dados e preocupações terrenas
A camada mais inferior — seus serviços de praxe:
- bancos de dados (catálogos de produtos, usuários, pedidos);
- APIs externas (provedores de pagamento, logística, SaaS de terceiros);
- protocolos especializados, como ACP (Agentic Commerce Protocol) para cenários de commerce e Instant Checkout.
O ACP descreve como o ChatGPT e agentes conversam com seu backend de commerce: solicitações para selecionar SKU, criar carrinho, finalizar pedido, devoluções, webhooks de operações bem-sucedidas/mal-sucedidas etc.
Para o GiftGenius seria algo assim:
- a tool MCP search_gifts lê do product feed/BD;
- o agente, ao escolher um produto específico, inicia um intento de commerce (via ACP);
- seu backend compatível com ACP aciona o PaymentService: “cobrar o valor”, informa o ChatGPT sobre o status;
- o usuário vê no ChatGPT que o pedido foi feito, sem sair para um site externo.
Agora que percorremos as camadas, vamos olhar para um cenário concreto end-to-end.
8. Cenário ponta a ponta: como a solicitação do usuário atravessa todas as camadas
Vamos pegar a solicitação: “Escolha um presente para a minha mãe até 50 dólares, ela gosta de ler e de chá”.
Vamos quebrar em passos.
- O usuário escreve o texto no ChatGPT. Essa é a primeira camada — o ChatGPT UI. Para o usuário tudo parece um chat comum.
- O modelo lê o histórico do diálogo, os metadados do seu App (descrições, categorias, permissões) e decide que o GiftGenius é um candidato adequado. Segundo as regras de discovery no Apps SDK, o modelo considera descrições textuais das tools, histórico de uso, contexto e até menções de marca.
- O ChatGPT:
- ou chama diretamente a ferramenta do seu App sem UI (cenário tool-first);
- ou propõe na resposta: “Posso usar o GiftGenius para ajudar a escolher o presente” e chama sua tool.
- O ChatGPT envia ao servidor MCP uma solicitação call_tool para a ferramenta search_gifts. O servidor MCP, por sua vez, executa a lógica de negócio: consulta o BD/feed, filtra por orçamento e preferências e retorna JSON com a lista de produtos apropriados.
- O resultado da ferramenta retorna ao ChatGPT. Ele pode:
- simplesmente usá-lo como dados para a resposta em texto (“Aqui estão 3 ideias de presentes...”), sem mostrar o widget;
- ou exibir o widget, passando o ToolOutput para o seu componente, para renderizar cards de produtos.
- Só nesse momento seu widget GiftGenius (Apps SDK) é iniciado e seu código Next.js é renderizado dentro do chat. O widget pode, por exemplo, mostrar um formulário com campos de esclarecimento: “Para quem é o presente?”, “Orçamento”, “Interesses”. O usuário pode clicar em botões ou apenas continuar escrevendo no chat — o modelo sincronizará isso com o App.
- Assim que o widget precisa de dados reais (catálogo de presentes), ele não faz fetch('https://my-backend/gifts') diretamente. Em vez disso, ele mesmo inicia a chamada da ferramenta MCP: o ChatGPT envia novamente ao servidor MCP a solicitação call_tool para a ferramenta search_gifts.
- Se o cenário for multi-etapas (é preciso pedir esclarecimentos, ranquear, fazer verificações de estoque, sugerir alternativas), a camada de agentes assume o planejamento, o controle do workflow e a orquestração.
- Quando o usuário decide “comprar” um produto específico, o ChatGPT inicia a compra pelo protocolo ACP. O backend de commerce, via ACP e Instant Checkout, realiza a operação, responde com o status, dispara webhooks e o ChatGPT mostra ao usuário o status final (“Pedido realizado, aqui está o recibo”).
Do ponto de vista do desenvolvedor, é ótimo que em cada nível haja limites claros de responsabilidade. E, ao mesmo tempo, todas as camadas estão conectadas por novos protocolos padronizados (MCP, ACP), e não por velhas e cansativas requisições REST.
Tudo isso é o quadro lógico: quais camadas existem e como a solicitação flui por elas. Em seguida, nos interessará o lado físico: como exatamente essas camadas podem ser implantadas em código e infraestrutura — em um único monólito Next ou em vários serviços (não estamos falando de monólito vs microsserviços como “arquiteturas”).
9. Monólito Next.js vs arquitetura separada
Agora a pergunta lógica: “Tudo isso precisa obrigatoriamente ser um monte de serviços separados? Posso simplesmente fazer um monólito Next.js e encerrar?”
Resposta: pode. No curso vamos do simples ao complexo. No início, é totalmente ok juntar “quase tudo” em um único repositório e até em um único runtime:
flowchart LR
U[ChatGPT] --> W["Next.js App (Apps SDK)"]
W --> M["MCP endpoint (no mesmo Next.js)"]
M --> DB[(BD/catálogo)]
Ou seja, seu servidor Next.js (rotas de API ou servidor separado) simultaneamente:
- entrega o widget de UI (páginas/componentes do Apps SDK),
- implementa o endpoint MCP (JSON-RPC sobre HTTP),
- consulta o BD/APIs externas.
Isso é conveniente em modo de desenvolvimento e para as primeiras versões do App: menos partes móveis, deploy mais simples.
Contudo, à medida que a funcionalidade cresce, surgem motivos para separar as camadas:
- o servidor MCP precisa escalar separadamente (muitas ferramentas pesadas);
- o backend financeiro vive em seu próprio domínio, é regulado por outras equipes e exige segurança especial;
- a lógica de agentes pode ser destacada em um app separado com monitoramento e SLA próprios.
Então o diagrama começa a se parecer mais com o que já vimos:
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]
Entra o conceito de MCP Gateway — a porta de entrada comum para o ChatGPT. Ele roteia chamadas para diferentes servidores MCP, trabalha com REST APIs, gerencia autorização, limites de requisição (rate limiting) etc.
Vamos começar os exemplos com um cenário mais monolítico, mas desde o início organizaremos o código para que seja relativamente indolor separá-lo em partes depois.
10. Onde exatamente você vai escrever código (e o que delega a outros)
Já que esboçamos como as camadas podem ser reunidas em monólito ou arquitetura distribuída, é útil fixar explicitamente em quais lugares você escreverá código e o que ficará com outros serviços/equipes.
Do ponto de vista de um desenvolvedor TypeScript/Next.js, é útil marcar claramente quais zonas você controla.
No widget (Apps SDK + Next.js) você:
- escreve componentes React que exibem o estado das ferramentas e a entrada do usuário;
- usa hooks do Apps SDK para ler ToolInput/ToolOutput e o estado do widget (widget state);
- configura o modo visual (inline/fullscreen/PiP, temas, tamanhos — isso estará no nível 8);
- interage com o ChatGPT através de window.openai para cenários mais avançados (módulo separado do curso).
No servidor MCP você:
- descreve tools/resources/prompts com o MCP SDK;
- implementa a lógica de negócio das ferramentas (basicamente funções TypeScript comuns, que consultam BD, APIs etc.);
- otimiza esquemas e respostas para que o modelo consiga lê-los com facilidade (menos alucinações, mais estrutura).
Na camada de agentes (se usar o Agents SDK) você:
- descreve quais ferramentas o agente tem disponíveis e quais são seus objetivos;
- configura o ciclo de execução (run cycle), memória, controle de loops;
- garante que o agente não faça bobagens nem entre em planejamento infinito.
Em ACP/backends você:
- ou integra serviços de commerce existentes (Stripe, sua loja com product feed etc.);
- ou projeta um backend novo que entende ACP e sabe aceitar e retornar pedidos.
Importante: raramente uma única pessoa domina todas as camadas em um produto maduro. Mas, na fase de protótipo (e neste curso), esperamos que você ao menos entenda onde cada parte do código vive.
11. Como a arquitetura afeta o UX e a política da plataforma
Embora UX e políticas sejam temas de módulos à parte, já no nível da arquitetura é importante entender como a separação de camadas escolhida impacta o UX e os requisitos da plataforma. Então, deixamos algumas observações de antemão.
Primeiro, sandbox. O widget não pode navegar na internet indiscriminadamente nem coletar dados do usuário — tudo passa por ferramentas controladas e permissões descritas no MCP/Store. A plataforma espera que você descreva honestamente quais dados e ações seu App precisa e baseará o discovery/sugestões de App nessas descrições.
Segundo, fluxo de UX. Como o modelo pode “esquecer” temporariamente seu App ou, ao contrário, sugeri-lo de forma muito agressiva, a arquitetura deve ser amigável a interrupções: se o agente não terminou um workflow longo e o usuário mudou de assunto, o app deve lidar bem com isso. Os cenários multi-etapas e a orquestração de workflows no curso serão construídos sobre tools MCP e a camada de agentes.
Terceiro, vendas. Assim que seu App começa a cobrar dinheiro, entram requisitos adicionais de segurança, logging, contratos ACP etc. A forma como você separou as camadas (UI, MCP, Agents, ACP/Backend) influenciará muito o quão trabalhoso será passar pela revisão na Store e pelo auditoria de segurança.
Primeiros resultados
Espero que você tenha montado no seu cabeça um mapa de visão geral:
- camadas superiores (ChatGPT UI + Apps SDK) determinam como o usuário vê e sente seu App;
- camada intermediária (MCP) é a forma padronizada de dar ao modelo ferramentas e dados;
- camadas de agentes e commerce fazem seu App deixar de ser apenas um “visualizador de dados” e virar um produto completo com lógica e dinheiro.
No segundo nível começaremos pelo mais interessante: baixar o template oficial do Apps SDK baseado em Next.js, executá-lo localmente e conectá-lo ao ChatGPT em Dev Mode. Ou seja, vamos primeiro colocar a mão na massa na camada Apps SDK/widget, enquanto MCP/agentes ficarão por ora como stubs ou como backend embutido.
Mas manter o esquema atual na cabeça já é importante: é como olhar para um monorepo e entender que a pasta apps/ — é a UI, services/mcp — o protocolo, services/agent — o orquestrador, e services/commerce — o dinheiro.
12. Erros típicos no entendimento da arquitetura do stack
Erro nº 1: achar que ChatGPT App = simplesmente “webhook para meu REST API”.
Dá para fazer assim por costume do mundo de “bots”: o modelo só manda POSTs para meu URL e depois “seja o que Deus quiser”. Na realidade, entre o modelo e o seu código estão o Apps SDK e o MCP. Você precisa descrever ferramentas, seus schemas e comportamento, e não apenas “escutar” requisições HTTP arbitrárias.
Erro nº 2: misturar níveis de UI e lógica de negócio.
Um antipadrão popular é puxar lógica de domínio complexa direto para o widget e deixar o MCP fino. O resultado é um UI pesado, difícil de testar e pouco reutilizável fora do ChatGPT. É muito mais robusto manter regras e acesso a dados no nível MCP/agent, e deixar o widget exclusivamente para exibição e interatividade simples.
Erro nº 3: ignorar o MCP e escrever “seu próprio protocolo”.
Às vezes surge a tentação: “para que MCP, vou só retornar JSON e o modelo se vira”. Em demos curtas isso pode “funcionar” de forma surpreendente, mas você perde na hora recursos padrão de discovery, inspeção, autorização e suporte multi-cliente que MCP e Apps SDK oferecem “de fábrica”.
Erro nº 4: construir todo o App em torno de uma única camada.
Uns fazem “tudo no agente”, sobrecarregando-o com um monte de responsabilidades. Outros tentam enfiar tudo nas tools MCP. Outros constroem um monólito Next.js gigante. O mais correto é aceitar que cada camada tem sua zona de responsabilidade: UI — exibição, MCP — acesso a dados/ações, agente — orquestração, ACP/Backend — invariantes de domínio e dinheiro.
Erro nº 5: subestimar o impacto da arquitetura na revisão da Store e na segurança.
Se você tem um único servidor que é ao mesmo tempo endpoint MCP, recurso ACP, guarda segredos e registra tudo em logs “como está”, a revisão de segurança e de política de conteúdo pode se arrastar. Uma arquitetura separada, com limites e protocolos claros, facilita muito a vida nas etapas posteriores.
GO TO FULL VERSION