MCP server
Lookup material for the Source CMS MCP server: the connection spec, every resource and resource template, and every tool. For setup instructions, see the MCP quickstart (Claude Code, Claude Desktop, Cursor, VS Code, GitHub Copilot, OpenCode, Codex) and the MCP guide (those plus MCP Inspector).
Connection
Section titled “Connection”| Property | Value |
|---|---|
| Server URL | {DRUPAL_SITE_URL}/mcp: your site URL plus /mcp. Also shown under Configurations > Experimental features > MCP Server > Configure > MCP client configuration in the site admin UI. |
| Transport | Streamable HTTP; responses arrive as SSE (text/event-stream) with a single data: event per response (verified) |
| Server identity | Name Acquia Source MCP, version 1.0.0 |
| Protocol version | 2025-11-25, negotiated at initialize. |
| Capabilities | logging, completions, prompts (listChanged), resources (subscribe + listChanged), tools (listChanged) |
| Session | Responses carry an mcp-session-id header; every subsequent request must echo it back as Mcp-Session-Id. |
| Authentication | OAuth 2.0 bearer token. The site’s API client tokens work: a client_credentials grant against {DRUPAL_SITE_URL}/oauth/token (no scope parameter needed). Interactive clients instead self-register via dynamic client registration and run the browser flow. See the authentication guide. |
| Token lifetime | Access tokens expire in 300 seconds; clients refresh silently. |
| Discovery | The site publishes /.well-known/oauth-protected-resource and /.well-known/oauth-authorization-server (authorization endpoint /oauth/authorize, token endpoint /oauth/token, JWKS at /.well-known/jwks.json, dynamic client registration at /oauth/register). An unauthenticated or expired request gets 401 whose WWW-Authenticate header is only Bearer realm="mcp_server" (verified 2026-07-03); read the resource metadata document at {DRUPAL_SITE_URL}/.well-known/oauth-protected-resource/mcp directly (16 scopes_supported, bearer_methods_supported: ["header"]). |
| Scopes | The 16 supported scopes are listed in the resource metadata document (not in the 401 header) and under OAuth configuration in the Configure panel. Scope gating was not observable in verification: a client_credentials token issued without a scope parameter (so carrying every scope selected on its API client) called every tool successfully. |
| Availability | Experimental; off by default, enabled per site under Configurations > Experimental features. |
| Debug client | npx @modelcontextprotocol/inspector --transport http, connection type Direct. |
Client configuration
Section titled “Client configuration”The server registration per harness, with the values from the table above. Interactive clients complete the browser OAuth flow on first connection; headless setups pass a client_credentials token as an Authorization header instead (MCP guide, step 2).
claude mcp add acquia-source-mcp {DRUPAL_SITE_URL}/mcp \ --transport http --scope projectAuthenticate from the /mcp panel.
Custom connector: Customize > Connectors, +, Add custom connector, the server URL, Add, then Connect. Custom connectors reach the server from Anthropic’s cloud, so the site must be reachable over the public internet.
.cursor/mcp.json (project) or ~/.cursor/mcp.json (global):
{ "mcpServers": { "acquia-source-mcp": { "url": "{DRUPAL_SITE_URL}/mcp" } }}.vscode/mcp.json in the project, or MCP: Open User Configuration (user profile):
{ "servers": { "acquia-source-mcp": { "type": "http", "url": "{DRUPAL_SITE_URL}/mcp" } }}Copilot Chat in VS Code reads the repository’s .vscode/mcp.json (the VS Code configuration) or your personal settings.json; other IDEs carry their own files per Extending Copilot Chat with MCP.
opencode.json at the project root:
{ "$schema": "https://opencode.ai/config.json", "mcp": { "acquia-source-mcp": { "type": "remote", "url": "{DRUPAL_SITE_URL}/mcp" } }}Tool domains: Content Management (read/write content entities), Content Modeling (define and evolve content structure), Taxonomy & Menus, Media, Site Settings, Drupal Canvas pages and components, and Drafts & Publishing. Alongside the tools, the server exposes resources (read-only data) and resource templates (parameterized reads).
Errors
Section titled “Errors”MCP runs over JSON-RPC 2.0, so failures surface at three levels:
- HTTP. An unauthenticated or expired request gets
401 Unauthorized. TheWWW-Authenticateheader is onlyBearer realm="mcp_server"(verified 2026-07-03: it does not point at the resource metadata or list scopes); the JSON-RPC body carries error-32001Authentication required. The resource metadata lives at the well-known URL in Connection. - JSON-RPC (schema-level). Input that violates a tool’s schema is rejected before execution with code
-32602: e.g. “Invalid parameters for tool ‘…’: Property ‘/workflow’: Invalid type. Expected string, but received null.”, plus adata.validation_errorsarray of{pointer, keyword, message}objects. - Tool-level. Failures during execution come back as a successful JSON-RPC response with
isError: false(verified 2026-07-03); checkstructuredContent.success, notisError. Two failure forms exist: anerrorobject of{code, message, retryable, details, requestId}(captured codes:validationfor a nonexistent target,configurationfor a missing integration), or, when entity validation fails, a populatedviolationsarray of{field_name, message, invalid_value, code}with noerrorobject.
Successful tool calls return their JSON payload twice: as text in result.content[0].text and mirrored in result.structuredContent.
| Code / status | Meaning | Typical cause here |
|---|---|---|
HTTP 401 Unauthorized |
Request carried no valid token | OAuth flow not completed, token expired (300 s lifetime), or the MCP Server feature was disabled after connect |
-32600 |
Invalid request | Malformed JSON-RPC envelope (client bug) |
-32601 |
Method not found | Stale client capability cache or protocol-version mismatch |
-32602 |
Invalid params | Tool input doesn’t match its schema: details in data.validation_errors |
-32603 |
Internal error | Server-side failure while executing the call |
-32001 |
Server-defined error | Two captured uses: Authentication required on an unauthenticated request, and request timeouts on oversized queries or batches (narrow or split them) |
Every entry below shares this error behavior; per-entry “Errors” notes list only what’s specific to that entry. Successful tool responses share success: true, a human-readable message, and a violations array (empty on success); per-entry Response lines list the distinctive members. MCP Inspector (Tools, List Resources, List Templates) shows the same shapes interactively.
Resources
Section titled “Resources”Read-only lists at fixed URIs. Read them with the standard MCP resources/read request.
drupal://content-types
Section titled “drupal://content-types”Lists the site’s content types with their schemas.
- URI:
drupal://content-types(no parameters) - Response:
{usage, content_types: [{entity_type, bundle, label, description, workflow, schema_uri}]}: one entry per content type, each pointing at itsdrupal://content-types/{bundle}schema. - Errors: standard errors only.
- Used in: MCP quickstart · MCP guide
drupal://media-types
Section titled “drupal://media-types”Lists the site’s media types with their schemas. DAM-backed types are flagged with dam_type: true.
- URI:
drupal://media-types(no parameters) - Response:
{media_types: [{entity_type, bundle, label, description, source, schema_uri, upload_supported, dam_type}]}. Captured: 12 types; the 8 DAM types aredam_type: true, upload_supported: false;image,document, andvideoare uploadable;remote_videois neither (OEmbed). - Errors: standard errors only.
- Used in: MCP guide
drupal://vocabularies
Section titled “drupal://vocabularies”Lists the site’s taxonomy vocabularies.
- URI:
drupal://vocabularies(no parameters) - Response:
{vocabularies: [{entity_type, vid, label, description, schema_uri}]}, each entry pointing at itsdrupal://vocabularies/{vid}schema (captured:categoriesandtags). - Errors: standard errors only.
- Used in: MCP guide
drupal://filter-formats
Section titled “drupal://filter-formats”Lists the text filter formats available when creating or editing content with formatted text fields.
- URI:
drupal://filter-formats(no parameters) - Response:
{formats: [{id, label, allowedHtml, allowedAttributes}]}. Captured:filtered_html(13 allowed tags) andplain_text;allowedAttributesmaps attribute names to allowed values, with"on*": falseblocking event handlers. - Errors: standard errors only.
- Used in: MCP guide
drupal://content-types/fields
Section titled “drupal://content-types/fields”Lists field storage definitions for the node entity type, with usage information: which storages exist and which bundles use them.
- URI:
drupal://content-types/fields(no parameters) - Response:
{fields: [{field_name, type, target_type, cardinality, appears_on, translatable}], description};appears_onlists the bundles using each storage (captured). - Errors: standard errors only.
- Used in: MCP guide
drupal://field-types
Section titled “drupal://field-types”Lists the field types available for content modeling, organized by category.
- URI:
drupal://field-types(no parameters) - Response: the field-type catalog: plugin IDs usable as
field_typein the modeling tools, including entries such asentity_referenceandfield_ui:entity_reference:media. - Errors: standard errors only.
- Used in: MCP guide
drupal://menus
Section titled “drupal://menus”Lists the site’s menus. Each entry includes an items_uri pointing at the drupal://menus/{menu_name} template for that menu’s item tree.
- URI:
drupal://menus(no parameters) - Response:
{menus: [{id, label, description, items_uri}]}(captured: one menu,main). - Errors: standard errors only.
- Used in: MCP guide
drupal://site-info
Section titled “drupal://site-info”Returns the site name and configured front/home page. Use its homepage object to identify the home page; never guess by path string-matching. If homepage is null, the site has no configured front page.
- URI:
drupal://site-info(no parameters) - Response: captured verbatim:
{"site_name": "New Site", "homepage": {"path": "/homepage", "entity_type": "canvas_page", "entity_id": 1}}. - Errors: standard errors only.
- Used in: MCP guide
canvas://components
Section titled “canvas://components”Lists the Drupal Canvas components available for composition.
- URI:
canvas://components(no parameters) - Response: array of
{id, name, library, source, version, props, slots, detail_uri}; each prop is{required, schema, default_value}with JSON Schema types (enums for select-style props). Captured: one code component,js.text. - Errors: standard errors only.
- Used in: MCP guide
canvas://pages
Section titled “canvas://pages”Lists the site’s editable Drupal Canvas pages with live and draft metadata.
- URI:
canvas://pages(no parameters) - Response: array of
{id, hasDraftChanges, live: {title, status, path, internalPath, canonicalUrl}, draft};draftisnullwhen the page has no pending draft (captured). - Errors: standard errors only.
- Used in: MCP guide
canvas://page-regions
Section titled “canvas://page-regions”Lists the global Canvas page regions (header, footer, and so on) shared across all pages for the active theme. Region IDs feed the page-region tools.
- URI:
canvas://page-regions(no parameters) - Response: array of
{id, region, theme, label}with theme-prefixed IDs (captured:astral.headerandastral.footer). - Errors: standard errors only.
- Used in: MCP guide
canvas://auto-saves
Section titled “canvas://auto-saves”Lists the current auto-saved drafts, with the identifiers the publish/discard tools need: publish_auto_saves takes both autosave_key and data_hash; discard_auto_saves takes the keys.
- URI:
canvas://auto-saves(no parameters) - Response: array of
{autosave_key, entity_type, entity_id, label, data_hash, updated, owner, langcode, draft_published}(captured). - Errors: standard errors only.
- Used in: MCP guide
Resource templates
Section titled “Resource templates”Parameterized reads. Substitute the {placeholder} with a concrete value.
drupal://entity/{entity_type_id}/{id}
Section titled “drupal://entity/{entity_type_id}/{id}”Loads one entity by entity type and ID. Supported entity types: node, taxonomy_term, media, user, canvas_page.
- Parameters:
entity_type_id: entity type machine name;id: the entity’s ID. - Example URI:
drupal://entity/node/17 - Response: the raw Drupal field-array representation, not the JSON:API shape: every field is an array of value objects (
"title": [{"value": "…"}]), and references carry{target_id, target_uuid, target_type, url}(captured fordrupal://entity/node/6). - Errors: standard errors; a nonexistent entity is a failed read.
- Used in: MCP guide
drupal://content-types/{bundle}
Section titled “drupal://content-types/{bundle}”Returns the JSON Schema for one content type.
- Parameters:
bundle: content type machine name. - Example URI:
drupal://content-types/article - Response: the full JSON Schema (draft-04) for the bundle’s payload: the fields the create/update tools accept for that content type.
- Errors: standard errors only.
- Used in: MCP guide
drupal://content-types/{bundle}/fields/{field_name}
Section titled “drupal://content-types/{bundle}/fields/{field_name}”Returns one field’s configuration on a content type: instance settings (label, description, required) and storage settings (type, cardinality, has_data, locked). Read it before changing a field with update_field_config.
- Parameters:
bundle: content type machine name;field_name: field machine name. - Example URI:
drupal://content-types/article/fields/summary - Response:
{field_name, bundle, label, description, required, default_value, field_settings, storage: {type, cardinality, translatable, storage_settings, has_data, locked}}(captured forarticle/body). - Errors: standard errors only.
- Used in: MCP guide
drupal://media-types/{bundle}
Section titled “drupal://media-types/{bundle}”Returns the JSON Schema for one media type.
- Parameters:
bundle: media type machine name (e.g.image). - Example URI:
drupal://media-types/image - Response: the full JSON Schema (draft-04) for the media type’s payload, same structure as the content-type schemas (captured for
image). - Errors: standard errors only.
- Used in: MCP guide
drupal://vocabularies/{vid}
Section titled “drupal://vocabularies/{vid}”Returns the JSON Schema for one taxonomy vocabulary.
- Parameters:
vid: vocabulary machine name. - Example URI:
drupal://vocabularies/tags - Response: the full JSON Schema (draft-04) for term payloads in that vocabulary (captured for
tags). - Errors: standard errors only.
- Used in: MCP guide
drupal://menus/{menu_name}
Section titled “drupal://menus/{menu_name}”Returns the item tree for one menu: enabled links in weight order, hierarchy represented by a depth field. Each item includes an id usable with update_menu_item and delete_menu_item.
- Parameters:
menu_name: menu machine name; discover IDs viadrupal://menus. - Example URI:
drupal://menus/main - Response:
{menu_name, label, items}(captured formain; itsitemswas[]). - Errors: standard errors only.
- Used in: MCP guide
canvas://components/{id}
Section titled “canvas://components/{id}”Returns one Drupal Canvas component’s detailed schema and metadata, including the props and slots it declares.
- Parameters:
id: component ID exactly as listed bycanvas://components; captured IDs are dotted,js.<machine_name>for code components (e.g.js.text). - Example URI:
canvas://components/js.text - Response: everything the
canvas://componentsentry lists for the component plus, per prop,source_type(e.g.static:field_item:string) anddefault_values: {source, resolved}(captured forjs.text). - Errors: standard errors only.
- Used in: MCP guide
Content management tools
Section titled “Content management tools”create_node
Section titled “create_node”Creates one content entry (node) of a given content type.
- Input:
bundle(string, required): content type machine name; discover bundles viadrupal://content-types.fields(object, required): field names as keys, values as direct values ({"title": "My Title", "bio": "Text"}, not an array of name/value pairs). Must include atitlekey. Field names do not use thefield_prefix. Readdrupal://content-types/{bundle}to discover the fields.
- Response:
{success, message, violations, warnings, entity_id, url, bundle, schema_uri}(captured). On a workflow-moderated bundle,warningsnotes that draft content is not accessible or referenceable until published. - Errors: standard errors;
-32602when input doesn’t match the bundle’s schema (readdrupal://content-types/{bundle}first). - Used in: MCP quickstart · MCP guide
update_node
Section titled “update_node”Updates an existing node. Partial update: only the provided fields change.
- Input:
entity_id(integer, required): node ID to update.fields(object, required): field names as keys; only provided fields are updated. Entity references accept labels or IDs. Use amoderation_statekey for workflow transitions (e.g."moderation_state": "published"). Field names do not use thefield_prefix.
- Response: same shape as
create_node(captured). A value that fails entity validation returnssuccess: falsewith the failure inviolations[](e.g. amoderation_statethat doesn’t exist in the bundle’s workflow) and noerrorobject. - Errors: standard errors.
- Used in: MCP quickstart · MCP guide
batch_create_nodes
Section titled “batch_create_nodes”Creates multiple nodes of the same content type in one call (the bulk-generation tool for content entries). Media and terms are created one call at a time.
- Input:
bundle(string, required): content type machine name; all nodes in the batch share it.nodes(array of objects, required, min 1): one field object per node, same format ascreate_node’sfields; every object must includetitle.options(object):validate_only(boolean, dry-run validation without saving),stop_on_error(boolean, defaultfalse),return_details(boolean, defaulttrue; setfalsefor token-efficient bulk runs).
- Response:
{total, successful, failed, results: [{index, success, title}], errors}; withoptions.validate_only: truethe response addsvalidate_only: trueand nothing is saved: a true dry run (both captured). - Errors: standard errors;
-32001on oversized batches: split them. - Used in: MCP quickstart · MCP guide
list_entities
Section titled “list_entities”Lists entities with filtering and pagination: the general read used to fetch site content (e.g. recent articles). Supports node, taxonomy_term, media, user, and canvas_page.
- Input:
entity_type(string, required): the entity type to list.bundle(string): bundle/content type machine name to filter by.filters(object): field names as keys, filter values as values. Operator suffixes:__contains,__starts_with,__ends_with,__gt,__gte,__lt,__lte,__not,__in,__not_in,__between,__not_between,__is_null,__is_not_null.labelis an alias for the entity label field (e.g.{"label__contains": "News"},{"created__gte": 1704067200}).limit(integer, default 50): maximum results.offset(integer, default 0): pagination offset.
- Response:
{entity_type, bundle, resource_template, total, items, pagination}where each item is{id, uuid, label, bundle, status, uri, path, canonicalUrl, revision_id},uriis a ready-to-readdrupal://entity/{entity_type_id}/{id}URI, andpaginationis{limit, offset, has_more}(captured). - Errors: standard errors;
-32001on unfiltered sweeps of large sites: filter by content type or page the results. - Used in: MCP quickstart · MCP guide
Content modeling tools
Section titled “Content modeling tools”create_content_type
Section titled “create_content_type”Creates a new content type (node bundle) and returns the schema URI for it.
- Input:
machine_name(string, required, max 32,^[a-z][a-z0-9_]*$): the content type machine name.label(string, required, max 255): human-readable label.workflow(string, required): the workflow to assign to the content type; see the caution above.description(string): optional description.options(object):create_body_field(boolean, defaulttrue: add the standard body field),help(string: help text on the node add form).
- Response:
{machine_name, label, schema_uri, message}(captured). - Errors: standard errors; tool-level
validationerrorWorkflow "…" does not exist.whenworkflownames a workflow the site doesn’t have. - Used in: MCP quickstart · MCP guide
add_field_to_content_type
Section titled “add_field_to_content_type”Adds a field to an existing content type. Supports field-storage reuse across bundles. Valid field types are listed by drupal://field-types.
- Input:
content_type(string, required): the content type machine name.field_name(string, required, max 32,^[a-z][a-z0-9_]*$): unique machine name; do not prefix withfield_.field_type(string, required): field type plugin ID (e.g.string,integer,datetime) fromdrupal://field-types.label(string, required, max 255): human-readable label.description(string): optional help text.required(boolean, defaultfalse).cardinality(integer, default 1): number of values;-1for unlimited.storage_settings(object): e.g.max_lengthfor string fields; forlist_string/list_integer, passallowed_valuesas{"gold": "Gold", "silver": "Silver"}.field_settings(object): field instance settings.default_value: optional default value.
- Response:
{success, field_name, content_type, field_type, storage_created, violations, message};storage_createdreports whether a new field storage was created rather than reused (captured). - Errors: standard errors;
-32602for a field type not present indrupal://field-types. - Used in: MCP quickstart · MCP guide
batch_add_fields_to_content_type
Section titled “batch_add_fields_to_content_type”Adds multiple fields to one or more content types in a single call. Items are processed in order, so a field storage created by an earlier item can be reused by a later item on a different bundle.
- Input:
fields(array of objects, required, min 1): each object takes the same parameters asadd_field_to_content_type:content_type,field_name,field_type,labelrequired;description,required,cardinality,storage_settings,field_settings,default_valueoptional.
- Response:
{total, successful, failed, results, errors}; each result is theadd_field_to_content_typeshape plus itsindex(captured). - Errors: standard errors.
- Used in: MCP guide
update_field_config
Section titled “update_field_config”Updates an existing field’s configuration on a content type. Mutable: label, description, required, default_value, field_settings, cardinality, and (for list fields only) storage_settings.allowed_values. Other storage-level settings (target_type, max_length, …) cannot be changed with this tool.
- Input:
content_type(string, required): the content type machine name.field_name(string, required): field machine name; do not prefix withfield_.label(string): new label.description(string): new help text.required(boolean): set required or optional.field_settings(object): instance settings to update.default_value: new default value.cardinality(integer):-1for unlimited or a positive integer. Increasing is always safe; reducing is only allowed when no entities have values at higher deltas.storage_settings(object): onlyallowed_valuesforlist_string/list_integerfield types.
- Response:
{success, field_name, content_type, violations, message}; the message names the keys that changed, e.g."(label, required)"(captured). - Errors: standard errors. Inspect current settings first via
drupal://content-types/{bundle}/fields/{field_name}. - Used in: MCP guide
Taxonomy and menu tools
Section titled “Taxonomy and menu tools”create_vocabulary
Section titled “create_vocabulary”Creates a taxonomy vocabulary. Idempotent: if the vocabulary already exists, returns the existing metadata without creating a duplicate.
- Input:
vid(string, required, max 32,^[a-z][a-z0-9_]*$): vocabulary machine name (e.g.tags,sponsor_tier).name(string, required, max 255): human-readable label.description(string): optional description.weight(integer): optional display weight.
- Response:
{success, vid, name, description, schema_uri, existed, message};existed: trueon the idempotent path for the existingtags. - Errors: standard errors.
- Used in: MCP guide
get_or_create_term
Section titled “get_or_create_term”Returns an existing taxonomy term by exact name match (case-insensitive), or creates it if absent (idempotent tagging).
- Input:
vid(string, required): vocabulary machine name; discover viadrupal://vocabularies.name(string, required): the exact term name to find or create.additional_fields(object): optional extra field values (e.g.description,parent,weight).
- Response:
{success, entity_id, name, vid, existed, message, violations, warnings}(captured: an existing term returnsexisted: truewith itsentity_id). - Errors: standard errors.
- Used in: MCP quickstart · MCP guide
create_menu
Section titled “create_menu”Creates a new custom menu.
- Input:
id(string, required, max 32,^[a-z0-9_-]+$): menu machine name (e.g.footer-menu).label(string, required, max 255): human-readable label.description(string): optional description.
- Response:
{success, message, violations, id, label}(captured). - Errors: standard errors.
- Used in: MCP guide
update_menu
Section titled “update_menu”Updates an existing menu’s label or description. At least one of label or description must be provided.
- Input:
id(string, required): menu machine name.label(string, max 255): new label.description(string): new description.
- Response:
{success, message, violations, id, label}carrying the updated label (captured). - Errors: standard errors.
- Used in: MCP guide
create_menu_item
Section titled “create_menu_item”Creates a menu link. The item is saved as an auto-save draft. Call publish_auto_saves with the returned autosave_key to make it visible in menus.
- Input:
menu_name(string, required): menu machine name (e.g.main,footer).title(string, required, max 255): link title.link(string, required): link URI:internal:/path,https://example.com,entity:node/1, orroute:route.name.parent(string): parent menu link plugin ID (e.g.menu_link_content:<uuid>).weight(integer): ordering weight; lower first (default 0).enabled(boolean, defaulttrue) ·expanded(boolean, defaultfalse) ·description(string): optional tooltip text.
- Response:
{success, uuid, id, title, menu_name, autosave_key, message, violations, warnings};autosave_keyhas the formmenu_link_content:<id>:<langcode>(captured). - Errors: standard errors.
- Used in: MCP guide
update_menu_item
Section titled “update_menu_item”Updates a menu item by entity ID. Partial update: only provided fields change; use weight to reorder. Changes are saved as an auto-save draft; publish them with publish_auto_saves.
- Input:
id(integer, required): menu link content entity ID (fromdrupal://menus/{menu_name}).title(string) ·link(string) ·parent(string; empty string removes the parent) ·weight(integer) ·enabled(boolean) ·expanded(boolean) ·description(string).
- Response: same shape as
create_menu_item, with a draft-state warning while the item is unpublished (captured). - Errors: standard errors.
- Used in: MCP guide
delete_menu_item
Section titled “delete_menu_item”Deletes a menu item by entity ID. One of the catalog’s two delete tools (with delete_canvas_page). Nodes, media, and terms have no MCP delete.
- Input:
id(integer, required): menu link content entity ID.delete_children(boolean, defaultfalse): whenfalse, existing children are re-parented to this item’s parent; whentrue, all descendants are also deleted.
- Response:
{success, id, title, children_deleted, message}(captured). - Errors: standard errors.
- Used in: MCP guide
Media tools
Section titled “Media tools”create_media
Section titled “create_media”Creates a file-based media entity (any file-based media type: image, document, video, …) and returns a signed upload URL. Upload the file afterwards with curl -X PUT <upload_url> -H "Content-Type: application/octet-stream" --data-binary @/path/to/file; the upload attaches the file and publishes the entity automatically. Reference the media in Canvas component props as the scalar MID (e.g. 42), and in Drupal entity reference fields as {"target_id": <mid>}. Don’t fetch the file URL from the media entity.
- Input:
bundle(string, required): media type machine name; discover viadrupal://media-types.name(string, required): media name.filename(string, required): target filename with extension (e.g.photo.jpg).metadata(object): source-field metadata (e.g.{"alt": "Image description", "title": "Image title"}for images).fields(object): additional field values keyed by field name; seedrupal://media-types/{bundle}.
- Response:
{mid, upload_url, method: "PUT", expires_in: 300, message}; the entity stays an unpublished draft until the file is uploaded, and the upload URL expires in 300 seconds (captured). - Errors: standard errors.
- Used in: MCP quickstart · MCP guide
create_remote_video
Section titled “create_remote_video”Creates a remote-video media entity from an OEmbed URL (YouTube, Vimeo, …). Created and published immediately.
- Input:
bundle(string, required): media type machine name (e.g.remote_video); any OEmbed-based bundle.url(string, required): the OEmbed URL; must be from a supported provider.name(string): media name; if omitted, Drupal auto-fetches the title from the OEmbed provider.fields(object): additional field values keyed by field name.
- Response:
{mid, url, message}; created and published in one step (from a YouTube URL). - Errors: standard errors.
- Used in: MCP guide
create_dam_media
Section titled “create_dam_media”Creates a DAM-backed media entity by referencing an existing Acquia DAM asset: only the asset_id reference is stored; no file upload. Works only with DAM media types (dam_type: true in drupal://media-types).
- Input:
bundle(string, required): a DAM-backed media type machine name.asset_id(string, required): the Acquia DAM asset UUID; the asset must already exist in DAM.name(string): media name; defaults to the asset filename from DAM.version_id(string): optional DAM asset version UUID; empty uses the latest finalized version (the DAM CDN always serves the current published asset regardless).external_id(string): optional DAM external ID.
- Response:
structuredContentcarriesmid(integer),url(string, the media entity’s absolute URL), andmessage(string), all three required. On a fresh import the message readsDAM media entity {mid} created and published successfully (asset_id: {asset_id}).; the tool is idempotent, so a repeat call for an already-imported asset returns the existing entity with messageDAM media entity {mid} already exists for asset_id {asset_id}, returning existing entity.(shape from the tool’soutputSchemaand kernel test against the DAM fixture, not a live DAM tenant). If the referenced asset is missing or not publicly available in DAM, the just-created entity saves unpublished, is deleted, and the tool returnscode: "validation". On a site without the DAM integration the call fails with tool-level errorcode: "configuration", messageAcquia DAM is not configured on this site…. - Errors: standard errors.
- Used in: MCP guide
Site settings tools
Section titled “Site settings tools”update_site_settings
Section titled “update_site_settings”Updates site settings such as the site name. Changes are staged and take effect when auto-saves are published.
- Input:
site_name(string, required, min length 1): the new site name.
- Response:
{success, message, violations, site_name, already_set, staged}. When the requested name already matches, the tool is a no-op:already_set: true,staged: false, and no auto-save is created. A real change instead stages an auto-save (staged: true), applied bypublish_auto_saves. - Errors: standard errors.
- Used in: MCP guide
update_site_logo
Section titled “update_site_logo”Uploads a new site logo and updates the theme configuration. Like create_media, it returns a signed upload URL: upload with curl -X PUT <upload_url> -H "Content-Type: application/octet-stream" --data-binary @/path/to/logo.png, after which the logo is immediately live.
- Input:
filename(string, required): filename with extension. Supported formats:png,jpg,jpeg,gif,svg,webp,ico,apng.
- Response:
{upload_url, method: "PUT", expires_in: 300, message}: the same signed-upload envelope ascreate_media. Until a file is PUT toupload_url, nothing changes; the URL expires in 300 seconds. - Errors: standard errors.
- Used in: MCP guide
set_homepage
Section titled “set_homepage”Sets a Canvas page as the site homepage. If the page is unpublished, a published draft is staged. Takes effect when auto-saves are published.
- Input:
page_id(integer, required, ≥ 1): Canvas page entity ID.
- Response:
{success, message, violations, page_id, page_title, page_url, auto_published, is_homepage, homepage_staged}. When the page is already the homepage, the tool is a no-op:is_homepage: true,homepage_staged: false. Setting a new homepage stages an auto-save (homepage_staged: true), and an unpublished target is auto-published. - Errors: standard errors.
- Used in: MCP guide
Canvas page and component tools
Section titled “Canvas page and component tools”Layout edits on Canvas pages write to the page’s draft (auto-save) channel. Make a page or its changes live with the draft and publishing tools.
create_canvas_page
Section titled “create_canvas_page”Creates an unpublished Canvas page draft with optional metadata.
- Input:
title(string, required, min length 1): page title.path(string): optional URL alias, e.g./acquia-engage.description(string): optional page description.
- Response:
{success, message, violations, page_id, revision_reference, page};pageis thecanvas://pagesentry shape with both channels:live.status: falseand adraftcarryingrevisionId,draftUrl, anddataHash(captured). - Errors: standard errors.
- Used in: MCP quickstart · MCP guide
update_canvas_page
Section titled “update_canvas_page”Updates page metadata (title/path/description/status) on an existing Canvas page draft. This changes the auto-save data_hash: if you publish via publish_auto_saves afterwards, use the page.draft.dataHash from this tool’s response, not a cached value.
- Input:
page_id(integer, required, ≥ 1): Canvas page entity ID.title(string) ·path(string) ·description(string): optional updated metadata.status(boolean): optional publish status:truepublishes the page when the draft is published;falsekeeps it unpublished.
- Response: the same page envelope; the draft’s
dataHashchanges with every metadata update (captured). - Errors: standard errors.
- Used in: MCP guide
delete_canvas_page
Section titled “delete_canvas_page”Deletes a Canvas page by ID. One of the catalog’s two delete tools (with delete_menu_item). Nodes, media, and terms have no MCP delete.
- Input:
page_id(integer, required, ≥ 1): Canvas page entity ID.force(boolean, defaultfalse): force deletion whentrue.
- Response:
{success, message, violations, page_id, deleted: true}(captured). - Errors: standard errors.
- Used in: MCP guide
get_page_layout
Section titled “get_page_layout”Returns the native Canvas client-side layout/model representation for a page.
- Input:
page_id(integer, required, ≥ 1): Canvas page entity ID.
- Response:
{success, message, violations, page_id, revision_reference, layout: {layout, model}}:layoutis the component tree (nodes of{uuid, nodeType, type: "js.text@<version>", name, slots}) andmodelmaps instance UUIDs to per-prop sources ({sourceType, expression}) (captured). - Errors: standard errors.
- Used in: MCP guide
set_page_layout
Section titled “set_page_layout”Sets the native Canvas layout/model payload on the page’s draft channel, replacing the current draft layout.
- Input:
page_id(integer, required, ≥ 1): Canvas page entity ID.layout(object, required): native Canvas layout/model payload (same format asget_page_layoutreturns).base_revision_id(integer or string): optional optimistic-lock token; a stale value returns a conflict.
- Response:
{success, message, violations, page_id, layout}echoing the saved layout; accepted withbase_revision_idset to therevision_referencefromget_page_layout(captured). - Errors: standard errors; conflict when
base_revision_idis stale. - Used in: MCP quickstart · MCP guide
add_component_to_page
Section titled “add_component_to_page”Adds a component instance at a slot/index target in a page’s draft layout. Available components and their IDs come from canvas://components.
- Input:
page_id(integer, required, ≥ 1): Canvas page entity ID.component_id(string, required): component ID to insert.props(object): component props (static source only for Alpha).parent_instance_id(string): instance ID of the parent component to nest inside; omit for top-level placement.slot(string): target slot name on the parent; required whenparent_instance_idis set (discover slot names viaget_page_layoutorcanvas://components/{id}).index(integer): insertion position within the page layout or the slot.
- Response:
{success, message, violations, page_id, new_instance_id, layout};layoutechoes the full updated draft layout/model (captured). - Errors: standard errors;
-32602for a component ID not listed bycanvas://components. - Used in: MCP quickstart · MCP guide
batch_add_components_to_page
Section titled “batch_add_components_to_page”Adds multiple component instances to a page’s draft layout in one call. All-or-nothing: if any component fails validation, the whole batch is rejected, no draft is written, and every per-component error is returned in failed_components so you can fix them all and retry.
Omit index on every item to append in batch order. Parents being created in the same batch get a temp_id starting with @ that children reference via parent_instance_id (e.g. {"temp_id": "@hero", …} then {"parent_instance_id": "@hero", "slot": "body", …}). Each parent must appear before its children.
- Input:
page_id(integer, required, ≥ 1): Canvas page entity ID.components(array of objects, required, min 1): each item:component_id(required), plus optionalprops,temp_id(^@.+),parent_instance_id,slot,index.
- Response: on success
{success, message, violations, page_id, total, successful, failed, new_instance_ids, component_results, layout}; eachcomponent_resultsentry is{index, component_id, instance_id, parent_instance_id, slot}(captured). - Errors: standard errors; validation failures list every failing component in
failed_components. - Used in: MCP guide
move_component
Section titled “move_component”Moves a component instance to a new slot/index target in the draft layout.
- Input:
page_id(integer, required, ≥ 1): Canvas page entity ID.instance_id(string, required): component instance ID to move.parent_instance_id(string): target parent component instance ID.slot(string): target slot name under the parent.index(integer): target index in the region/slot component list.
- Response:
{success, message, violations, page_id, instance_id, layout}with the full layout echo (captured). - Errors: standard errors.
- Used in: MCP guide
remove_component
Section titled “remove_component”Removes a component instance (including nested descendants) from the draft layout.
- Input:
page_id(integer, required, ≥ 1): Canvas page entity ID.instance_id(string, required): component instance ID to remove.
- Response:
{success, message, violations, page_id, removed_instance_id, layout}(captured). - Errors: standard errors.
- Used in: MCP guide
update_component_props
Section titled “update_component_props”Partially updates the props of a component instance in a page’s draft layout.
- Input:
page_id(integer, required, ≥ 1): Canvas page entity ID.instance_id(string, required): component instance ID to update.props(object, required): partial props patch (static source only for Alpha). Prop names and types for a given component come fromcanvas://components/{id}.
- Response:
{success, message, violations, page_id, instance_id, layout}(captured). - Errors: standard errors;
-32602for prop values that don’t match the component’s declared types. - Used in: MCP quickstart · MCP guide
get_page_region_layout
Section titled “get_page_region_layout”Returns the current layout of a global Canvas page region (e.g. header or footer). Regions are shared across all pages for the active theme.
- Input:
region_id(string, required): page region config entity ID (e.g.astral.header); list regions viacanvas://page-regions.
- Response:
{success, message, violations, region_id, layout: {layoutVersion, regions: [{id, components}], componentCount}}(captured forastral.header). - Errors: standard errors.
- Used in: MCP guide
set_page_region_layout
Section titled “set_page_region_layout”Replaces the full layout of a global Canvas page region (e.g. header or footer).
- Input:
region_id(string, required): page region config entity ID; list regions viacanvas://page-regions.layout(object, required): layout payload in the same formatget_page_region_layoutreturns.
- Response: the same shape, echoing the saved region layout (captured). Verified: region layout edits apply directly to the region; they do not appear in
canvas://auto-saves. - Errors: standard errors.
- Used in: MCP guide
add_component_to_page_region
Section titled “add_component_to_page_region”Adds a component instance to a global Canvas page region (e.g. header or footer).
- Input:
region_id(string, required): page region config entity ID; list regions viacanvas://page-regions.component_id(string, required): component ID to insert.props(object): component props (static source only for Alpha).parent_instance_id(string) ·slot(string) ·index(integer): optional placement, as inadd_component_to_page.
- Response:
{success, message, violations, region_id, new_instance_id, layout}; region components carry{instanceId, componentId, name, props, region, parent, slot, index, slots}with resolvedpropsvalues, unlike the pagemodelrepresentation (captured). - Errors: standard errors.
- Used in: MCP guide
Draft and publishing tools
Section titled “Draft and publishing tools”publish_canvas_page
Section titled “publish_canvas_page”Sets a Canvas page to published (publicly visible) and commits all pending draft changes. Use it to make a page live; to commit layout or content changes on an already-published page without changing its visibility, use publish_auto_saves instead.
- Input:
page_id(integer, required, ≥ 1): Canvas page entity ID.
- Response: the page envelope after publishing:
live.status: true,draft: null,hasDraftChanges: false(captured). - Errors: standard errors.
- Used in: MCP guide
publish_auto_saves
Section titled “publish_auto_saves”Publishes one or more auto-saved drafts to their canonical entities: Canvas layout edits, menu items, staged site settings.
- Input:
autosaves(array of objects, required): each entry requiresautosave_key(string) anddata_hash(string), both from thecanvas://auto-savesresource; the hash verifies you are publishing the version you expect.
- Response:
{success, message, violations, results: [{autosave_key, success, message}]}(captured). - Errors: standard errors; a stale
data_hashis rejected: re-readcanvas://auto-saves(or use thedataHashreturned by the tool that changed the draft). - Used in: MCP guide
discard_auto_saves
Section titled “discard_auto_saves”Discards one or more auto-saved drafts without publishing. Accepts individual keys for granular discard.
- Input:
autosave_keys(array of strings, required): auto-save keys from thecanvas://auto-savesresource.
- Response:
{success, message, violations, results: [{autosave_key, success, message}]}(captured). Verified caveat: discarding the auto-save of a newly created menu item leaves the disabled entity behind; remove it withdelete_menu_item. - Errors: standard errors.
- Used in: MCP guide
get_canvas_preview_signed_url
Section titled “get_canvas_preview_signed_url”Generates a signed URL for previewing a Canvas page’s draft/auto-save without a Drupal login session. The URL is preview-only and expires in 5 minutes.
- Input:
page_id(integer, required, ≥ 1): Canvas page entity ID.
- Response:
{success, message, violations, preview_url, expires_at, expires_in_seconds: 300}(captured). - Errors: standard errors.
- Used in: MCP guide
Used in
Section titled “Used in”- MCP quickstart: enable the server and make a first tool call with your coding agent.
- MCP server integration guide: client setup patterns, resource browsing, and known limits.
- MCP guide, govern the agent’s access: the scope, revocation, and accountability controls around this connection spec.
- Authentication guide: the OAuth flow behind the connection spec.
Was this page helpful?
What went wrong?
Still stuck? Contact Acquia Support (opens in a new tab)