Como publicar um servidor MCP no AWS Lambda, Azure e Cloud Run lado a lado
Um servidor MCP em TypeScript sem estado, três hosts. Veja a configuração exata do Lambda Web Adapter, o host.json do Azure Functions para servidores autogerenciados e o comando de deploy do Cloud Run, além das opções de autenticação, dos timeouts e das contrapartidas de cold start que definem qual plataforma serve ao seu projeto.
Seu servidor MCP roda bem no notebook via stdio. Depois, um colega pede uma URL que ele possa colar em um cliente, e aí o trabalho de verdade começa. Um servidor remoto precisa de HTTPS, autenticação, um transporte que sobreviva a balanceadores de carga e um host que não cobra de você enquanto ninguém o chama. Este artigo pega um servidor TypeScript pequeno e o coloca em três plataformas: AWS Lambda, Azure Functions e Google Cloud Run. Você recebe a configuração que realmente importa em cada uma, o controle de acesso que mantém estranhos do lado de fora e uma comparação direta para escolher um host em dez minutos, e não em uma semana.
💡 Escopo: todos os trechos abaixo partem do transporte Streamable HTTP. O stdio serve para processos filhos locais, então um servidor que fala apenas stdio precisa de uma camada HTTP antes que qualquer um desses hosts consiga executá-lo.
Escolha o transporte antes da nuvem
Por que o modo sem estado vence no serverless
Plataformas serverless iniciam e encerram instâncias quando bem entendem. A requisição um cai na instância A, a dois na instância B, e a três dispara um cold start na instância C. Se o seu servidor guarda uma sessão na memória, essa sequência quebra tudo.
A solução é um servidor Streamable HTTP sem estado: um único endpoint /mcp que aceita um POST, responde e esquece. As três plataformas são construídas em torno desse formato. A prévia autogerenciada do Azure só aceita servidores sem estado no transporte streamable-http. O Cloud Run documenta SSE e Streamable HTTP como suas duas opções remotas, com streaming de resposta HTTP integrado. O Lambda funciona da mesma forma assim que você coloca um web adapter na frente.
O que a especificação de julho de 2026 mudou
A revisão 2026-07-28 da especificação do MCP seguiu na mesma direção:
Sem sessões no nível do protocolo. O cabeçalho Mcp-Session-Id foi removido do Streamable HTTP.
Sem handshake. A troca initialize foi removida, e agora toda requisição leva sua versão de protocolo e as capacidades do cliente em _meta.
Estado por meio de handles. Um servidor que precisa de memória entre chamadas gera um handle explícito e o passa como um argumento comum de ferramenta.
Sem retomada de stream. Um stream de resposta interrompido perde a requisição em andamento, e o cliente precisa enviá-la de novo com um novo ID de requisição.
HTTP+SSE foi descontinuado. Trabalhos novos devem usar Streamable HTTP.
Na prática, você pode escrever o servidor como código comum de requisição e resposta e deixar a plataforma rodar quantas cópias quiser. Um alerta: as versões do SDK vêm depois das revisões da especificação, então fixe a versão do seu SDK e teste com os clientes que você usa antes de confiar em um deploy.
Um servidor, três destinos
O handler que todos os hosts compartilham
O servidor de demonstração expõe duas ferramentas que servem de fachada para a API para desenvolvedores da PicassoIA: uma inicia um job de imagem, a outra consulta o resultado. A API segue o estilo Replicate, é assíncrona e tem a URL base https://api.picassoia.com/v1, autenticação Bearer, POST /models/{owner}/{name}/predictions para iniciar um job e GET /predictions/{id} para ler o resultado. Separar o trabalho em início e consulta mantém cada requisição curta, o que combina com plataformas que cobram por milissegundo. O job abaixo tem como alvo o PicassoIA Image pelo slug picassoia/picassoia-image.
Um servidor e um transporte novos a cada requisição é o padrão sem estado dos exemplos do SDK, e custa quase nada, porque registrar duas ferramentas é barato. Os nomes dos métodos mudam entre as versões do SDK, então ajuste o trecho à versão que você instalar e confira os campos de requisição e resposta na documentação da API PicassoIA.
Segredos ficam fora da imagem
Não coloque nada sensível dentro do contêiner. Leia PICASSOIA_API_TOKEN do cofre de segredos da plataforma: AWS Secrets Manager ou SSM Parameter Store no Lambda, uma configuração de aplicativo que aponta para um cofre gerenciado no Azure e o Google Secret Manager no Cloud Run.
💡 As contas da PicassoIA permitem 5 predições simultâneas, compartilhadas entre tokens e conexões MCP. Limite o paralelismo do seu host com a concorrência reservada do Lambda, --max-instances e --concurrency no Cloud Run, ou o número máximo de instâncias do Azure, em vez de descobrir o teto em produção.
Faça o deploy no AWS Lambda
Configuração do Lambda Web Adapter
O caminho menos invasivo roda seu app Express sem alterações pelo Lambda Web Adapter. Para uma imagem de contêiner, é apenas uma linha a mais:
FROM public.ecr.aws/docker/library/node:22-slim
COPY --from=public.ecr.aws/awsguru/aws-lambda-adapter:1.1.0 /lambda-adapter /opt/extensions/lambda-adapter
ENV PORT=8080 AWS_LWA_INVOKE_MODE=response_stream AWS_LWA_READINESS_CHECK_PATH=/health
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY dist ./dist
CMD ["node", "dist/server.js"]
Prefere pacotes zip? Anexe a camada do adapter, defina AWS_LAMBDA_EXEC_WRAPPER como /opt/bootstrap e aponte o handler para um script de inicialização. O adapter lê a porta de AWS_LWA_PORT (ele recorre a PORT, padrão 8080) e verifica o caminho de prontidão antes de encaminhar o tráfego.
Function URL e streaming de resposta
Coloque uma Function URL na frente e defina o modo de invocação como RESPONSE_STREAM, que combine com a variável do adapter acima. O modo bufferizado padrão segura a resposta inteira até a ferramenta terminar, o que anula o streaming. O Lambda oferece até 15 minutos por invocação e até 10 GB de memória, muito mais do que uma ferramenta de início e consulta precisa.
Existem dois caminhos de acesso:
AWS_IAM Function URL. Os chamadores assinam as requisições com SigV4. Bom para tráfego entre serviços, incômodo para clientes MCP de desktop.
NONE mais uma verificação própria. Execute OAuth dentro do servidor ou coloque um autorizador na frente. Um autorizador Cognito ou Lambda pelo API Gateway é a escolha usual, mas o timeout padrão da integração fica perto de 30 segundos, então chamadas longas de ferramenta favorecem a Function URL.
O Serverless Framework v4 pode configurar tudo isso com algumas linhas de YAML:
mcp:
servers:
images:
server: index.ts
💡 Esse post aponta duas armadilhas: o login OAuth interativo exige um domínio personalizado na raiz, e não a URL padrão execute-api, e o Cognito não tem registro dinâmico de clientes.
Faça o deploy no Azure Functions
O host.json que importa
O Azure executa servidores construídos com o SDK como custom handlers: o host do Functions recebe a requisição e a repassa ao seu processo. A documentação de MCP autogerenciado da Microsoft traz este arquivo mínimo para um servidor TypeScript, e o quickstart de Node o mostra em um projeto funcional:
O perfil mcp-custom-handler ativa o proxy HTTP, roteia todos os caminhos ({*route}) para o seu servidor e limpa o prefixo de rota, para que /mcp chegue intacto. Faça o valor port coincidir com a porta em que o servidor escuta. Teste localmente com func start, já que o depurador com F5 ainda não é suportado, e depois publique com func azure functionapp publish <APP_NAME>.
Limites da prévia e login com Entra
Leia as letras miúdas antes de se comprometer: este recurso está em prévia pública. Ele aceita apenas servidores sem estado, em streamable-http, escritos com os SDKs de Python, TypeScript, C# ou Java, e o app precisa rodar no plano Flex Consumption. Se você precisa de estado, a Microsoft indica a extensão de MCP do Functions. O Flex Consumption pode manter instâncias sempre prontas para reduzir cold starts, ao custo de pagar pela capacidade ociosa.
A autenticação é onde o Azure se destaca. A autenticação de servidor integrada da plataforma implementa para você os requisitos de autorização do MCP: emite o desafio 401, publica o documento de Protected Resource Metadata e envia os clientes ao Microsoft Entra ID para entrar. O host.json expandido da documentação define defaultAuthorizationLevel como anonymous e deixa o login a cargo da camada da plataforma, então ative isso antes de a URL ir para qualquer lugar público.
Faça o deploy no Cloud Run
Um comando a partir do código-fonte
O Cloud Run é o que menos complica. Com um Dockerfile ou um projeto Node na pasta:
Já tem uma imagem? gcloud run deploy --image IMAGE_URL --port PORT resolve. O Cloud Run injeta PORT, e o servidor precisa escutar em 0.0.0.0, o que o handler compartilhado já faz. A linha do adapter no Dockerfile da seção do Lambda é apenas um arquivo inerte aqui, então uma mesma imagem pode servir às duas plataformas.
Privado por padrão
Uma nova URL do Cloud Run exige o papel de IAM Cloud Run Invoker (roles/run.invoker) em cada requisição. Para um cliente local, a documentação do Google recomenda um proxy que injete a sua identidade:
gcloud run services proxy mcp-images --region us-central1 --port=3000
Depois, aponte o cliente para http://localhost:3000/mcp. Chamadores automatizados podem enviar um token ID OIDC como Authorization: Bearer <token>, com o público definido como a URL run.app do serviço. Chamadores que rodam no Cloud Run têm mais opções, incluindo um sidecar, a autenticação padrão entre serviços ou o Cloud Service Mesh. Um servidor público, voltado ao consumidor, precisa de --allow-unauthenticated mais OAuth dentro do seu app, e essa é uma decisão a tomar de propósito, não por padrão.
Instâncias quentes e timeouts
O Cloud Run escala a zero por padrão. Adicione --min-instances 1 se os cold starts incomodarem, e preveja o custo da instância ociosa. As requisições podem durar até 60 minutos com --timeout (o padrão é 5 minutos), o maior teto dos três, e o streaming de resposta HTTP não exige nenhuma opção extra.
Comparação lado a lado
Pergunta
AWS Lambda
Azure Functions
Cloud Run
Empacotamento
Imagem de contêiner com o Web Adapter, ou zip mais camada
Custom handler mais host.json
Imagem de contêiner ou deploy a partir do código-fonte
Servidores com estado
Evitar
Não na prévia autogerenciada
Evitar
Requisição mais longa
15 minutos
Definida pelo plano Flex Consumption
60 minutos
Opções de login
Function URL com IAM, autorizador Cognito ou Lambda
Autenticação integrada com Entra ID
Papel Invoker ou token ID OIDC
Instâncias quentes
Concorrência provisionada
Instâncias sempre prontas
--min-instances
Status para MCP autogerenciado
Funciona pelo adapter
Prévia pública
Caminho de hospedagem documentado
Qual host serve para cada time?
Já na AWS, com tráfego irregular: Lambda. Você paga por requisição e nada enquanto está ocioso.
Time da Microsoft com Entra ID: Azure Functions. A autenticação integrada poupa você de escrever uma camada OAuth, desde que um recurso em prévia seja aceitável.
Time pequeno com chamadas longas de ferramenta: Cloud Run. A menor complicação e o timeout mais longo.
Se você não consegue decidir, construa primeiro uma imagem de contêiner. Ela roda no Cloud Run como está, roda no Lambda pelo adapter, e o mesmo código roda atrás do custom handler do Azure.
Teste o endpoint antes dos clientes
Execute o MCP Inspector com npx @modelcontextprotocol/inspector, escolha Streamable HTTP, cole sua URL /mcp e liste as ferramentas. Depois, faça o teste que as pessoas pulam: chame a URL sem credenciais.
curl -i -X POST "$URL/mcp" -H "Content-Type: application/json" -d '{}'
Um 401 ou 403 significa que a porta da frente está protegida. Qualquer outra resposta significa que a requisição passou pela sua autenticação, e a sua conta upstream paga por tudo o que esse chamador fizer a seguir.
3 erros comuns
Vincular ao localhost.127.0.0.1 funciona no notebook e falha atrás de qualquer uma dessas plataformas. Vincule a 0.0.0.0.
Manter estado na memória. Um contador ou cache que vive no processo desaparece no próximo cold start. Use handles explícitos ou um armazenamento externo.
Bufferizar o stream. O modo de invocação padrão do Lambda é bufferizado, e um proxy no meio do caminho pode fazer o mesmo. Se as mensagens de progresso chegarem todas de uma vez, procure um buffer.
Escreva e ilustre com a PicassoIA
A mesma plataforma que oferece algo para o seu servidor chamar também pode escrever o código ao redor dele e criar as imagens da documentação.
Use o Claude Sonnet 5 na PicassoIA
Um modelo de programação leva você dos trechos acima a um servidor que combina com as suas próprias ferramentas. O Claude Sonnet 5 lida com tarefas de programação em várias etapas e uso de ferramentas, e lê imagens, então uma captura de tela de um deploy que falhou pode ir direto para a requisição.
Cole um prompt que nomeie o transporte, as ferramentas e o host, por exemplo: "Write a stateless Streamable HTTP MCP server in TypeScript with two tools, start_job and get_job, ready for Cloud Run."
Preencha o prompt de sistema uma vez para que cada resposta siga as suas regras: sem estado, vincular a 0.0.0.0, ler PORT, sem sessões na memória.
Escolha um nível de effort adequado à tarefa, usando a tabela abaixo.
Deixe o max_tokens no padrão de 8.192 para respostas de um único arquivo, e peça um arquivo por vez se uma resposta for cortada.
Anexe uma imagem quando tiver uma captura de log. A configuração max_image_resolution vem em 0,5 megapixel por padrão e reduz a imagem antes do envio.
Parâmetro
Configuração sugerida
Use para
effort
low (padrão)
Ajustes de configuração e correções de uma linha
effort
high ou max
Fluxos de autenticação e bugs que tocam vários arquivos
max_tokens
8192 (padrão)
Um arquivo por resposta
system_prompt
Suas regras de hospedagem
Saída coerente em todo o projeto
image
Captura de erro
Depuração de logs de deploy
Para uma segunda opinião sobre um bug difícil de autenticação, rode o mesmo prompt no GPT 5.6 Sol e compare as duas respostas.
Gere suas próprias imagens
Quando o servidor estiver no ar, ele vai precisar de um cabeçalho para o README, um fundo para o diagrama e um cartão para redes sociais. O PicassoIA Image transforma um prompt simples em uma imagem finalizada em segundos, com sete proporções, de 1:1 a 16:9, uma seed bloqueável para resultados reproduzíveis, saída em JPG, PNG ou WebP e até duas variações por execução. Ele é descrito como ilimitado, sem teto por imagem, então você pode iterar à vontade. Quando uma imagem fixa merecer movimento, o PicassoIA Video a anima em um clipe curto.
Experimente este prompt: a quiet loft office at dusk, laptop open on an oak desk, soft window light, 35mm photograph, film grain. Mude um detalhe, trave a seed, gere de novo e compare as duas. Abra a PicassoIA, rode seu primeiro prompt e veja como fica sua próxima imagem. Todos os modelos estão em picassoia.com/en/all-models, então há bastante coisa para experimentar.