FINANÇAS COMPORTAMENTAIS · PSICOLOGIA ECONÔMICA

MCP stateless não elimina estado: sua aplicação precisa torná-lo explícito

Imagine um servidor MCP que controla navegadores remotos. Uma ferramenta abre o navegador, outra acessa uma URL e a terceira…

Imagine um servidor MCP que controla navegadores remotos. Uma ferramenta abre o navegador, outra acessa uma URL e a terceira tira uma captura de tela.

No primeiro desenho da aplicação, o servidor guarda o navegador numa sessão em memória. A chamada seguinte chega à mesma instância, encontra o recurso e continua o trabalho. Tudo parece simples até o serviço ganhar uma segunda instância, um balanceador ou um retry.

Com o ciclo stateless da especificação MCP 2026-07-28, a próxima requisição pode cair em qualquer instância. Se ela não trouxer um browser_id, a identidade de quem fez a chamada e a operação esperada, o servidor não tem como adivinhar qual navegador deve recuperar.

É aí que a palavra “stateless” costuma confundir.

O protocolo deixa de manter uma sessão implícita. O navegador, o carrinho, o job de vídeo e a tarefa longa continuam existindo. Esse estado não desaparece. Ele precisa ganhar nome, contrato e regras de acesso.

O que realmente sai do protocolo

A nova revisão remove o handshake initialize/initialized, o header Mcp-Session-Id e a sessão mantida no nível do protocolo. Versão, identificação e capacidades do cliente passam a acompanhar cada requisição em _meta.

Na prática, isso reduz a afinidade entre uma conexão e uma instância específica do servidor. Uma chamada não precisa encontrar a mesma memória de processo usada pela chamada anterior. Fica mais simples distribuir tráfego, trocar uma instância com problema e operar o serviço sem sticky session.

Mas essa simplificação vale para o transporte. Ela não decide onde seu produto guarda recursos que vivem por mais de uma chamada.

Vale separar três coisas que antes podiam acabar misturadas:

  1. o contexto do protocolo, como versão e capacidades do cliente;
  2. o estado do produto, como um navegador aberto ou um carrinho em edição;
  3. o progresso de uma operação, como uma exportação que espera aprovação ou mais dados.

O primeiro passa em _meta. Os outros dois continuam sendo responsabilidade da aplicação.

Um handle explícito muda o contrato

Vamos voltar ao navegador remoto. Um fluxo mínimo pode funcionar assim:

create_browser() -> { browser_id: "brw_7f2..." }navigate({ browser_id: "brw_7f2...", url: "https://example.com"})

create_browser persiste o recurso e devolve um handle opaco. navigate recebe esse handle, valida o acesso e recupera o navegador no armazenamento adequado. A instância que criou o recurso não precisa ser a mesma que executa a navegação.

Essa mudança melhora a rastreabilidade. Logs, métricas e erros podem apontar para o recurso envolvido sem depender de uma sessão escondida. Também deixa mais claro quais ferramentas criam estado e quais apenas consultam ou alteram algo já existente.

Só que um identificador enviado pelo cliente não é uma autorização.

Se o servidor aceita qualquer browser_id válido sem conferir o dono ou o escopo, ele cria uma porta para um usuário operar o recurso de outro. O contrato precisa responder a perguntas bem menos empolgantes do que “qual será o nome da ferramenta?”, mas muito mais importantes:

  • quem pode usar este handle;
  • por quanto tempo ele existe;
  • o que acontece depois da expiração;
  • se ele pode atravessar organizações ou projetos;
  • quais operações são permitidas para aquela identidade.

O ideal é que o handle não revele detalhes internos e que toda operação verifique a autorização no recurso recuperado. Não conte com o modelo para respeitar esse limite. O controle precisa existir no servidor.

O estado escondido costuma aparecer em cinco lugares

Antes de atualizar o SDK, procure onde a implementação atual depende da sessão. Uma busca por initialize, Mcp-Session-Id, Redis, caches em memória e configuração de sticky routing costuma revelar parte do problema.

Depois, acompanhe um fluxo real por duas ou três chamadas. O que a segunda chamada espera encontrar sem receber como argumento?

Em servidores pequenos, o estado escondido aparece bastante nestes pontos:

  • recursos abertos, como navegador, terminal, arquivo temporário ou conexão;
  • projeto, workspace, conta ou ambiente selecionado;
  • permissões calculadas apenas durante a inicialização;
  • resultados parciais de tarefas demoradas;
  • chaves usadas para correlacionar logs, cobranças ou limites.

Nem tudo precisa virar um campo enorme repetido em cada chamada. Muitas vezes basta passar um identificador curto e recuperar os dados no servidor. O ponto é tornar a dependência visível no contrato, em vez de deixá-la presa à memória de uma conexão.

Também vale resistir à tentação de criar um context_id genérico que guarda tudo. Ele pode recriar a antiga sessão com outro nome. Prefira handles ligados a recursos e operações concretas: browser_id, cart_id, export_id, task_id.

