Migrar uma API WordPress existente para MCP: um plano de 4 semanas
Construir um servidor MCP de raiz é simples. Migrar a partir de uma REST API do WordPress existente e a funcionar, enquanto continua a servir tráfego de produção, é uma forma mais difícil. Este plano é o que uso para passar de “temos /wp-json/ e um consumidor parceiro” para “temos /wp-json/, esse parceiro e um servidor MCP amigo dos LLM à frente”, sem partir nada.
O artigo faz parte do pilar desenvolvimento de servidores MCP.
TL;DR
- Quatro semanas: auditoria, estrutura, execução em paralelo, transição.
- A REST continua ativa para os consumidores existentes; o MCP é um acréscimo, não um substituto.
- Os esquemas Zod vêm da auditoria à REST, não de uma lista de desejos.
- Execução em paralelo com um agente interno antes de o tráfego externo chegar ao MCP.
- O Logpush capta cada chamada de ferramenta; as discrepâncias entre respostas MCP e REST aparecem como erros de esquema.
Como auditar os endpoints da REST API do WordPress
A auditoria é uma folha de cálculo. Uma linha por endpoint, com estas colunas:
| Coluna | O que registamos |
|---|---|
| Endpoint | /wp-json/wp/v2/posts, /wp-json/wc/v3/products, etc. |
| Verbos HTTP | GET, POST, PUT, DELETE suportados |
| Consumidores atuais | Loja, ERP do parceiro, recetores de webhooks |
| Volume de tráfego | Pedidos por dia a partir dos registos de acesso |
| Sensibilidade dos dados | Públicos, de clientes, só administração |
| Altera o estado? | Sim/não |
| Corresponde a uma ferramenta MCP? | Nome proposto da ferramenta e intenção |
| Notas | Plugins envolvidos, formas de campos personalizados, armadilhas |
Para uma loja WooCommerce típica, a folha tem 20 a 60 linhas. A maioria traduz-se de forma limpa em ferramentas MCP; um punhado (internos da administração, endpoints específicos de plugins, recetores de webhooks) fica só em REST.
O resultado da semana 1 são dois artefactos:
- Um inventário de ferramentas proposto:
catalogue.list,product.detail,order.intent,order.status,inventory.check, mais o que for específico da sua construção. - Um primeiro rascunho dos esquemas Zod para as entradas e saídas de cada ferramenta, derivado das respostas REST reais captadas durante a auditoria.
Capto as respostas REST com curl e jq para inspecionar a forma, ou com uma coleção do Postman partilhada pela equipa. O objetivo é a verdade empírica, não o que o README diz. Os plugins do WordPress são conhecidos por acrescentar campos que a documentação nunca regista; a auditoria apanha-os.
Como montar um servidor MCP no Cloudflare Workers
O resultado da semana 2 é um servidor MCP funcional, com deploy num ambiente Cloudflare Workers fora de produção, e o inventário de ferramentas da semana 1 implementado como adaptadores finos sobre os endpoints REST existentes.
O esqueleto do servidor:
import { createMcpHandler, hostHeaderValidationResponse, McpServer } from "@modelcontextprotocol/server";
import { catalogueListInput, catalogueListOutput, handleCatalogueList } from "./tools/catalogue-list.js";
import { productDetailInput, productDetailOutput, handleProductDetail } from "./tools/product-detail.js";
// ... um import por ferramenta
export default {
async fetch(request: Request, env: Env): Promise<Response> {
// rejeitar pedidos com cabeçalho Host alheio (proteção contra DNS rebinding)
const rejected = hostHeaderValidationResponse(request, [env.MCP_HOSTNAME]);
if (rejected) return rejected;
const handler = createMcpHandler(() => {
const server = new McpServer({ name: "wppoland-mcp", version: "0.1.0" });
server.registerTool(
"catalogue.list",
{
description: "List WooCommerce products with filters",
inputSchema: catalogueListInput,
outputSchema: catalogueListOutput,
annotations: { readOnlyHint: true },
},
(input) => handleCatalogueList(input, env),
);
server.registerTool(
"product.detail",
{
description: "Return one product by SKU",
inputSchema: productDetailInput,
outputSchema: productDetailOutput,
annotations: { readOnlyHint: true },
},
(input) => handleProductDetail(input, env),
);
// ... uma chamada registerTool() por ferramenta
return server;
});
return handler.fetch(request);
},
};O esqueleto segue a versão 2 do SDK oficial de TypeScript (@modelcontextprotocol/server), que implementa a revisão 2026-07-28 da especificação. createMcpHandler devolve um objeto com um método fetch, precisamente a forma que um módulo Cloudflare Workers espera como exportação predefinida, e a fábrica cria um McpServer novo em cada pedido (guia do SDK para runtimes web-standard). O mesmo guia avisa que o handler não valida Host nem Origin por si, e por isso o guarda fica à frente dele. Os projetos em @modelcontextprotocol/sdk 1.x continuam a receber correções de erros e de segurança durante pelo menos seis meses após o lançamento da v2 a 27 de julho de 2026 (README do SDK), por isso uma migração que comece agora deve apontar à v2.
Cada handler é um adaptador fino. Recebe a entrada validada, constrói a query string, faz fetch a /wp-json/, mapeia a resposta para uma forma de saída alinhada com schema.org, chama parse sobre a saída e devolve. A lógica de negócio fica no WordPress; o handler é uma tradução mecânica.
A semana 2 inclui também a estrutura de autenticação do guia de padrões de autenticação MCP. Para a execução em paralelo da semana 3 uso um único token de teste com todos os scopes; os scopes de produção aperto-os na semana 4.
O wrangler.toml do ambiente de preview aponta para uma instalação de staging do WordPress ou uma cópia da produção. O servidor MCP está acessível num URL *.mcp-staging.wppoland.workers.dev disponível apenas para a equipa.
Como testar o servidor MCP em paralelo com a REST API
É na semana 3 que os bugs aparecem. O padrão:
Construa um harness de comparação. Um pequeno script TypeScript que recebe o nome de uma ferramenta e uma entrada, chama o servidor MCP, depois chama diretamente o endpoint REST equivalente e compara as duas respostas. A diferença fica registada com o nome da ferramenta, a entrada e um caminho ao estilo JSON pointer para cada discrepância.
async function compareToolToRest(toolName: string, input: unknown) {
const mcpResponse = await callMcp(toolName, input);
const restResponse = await callEquivalentRest(toolName, input);
const diff = jsonDiff(restResponse, mcpResponse);
if (diff.length > 0) {
await logMismatch({ toolName, input, diff });
}
}Cada ferramenta contra um conjunto representativo de entradas. Para catalogue.list: query vazia, query que devolve centenas de produtos, query com filtro de categoria, query com intervalo de preços, query sem resultados. Para product.detail: SKU conhecido, SKU desconhecido, SKU com variações, SKU com campos personalizados. Cubra os casos-limite da auditoria.
Aponte um agente interno para o servidor MCP. O Claude Desktop com o servidor MCP configurado como fonte remota de ferramentas é a configuração que uso. Alguém da equipa passa 30 minutos por dia, durante uma semana, a interagir com a própria loja através do agente e a registar as surpresas num documento partilhado.
Os mesmos prompts de teste em três clientes. Luca Rossi observa no ensaio How to design a good MCP server, de outubro de 2026, escrito com a equipa da Manufact, que o mesmo servidor pode dar resultados muito diferentes no ChatGPT, no Claude e na longa lista de outros clientes. Por isso, um conjunto curto e fixo de prompts de teste (golden prompts) em alguns clientes reais deve fazer parte dos testes normais do produto. A lista de verificação do ensaio acrescenta uma pessoa responsável pelo estado do servidor MCP, que o volta a verificar após cada lançamento importante do MCP, do Claude ou do ChatGPT. Neste plano, isso significa que as sessões com o agente na semana 3 correm no Claude Desktop e em dois outros clientes que os seus utilizadores usam de facto, e que o script de comparação volta a correr após cada revisão do protocolo, tal como após uma atualização do WordPress.
Aperte os esquemas com base no que volta. Cada falha de validação Zod no registo é um bug de esquema ou um bug de mapeamento. Corrija, volte a fazer deploy do Worker de preview, repita o harness.
O resultado da semana 3 é um harness que passa com zero diferenças e um inventário de ferramentas que sobreviveu a cinco dias de 30 minutos diários de interação real com o agente. Se faltar algum dos dois, a semana 4 não arranca.
Como pôr o servidor MCP em produção e monitorizá-lo
A transição não tem drama se as semanas 1 a 3 correram bem.
Faça deploy dos Workers de produção. wrangler deploy --env production. O servidor MCP de produção aponta para a origem WordPress de produção, com scopes de produção nos tokens emitidos pela administração do WordPress.
Emita tokens para o primeiro runtime real de agente. Normalmente um destes: um agente interno para colaboradores, uma integração de parceiro que pede uma superfície MCP, um assistente público na loja. Comece pelo consumidor mais pequeno e de menor risco.
Ligue o Cloudflare Logpush a um armazenamento de longo prazo. Os campos de registo descritos no artigo sobre construir um servidor MCP para WooCommerce são as predefinições certas: nome da ferramenta, hash da entrada, latência, resultado da validação, scope do token. O armazenamento é o que a sua equipa já usa (BigQuery, ClickHouse, S3 + Athena).
Construa um painel de observação. Três consultas desde o primeiro dia:
- Chamadas de ferramentas por minuto, divididas por nome da ferramenta. Deteta picos de carga.
- Taxa de falhas de validação por ferramenta, dividida por código (
input_invalid,output_invalid). Deteta regressões. - Latência p50/p95/p99 por ferramenta. Deteta um WordPress lento mais acima na cadeia.
Mantenha a REST viva e intocada. A loja existente, as integrações de parceiros existentes e os recetores de webhooks existentes continuam a usar /wp-json/ exatamente como antes. O MCP é um acréscimo, não um substituto. É a regra mais importante da migração.
Os erros mais comuns ao migrar a REST API para MCP
Seis coisas que vi falhar em migrações reais:
Um campo da resposta REST que a auditoria não apanhou. Um plugin acrescenta meta_data: [...] às respostas de produtos. O esquema de saída MCP não o conhece. O parse do Zod falha com dados reais. Correção: repita a auditoria sobre tráfego de produção, alargue o esquema ou descarte o campo explicitamente com .transform().
Permalinks diferentes entre staging e produção. A ferramenta MCP product.detail devolve o campo permalink do WooCommerce. Os permalinks de staging são https://staging.example.com/...; os de produção https://example.com/.... Os dados de teste passam; a produção falha no validador de URL. Correção: configure o Worker de staging com um passo de reescrita de permalinks que espelhe o comportamento de produção.
Tratamento de variações do WooCommerce. A auditoria captou a forma da resposta de um produto simples. As respostas das variações são diferentes (os SKU das variações vivem em /wp-json/wc/v3/products/<id>/variations). Correção: trate as variações como um fetch separado em product.detail e mapeie-as para hasVariant do schema.org.
O token de autenticação vaza para os registos. Um handler regista o cabeçalho Authorization completo para depuração. O token acaba no armazenamento de registos. Correção: oculte o cabeçalho na camada de registo; rode todos os tokens emitidos antes de a ocultação estar em vigor. Relevante para o cumprimento do artigo 32.º do RGPD.
A atualização de um plugin parte a resposta REST. O WooCommerce 9.x muda o nome de um campo, o handler MCP continua à espera do nome antigo, o parse do Zod falha. Correção: fixe a versão do WooCommerce em staging, corra o harness de comparação em cada atualização do WordPress e trate o harness como parte da barreira de atualização.
O agente entra em ciclo numa chamada de ferramenta malformada. Um agente defeituoso repete order.intent 100 vezes por minuto quando a entrada falha a validação. Sem rate limit, a origem WordPress recebe 100 chamadas em cascata. Correção: rate limit por principal, como no guia de padrões de autenticação MCP, e devolva retry_after_seconds no envelope de erro.
Quanto tempo demora migrar a API do WordPress para MCP
Quatro semanas é a predefinição. Dois ajustes:
Superfície menor, duas semanas. Três ferramentas, um consumidor, sem complexidade de autenticação. Comprima a auditoria e a estrutura na semana 1, a execução em paralelo e a transição na semana 2. O mesmo padrão, um calendário mais curto.
Superfície maior, seis semanas. Uma dúzia de ferramentas, vários modos de autenticação, ações sensíveis que alteram dados. Acrescente uma semana entre a estrutura e a execução em paralelo para revisão de segurança. Acrescente uma semana entre a execução em paralelo e a transição para um lançamento suave com um único utilizador autorizado por OAuth, antes de um rollout mais amplo.
As quatro fases mantêm a mesma ordem, seja qual for o orçamento de tempo.
O WordPress muda depois de adotar MCP
Em termos simples, depois da migração:
- A interface de administração do WordPress fica igual.
- O Block Editor fica igual.
- O sistema de autenticação de utilizadores fica igual.
- Os endpoints REST existentes ficam iguais e continuam a servir os seus consumidores.
- A lógica de disparo de webhooks fica igual.
- A camada de dados (
wp_posts,wp_postmeta, tabelas do WooCommerce) fica igual.
O que se acrescenta: o servidor MCP no Cloudflare Workers, uma interface de emissão de tokens na administração do WordPress (um pequeno plugin ou uma função do tema) e a configuração do Cloudflare Logpush. Tudo o resto fica igual.
É precisamente isto que torna a migração de baixo risco. Se o servidor MCP tiver um mau dia, desliga o Worker. A superfície para agentes desaparece. A loja continua a funcionar, as integrações de parceiros continuam a funcionar e as encomendas continuam a entrar.
Como mapear verbos REST para anotações de ferramentas MCP
A folha de auditoria já tem uma coluna sobre se o endpoint altera o estado. Em MCP, essa coluna passa a ser anotações da ferramenta. O esquema da especificação 2026-07-28 define quatro indicações booleanas em ToolAnnotations: readOnlyHint (predefinição false), destructiveHint (predefinição true), idempotentHint (predefinição false) e openWorldHint (predefinição true). As indicações de destrutiva e idempotente só têm significado quando readOnlyHint é false (esquema MCP).
Um mapeamento que decorre diretamente das colunas da auditoria:
| Verbo REST na auditoria | Anotações na ferramenta MCP |
|---|---|
GET em /wp/v2/posts ou /wc/v3/products | readOnlyHint: true |
| POST que cria um registo (intenção de encomenda, rascunho de artigo) | readOnlyHint: false, destructiveHint: false |
| PUT ou PATCH sobre um ID conhecido | readOnlyHint: false, idempotentHint: true |
| DELETE | readOnlyHint: false, destructiveHint: true |
As predefinições são a razão para definir as anotações. Uma ferramenta registada sem elas conta como possivelmente destrutiva e não idempotente, por isso uma ferramenta de catálogo só de leitura sem readOnlyHint parece ao cliente mais arriscada do que é. O guia do SDK descreve o efeito prático: um anfitrião pode aprovar automaticamente uma ferramenta só de leitura e pedir confirmação antes de uma destrutiva (guia do SDK sobre ferramentas). A especificação acrescenta que os clientes devem tratar as anotações como não fidedignas, a menos que venham de um servidor de confiança, por isso as anotações nunca substituem a verificação de permissões do lado do WordPress.
A nomenclatura vem da mesma página da especificação: os nomes das ferramentas devem ter entre 1 e 128 caracteres, distinguir maiúsculas de minúsculas e usar apenas letras ASCII, algarismos, sublinhado, hífen e ponto (ferramentas MCP). catalogue.list e product.detail cumprem a regra; um nome copiado de uma rota REST com barras não cumpre.
Como devolver a um agente os erros da REST API do WordPress
Um erro da REST API do WordPress chega como JSON com code, message e data.status. A especificação MCP separa dois tipos de falha. Os erros de protocolo (ferramenta desconhecida, pedido mal formado, erro do servidor) voltam como erros JSON-RPC normais. Os erros de execução da ferramenta (falhas da API, erros de validação da entrada, erros de lógica de negócio) voltam dentro do resultado da ferramenta com isError: true, e os clientes devem passá-los ao modelo para que este corrija a chamada e tente de novo (ferramentas MCP, tratamento de erros).
Para um handler assente na REST API, isto significa que um 404 para um ID de produto desconhecido ou um 400 para um parâmetro inválido é um erro de execução. Devolva isError: true com um bloco de texto que diga ao modelo o que mudar, por exemplo que nenhum produto tem esse SKU e que catalogue.list devolve SKUs válidos. Só uma falha da própria camada MCP passa a erro JSON-RPC. Transformar cada 4xx do WordPress num erro JSON-RPC esconde a causa ao modelo, e o agente repete às cegas, exatamente o ciclo da lista de erros acima.
A mesma página fixa duas regras para resultados bem-sucedidos. Quando uma ferramenta declara um outputSchema, o servidor tem de devolver resultados estruturados conformes com esse esquema. Uma ferramenta que devolve structuredContent deve também devolver o JSON serializado num bloco de texto, por compatibilidade com versões anteriores. A versão 2 do SDK de TypeScript valida structuredContent contra outputSchema antes de o resultado sair do servidor (guia do SDK sobre ferramentas), a mesma verificação em que assenta o arnês da semana 3.
Que credencial o servidor MCP envia ao WordPress
Nesta arquitetura encontram-se duas credenciais, e a especificação mantém-nas separadas. A autorização é opcional em MCP. Quando um servidor num transporte HTTP a suporta, atua como servidor de recursos OAuth 2.1: tem de verificar se cada token de acesso foi emitido para ele como destinatário (RFC 8707), tem de responder HTTP 401 a tokens inválidos ou expirados e não pode aceitar nem reencaminhar outros tokens (autorização MCP). Os servidores no transporte stdio devem dispensar esse fluxo e obter as credenciais do ambiente.
Para um Worker à frente de /wp-json/, isto exclui reencaminhar o token do agente para o WordPress. O token do agente fica no Worker. O Worker chama o WordPress com uma credencial própria, normalmente uma palavra-passe de aplicação (Application Password) de um utilizador WordPress dedicado, que tem apenas as permissões de que o inventário de ferramentas precisa. As palavras-passe de aplicação existem no WordPress desde a versão 5.6 e são enviadas com autenticação HTTP Basic sobre HTTPS (manual da REST API, autenticação). Guarde essa palavra-passe como segredo do Worker com wrangler secret put, e não como variável comum no wrangler.toml (segredos no Cloudflare Workers).
A separação traz uma vantagem prática na semana 4. Rodar a credencial do WordPress não toca nos tokens dos agentes, e revogar um token de agente não toca no WordPress. As permissões do utilizador dedicado decidem-se pela coluna de sensibilidade dos dados da auditoria: um inventário só de catálogo não precisa de nenhuma permissão sobre encomendas.
Quando o WordPress MCP Adapter é o melhor caminho
Este plano coloca o MCP na periferia da rede, num Worker. O WordPress tem também um caminho oficial que coloca o MCP dentro do próprio WordPress. O MCP Adapter, parte da iniciativa AI Building Blocks for WordPress, expõe como ferramentas, recursos e prompts MCP as capacidades (abilities) registadas através da WordPress Abilities API. No wordpress.org, o plugin está na versão 0.7.1, requer WordPress 6.9 e PHP 7.4 e foi atualizado pela última vez a 16 de outubro de 2026 (página do plugin).
O que a documentação do adaptador diz sobre os pontos que pesam na escolha:
- As capacidades são privadas por predefinição. Uma capacidade só chega ao MCP quando
meta.public(oumeta.mcp.public) está atrue. No WordPress 6.9 e 7.0 essa flag controla apenas o MCP, e o acesso por REST continua a exigirmeta.show_in_rest; o núcleo aplicameta.publicà REST a partir da 7.1. - O servidor predefinido expõe três meta-ferramentas (
mcp-adapter/discover-abilities,mcp-adapter/get-ability-info,mcp-adapter/execute-ability) e responde por HTTP em/wp-json/mcp/mcp-adapter-default-server. wp mcp-adapter serve --user=<id>serve um servidor por stdio através do WP-CLI.- Sem um callback de permissões de transporte próprio, um servidor admite utilizadores com sessão iniciada (
is_user_logged_in()). - As anotações escritas no formato da Abilities API (
readonly,destructive,idempotent) são convertidas emreadOnlyHint,destructiveHinteidempotentHint.
O adaptador encaixa quando as ferramentas são lógica do WordPress que já vive em PHP e os clientes agênticos chegam diretamente ao site. O caminho pelo Worker encaixa quando a superfície MCP precisa de emissão de tokens própria, limites na periferia e Logpush, ou tem de continuar a responder quando a origem WordPress está lenta. A auditoria da semana 1 serve os dois caminhos: cada linha que corresponde a uma ferramenta passa a ser um handler no Worker ou uma capacidade registada.
Atualização, 24 de outubro de 2026: no benchmark Building with WordPress de Andy Peatling de outubro, o Opus 5.5 no Claude Code e o GPT-6.1-Sol no Codex concluíram 0 de 42 tarefas de proprietários de sites quando o adaptador era o único acesso, e 33 de 42 com uma palavra-passe de aplicação para a REST API. As três abilities do próprio WordPress só leem informação sobre o site, o utilizador e o servidor, e as únicas escritas vieram das abilities de produtos do WooCommerce. No issue #402, Peatling planeia abilities experimentais do núcleo em quatro etapas para fechar essa lacuna. A 21 de outubro, a equipa de IA do WordPress registou a aprovação para tornar o MCP parte da experiência predefinida do WordPress, com a 7.3 como alvo possível e sem compromisso de versão (resumo semanal). Enquanto as abilities de escrita não existirem, o caminho do adaptador obriga a escrevê-las, ao passo que os endpoints REST da auditoria da semana 1 já funcionam.
Atualização, 24 de outubro de 2026: cada plugin que traz o MCP para dentro do WordPress acrescenta superfície de ataque própria. A Wordfence publicou três entradas deste tipo a 15 e 16 de outubro de 2026: no AI Engine até à versão 3.8.3 faltava uma verificação de permissões, pelo que um colaborador (contributor) com sessão iniciada podia executar uma ação não autorizada (CVE-2026-110888); a ferramenta MCP wsp_get_posts do WSP MCP até à versão 2.9.5 permitia a qualquer subscritor com sessão iniciada ler títulos, autores e excertos de rascunhos e de artigos pendentes ou agendados (CVE-2026-109382); e o xSpeed Cache até à versão 1.4.2, um plugin de cache com funções MCP, permitia cross-site scripting armazenado por colaboradores (CVE-2026-109985). Nenhuma das três exige uma conta de administrador. Registar abilities dentro do WordPress coloca a mesma questão ao seu próprio código: cada ability precisa de um callback de permissões que verifique uma capability concreta, e não apenas se o utilizador tem sessão iniciada.
Que versão da especificação MCP adotar
A revisão atual da especificação é a 2026-07-28, e duas das suas regras tocam neste plano. Primeiro, o MCP não tem sessão ao nível do protocolo, por isso um servidor não pode contar com o estado da ligação para relacionar uma chamada de ferramenta com a seguinte. Para estado como um carrinho de compras, a especificação recomenda devolver um identificador explícito a partir de uma ferramenta de criação, aceitar esse identificador nas chamadas seguintes, verificar a autorização de quem chama face ao identificador em cada chamada e indicar o tempo de vida do identificador na descrição da ferramenta (ferramentas MCP, ferramentas com estado). Em order.intent, o ID da intenção é esse identificador.
Segundo, cada pedido leva a versão do protocolo e as capacidades do cliente em campos _meta no corpo da mensagem, e o transporte Streamable HTTP replica-os em cabeçalhos HTTP para que os intermediários possam encaminhar pedidos sem analisar o corpo (transportes MCP). Do lado do adaptador, wp mcp-adapter list --protocol=2026-07-28 conta os componentes disponíveis nessa revisão; o adaptador aceita aí 2025-11-25 e 2026-07-28.
Temas relacionados
Este artigo trata da forma da migração. A implementação está descrita no artigo sobre construir um servidor MCP para WooCommerce. A estratégia de autenticação é tratada no guia de padrões de autenticação MCP. O desenho de ferramentas tipadas é tratado no artigo sobre ferramentas de catálogo tipadas com Zod para MCP. A decisão ao nível do protocolo é tratada na comparação entre MCP e REST. A página do serviço é desenvolvimento de servidores MCP.
O orçamento é individual, porque o âmbito da migração depende do número de endpoints na auditoria, da complexidade da autenticação e do número de consumidores.
Do lado da implementação, este tema enquadra-se na migração para Next.js ou Astro.







