Issue #3630858: Add an experimental Gutenberg Tools submodule to create and edit pages from AI assistants (MCP)
Closes https://www.drupal.org/project/gutenberg/issues/3630858
Adds the experimental Gutenberg Tools submodule (modules/gutenberg_tools), so AI assistants like Claude and ChatGPT can create and edit Gutenberg content through the MCP Server. The tools are Tool API plugins, so AI Agents and ECA can use them too. The submodule is flagged lifecycle: experimental while Tool API and MCP Server are in beta.
The tools
| Tool | Does |
|---|---|
gutenberg_content_types |
Lists the Gutenberg content types and their settings |
gutenberg_block_catalog |
Describes the blocks, components, fields and theme presets a content type allows |
gutenberg_markup_guide |
Explains block markup, with an exact example of each block the content type allows |
gutenberg_list_pages |
Finds content by title and content type |
gutenberg_get_page |
Returns the markup of a page and an outline of its blocks, with their paths |
gutenberg_validate |
Validates markup against what the editor of a content type accepts |
gutenberg_preview |
Returns a link to a preview in the theme of the site, and the rendered HTML |
gutenberg_create_page |
Creates a page, unpublished unless asked |
gutenberg_update_page |
Changes the content, single blocks by path, the title or the status, as a new revision |
With MCP Server Tool Bridge enabled, the module's optional config exposes them as tool_api__gutenberg_*. They act as the user: the use gutenberg tools permission, node access, and the Gutenberg text format for writes and previews.
Changes to the main module
BlockSerializer: a port ofserialize_blocks(), escaping attributes like the editor (including the backslashes the current editor escapes).BlockParsernow records invalid attribute JSON ininvalidAttrsinstead of throwing aTypeError.GutenbergContentTypeManager::getAllowedBlocks(): the allowed blocks of a content type, moved from the editor plugin, which now uses it.BlockValidator(gutenberg.block_validator): checks markup for what the editor would refuse: allowed and denied blocks,parent/ancestor, attribute types and enums, attributes written in the comment that the editor reads from the HTML, components, props, slots, field blocks, the mapped title and locked templates.gutenberg_basetreats the node previews (core's and the tools') as node pages.
Validity of the HTML
The editor marks a block invalid when its HTML differs from its save(), which PHP can't run. So the examples of the markup guide are generated from the installed @wordpress packages by npm run generate-markup-guide (scripts/generate-markup-guide.js). The new markup-guide-sync CI job checks they are up to date, and markup-guide.spec.mjs loads every example in the Drupal editor and expects no invalid block. Run the script after updating the @wordpress packages (added to the upgrade checklist in AGENTS.md).
Preview links
The preview, create and update tools return /gutenberg-tools/preview/{token}: the content as the page of the node, in the default theme. An assistant's browser isn't logged in, so the token (192 random bits) is the access, for an hour. The page isn't cached, indexed or sent as a referrer, and doesn't change the node or its caches. The README has a Security section on this.
Testing
- PHPUnit: unit tests of the serializer (round trip of a full landing page), the parser and
BlockTree; kernel tests of the validator and of the tools (access, create, update with block operations, refused edits, previews including the anonymous request). - Playwright:
markup-guide.spec.mjs. - Locally with Claude Desktop and Claude Code over STDIO (
drush mcp:server <user>): see "Trying it locally" inmodules/gutenberg_tools/README.md, and the DDEV section of the README for this repo's D11 site.
Not tested yet: claude.ai and ChatGPT connectors over HTTP with MCP Server OAuth (alpha, Drupal 11), which need a public site. The README describes the setup.
drupal/tool is added to require-dev, for the tests; CI only runs Drupal 11 variants, which Tool API supports.