MCP Tools: Site Structure

Structure tools change the shape of your site rather than its words: which page types exist, what the navigation tree looks like, which labels group your content, what lives at which URL, what your funnel stages are called, and which phrases turn into links automatically. Fifteen tools cover that surface, and none of them puts anything on your live site. Every write lands in a draft state and waits for a person to publish it.

All fifteen tools at a glance
ToolReads or writesAlso in the assistant?
list_page_typesReadYes
get_page_type_schemaReadNo
list_menusReadYes
get_menuReadYes
update_menu_draftWrite — replaces the whole treeYes
list_labelsReadNo
get_labelReadNo
update_labelWriteNo
list_label_usersReadNo
list_pathsReadNo
resolve_pathReadNo
list_journey_stagesReadNo
update_journey_stageWrite — name and description onlyNo
list_autolinksReadNo
create_autolinkWriteNo

Page types

Two tools. A page type is the template-plus-schema that decides what fields a page has and where its URLs live, so both of these are things a model should call before it creates or edits a page, not after.

list_page_types

GET /api/ai/assistant/context/page_types · Returns { pageTypes: [{ pageTypeId, slug, name, type }] } · Also available in the Leed Assistant

Takes no parameters. type is one of documentation, api or posts, and is absent for a custom type. The tool’s own description instructs the model to call this before choosing a pageTypeId, and to ask you rather than guess when more than one page type plausibly matches — so “put this in the blog” resolves to the posts-kind entry and “add it to the docs” to the documentation-kind one.

get_page_type_schema

GET /api/pagetypes/:pageTypeId · Returns { pageType } · MCP only

ParameterTypeRequiredDefaultNotes
pageTypeIdstringYes—From list_page_types

Returns the full page type, including its field schema and its required-field configuration. This is the call that tells a model that documentation pages must carry a summary before they can be published, so it is worth making before a bulk authoring run rather than discovering the requirement one rejected publish at a time.

Three tools, and the most consequential write on this page.

list_menus

GET /api/menu · Returns { menus } · Also available in the Leed Assistant

Takes no parameters. Each row carries menuId, name, isDirty and an isDocsMenu flag saying whether that menu is bound to a documentation page type as its left navigation — which matters, because the docs-menu rules below apply only to those.

get_menu

GET /api/menu/:menuId · Returns { menu, isDocsMenu } · Also available in the Leed Assistant

ParameterTypeRequiredDefaultNotes
menuIdstringYes—From list_menus

Returns the menu’s draft state — the tree as it currently stands, including unpublished edits — alongside its dirty flag. Always read before you write: the update tool replaces what is there.

update_menu_draft

PUT /api/menu/:menuId · Returns { menu, isDocsMenu } · Also available in the Leed Assistant

ParameterTypeRequiredDefaultNotes
menuIdstringYes—Which menu to write
itemsarray of menu itemsNounchangedReplaces the whole tree. See below
namestringNounchangedThe menu’s name — see the warning about renaming
descriptionstringNounchangedInternal description only
expandedbooleanNounchangedWhether the menu renders expanded by default
isDirtybooleanNoset to true by the routeDo not send it; the save marks the menu dirty for you

A menu save is a whole-tree replace

A menu item is a node, and a node with children is a folder. The shape is the same either way:

FieldTypeMeaningDocs-menu constraint
menuItemIdstring, requiredStable id for the nodeYou supply it; it is not generated for you
namestring, requiredThe visible label in the navFor a folder, this is what gets slugified into the URL segment
titlestring, requiredThe hover tooltipNever appears in a URL
hrefstring, requiredpageid:<pageId> for a page; "" for a folderBlanked automatically on folders — see below
targetstring, requiredLink target; "" for a normal in-site link—
submenuarray, requiredChild items; [] for a leafA page item may not have children
icon + iconStylestring, optionalFont Awesome icon on the itemFolders carry no icon
expandedboolean, optionalFolder open by default—
disabledboolean, optionalRenders the item grayed out—
descriptionstring, optionalInternal note—

Three rules are enforced by the route rather than by convention, and each returns an error rather than silently doing something else:

  • A folder can never be a link. On every save to a docs-bound menu, stripFolderHrefs blanks the href of any item that has children. Sending a folder with an href is not an error — the href is simply discarded.
  • A page item may not have children. Sending one is a 400 with the message “A docs page item cannot have children — place pages inside folders instead”. This exists precisely because the previous rule would otherwise blank that page’s href and drop it out of the nav.
  • A documentation page may appear in exactly one docs left-nav menu, once. A duplicate inside the tree, or a page already carried by another docs menu, is a 409.

There is no order field on a menu item. Order is array order, top to bottom, at every level.

A two-level docs menu — one folder holding one page — looks like this. menuId travels as its own argument alongside items, not inside it:

{
  "menuId": "docs-left-nav",
  "items": [
    {
      "menuItemId": "folder-getting-started",
      "name": "Getting Started",
      "title": "Getting Started",
      "href": "",
      "target": "",
      "expanded": true,
      "submenu": [
        {
          "menuItemId": "page-install",
          "name": "Install the CLI",
          "title": "Install the CLI",
          "href": "pageid:9f1c0f5e-6b1a-4b2e-9a77-0c2d5a1f8e10",
          "target": "",
          "icon": "fa-solid fa-download",
          "iconStyle": "solid",
          "submenu": []
        }
      ]
    }
  ]
}

Publishing a menu is not an MCP action

The registry contains a publish_menu tool, but it is not exposed to MCP clients — an MCP connection is never shown it and cannot call it by name. Menus reach the live site through the deployments flow, which a person runs from the CMS. If you want the same tree edited by hand instead, Building and Editing a Menu is the screen, and Left Navigation Menu covers the docs-specific rules from the editor’s side.

Labels

Four tools. A label does three jobs at once in Leed — a taxonomy, a series, and an RBAC boundary — so read Labels and Series before reshaping them programmatically.

list_labels

GET /api/labels · Returns { labels, isDirty } · MCP only

Takes no parameters. isDirty is the whole label list’s flag, not per-label.

get_label

GET /api/labels/:labelId · Returns { label } · MCP only

ParameterTypeRequiredDefaultNotes
labelIdstringYes—From list_labels

update_label

PUT /api/labels/:labelId · Returns { label } · MCP only

ParameterTypeRequiredDefaultNotes
labelIdstringYes—Which label to edit
namestringNounchangedDisplay name
descriptionstringNounchanged—
visiblebooleanNounchangedWhether the label is shown on the public site
isSeriesbooleanNounchangedTurns the label into a multi-part series
seriesmultipartannouncementNounchanged
slugstringNounchangedThe label’s URL segment

Only the fields you send change. There is no create_label and no delete_label on the MCP surface.

list_label_users

GET /api/labels/:labelId/users · Returns { users: [{ userId, role }] } · MCP only

ParameterTypeRequiredDefaultNotes
labelIdstringYes—Which label to inspect

URL paths

Two read-only tools that answer “what lives where”.

list_paths

GET /api/paths · Returns { paths } · MCP only

ParameterTypeRequiredDefaultNotes
qstringNo—Free-text filter over the path text
tstringNoall typesComma-separated list of row types, e.g. alias or current,next

Each row carries id, pageId, path, type, title, createdAt and a cmsManaged flag. The type is the field that matters:

TypeMeaningCreated by
currentThe live URL of a published pagePublishing a page
nextA placeholder reserving a URL for a page that is not published yetCreating or moving an unpublished page, or a staged folder move
aliasA custom path that redirects to a pageAdding an alias in the CMS, or a page whose URL changed

A page that has moved typically owns several rows: one current at its new URL and one alias per old URL. URL Paths and Slugs is the full model.

resolve_path

GET /api/paths/lookup · Returns { pageId } (or { pageId: null }) · MCP only

ParameterTypeRequiredDefaultNotes
urlstringYes—A relative path or an absolute URL on your own domain

The reverse of list_paths, and the tool a model should reach for whenever it has a URL and needs a page. Anything that is not on your domain returns null rather than an error. Use it before writing a cross-link: a body should carry pageid:<id>, never a literal path, so the link survives the page moving.

Journey stages

Journey stages are the funnel bands Engage scores contacts into. Two tools, and the write is deliberately narrow.

list_journey_stages

GET /api/journeys · Returns { journeys } · MCP only

Takes no parameters.

update_journey_stage

PUT /api/journeys/:journeyId · Returns { journeys } — the whole list, re-saved · MCP only

ParameterTypeRequiredDefaultNotes
journeyIdstringYes—Which stage to edit
namestringNounchangedDisplay name of the stage
descriptionstringNounchanged—

The patch is merged into the matching stage; an unknown journeyId is a 404. The set of stages is fixed — there is no tool to add one, remove one or reorder them, over MCP or in the assistant. Renaming a stage does not re-score anybody. Journey Stages covers what the stages mean and why the Engage journey is not editable.

An autolink turns a phrase into a link to a page everywhere that phrase appears, at build time.

GET /api/autolinks · Returns { autolinks } · MCP only

Takes no parameters. Each entry carries autolinkId, text, an optional pageId and an optional pageCount — the number of pages the phrase matched on the last site build, which is a build statistic rather than something you set.

POST /api/autolinks · Returns { autolink, autolinks } · MCP only

ParameterTypeRequiredDefaultNotes
textstringYes—The phrase to match
pageIdstringNo—The page to link it to

The id is generated server-side. Autolinks are stored as one list per workspace, so a create reads the current list, appends, and re-saves the whole thing — which is why the response hands you both the new entry and the full list.

Autolinking is a Starter-and-up feature at build time, and phrase ordering and the per-page opt-out both change what actually gets linked — Autolinks covers both. If the tool name you came here for is not on this page, the Operator MCP Tool Index lists every tool alphabetically with the page that documents it.

ESC