Pular para o conteúdo
mnzes

Como funciona a arquitetura do MCP?

PorDiógenes MenezesAprendendo IA em público

12 min de leitura

A arquitetura do MCP tem três papéis. O host é a aplicação que você abre e que conversa com o modelo. O cliente vive dentro do host e fala com exatamente um servidor. O servidor é um processo separado que expõe tools, resources e prompts de um sistema. O host cria um cliente por servidor conectado e é o único que enxerga a conversa inteira.

A especificação chama isso de arquitetura cliente-host-servidor, e a frase que vem logo depois é a mais importante da página: o MCP é um protocolo stateless, em que toda requisição é autossuficiente e carrega a própria versão de protocolo e as próprias capacidades1. Isso mudou na revisão 2026-07-28 e reorganizou boa parte do que segue.

Duas coisas ficam de fora deste artigo e têm as suas. Como as mensagens chegam de um lado ao outro é assunto dos transportes do MCP, e o servidor rodar na sua máquina ou em outra é a diferença entre local e remoto. Aqui interessa quem é quem, e o Model Context Protocol em geral está no artigo do cluster.

aplicação host — um processotrês processos separadoscliente 1servidor de arquivoscliente 2servidor do banco1 cliente : 1 servidorcliente 3servidor de calendário
Figura 1O host multiplica clientes em vez de multiplexar um só. É essa escolha que mantém cada servidor cego para o que os outros receberam.

O que cada papel faz

O host é o processo da aplicação. Ele cria e destrói instâncias de cliente, controla quais conexões existem e por quanto tempo, aplica as políticas de segurança e os requisitos de consentimento, resolve as decisões de autorização do usuário e agrega o contexto vindo de todos os clientes1. É também ele que fala com o modelo. Nenhum servidor tem acesso a essa camada.

O cliente é criado pelo host e conversa com um servidor só. Ele anexa a versão de protocolo e as capacidades a toda requisição, roteia mensagens nas duas direções, cuida das assinaturas de notificação e mantém a fronteira entre um servidor e os outros1. Na prática você nunca vê um cliente: quando alguém diz “o Claude Code é um cliente MCP”, o que está descrito é o host, e o cliente é o componente interno que ele instancia uma vez por servidor da sua configuração.

O servidor expõe as três primitivas, opera de forma independente e pode ser um processo local ou um serviço remoto1. Ele não sabe quem está do outro lado além do que a requisição carrega, e não sabe que outros servidores existem.

Vale a distinção que confunde quase todo mundo na primeira leitura: o cliente é uma peça de software dentro do seu editor, não o seu editor. Um host com quatro servidores configurados tem quatro clientes vivos ao mesmo tempo.

Por que um cliente por servidor

Multiplexar tudo em uma conexão só seria mais simples de implementar. A especificação escolheu o contrário, e o princípio de projeto que justifica isso está escrito com todas as letras: servidores não devem conseguir ler a conversa inteira nem enxergar dentro de outros servidores1. O histórico completo fica no host, cada servidor recebe apenas o contexto necessário e as interações entre servidores são controladas pelo host.

O isolamento é a razão de o desenho ser esse. Se você conecta um servidor de sistema de arquivos e um servidor de um SaaS de terceiro, o segundo não tem como observar o que o primeiro devolveu. A composição acontece no host, sob a política do host.

Esse isolamento tem uma consequência prática que aparece cedo em qualquer agregador. Nome de tool é único dentro de um servidor, não entre servidores. Dois servidores podem expor uma tool search cada, e a especificação recomenda explicitamente que quem agrega implemente uma estratégia de desambiguação, como prefixar com um identificador do servidor. Ela também avisa que o name do serverInfo não é garantidamente único e não serve para isso1. Se você está escrevendo um host, esse é o primeiro bug que você vai encontrar.

Como os dois lados se descobrem

até a revisão 2025-11-25revisão 2026-07-28initializenotifications/initializedtools/callobrigatórioserver/discovertools/callpode pulardevolve versõese capacidadestoda requisição carrega versãoe capacidades em _meta
Figura 2O handshake obrigatório virou uma consulta opcional. O que antes era estado da conexão agora viaja em toda requisição, dentro do corpo da mensagem.

