WordPress Block MCP

Block MCP es el MCP de WordPress diseñado para la forma en que los agentes realmente editan: un bloque a la vez, a través de múltiples turnos, sin corromper la página.

Documentación

Block MCP

Block MCP es el MCP de WordPress construido para la forma en que los agentes realmente editan: un bloque a la vez, a lo largo de múltiples turnos, sin corromper la página. Es un servidor MCP más un plugin de WordPress que expone el contenido de Gutenberg como un árbol de bloques estructurado y direccionable en lugar de HTML crudo, de modo que un agente puede cambiar un solo encabezado sin reescribir la página. Cada bloque lleva un UUID estable gk_ref que sobrevive a los desplazamientos de hermanos (ningún otro MCP de WordPress tiene esto), por lo que las cadenas de edición de múltiples turnos no necesitan volver a obtener la página entre llamadas. Cada escritura crea una revisión de WordPress para revertir cambios, las protecciones ETag/If-Match evitan sobrescrituras concurrentes, y una política de niveles del lado del servidor impide que los bloques heredados lleguen al disco. Respaldado por 326 pruebas PHP, 249 pruebas TypeScript, CI en PHP 8.2/8.3 + Node 20, y traducciones a 20 idiomas.

Por qué los agentes eligen Block MCP

  • Edita un bloque, no toda la página. Cambia el nivel de un encabezado sin tocar el HTML circundante. Los MCP estándar fuerzan una reescritura completa de la página en cada edición; Block MCP toca solo ese encabezado.
  • Ida y vuelta seguro para el editor. Los marcadores de bloque <!-- wp:* --> se conservan exactamente. Sin advertencias de "este bloque contiene contenido inesperado o no válido" al reabrir.
  • Referencias de bloque estables que ningún otro MCP de WordPress tiene. Encadena rápidamente inserciones, eliminaciones y actualizaciones entre turnos desde una sola lectura.
  • Ediciones por lotes atómicas. Corrige N bloques independientes en una revisión con update_blocks — validación de todo o nada, de modo que una referencia obsoleta o un índice fuera de rango aborta todo el lote antes de que algo llegue al disco. Mantiene el historial de revisiones limpio en lugar de 6 entradas para un solo cambio lógico.
  • Política de niveles aplicada en el servidor. Decide qué bloques quieres permitir o rechazar antes de que se guarden, con reemplazos sugeridos.
  • Concurrencia optimista integrada. Dos agentes trabajando en la misma publicación no pueden sobrescribirse silenciosamente entre sí.
  • Soporte de Yoast SEO integrado. Lee y escribe metadatos de Yoast (títulos, descripciones, palabras clave de enfoque, URL canónicas, tipos de esquema, términos principales, tarjetas Open Graph / Twitter) en el momento en que Yoast SEO está activo en el sitio.

Tabla de contenidos

De un vistazo

Aquí es donde Block MCP gana. La mayoría de los otros MCP de WordPress son envoltorios alrededor de la API REST estándar de WordPress — bien para escribir, pero mal para editar. "Cambia un encabezado, luego agrega un botón, luego corrige el siguiente párrafo" podría resultar en que tu publicación necesite una rehabilitación importante para volver a una sintaxis correcta. Block MCP es la respuesta a un MCP del editor de bloques de WordPress que simplemente funciona.

Lo que el agente puede hacerAPI REST estándar de WPBlock MCP
Editar un encabezado sin tocar el resto de la página❌ Reescribe toda la página en cada edición✅ Actualiza solo ese encabezado
Hacer 5 ediciones seguidas sin reenviar toda la página cada vez❌ Envía el cuerpo completo de la página 5 veces✅ Envía solo lo que cambió
Encontrar qué bloque contiene "Precios" sin escanear el HTML renderizado❌ Sin búsqueda estructurada — el agente tiene que usar regex sobre el HTML✅ Búsqueda integrada por texto o tipo de bloque
Evitar que los bloques heredados/obsoletos se guarden en primer lugar❌ Escribe cualquier HTML, válido o no✅ El servidor rechaza bloques heredados, sugiere reemplazos modernos
Editar una página y que aún se abra limpiamente en el editor de bloques después❌ Edita como HTML crudo — espera muchos bloques con "Este bloque contiene contenido inesperado o no válido" porque los marcadores de bloque originales se eliminaron✅ El marcado de bloques se conserva exactamente.
Seguir editando el bloque correcto después de agregar o eliminar otros bloques encima❌ Relee toda la página después de cada edición✅ La IA puede seguir trabajando sin releer
Corregir N errores tipográficos en una página en una sola revisión❌ N idas y vueltas, N revisiones saturando el historial✅ Una llamada a update_blocks, una revisión, atómica — una falla parcial revierte todo el lote

Cuando realmente le pides a una IA que edite una página

Lo que importa es si la página es correcta después de que el agente termina. Así que pusimos a Claude frente a cada MCP, escribimos una instrucción real — "cambia el encabezado H2 'Ejemplos de código' a H3" — y luego reabrimos la página y la inspeccionamos.

27 ejecuciones en total: tres servidores MCP × Haiku, Sonnet, Opus × 3 intentos cada uno.

ModeloBlock MCPAI Engine ProInstaWP/mcp-wp
Haiku✅ 3 / 3 · 10 s promedio⚠️ 2 / 3 · 44 s promedio❌ 0 / 3 · 20 s promedio
Sonnet✅ 3 / 3 · 9 s promedio✅ 3 / 3 · 14 s promedio❌ 0 / 3 · 36 s promedio
Opus✅ 3 / 3 · 9 s promedio✅ 3 / 3 · 13 s promedio⚠️ 2 / 3 · 38 s promedio
Total✅ 9 / 98 / 92 / 9

Tres conclusiones:

Block MCP funciona en el modelo más barato — y termina más rápido. Haiku pasa todas las pruebas en 10 segundos. El agente no necesita pensar mucho sobre la página porque la API tiene exactamente la forma de la tarea. AI Engine Pro en Haiku tarda 44 segundos cuando funciona; InstaWP nunca lo logra.