Retry sem idempotência duplica o problema

Uma arquitetura stateless facilita repetir uma chamada quando a conexão cai ou uma instância some. Para leituras, isso tende a ser tranquilo. Para operações com efeito colateral, o retry pode abrir dois navegadores, criar duas cobranças ou iniciar duas exportações.

Considere este fluxo:

create_browser({ idempotency_key: "run_42:create_browser"})

Se a resposta se perder e o cliente repetir a chamada com a mesma chave, o servidor devolve o recurso já criado em vez de abrir outro. A forma exata depende do domínio, mas a pergunta é sempre a mesma: “Se esta requisição chegar duas vezes, o efeito também acontece duas vezes?”

Não jogue essa decisão para o cliente por acidente. Defina quais operações são seguras para retry, quais exigem uma chave e por quanto tempo o resultado dessa chave fica armazenado.

Para operações que aguardam nova entrada, o novo ciclo também pede um desenho explícito. Requisições iniciadas pelo servidor só podem acontecer durante uma chamada ativa. Quando faltar informação, o fluxo pode retornar um InputRequiredResult; o cliente responde depois em uma nova requisição. A retomada precisa carregar dados suficientes para localizar a operação anterior.

O estado continua lá. O que muda é a forma de retomá-lo.

Compatibilidade do SDK não migra seu produto

O GitHub MCP Server é um bom exemplo do ganho operacional. Na adaptação para a nova especificação, o servidor removeu gravações no Redis durante initialize e leituras de sessão em cada chamada. Informações usadas em logs e detecção de segredos passaram a vir dos novos headers, sem precisar inspecionar profundamente o payload.

O SDK Go também mantém uma camada de compatibilidade para o fluxo de elicitation funcionar com clientes antigos e novos. Isso reduz o trabalho de quem usa o SDK.

O cuidado está em transformar esse caso em regra universal. Um wrapper consegue resolver detalhes de compatibilidade do protocolo. Ele não sabe que seu current_workspace vivia na sessão, que uma ferramenta espera um token calculado na inicialização ou que um job precisa retomar do último checkpoint.

Atualizar a dependência é o começo da migração, não a prova de que ela terminou.

Se o servidor ainda aceita clientes anteriores, escolha o ciclo de vida pela versão negociada. Versões até 2025-11-25 usam o handshake; a revisão 2026-07-28 usa os metadados por requisição. Tentar empurrar os dois comportamentos por um único caminho implícito deixa a compatibilidade difícil de observar e ainda pior de remover depois.

Teste o protocolo e o seu domínio separadamente

Uma conexão bem-sucedida não prova que a migração está correta. Ela só mostra que cliente e servidor conseguiram conversar naquele cenário.

O framework oficial de conformidade permite testar clientes e servidores de forma separada. A suíte draft, configurada para --spec-version 2026-07-28, ajuda a verificar o ciclo stateless e a distinguir regressões novas de falhas já conhecidas.

Essa é a primeira camada. A segunda pertence ao produto.

Para o exemplo do navegador, eu testaria pelo menos:

Cenário Resultado esperado
outra instância recebe navigate recupera o navegador pelo browser_id
usuário informa handle de outra conta acesso negado sem revelar dados do recurso
handle expirou erro claro e recuperável
create_browser é repetido com a mesma chave nenhum navegador extra é criado
cliente antigo inicia uma sessão caminho compatível é selecionado pela versão
operação pede mais dados retomada localiza a mesma operação

A conformidade cobre o protocolo. Esses testes cobrem autorização, expiração, idempotência e continuidade, que são regras da sua aplicação.

Um mapa de migração que cabe num PR

Se eu tivesse de preparar um servidor MCP próprio para essa revisão, dividiria o trabalho em passos pequenos:

  1. mapear dependências de initialize, sessão, memória local e sticky routing;
  2. listar recursos e operações que atravessam chamadas;
  3. criar handles opacos para os recursos que precisam ser retomados;
  4. validar identidade e autorização em toda operação que recebe um handle;
  5. definir idempotência para escritas e criações;
  6. separar o comportamento por versão enquanto houver clientes antigos;
  7. rodar a suíte de conformidade;
  8. adicionar testes de domínio para retry, expiração, acesso indevido e troca de instância.

O PR não precisa redesenhar todo o produto de uma vez. Comece pelo fluxo que mais depende da sessão e prove que outra instância consegue continuá-lo apenas com a requisição e os recursos referenciados.

Se isso ainda não for possível, você encontrou estado escondido. E esse é justamente o trabalho que a mudança stateless coloca à vista.

O teste que eu faria antes do merge

Remover a sessão do núcleo do MCP pode simplificar bastante a infraestrutura. O servidor ganha liberdade para rotear chamadas e trocar instâncias sem depender da memória de uma conexão específica.