Até a revisão 2025-11-25, a conexão começava com um handshake: o cliente enviava initialize com a versão e as capacidades que suportava, o servidor respondia com as dele, o cliente confirmava com notifications/initialized e só então podia chamar qualquer coisa. Toda a negociação ficava guardada no estado da conexão.

A revisão 2026-07-28 desmontou isso. O cliente inclui as capacidades em _meta.io.modelcontextprotocol/clientCapabilities em cada requisição, e o servidor anuncia as dele em resposta a server/discover, uma chamada que o cliente pode fazer antes de qualquer outra para descobrir capacidades de antemão1. Pode, não precisa. Um cliente que já sabe o que quer chamar manda tools/call direto.

A mudança troca uma economia por outra. Antes, a negociação custava duas viagens e valia para a sessão inteira. Agora não existe sessão, cada requisição repete alguns bytes de metadado e qualquer servidor atrás de um balanceador atende qualquer requisição sem estado compartilhado. Para um servidor local em stdio o ganho é nulo; para um servidor remoto com várias instâncias, é o que torna o escalonamento horizontal trivial.

A parte que ninguém pode ignorar em 2026 é a compatibilidade. Um cliente que suporta as duas eras deve sondar com server/discover antes de qualquer outra coisa, e a especificação enumera os três desfechos: se vier um DiscoverResult, o servidor é moderno; se vier um erro moderno reconhecido, como UnsupportedProtocolVersionError, o servidor é moderno mas não fala aquela versão, e não se deve cair para initialize; se vier qualquer outro erro ou nenhuma resposta, o servidor é legado e aí sim usa-se o handshake1. O aviso que acompanha a regra explica por que o fallback não pode ser amarrado a um código de erro específico: servidores legados respondem a métodos desconhecidos antes do initialize com erros definidos pela implementação, comumente -32601 ou -32602, ou simplesmente não respondem.

O servidor não faz perguntas

Um detalhe do desenho que mudou de forma silenciosa e quebra código antigo: nesta revisão, servidores não iniciam requisições JSON-RPC. Nenhuma.

Antes, um servidor que precisasse de uma completação do modelo, de um dado do usuário ou da lista de diretórios permitidos mandava uma requisição própria pelo canal. Agora ele devolve um InputRequiredResult dentro da resposta, com os pedidos em inputRequests, e o cliente refaz a requisição original acrescentando inputResponses e o requestState que o servidor mandou junto1. O id JSON-RPC da segunda tentativa precisa ser diferente do da primeira.

Duas consequências valem registro. A primeira é que o fluxo fica todo iniciado pelo cliente, o que casa com o modelo de requisição e resposta do HTTP e elimina a necessidade de um canal permanente aberto do servidor para o cliente. A segunda é que a lógica do servidor precisa ser retomável: ele responde, morre, e recebe de volta uma requisição nova que precisa continuar de onde parou. É para isso que serve o requestState, e é o ponto onde uma implementação apressada guarda estado em memória e quebra assim que sobem duas réplicas.

Some-se a isso que roots, sampling e logging estão marcados como depreciados na 2026-07-28, com remoção possível na primeira revisão publicada em 28 de julho de 2027 ou depois. A arquitetura está encolhendo o que o servidor pode pedir de volta, não expandindo.

Quem confia em quem

modelousuárioaplicação hostagrega e autorizaservidor Aservidor Bconsentecontexto agregadochamachamao que volta do servidoré entrada não confiável
Figura 3Só uma seta carrega consentimento, e ela sai do usuário. Tudo que volta de um servidor entra no contexto como dado, não como instrução autorizada.

A arquitetura tem uma única fonte de autoridade, e é o usuário. Ele consente com o host, o host aplica esse consentimento sobre os clientes e nada abaixo disso carrega permissão própria.

O que vem na direção contrária é dado, não ordem. A descrição de uma tool, o schema dos argumentos e o resultado de uma chamada entram no contexto do modelo e influenciam o que ele decide fazer em seguida. A especificação é direta sobre o peso disso: clientes precisam considerar as anotações de tool como não confiáveis, a menos que venham de servidores confiáveis1. A palavra usada é “untrusted”, e ela vale para tudo que o servidor escreve.