El envoltorio wp/v2 de InstaWP falla 7 de 9 veces — incluso Opus solo lo logra 2/3. Cuando el agente informa éxito, técnicamente es correcto que el texto del encabezado cambió. Pero la ida y vuelta de toda la página a través de update_page elimina todos los marcadores de bloque <!-- wp:* -->. Reabre la página en el editor de bloques y verás advertencias de "Este bloque contiene contenido inesperado o no válido" en la mayoría de los bloques. La API REST estándar no está rota — hace exactamente lo que está documentado — pero su forma de datos permite que la IA corrompa el contenido sin darse cuenta.

AI Engine Pro es competitivo con Sonnet y Opus pero tropieza con Haiku. Su herramienta wp_alter_post es consciente de los bloques (el marcado de la publicación sigue siendo válido), pero en las pruebas fallidas con Haiku el HTML renderizado y los atributos declarados del bloque se desincronizan — por ejemplo, el marcador de comentario aún dice level: 2 mientras que la etiqueta interna es <h3>. El editor de bloques también lo marca como roto. Sonnet y Opus reintentan hasta que son consistentes (2–3 llamadas de herramienta); Haiku a veces se rinde después de declarar éxito.

Reproduce con scripts/mcp-agent-bench.mjs.

Ahora prueba las operaciones estructurales que los agentes realmente necesitan

Un cambio de nivel de encabezado es el caso fácil. El trabajo interesante es cuando un agente tiene que mover un bloque, colocar un párrafo dentro de un contenedor existente, modificar una tabla o eliminar un bloque — el tipo de edición estructural de múltiples pasos que los flujos de trabajo de contenido reales exigen.

Cinco escenarios más difíciles. Misma matriz: tres MCP × Claude Haiku.

EscenarioBlock MCPAI Engine ProInstaWP/mcp-wp
Mover un bloque a una nueva posición hermano✅ 15 s · 2 llamadas✅ 25 s · 3 llamadas❌ fallo estructural · 29 s
Insertar un párrafo dentro de un core/group✅ 15 s · 2 llamadas✅ 20 s · 4 llamadas❌ fallo estructural · 32 s
Agregar una fila a una tabla comparativa✅ 13 s · 2 llamadas✅ 25 s · 4 llamadas❌ fallo estructural · 32 s
Eliminar una columna de una tabla✅ 12 s · 2 llamadas✅ 24 s · 4 llamadas❌ fallo estructural · 26 s
Eliminar un bloque de encabezado✅ 12 s · 3 llamadas✅ 16 s · 3 llamadas❌ fallo estructural · 24 s
Total✅ 5 / 5✅ 5 / 5❌ 0 / 5

Block MCP promedia 13 segundos y dos llamadas de herramienta por escenario. El agente lee la página una vez, encuentra el bloque objetivo por referencia o ruta, llama a una mutación, listo.

AI Engine Pro mantiene la página intacta y termina correctamente, aproximadamente 2 veces más lento. Su herramienta wp_alter_post pide al agente que proporcione tanto el marcado del comentario del bloque como el HTML renderizado, por lo que la mayoría de los escenarios gastan una ida y vuelta adicional generando la forma correcta.

InstaWP/mcp-wp falla en todos los escenarios con un "fallo estructural": el agente (Haiku, dado update_page) escribe la página de vuelta como HTML plano — <h1>...</h1><p>...</p><ol>... — sin marcadores de bloque <!-- wp:* -->. WordPress acepta el guardado, parse_blocks() colapsa toda la página en un solo fragmento de formato libre, y cada bloque distintivo de la página desaparece como entidad estructurada. El agente cree que tuvo éxito; la página está rota en el editor de bloques al reabrir. Ese es el precio de envolver la superficie REST wp/v2 estándar y confiar en que el agente reconstruya el marcado de bloques a mano.

Reproduce con scripts/mcp-agent-bench.mjs.

Por qué Block MCP

Block MCP es el único MCP de WordPress diseñado desde cero para la forma en que los agentes realmente editan páginas: un bloque a la vez, a lo largo de múltiples turnos, sin corromper nada en el camino. El banco de pruebas del bucle de agente lo refleja — 9 de 9 en todos los niveles de Claude, incluido el más barato.

La mayoría de los MCP de WordPress envuelven la API REST predeterminada. Eso le da al agente CRUD a nivel de publicación, pero se detiene ahí — para cambiar un encabezado en una página, el agente tiene que leer todo el HTML post_content, analizarlo, encontrar la etiqueta correcta, mutarla y escribir todo de vuelta. Los límites de los bloques se disuelven, la estructura se rompe sutilmente y no hay ruta de deshacer.

Block MCP está construido alrededor del propio árbol de bloques. El agente ve una vista estructurada, direccionable y bien tipada de la página — y escribe a través de endpoints diseñados específicamente que saben qué son los bloques.

Lo que eso te da en la práctica:

  • Edición consciente de bloques. Cambia el nivel de un encabezado, sustituye la URL de un botón o reordena columnas sin tocar el HTML circundante. El agente trabaja en JSON; el plugin se encarga del análisis y la serialización.
  • Referencias de bloque estables. Cada bloque lleva un ID persistente. Un agente puede obtener una página una vez, capturar las referencias de cada bloque que pretende editar y luego encadenar inserciones/eliminaciones/actualizaciones contra esas referencias sin volver a leer. Los desplazamientos entre hermanos no invalidan las direcciones.
  • Operaciones estructurales basadas en rutas. Nueve operaciones (update-attrs, replace-block, wrap-in-group, unwrap-group, move, duplicate, insert-child, remove-block, update-html) funcionan a cualquier profundidad de anidamiento mediante rutas enteras o referencias.
  • Transformaciones automáticas. Cambia el atributo level de un encabezado y la etiqueta <h2>/<h3> se actualiza con él. Convierte una lista en ordenada y <ul> se convierte en <ol>. El plugin mantiene sincronizados los atributos y el innerHTML para los patrones comunes, de modo que los agentes no tengan que hacerlo.
  • Aplicación de políticas del sitio. Los niveles de preferencia por sitio rechazan la inserción de bloques que hayas marcado como heredados y sugieren reemplazos. Un agente no puede escribir bloques que tu sitio no quiere.
  • Deshacer respaldado por revisiones. Cada escritura devuelve before_revision_id y revision_id. revert_to_revision revierte a cualquiera de los dos lados de cualquier edición.
  • Herramientas de descubrimiento. Explora los tipos de bloque registrados con puntuación de preferencia, busca patrones, consulta el uso de bloques/patrones en todo el sitio y resuelve URLs a IDs de entrada. El agente puede planificar con conocimiento de lo que tu sitio contiene realmente.
  • Salvaguardas para bloques estáticos. Advierte cuando un cambio de atributo dejaría el marcado renderizado obsoleto, para que el agente sepa cuándo debe pasar también el innerHTML.

