1. O problema dos túneis “aleatórios”
Quando você executa pela primeira vez ngrok http 3000 ou o rápido Cloudflare Quick Tunnel, parece mágica: pum — e seu http://localhost:3000 vira https://random-1234.tunnelprovider.com. Dá para copiar o URL no ChatGPT Dev Mode, e o GPT carrega seu App todo feliz.
Aí você reinicia o túnel… e recebe um novo domínio. O URL antigo nas configurações do aplicativo Dev no ChatGPT de repente vira um “link quebrado”, o GPT mostra honestamente “App unavailable”, e você volta às configurações, troca o URL, clica em Save, espera atualizar, e passa a odiar em silêncio toda essa stack.
Para um “brincar à noite” pontual, isso é tolerável. Mas quando você:
- trabalha no App todos os dias;
- quer mostrar uma versão intermediária a um colega/gestor;
- em paralelo prepara também staging e production,
reconectar o Dev Mode a cada novo URL aleatório vira sofrimento puro.
Além disso, se você já adicionou ao aplicativo algo que depende do domínio (por exemplo, OAuth redirect URI ou webhooks), cada novo URL quebra essas coisas também. Surge um efeito cascata: trocou o túnel — e é preciso corrigir a configuração do App, o redirect‑URL no provedor OAuth e as configurações do receptor de webhook.
Daí nasce a ideia central da aula: um dev‑URL estável não é luxo, é um meio de preservar a sanidade do desenvolvedor.
Insight
O ChatGPT tem timeouts bem rígidos ao trabalhar com seu aplicativo, e é fácil subestimá-los. A chamada de ferramenta do MCP tem limite de tempo: no máximo 2 minutos — depois disso a plataforma simplesmente considera a chamada malsucedida, mesmo que seu servidor ainda esteja fazendo algo.
Com a registração do aplicativo (Store ou Dev Mode) é ainda mais rigoroso: para ler o manifesto, recursos e descrições de ferramentas, o ChatGPT dá cerca de 20 segundos. Se nesse tempo seu servidor MCP não conseguir inicializar, entregar a lista de tools/resources etc., o registro do App falhará por timeout.
Recomendação: toda a inicialização pesada deve acontecer antes de você ir ao Dev Mode ou Store. Aquecimento de conexões com o BD, carregamento de configs grandes, caches preguiçosos — tudo isso é melhor fazer de antemão, por exemplo, acionando o servidor uma vez via MCP Jam ou um script interno separado. Do ponto de vista da plataforma, o servidor MCP deve estar “aquecido” e responder em segundos, e não “acordar” durante o registro.
2. O que é um túnel “maduro”
Vamos fixar em que o túnel “maduro” difere daquele que você executou no início do curso.
O modo inicial (módulo 2) parecia assim:
# Exemplo com ngrok
ngrok http 3000
# Resultado: https://random-abc123.ngrok-free.app
Você pegava esse URL descartável e o colava no Dev Mode. Na próxima execução do ngrok, o URL já era outro, e a configuração do ChatGPT ficava desatualizada.
No caminho “maduro” você tem:
- um subdomínio estático no provedor de túnel (ou seu próprio domínio);
- o mesmo domínio sempre encaminha para seu localhost:3000;
- você pode reiniciar o túnel, a máquina, o roteador, mas o URL permanece o mesmo.
Subdomínios estáticos assim estão disponíveis, por exemplo:
- no ngrok — um domínio estático gratuito por conta;
- no Cloudflare Tunnel — via túnel nomeado e vinculação ao seu domínio.
E o aplicativo do ChatGPT no Dev Mode fica configurado exatamente para esse único URL e não enche mais o seu saco.
Formalmente, os requisitos para nosso túnel “maduro” são:
- um domínio público HTTPS sempre igual;
- certificado TLS válido (o provedor cuida disso para nós);
- um config que descreve: “tudo o que chegar em https://dev.yourdomain.com, encaminhe para http://localhost:3000”;
- opcionalmente — medidas mínimas de segurança (pelo menos não expor o URL no StackOverflow).
3. Configurando um dev‑URL estável: exemplo com Cloudflare Tunnel
No curso recomendamos o Cloudflare Tunnel como ferramenta principal, porque ele serve bem tanto para dev quanto para cenários mais sérios. Já no módulo 2 você viu um exemplo de configuração básica; agora vamos “arrematar” isso até um dev‑URL permanente.
Suponha que temos o aplicativo didático GiftGenius e queremos o URL estável giftgenius-dev.yourdomain.com.
Passos mínimos (resumidos, sem prender ao UI do Cloudflare):
- Vincule seu domínio à conta Cloudflare (uma vez, via painel deles).
- Instale o cloudflared localmente e faça login.
brew install cloudflare/cloudflare/cloudflared # macOS
cloudflared login # abrirá o navegador para autenticação
3. Crie um túnel nomeado:
cloudflared tunnel create giftgenius-dev
4. Configure a rota em ~/.cloudflared/config.yml:
tunnel: giftgenius-dev
credentials-file: /Users/you/.cloudflared/giftgenius-dev.json
ingress:
- hostname: giftgenius-dev.yourdomain.com
service: http://localhost:3000 # nosso servidor Next.js de desenvolvimento
- service: http_status:404
5. Inicie o túnel:
cloudflared tunnel run giftgenius-dev
Agora, enquanto estiverem rodando o npm run dev e o cloudflared tunnel run, seu Next.js local estará acessível no URL permanente https://giftgenius-dev.yourdomain.com. E é exatamente esse que você indica nas configurações do ChatGPT Dev Mode.
Como isso se conecta ao nosso aplicativo
Se você abrir no navegador o URL do seu aplicativo, aquele que informa ao ChatGPT ao conectar o App de Dev:
https://giftgenius-dev.yourdomain.com/mcp
você verá uma resposta (erro) — algo como:
{"jsonrpc":"2.0","error":{"code":-32000,"message":"Method not allowed."},"id":null}
Isso é absolutamente normal, pois o servidor em /mcp não espera uma requisição GET. Todas as outras partes do aplicativo — o widget, o endpoint MCP /mcp, as rotas de API — passam por esse mesmo túnel; você não precisa lembrar um domínio novo a cada vez.
4. Alternativa: subdomínio estável no ngrok
Se você já está acostumado ao ngrok, dá para “amadurecê-lo” de forma parecida usando um static domain. A partir de 2023 o ngrok oferece, até mesmo no plano gratuito, a possibilidade de fixar um subdomínio estático do tipo myapp-dev.ngrok-free.app.
Esquema mínimo:
# ~/.config/ngrok/ngrok.yml
authtoken: <seu token>
tunnels:
giftgenius-dev:
addr: 3000
proto: http
domain: giftgenius-dev.ngrok-free.app
Execução:
ngrok start giftgenius-dev
Como resultado, o URL https://giftgenius-dev.ngrok-free.app será permanente, e é ele que você fornece ao ChatGPT Dev Mode como URL base do aplicativo.
Filosofia igual:
- nada de endereços “aleatórios”;
- só muda o estado interno do túnel (iniciado/não iniciado), e não o domínio;
- não é preciso reconectar o Dev Mode.
Cloudflare e ngrok, nesse sentido, são apenas “sabores de sorvete”. Alguns preferem seus próprios domínios e controle de DNS mais “fino” (Cloudflare), outros gostam do “configurei o YAML — pronto” (ngrok). Para o curso, ambos os caminhos são válidos, o importante é o URL estável.
5. Diagrama: ChatGPT Dev Mode ↔ túnel ↔ stack local
Para formalizar um pouco o que acontece, vamos desenhar um esquema.
flowchart TD
ChatGPT["ChatGPT (Dev Mode)"]
AppCfg["Dev App (config: https://giftgenius-dev...)"]
Tunnel["Túnel Cloudflare/ngrok (giftgenius-dev...)"]
Next["Servidor Next.js de desenvolvimento localhost:3000 + MCP handler"]
ChatGPT --> AppCfg
AppCfg -->|"no config está https://giftgenius-dev.../.well-known/openai-app"| Tunnel
Tunnel -->|"Proxy HTTPS → HTTP"| Next
O ChatGPT nunca sabe o que você está rodando no seu notebook. Para ele existe apenas um endpoint HTTPS. O que está por trás — Vercel, túnel local, Kubernetes — é problema seu. E, nesta aula, nos interessa justamente a estabilidade desse endpoint HTTPS para a desenvolvimento local.
Resta fazer com que, dentro do nosso aplicativo, esse endereço também seja uma única “fonte de verdade”, e não se espalhe em strings hardcoded — é disso que trata a próxima seção.
6. Variáveis de ambiente e baseURL no código
Para que tudo funcione sem surpresas, é útil definir uma vez no código do Next.js o “URL base externo do aplicativo” e, depois, depender só dele.
Por exemplo, na pasta app/lib/config.ts do nosso aplicativo GiftGenius podemos criar:
// app/lib/config.ts
export const baseUrl =
process.env.NEXT_PUBLIC_APP_URL ?? "http://localhost:3000"; // fallback
export const mcpEndpoint = `${baseUrl}/mcp`; // URL do servidor MCP
E em .env.local, durante o desenvolvimento, indicar:
NEXT_PUBLIC_APP_URL=https://giftgenius-dev.yourdomain.com
Então:
- dentro do widget e de quaisquer links você sempre usa baseUrl;
- para o ChatGPT Dev Mode e para o navegador tudo fica consistente;
- se amanhã você migrar para um staging na Vercel com o domínio https://giftgenius-staging.vercel.app, basta mudar apenas a variável de ambiente.
Isso é especialmente importante para:
- callback‑URL (por exemplo, para OAuth, handlers de webhook);
- links que você mostra ao usuário no widget (botão “Abrir no navegador” via openExternal);
- quaisquer URLs absolutos na lógica do aplicativo.
Por enquanto falamos só do dev‑URL, mas a própria ideia arquitetural de “uma única fonte de verdade para baseUrl” funciona muito bem e vai com você para staging/production.
7. Atualizando o URL no ChatGPT Dev Mode
Ok, criamos um domínio estável. Como viver com ele no Dev Mode?
Lógica:
- Nas configurações do aplicativo Dev, você informa uma única vez o URL raiz: https://giftgenius-dev.yourdomain.com/
- O ChatGPT o consulta pelo manifesto (.well-known/openai-app) e, depois, usa as mesmas bases para acessar o MCP (/mcp), estáticos etc.
- Se você muda apenas o código (widget React, MCP handlers, estilos), não é preciso mudar o URL. Basta que o túnel esteja ativo e o servidor Next.js responda.
- Se você trocar o domínio (raro, por exemplo, de ngrok para Cloudflare), precisa entrar uma vez no Dev Mode e mudar o endpoint.
Em alguns casos o ChatGPT faz cache do manifesto, e as mudanças nele podem não surgir instantaneamente. Na interface do Dev Mode geralmente há um botão como “Reload configuration / Refresh App”, mas, no pior cenário, até “desconectar e reconectar o App no mesmo URL” ajuda.
Importante: enquanto você não mudar o URL, o Dev Mode automaticamente “capta” novas versões do código. O principal gatilho para o App é o domínio, não o commit‑hash.
8. Alternando entre dev / staging / prod no Dev Mode
O domínio dev estável é só o primeiro degrau. Para não se afogar no caos de URLs à medida que o projeto cresce, é útil entender desde cedo como o túnel de dev se encaixa no esquema geral de ambientes (dev/staging/prod) e no Dev Mode. Embora staging e prod sejam tema da próxima aula sobre Vercel, o Dev Mode já hoje trabalha com múltiplos ambientes.
Para entender o que vem a seguir, esta tabela ajuda:
| Ambiente | URL base | Onde o código roda |
|---|---|---|
| Local | |
Next.js local + MCP via túnel |
| Staging | |
Vercel Preview / deploy de staging |
| Prod | |
Vercel Production |
Há duas formas de trabalhar com o Dev Mode.
Primeira — um único Dev‑App, mas você atualiza de tempos em tempos o URL nas configurações para testar o staging ou o prod (com cuidado). Serve nas fases iniciais, mas é fácil se confundir: hoje você testou local, amanhã staging, depois de amanhã esqueceu de alternar e, sem querer, envia requisições via Dev‑App para o prod.
Segunda — mais saudável: vários aplicativos Dev, cada um atrelado claramente a um ambiente:
- GiftGenius Dev → giftgenius-dev.yourdomain.com;
- GiftGenius Staging → giftgenius-staging.vercel.app;
- GiftGenius (produção, via Store) → giftgenius.vercel.app.
Nesta aula damos passos incrementais, organizando pelo menos o dev‑URL. Na próxima você verá como ligar Vercel e preview‑deploys ao staging/production.
9. Trabalho em equipe: vários desenvolvedores e um túnel
Enquanto temos um único domínio de dev e um único desenvolvedor introvertido, o túnel é seu amigo pessoal. Mas, quando chega a equipe, túneis e ambientes começam a se cruzar, e é importante evitar a “guerra por um subdomínio”.
Imagine que dois desenvolvedores decidem usar o mesmo subdomínio estático, digamos giftgenius-dev.ngrok-free.app. Ambos executam ngrok start giftgenius-dev em suas máquinas. No melhor caso, um túnel simplesmente não sobe (conflito de domínio); no pior, vocês ficam “derrubando” a sessão um do outro, e o ChatGPT às vezes chega a um, às vezes a outro.
Há algumas estratégias aqui.
A mais simples — domínios de dev pessoais:
- alex.dev.giftgenius.app;
- maria.dev.giftgenius.app.
E um Dev‑App por pessoa no ChatGPT, por exemplo GiftGenius Dev (Alex) e GiftGenius Dev (Maria). Assim, cada um roda seu ambiente local em paz sem atrapalhar o outro.
Um caminho mais “de equipe” — um endpoint de staging compartilhado:
- Todos os devs têm seu túnel de dev pessoal (para depuração individual).
- Além disso, há um staging na Vercel, para onde os feature branches são mesclados e para o qual aponta o Dev‑App compartilhado GiftGenius Staging.
Esse fluxo é comum em equipes reais:
- a feature nasce localmente e é depurada via túnel pessoal;
- depois do pull request e merge, ela é testada por todos via staging (sem túneis, apenas pelo URL da Vercel).
10. Segurança do túnel de dev (curto e sem paranoia)
Túnel é um jeito prático de expor seu servidor local na internet. E a internet, como sabemos, é feita em grande parte de bots, scanners e pessoas que adoram checar se você esqueceu a senha admin/admin.
Coisas básicas para lembrar já no estágio de dev:
- o túnel dá acesso externo a tudo que estiver nessa porta; não exponha ali também a admin do BD, phpMyAdmin e “minha CRM de testes sem senha”;
- não publique o URL do túnel em repositórios e chats públicos;
- desligue o túnel quando não estiver trabalhando (e desligue o notebook de vez em quando — ele também precisa descansar).
Medidas mais sérias como Basic Auth, verificação de cabeçalhos especiais ou token no URL veremos nos módulos de segurança. O importante agora é: túnel é ferramenta de desenvolvimento, não servidor protegido. A produção vai viver em hospedagem de verdade, como a Vercel, com outros mecanismos de proteção.
11. Prática: configurando um dev‑URL estável para nosso aplicativo
Da teoria e alertas — à prática: vamos amarrar tudo isso ao nosso aplicativo didático em Next.js (template do Apps SDK).
Suponha que a estrutura do projeto seja assim:
apps/
web/ # Next.js App + widget
mcp-server/ # (opcional) MCP separado, ou handler /mcp dentro de web
Na prática você pode manter o MCP direto no Next.js, em app/api/mcp/route.ts, mas o princípio é o mesmo.
Passo 1. Ajuste o .env.local
Adicione ali o dev‑URL estável do túnel:
NEXT_PUBLIC_APP_URL=https://giftgenius-dev.yourdomain.com
No código de dev nós já usamos o baseUrl vindo dessa variável (veja acima). Se ainda não usou — é hora de extrair.
Passo 2. Inicie o servidor de dev e o túnel
cd apps/web
npm run dev # Next.js em localhost:3000
# outro terminal
cloudflared tunnel run giftgenius-dev
Verifique no navegador que https://giftgenius-dev.yourdomain.com abre e mostra seu App.
Passo 3. Conecte no ChatGPT Dev Mode
Na interface do ChatGPT (seção para desenvolvedores):
- crie ou edite o GiftGenius Dev;
- no campo URL/Endpoint informe https://giftgenius-dev.yourdomain.com/;
- salve.
Depois disso, o ChatGPT acessa o manifesto em /.well-known/openai-app e, então, começa a executar seu App por cima desse domínio.
Agora você pode:
- alterar o código do widget, MCP handlers, estilos;
- reiniciar o npm run dev;
- reiniciar o cloudflared tunnel run giftgenius-dev;
e, ainda assim, nunca mais mexer nas configurações do Dev‑App, enquanto o domínio for o mesmo.
12. Como isso aparece na lógica do código: exemplo com openExternal
Para fechar o exemplo com o que já escrevemos nas aulas anteriores, vamos adicionar no widget um botão “Abrir a interface completa no navegador”, que também usará o dev‑URL estável.
Suponha que temos o componente React do widget GiftWidget:
// app/components/GiftWidget.tsx
"use client";
import { baseUrl } from "../lib/config"; // pegamos baseUrl do env
export function GiftWidget() {
const handleOpenFull = () => {
window.openai.openExternal({
// abre a página do aplicativo em uma nova aba
url: `${baseUrl}/full`,
label: "Abrir a interface completa",
});
};
return (
<div>
<button onClick={handleOpenFull}>
Modo completo
</button>
</div>
);
}
Se o NEXT_PUBLIC_APP_URL aponta para o túnel, então:
- no desenvolvimento local abrirá a página https://giftgenius-dev.yourdomain.com/full;
- após o deploy em staging — https://giftgenius-staging.vercel.app/full;
- em prod — o domínio de produção.
Mais uma vez — uma única fonte de verdade para o domínio: trocamos o ambiente, mas não trocamos o código.
13. Mini‑estratégia: como pensar o túnel “de forma adulta”
Resumindo em um modelo mental simples, dá para considerar que:
- o túnel é apenas um fio temporário entre seu notebook e um domínio público estável;
- o ChatGPT Dev Mode conhece apenas o domínio, e pouco importa onde o código roda fisicamente;
- quanto menos você muda o domínio, menos tempo gasta nas configurações do ChatGPT e dos provedores OAuth;
- o túnel de dev é só uma linha no seu mapa de ambientes, ao lado de staging (Vercel preview) e prod (Vercel production).
A próxima aula mostra como esse fio é substituído por uma hospedagem de verdade na Vercel e como ligar tudo isso a branches Git, preview‑deploys e produção.
14. Erros típicos ao trabalhar com o túnel “maduro”
Erro nº 1: “Configurei um domínio estático, mas continuo usando URLs aleatórios”.
Às vezes o desenvolvedor cria um lindo giftgenius-dev.yourdomain.com, mas por hábito executa ngrok http 3000 sem config. Resultado: o ChatGPT olha para um domínio, e o código roda por outro. Se você já criou um dev‑URL estável — use só ele e inicie o túnel via config (túnel nomeado/perfil).
Erro nº 2: localhost:3000 hardcoded no código.
Acontece quando no componente React ou no handler do MCP escrevem fetch("http://localhost:3000/api/..."). Localmente até funciona, mas no Dev Mode — e mais ainda em staging/prod — quebra na hora. Sempre extraia o URL base para o config (baseUrl, NEXT_PUBLIC_APP_URL) e use em todo lugar onde precisar de links absolutos.
Erro nº 3: Ficar alterando o URL no Dev Mode em vez de ter um túnel estável.
Se você se pega pensando “tá, vou mudar o URL nas configurações só mais uma vez”, isso é um alerta. Configurar um subdomínio estático no ngrok/Cloudflare leva 10–15 minutos uma única vez, e economiza horas ao longo do desenvolvimento.
Erro nº 4: Domínio estático compartilhado pela equipe sem regras.
Dois devs, um domínio giftgenius-dev.ngrok-free.app, e ambos sobem o túnel quando querem. Resultado — conflito de túneis, respostas “misteriosamente” sumindo no Dev Mode e depuração no estilo “na minha máquina funcionava”. Para equipes, ou domínios de dev pessoais para cada um, ou um domínio de staging em hosting real.
Erro nº 5: Tratar o túnel como “quase produção”.
Às vezes alguém pensa: “Se tenho um URL HTTPS estável via túnel, vamos receber usuários/pagamentos reais por ele”. Isso leva à dor: notebook desligado — aplicativo morto; internet caiu — mesma coisa; e a segurança, no melhor dos casos, é simbólica. Túnel é ferramenta de dev. Para tráfego real existem a Vercel e toda a infraestrutura “adulta”, à qual chegaremos na próxima aula.
Erro nº 6: Esquecer de sincronizar variáveis de ambiente e o Dev Mode.
Muitas vezes mudam a NEXT_PUBLIC_APP_URL no .env.local, mas esquecem de alterar o URL no Dev Mode (ou vice‑versa). O resultado: o widget gera links para um domínio e o ChatGPT acessa outro. Mantenha uma tabelinha simples “ambiente ↔ domínio ↔ App no ChatGPT” e atualize quando algo mudar — é mais barato do que tentar adivinhar qual URL é o verdadeiro agora.
GO TO FULL VERSION