Skip to main content

Tools reference

The Control MCP server has 18 tools. Your assistant chooses which to call from your request, so you don't normally name them. This page is for checking what an assistant can do, reading what it did, or building your own client.

Every tool runs as the signed-in user, inside the projects that user can edit. Each one tells your client what kind of action it is, so the client can let reads through and ask you before changes:

KindMeaning
ReadOnly reads. Changes nothing.
AddsCreates something new and leaves existing content alone.
ChangesOverwrites or removes something that already exists.

All tools​

ToolWhat it doesKind
list_projectsLists the projects you can edit, with their site address and collections.Read
list_collectionsLists a project's collections.Read
get_collection_content_typesDescribes what a post of a collection can hold.Read
list_postsLists a collection's posts, newest first.Read
get_post_contentReads one post: header, body blocks and status.Read
create_postCreates a post in a collection, in one call.Adds
create_collectionCreates a collection and its template, optionally with a first post.Adds
add_post_blocksAdds blocks to a post's body at a chosen position.Adds
update_text_blockRewords a text or quote block.Changes
update_image_blockChanges the images, alt text or caption of an image block or gallery.Changes
delete_post_blocksDeletes blocks from a post's body.Changes
update_postChanges a post's title, subtitle, date or key image.Changes
update_post_settingsChanges a post's slug, or whether the website includes it.Changes
delete_postDeletes a whole post.Changes
request_asset_uploadCreates a short-lived link for uploading your own images.Adds
check_asset_uploadLists the images that reached an upload link.Read
publish_websitePublishes the project's website.Changes
get_publish_statusTells whether the latest publish has reached the site.Read
Everything works on the editor's version

Creating, editing and deleting change what you see in the Control editor, exactly as if you'd done it there. None of it reaches your live site until the website is published, either from the editor or with publish_website when you ask for it.