La combinación — consciente de bloques, con referencias estables, con seguimiento de revisiones y aplicación de políticas — es lo que los MCP existentes que envuelven la REST API no te ofrecen.

Comparación con otros MCP de WordPress

El espacio de MCP de WordPress es pequeño, y Block MCP es el único que opera en la capa del árbol de bloques. Los otros proyectos trabajan en capas distintas y apuntan a flujos de trabajo diferentes — a menudo son complementarios en lugar de competir frontalmente, pero el banco de pruebas del agente anterior muestra que no todos producen resultados correctos cuando se les pide editar un bloque.

InstaWP/mcp-wp — Un MCP que envuelve la REST API y opera sobre entradas completas, además de una amplia cobertura de usuarios, comentarios, medios, plugins y búsqueda en el repositorio de plugins. Característica destacada: gestión multi-sitio desde una sola instancia MCP. Recurre a él cuando necesitas CRUD a nivel de entrada en muchos sitios o administración general de WordPress. No es consciente de bloques: editar un solo encabezado dentro de una página larga significa leer y reescribir toda la entrada, y el viaje de ida y vuelta a través de wp/v2 de update_page elimina todos los marcadores de bloque <!-- wp:* -->. En nuestro banco de pruebas falló la validación en 7 de 9 ensayos con Haiku/Sonnet/Opus.

AI Engine Pro — Servidor MCP autoalojado dentro de WordPress (HTTP Streamable en /wp-json/mcp/v1/http), creado por Meow Apps y el plugin de IA para WordPress más instalado (más de 100K). El nivel gratuito expone entradas/comentarios/usuarios/medios como herramientas MCP; Pro añade una barra lateral de Editor Assistant y tuberías MCP adicionales. Su herramienta wp_alter_post sí es consciente de bloques — los marcadores de comentario de bloque sobreviven — pero puede desincronizar los atributos declarados del bloque de su innerHTML (por ejemplo, el marcador de comentario sigue diciendo level: 2 mientras que la etiqueta interna es <h3>), y el editor de bloques también lo marca como roto. Sonnet y Opus reintentan hasta que es consistente y pasan; Haiku a veces se rinde a las 7–12 llamadas de herramienta. 8 de 9 en el banco de pruebas.

Block MCP (este proyecto) — Opera una capa por debajo: dentro del árbol de bloques de una sola entrada. Direccionamiento basado en rutas y referencias, transformaciones automáticas que mantienen los atributos y el innerHTML sincronizados en el servidor, aplicación de niveles de preferencia, revisiones por bloque. Nada de eso existe en los otros tres. Recurre a él cuando un agente necesita editar bloques — cambiar el nivel de un encabezado, intercambiar un diseño de columnas, insertar un CTA después del tercer párrafo — sin reescribir el contenido circundante. 9 de 9 en el banco de pruebas, perfecto en los tres modelos Claude, incluido el más barato.

Estos pueden coexistir. Block MCP podría (y probablemente será) exponerse a través del adaptador oficial como capacidades registradas una vez que esa vía madure — la misma lógica, con tuberías bendecidas. Consulta issues para la hoja de ruta.

Características

Lectura

  • Árbol de bloques completo como JSON estructurado: rutas, nombres, atributos, referencias, text_preview del contenido de cada bloque
  • Resumen de la página en una sola llamada: recuentos por tipo de bloque, encabezados con rutas, marcadores de sección, profundidad máxima de anidamiento
  • Modo esquema para inspección rápida de la estructura de la página
  • Busca bloques por texto o nombre de bloque
  • El modo renderizado expande shortcodes, resuelve patrones sincronizados y marca bloques dinámicos

Escritura — por índice, por referencia o por ruta

  • update_block — índice plano O referencia
  • update_blocks — lote atómico de N actualizaciones en UNA revisión; validación de todo o nada, máx. 50 elementos, cuenta como una escritura contra el límite de tasa
  • delete_block — contador de nivel superior O referencia
  • insert_blocks — ancla en after_top_level/before_top_level O after_ref/before_ref
  • edit_block_tree — 9 operaciones estructurales basadas en rutas o referencias:
    • update-attrs, update-html, replace-block, remove-block
    • wrap-in-group, unwrap-group, insert-child, duplicate, move
  • rewrite_post_blocks — reescritura completa de la página
  • Parámetro dry_run para validar cualquier mutación sin escribir

Seguridad

  • La transformación automática mantiene el innerHTML sincronizado cuando cambian los atributos (nivel de encabezado, lista ordenada, tagName de grupo, URL de botón, src de imagen, altura de espaciador, etc.)
  • Las protecciones de bloques estáticos advierten cuando un cambio de atributo puede dejar el marcado renderizado obsoleto
  • Niveles de preferencia configurables: los bloques heredados se rechazan al insertar, los bloques de nivel de evasión devuelven advertencias con reemplazos sugeridos
  • Límite de tasa por entrada (10 escrituras/min, 2 reescrituras completas/min)
  • Cada escritura crea una revisión de WordPress; revert_to_revision deshace cualquier edición

Descubrimiento

  • Lista los tipos de bloque filtrados por espacio de nombres, categoría o nivel de preferencia
  • Explora patrones (sincronizados + registrados) puntuados por actualidad, recuento de referencias y contenido heredado
  • Analíticas de uso de bloques/patrones en todo el sitio (en caché)
  • Resuelve cualquier URL o slug a su ID de entrada, tipo y enlace de edición

Cómo funciona

AI Agent  ←stdio→  MCP server (your machine)  ←HTTPS→  WordPress plugin (your site)

Plugin de WordPress (wordpress-plugin/gk-block-mcp/) — REST API en gk-block-api/v1. Gestiona el análisis de bloques, la serialización, las comprobaciones de seguridad, la puntuación de preferencias, el límite de tasa y las revisiones. Funciona con cualquier tipo de entrada que almacene bloques de Gutenberg en post_content.

