Acquia Source — Navigation menus via Source MCP
Principle: Menus belong in the CMS (Drupal menu entities and menu
links). That is the correct, maintainable model for production. This skill
automates the same data you would create under Structure → Menus on an
Acquia Source site. It does not replace the CMS with hardcoded link
lists in components for real site delivery.
When this applies
Use this skill when all of the following hold:
- The target is an Acquia Source Drupal site (see
AGENTS.md — e.g. .cms.acquia.site or
CANVAS_SITE_URL for that environment).
- You are authoring or changing menus or menu links for that remote
site.
- You will use Source MCP (read each tool schema; server id is often
user-source-mcp).
Do not use this skill
- Not an Acquia Source / Source-MCP target (other hosting, local-only
Workbench, or a Canvas site where you are not using the Source MCP server for
that environment). For those, use the Drupal admin (or the project’s
normal operations) to create menus; do not route that work through this
document.
- Treating static
FALLBACK_LINKS in code as a substitute for a real Drupal
menu on a site that should be editor-driven. Keep fallbacks for empty/preview
only; on Source, still create the menu in the CMS (MCP or UI).
If Source MCP is unavailable on a Source site, still create the same
menus in the Drupal admin (Structure → Menus) — that is the right place;
only the automation path is missing, not the model. See
canvas-navigation-components.
Relationship to Canvas components
- CMS first: Authors and this skill work on Drupal; components only
read
menu_items by machine name. Keep menuName in component.yml
/ props in sync with the menu you created in the CMS (see
canvas-data-fetching
and
canvas-navigation-components).
- This skill does not push React code — only menu entities on the server.
Use
canvas-component-push when
component source still needs uploading.
Discover existing menus
Before creating duplicates, list menus:
- MCP resource:
drupal://menus (JSON list; entries may include links to
per-menu item trees — see your server’s resource templates).
Use the same server id as for tools (<source-mcp-id>).
MCP tools (read schemas before each call)
Always read each tool’s JSON schema in your MCP filesystem for the Source
server before invoking tools. Typical menu-related tools:
| Tool |
Purpose |
create_menu |
New custom menu: machine id, label, optional description. |
update_menu |
Change label / description for an existing menu id. |
create_menu_item |
Add a link: menu_name, title, link, optional parent, weight, enabled, expanded, description. |
update_menu_item |
Patch by menu link content id (integer): title, link, parent, weight, enabled, expanded, description. |
delete_menu_item |
Remove by id; optional delete_children. |
Link URIs (link field)
Use the formats your tool schema documents (commonly):
- Internal path:
internal:/path (e.g. internal:/about,
internal:/node/1)
- External:
https://example.com
- Entity shortcut:
entity:node/1
- Route:
route:<Drupal route name>
Match paths to real aliases or nodes on the site so links resolve after publish.
Hierarchy (nested items)
- Create parents before children.
parent is usually a menu link plugin id string (for example
menu_link_content:<uuid>) — take the value from create_menu_item
responses or from the menu tree resource for the parent item, per your MCP
tool output.
weight: lower values tend to sort first; use for ordering within a
level.
Ordering and cleanup
- Use
update_menu_item with weight (and link / title) to
reorder or fix mistakes without deleting.
- Use
delete_menu_item when removing entries; confirm
delete_children behavior if the item has descendants.
Suggested workflow
- Fetch
drupal://menus → note existing main, footer, etc.
- If you need a new menu (new machine name), call
create_menu → then
add items with menu_name set to that id.
- Otherwise
create_menu_item against main / footer / etc.,
using link URIs that match deployed Canvas pages or nodes (coordinate
with acquia-source-canvas-pages
for routes).
- Verify in the Drupal UI or via JSON:API
menu_items from the component’s
menuName as in canvas-data-fetching.
Related skills
1---2name: acquia-source-navigation-menus3description: Acquia Source only. Create and edit Drupal menus in the CMS via Source MCP. Do not use for non-Source sites; production nav should still be authored in Drupal, not only in component code.4---56# Acquia Source — Navigation menus via Source MCP78**Principle:** **Menus belong in the CMS** (Drupal menu entities and menu9links). That is the correct, maintainable model for production. This skill10**automates the same data** you would create under **Structure → Menus** on an11**Acquia Source** site. It does **not** replace the CMS with hardcoded link12lists in components for real site delivery.1314## When this applies1516Use this skill when **all** of the following hold:17181. The target is an **Acquia Source** Drupal site (see19 [`AGENTS.md`](../../../AGENTS.md) — e.g. **`.cms.acquia.site`** or20 **`CANVAS_SITE_URL`** for that environment).212. You are **authoring or changing** **menus or menu links** for that **remote**22 site.233. You will use **Source MCP** (read each tool schema; server id is often24 **`user-source-mcp`**).2526## Do not use this skill2728- **Not an Acquia Source / Source-MCP target** (other hosting, local-only29 Workbench, or a Canvas site where you are not using the Source MCP server for30 that environment). For those, use the **Drupal admin** (or the project’s31 normal operations) to create menus; do not route that work through this32 document.33- **Treating static `FALLBACK_LINKS` in code as a substitute** for a real Drupal34 menu on a site that should be editor-driven. Keep fallbacks for empty/preview35 only; on Source, still create the menu in the CMS (MCP or UI).3637If Source MCP is **unavailable** on a **Source** site, **still** create the same38menus in the **Drupal admin** (Structure → Menus) — that is the right place;39only the _automation_ path is missing, not the model. See40[`canvas-navigation-components`](../canvas-navigation-components/SKILL.md).4142## Relationship to Canvas components4344- **CMS first:** Authors and this skill work on **Drupal**; components only45 **read** `menu_items` by machine name. Keep **`menuName`** in `component.yml`46 / props in sync with the menu you created in the CMS (see47 [`canvas-data-fetching`](../canvas-data-fetching/SKILL.md#navigation--menu-components)48 and49 [`canvas-navigation-components`](../canvas-navigation-components/SKILL.md)).50- **This skill** does not push React code — only menu entities on the server.51 Use [`canvas-component-push`](../canvas-component-push/SKILL.md) when52 component source still needs uploading.5354## Discover existing menus5556Before creating duplicates, list menus:5758- **MCP resource:** `drupal://menus` (JSON list; entries may include links to59 per-menu item trees — see your server’s resource templates).6061Use the same server id as for tools (`<source-mcp-id>`).6263## MCP tools (read schemas before each call)6465Always **read each tool’s JSON schema** in your MCP filesystem for the Source66server before invoking tools. Typical menu-related tools:6768| Tool | Purpose |69| ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |70| **`create_menu`** | New custom menu: machine **`id`**, **`label`**, optional **`description`**. |71| **`update_menu`** | Change **`label`** / **`description`** for an existing menu **`id`**. |72| **`create_menu_item`** | Add a link: **`menu_name`**, **`title`**, **`link`**, optional **`parent`**, **`weight`**, **`enabled`**, **`expanded`**, **`description`**. |73| **`update_menu_item`** | Patch by menu link content **`id`** (integer): **`title`**, **`link`**, **`parent`**, **`weight`**, **`enabled`**, **`expanded`**, **`description`**. |74| **`delete_menu_item`** | Remove by **`id`**; optional **`delete_children`**. |7576### Link URIs (`link` field)7778Use the formats your tool schema documents (commonly):7980- **Internal path:** `internal:/path` (e.g. `internal:/about`,81 `internal:/node/1`)82- **External:** `https://example.com`83- **Entity shortcut:** `entity:node/1`84- **Route:** `route:<Drupal route name>`8586Match paths to real aliases or nodes on the site so links resolve after publish.8788### Hierarchy (nested items)8990- Create **parents before children**.91- **`parent`** is usually a **menu link plugin id** string (for example92 `menu_link_content:<uuid>`) — take the value from **`create_menu_item`**93 responses or from the menu tree resource for the parent item, per your MCP94 tool output.95- **`weight`:** lower values tend to sort first; use for ordering within a96 level.9798### Ordering and cleanup99100- Use **`update_menu_item`** with **`weight`** (and **`link`** / **`title`**) to101 reorder or fix mistakes without deleting.102- Use **`delete_menu_item`** when removing entries; confirm103 **`delete_children`** behavior if the item has descendants.104105## Suggested workflow1061071. Fetch **`drupal://menus`** → note existing **`main`**, **`footer`**, etc.1082. If you need a **new** menu (new machine name), call **`create_menu`** → then109 add items with **`menu_name`** set to that **`id`**.1103. Otherwise **`create_menu_item`** against **`main`** / **`footer`** / etc.,111 using **`link`** URIs that match deployed Canvas pages or nodes (coordinate112 with [`acquia-source-canvas-pages`](../acquia-source-canvas-pages/SKILL.md)113 for routes).1144. Verify in the Drupal UI or via JSON:API **`menu_items`** from the component’s115 **`menuName`** as in **`canvas-data-fetching`**.116117## Related skills118119| Skill | Role |120| -------------------------------------------------------------------------- | ----------------------------------------------------------------- |121| [`AGENTS.md`](../../../AGENTS.md) | Acquia Source signals, **`CANVAS_SITE_URL`**, Canvas pages vs CLI |122| [`canvas-navigation-components`](../canvas-navigation-components/SKILL.md) | **`menuName`**, decomposition, UX/accessibility |123| [`canvas-data-fetching`](../canvas-data-fetching/SKILL.md) | **`menu_items`**, `sortMenu`, SWR, fallbacks |124| [`acquia-source-canvas-pages`](../acquia-source-canvas-pages/SKILL.md) | Paths and **`canvas_page`** URLs menus should point to |125| [`acquia-source-site-build`](../acquia-source-site-build/SKILL.md) | Full pipeline Phase B5 (menus) |126| [`canvas-component-push`](../canvas-component-push/SKILL.md) | Push nav **components** (separate from menu entities) |