Pular para o conteúdo
mnzes

Qual a diferença entre stdio e HTTP no MCP?

PorDiógenes MenezesAprendendo IA em público

12 min de leitura

O MCP define dois transportes. No stdio, o cliente sobe o servidor como subprocesso e os dois trocam mensagens JSON-RPC delimitadas por linha pelo stdin e pelo stdout. No Streamable HTTP, o servidor expõe um endpoint único e cada mensagem vira um POST, cuja resposta é um objeto JSON ou um stream SSE preso àquela requisição. A semântica do protocolo é a mesma nos dois1.

Essa última frase é a que orienta tudo o que vem depois. A especificação chama o transporte de binding: ele define como a mensagem é enquadrada e entregue, como o metadado da requisição viaja e como cancelamento e término são sinalizados. Ele não define o que as mensagens significam1.

O transporte é a camada de baixo dos três papéis descritos na arquitetura do MCP. A escolha entre os dois quase sempre é a mesma decisão de servidor local ou remoto, vista de outro ângulo, e as consequências de operação aparecem em MCP em produção.

stdio · máquina localStreamable HTTP · redeclienteservidor(processo filho)stdinuma linha = uma mensagemstdout volta, stderr é logclienteservidor(processo próprio)POST /mcpresposta: um JSON ou um streamSSE preso àquela requisição
Figura 1A semântica do protocolo é idêntica nos dois. O que muda é o enquadramento da mensagem e quem é dono do ciclo de vida do processo do outro lado.

stdio, uma linha por mensagem

O cliente lança o servidor como subprocesso. O servidor lê JSON-RPC do stdin e escreve JSON-RPC no stdout, uma mensagem por linha, e as mensagens não podem conter quebra de linha embutida2.

Três regras dessa página explicam quase todo bug de servidor stdio que você vai encontrar.

O servidor não pode escrever no stdout nada que não seja mensagem MCP válida. Um print() de depuração esquecido no meio do código corrompe o enquadramento e o cliente para de entender o canal. É a causa número um de “meu servidor não conecta” e não aparece em nenhum log, porque o log é justamente o que quebrou.

O servidor pode escrever strings UTF-8 no stderr para qualquer finalidade de log, e o cliente não deve presumir que saída em stderr indica erro2. É para lá que vai o seu print().

Todas as mensagens compartilham um canal só: não existe stream por requisição. Isso tem consequência no cancelamento. Como não há stream para fechar, o cliente cancela mandando uma notificação notifications/cancelled com o ID da requisição, e o servidor não pode mandar mais nenhuma mensagem daquela requisição depois disso2.

O desligamento tem uma sequência definida: o cliente fecha o stream de entrada do filho, espera o servidor sair e, se ele não sair em tempo razoável, termina o processo à força — em POSIX escalando de SIGTERM para SIGKILL, no Windows via TerminateProcess ou Job Objects2. O lado do servidor tem uma obrigação correspondente: sair rápido quando o stdin fecha ou quando a leitura retorna fim de arquivo. Esse é o sinal de encerramento gracioso portável, e servidor que o ignora é servidor que só morre no SIGKILL.

Se o processo cai sozinho, o cliente deve reiniciá-lo. E aqui aparece um efeito direto do protocolo ter virado stateless: como não há sessão, as requisições em voo simplesmente se perdem e o cliente pode reemitir contra o processo novo. O que precisa ser refeito são os streams de subscriptions/listen ativos2.

Uma observação que costuma passar batido: o enquadramento do stdio não depende das streams padrão. Uma mensagem JSON-RPC por linha sobre um fluxo de bytes bidirecional confiável funciona igual em socket Unix ou TCP, e a especificação recomenda que transportes customizados sobre esse tipo de canal reaproveitem esse enquadramento em vez de inventar outro1.

Streamable HTTP, um POST por mensagem

O servidor precisa expor um caminho HTTP único, o endpoint MCP, que aceite POST. Toda mensagem JSON-RPC enviada pelo cliente precisa ser um novo POST para esse endpoint, e o cliente precisa incluir um cabeçalho Accept listando application/json e text/event-stream3.

O corpo é uma requisição ou uma notificação, nunca uma resposta. Se for notificação e o servidor aceitar, a resposta é 202 Accepted sem corpo. Se for requisição, o servidor devolve Content-Type: application/json com um objeto único ou Content-Type: text/event-stream com um stream, e o cliente precisa suportar os dois3.

