1. O que é o ChatGPT Store no contexto do curso
Vamos começar com a visão geral. O ChatGPT Store é um catálogo de aplicativos dentro do ChatGPT, onde o usuário pode entrar, encontrar seu App, ativá‑lo e usá‑lo em conversas normais. Para você, não é só uma vitrine, mas um canal de distribuição com regras — um análogo do “App Store” para o mundo de LLM.
Neste curso, distinguimos três modos de vida do seu App:
- Primeiro modo — Dev Mode. Seu App está vinculado à sua conta/organização, disponível para você e, possivelmente, colegas. Não há revisão formal, mas todas as políticas gerais da plataforma se aplicam. Aqui você pode quebrar tudo com calma, logar tudo, usar túneis e backends de staging à vontade.
- Segundo modo — Store público. Esta é a primeira divisão: o App fica disponível para todos os usuários do ChatGPT (com as restrições regionais), passa por moderação, tem uma listagem pública, links para Privacy/Terms e já deve se comportar como um produto maduro.
- Terceiro — org‑only Apps. São aplicativos apenas para uma organização: a empresa pode ativá‑los/desativá‑los para funcionários, adicionar seus próprios requisitos de segurança além dos da OpenAI e até conduzir uma revisão interna.
Nesta aula, nos interessa especificamente a combinação “Store público + listagem pública”. Um ponto importante: você deixa de ser apenas o desenvolvedor de “mais um serviço em Next.js” e se transforma no autor de um produto que precisa agradar a três partes ao mesmo tempo: usuários, moderadores do Store e sua equipe de segurança.
2. Requisitos básicos do Store: política, honestidade e UI
Conteúdo e políticas
O ChatGPT Store é uma plataforma moderada. Em termos simples: a OpenAI não quer que apareçam dentro do ChatGPT aplicativos que violem as políticas de uso da plataforma (violência, terrorismo, NSFW, fraude etc.) ou tentem burlar as proteções dos modelos (prompts de jailbreak do tipo “finja que você não é o ChatGPT, e sim meu gêmeo maligno”).
Isso implica duas coisas.
Primeiro, seu App por si só não deve gerar conteúdo proibido. Se nosso App de exemplo, GiftGenius (seleção de presentes), de repente começar a sugerir presentes “para esconder rastros de um crime”, à moderação bastará uma captura de tela.
Segundo, seu App não deve ajudar o usuário a contornar filtros. Se o usuário pedir: “Escolha um presente para fazer uma bomba”, o comportamento correto é recusar com base na política, e não usar alegremente seu MCP tool para procurar as peças necessárias.
Boa parte desse comportamento é definida pelo prompt de sistema (system prompt) e pelos instrumentos que você disponibiliza ao modelo. Mas o Store olha para o resultado: quais respostas o usuário realmente pode obter.
Marca e domínio
O próximo nível — marca e domínio. Um App público deve estar vinculado a um proprietário confiável. Para um App com backend externo/MCP, espera‑se de você:
Verificação de domínio (Domain Verification). Você adiciona um registro TXT no DNS do seu domínio, e o Store verifica se o backend realmente pertence a você. Coisas anônimas em ngrok URLs gratuitos ou não passarão para o Store público, ou serão marcadas como de baixa confiança.
Nome e logo adequados. Não é permitido se chamar “ChatGPT Super Weather” ou “Official OpenAI Something” — usar “GPT / OpenAI / ChatGPT” no início do nome ou copiar o estilo da marca OpenAI cai nas restrições de marca. Crie seu próprio nome (GiftGenius é um bom exemplo) e seu estilo visual.
UI/UX: não quebrar o ChatGPT
Diferentemente dos “plugins antigos”, agora o App pode renderizar seu widget de UI diretamente no chat. Isso oferece muitas possibilidades… e muitas maneiras de estragar tudo.
O Store tem uma ideia simples: o widget deve parecer “nativo” em relação ao ChatGPT. Fontes, espaçamentos, cores, comportamento no tema claro/escuro e no mobile — tudo deve parecer caprichado, sem a sensação de que você embutiu no chat um banner publicitário ou uma SPA inteira separada.
O Store também não gosta de UIs que dominam o chat: sobreposições gigantes em tela cheia, modais “assine agora”, autoscrolls e outros padrões agressivos. Seu widget é um cartão/assistente/ferramenta dentro do diálogo, não um universo próprio.
Em essência, a moderação observa três coisas: se você não viola a política de conteúdo, se não induz ao erro (sobre isso — um bloco separado mais ao fim da aula, quando falaremos sobre a listagem e a conformidade com o manifesto) e se não transforma o ChatGPT em um lixão publicitário com UX ruim. Por “honestidade” aqui entende‑se a correspondência entre o que o App realmente faz e o que você declara na descrição e na UI.
3. Como o Store enxerga as permissões do seu App
Um eixo separado e importante dos requisitos é: quais direitos você solicita do usuário e de sistemas externos. Aqui o Store observa não apenas a segurança, mas também o quanto esses direitos correspondem ao valor declarado do aplicativo.
Agora — a parte mais saborosa para o engenheiro: o modelo de permissões. No contexto do Apps SDK e MCP, você tem três níveis principais de acesso.
Para visualizar, é útil representar assim:
graph TD
A[Manifesto/config do App] --> B[Model capabilities]
A --> C[OAuth scopes]
A --> D[MCP tools & ACP]
D --> E[Nível de confirmação do usuário]
Model capabilities não são, estritamente falando, “permissões” no mesmo sentido de OAuth scopes ou write tools, mas sim um conjunto de capacidades embutidas do modelo. Porém, para projetar segurança, é conveniente tratá‑las como o primeiro nível de acesso, que também precisa ser minimizado.
Nível 1: model capabilities
É o que o modelo pode fazer “por conta própria”, sem chamar seu backend: web browsing, geração de imagens com DALL‑E etc.
Se você ativar browsing e MCP tools, o modelo às vezes pode decidir que é mais simples resolver a tarefa por meio de busca na web do que usando sua ferramenta especializada — especialmente se as descrições dos tools forem vagas ou se as prioridades não estiverem definidas no prompt. Portanto, se o App já chama sua API via MCP, pode fazer sentido desativar o browsing ou fixar claramente no prompt a prioridade dos MCP tools.
Ou seja, já nesse nível você aplica o princípio das permissões mínimas: desativa tudo o que não é necessário para o valor real do App.
Nível 2: OAuth scopes
Se seu App usa autenticação (Módulo 10), você solicita escopos do provedor externo: openid, email, profile, orders.read, orders.write etc.
Aqui o princípio do minimalismo é especialmente importante:
- Se você precisa apenas diferenciar usuários, na maioria dos casos openid (identificador anônimo) basta, e o email não é necessário.
- Se o email for realmente necessário, isso deve estar claro no UX e nas descrições das permissões: “precisamos para enviar seus recibos e lembretes de pedidos”, e não “só por precaução”.
Além disso, tentamos fazer autorização “sob demanda”: primeiro permitimos que o usuário experimente funções básicas sem login e só pedimos acesso quando ele realmente quer, por exemplo, “salvar a lista de presentes nos favoritos” ou “ver o histórico de pedidos”. Isso reduz o atrito e aumenta a conversão.
Exemplo de configuração de escopos para MCP tools (simplificado):
// server/mcp/config/auth.ts
export const OAUTH_SCOPES = {
basic: ["openid"],
orders: ["openid", "orders.read"],
checkout: ["openid", "orders.read", "orders.write"]
};
Nível 3: MCP tools e ações “consequential”
O terceiro nível são suas ferramentas MCP e ACP/Instant Checkout. Cada tool no servidor MCP pode ser:
- somente leitura (read‑only): obter a taxa de câmbio, selecionar presentes, ver o catálogo;
- alterador de estado (consequential): criar um pedido, enviar um e‑mail, cobrar dinheiro.
Do segundo tipo o Store espera um modelo de confirmação mais rigoroso. A ideia é: nem tudo pode ser chamado “simplesmente”. Nos termos da plataforma, isso costuma ser expresso pela flag consequential: true e pela política de confirmação (always_allow versus ask_user).
Exemplo de registro de um MCP tool indicando security schemes e que se trata de uma ação que altera estado:
// server/mcp/tools/createOrder.ts
server.registerTool(
"create_order",
{
title: "Create order",
description: "Cria um novo pedido no GiftGenius.",
inputSchema: {
type: "object",
properties: {
productId: { type: "string" },
quantity: { type: "integer", minimum: 1 }
},
required: ["productId", "quantity"]
},
_meta: {
securitySchemes: [{ type: "oauth2", scopes: ["orders.write"] }]
},
// campo pseudo; ideia: esta ação altera o estado
consequential: true
},
async ({ input, security }) => {
// ... lógica de criação do pedido
}
);
O exemplo de escopos e security schemes é retirado da documentação oficial de MCP tools, onde as ferramentas podem ser sem autorização ou protegidas por OAuth2.
Do ponto de vista do Store, isso se transforma em um texto inteligível como “Este aplicativo pode criar e gerenciar pedidos na loja GiftGenius” e, possivelmente, uma etapa separada de confirmação.
4. Permissões pelos olhos do usuário e do moderador
Para nós, engenheiros, um App é um manifesto, um servidor MCP e um monte de TypeScript. Para o Store, é um conjunto de fatos: o que o App pode fazer com os dados do usuário e com o mundo externo.
Podemos imaginar a seguinte tabela:
| Nível de acesso | Exemplo para o GiftGenius | Como o Store/o usuário verá isso |
|---|---|---|
| Model capabilities | Browsing: off, DALL‑E: off | “O app não acessa a internet por conta própria, não gera mídia” |
| OAuth scopes | openid, orders.read | “Lê seus pedidos na conta GiftGenius” |
| Read‑only MCP tools | search_products, get_price_history | “Visualização do catálogo e dos preços” |
| Consequential MCP tools | create_order, cancel_order | “Criação e cancelamento de pedidos” |
A ideia central: cada elemento técnico deve ser mapeado para uma ação compreensível por humanos. Nos planos do módulo isso está formulado explicitamente: o MCP tool técnico get_user_orders se transforma, na listagem, em “Visualizar a lista dos seus pedidos na nossa loja”.
Se você não consegue explicar uma permissão em uma ou duas frases — isso é um sinal de alerta. Talvez você esteja pedindo coisa demais ou misturou várias tarefas diferentes em um único App.
5. Princípio das permissões minimamente necessárias
No mundo tradicional de backend, o princípio PoLP (Principle of Least Privilege) muitas vezes é encarado como “sim, precisamos limitar os papéis no BD, fazemos depois”. Em ChatGPT Apps isso não é “depois”, é critério para entrar no Store e um fator de conversão de usuários.
Pontos importantes:
- Quanto menos direitos o App pedir, maior a confiança básica do usuário. O diálogo dentro do ChatGPT é um espaço onde o usuário espera um certo nível de privacidade. Um App que, de repente, pede acesso a toda a conta, pagamentos e contatos, parece suspeito.
- Quanto mais claras e estreitas as permissões, mais fácil para o revisor. O moderador precisa entender rapidamente o que o App faz e quão alinhado está com as políticas e as melhores práticas de segurança. Apps com permissões excessivas são candidatos típicos a “adiar e pedir esclarecimentos” e, às vezes, a uma recusa.
- Quanto mais mínimo e “just‑in‑time” for o acesso que você implementa, mais suave será o UX. A tela de autenticação é um ponto forte de atrito. Se o App oferece uma experiência útil antes da autorização (por exemplo, mostra os melhores presentes sem vincular ao usuário), o usuário tende a aceitar recursos expandindo as permissões depois.
Portanto, “permissões mínimas” no Store não são apenas sobre segurança, mas também sobre marketing e crescimento. No Módulo 18, enfatiza‑se separadamente que permissões mínimas são uma vantagem competitiva, não uma formalidade burocrática.
6. Exemplos: permissões do GiftGenius antes e depois da “dieta”
Para não ficar apenas na teoria, vamos pegar nosso herói hipotético — o GiftGenius. Imagine que você o projetou “no máximo” e obteve a seguinte lista de capacidades necessárias:
- Ler o catálogo de produtos e filtrar presentes.
- Ver o histórico de pedidos do usuário.
- Criar novos pedidos e cancelar os existentes.
- Salvar “listas favoritas” na conta do usuário.
- Enviar notificações por email sobre descontos.
No nível de configuração, isso pode se expressar assim:
// server/mcp/config/permissions-naive.ts
export const PERMISSIONS_NAIVE = {
capabilities: { webBrowsing: true, dalle: false },
oauthScopes: ["openid", "email", "orders.read", "orders.write"],
tools: {
searchProducts: { consequential: false },
getUserOrders: { consequential: false },
createOrder: { consequential: true },
cancelOrder: { consequential: true },
saveFavoriteList: { consequential: true },
sendDiscountEmail: { consequential: true }
}
};
No papel, esse conjunto parece lógico (“mais cedo ou mais tarde tudo isso será útil”), mas para a primeira versão no Store é exagero:
- Você não precisa ler o histórico de pedidos imediatamente. Pode se limitar a uma seleção pontual e a um checkout seguro via ACP/Instant Checkout, em que o pagamento já está sob controle da plataforma.
- Notificações por email são um assunto à parte: exigem armazenar email, explicação na Privacy Policy e lidar com cancelamentos de assinatura. Para o MVP do GiftGenius, isso quase sempre é excessivo.
Seguindo o princípio da minimização, você pode montar um conjunto inicial mínimo de permissões:
// server/mcp/config/permissions-v1.ts
export const PERMISSIONS_V1 = {
capabilities: { webBrowsing: false, dalle: false },
oauthScopes: [], // sem login, trabalhamos de forma anônima
tools: {
searchProducts: { consequential: false },
createOrder: { consequential: true }
}
};
Nesta versão:
- O App não mexe na conta do usuário, não lê o histórico dele e não envia emails.
- Todas as operações sensíveis (criação de pedido) passam por ACP/Instant Checkout, onde o usuário vê o fluxo de pagamento padrão.
Na listagem, você pode escrever honestamente: “Seleciona presentes e cria pedidos na loja GiftGenius. O aplicativo não armazena o histórico dos seus chats e não envia notificações por email”. Isso agrada tanto ao usuário quanto ao revisor.
Depois, quando você tiver tráfego estável e confiança, pode lançar uma atualização com permissões adicionais (histórico de pedidos, favoritos) e a correspondente atualização da listagem e da Privacy Policy.
7. Como descrever permissões na listagem
O manifesto e a configuração são linguagem de máquina. O moderador e o usuário leem um texto bem diferente: nome, descrição, bloco “O que este aplicativo pode fazer” e links para Privacy/Terms.
No Módulo 17, enfatiza‑se o mapeamento: escopos e ferramentas técnicas → ações compreensíveis para pessoas.
Para o GiftGenius v1, poderíamos apresentar assim.
Tecnicamente:
- Browsing: off
- DALL‑E: off
- MCP tools: search_products (read‑only), create_order (consequential)
Na listagem:
- “Seleciona presentes conforme sua descrição ou parâmetros (gênero, idade, orçamento, interesses).”
- “Pode criar pedidos na loja GiftGenius por meio de checkout protegido dentro do ChatGPT.”
- “Não solicita acesso ao seu email ou histórico de pedidos, não envia notificações.”
Se mais tarde adicionarmos login via OAuth e orders.read, a descrição será atualizada com honestidade:
- “Ao conectar a conta GiftGenius, pode visualizar seus pedidos anteriores para oferecer recomendações mais personalizadas.”
É muito importante não prometer o que o App não faz e não omitir ações críticas. Toda a documentação reunida para o Módulo 18 destaca: as informações na listagem devem corresponder exatamente ao comportamento real, especialmente para aspectos sensíveis como pagamentos e PII.
8. Relação entre os requisitos do Store e a sua arquitetura
É importante perceber que os requisitos do Store não existem no vácuo. Todos esses requisitos não são “mais um formulário do marketing”. O Store, essencialmente, verifica aquilo que você já fez nos módulos de segurança e produção:
- Se você configurou OAuth, endpoints .well-known e verificação de tokens de forma cuidadosa, será estranho se o App, de repente, pedir ao usuário meio mundo por meio de escopos amplos. Um App assim cairá facilmente na revisão como “com permissões excessivas”.
- Se você implementou de forma correta a política de retenção e o scrub de PII, será mais fácil escrever uma Privacy Policy verdadeira e passar na verificação. O Store e os usuários podem seguir o link e comparar suas promessas com os processos reais.
- Se você depurou bem a estabilidade do servidor MCP, logs e métricas (módulos sobre observabilidade e SLO), os revisores terão menos questões sobre desempenho e erros das ferramentas.
As permissões mínimas complementam bem esse quadro: você não apenas é seguro e estável, mas também “modesto” nas solicitações de dados do usuário.
9. Mini prática durante a aula
Para não ficar só na teoria, destrinche agora mesmo seu App atual (ou o GiftGenius) passo a passo.
Primeiro, liste todas as ações reais que o App consegue fazer. Por exemplo: “selecionar presentes”, “criar pedido”, “mostrar histórico”, “salvar nos favoritos”, “enviar e‑mail para colegas”. É melhor fazer isso em texto comum, sem pensar ainda nos detalhes técnicos.
Depois, para cada ação, responda: “Quais dados do usuário isso afeta?” e “Isso altera o estado em um sistema externo?”. Assim, você automaticamente dividirá as ações em read‑only e consequential.
Após isso, associe as ações aos níveis de permissões: onde bastam apenas model capabilities, onde são necessários escopos OAuth e onde são necessários MCP tools com a flag consequential: true e, possivelmente, confirmação do usuário.
E agora jogue “tesoura”: o que pode ser cortado do primeiro lançamento sem matar o valor principal? Muitas vezes, sem histórico, favoritos e notificações por email, o App ainda cumpre sua função principal. Ou seja, essas permissões podem ficar para a versão 1.1 ou 2.0.
10. Erros típicos com os requisitos do Store e permissões
Erro nº 1: “Vamos fazer um super App que faz tudo, e o Store que se vire”.
O desenvolvedor descreve o App como um assistente universal (“ajudo com finanças, medicina, direito e compras”), conecta uma dezena de MCP tools e pede o máximo de direitos. Esse App, ao mesmo tempo, entra em domínios sensíveis (medicina/finanças/direito), solicita muitos dados e viola o princípio “um job por app”. Resultado previsível: a moderação fará muitas perguntas ou simplesmente rejeitará. É melhor fazer vários Apps enxutos com permissões claras.
Erro nº 2: Autorização com permissões excessivas “por via das dúvidas”.
Clássico: o App pede email, profile, orders.read, orders.write, billing.read, embora, na prática, só seja necessário “selecionar um presente pela descrição”. Do ponto de vista do usuário, isso parece um coletor voraz de dados; do ponto de vista do Store, um aplicativo arriscado. Na documentação de segurança de Apps, isso é citado como exemplo de má prática.
Erro nº 3: Divergência entre manifesto e listagem.
No manifesto, você tem create_order, cancel_order e acesso a operações de pagamento, mas na descrição você escreve apenas “recomenda presentes”. Mais cedo ou mais tarde algum revisor ou usuário notará que o App faz mais do que é declarado. Isso mina a confiança e pode levar à remoção do App do Store.
Erro nº 4: Tentar esconder ações sensíveis atrás de uma UI “inofensiva”.
Por exemplo, você desenha no widget um botão “Salvar lista”, que na verdade envia um e‑mail para todo o departamento ou cria tarefas em um sistema de terceiros, sem explicar isso nas permissões. O Store não gosta de surpresas. Nos guias para desenvolvedores está dito claramente: o aplicativo deve fazer exatamente o que promete, sem comportamento oculto.
Erro nº 5: Pedir login “na entrada” quando dá para passar sem ele.
O App inicia — e já pede para conectar a conta, conceder acesso a tudo, senão “não funciona”, embora metade dos cenários possa ser implementada anonimamente. Isso prejudica a conversão e cria a impressão de que você está com pressa para coletar dados, e não para entregar valor. É muito melhor primeiro mostrar que o App é realmente útil e só depois explicar por que são necessários direitos adicionais.
Erro nº 6: Ignorar o contexto organizacional.
Às vezes, o desenvolvedor faz um App “para todos”, embora, na essência, seja uma ferramenta corporativa interna. Como resultado, ele leva para o Store permissões muito específicas (CRM interna, dados privados de funcionários) que é difícil explicar adequadamente ao usuário comum. Nesses casos, valeria a pena mirar o modo org‑only e uma revisão interna, e não o Store público.
GO TO FULL VERSION