Every tool answers with JSON. When a tool refuses a request (a slug that's taken, a block that's locked, a project you can't access), the answer says why and what to do instead, so your assistant can correct itself or tell you.


Projects and collections​

list_projects​

Read. Lists the projects you can edit. Many projects have no title, so each one also comes with its site address and domains. "My portfolio at example.com" is enough for your assistant to find the right one.

Parameters: none.

Returns a list of projects:

FieldDescription
idThe project's id, which every other tool takes as projectId.
titleThe project's title. Often empty.
descriptionThe project's description.
urlThe site's main address, e.g. https://example.com.
domainsThe site's active domains, or its *.cntrl.site address if it has none.
pagesCountHow many pages the project has.
collectionsThe project's collections, as { id, name }.

list_collections​

Read. Lists a project's collections. A collection is a family of posts that share one template, such as a blog, a set of case studies or a changelog.

ParameterTypeRequiredDescription
projectIdstringYesThe project, from list_projects.

Returns a list of { id, name }.

get_collection_content_types​

Read. Describes what a post of the collection can hold. Assistants call it before creating a post.

ParameterTypeRequiredDescription
projectIdstringYesThe project.
collectionIdstringYesThe collection, from list_collections.

Returns:

FieldDescription
headerWhich header elements the collection's posts show: title (always), subtitle, keyImage, and date with its format when posts show one. Missing when the template has no header.
presetsThe text preset ids the body can use, such as heading, body or caption.
bodyThe blocks in the template, in order. Each is text (with its preset), quote, image, date (with its format) or other (design blocks such as dividers, components and videos). Content blocks carry a key, the name a page component (for example a grid of posts) uses to show that field.

The body is a list of what's available, not an outline to follow. See Templates aren't forms.


Reading posts​

list_posts​

Read. Lists a collection's posts, newest first.

ParameterTypeRequiredDescription
projectIdstringYesThe project.
collectionIdstringYesThe collection.

Returns a list of { id, title, slug }. title is the name the dashboard lists the post by. Pass id as postId to the other post tools.

get_post_content​

Read. Reads one post in the same shape create_post takes, with an id on every body block so the post can be edited. It reads the editor's version, so it can include changes that aren't live yet. It reads the post as a visitor on your largest layout would see it: hidden and empty content is left out.

ParameterTypeRequiredDescription
projectIdstringYesThe project.
postIdstringYesThe post's id from list_posts.

Returns:

FieldDescription
id, slugThe post's id and address.
titleThe title its header shows.
pageTitleThe title the dashboard lists it by, which can differ.
statuslive if the website includes the post, draft if it leaves it out.
subtitle, date, keyImageThe header elements it shows. date is { date, format }. keyImage is { url, altText, caption }.
bodyThe body blocks, top to bottom, each with an id: text (preset, text), quote, image (urls, altText, caption), date, video, code (code, language) and table (header, rows). Design blocks come as other with their blockType.
elementsText, images and videos placed freely on the post rather than in its body, top to bottom.

Text comes as plain text, without formatting or links.


Creating​

create_post​

Adds. Creates one post in a collection, header and body, in a single call. The post reads in the order you give its blocks. Each block takes the styling of a matching block in the template where there's one free, and is added new where there isn't.

ParameterTypeRequiredDescription
projectIdstringYesThe project.
collectionIdstringYesThe collection.
titlestringYesThe post's title, up to 200 characters. Shown in its header and used as its page title.
subtitlestringNoShown under the title. Leave it out and the header hides it.
dateobjectNo{ date?, format? }. {} shows the day the post is created; date is YYYY-MM-DD. See Dates.
keyImageobjectNo{ sourceUrl, altText?, caption? }, the header's picture. Leave it out and the header uses its text-only layout.
bodyBlock[]YesThe blocks under the header, top to bottom. Pass [] for a post that's only its header. See Blocks.
slugstringNoThe post's address, lowercase words joined by hyphens. Leave it out to generate one; you can rename it in the editor.

The template's text, quote and image blocks that the post doesn't use are removed. Its design blocks (dividers, components, videos, a date in the body) stay, and delete_post_blocks can remove them.

Returns { pageId, articleId, slug }. pageId is the post's id for the other post tools.

create_collection​

Adds. Creates a collection, with a template written in the same shape as a post. Every future post of the collection starts from this template, so assistants are told to add posts to an existing collection whenever one fits.

ParameterTypeRequiredDescription
projectIdstringYesThe project.
namestringYesThe collection's name, up to 120 characters.
templateobjectYesThe header elements and body every post starts from, shaped like create_post's fields (title optional). A subtitle or keyImage given here is shown with placeholder content; one left out is hidden. A date here gives every post a date. Text blocks use the default presets: title, subtitle, heading, subheading, lead, body, caption, footnote.
firstPostobjectNoA first post to create in the same call, shaped like create_post's fields, slug included.

Returns { collectionId, templateArticleId }, plus firstPost when one was created. If the first post's slug is taken, or it uses a preset outside the defaults, nothing is created.

add_post_blocks​

Adds. Adds blocks to an existing post's body and leaves the rest as it is. It takes text, quote, image and date blocks, but not code, table or video blocks.

ParameterTypeRequiredDescription
projectIdstringYesThe project.
postIdstringYesThe post.
blocksBlock[]YesThe blocks to add, in reading order, as in create_post's body.
indexintegerNoThe position in the body, counted as get_post_content shows it. The new blocks go before the block now at that position; 0 is the top. Leave it out to add them at the bottom.

To add images to a gallery that's already in the post, use update_image_block.

Returns the post as it now stands, in the shape of get_post_content.


Editing​

update_text_block​

Changes. Rewords a text or quote block. The block keeps its place, preset and block styling.

ParameterTypeRequiredDescription
projectIdstringYesThe project.
postIdstringYesThe post.
blockIdstringYesThe block's id from get_post_content.
textstringYesThe block's whole new text, plain. Separate paragraphs with a blank line.
caution

Links and formatting set on individual words (bold, a color, a different font) are lost when a block is reworded. Assistants are told to warn you. Make the change in the editor if you need to keep them.

Returns the post as it now stands.

update_image_block​

Changes. Changes the images, alt text or caption of an image block or gallery. Only what you name changes; the block keeps its place and styling.

ParameterTypeRequiredDescription
projectIdstringYesThe project.
postIdstringYesThe post.
blockIdstringYesThe image block's id from get_post_content.
sourceUrlsstring[]NoThe images the block should hold, in order, up to 10: existing URLs from get_post_content, URLs from an upload link, or public https images. To add one image, pass the current list with the new one where it belongs. An image left out is removed.
altTextstringNoThe alt text the block's images share.
captionstringNoThe caption they share. An empty string clears it.

More images than fit one row continue in new image blocks right under this one, as they would in a new post.

Returns the post as it now stands.

delete_post_blocks​

Changes. Deletes blocks from a post's body, design blocks included. It's all or nothing: if one id isn't in the body, or a block is locked in the editor, nothing is deleted.

ParameterTypeRequiredDescription
projectIdstringYesThe project.
postIdstringYesThe post.
blockIdsstring[]YesThe ids of the blocks to delete, from get_post_content.

The header (title, subtitle, date, key image) can't be deleted this way; use update_post. Code, table, video and design blocks can't be added back by any tool, so assistants delete them only when you ask.

Returns the post as it now stands.

update_post​

Changes. Changes a post's header. Only what you name changes; the body isn't touched.

ParameterTypeRequiredDescription
projectIdstringYesThe project.
postIdstringYesThe post.
titlestringNoThe title in the header, also used as the page title.
subtitlestring or nullNoSets the subtitle and shows it. null clears and hides it.
dateobjectNo{ date?, format? }. A date the collection hides stays hidden.
keyImageobject or nullNo{ sourceUrl, altText?, caption? } sets the key image and shows it. null clears and hides it.

A subtitle or key image you hid on some layouts in the editor stays hidden there.

Returns the post as it now stands.

update_post_settings​

Changes. Changes a post's address, or whether the website includes it.

ParameterTypeRequiredDescription
projectIdstringYesThe project.
postIdstringYesThe post.
slugstringNoThe post's new address. Once published, links to the old address stop working. Refused if another page of the project already uses it.
statuslive or draftNodraft leaves the post off the website and live includes it, like Draft and Set Live in the editor. New posts are live.

Both take effect on the site the next time it's published.

Returns { id, title, slug, status }.

delete_post​

Changes. Deletes a whole post. Assistants are told to delete a post only when you ask, and to name it back to you first unless you named it exactly.

ParameterTypeRequiredDescription
projectIdstringYesThe project.
postIdstringYesThe post.

A post that was published stays on the live site until the next publish. Until then, Revert in the dashboard can bring it back, but it also undoes every other unpublished change. A post that was never published can't be brought back.

Returns { id, title, slug } of the deleted post.


Images​

See Adding images for how the two ways of adding images work.

request_asset_upload​

Adds. Creates a short-lived upload link for images on your device or attached in the chat. It returns two addresses for the same link:

  • uploadUrl, a page you open in any browser (your phone works too) and drop images onto.
  • fileUploadUrl, for assistants that can run commands and read files. They send one file per request as a multipart POST with the file in a field named file.
ParameterTypeRequiredDescription
projectIdstringYesThe project the images are for.

Links expire after 15 minutes and take up to 10 images of up to 20 MB each, as JPEG, PNG, WebP, AVIF or GIF.

Returns { ticketId, uploadUrl, fileUploadUrl, expiresAt, maxFiles }.

check_asset_upload​

Read. Lists the images that have reached an upload link so far, by either route. Assistants call it after you say you're done.

ParameterTypeRequiredDescription
ticketIdstringYesThe ticketId from request_asset_upload.

Returns { status, assets, expiresAt }. status is pending until at least one image arrives, then uploaded, or expired if the link expired empty. assets is a list of { url, name }, and each url can go anywhere an image goes. Results stay readable for about a day after the link expires.


Publishing​

publish_website​

Changes. Publishes the project's website, like the Publish button. Every unpublished change in the project goes live, including changes you or your team made in the editor. Assistants are told to call it only when you ask or accept their offer to publish.

ParameterTypeRequiredDescription
projectIdstringYesThe project.

Returns { status }, and webhookFailed: true when the project's webhook couldn't be reached:

  • building: Control is building the site, which still shows the old version until it finishes. Follow with get_publish_status.
  • published: the site runs on your own hosting, which picks the changes up itself. There's nothing to wait for.

Each call cancels a build that's still running and starts a new one. A project can be published at most 5 times a minute.

get_publish_status​

Read. Tells whether the latest publish has reached the site. While a build runs, it waits up to 20 seconds for it to finish before answering, so assistants can call it again straight away.

ParameterTypeRequiredDescription
projectIdstringYesThe project.

Returns { status }:

  • building: still running. The site shows the old version.
  • published: done. The changes are live.
  • failed: the changes didn't reach the site, or that couldn't be confirmed. Check the build logs and rebuild from the dashboard.
  • none: no recent publish to report.

A publish usually takes a few minutes, and longer the first time a site is published.