O stream SSE é o ponto que mais confunde quem vem da revisão antiga. Ele é preso à requisição: carrega notificações relacionadas àquela chamada, como notifications/progress, e termina na resposta final. O servidor não pode mandar requisições JSON-RPC independentes por ali. Streams longos existem, mas por um caminho explícito: o cliente manda subscriptions/listen e a resposta daquela requisição é o stream que fica aberto entregando as notificações que ele assinou3.

Duas recomendações operacionais que evitam dor de cabeça: incluir X-Accel-Buffering: no na resposta SSE, para proxies reversos não bufferizarem os eventos, e emitir periodicamente uma linha de comentário SSE como keep-alive nos streams longos, para intermediários não derrubarem a conexão em períodos de silêncio3.

O cancelamento aqui é o oposto do stdio: fechar o stream de resposta precisa ser tratado pelo servidor como cancelamento daquela requisição. Como cada requisição tem seu próprio stream, a desconexão é inequívoca3.

Os cabeçalhos que o servidor cobra

A revisão 2026-07-28 espelha campos do corpo em cabeçalhos HTTP para que balanceadores e gateways possam rotear sem abrir o JSON. Isso é obrigatório, não opcional.

Todo POST precisa levar MCP-Protocol-Version, e o valor precisa bater com io.modelcontextprotocol/protocolVersion no _meta do corpo. Se não bater, o servidor precisa recusar com 400 Bad Request e o erro HeaderMismatch, de código -32020. Também são obrigatórios Mcp-Method, com o nome do método, e Mcp-Name, com params.name ou params.uri, nas chamadas de tools/call, resources/read e prompts/get3.

Existe ainda uma extensão que espelha parâmetro de tool em cabeçalho: uma propriedade x-mcp-header no schema do argumento faz o cliente enviar Mcp-Param-{Nome} com aquele valor. Serve para roteamento por região ou por tenant sem inspeção de corpo. A spec vem com o aviso óbvio junto: não marque parâmetro sensível assim, porque o valor fica visível para qualquer intermediário da rede3.

Do lado de segurança, três exigências. O servidor precisa validar o cabeçalho Origin em toda conexão e responder 403 Forbidden se ele estiver presente e inválido; deve escutar apenas em 127.0.0.1 quando roda local, em vez de 0.0.0.0; e deve implementar autenticação em todas as conexões. Sem isso, um atacante consegue usar DNS rebinding para interagir com o seu servidor MCP local a partir de um site remoto3.

O que mudou em 28 de julho de 2026

A revisão 2026-07-28 mudou a forma do Streamable HTTP e quebra cliente antigo. As três remoções que importam3:

  1. O endpoint GET de stream saiu. Não existe mais stream autônomo aberto por GET para receber mensagens iniciadas pelo servidor.
  2. As sessões de protocolo saíram. O cabeçalho Mcp-Session-Id, e o DELETE que encerrava a sessão, não fazem parte desta revisão.
  3. A retomada por Last-Event-ID não é suportada. Se a conexão cai no meio de uma chamada, a requisição se perde.

Um servidor que implementa só esta revisão e recebe tráfego antigo deve responder 405 Method Not Allowed a GET e DELETE no endpoint, ignorar Mcp-Session-Id sem cunhar nem ecoar identificador, e ignorar Last-Event-ID3.

O SSE não morreu, o transporte com esse nome está de saída

Aqui é onde quase todo texto sobre MCP erra, e a afirmação precisa de data.

Em 30 de julho de 2026, o registro de features depreciadas lista o transporte HTTP+SSE da revisão 2024-11-05 — aquele de dois endpoints, com um GET que abria o stream e um POST separado para as mensagens — como depreciado desde a revisão 2025-03-26, reclassificado sob a política formal de ciclo de vida pela SEP-2596, com remoção mais cedo possível três meses depois de essa política atingir o estado Final4. Novas implementações não devem adotá-lo, e as existentes devem migrar.

O SSE como tecnologia continua no centro do transporte atual: sempre que uma requisição precisa emitir progresso antes do resultado, ou quando o cliente abre um subscriptions/listen, a resposta é um stream SSE3. Dizer “o MCP abandonou o SSE” está errado. Dizer “o transporte HTTP+SSE de dois endpoints está depreciado” está certo.