Servidor MCP (src/) — Servidor stdio en TypeScript que expone la REST API como herramientas MCP. Se autentica como un usuario normal de WordPress mediante Application Password. Sin privilegios especiales, sin acceso directo a la base de datos desde el lado MCP.

Inicio rápido

1. Instala el plugin de WordPress

Lo más fácil — descarga el ZIP más reciente: gk-block-mcp.zip (compilado automáticamente desde main en cada push).

Luego en WordPress: Plugins → Añadir nuevo → Subir plugin y elige el ZIP.

O copia wordpress-plugin/gk-block-mcp/ a wp-content/plugins/ de tu sitio y actívalo manualmente. O mediante WP-CLI:

wp plugin install https://github.com/GravityKit/block-mcp/releases/download/latest/gk-block-mcp.zip --activate

2. Conecta tu asistente de IA

La vía más rápida lo aprovisiona todo por ti — una cuenta de servicio block-mcp dedicada, un rol de capacidades mínimas y una Application Password — desde dentro de WordPress. Ve a Ajustes → Block MCP → Conectar y elige tu cliente.

Claude Desktop (un clic). Descarga el archivo .mcpb generado y ábrelo; Claude Desktop instala el servidor y guarda la credencial en tu llavero del sistema operativo. El .mcpb es autocontenido: incluye el servidor, así que no hay nada más que instalar.

Cursor, Claude Code, ChatGPT Desktop (aprobación en navegador). Ejecuta el conector y haz clic en Aprobar en el navegador que se abre:

npx -y @gravitykit/block-mcp connect --site https://example.com

Escribe la configuración MCP de tu cliente por ti (solo propietario, modo 0600), de modo que la contraseña del sitio nunca acabe en tu historial de shell ni en un archivo editado a mano. Añade --client cursor|claude-code|claude-desktop|print para apuntar a un cliente específico. Cada sitio que conectas recibe su propia entrada de servidor, de modo que un asistente puede apuntar a varios sitios.

Tiempo de ejecución: la vía común ejecuta el servidor con npx -y @gravitykit/block-mcp — no hay nada que clonar ni compilar. El .mcpb de Claude Desktop incorpora el mismo paquete.

3. Configuración manual (avanzada)

¿Prefieres hacer la conexión a mano? Crea una Application Password y registra el servidor tú mismo.

En el administrador de WordPress: Usuarios → Perfil → Application Passwords. O mediante CLI:

wp user application-password create <username> "Block MCP" --porcelain

Los endpoints de lectura requieren la capacidad edit_posts; los endpoints de escritura requieren edit_post en la entrada concreta que se modifica. Luego compila y registra el servidor:

git clone https://github.com/GravityKit/block-mcp
cd block-mcp
npm install   # auto-builds dist/index.cjs via the prepare script

Registra el servidor en tu cliente MCP. Ejemplo para el ~/.claude.json de 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"
      }
    }
  }
}

Reinicia tu cliente MCP. Ejecuta npm run inspect para probar las herramientas de forma interactiva.

4. (Opcional) Ajusta la configuración

Cuando el plugin está activo, aparece una página de administración en Ajustes → Block MCP. Los valores predeterminados funcionan de serie, pero merece la pena echarle un vistazo — aquí es donde decides qué bloques pueden escribir los agentes de IA, qué sugerir como reemplazos y a qué tipos de entrada puede apuntar create_post.

Namespace tier scores

Consulta la sección Configuración más abajo para el desglose completo.

Herramientas MCP

E/S de contenido

HerramientaPropósito
get_page_blocksLee los bloques de una entrada. Admite outline, summary_only, search, block_name, render, fields, persist_refs
update_blockActualiza los atributos/innerHTML de un bloque (por flat_index o ref)
update_blocksAplica N actualizaciones independientes de forma atómica en UNA revisión (máx. 50). Validación de todo o nada: cualquier referencia obsoleta / índice fuera de rango / rechazo de almacenamiento dual / destino duplicado aborta el lote con errores detallados antes de que nada llegue al disco
insert_blocksInserta bloques en una posición (por contador o referencia)
delete_blockElimina bloque(s) (por contador o referencia)
replace_block_rangeIntercambio atómico de N bloques por M bloques en una sola revisión
rewrite_post_blocksReescritura completa de la página
edit_block_tree9 operaciones estructurales basadas en rutas o referencias
insert_patternInserta un patrón, sincronizado o en línea
create_patternCrea un patrón sincronizado a partir de bloques estructurados o contenido bruto, con control del estado de sincronización
revert_to_revisionRevierte a un ID de revisión anterior

Entradas y taxonomías

HerramientaPropósito
create_postCrea una entrada o página (borrador, publicada, futura) — acepta bloques o HTML
update_postActualiza metadatos de entrada, estado y términos — cubre transiciones de publicar/eliminar/restaurar
list_termsLista términos de taxonomía (categorías, etiquetas, personalizadas) para la búsqueda de IDs
find_posts / post_info / resolve_urlLocaliza entradas por búsqueda, ID, slug o URL

Medios

HerramientaPropósito
upload_mediaSube mediante ruta local, sideload por URL (con protección SSRF) o base64. Devuelve el ID de adjunto + URL

Descubrimiento

HerramientaPropósito
list_block_typesExplora los tipos de bloque registrados con niveles de preferencia, variaciones de estilo y restricciones de anidamiento (parent/ancestor/allowed_blocks). Pasa include_supports:true para el objeto supports completo de cada bloque (opt-in, por defecto false)
list_patterns / get_patternBusca e inspecciona patrones con puntuación; filtra por category y explora el vocabulario de categorías registrado
get_site_usageAnalíticas de uso de bloques/patrones
list_binding_sourcesFuentes de enlaces de bloque registradas (p. ej. core/post-meta, core/pattern-overrides) a las que puede hacer referencia el metadata.bindings de un bloque

SEO (cuando Yoast SEO está activo)

HerramientaPropósito
yoast_get_seoLeer metadatos SEO: título, descripción, robots, OG, Twitter, schema, puntuaciones
yoast_update_seo / yoast_bulk_update_seoActualizar campos SEO en una o varias entradas

