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

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 fazerAPI REST padrão do WordPressBlock 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.

ModeloBlock MCPAI Engine ProInstaWP/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 / 98 / 92 / 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árioBlock MCPAI Engine ProInstaWP/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 level de 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_id e revision_id. revert_to_revision reverte 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_preview do 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 ref
  • update_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 taxa
  • delete_block — contador de nível superior OU ref
  • insert_blocks — ancorar em after_top_level/before_top_level OU after_ref/before_ref
  • edit_block_tree — 9 operações estruturais baseadas em caminho ou ref:
    • update-attrs, update-html, replace-block, remove-block
    • wrap-in-group, unwrap-group, insert-child, duplicate, move
  • rewrite_post_blocks — reescrita completa da página
  • Parâmetro dry_run para 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_revision desfaz 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 .mcpb do 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.

Namespace tier scores

Veja a seção Configuração abaixo para o detalhamento completo.

Ferramentas MCP

Entrada/Saída de conteúdo

FerramentaFinalidade
get_page_blocksLer os blocos de um post. Suporta outline, summary_only, search, block_name, render, fields, persist_refs
update_blockAtualizar atributos/innerHTML de um bloco (por flat_index ou ref)
update_blocksAplicar 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_blocksInserir blocos em uma posição (por contador ou ref)
delete_blockRemover bloco(s) (por contador ou ref)
replace_block_rangeTroca atômica de N blocos por M blocos em uma única revisão
rewrite_post_blocksReescrita completa da página
edit_block_tree9 operações estruturais baseadas em caminho ou ref
insert_patternInserir um padrão, sincronizado ou inline
create_patternCriar um padrão sincronizado a partir de blocos estruturados ou conteúdo bruto, com controle de status de sincronização
revert_to_revisionReverter para um ID de revisão anterior

Posts e taxonomias

FerramentaFinalidade
create_postCriar um post ou página (rascunho, publicar, futuro) — aceita blocos ou HTML
update_postAtualizar metadados do post, status, termos — cobre transições de publicar/lixeira/restaurar
list_termsListar termos de taxonomia (categorias, tags, personalizadas) para consulta de ID
find_posts / post_info / resolve_urlLocalizar posts por busca, ID, slug ou URL

Mídia

FerramentaFinalidade
upload_mediaUpload via caminho local, sideload de URL (com proteção SSRF) ou base64. Retorna ID do anexo + URL

Descoberta

FerramentaFinalidade
list_block_typesNavegar 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_patternPesquisar e inspecionar padrões com pontuação; filtrar por category e navegar pelo vocabulário de categorias registradas
get_site_usageAnálise de uso de blocos/padrões
list_binding_sourcesFontes 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)

FerramentaFinalidade
yoast_get_seoLer metadados de SEO: título, descrição, robots, OG, Twitter, schema, pontuações
yoast_update_seo / yoast_bulk_update_seoAtualizar campos de SEO em um ou vários posts

Modelos (somente temas de blocos)

FerramentaFinalidade
list_templatesNavegar pelos modelos e partes de modelo de um tema de blocos (filtrar por tipo, área, post_type, slug, origem)
get_templateMetadados de um único modelo, conteúdo bruto e blocos analisados
update_templateSubstituir o conteúdo inteiro de um modelo/parte, controlado por uma configuração do site (desativado por padrão)
reset_templateExcluir 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_template substitui o conteúdo inteiro de um modelo: substituição do modelo completo, como rewrite_post_blocks, não uma edição por bloco. Forneça exatamente um de content (marcação bruta) ou blocks (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_template exclui 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ívelPontuaçãoPolítica
preferido≥ 80Usar livremente
aceitável50–79Usar se o preferido não estiver disponível
evitar10–49Avisar, retornar substituição sugerida
legado< 10Rejeitar 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).

Replacement map

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.

Dual-storage blocks

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).

Post types allow-list

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.

Storage scan and reset

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:

ModoO 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.
pasteO 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'."

  1. resolve_url({ url: "/about/" }) → ID do post
  2. get_page_blocks({ post_id, outline: true }) → encontra o título em path: [4], ref blk_a3f2c1q9
  3. edit_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."

  1. get_page_blocks({ post_id }) uma vez — capture refs para todos os três blocos alvo
  2. delete_block({ post_id, ref: <para-ref> })
  3. edit_block_tree({ post_id, op: "update-attrs", ref: <heading-ref>, attributes: { level: 3 } })
  4. 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

  1. list_terms({ taxonomy: "category", search: "Documentation" }) → ID da categoria
  2. create_post({ title: "Getting Started", status: "draft", categories: [<id>], blocks: [...] }) → ID do post
  3. upload_media({ path: "/tmp/screenshot.png", alt_text: "...", post_id }) → ID do anexo + URL
  4. insert_blocks({ post_id, after_top_level: 0, blocks: [{ name: "core/image", attributes: { id: <atch>, url, alt: "..." } }] })
  5. yoast_update_seo({ post_id, title: "...", description: "...", focus_keyword: "..." })
  6. 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_post em 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 filtro wp_kses_allowed_html se 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-group e replace_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çãoupdate-attrs e update-html podem 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 com block_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 completa PUT /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, tagName de grupo, URL de botão, src/alt de imagem, booleanos de vídeo/áudio, altura/largura de espaçador, open de detalhes e citação. Para qualquer outra coisa, envie innerHTML junto com attributes (update_block recusará 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 entre attributes e innerHTML. A API exige ambos os campos juntos na atualização (erro dual_storage_requires_both caso 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.bindings estão bloqueados para escrita por padrão — uma escrita que atinge um atributo vinculado retorna 400 bound_attribute. Passe allow_bound_writes: true na atualização para sobrescrever.
  • As leituras expõem o mapa de vínculos como um campo bindings de nível superior e um array bound_attributes; a resolução do vínculo (renderização do valor dinâmico) ocorre apenas no modo render.

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ência core/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 filtro gk_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=true resolve 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ódigoQuando disparaComo recuperar
rest_forbiddenO chamador não possui a capacidade edit_posts na requisiçãoUse uma Senha de Aplicativo para um usuário com edit_posts
rest_cannot_editO chamador não possui edit_post para o post específicoReatribua o post ou eleve a capacidade do usuário
rest_cannot_createO chamador não possui edit_posts (ou a capacidade de criação específica do tipo de post) para create_postO mesmo
rest_cannot_publishcreate_post / update_post solicitou publish mas o chamador não possui publish_postsReduza o status para draft/pending, ou eleve o usuário
rest_cannot_uploadupload_media chamado sem a capacidade upload_filesEleve o usuário
rest_cannot_assign_authorcreate_post / update_post definiu author para outro usuário sem edit_others_postsRemova o campo author ou eleve
uploads_disabledO administrador do site desativou o kill-switch de uploads em Configurações → Block MCPReative no admin ou pare de chamar upload_media

Não encontrado (HTTP 404)

CódigoQuando disparaComo recuperar
post_not_foundpost_id não resolve para um postExecute novamente resolve_url ou find_posts
block_not_foundflat_index / path / ref não endereça um bloco existenteBusque novamente get_page_blocks
ref_stalegk_ref não existe mais no post (excluído ou substituído)Busque novamente e re-vincule
pattern_not_foundpattern_id não corresponde a um padrão sincronizado ou registradoUse list_patterns
revision_not_foundrevert_to_revision recebeu um ID que não é uma revisão do post de destinoUse o histórico de update_post ou consulte as revisões do post
not_foundRecurso não encontrado genérico para endpoints que não possuem um código específicoInspecione message para saber qual recurso

Pré-condição / concorrência (HTTP 412)

CódigoQuando disparaComo recuperar
stale_revisionO 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ódigoQuando disparaComo recuperar
legacy_blockInserir um bloco no nível legadoUse a substituição sugerida retornada em data.suggested_replacement
dual_storage_requires_bothAtualizar um bloco de armazenamento duplo com apenas attributes ou apenas innerHTMLEnvie ambos os campos juntos
bound_attributeA atualização atinge um atributo listado em attrs.metadata.bindingsResolva o vínculo upstream, ou passe allow_bound_writes: true
batch_too_largeO payload de update_blocks excede MAX_BATCH_SIZE (50)Divida em vários lotes
batch_validation_failedUm ou mais itens em um lote falharam na validação; toda a chamada foi rejeitada antes de qualquer gravação em discoInspecione data.errors[] para os códigos por item e tente novamente os itens válidos
empty_batchupdate_blocks chamado com updates: []Pule a chamada
block_depth_exceededA profundidade da árvore excederia 32 níveis após a gravaçãoAchate a estrutura do bloco
invalid_path / invalid_destination / invalid_targetO array de caminho não contém inteiros não negativos, ou não endereça um blocoBusque novamente e use um caminho novo
invalid_refA ref não é uma forma válida de blk_XXXXXXXXBusque novamente e use uma ref retornada
ref_not_top_levelA operação requer um bloco de nível superior (ex.: replace_block_range) mas a ref aponta para um bloco aninhadoPasse a ref do ancestral de nível superior
invalid_opA operação edit_block_tree não está no enum de 9 operaçõesUse uma de update-attrs, update-html, replace-block, remove-block, wrap-in-group, unwrap-group, insert-child, duplicate, move
invalid_blockA 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_titleCampo obrigatório omitidoInclua o campo
invalid_count / invalid_range / invalid_index / invalid_limit / invalid_cursorArgumento numérico fora do intervalo ou com forma incorretaVeja message para os limites esperados
invalid_updatesO array de atualizações de update_blocks está malformadoRemodele conforme o esquema de update_blocks
invalid_post_type / invalid_status / invalid_taxonomy / invalid_term / invalid_author / invalid_parent / invalid_featured_mediaValidação do campo create_post / update_postVerifique o valor no registro relevante do WordPress
cycle_parentA atribuição de pai criaria um loop de hierarquiaEscolha um pai diferente
mixed_trash_payloadupdate_post misturou status: trash com outros camposMova para a lixeira primeiro, depois atualize separadamente
invalid_if_matchO cabeçalho está presente mas não é um inteiro positivoEnvie If-Match: <revision_id>
revision_mismatchInterno — o ID de revisão capturado não correspondeu antes do salvamentoTente novamente; se persistir, abra um issue
no_inner_blocksunwrap-group em um bloco que não possui nenhumOu remova o wrapper de outra forma ou insira os filhos primeiro
no_file / missing_fileupload_media não recebeu payload multipartEnvie um campo file, url, ou data_base64
multiple_inputs / mutually_exclusiveupload_media recebeu mais de um de file / url / data_base64Envie exatamente um
invalid_filename / disallowed_mime / file_too_large / invalid_base64 / invalid_urlPayload de upload_media rejeitadoVeja message para saber qual verificação falhou
upload_errorO manipulador de upload do WordPress retornou um erroInspecione message
empty_patterninsert_pattern recebeu um padrão sem blocos analisadosEscolha um padrão diferente
invalid_bodyO corpo JSON da requisição não pôde ser analisadoValide a forma do JSON

Limite de taxa (HTTP 429)

CódigoQuando disparaComo recuperar
rate_limit_exceededOrç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_limitedA verificação da página de configurações foi acionada com muita frequênciaAguarde; 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.

SintomaO que significaComo recuperar
Block API Error (405) com corpo HTML (ex.: nginx) em uma ferramenta de ediçãoO firewall rejeitou tanto o verbo real quanto a reprodução de substituiçãoPeç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çãoO host rejeita verbos de edição; o fallback não pôde ser concluídoO mesmo que acima; confirme com curl -X PATCH contra /wp-json/gk-block-api/v1/...

Upstream (HTTP 502)

CódigoQuando disparaComo recuperar
url_fetch_failedO 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ódigoQuando disparaComo recuperar
internal_errorExceção não capturada subiu até o envelope RESTAbra um issue com a mensagem + reprodução
wp_insert_post_failedwp_insert_post retornou um WP_ErrorInspecione message; frequentemente é um campo obrigatório ausente na camada do banco de dados
duplicate_failedA 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_failedA URL de upload_media passou pelas camadas SSRF + HTTP mas media_handle_sideload falhouInspecione message; frequentemente é cota de disco ou registro MIME
attachment_missingupload_media criou o anexo mas não conseguiu encontrá-lo para metadadosAbra um issue
trash_failed / untrash_failedwp_trash_post / wp_untrash_post retornou falseTente 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.