WordPress Block MCP
Block MCP é o WordPress MCP construído para a forma como os agentes realmente editam: um bloco por vez, em múltiplas interações, sem corromper a página.
Documentação
Block MCP
Block MCP é o MCP do WordPress construído para a forma como os agentes realmente editam — um bloco de cada vez, em múltiplas etapas, sem corromper a página. É um servidor MCP mais um plugin do WordPress que expõe o conteúdo do Gutenberg como uma árvore de blocos estruturada e endereçável, em vez de HTML bruto, para que um agente possa alterar um único título sem reescrever a página. Cada bloco carrega um UUID estável gk_ref que sobrevive a deslocamentos de irmãos (nenhum outro MCP do WordPress tem isso), então cadeias de edição em múltiplas etapas não re-buscam a página entre chamadas. Cada escrita cria uma revisão do WordPress para rollback, ETag/If-Match protege contra sobrescritas concorrentes, e uma política de camadas no servidor impede que blocos legados sejam gravados. Suportado por 326 testes PHP, 249 testes TypeScript, CI em PHP 8.2/8.3 + Node 20, e traduções para 20 idiomas.
Por que os agentes escolhem o Block MCP
- Edita um bloco, não a página inteira. Altere o nível de um título sem tocar no HTML ao redor. MCPs padrão forçam uma reescrita completa da página a cada edição; o Block MCP toca apenas no título.
- Round-trips seguros para o editor. Os marcadores de bloco
<!-- wp:* -->são preservados exatamente. Sem avisos de "este bloco contém conteúdo inesperado ou inválido" ao reabrir. - Referências de bloco estáveis que nenhum outro MCP do WordPress tem. Encadeie rapidamente inserções, exclusões e atualizações em várias etapas a partir de uma única leitura.
- Edições em lote atômicas. Corrija N blocos independentes em uma revisão com
update_blocks— validação tudo-ou-nada, então uma referência obsoleta ou índice fora do intervalo aborta todo o lote antes de qualquer coisa ser gravada. Mantém o histórico de revisões limpo em vez de 6 entradas para uma única mudança lógica. - Política de camadas aplicada no servidor. Decida quais blocos você quer permitir ou rejeitar antes de serem salvos, com substituições sugeridas.
- Concorrência otimista embutida. Dois agentes trabalhando no mesmo post não podem sobrescrever um ao outro silenciosamente.
- Suporte Yoast SEO embutido. Leia e escreva meta do Yoast (títulos, descrições, palavras-chave de foco, URLs canônicas, tipos de schema, termos primários, cartões Open Graph / Twitter) assim que o Yoast SEO estiver ativo no site.
Sumário
- Visão geral
- Por que este MCP
- Comparado a outros MCPs do WordPress
- Recursos
- Como funciona
- Início rápido
- Ferramentas MCP
- Modelos
- Referências estáveis
- Configuração
- Segurança
- Exemplos
- Testes
- Requisitos
- Limitações
- Códigos de erro
- Traduções
- Licença
- Contribuindo
Visão geral
Aqui é onde o Block MCP vence. A maioria dos outros MCPs do WordPress são wrappers em torno da API REST padrão do WordPress — bons para escrever, mas errados para editar. "Alterar um título, depois adicionar um botão, depois corrigir o próximo parágrafo" pode resultar em seu post precisando de uma grande reabilitação para voltar à sintaxe correta. O Block MCP é a resposta para um MCP do editor de blocos do WordPress que simplesmente funciona.
| O que o agente pode fazer | API REST padrão do WordPress | Block MCP |
|---|---|---|
| Editar um título sem tocar no resto da página | ❌ Reescreve a página inteira a cada edição | ✅ Atualiza apenas o título |
| Fazer 5 edições seguidas sem reenviar a página inteira a cada vez | ❌ Envia o corpo completo da página 5× | ✅ Envia apenas o que mudou |
| Encontrar qual bloco contém "Pricing" sem escanear HTML renderizado | ❌ Sem busca estruturada — o agente tem que usar regex no HTML | ✅ Busca embutida por texto ou tipo de bloco |
| Impedir que blocos legados/obsoletos sejam salvos em primeiro lugar | ❌ Escreve qualquer HTML, válido ou não | ✅ O servidor rejeita blocos legados, sugere substituições modernas |
| Editar uma página e ainda abri-la limpa no editor de blocos depois | ❌ Edita como HTML bruto — espere muitos blocos com "Este bloco contém conteúdo inesperado ou inválido" porque os marcadores de bloco originais foram removidos | ✅ A marcação do bloco é preservada exatamente. |
| Continuar editando o bloco certo após adicionar ou remover outros blocos acima dele | ❌ Relê a página inteira após cada edição | ✅ A IA pode continuar trabalhando sem reler |
| Corrigir N erros de digitação em uma página em uma única revisão | ❌ N round-trips, N revisões poluindo o histórico | ✅ Uma chamada update_blocks, uma revisão, atômica — falha parcial reverte todo o lote |
Quando você realmente pede a um IA para editar uma página
O que importa é se a página está correta depois que o agente termina. Então colocamos o Claude na frente de cada MCP, digitamos uma instrução real — "mude o título H2 'Code samples' para H3" — e depois reabrimos a página e a inspecionamos.
27 execuções no total: três servidores MCP × Haiku, Sonnet, Opus × 3 tentativas cada.
| Modelo | Block MCP | AI Engine Pro | InstaWP/mcp-wp |
|---|---|---|---|
| Haiku | ✅ 3 / 3 · 10 s média | ⚠️ 2 / 3 · 44 s média | ❌ 0 / 3 · 20 s média |
| Sonnet | ✅ 3 / 3 · 9 s média | ✅ 3 / 3 · 14 s média | ❌ 0 / 3 · 36 s média |
| Opus | ✅ 3 / 3 · 9 s média | ✅ 3 / 3 · 13 s média | ⚠️ 2 / 3 · 38 s média |
| Total | ✅ 9 / 9 | 8 / 9 | 2 / 9 |
Três conclusões:
O Block MCP funciona no modelo mais barato — e termina mais rápido. Haiku passa em todas as tentativas em 10 segundos. O agente não precisa pensar muito sobre a página porque a API é moldada exatamente como a tarefa. O AI Engine Pro no Haiku leva 44 segundos quando funciona; o InstaWP nunca funciona.
O wrapper wp/v2 do InstaWP falha 7 de 9 vezes — até o Opus só acerta 2/3. Quando o agente relata sucesso, tecnicamente é verdade que o texto do título mudou. Mas o round-trip da página inteira através de update_page remove todos os marcadores de bloco <!-- wp:* -->. Reabra a página no editor de blocos e você verá avisos de "Este bloco contém conteúdo inesperado ou inválido" na maioria dos blocos. A API REST padrão não está quebrada — ela faz exatamente o que está documentado — mas sua forma de dados permite que a IA corrompa o conteúdo sem perceber.
O AI Engine Pro é competitivo com Sonnet e Opus, mas tropeça no Haiku. Sua ferramenta wp_alter_post é ciente de blocos (a marcação do post permanece válida), mas nas tentativas falhas do Haiku o HTML renderizado e os atributos declarados do bloco saem de sincronia — por exemplo, o marcador de comentário ainda diz level: 2 enquanto a tag interna é <h3>. O editor de blocos também sinaliza isso como quebrado. Sonnet e Opus tentam novamente até ficarem consistentes (2–3 chamadas de ferramenta); Haiku às vezes desiste após declarar sucesso.
Reproduza com scripts/mcp-agent-bench.mjs.
Agora tente as operações estruturais que os agentes realmente precisam
Uma única mudança de nível de título é o caso fácil. O trabalho interessante é quando um agente precisa mover um bloco, inserir um parágrafo dentro de um contêiner existente, modificar uma tabela ou excluir um bloco — o tipo de edição estrutural em várias etapas que os fluxos de trabalho de conteúdo reais exigem.
Cinco cenários mais difíceis. Mesma matriz: três MCPs × Claude Haiku.
| Cenário | Block MCP | AI Engine Pro | InstaWP/mcp-wp |
|---|---|---|---|
| Mover um bloco para uma nova posição irmã | ✅ 15 s · 2 chamadas | ✅ 25 s · 3 chamadas | ❌ falha estrutural · 29 s |
Inserir um parágrafo dentro de um core/group | ✅ 15 s · 2 chamadas | ✅ 20 s · 4 chamadas | ❌ falha estrutural · 32 s |
| Adicionar uma linha a uma tabela de comparação | ✅ 13 s · 2 chamadas | ✅ 25 s · 4 chamadas | ❌ falha estrutural · 32 s |
| Excluir uma coluna de uma tabela | ✅ 12 s · 2 chamadas | ✅ 24 s · 4 chamadas | ❌ falha estrutural · 26 s |
| Excluir um bloco de título | ✅ 12 s · 3 chamadas | ✅ 16 s · 3 chamadas | ❌ falha estrutural · 24 s |
| Total | ✅ 5 / 5 | ✅ 5 / 5 | ❌ 0 / 5 |
O Block MCP tem média de 13 segundos e duas chamadas de ferramenta por cenário. O agente lê a página uma vez, encontra o bloco alvo por referência ou caminho, faz uma mutação, pronto.
O AI Engine Pro mantém a página intacta e termina corretamente, cerca de 2× mais lento. Sua ferramenta wp_alter_post pede ao agente que forneça tanto a marcação do comentário do bloco quanto o HTML renderizado, então a maioria dos cenários gasta um round-trip extra para gerar a forma correta.
O InstaWP/mcp-wp falha em todos os cenários com uma "falha estrutural": o agente (Haiku, dado update_page) escreve a página de volta como HTML simples — <h1>...</h1><p>...</p><ol>... — sem marcadores de bloco <!-- wp:* -->. O WordPress aceita a gravação, parse_blocks() colapsa a página inteira em um único bloco de forma livre, e cada bloco distinto na página desaparece como entidade estruturada. O agente pensa que teve sucesso; a página está quebrada no editor de blocos ao reabrir. Esse é o preço de envolver a superfície REST padrão do wp/v2 e confiar que o agente reconstrua a marcação do bloco manualmente.
Reproduza com scripts/mcp-agent-bench.mjs.
Por que o Block MCP
O Block MCP é o único MCP do WordPress projetado do zero para a forma como os agentes realmente editam páginas: um bloco de cada vez, em múltiplas etapas, sem corromper nada pelo caminho. O benchmark do loop de agente reflete isso — 9 de 9 em todos os níveis do Claude, incluindo o mais barato.
A maioria dos MCPs do WordPress envolve a API REST padrão. Isso dá ao agente CRUD em nível de post, mas para por aí — para mudar um título em uma página, o agente tem que ler todo o HTML post_content, analisá-lo, encontrar a tag certa, mutá-la e escrever tudo de volta. As fronteiras dos blocos se dissolvem, a estrutura quebra sutilmente e não há caminho de desfazer.
O Block MCP é construído em torno da própria árvore de blocos. O agente vê uma visão estruturada, endereçável e bem tipada da página — e escreve através de endpoints construídos especificamente que sabem o que são blocos.
O que isso te dá na prática:
- Edição ciente de blocos. Altere o nível de um título, troque a URL de um botão, reordene colunas — sem tocar no HTML ao redor. O agente trabalha em JSON; o plugin cuida do parse/serialize.
- Refs de blocos estáveis. Cada bloco carrega um ID persistente. Um agente pode buscar uma página uma vez, capturar os refs de cada bloco que pretende editar e então encadear inserções/exclusões/atualizações contra esses refs sem reler. Deslocamentos de irmãos não invalidam os endereços.
- Operações estruturais baseadas em caminho. Nove operações (
update-attrs,replace-block,wrap-in-group,unwrap-group,move,duplicate,insert-child,remove-block,update-html) funcionam em qualquer profundidade de aninhamento via caminhos inteiros ou refs. - Auto-transformações. Altere o atributo
levelde um título e a tag<h2>/<h3>é atualizada junto. Alterne uma lista para ordenada e<ul>vira<ol>. O plugin mantém atributos e innerHTML sincronizados para os padrões comuns, para que os agentes não precisem fazer isso. - Aplicação de políticas do site. Níveis de preferência por site rejeitam inserções de blocos que você marcou como legados e sugerem substituições. Um agente não pode escrever blocos que seu site não quer.
- Desfazer com suporte a revisões. Cada escrita retorna
before_revision_iderevision_id.revert_to_revisionreverte para qualquer lado de uma edição. - Ferramentas de descoberta. Navegue pelos tipos de bloco registrados com pontuação de preferência, pesquise padrões, consulte o uso de blocos/padrões em todo o site, resolva URLs para IDs de post. O agente pode planejar com conhecimento do que seu site realmente contém.
- Proteções de blocos estáticos. Avisa quando uma alteração de atributo deixaria a marcação renderizada obsoleta, para que o agente saiba quando também passar innerHTML.
A combinação — ciente de blocos, refs estáveis, rastreamento de revisões, aplicação de políticas — é o que os MCPs existentes que envolvem a REST API não oferecem.
Comparado a outros MCPs do WordPress
O espaço de MCPs do WordPress é pequeno, e o Block MCP é o único que opera na camada de árvore de blocos. Os outros projetos trabalham em camadas diferentes e visam fluxos de trabalho diferentes — muitas vezes são complementares em vez de concorrentes, mas o benchmark de loop de agente acima mostra que nem todos produzem resultados corretos quando solicitados a editar um bloco.
InstaWP/mcp-wp — Um MCP que envolve a REST API e opera em posts inteiros, além de ampla cobertura de usuários, comentários, mídia, plugins e busca no repositório de plugins. Destaque: gerenciamento de múltiplos sites a partir de uma única instância do MCP. Use-o quando precisar de CRUD em nível de post em vários sites ou administração geral do WordPress. Não é ciente de blocos: editar um único título dentro de uma página longa significa ler e reescrever o post inteiro, e a ida e volta através do wp/v2 e do seu update_page remove todos os marcadores de bloco <!-- wp:* -->. No nosso benchmark, falhou na validação em 7 de 9 tentativas entre Haiku/Sonnet/Opus.
AI Engine Pro — Servidor MCP auto-hospedado dentro do WordPress (HTTP Streamable em /wp-json/mcp/v1/http), criado pela Meow Apps e o plugin de IA para WordPress mais instalado (100K+). O nível gratuito expõe posts/comentários/usuários/mídia como ferramentas MCP; o Pro adiciona uma barra lateral de Assistente de Editor e mais encanamento MCP. Sua ferramenta wp_alter_post é ciente de blocos — os marcadores de comentário de bloco sobrevivem — mas pode dessincronizar os atributos declarados do bloco do seu innerHTML (por exemplo, o marcador de comentário ainda diz level: 2 enquanto a tag interna é <h3>), e o editor de blocos também sinaliza isso como quebrado. Sonnet e Opus tentam novamente até ficarem consistentes e passam; Haiku às vezes desiste após 7–12 chamadas de ferramenta. 8 de 9 no benchmark.
Block MCP (este projeto) — Opera uma camada abaixo: dentro da árvore de blocos de um único post. Endereçamento baseado em caminho e refs, auto-transformações que mantêm atributos e innerHTML sincronizados no lado do servidor, aplicação de níveis de preferência, revisões por bloco. Nada disso existe nos outros três. Use-o quando um agente precisar editar blocos — alterar o nível de um título, trocar o layout de colunas, inserir um CTA após o terceiro parágrafo — sem reescrever o conteúdo ao redor. 9 de 9 no benchmark, perfeito em todos os três modelos Claude, incluindo o mais barato.
Eles podem coexistir. O Block MCP pode (e provavelmente será) ser exposto através do adaptador oficial como habilidades registradas quando esse caminho amadurecer — mesma lógica, encanamento abençoado. Veja issues para o roteiro.
Recursos
Leitura
- Árvore de blocos completa como JSON estruturado: caminhos, nomes, atributos, refs,
text_previewdo conteúdo de cada bloco - Resumo da página em uma chamada: contagens de tipos de bloco, títulos com caminhos, marcadores de seção, profundidade máxima de aninhamento
- Modo de esboço para inspeção rápida da estrutura da página
- Pesquisar blocos por texto ou nome do bloco
- Modo de renderização expande shortcodes, resolve padrões sincronizados, marca blocos dinâmicos
Escrita — por índice, por ref ou por caminho
update_block— índice plano OU refupdate_blocks— lote atômico de N atualizações em UMA revisão; validação tudo-ou-nada, máximo de 50 itens, conta como uma escrita contra o limite de taxadelete_block— contador de nível superior OU refinsert_blocks— ancorar emafter_top_level/before_top_levelOUafter_ref/before_refedit_block_tree— 9 operações estruturais baseadas em caminho ou ref:update-attrs,update-html,replace-block,remove-blockwrap-in-group,unwrap-group,insert-child,duplicate,move
rewrite_post_blocks— reescrita completa da página- Parâmetro
dry_runpara validar qualquer mutação sem escrever
Segurança
- Auto-transformação mantém innerHTML sincronizado quando atributos mudam (nível de título, lista ordenada, tagName do grupo, URL do botão, src da imagem, altura do espaçador, etc.)
- Proteções de blocos estáticos avisam quando uma alteração de atributo pode deixar a marcação renderizada obsoleta
- Níveis de preferência configuráveis: blocos legados rejeitados na inserção, blocos de nível "evitar" retornam avisos com substituições sugeridas
- Limite de taxa por post (10 escritas/min, 2 reescritas completas/min)
- Cada escrita cria uma revisão do WordPress;
revert_to_revisiondesfaz qualquer edição
Descoberta
- Listar tipos de bloco filtrados por namespace, categoria ou nível de preferência
- Navegar por padrões (sincronizados + registrados) pontuados por recência, contagem de referências e conteúdo legado
- Análise de uso de blocos/padrões em todo o site (em cache)
- Resolver qualquer URL ou slug para seu ID de post, tipo e link de edição
Como Funciona
AI Agent ←stdio→ MCP server (your machine) ←HTTPS→ WordPress plugin (your site)
Plugin WordPress (wordpress-plugin/gk-block-mcp/) — API REST em gk-block-api/v1. Lida com parsing de blocos, serialização, verificações de segurança, pontuação de preferência, limite de taxa, revisões. Funciona com qualquer tipo de post que armazene blocos Gutenberg em post_content.
Servidor MCP (src/) — servidor stdio em TypeScript que expõe a API REST como ferramentas MCP. Autentica como um usuário normal do WordPress via Application Password. Sem privilégios especiais, sem acesso direto ao banco de dados do lado do MCP.
Início Rápido
1. Instale o plugin WordPress
Mais fácil — baixe o ZIP mais recente: gk-block-mcp.zip (construído automaticamente a partir de main a cada push).
Depois no WordPress: Plugins → Adicionar novo → Enviar plugin e escolha o ZIP.
Ou copie wordpress-plugin/gk-block-mcp/ para o wp-content/plugins/ do seu site e ative manualmente. Ou via WP-CLI:
wp plugin install https://github.com/GravityKit/block-mcp/releases/download/latest/gk-block-mcp.zip --activate
2. Conecte seu assistente de IA
O caminho mais rápido provisiona tudo para você — uma conta de serviço block-mcp dedicada, um papel com capacidades mínimas e uma Application Password — de dentro do WordPress. Vá para Configurações → Block MCP → Conectar e escolha seu cliente.
Claude Desktop (um clique). Baixe o arquivo .mcpb gerado e abra-o; o Claude Desktop instala o servidor e armazena a credencial no chaveiro do seu SO. O .mcpb é autocontido — ele inclui o servidor, então não há mais nada para instalar.
Cursor, Claude Code, ChatGPT Desktop (aprovação no navegador). Execute o conector e clique em Aprovar no navegador que abrir:
npx -y @gravitykit/block-mcp connect --site https://example.com
Ele escreve a configuração MCP do seu cliente para você (somente proprietário, modo 0600), então a senha do site nunca cai no histórico do seu shell ou em um arquivo editado manualmente. Adicione --client cursor|claude-code|claude-desktop|print para direcionar um cliente específico. Cada site que você conecta recebe sua própria entrada de servidor, então um assistente pode apontar para vários sites.
Runtime: o caminho comum executa o servidor com
npx -y @gravitykit/block-mcp— nada para clonar ou compilar. O.mcpbdo Claude Desktop incorpora o mesmo pacote.
3. Configuração manual (avançado)
Prefere configurar manualmente? Crie uma Application Password e registre o servidor você mesmo.
No admin do WordPress: Usuários → Perfil → Application Passwords. Ou via CLI:
wp user application-password create <username> "Block MCP" --porcelain
Endpoints de leitura exigem a capacidade edit_posts; endpoints de escrita exigem edit_post no post específico que está sendo alterado. Depois compile e registre o servidor:
git clone https://github.com/GravityKit/block-mcp
cd block-mcp
npm install # auto-builds dist/index.cjs via the prepare script
Registre o servidor no seu cliente MCP. Exemplo para o ~/.claude.json do Claude Code:
{
"mcpServers": {
"block-mcp": {
"command": "node",
"args": ["/absolute/path/to/block-mcp/dist/index.cjs"],
"env": {
"WORDPRESS_URL": "https://example.com",
"WORDPRESS_USER": "your-wp-username",
"WORDPRESS_APP_PASSWORD": "xxxx xxxx xxxx xxxx xxxx xxxx"
}
}
}
}
Reinicie seu cliente MCP. Execute npm run inspect para testar as ferramentas interativamente.
4. (Opcional) Ajuste as configurações
Quando o plugin está ativo, uma página de administração aparece em Configurações → Block MCP. Os padrões funcionam de imediato, mas vale a pena dar uma olhada — é aqui que você decide quais blocos os agentes de IA podem escrever, o que sugerir como substituições e quais tipos de post o create_post pode direcionar.