Plantillas (solo temas de bloques)

HerramientaPropósito
list_templatesExplorar las plantillas y partes de plantilla de un tema de bloques (filtrar por tipo, área, post_type, slug, fuente)
get_templateMetadatos, contenido sin procesar y bloques analizados de una sola plantilla
update_templateReemplazar el contenido completo de una plantilla/parte, controlado por un ajuste del sitio (desactivado por defecto)
reset_templateEliminar la anulación de base de datos de una plantilla, revirtiéndola al archivo del tema

Plantillas

list_templates / get_template son herramientas de solo lectura para explorar las plantillas de un tema de bloques (diseños de página como single, archive) y partes de plantilla (regiones reutilizables como header, footer), el mismo contenido que muestra la lista de plantillas del Editor del sitio.

El wp_id de cada fila te indica si una anulación de base de datos está ocultando actualmente el archivo del tema: null significa que el id se resuelve al propio archivo del tema; un número significa que existe una personalización y ese ID de entrada es la anulación. En un tema clásico (no de bloques), list_templates devuelve una lista vacía con un note que explica el motivo, en lugar de un error.

Las plantillas solo se abordan por índice. El campo blocks de get_template tiene el formato get_page_blocks. Si las herramientas de escritura por bloque (update_block, edit_block_tree por ref) se aplican depende del wp_id: una plantilla que aún se resuelve al archivo del tema (wp_id: null) no es escribible por ellas, mientras que una plantilla con anulación de base de datos (un wp_id numérico) es una entrada ordinaria que editan como cualquier otra. Usa update_template (ver Edición de plantillas abajo) para materializar la anulación de una plantilla que solo existe en el archivo del tema.

Edición de plantillas

update_template / reset_template escriben en plantillas. Ambas están desactivadas por defecto. Activa primero "Permitir al asistente editar plantillas y partes de plantilla del tema" en Ajustes → Block MCP, o cada llamada devolverá un 403 con un mensaje accionable. Activar el interruptor otorga a la cuenta del agente de Block MCP una capacidad gk_block_mcp_edit_templates dedicada (nada más de lo que puede hacer cambia); la conexión "self" de un humano también puede editar plantillas, ya que ya lleva edit_theme_options.

  • update_template reemplaza el contenido completo de una plantilla: reemplazo de plantilla completa, como rewrite_post_blocks, no una edición por bloque. Proporciona exactamente uno de content (marcado sin procesar) o blocks (estructurado; validado contra el registro de bloques y los niveles de preferencia, igual que cualquier otra escritura de bloques estructurados). Si el id se resuelve actualmente al archivo del tema, se crea automáticamente una anulación de base de datos (override_created: true); el archivo del tema nunca se toca. Escribir de nuevo reutiliza la misma anulación.
  • reset_template elimina la anulación, revirtiendo el id al archivo del tema. Apariencia → Editor → Restablecer hace lo mismo desde el administrador de WordPress.

Una vez que existe una anulación, su wp_id es un ID de entrada normal: update_block, get_page_blocks y el resto de la superficie de herramientas por bloque funcionan con ella como con cualquier otra entrada.

Referencias estables

Cada bloque en una respuesta de get_page_blocks incluye un campo ref:

{
  "index": 5,
  "path": [0, 2, 1],
  "ref": "blk_a3f2c1q9",
  "name": "core/heading",
  "attributes": { "level": 2, "content": "Hello" }
}

Las referencias se almacenan en attrs.metadata.gk_ref dentro de post_content, por lo que sobreviven entre sesiones y entre mutaciones que desplazan posiciones de hermanos. Pasa ref a update_block, delete_block o edit_block_tree para abordar el mismo bloque de forma fiable incluso después de inserciones o eliminaciones en otra parte de la página.

La primera lectura de una entrada asigna y persiste perezosamente las referencias mediante una escritura directa en la base de datos que omite la creación de revisiones (las referencias son metadatos solo de editor, no contenido). Pasa persist_refs: false para leer sin ese efecto secundario.

Configuración

Todo en esta sección es editable en Ajustes → Block MCP en el administrador de WordPress. Los valores predeterminados son sensatos: nada de esto es necesario para empezar.

Puntuaciones de nivel por espacio de nombres

Las preferencias de bloques se almacenan como una opción de WordPress (gk_block_api_preferences) y son configurables por sitio. Cada espacio de nombres de bloque recibe una puntuación de 0 a 100, que se asigna a un nivel:

NivelPuntuaciónPolítica
preferido≥ 80Usar libremente
aceptable50–79Usar si el preferido no está disponible
evitar10–49Advertir, devolver reemplazo sugerido
legacy< 10Rechazar al insertar