O mesmo registro traz o resto do que está de saída em 30 de julho de 2026: roots, sampling, logging e o registro dinâmico de cliente, todos depreciados na 2026-07-28, com remoção possível na primeira revisão publicada em 28 de julho de 2027 ou depois4.

Qual escolher

um usuáriovários usuáriosna máquinado usuárioem umservidorstdioStreamable HTTPbind em 127.0.0.1valide o OriginStreamable HTTPcom autenticaçãoStreamable HTTPauth por requisiçãosem estado na instânciaHTTP+SSE de dois endpoints (2024-11-05): depreciado desde 2025-03-26
Figura 2A decisão tem um ramo só: o servidor roda na máquina de quem usa ou não. Fora do canto superior esquerdo, tudo é Streamable HTTP com autenticação.

Servidor na máquina do usuário, servindo essa pessoa: stdio. Sem rede, sem autenticação, sem porta aberta, e o ciclo de vida do processo é do cliente. É o que acontece quando você acrescenta um servidor ao arquivo de configuração do seu editor.

Servidor local mas acessado por HTTP, o que é legítimo em alguns setups: Streamable HTTP, escutando em 127.0.0.1 e validando Origin. Sem essas duas coisas, qualquer página aberta no browser do usuário alcança o servidor.

Servidor em outra máquina, com um ou muitos usuários: Streamable HTTP com autenticação. Como não existe sessão de protocolo, cada requisição carrega a própria credencial e qualquer réplica atende qualquer requisição. Isso é o que torna o escalonamento horizontal trivial e o que obriga o servidor a não guardar estado na instância.

Onde cada um falha

stdio não tem isolamento. O servidor roda com as permissões do usuário, na máquina do usuário, com acesso ao mesmo sistema de arquivos e às mesmas variáveis de ambiente. Não há sandbox no protocolo. Instalar um servidor stdio de terceiro é executar código de terceiro.

stdio não escala para além de uma pessoa. Um processo por cliente, na máquina de cada um. Dez pessoas usando o mesmo servidor são dez instalações para atualizar.

HTTP transformou perda de conexão em perda de trabalho. Sem Last-Event-ID, um POST de tool que estava rodando há quarenta segundos e perde a conexão perde tudo. O cliente precisa reemitir com um id novo, e o servidor precisa que a operação seja idempotente ou reversível — coisa que a maior parte dos servidores não é.

HTTP local sem Origin é uma porta aberta. É o único modo de falha desta lista que a especificação nomeia explicitamente, com o vetor descrito: DNS rebinding a partir de um site remoto.

O cancelamento tem semânticas diferentes e o código costuma ter uma só. No stdio o cliente manda uma notificação; no HTTP ele fecha o stream. Um servidor escrito assumindo um dos dois vai continuar trabalhando depois do cancelamento no outro. Um estudo de medição de 2025 sobre agentes com MCP chegou a recomendar mecanismos de aborto de tarefa entre as otimizações mais relevantes5.

Quanto custa

O custo do transporte em si é pequeno perto do custo do contexto, e é útil manter a proporção em mente. O mesmo estudo de 2025 mediu interações com MCP e mostrou que a inflação de tokens vem do conjunto de prompt de sistema, definições de tool e histórico, não do canal por onde as mensagens passam5.

O que o transporte cobra é operação. Em stdio, um processo por servidor por usuário, com memória e ciclo de vida para gerenciar, e atualização que depende da máquina de cada pessoa. Em HTTP, um serviço para hospedar, autenticar, monitorar e limitar, mais o custo fixo de TLS e de um round-trip de rede por mensagem em vez de uma escrita em pipe.

A conta que decide raramente é de latência. É de quem administra o processo.

Por onde começar

  1. Comece por stdio. Sem rede e sem autenticação, o ciclo de desenvolvimento é mais curto e os erros aparecem no lugar certo.
  2. Redirecione todo log para stderr antes da primeira linha de lógica. Em Python, print() sem file=sys.stderr é o bug clássico.
  3. Escreva o encerramento no stdin fechado. Servidor que só morre no SIGKILL deixa processo órfão na máquina do usuário.
  4. Ao migrar para HTTP, implemente os três cabeçalhos obrigatórios de uma vez. MCP-Protocol-Version, Mcp-Method e Mcp-Name, com validação contra o corpo.
  5. Valide Origin e escute em 127.0.0.1 mesmo em desenvolvimento. O hábito é o que evita subir para produção com 0.0.0.0.
  6. Assuma que qualquer requisição pode ser reemitida. Sem retomada de stream e sem sessão, idempotência deixou de ser refinamento e virou requisito.