Veja a seção Configuração abaixo para o detalhamento completo.
Ferramentas MCP
Entrada/Saída de conteúdo
| Ferramenta | Finalidade |
|---|---|
get_page_blocks | Ler os blocos de um post. Suporta outline, summary_only, search, block_name, render, fields, persist_refs |
update_block | Atualizar atributos/innerHTML de um bloco (por flat_index ou ref) |
update_blocks | Aplicar N atualizações independentes atomicamente em UMA revisão (máx. 50). Validação tudo-ou-nada — qualquer ref obsoleta / índice fora do intervalo / rejeição de armazenamento duplo / alvo duplicado aborta o lote com erros detalhados antes que qualquer coisa chegue ao disco |
insert_blocks | Inserir blocos em uma posição (por contador ou ref) |
delete_block | Remover bloco(s) (por contador ou ref) |
replace_block_range | Troca atômica de N blocos por M blocos em uma única revisão |
rewrite_post_blocks | Reescrita completa da página |
edit_block_tree | 9 operações estruturais baseadas em caminho ou ref |
insert_pattern | Inserir um padrão, sincronizado ou inline |
create_pattern | Criar um padrão sincronizado a partir de blocos estruturados ou conteúdo bruto, com controle de status de sincronização |
revert_to_revision | Reverter para um ID de revisão anterior |
Posts e taxonomias
| Ferramenta | Finalidade |
|---|---|
create_post | Criar um post ou página (rascunho, publicar, futuro) — aceita blocos ou HTML |
update_post | Atualizar metadados do post, status, termos — cobre transições de publicar/lixeira/restaurar |
list_terms | Listar termos de taxonomia (categorias, tags, personalizadas) para consulta de ID |
find_posts / post_info / resolve_url | Localizar posts por busca, ID, slug ou URL |
Mídia
| Ferramenta | Finalidade |
|---|---|
upload_media | Upload via caminho local, sideload de URL (com proteção SSRF) ou base64. Retorna ID do anexo + URL |
Descoberta
| Ferramenta | Finalidade |
|---|---|
list_block_types | Navegar pelos tipos de bloco registrados com níveis de preferência, variações de estilo e restrições de aninhamento (parent/ancestor/allowed_blocks). Passe include_supports:true para o objeto supports completo de cada bloco (opt-in, padrão false) |
list_patterns / get_pattern | Pesquisar e inspecionar padrões com pontuação; filtrar por category e navegar pelo vocabulário de categorias registradas |
get_site_usage | Análise de uso de blocos/padrões |
list_binding_sources | Fontes de bindings de blocos registradas (ex.: core/post-meta, core/pattern-overrides) que o metadata.bindings de um bloco pode referenciar |
SEO (quando o Yoast SEO está ativo)
| Ferramenta | Finalidade |
|---|---|
yoast_get_seo | Ler metadados de SEO: título, descrição, robots, OG, Twitter, schema, pontuações |
yoast_update_seo / yoast_bulk_update_seo | Atualizar campos de SEO em um ou vários posts |
Modelos (somente temas de blocos)
| Ferramenta | Finalidade |
|---|---|
list_templates | Navegar pelos modelos e partes de modelo de um tema de blocos (filtrar por tipo, área, post_type, slug, origem) |
get_template | Metadados de um único modelo, conteúdo bruto e blocos analisados |
update_template | Substituir o conteúdo inteiro de um modelo/parte, controlado por uma configuração do site (desativado por padrão) |
reset_template | Excluir a substituição de banco de dados de um modelo, revertendo-o para o arquivo do tema |
Modelos
list_templates / get_template são ferramentas somente leitura para navegar pelos modelos de um tema de blocos (layouts de página como single, archive) e partes de modelo (regiões reutilizáveis como header, footer), o mesmo conteúdo que a lista de modelos do Editor do Site exibe.
O wp_id de cada linha informa se uma substituição de banco de dados está atualmente ocultando o arquivo do tema: null significa que o id resolve para o próprio arquivo do tema; um número significa que existe uma personalização e esse ID de post é a substituição. Em um tema clássico (não baseado em blocos), list_templates retorna uma lista vazia com um note explicando o motivo, em vez de um erro.
Os modelos são endereçados somente por índice. O campo blocks de get_template é formatado como get_page_blocks. Se as ferramentas de gravação por bloco (update_block, edit_block_tree por ref) se aplicam depende do wp_id: um modelo que ainda resolve para o arquivo do tema (wp_id: null) não é gravável por elas, enquanto um modelo com substituição de banco de dados (um wp_id numérico) é um post comum que elas editam como qualquer outro. Use update_template (veja Editando modelos abaixo) para materializar a substituição de um modelo que existe apenas no arquivo do tema.
Editando modelos
update_template / reset_template gravam em modelos. Ambos estão desativados por padrão. Ative "Permitir que o assistente edite modelos e partes de modelo do tema" em Configurações → Block MCP primeiro, ou toda chamada retornará 403 com uma mensagem acionável. Ativar o interruptor concede à conta do agente Block MCP uma capacidade gk_block_mcp_edit_templates dedicada (nada mais que ela pode fazer muda); a conexão "própria" de um humano também pode editar modelos, já que ela já carrega edit_theme_options.
update_templatesubstitui o conteúdo inteiro de um modelo: substituição do modelo completo, comorewrite_post_blocks, não uma edição por bloco. Forneça exatamente um decontent(marcação bruta) oublocks(estruturado; validado contra o registro de blocos e os níveis de preferência, igual a qualquer outra gravação de bloco estruturado). Se o id atualmente resolve para o arquivo do tema, uma substituição de banco de dados é criada automaticamente (override_created: true); o arquivo do tema em si nunca é tocado. Gravar novamente reutiliza a mesma substituição.reset_templateexclui a substituição, revertendo o id para o arquivo do tema. Aparência → Editor → Redefinir faz o mesmo pela administração do WordPress.
Uma vez que uma substituição existe, seu wp_id é um ID de post normal — update_block, get_page_blocks e o restante das ferramentas por bloco funcionam com ele como qualquer outro post.
Refs estáveis
Todo bloco em uma resposta get_page_blocks inclui um campo ref:
{
"index": 5,
"path": [0, 2, 1],
"ref": "blk_a3f2c1q9",
"name": "core/heading",
"attributes": { "level": 2, "content": "Hello" }
}
As refs são armazenadas em attrs.metadata.gk_ref dentro de post_content, então sobrevivem entre sessões e entre mutações que deslocam posições de irmãos. Passe ref para update_block, delete_block ou edit_block_tree para endereçar o mesmo bloco de forma confiável mesmo após inserções ou exclusões em outro lugar da página.
A primeira leitura de um post atribui e persiste refs de forma preguiçosa por meio de uma gravação direta no banco que pula a criação de revisão (refs são metadados apenas de editor, não conteúdo). Passe persist_refs: false para ler sem esse efeito colateral.
Configuração
Tudo nesta seção é editável em Configurações → Block MCP na administração do WordPress. Os padrões são sensatos — nada disso é necessário para começar.
Pontuações de nível por namespace
As preferências de blocos são armazenadas como uma opção do WordPress (gk_block_api_preferences) e configuráveis por site. Cada namespace de bloco recebe uma pontuação de 0 a 100, que mapeia para um nível:
| Nível | Pontuação | Política |
|---|---|---|
| preferido | ≥ 80 | Usar livremente |
| aceitável | 50–79 | Usar se o preferido não estiver disponível |
| evitar | 10–49 | Avisar, retornar substituição sugerida |
| legado | < 10 | Rejeitar na inserção |
Os padrões vêm com core/* preferido e um conjunto inicial de namespaces conhecidamente obsoletos marcados como legado. Adicione novos namespaces digitando na linha inferior — uma nova linha em branco aparece assim que você começa a digitar.
Mapa de substituição
Quando um agente tenta inserir um bloco legado, o erro de rejeição inclui uma substituição sugerida deste mapa. Ambas as colunas são menus suspensos pesquisáveis de todos os blocos atualmente registrados no seu site (você também pode digitar um nome de bloco que não esteja registrado atualmente).

Blocos que armazenam dados em dois lugares
Alguns blocos (notavelmente yoast/faq-block) mantêm os mesmos dados em ambos seus atributos e seu innerHTML. Atualizar um sem o outro corrompe o bloco silenciosamente. O Block MCP detecta a maioria automaticamente ao escanear seu site; liste extras aqui para que a API force os agentes a enviar ambos os campos juntos.

Tipos de post que agentes de IA podem criar
Restrinja create_post a tipos de post específicos. Deixe tudo desmarcado para permitir qualquer tipo de post público com suporte REST (o padrão).

Verificação do modo de armazenamento e redefinição
A verificação percorre todos os posts publicados e classifica cada bloco distinto como estático / dinâmico / duplo, substituindo os padrões de filtro por dados ao vivo do seu site. Lenta em sites grandes; o resultado é armazenado em cache. O botão Redefinir abaixo limpa todas as opções que este plugin possui e restaura os padrões codificados.

Segurança
O Block MCP dá a um assistente de IA exatamente o acesso de que ele precisa para editar conteúdo — e nada mais.
- Uma conta separada e limitada. A conexão cria uma conta dedicada apenas para o assistente. Ela pode escrever e editar seus posts, páginas e mídia, mas não pode alterar configurações do site, excluir conteúdo de outras pessoas ou entrar no seu painel — e desconectá-la remove todo esse acesso de uma vez. (Você pode conectar pela sua própria conta; isso é claramente marcado como a opção de maior acesso, e o proprietário do site pode desativar essa opção completamente.)
- Sua senha permanece privada. Ela nunca é exibida em um endereço da web nem salva no histórico do navegador, e a conexão é configurada localmente no seu próprio computador. Quaisquer arquivos de configuração gravados são legíveis apenas por você.
- Segredos armazenados são criptografados. Qualquer credencial mantida entre etapas de configuração é criptografada (AES‑256‑GCM) antes de ser salva e limpa após o uso — nunca mantida como texto simples.
- O assistente não pode injetar código. Tudo o que ele escreve é sanitizado, então ele não pode inserir scripts ou rastreadores nas suas páginas.
Modo selado (Claude Desktop)
O instalador de um clique do Claude Desktop pode incluir sua credencial ou deixá-la de fora:
| Modo | O que acontece |
|---|---|
prefill (padrão) | O instalador inclui a senha, então a configuração é de um clique; o Claude Desktop a salva no chaveiro do seu sistema operacional. |
paste | O instalador deixa a senha de fora — você a cola você mesmo, então ela nunca chega a um arquivo baixado. |
Desenvolvedores podem forçar o modo de colagem com um filtro, ou definindo GK_BLOCK_MCP_FORCE_PASTE_SECRET como true em wp-config.php:
add_filter( 'gk/block-mcp/credential/seal-mode', fn() => 'paste' );
Exemplos
Atualizar um título por URL
"Altere o H2 'Welcome' em
/about/para 'About Us'."
resolve_url({ url: "/about/" })→ ID do postget_page_blocks({ post_id, outline: true })→ encontra o título empath: [4], refblk_a3f2c1q9edit_block_tree({ post_id, op: "update-attrs", ref: "blk_a3f2c1q9", attributes: { content: "About Us" } })
A transformação automática atualiza tanto o atributo content quanto o texto interno <h2>. Revisão criada.
Fluxo de trabalho de edição encadeada (onde as refs brilham)
"Na página inicial: exclua o terceiro parágrafo, mude o próximo H2 para H3 e adicione um botão de CTA depois dele."
get_page_blocks({ post_id })uma vez — capture refs para todos os três blocos alvodelete_block({ post_id, ref: <para-ref> })edit_block_tree({ post_id, op: "update-attrs", ref: <heading-ref>, attributes: { level: 3 } })insert_blocks({ post_id, after_ref: <heading-ref>, blocks: [{ name: "core/buttons", … }] })
Com endereçamento baseado em caminho, o agente precisaria buscar novamente entre cada etapa. Com refs, uma única leitura cobre toda a cadeia.
Criar e publicar um documento
list_terms({ taxonomy: "category", search: "Documentation" })→ ID da categoriacreate_post({ title: "Getting Started", status: "draft", categories: [<id>], blocks: [...] })→ ID do postupload_media({ path: "/tmp/screenshot.png", alt_text: "...", post_id })→ ID do anexo + URLinsert_blocks({ post_id, after_top_level: 0, blocks: [{ name: "core/image", attributes: { id: <atch>, url, alt: "..." } }] })yoast_update_seo({ post_id, title: "...", description: "...", focus_keyword: "..." })update_post({ post_id, status: "publish" })
Testes
Execute todos os conjuntos localmente:
# TypeScript (Vitest): 885 tests
npm test
# PHP (PHPUnit, stub WP bootstrap): 1,440 tests
cd wordpress-plugin/gk-block-mcp && phpunit -c tests/phpunit.xml
O conjunto PHP usa uma camada mínima de stub do WordPress (sem exigir instalação completa do WP) para exercitar validação, caminhos de erro, mecanismo de mutação, resolução de refs, transformações automáticas de HTML, ciclo de vida de posts, listagem de termos, validação de mídia e resumo/estrutura REST.
Um script de fumaça de ponta a ponta está incluído em scripts/ para validação com WordPress ao vivo; aponte-o para qualquer site WordPress definindo WORDPRESS_URL, WORDPRESS_USER e WORDPRESS_APP_PASSWORD.
Requisitos
- Node.js ≥ 20
- WordPress ≥ 6.0 com Senhas de Aplicativo habilitadas
- PHP ≥ 7.4
- HTTPS (exigido pelo WordPress para autenticação com Senha de Aplicativo)
Limitações
Escopo
- As edições funcionam em posts armazenados como blocos. Modelos de tema de blocos (
wp_template,wp_template_part) e áreas de widgets ainda não são suportados. - Tipos de post personalizados devem declarar
show_in_rest: true(ou estar na lista de permissões configurada) para serem graváveis. - O innerHTML passa por
wp_kses_postem toda gravação —<script>, manipuladores de eventos inline e outra marcação não permitida são removidos. Adicione tags à lista de permissões com o filtrowp_kses_allowed_htmlse necessário.
Política de níveis
- Blocos de nível legado (pontuação < 10) são rejeitados na inserção,
replace-block,insert-child,wrap-in-groupereplace_all_blocks. O erro inclui uma substituição sugerida quando uma está mapeada. - Blocos de nível evitar (pontuação 10–49) são gravados com avisos, não erros.
- A política de níveis é somente na inserção —
update-attrseupdate-htmlpodem mutar um bloco legado que já está na página (para que páginas existentes não sejam quebradas).
Limites estruturais
- A profundidade de aninhamento de blocos é limitada a 32 níveis (
MAX_BLOCK_DEPTH). Árvores mais profundas que isso são rejeitadas comblock_depth_exceeded. Não filtrável. - Gravações em lote (
update_blocks) têm limite de 50 itens por chamada (MAX_BATCH_SIZE). Um lote conta como uma gravação contra o limite de taxa, independentemente de N.
Limites de taxa
- Por post, por minuto, com suporte de transientes. 10 gravações/min para
update_*/delete_*/insert_*/mutate_*/update_post; 2/min para reescrita completaPUT /blocks. - Os compartimentos são por post, não por usuário — vários agentes editando o mesmo post compartilham o orçamento.
- Retorna HTTP 429
rate_limit_exceeded; redefine naturalmente após 60 s.
innerHTML de bloco estático
- O WordPress não tem equivalente em PHP da função React
save, então o servidor não pode regenerar a marcação renderizada de um bloco estático apenas a partir de seus atributos. As transformações automáticas cobrem nível de título, lista ordenada,tagNamede grupo, URL de botão,src/altde imagem, booleanos de vídeo/áudio, altura/largura de espaçador,opende detalhes e citação. Para qualquer outra coisa, envieinnerHTMLjunto comattributes(update_blockrecusará gravações de armazenamento duplo que omitam qualquer um dos lados).
Blocos de armazenamento duplo
- Um pequeno conjunto de blocos (notavelmente
yoast/faq-block) duplica estado entreattributeseinnerHTML. A API exige ambos os campos juntos na atualização (errodual_storage_requires_bothcaso contrário) e a lista de armazenamento duplo é configurável em Configurações → Block MCP.
Block Bindings API
- Requer WordPress 6.5+ no site de destino.
- Os atributos listados em
attrs.metadata.bindingsestão bloqueados para escrita por padrão — uma escrita que atinge um atributo vinculado retorna 400bound_attribute. Passeallow_bound_writes: truena atualização para sobrescrever. - As leituras expõem o mapa de vínculos como um campo
bindingsde nível superior e um arraybound_attributes; a resolução do vínculo (renderização do valor dinâmico) ocorre apenas no modorender.
Extração de atributos com reconhecimento de esquema
- As leituras mesclam atributos originados via
block.json(source: attribute | html | rich-text | text) na resposta. source: 'query'ainda não é suportado — retorna apenas os atributos delimitadores com um TODO.source: 'meta'está obsoleto e é ignorado.
Padrões
- Padrões registrados são sempre embutidos na inserção. Apenas padrões sincronizados (entradas CPT
wp_block) podem ser inseridos como referênciacore/block.
Uploads de mídia
- O sideload por URL é limitado a 25 MB e usa um timeout de 10 s.
- A proteção SSRF rejeita hosts RFC1918 / loopback / link-local / cloud-metadata (
169.254.0.0/16) antes do download. A lista de bloqueio é extensível via o filtrogk_block_api_url_sideload_blocked_ranges. - Os uploads podem ser desabilitados em todo o site com o kill-switch em Configurações → Block MCP.
Modo de renderização
?render=trueresolve blocos dinâmicos, expande shortcodes e segue referências de padrões sincronizados. Desabilitado por padrão — os caminhos de leitura retornam a marcação bruta do bloco para que um agente veja o que o editor vê.
Códigos de Erro
Todo endpoint REST retorna erros como JSON no formato padrão do WordPress { code, message, data: { status, … } }. O servidor MCP encaminha o status HTTP e o código para o resultado da ferramenta, para que o agente possa despachar diretamente em code.
Autenticação e permissões (HTTP 403)
| Código | Quando dispara | Como recuperar |
|---|---|---|
rest_forbidden | O chamador não possui a capacidade edit_posts na requisição | Use uma Senha de Aplicativo para um usuário com edit_posts |
rest_cannot_edit | O chamador não possui edit_post para o post específico | Reatribua o post ou eleve a capacidade do usuário |
rest_cannot_create | O chamador não possui edit_posts (ou a capacidade de criação específica do tipo de post) para create_post | O mesmo |
rest_cannot_publish | create_post / update_post solicitou publish mas o chamador não possui publish_posts | Reduza o status para draft/pending, ou eleve o usuário |
rest_cannot_upload | upload_media chamado sem a capacidade upload_files | Eleve o usuário |
rest_cannot_assign_author | create_post / update_post definiu author para outro usuário sem edit_others_posts | Remova o campo author ou eleve |
uploads_disabled | O administrador do site desativou o kill-switch de uploads em Configurações → Block MCP | Reative no admin ou pare de chamar upload_media |
Não encontrado (HTTP 404)
| Código | Quando dispara | Como recuperar |
|---|---|---|
post_not_found | post_id não resolve para um post | Execute novamente resolve_url ou find_posts |
block_not_found | flat_index / path / ref não endereça um bloco existente | Busque novamente get_page_blocks |
ref_stale | gk_ref não existe mais no post (excluído ou substituído) | Busque novamente e re-vincule |
pattern_not_found | pattern_id não corresponde a um padrão sincronizado ou registrado | Use list_patterns |
revision_not_found | revert_to_revision recebeu um ID que não é uma revisão do post de destino | Use o histórico de update_post ou consulte as revisões do post |
not_found | Recurso não encontrado genérico para endpoints que não possuem um código específico | Inspecione message para saber qual recurso |
Pré-condição / concorrência (HTTP 412)
| Código | Quando dispara | Como recuperar |
|---|---|---|
stale_revision | O cabeçalho If-Match / o campo do corpo if_match não correspondeu ao ID de revisão atual (outra pessoa editou o post) | Busque novamente, reaplique as alterações com base no estado atual, tente novamente |
Validação (HTTP 400)
| Código | Quando dispara | Como recuperar |
|---|---|---|
legacy_block | Inserir um bloco no nível legado | Use a substituição sugerida retornada em data.suggested_replacement |
dual_storage_requires_both | Atualizar um bloco de armazenamento duplo com apenas attributes ou apenas innerHTML | Envie ambos os campos juntos |
bound_attribute | A atualização atinge um atributo listado em attrs.metadata.bindings | Resolva o vínculo upstream, ou passe allow_bound_writes: true |
batch_too_large | O payload de update_blocks excede MAX_BATCH_SIZE (50) | Divida em vários lotes |
batch_validation_failed | Um ou mais itens em um lote falharam na validação; toda a chamada foi rejeitada antes de qualquer gravação em disco | Inspecione data.errors[] para os códigos por item e tente novamente os itens válidos |
empty_batch | update_blocks chamado com updates: [] | Pule a chamada |
block_depth_exceeded | A profundidade da árvore excederia 32 níveis após a gravação | Achate a estrutura do bloco |
invalid_path / invalid_destination / invalid_target | O array de caminho não contém inteiros não negativos, ou não endereça um bloco | Busque novamente e use um caminho novo |
invalid_ref | A ref não é uma forma válida de blk_XXXXXXXX | Busque novamente e use uma ref retornada |
ref_not_top_level | A operação requer um bloco de nível superior (ex.: replace_block_range) mas a ref aponta para um bloco aninhado | Passe a ref do ancestral de nível superior |
invalid_op | A operação edit_block_tree não está no enum de 9 operações | Use uma de update-attrs, update-html, replace-block, remove-block, wrap-in-group, unwrap-group, insert-child, duplicate, move |
invalid_block | A definição do bloco está malformada (faltando name, nome não registrado, etc.) | Verifique o nome do bloco com list_block_types |
missing_attributes / missing_html / missing_block / missing_blocks / missing_destination / missing_target / missing_data / missing_lookup / missing_file / missing_title | Campo obrigatório omitido | Inclua o campo |
invalid_count / invalid_range / invalid_index / invalid_limit / invalid_cursor | Argumento numérico fora do intervalo ou com forma incorreta | Veja message para os limites esperados |
invalid_updates | O array de atualizações de update_blocks está malformado | Remodele conforme o esquema de update_blocks |
invalid_post_type / invalid_status / invalid_taxonomy / invalid_term / invalid_author / invalid_parent / invalid_featured_media | Validação do campo create_post / update_post | Verifique o valor no registro relevante do WordPress |
cycle_parent | A atribuição de pai criaria um loop de hierarquia | Escolha um pai diferente |
mixed_trash_payload | update_post misturou status: trash com outros campos | Mova para a lixeira primeiro, depois atualize separadamente |
invalid_if_match | O cabeçalho está presente mas não é um inteiro positivo | Envie If-Match: <revision_id> |
revision_mismatch | Interno — o ID de revisão capturado não correspondeu antes do salvamento | Tente novamente; se persistir, abra um issue |
no_inner_blocks | unwrap-group em um bloco que não possui nenhum | Ou remova o wrapper de outra forma ou insira os filhos primeiro |
no_file / missing_file | upload_media não recebeu payload multipart | Envie um campo file, url, ou data_base64 |
multiple_inputs / mutually_exclusive | upload_media recebeu mais de um de file / url / data_base64 | Envie exatamente um |
invalid_filename / disallowed_mime / file_too_large / invalid_base64 / invalid_url | Payload de upload_media rejeitado | Veja message para saber qual verificação falhou |
upload_error | O manipulador de upload do WordPress retornou um erro | Inspecione message |
empty_pattern | insert_pattern recebeu um padrão sem blocos analisados | Escolha um padrão diferente |
invalid_body | O corpo JSON da requisição não pôde ser analisado | Valide a forma do JSON |
Limite de taxa (HTTP 429)
| Código | Quando dispara | Como recuperar |
|---|---|---|
rate_limit_exceeded | Orçamento de escrita por post esgotado (10 escritas/min, ou 2 reescritas completas/min) | Aguarde até 60 s e tente novamente; considere agrupar com update_blocks |
scan_rate_limited | A verificação da página de configurações foi acionada com muita frequência | Aguarde; isso afeta apenas verificações do lado do admin |
Método não permitido (HTTP 405)
Não é um erro do plugin: um 405 vem do firewall ou servidor web do host, antes do WordPress. Alguns hosts gerenciados rejeitam PUT, PATCH e DELETE diretamente, razão pela qual leituras e create_post funcionam nesse host enquanto toda ferramenta de edição falha.
O cliente lida com isso por conta própria. Quando um desses verbos é rejeitado, ele reproduz a requisição como um POST carregando um cabeçalho X-HTTP-Method-Override (a forma que o núcleo do WordPress aceita), e lembra do host, para que edições posteriores passem na primeira tentativa. Hosts que aceitam os verbos reais nunca veem o cabeçalho.
| Sintoma | O que significa | Como recuperar |
|---|---|---|
Block API Error (405) com corpo HTML (ex.: nginx) em uma ferramenta de edição | O firewall rejeitou tanto o verbo real quanto a reprodução de substituição | Peça ao host para permitir PUT, PATCH e DELETE, ou para parar de remover X-HTTP-Method-Override, no caminho REST do WordPress |
| Leituras funcionam, edições falham imediatamente após a instalação | O host rejeita verbos de edição; o fallback não pôde ser concluído | O mesmo que acima; confirme com curl -X PATCH contra /wp-json/gk-block-api/v1/... |
Upstream (HTTP 502)
| Código | Quando dispara | Como recuperar |
|---|---|---|
url_fetch_failed | O sideload de URL de upload_media falhou na camada HTTP (DNS, TLS, não-2xx, ou bloqueio SSRF) | Verifique se a URL é publicamente acessível e não está em uma faixa de IP bloqueada |
Erro de servidor (HTTP 500)
| Código | Quando dispara | Como recuperar |
|---|---|---|
internal_error | Exceção não capturada subiu até o envelope REST | Abra um issue com a mensagem + reprodução |
wp_insert_post_failed | wp_insert_post retornou um WP_Error | Inspecione message; frequentemente é um campo obrigatório ausente na camada do banco de dados |
duplicate_failed | A operação edit_block_tree duplicate não conseguiu clonar o bloco em JSON (só dispara em entrada verdadeiramente malformada — recursos, UTF-8 inválido) | Abra um issue com a definição do bloco |
sideload_failed | A URL de upload_media passou pelas camadas SSRF + HTTP mas media_handle_sideload falhou | Inspecione message; frequentemente é cota de disco ou registro MIME |
attachment_missing | upload_media criou o anexo mas não conseguiu encontrá-lo para metadados | Abra um issue |
trash_failed / untrash_failed | wp_trash_post / wp_untrash_post retornou false | Tente novamente; se persistir, verifique conflitos de filtros |
Traduções
O plugin WordPress acompanha traduções para os 20 locais mais usados do WordPress: árabe, chinês (simplificado), tcheco, dinamarquês, holandês, finlandês, francês, alemão, húngaro, indonésio, italiano, japonês, coreano, polonês, português (BR), romeno, russo, espanhol, sueco, turco.
As traduções foram geradas com Potomatic — um CLI de código aberto para traduzir arquivos .pot em escala com IA.
Licença
- Plugin WordPress: GPL-2.0-or-later
- Servidor MCP: MIT
Contribuindo
Issues e PRs são bem-vindos em github.com/GravityKit/block-mcp. Execute as suítes de teste antes de enviar; novas mutações devem ser acompanhadas de cobertura PHPUnit + Vitest.