Los valores predeterminados incluyen core/* como preferido y un conjunto inicial de espacios de nombres conocidos como obsoletos marcados como legacy. Añade nuevos espacios de nombres escribiendo en la fila inferior: aparece una nueva fila en blanco en cuanto empiezas a escribir.

Mapa de reemplazo

Cuando un agente intenta insertar un bloque legacy, el error de rechazo incluye un reemplazo sugerido de este mapa. Ambas columnas son menús desplegables con búsqueda de todos los bloques actualmente registrados en tu sitio (también puedes escribir un nombre de bloque que no esté registrado actualmente).

Replacement map

Bloques que almacenan datos en dos lugares

Algunos bloques (notablemente yoast/faq-block) mantienen los mismos datos en ambos: sus atributos y su innerHTML. Actualizar uno sin el otro corrompe el bloque silenciosamente. Block MCP detecta la mayoría automáticamente escaneando tu sitio; enumera aquí cualquier extra para que la API obligue a los agentes a enviar ambos campos juntos.

Dual-storage blocks

Tipos de entrada que los agentes de IA pueden crear

Restringe create_post a tipos de entrada específicos. Deja todo sin marcar para permitir cualquier tipo de entrada público con soporte REST (el valor predeterminado).

Post types allow-list

Escaneo de modo de almacenamiento + restablecimiento

El escaneo recorre cada entrada publicada y clasifica cada bloque distinto como estático / dinámico / dual, reemplazando los valores predeterminados del filtro con datos en vivo de tu sitio. Lento en sitios grandes; el resultado se almacena en caché. El botón Restablecer debajo limpia todas las opciones que posee este plugin y restaura los valores predeterminados codificados.

Storage scan and reset

Seguridad

Block MCP le da a un asistente de IA exactamente el acceso que necesita para editar contenido, y nada más.

  • Una cuenta separada y limitada. Conectarse crea una cuenta dedicada solo para el asistente. Puede escribir y editar tus entradas, páginas y medios, pero no puede cambiar los ajustes del sitio, eliminar el contenido de otras personas ni iniciar sesión en tu panel; y desconectarla elimina todo ese acceso de una vez. (Puedes conectarte a través de tu propia cuenta en su lugar; está claramente marcada como la opción de mayor acceso, y el propietario del sitio puede desactivar esa opción por completo.)
  • Tu contraseña permanece privada. Nunca se muestra en una dirección web ni se guarda en el historial de tu navegador, y la conexión se configura localmente en tu propio ordenador. Cualquier archivo de configuración escrito solo es legible por ti.
  • Los secretos almacenados están cifrados. Cualquier credencial retenida entre pasos de configuración se cifra (AES‑256‑GCM) antes de guardarse y se borra una vez utilizada; nunca se mantiene como texto plano.
  • El asistente no puede inyectar código. Todo lo que escribe se sanitiza, por lo que no puede colar scripts o rastreadores en tus páginas.

Modo sellado (Claude Desktop)

El instalador de un clic de Claude Desktop puede incluir tu credencial u omitirla:

ModoQué ocurre
prefill (predeterminado)El instalador incluye la contraseña, por lo que la configuración es de un clic; Claude Desktop la guarda en el llavero de tu sistema operativo.
pasteEl instalador omite la contraseña: la pegas tú mismo, por lo que nunca termina en un archivo descargado.

Los desarrolladores pueden forzar el modo pegado con un filtro, o definiendo GK_BLOCK_MCP_FORCE_PASTE_SECRET como true en wp-config.php:

add_filter( 'gk/block-mcp/credential/seal-mode', fn() => 'paste' );

Ejemplos

Actualizar un encabezado por URL

"Cambia el H2 'Welcome' en /about/ a 'About Us'."

  1. resolve_url({ url: "/about/" }) → ID de entrada
  2. get_page_blocks({ post_id, outline: true }) → encuentra el encabezado en path: [4], ref blk_a3f2c1q9
  3. edit_block_tree({ post_id, op: "update-attrs", ref: "blk_a3f2c1q9", attributes: { content: "About Us" } })

La auto-transformación actualiza tanto el atributo content como el texto interno <h2>. Se crea una revisión.

Flujo de trabajo de edición encadenada (donde brillan las referencias)

"En la página de inicio: elimina el tercer párrafo, cambia el siguiente H2 a H3 y añade un botón CTA después."

  1. get_page_blocks({ post_id }) una vez: captura las referencias de los tres bloques objetivo
  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", … }] })

Con el direccionamiento basado en rutas, el agente necesitaría volver a obtener datos entre cada paso. Con las referencias, una sola lectura cubre toda la cadena.

Redactar y publicar un documento

  1. list_terms({ taxonomy: "category", search: "Documentation" }) → ID de categoría
  2. create_post({ title: "Getting Started", status: "draft", categories: [<id>], blocks: [...] }) → ID de entrada
  3. upload_media({ path: "/tmp/screenshot.png", alt_text: "...", post_id }) → ID de adjunto + 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" })

Pruebas

Ejecuta todos los conjuntos de pruebas 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

El conjunto de pruebas PHP utiliza una capa stub mínima de WordPress (no se requiere una instalación completa de WP) para ejercitar la validación, las rutas de error, el motor de mutaciones, la resolución de referencias, las auto-transformaciones HTML, el ciclo de vida de las entradas, el listado de términos, la validación de medios y el resumen/esquema REST.

Se incluye un script de prueba de humo de extremo a extremo en scripts/ para la validación con WordPress en vivo; apúntalo a cualquier sitio de WordPress configurando WORDPRESS_URL, WORDPRESS_USER y WORDPRESS_APP_PASSWORD.

Requisitos

  • Node.js ≥ 20
  • WordPress ≥ 6.0 con contraseñas de aplicación habilitadas
  • PHP ≥ 7.4
  • HTTPS (requerido por WordPress para la autenticación con contraseña de aplicación)

Limitaciones

Alcance

  • Las ediciones funcionan en entradas almacenadas como bloques. Las plantillas de temas de bloques (wp_template, wp_template_part) y las áreas de widgets aún no son compatibles.
  • Los tipos de entrada personalizados deben declarar show_in_rest: true (o estar en la lista de permitidos configurada) para poder escribirse.
  • innerHTML pasa por wp_kses_post en cada escritura: <script>, los manejadores de eventos en línea y otro marcado no permitido se eliminan. Añade a la lista blanca etiquetas adicionales con el filtro wp_kses_allowed_html si es necesario.

Política de niveles

  • Los bloques de nivel legacy (puntuación < 10) son rechazados de forma estricta al insertar, replace-block, insert-child, wrap-in-group y replace_all_blocks. El error incluye un reemplazo sugerido cuando hay uno mapeado.
  • Los bloques de nivel evitar (puntuación 10–49) se escriben con advertencias, no errores.
  • La política de niveles es solo de inserción: update-attrs y update-html pueden mutar un bloque legacy que ya está en la página (para que las páginas existentes no se rompan).

Límites estructurales

  • La profundidad de anidamiento de bloques está limitada a 32 niveles (MAX_BLOCK_DEPTH). Los árboles más profundos se rechazan con block_depth_exceeded. No se puede filtrar.
  • Las escrituras por lotes (update_blocks) tienen un límite de 50 elementos por llamada (MAX_BATCH_SIZE). Un lote cuenta como una escritura contra el límite de velocidad independientemente de N.

Límites de velocidad

  • Por entrada, por minuto, respaldado por transitorios. 10 escrituras/min para update_*/delete_*/insert_*/mutate_*/update_post; 2/min para la reescritura completa PUT /blocks.
  • Los depósitos son por entrada, no por usuario: varios agentes que editan la misma entrada comparten el presupuesto.
  • Devuelve HTTP 429 rate_limit_exceeded; se restablece naturalmente después de 60 s.