O problema é que a fronteira depende de alguém estar de pé nela. Um estudo de 2026 minerou 1.723 aplicações consumidoras de MCP no GitHub e mediu exatamente esse ponto: 90,8% registram log e 77,2% oferecem controle para ligar e desligar servidores, mas apenas 37,2% colocam uma aprovação bloqueante antes de executar uma tool2. Na maioria das aplicações estudadas, o modelo aciona qualquer ferramenta habilitada sem passar por ninguém. A camada de política existe no desenho e está vazia na implementação.

Do lado do servidor, a evidência é da mesma natureza. Um levantamento de 2025 analisou 67.057 servidores em seis registros públicos e descreveu o padrão de ataque em duas etapas: verificação fraca na entrada do registro deixa um servidor adversário chegar ao host, e depois metadados de tool controlados pelo atacante moldam o raciocínio do modelo e induzem operações que o host executa sem verificação independente3. A ferramenta dos autores apontou 833 servidores com vulnerabilidade explorável e 18 com descrições suspeitas. Outro estudo do mesmo ano avaliou 1.899 servidores de código aberto e encontrou 7,2% com vulnerabilidades gerais e 5,5% com tool poisoning específico do MCP4.

Onde a arquitetura falha

O isolamento entre servidores não isola o contexto. Cada servidor é cego para os outros, mas todos escrevem no mesmo contexto do modelo. Um resultado devolvido pelo servidor A pode conter texto que leva o modelo a chamar uma tool do servidor B. O caminho concreto é banal: um comentário em um ticket, uma linha de README, o campo de descrição de um registro no banco. Nada disso passa por validação, porque é conteúdo legítimo do sistema de origem e o servidor está fazendo o trabalho dele ao devolver. O host é o ponto onde isso poderia ser barrado, e é justamente onde 62,8% das aplicações medidas não têm nada2.

A política mora no host, e o host é de outra pessoa. Se você escreve um servidor, você não controla se existe aprovação humana, se há log, se o usuário consegue ver os argumentos antes da chamada. Você pode recomendar no README. É tudo o que você pode fazer.

Stateless empurrou o estado para dentro dos argumentos. Sem sessão de protocolo, um servidor que precisa relacionar chamadas devolve um handle explícito e o recebe de volta como argumento comum. A especificação avisa do risco: para servidores sem autenticação, o handle é necessariamente um bearer token e precisa de entropia suficiente e vida útil limitada1. Um identificador sequencial ali vira enumeração de sessão alheia.

Um cliente por servidor multiplica processos. Dez servidores em stdio são dez subprocessos vivos na máquina do usuário, cada um com seu consumo de memória e seu ciclo de vida para gerenciar. O modelo de ameaça de 2025 que decompôs o ciclo de vida de um servidor em quatro fases existe porque a operação dessas peças é um problema próprio, separado do protocolo5.

Como montar sem se arrepender

  1. Decida cedo se você está escrevendo host ou servidor. As duas metades têm responsabilidades quase disjuntas, e a maior parte da confusão vem de tentar fazer as duas na mesma cabeça.
  2. Se for host, escreva a desambiguação de nomes antes do segundo servidor. Prefixe com um identificador que você controla, não com o serverInfo.name.
  3. Se for host, coloque a aprovação bloqueante antes de qualquer tool de escrita. É a única coisa nesta lista que os dados dizem que quase ninguém faz.
  4. Se for servidor, escreva a lógica como retomável desde o começo. Sem sessão, estado em memória entre chamadas só funciona com uma réplica, e você vai descobrir isso em produção.
  5. Sonde com server/discover e trate os três desfechos. Cair para initialize por causa de um código de erro qualquer é o bug de interoperabilidade mais provável do segundo semestre de 2026.
  6. Trate tudo que o servidor escreve como texto de origem desconhecida. Descrição, schema, resultado e anotação. A especificação já classifica assim.

