MCP vs REST: quando cada um ganha na integração de agentes de IA
Tratar o MCP e o REST como alternativas é partir da premissa errada. Estão em camadas diferentes: o REST é transporte mais convenções, o MCP é um protocolo tipado pensado para um consumidor LLM. A decisão real é com que superfície fala cada consumidor e como é que as duas superfícies partilham um backend. Este artigo apresenta o enquadramento que uso quando defino o âmbito de integrações de IA em projetos WordPress e WooCommerce.
Este artigo está ligado ao pilar desenvolvimento de servidores MCP.
Em resumo
- O MCP e o REST complementam-se, não são alternativas.
- O REST ganha com clientes determinísticos, com um conjunto de ações fixo e documentação OpenAPI.
- O MCP ganha com agentes LLM que precisam de descobrir ferramentas em tempo de execução e de esquemas tipados com anotações de comportamento para ações que alteram dados.
- A configuração por defeito em produção é o REST como system of record e o MCP como superfície para agentes à frente.
- O mesmo backend, duas superfícies, uma única fonte de verdade.
O que é o MCP e o que é uma API REST
REST. Um estilo arquitetural da tese de doutoramento de Roy Fielding de 2000 (a fonte da tese), normalmente expresso sobre HTTP com verbos e URLs de recursos. O WordPress expõe uma API REST em /wp-json/wp/v2/ (manual da API REST do WordPress); o WooCommerce estende-a em /wp-json/wc/v3/. A documentação costuma ser OpenAPI (especificação OpenAPI) e os SDKs são gerados a partir do esquema em tempo de build.
MCP. Um protocolo baseado em JSON-RPC 2.0 que a Anthropic anunciou a 25 de novembro de 2024 (anúncio da Anthropic) para ligar hosts LLM (Claude Desktop, IDEs, ambientes de agentes próprios) a dados e ferramentas. Três primitivas: tools (funções invocáveis), resources (documentos só de leitura), prompts (modelos fornecidos pelo servidor). A descoberta acontece em tempo de execução via tools/list. Desde a revisão 2026-07-28 o protocolo deixou de ter sessões: cada pedido transporta a versão do protocolo e as capacidades do cliente, e o cliente volta a pedir a lista quando a cópia em cache expira ou chega uma notificação de alteração.
Vistas de longe, as formas parecem semelhantes. Sob carga, afastam-se depressa.
Matriz de decisão entre MCP e API REST
Seis fatores que avalio antes de escolher a superfície para uma determinada ação:
| Fator | Favorece REST | Favorece MCP |
|---|---|---|
| Tipo de consumidor | Cliente web ou de parceiro determinístico | Agente LLM |
| Descoberta de capacidades | Em compilação via OpenAPI | Em execução via tools/list |
| Forma da ação | Fixa, bem conhecida | Intenção livre |
| Segurança das alterações | Semântica dos verbos HTTP (RFC 9110) | inputSchema + anotações readOnlyHint, destructiveHint, idempotentHint (só indicações) |
| Autenticação | Tokens bearer, OAuth | O mesmo, mais scopes associados a cada ferramenta |
| Cache | Cabeçalhos de cache HTTP | ttlMs e cacheScope nas listas; tools/call sem indicação de cache |
A matriz diz-me qual o protocolo preferível para uma ação, não para a API inteira. A maioria dos projetos acaba dividida.
Quando usar uma API REST em vez de MCP
Uma loja online a obter uma página de categoria. Programada contra /wp-json/wp/v2/categories?slug=widgets. A forma é conhecida, os cabeçalhos de cache fazem o seu trabalho e a CDN pode guardar em cache por URL.
A integração de ERP de um parceiro a sincronizar o stock diariamente. A equipa do parceiro lê o OpenAPI, gera um SDK tipado e agenda um cron para as 03:00 UTC. Quer URLs estáveis, formas de resposta previsíveis e códigos de estado HTTP. O MCP acrescentaria complexidade sem valor.
Tráfego público e anónimo de leitura. Um crawler de SEO a percorrer páginas de produto, um agregador de comparação de preços a puxar feeds de produtos. O REST com rate limiting trata este caso com a infraestrutura mais madura que existe.
Entrega de webhooks. Quando uma encomenda muda de estado, um webhook do WooCommerce envia o evento para um endpoint do parceiro. Esse endpoint é um recetor HTTP. O MCP é a forma errada, porque o agente não está no circuito; o recetor é um sistema determinístico.
Quando usar MCP em vez de REST
Um agente LLM a agir sobre a intenção livre do utilizador. “Encontra-me um casaco impermeável por menos de 200 euros que seja enviado para Lisboa.” O agente não sabe de antemão que combinação de filtros aplicar; tem de examinar as ferramentas disponíveis, ler as descrições e decidir. O REST dá-lhe parâmetros de query espalhados por vários endpoints e nenhum sinal sobre quais usar.
Ações que alteram dados em que a idempotência importa. Criar uma encomenda a partir de um LLM é o exemplo mais evidente. Uma ferramenta MCP order.intent com um esquema de entrada tipado, um parâmetro idempotency_key obrigatório e destructiveHint: false diz ao agente e ao cliente o que a chamada faz antes de ela correr. O protocolo não garante a idempotência: é o handler que tem de recusar uma segunda encomenda com a mesma chave. A diferença para um POST /wp-json/wc/v3/orders livre está num contrato que o modelo consegue ler.
Uma superfície de ferramentas que muda com frequência. Acrescentar um novo filtro de pesquisa ou um novo tipo de produto significa publicar uma nova ferramenta MCP com description e inputSchema. O servidor envia notifications/tools/list_changed aos clientes que abriram subscriptions/listen, e o agente apanha a ferramenta no tools/list seguinte sem alterações de código do lado do agente. Com REST, cada alteração é uma versão coordenada do SDK.
Fluxos de agente em vários passos. “Verifica se o SKU AC-101 está em stock; se não estiver, sugere três alternativas; se estiver, propõe uma encomenda.” Cada passo é uma chamada a uma ferramenta e o agente compõe-nas. Com REST, o agente tem de codificar a forma do fluxo no próprio prompt.
MCP e REST numa loja WooCommerce
Num projeto WooCommerce típico, traço a fronteira assim:
| Ação | Consumidor | Superfície |
|---|---|---|
| Navegação pública no catálogo | Cliente web, crawlers | REST |
| Renderização da página de produto | Cliente web | REST |
| Sincronização de stock (B2B) | ERP do parceiro | REST + OpenAPI |
| Entrega de webhooks | Endpoints de parceiros | REST |
| Agente: pesquisar produto | LLM | MCP |
| Agente: ler estado da encomenda | LLM | MCP |
| Agente: propor encomenda | LLM | MCP |
| Agente: cancelar encomenda | LLM | MCP |
| Operações de administração | Admin do WordPress | REST + autenticação por cookie |
Os handlers das ferramentas do servidor MCP chamam os mesmos endpoints /wp-json/wc/v3/ que os consumidores REST usam. Uma única fonte de verdade para a camada de dados, duas superfícies para dois tipos de consumidor.
Autenticação e scopes OAuth em MCP e REST
No WordPress, a API REST tem três caminhos documentados (autenticação na API REST). A autenticação por cookie serve o código que corre no próprio site e exige um nonce da ação wp_rest, enviado no cabeçalho X-WP-Nonce; sem nonce, o pedido corre como utilizador anónimo, mesmo com sessão iniciada. As Application Passwords fazem parte do core desde o WordPress 5.6 e funcionam com HTTP Basic, apenas sobre HTTPS. OAuth 1.0a e JSON Web Tokens chegam por plugins. O afinamento das permissões acontece por rota, nas capabilities do utilizador e no permission_callback de cada endpoint.
A autorização no MCP é opcional e aplica-se aos transportes HTTP; com stdio, as credenciais vêm do ambiente. Quando é usada, o servidor MCP é um resource server OAuth 2.1, tem de publicar Protected Resource Metadata (RFC 9728) e só aceita tokens emitidos para si: o cliente identifica o servidor no parâmetro resource (RFC 8707) e o servidor rejeita tokens de outra audiência. O servidor também não pode aceitar nem fazer passar outros tokens, por isso autentica-se no WordPress com credenciais próprias, por exemplo uma Application Password de um utilizador com um papel limitado.
Os scopes funcionam como em qualquer API OAuth, com duas regras úteis para agentes. O servidor pode devolver em tools/list apenas as ferramentas que os scopes do token permitem. E quando uma chamada precisa de mais, responde HTTP 403 com error="insufficient_scope" e os scopes necessários no cabeçalho WWW-Authenticate, para que o cliente peça uma nova autorização com o conjunto alargado. O utilizador concede orders:read ao agente; o agente nem vê order.cancel e, se tentar chamá-la, recebe o 403 antes de o handler correr. O OpenAPI descreve o mesmo com securitySchemes e security por operação (especificação OpenAPI), mas na prática muitas APIs REST documentam um único scope global e deixam a granularidade fina para a aplicação.
Nas integrações com agentes, este mapeamento de scopes por ferramenta é um ganho ergonómico real, que também encaixa nos requisitos de minimização de dados do RGPD. Por baixo, o mecanismo é o OAuth que o REST já conhece, mas o contrato fica mais legível tanto para o utilizador como para o agente.
Como difere a cache de respostas MCP da cache HTTP do REST
O REST tem décadas de infraestrutura de cache HTTP: cabeçalhos Cache-Control, revalidação com ETag, regras Vary, cache na periferia da CDN, cache no navegador e em proxies intermédios. Uma resposta a GET /wp-json/wc/v3/products?stock_status=instock com Cache-Control: public, max-age=60 fica em cache na periferia sem esforço adicional.
No MCP, a revisão 2026-07-28 trouxe uma parte disto (cache no MCP). Os resultados de tools/list, prompts/list, resources/list, resources/templates/list e resources/read têm de levar ttlMs, que funciona como o max-age, e cacheScope, com os valores public e private, análogos aos do Cache-Control. Os resultados de tools/call, que são o grosso do tráfego de um agente, não estão nessa lista. Viajam como payloads JSON-RPC dentro de pedidos POST e os cabeçalhos de cache HTTP não se aplicam. A cache das chamadas tem de acontecer ao nível da aplicação, dentro do handler da ferramenta, com uma chave explícita derivada da entrada. Isto funciona bem quando os próprios handlers do servidor MCP guardam em cache a chamada REST a montante (é o que faço em produção), mas significa que a camada de cache é um problema seu para desenhar.
Este é o argumento mais forte para manter o tráfego público de leitura em REST e encaminhar apenas o tráfego de agentes pelo MCP. A infraestrutura de cache HTTP é demasiado valiosa para abdicar dela na superfície pública.
Anotações de ferramentas MCP contra verbos HTTP idempotentes
No REST, a segurança de uma operação está no próprio verbo. A RFC 9110 define GET, HEAD, OPTIONS e TRACE como métodos seguros, e PUT, DELETE e os métodos seguros como idempotentes: vários pedidos idênticos têm o mesmo efeito pretendido que um só. O POST não é idempotente. Um proxy, um crawler ou uma biblioteca de novas tentativas decide o que pode repetir só a partir do método, sem ler o corpo.
O MCP envia tudo como tools/call dentro de um POST, por isso o verbo não diz nada. A informação passa para a definição da ferramenta. O esquema da especificação define quatro anotações booleanas em ToolAnnotations:
| Anotação | Significado | Valor por defeito |
|---|---|---|
readOnlyHint | a ferramenta não altera o ambiente | false |
destructiveHint | pode fazer alterações destrutivas, e não só aditivas | true |
idempotentHint | repetir a chamada com os mesmos argumentos não tem efeito adicional | false |
openWorldHint | interage com um conjunto aberto de entidades externas, como uma pesquisa na web | true |
Os valores por defeito são pessimistas: uma ferramenta sem anotações é tratada como capaz de escrever, de destruir e de não ser idempotente. A especificação diz que todas estas propriedades são indicações, que não garantem uma descrição fiel do comportamento, e que um cliente não deve decidir com base em anotações de servidores em que não confia. A página de tools recomenda ainda uma pessoa no circuito com poder para recusar uma invocação, e pedidos de confirmação em operações sensíveis.
Numa loja WooCommerce, isto traduz-se assim: product.search leva readOnlyHint: true, order.cancel leva destructiveHint: true, e a idempotência de order.intent é garantida no handler por uma chave que o servidor verifica, não pela anotação. A anotação ajuda o cliente a decidir quando pedir confirmação. Não substitui as obrigações do servidor que a especificação enumera: validar todas as entradas, aplicar controlo de acesso, limitar a taxa de invocações e sanitizar as saídas.
Como o MCP reporta erros em comparação com os códigos de estado HTTP
Uma API REST comunica falhas com o código de estado: 400 para um pedido mal formado, 401 sem autenticação válida, 403 sem permissão, 404 para uma rota inexistente. A especificação de tools separa dois níveis. Os erros de protocolo (ferramenta desconhecida, pedido que não cumpre o esquema de tools/call, falha do servidor) chegam como erros JSON-RPC normais, por exemplo com o código -32602. Os erros de execução (falha da API a montante, data no formato errado, regra de negócio violada) chegam dentro de um resultado com isError: true e uma mensagem em texto.
A especificação recomenda que os clientes passem os erros de execução ao modelo, porque trazem informação que lhe permite corrigir os argumentos e tentar de novo. Num servidor MCP que envolve a API REST do WordPress, um 400 de validação devolvido pelo WordPress deve virar um resultado com isError: true que nomeia o parâmetro em falta, e não um erro de protocolo que o modelo não consegue corrigir.
Descoberta na API REST do WordPress contra tools/list do MCP
O REST do WordPress também se descreve a si próprio, de outra forma. As páginas do site enviam um cabeçalho Link com rel="https://api.w.org/" a apontar para a raiz da API, e a raiz em /wp-json/ devolve um objeto com os namespaces disponíveis (wp/v2, wc/v3 e os dos plugins), as rotas e uma chave authentication com os métodos suportados (descoberta da API REST). Um pedido OPTIONS a uma rota devolve o esquema dessa rota, escrito num subconjunto do JSON Schema draft 4 (esquema na API REST).
A diferença está em quem lê. O índice do WordPress é feito para um programador ou para um gerador de SDK: lista todas as rotas registadas e cada uma aceita parâmetros globais como _fields (respostas parciais, com propriedades aninhadas desde o WordPress 5.3), _embed (recursos ligados na mesma resposta) e _envelope (parâmetros globais). As coleções paginam com per_page até 100 e devolvem os totais nos cabeçalhos X-WP-Total e X-WP-TotalPages (paginação). Tudo isto serve bem um cliente programado, mas um modelo que receba o índice inteiro gasta contexto a escolher entre rotas que nunca vai usar.
O tools/list do MCP devolve só o que o servidor decidiu expor, cada ferramenta com description, inputSchema (JSON Schema 2020-12 por defeito) e, opcionalmente, outputSchema. A especificação permite que a lista varie consoante os scopes do token e pede uma ordem determinística, para que o cliente possa guardá-la em cache e o modelo aproveite a cache de prompts. Um servidor MCP para WordPress é, na prática, uma seleção curada do índice /wp-json/, com descrições escritas para um modelo e não para um programador.
O WordPress 6.9 acrescentou uma peça intermédia, a Abilities API. Um plugin regista uma ability com input_schema, output_schema, um permission_callback opcional e show_in_rest nos metadados. É uma forma nativa de descrever unidades de funcionalidade com esquema, que é exatamente o contrato de que um servidor MCP precisa para cada ferramenta.
O que mudou no MCP 2026-07-28 para proxies e balanceadores HTTP
As revisões de 2025 tinham um handshake initialize, sessões identificadas pelo cabeçalho Mcp-Session-Id e um fluxo SSE aberto por GET. Com vários servidores atrás de um balanceador, uma sessão por ligação obriga a encaminhar o mesmo cliente para o mesmo servidor ou a partilhar o estado entre servidores, um problema que o REST sem estado não tem. A revisão 2026-07-28 removeu as três coisas. Cada pedido transporta a versão do protocolo e as capacidades do cliente em _meta. Quem precisa de estado entre chamadas, como um carrinho, devolve um identificador explícito numa ferramenta e recebe-o como argumento nas chamadas seguintes.
O transporte Streamable HTTP passou também a espelhar metadados em cabeçalhos. MCP-Protocol-Version e Mcp-Method são obrigatórios em cada POST, Mcp-Name também em tools/call, resources/read e prompts/get, e uma ferramenta pode marcar parâmetros com x-mcp-header para os expor como Mcp-Param-{nome}. Um WAF ou um gateway consegue assim encaminhar ou limitar a taxa por ferramenta sem ler o corpo JSON. Se um cabeçalho não coincidir com o corpo, o servidor responde 400 com o erro HeaderMismatch (-32020). A especificação desaconselha marcar parâmetros sensíveis desta forma, porque os cabeçalhos ficam visíveis para os intermediários.
Para quem já opera uma API REST atrás de uma CDN, as duas superfícies ficam mais próximas na operação: as mesmas regras de encaminhamento e de rate limiting por cabeçalho servem ambas. A cache HTTP continua a não se aplicar a tools/call, porque cada chamada é um POST.
Como usar MCP e REST no mesmo backend WordPress
A arquitetura por defeito que entrego para sites WordPress e WooCommerce com ambições de agentes de IA:
┌──────────────────┐
│ WordPress core │
│ + WooCommerce │
│ (REST origin) │
└────────┬─────────┘
│
┌────────────────┼────────────────┐
│ │ │
┌───────▼────────┐ ┌────▼─────┐ ┌──────▼──────┐
│ Public REST │ │ Webhook │ │ MCP server │
│ (cache at CDN) │ │ delivery │ │ (Workers) │
└───────┬────────┘ └────┬─────┘ └──────┬──────┘
│ │ │
┌───────▼────────┐ ┌────▼─────┐ ┌──────▼──────┐
│ Storefront, │ │ Partner │ │ LLM agent │
│ price feeds, │ │ endpoints│ │ (Claude, │
│ public APIs │ │ │ │ ChatGPT, │
│ │ │ │ │ custom) │
└────────────────┘ └──────────┘ └─────────────┘A mesma origem WordPress. Três superfícies, três perfis de consumidor. Os handlers do servidor MCP chamam os mesmos endpoints REST que a superfície pública guarda em cache; a entrega de webhooks partilha os mesmos hooks de eventos do WordPress que a lógica de invalidação do servidor MCP escuta.
A fronteira entre MCP e REST é uma decisão de implementação em produção, não uma decisão de código. A camada de dados (base de dados do WooCommerce, endpoints REST) é partilhada. A camada de apresentação (ferramentas tipadas contra recursos JSON) é separada.
Erros comuns de arquitetura com MCP e REST
Pôr o MCP a fazer o trabalho do REST. Guardar em cache páginas públicas do catálogo através do MCP é um erro. Use REST com uma CDN.
Pôr o REST a fazer o trabalho do MCP. Documentar uma superfície de ações pensada para LLMs em OpenAPI e esperar que o agente “se desenrasque” dá resultados frágeis. Os agentes saem-se melhor com a descoberta de ferramentas do MCP.
Duas camadas de dados paralelas. Se os handlers MCP reimplementam a lógica de negócio em vez de chamarem a origem REST, cada atualização do WordPress parte as duas superfícies. Mantenha a camada de dados no WordPress e as superfícies de protocolo finas.
Esquecer o custo. Um servidor MCP é mais uma unidade a implementar, mais uma estratégia de autenticação, mais uma coisa a monitorizar. Não avance com um se o seu único consumidor for uma integração de ERP de um parceiro; publique o OpenAPI e dê o trabalho por concluído.
Temas relacionados
Este artigo trata da decisão ao nível do protocolo. O passo a passo da implementação está em construir um servidor MCP para WooCommerce. A estratégia de autenticação está em padrões de autenticação MCP. O desenho de ferramentas tipadas está em ferramentas de catálogo tipadas com Zod para MCP. O caminho de migração a partir de uma API existente está em migrar uma API WordPress para MCP. A página do serviço é desenvolvimento de servidores MCP.
O preço é individual, porque a forma certa depende dos consumidores que serve e das ações que exigem contratos de nível de agente.