Em compensação, a aplicação precisa assumir o trabalho que a sessão fazia silenciosamente. Os handles entram nos contratos, cada recurso exige verificação de acesso e as novas tentativas precisam ser idempotentes. Uma operação interrompida também precisa dizer como será retomada.

Antes de considerar a migração pronta, faça um teste simples: crie um recurso numa instância e envie a próxima chamada para outra. Se ela consegue continuar usando apenas a nova requisição, a identidade autorizada e os recursos referenciados, o estado está explícito o bastante para ser operado.

Se não consegue, o problema não é que o MCP perdeu contexto. É que sua aplicação ainda guardava contexto num lugar que o contrato não mostrava.

Notas de fonte

Perguntas frequentes

Respostas institucionais sobre esta cobertura, fontes e limites editoriais.

Sobre o que trata “MCP stateless não elimina estado: sua aplicação precisa torná-lo explícito”?
Imagine um servidor MCP que controla navegadores remotos. Uma ferramenta abre o navegador, outra acessa uma URL e a terceira tira uma captura de tela.No primeiro desenho da aplicação, o servidor guarda o navegador numa sessão…
O que a matéria explica sobre “O que realmente sai do protocolo”?
A nova revisão remove o handshake initialize/initialized, o header Mcp-Session-Id e a sessão mantida no nível do protocolo. Versão, identificação e capacidades do cliente passam a acompanhar cada requisição em _meta.Na prática, isso reduz a afinidade entre uma conexão e uma instância…
O que a matéria explica sobre “Um handle explícito muda o contrato”?
Vamos voltar ao navegador remoto. Um fluxo mínimo pode funcionar assim:create_browser() -> { browser_id: "brw_7f2..." }navigate({ browser_id: "brw_7f2...", url: "https://example.com"})create_browser persiste o recurso e devolve um handle opaco. navigate recebe esse handle, valida o acesso e recupera o navegador no armazenamento adequado.…
O que a matéria explica sobre “O estado escondido costuma aparecer em cinco lugares”?
Antes de atualizar o SDK, procure onde a implementação atual depende da sessão. Uma busca por initialize, Mcp-Session-Id, Redis, caches em memória e configuração de sticky routing costuma revelar parte do problema.Depois, acompanhe um fluxo real por duas ou três chamadas. O…
O que a matéria explica sobre “Retry sem idempotência duplica o problema”?
Uma arquitetura stateless facilita repetir uma chamada quando a conexão cai ou uma instância some. Para leituras, isso tende a ser tranquilo. Para operações com efeito colateral, o retry pode abrir dois navegadores, criar duas cobranças ou iniciar duas exportações.Considere este fluxo:create_browser({…
Quem edita o conteúdo do Estrato Mente?
A cobertura é produzida e revisada pela equipe editorial do Estrato Mente, com editor-chefe responsável pela linha editorial. Conheça a redação em https://mente.estrato.cc/equipe/.
Quais fontes o Estrato prioriza?
Priorizamos fontes primárias (órgãos oficiais, balanços, estudos revisados, documentos públicos) e cruzamos informações antes da publicação, conforme a política editorial.
Como solicitar correção de uma matéria?
Envie o pedido pela página de Correções (https://mente.estrato.cc/correcoes/) ou Contato (https://mente.estrato.cc/contato/). Erros materiais são corrigidos com registro da atualização.
WhatsApp X LinkedIn
Compartilhar: LinkedIn
Nina Barros

Nina Barros

Nina Barros integra a equipe editorial do Estrato Mente, vertical da rede Estrato, na função de Repórter de Finanças comportamentais. O escopo permanente de cobertura inclui vieses e decisões, com atenção ao leitor brasileiro que busca contexto factual, datas oficiais e implicações práticas. Na produção diária, prioriza fontes primárias (órgãos públicos, balanços, papers e documentos oficiais), cruza pelo menos duas referências independentes quando o tema é contestado e evita manchetes que prometam certeza onde há incerteza. Critérios de qualidade: lead com o fato principal, atribuição clara de autoria da equipe Estrato, atualização com selo quando há mudança material e linguagem acessível sem simplificar demais o risco ou o contexto. Trabalha sob revisão da mesa editorial e do editor-chefe do portal. Matérias YMYL recebem segunda leitura antes da publicação e podem ser atualizadas quando surgem novos dados oficiais. Limites: este perfil descreve o papel editorial na marca Estrato. O conteúdo publicado é informativo e não constitui aconselhamento médico, financeiro, jurídico ou profissional personalizado. Transparência ao leitor: metodologia em /metodologia/, ética em /etica-editorial/, correções em /correcoes/, equipe em /equipe/ e canal em /contato/ ([email protected]). Na página-mãe da rede, a bio ampliada e o arquivo de matérias ficam em estrato.cc/blog/, com link para o arquivo do autor em cada portal.

Deixe um comentário