innerHTML de bloques estáticos

  • WordPress no tiene un equivalente en PHP de la función React save, por lo que el servidor no puede regenerar el marcado renderizado de un bloque estático solo a partir de sus atributos. Las auto-transformaciones cubren el nivel de encabezado, lista ordenada, grupo tagName, URL de botón, imagen src/alt, booleanos de video/audio, alto/ancho de espaciador, detalles open y cita. Para cualquier otra cosa, envía innerHTML junto con attributes (update_block rechazará las escrituras de almacenamiento dual que omitan cualquiera de los dos lados).

Bloques de almacenamiento dual

  • Un pequeño conjunto de bloques (notablemente yoast/faq-block) duplica el estado entre attributes y innerHTML. La API requiere ambos campos juntos al actualizar (error dual_storage_requires_both en caso contrario) y la lista de almacenamiento dual es configurable en Ajustes → Block MCP.

API de Block Bindings

  • Requiere WordPress 6.5+ en el sitio de destino.
  • Los atributos listados en attrs.metadata.bindings están bloqueados para escritura de forma predeterminada: una escritura que apunte a un atributo enlazado devuelve 400 bound_attribute. Pasa allow_bound_writes: true en la actualización para anularlo.
  • Las lecturas exponen el mapa de enlaces como un campo bindings de nivel superior y un array bound_attributes; la resolución del enlace (renderizar el valor dinámico) ocurre solo en modo render.

Extracción de atributos con conocimiento del esquema

  • Las lecturas combinan atributos obtenidos mediante block.json (source: attribute | html | rich-text | text) en la respuesta.
  • source: 'query' aún no es compatible: devuelve solo los atributos delimitadores con un TODO. source: 'meta' está obsoleto y se ignora.

Patrones

  • Los patrones registrados siempre se incrustan al insertar. Solo los patrones sincronizados (entradas CPT wp_block) se pueden insertar como referencia core/block.

Subida de medios

  • La carga lateral por URL está limitada a 25 MB y usa un tiempo de espera de 10 s.
  • La protección SSRF rechaza hosts RFC1918 / loopback / link-local / metadatos de nube (169.254.0.0/16) antes de la descarga. La lista de bloqueo se puede ampliar mediante el filtro gk_block_api_url_sideload_blocked_ranges.
  • Las subidas se pueden deshabilitar en todo el sitio con el interruptor de emergencia en Ajustes → Block MCP.

Modo de renderizado

  • ?render=true resuelve bloques dinámicos, expande shortcodes y sigue referencias de patrones sincronizados. Deshabilitado por defecto: las rutas de lectura devuelven el marcado de bloque sin procesar para que un agente vea lo que ve el editor.

Códigos de error

Cada endpoint REST devuelve errores como JSON en la forma estándar de WordPress { code, message, data: { status, … } }. El servidor MCP reenvía el estado HTTP y el código al resultado de la herramienta para que el agente pueda despachar directamente sobre code.

Autenticación y permisos (HTTP 403)

CódigoCuándo se produceCómo recuperarse
rest_forbiddenEl llamador carece de la capacidad edit_posts en la solicitudUsa una contraseña de aplicación para un usuario con edit_posts
rest_cannot_editEl llamador carece de edit_post para el post específicoReasigna el post o eleva la capacidad del usuario
rest_cannot_createEl llamador carece de edit_posts (o la capacidad de creación específica del tipo de post) para create_postIgual
rest_cannot_publishcreate_post / update_post solicitó publish pero el llamador carece de publish_postsBaja el estado a draft/pending, o eleva el usuario
rest_cannot_uploadupload_media llamado sin capacidad upload_filesEleva el usuario
rest_cannot_assign_authorcreate_post / update_post estableció author a otro usuario sin edit_others_postsElimina el campo author o eleva
uploads_disabledEl administrador del sitio desactivó el interruptor de emergencia de subidas en Ajustes → Block MCPVuelve a habilitarlo en el administrador o deja de llamar a upload_media

No encontrado (HTTP 404)

CódigoCuándo se produceCómo recuperarse
post_not_foundpost_id no resuelve a un postVuelve a ejecutar resolve_url o find_posts
block_not_foundflat_index / path / ref no aborda un bloque existenteVuelve a obtener get_page_blocks
ref_stalegk_ref ya no existe en el post (eliminado o reemplazado)Vuelve a obtener y a enlazar
pattern_not_foundpattern_id no coincide con un patrón sincronizado o registradoUsa list_patterns
revision_not_foundrevert_to_revision recibió un ID que no es una revisión del post objetivoUsa el historial de update_post o consulta las revisiones del post
not_foundRecurso no encontrado genérico para endpoints que no tienen un código específicoInspecciona message para saber qué recurso

Precondición / concurrencia (HTTP 412)

CódigoCuándo se produceCómo recuperarse
stale_revisionEl encabezado If-Match / el campo del cuerpo if_match no coincidió con el ID de revisión actual (otra persona editó el post)Vuelve a obtener, reaplica los cambios contra el estado fresco y reintenta

Validación (HTTP 400)