O passo 6 é o que mais muda em relação ao que os tutoriais escritos antes de julho de 2026 ensinam.

Footnotes

  1. A página de visão geral de transportes da revisão 2026-07-28 é a fonte para a definição de transporte como binding, para a lista dos dois transportes padrão e para a recomendação de reaproveitar o enquadramento do stdio em transportes customizados. Verificada em 30 de julho de 2026. 2 3

  2. A página do transporte stdio da mesma revisão é a fonte para o enquadramento por linha, para as regras de stdout e stderr, para o cancelamento por notifications/cancelled, para a sequência de desligamento e para o comportamento em terminação inesperada. 2 3 4 5

  3. A página do Streamable HTTP da mesma revisão é a fonte para o endpoint único, para as regras de Accept e de resposta, para o modelo de stream por requisição, para os cabeçalhos obrigatórios e o erro HeaderMismatch, para as exigências de Origin e bind local, e para as três remoções desta revisão. 2 3 4 5 6 7 8 9 10 11

  4. O registro de features depreciadas da revisão 2026-07-28 é a fonte para o estado do transporte HTTP+SSE de 2024-11-05 e para as datas de remoção mais cedo possível de roots, sampling, logging e registro dinâmico de cliente. 2

  5. Ding et al. (2025) mediram interações de agentes com MCP e atribuíram a inflação de tokens ao prompt de sistema, às definições de tool e ao histórico, recomendando chamadas de tool em paralelo e mecanismos de aborto de tarefa. 2

Perguntas frequentes

Quais transportes o MCP define?
Dois padrão, na revisão 2026-07-28: stdio, em que o cliente sobe o servidor como subprocesso e troca mensagens delimitadas por linha pelas streams padrão, e Streamable HTTP, em que cada mensagem é um POST para um endpoint único. A semântica do protocolo é idêntica nos dois; muda só o enquadramento.
O que é Streamable HTTP no MCP?
É o transporte de rede do MCP. O servidor expõe um endpoint único que aceita POST, cada requisição JSON-RPC vira um POST, e a resposta volta como um objeto JSON ou como um stream SSE preso àquela requisição. Ele substituiu o transporte HTTP+SSE de dois endpoints na revisão 2025-03-26.
O SSE foi depreciado no MCP?
O transporte HTTP+SSE de dois endpoints, da revisão 2024-11-05, está depreciado desde 2025-03-26 e consta no registro de features depreciadas em 30 de julho de 2026. O SSE em si continua em uso: o Streamable HTTP responde com stream SSE sempre que a requisição exige eventos antes do resultado.
Qual transporte MCP devo usar?
Se o servidor roda na máquina de quem usa e serve uma pessoa, stdio. Em qualquer outro caso, Streamable HTTP com autenticação. Rodar HTTP em localhost também é legítimo, mas exige validar o cabeçalho Origin e escutar em 127.0.0.1, senão qualquer página aberta no browser alcança o servidor.
O cabeçalho Mcp-Session-Id ainda existe?
Não na revisão 2026-07-28, que removeu as sessões de protocolo junto com o endpoint GET de stream e a retomada por Last-Event-ID. Um servidor que só implementa essa revisão deve responder 405 a GET e DELETE no endpoint, ignorar Mcp-Session-Id sem ecoar nada e ignorar Last-Event-ID.
Por que o servidor stdio quebra quando eu imprimo algo?
Porque o stdout é o canal do protocolo. A especificação proíbe o servidor de escrever no stdout qualquer coisa que não seja mensagem MCP válida, e uma linha solta de print corrompe o enquadramento. Log de servidor stdio vai para stderr, que o cliente pode capturar, encaminhar ou ignorar.

Referências

  1. Agentic AI Foundation. Model Context Protocol specification, revision 2026-07-28 — Transports (2026)
  2. Agentic AI Foundation. Model Context Protocol specification, revision 2026-07-28 — stdio transport (2026)
  3. Agentic AI Foundation. Model Context Protocol specification, revision 2026-07-28 — Streamable HTTP transport (2026)
  4. Agentic AI Foundation. Model Context Protocol — Deprecated features registry, revision 2026-07-28 (2026)
  5. Ding, Z., Zhu, M., Liu, Y.. Network and Systems Performance Characterization of MCP-Enabled LLM Agents (2025)arXiv:2511.07426