O passo 3 é o que separa a arquitetura desenhada da arquitetura implementada, e os números disponíveis dizem que quase dois terços das aplicações param antes dele.

Footnotes

  1. A página de arquitetura da revisão 2026-07-28 é a fonte para os três papéis, para a relação 1:1 entre cliente e servidor, para os princípios de projeto, para o modelo de descoberta de capacidades, para as regras de compatibilidade com o handshake antigo e para a classificação das anotações de tool como não confiáveis. Verificada em 30 de julho de 2026. 2 3 4 5 6 7 8 9 10 11

  2. Majeed et al. (2026) mineraram 1.723 aplicações consumidoras de MCP no GitHub: 85,2% configuram servidores por arquivo, 81,1% usam um SDK oficial, 90,8% registram log, 77,2% permitem ligar e desligar servidores e 37,2% exigem aprovação bloqueante antes de executar uma tool. 2

  3. Li e Gao (2025) analisaram 67.057 servidores em seis registros públicos e descreveram um ataque em duas etapas — entrada no registro e manipulação de invocação via metadados — identificando 833 servidores vulneráveis e 18 com descrições suspeitas.

  4. Hasan et al. (2025) avaliaram 1.899 servidores MCP de código aberto: 7,2% com vulnerabilidades gerais, 5,5% com tool poisoning específico do MCP e 66% com code smells.

  5. Hou et al. (2025) decompuseram o ciclo de vida de um servidor MCP em quatro fases e derivaram uma taxonomia de ameaças por tipo de atacante.

Perguntas frequentes

Quem é o host no MCP?
O host é a aplicação que você abre: o editor, o assistente de chat, o agente que você escreveu. Ele cria e destrói os clientes, guarda a conversa inteira, decide quais servidores estão conectados e é o único lugar onde a autorização do usuário existe. Servidor nenhum vê essa camada.
Qual a diferença entre cliente e servidor no MCP?
O cliente vive dentro do host e fala com exatamente um servidor, traduzindo entre o protocolo e a aplicação. O servidor é um processo separado que expõe tools, resources e prompts de um sistema específico. A relação é 1:1, e é ela que mantém os servidores isolados entre si.
Qual é um exemplo de cliente MCP?
O componente dentro do VS Code que conversa com o servidor de sistema de arquivos que você adicionou na configuração. Ele não aparece na interface: o que você vê é o host. Se você conectou três servidores nesse editor, existem três clientes rodando, isolados uns dos outros.
Quantos clientes um host pode ter?
Um por servidor conectado, sem limite definido na especificação. O custo prático não é o número de clientes e sim o que cada servidor injeta no contexto do modelo: cada tool anunciada vira declaração no prompt em toda chamada. Dez servidores conectados custam contexto antes de qualquer pergunta.
O MCP ainda tem handshake de inicialização?
Não na revisão 2026-07-28, que tornou o protocolo stateless. O par initialize e notifications/initialized saiu, e cada requisição passou a carregar a própria versão de protocolo e as capacidades do cliente em _meta. Sobrou server/discover, uma consulta opcional que devolve versões e capacidades do servidor.
Um servidor MCP enxerga a conversa inteira?
Não, e isso é um princípio de projeto explícito da especificação. O histórico completo fica no host, e cada servidor recebe apenas o que aquela chamada precisa. Um servidor também não vê o que outro servidor recebeu ou devolveu. Quem agrega tudo é o host, e só ele.

Referências

  1. Agentic AI Foundation. Model Context Protocol specification, revision 2026-07-28 — Architecture (2026)
  2. Majeed, M. H. A., Mahmoud, M., Nadi, S.. An Empirical Study of Model Context Protocol Applications (2026)arXiv:2607.25635
  3. Li, X., Gao, X.. A First Look at the Security Issues in the Model Context Protocol Ecosystem (2025)arXiv:2510.16558
  4. Hasan, M. M. et al.. Model Context Protocol (MCP) at First Glance: Studying the Security and Maintainability of MCP Servers (2025)arXiv:2506.13538
  5. Hou, X. et al.. Model Context Protocol (MCP): Landscape, Security Threats, and Future Research Directions (2025)arXiv:2503.23278