CódigoCuándo se produceCómo recuperarse
legacy_blockInsertar un bloque en el nivel heredadoUsa el reemplazo sugerido devuelto en data.suggested_replacement
dual_storage_requires_bothActualizar un bloque de doble almacenamiento solo con attributes o solo con innerHTMLEnvía ambos campos juntos
bound_attributeLa actualización apunta a un atributo listado en attrs.metadata.bindingsResuelve el enlace en origen, o pasa allow_bound_writes: true
batch_too_largeEl payload de update_blocks supera MAX_BATCH_SIZE (50)Divide en varios lotes
batch_validation_failedUno o más elementos de un lote fallaron la validación; toda la llamada fue rechazada antes de cualquier escritura en discoInspecciona data.errors[] para los códigos por elemento y reintenta los elementos válidos
empty_batchupdate_blocks llamado con updates: []Omite la llamada
block_depth_exceededLa profundidad del árbol excedería 32 niveles después de la escrituraAplana la estructura de bloques
invalid_path / invalid_destination / invalid_targetEl array de ruta no es de enteros no negativos, o no aborda un bloqueVuelve a obtener y usa una ruta fresca
invalid_refLa referencia no es una forma válida de blk_XXXXXXXXVuelve a obtener y usa una referencia devuelta
ref_not_top_levelLa operación requiere un bloque de nivel superior (p. ej., replace_block_range) pero la referencia apunta a un bloque anidadoPasa la referencia del ancestro de nivel superior
invalid_opOperación edit_block_tree no está en el enum de 9 operacionesUsa uno de update-attrs, update-html, replace-block, remove-block, wrap-in-group, unwrap-group, insert-child, duplicate, move
invalid_blockLa definición del bloque está malformada (falta name, nombre no registrado, etc.)Verifica el nombre del bloque con list_block_types
missing_attributes / missing_html / missing_block / missing_blocks / missing_destination / missing_target / missing_data / missing_lookup / missing_file / missing_titleCampo obligatorio omitidoIncluye el campo
invalid_count / invalid_range / invalid_index / invalid_limit / invalid_cursorArgumento numérico fuera de rango o forma incorrectaConsulta message para los límites esperados
invalid_updatesEl array de actualizaciones de update_blocks está malformadoReforma según el esquema de update_blocks
invalid_post_type / invalid_status / invalid_taxonomy / invalid_term / invalid_author / invalid_parent / invalid_featured_mediaValidación de campo de create_post / update_postVerifica el valor contra el registro relevante de WordPress
cycle_parentLa asignación del padre crearía un bucle de jerarquíaElige un padre diferente
mixed_trash_payloadupdate_post mezcló status: trash con otros camposMueve a la papelera primero y actualiza por separado
invalid_if_matchEl encabezado está presente pero no es un entero positivoEnvía If-Match: <revision_id>
revision_mismatchInterno: el ID de revisión capturado no coincidió antes de guardarReintenta; si es persistente, informa un problema
no_inner_blocksunwrap-group en un bloque que no tiene ningunoElimina el contenedor de otra manera o primero inserta los hijos
no_file / missing_fileupload_media no recibió payload multipartEnvía un campo file, url, o data_base64
multiple_inputs / mutually_exclusiveupload_media recibió más de uno de file / url / data_base64Envía exactamente uno
invalid_filename / disallowed_mime / file_too_large / invalid_base64 / invalid_urlPayload de upload_media rechazadoConsulta message para saber qué compuerta falló
upload_errorEl manejador de subida de WordPress devolvió un errorInspecciona message
empty_patterninsert_pattern recibió un patrón sin bloques analizadosElige un patrón diferente
invalid_bodyEl cuerpo JSON de la solicitud no se pudo analizarValida la forma JSON

Límite de tasa (HTTP 429)

CódigoCuándo se produceCómo recuperarse
rate_limit_exceededPresupuesto de escritura por post agotado (10 escrituras/min, o 2 reescrituras completas/min)Espera hasta 60 s y reintenta; considera agrupar con update_blocks
scan_rate_limitedEl escaneo de la página de ajustes se disparó con demasiada frecuenciaEspera; esto afecta solo a los escaneos del lado de administración

Método no permitido (HTTP 405)

No es un error del plugin: un 405 proviene del firewall o servidor web del host, antes de WordPress. Algunos hosts gestionados rechazan PUT, PATCH, y DELETE directamente, por lo que las lecturas y create_post tienen éxito en ese host mientras que cada herramienta de edición falla.

El cliente maneja esto por su cuenta. Cuando uno de esos verbos es rechazado, reproduce la solicitud como un POST con un encabezado X-HTTP-Method-Override (la forma que acepta el núcleo de WordPress), y recuerda el host, para que las ediciones posteriores pasen en el primer intento. Los hosts que aceptan los verbos reales nunca ven el encabezado.

SíntomaQué significaCómo recuperarse
Block API Error (405) con un cuerpo HTML (p. ej., nginx) en una herramienta de ediciónEl firewall rechazó tanto el verbo real como la reproducción de anulaciónPide al host que permita PUT, PATCH, y DELETE, o que deje de eliminar X-HTTP-Method-Override, en la ruta REST de WordPress
Las lecturas funcionan, las ediciones fallan inmediatamente después de la instalaciónEl host rechaza los verbos de edición; la alternativa no pudo completarseIgual que arriba; confirma con curl -X PATCH contra /wp-json/gk-block-api/v1/...

Upstream (HTTP 502)

CódigoCuándo se produceCómo recuperarse
url_fetch_failedLa carga lateral por URL de upload_media falló en la capa HTTP (DNS, TLS, no-2xx, o bloqueo SSRF)Verifica que la URL sea accesible públicamente y no esté en un rango de IP bloqueado

Error del servidor (HTTP 500)

CódigoCuándo se produceCómo recuperarse
internal_errorExcepción no capturada subió hasta el sobre RESTInforma un problema con el mensaje + reproducción
wp_insert_post_failedwp_insert_post devolvió un WP_ErrorInspecciona message; a menudo falta un campo requerido en la capa de base de datos
duplicate_failedLa operación edit_block_tree duplicate no pudo clonar el bloque como JSON (solo ocurre con entrada verdaderamente malformada — recursos, UTF-8 inválido)Informa un problema con la definición del bloque
sideload_failedLa URL upload_media pasó las capas SSRF + HTTP pero media_handle_sideload fallóInspecciona message; a menudo cuota de disco o registro MIME
attachment_missingupload_media creó el adjunto pero no pudo encontrarlo para metadatosInforma un problema
trash_failed / untrash_failedwp_trash_post / wp_untrash_post devolvió falseReintenta; si es persistente, revisa conflictos de filtros

Traducciones

El plugin de WordPress incluye traducciones para los 20 locales de WordPress más usados: árabe, chino (simplificado), checo, danés, neerlandés, finlandés, francés, alemán, húngaro, indonesio, italiano, japonés, coreano, polaco, portugués (BR), rumano, ruso, español, sueco, turco.

Las traducciones se generaron con Potomatic — un CLI de código abierto para traducir con IA archivos .pot a escala.

Licencia

  • Plugin de WordPress: GPL-2.0-or-later
  • Servidor MCP: MIT

Contribución

Los problemas y PR son bienvenidos en github.com/GravityKit/block-mcp. Ejecuta los conjuntos de pruebas antes de enviar; las nuevas mutaciones deben incluir cobertura PHPUnit + Vitest.