MCP tools for Pages
Build, edit, style, personalize, and take down hosted landing pages from your AI assistant, with every argument, result, and error for the Pages MCP tools.
Ask your AI assistant to build a landing page from a brief, tighten its copy, add an audience for an ad campaign, or take it down, and it works on the same Pages you edit in the dashboard. These tools change drafts; your page goes live when you publish.
There's no REST API for Pages. The MCP tools below and the dashboard are the ways to work with them. The REST API's publish endpoint publishes page changes along with the rest of the project.
MCP page access and drafts
Pages is in early access. Every tool here is listed for every connection, but refuses projects without access with Pages are not available for this project yet. Projects in the early access program, and RightMessage admins, have access. To ask for it, email support@rightmessage.com.
Every tool accepts an optional string project_id and follows the shared MCP authorization and project-selection rules. Page IDs look like pg_…. An unknown ID returns Unknown page "<id>". Valid choices: …, listing up to 20 of the project's pages.
Every page and site style edit is saved as a new draft version, so get-page-history and restore-page-revision can undo it, and so can Version history in the dashboard. No tool here publishes. Use publish-config to make page changes live. Publishing pages needs the Scale or Pro plan; on another plan, the rest of the project publishes and page drafts are kept.
Three things take effect without a publish: unpublish-page, delete-page, and update-page-domains.
Writes that lose a race return a prefixed error and change nothing:
| Prefix | What happened |
|---|---|
stale_draft | The page changed after the version you sent. Read it again. |
element_changed | The element changed since seen_revision_id. The JSON result includes current_html, current_css, and head_revision_id. |
element_missing | The element is no longer on the page. |
nothing_to_undo, nothing_to_redo | There's no version to move to. |
out_of_scope | Righty was limited to a selected element and the call went beyond it. |
invalid, too_large | The HTML, CSS, or value was refused. The message lists why. |
Page HTML can't contain scripts or event handler attributes such as onclick. Forms go on a page through create-page-widget, and scripts are added by people in Page settings. No tool reads or writes scripts.
Examples are illustrative and use the fictional WorkForge project.
list-pages
Lists the project's pages. Takes only project_id.
Each page has page_id, name, path, status, live_url, and revision_id, the current draft version.
status | Meaning |
|---|---|
draft | Never published. Goes live on the next publish. |
live | Published, with no pending changes. |
changed | Published, with draft changes that go live on the next publish. |
offline | Unpublished. Held out of publishes until publish-config names it in include_page_ids. |
get-page
Reads one page.
| Argument | Type | Notes |
|---|---|---|
page_id | String, required | |
element_id | String | Adds that element's html and css. |
format | outline (default) or full | full adds the whole page html and css. |
The result includes revision_id, status, page_url (the page's address, known before its first publish), live_url, page_rule (the exact rule campaigns use for this page), settings, uses_site_styles and the page's own style tokens, the outline of addressable elements, hidden elements and unfilled placeholders, its form slots and widgets with their form goal selector, the campaigns that change the page, whether scripts are set (never their content), and the page's build.
build-page
Has Righty build a new page from a brief, the same way New page does. It takes a few minutes and returns straight away. Poll get-page-build every 20 to 30 seconds.
| Argument | Type | Notes |
|---|---|---|
name | String | New page. 1 to 120 characters. |
path | String | New page. / or up to five lowercase segments, like /offer or /guides/free-guide. |
brief | String | New page. Who it's for and what it should get them to do. Up to 4,000 characters. |
goal | Object | New page. kind is form, quiz, survey, or url. content_id picks an existing form (ofr_…) or flow (ofn_…); omit it to have the build create one. url is the https:// link for url. |
references | Array of URLs | Up to 3 pages to screenshot for their look. One that can't be captured is skipped. |
use_site_styles | Boolean | Default true. false lets the build design the page's own look. |
clarifications | Object | The questions get-page-questions returned, with the user's answers filled in. |
page_id and resume | String and boolean | Start an existing page's waiting build, or continue a stopped or failed one. |
The result includes page_id, build_id, status: "running", page_url, page_rule, and any skipped_references. Unlike a build from the dashboard, a build through MCP stops at the page. It doesn't set up audiences or A/B tests, and a new quiz or survey it adds to the page stays empty. Its summary lists the audiences and tests the brief asked for, so you can add them with the tools below and build the flow with the flow tools.
get-page-questions
Asks Righty what it would like to know before building a page. It takes the same brief, goal, references, use_site_styles, and name as build-page, and creates nothing.
The result has questions and next. Show the questions to the user, fill in their answers, and pass the whole object to build-page as clarifications. Every question is optional. With no questions, next says to build without clarifications.
get-page-build
Reads a build's progress. Pass build_id from build-page, or page_id for the page's latest build.
The result has status (running, completed, stopped, failed, or failed_system), the current stage, labeled steps, the built sections, the number of placeholders left to fill, and resumable. A resumable build can continue with build-page page_id and resume: true.
create-page
Creates a draft page from your own HTML and CSS, or copies a page.
| Argument | Type | Notes |
|---|---|---|
name | String, required | 1 to 120 characters. |
path | String, required | / or up to five lowercase segments, as for build-page. Unique in the project. |
html, css | Strings | The page body and its CSS. Give sections ids such as data-rm-id="hero". |
copy_from | String | A page to copy instead, with its forms and look. Not with html and css. |
use_site_styles | Boolean | Default true. Not with copy_from. |
Returns page_id, name, path, revision_id, and uses_site_styles, plus widget_ids for a copy.
update-page
Changes a page's search and sharing settings, or replaces its whole HTML and CSS. Send one or the other.
settingsacceptstitle(up to 120 characters),description(up to 320),socialImageandfavicon(usf://media orhttps://),canonical(anhttps://URL),lang, andnoindex.htmlandcssreplace the page body, withexpect_revision_idset to the page's current version.
update-page-element
Changes one element, named by its data-rm-id. Every element on a page has one, and campaign changes target elements by it, so ids stay the same across edits.
operation | What it does |
|---|---|
set_text | Replace the element's text with inline HTML: bold, italic, underline, strikethrough, links, and similar. |
set_image | Set src (a usf:// media library image) and alt. |
set_css | Replace the element's CSS rules. |
replace | Replace the element's HTML and CSS. |
hide, show | Hide or show it on the page. |
remove, duplicate | Remove or duplicate it. |
move | Move it before or after target_id, or prepend or append it inside. It keeps its ids. |
insert_before, insert_after | Add new HTML just before or after element_id. |
prepend, append | Add new HTML at the start or end of element_id, or of the page when you leave element_id out. |
Every operation except the inserts needs seen_revision_id, the version you last read. The result has the new revision_id, the before_revision_id, the element_id, and, when the edit removed elements that campaign changes target, orphaned_changes listing those changes.
generate-page-image
Generates an image for one element and saves it to the media library. It takes 10 to 60 seconds, and if generation fails nothing changes.
| Argument | Notes |
|---|---|
page_id, element_id, seen_revision_id | Required. |
prompt | Required. Up to 900 characters. |
alt | Required. Up to 150 characters. |
style | Required. photo, illustration, or abstract. |
aspect_ratio | Required. 1:1, 4:3, 3:2, 16:9, 21:9, 3:4, 2:3, or 4:5. |
placement | hero (1,600 pixels wide), beside (1,200, the default), or card (800). |
Generated images never show text, logos, software screens, or people presented as customers.
check-page-layout
Renders a page at 1,280, 768, and 375 pixels wide and reports anything wider than the screen, with the offending element ids and screenshot links. Pass page_id, and optionally a revision_id to check an earlier version. rendered: false means the page couldn't be rendered, not that its layout is wrong.
create-page-widget
Puts a form (ofr_…) or flow (ofn_…) on a page. Pass page_id and content_id. It creates an Embedded widget with the Unstyled theme that the page owns and styles with its CSS, and that doesn't appear in the Widgets list. Place the returned slot_html on the page with update-page-element. The widget is a draft change until you publish.
get-page-history
Lists versions of a page (page_id) or of the site styles (site_styles: true), newest first. limit is 1 to 100 (default 20), and before pages back from a version number.
Each version has revision_id, number, source, summary, and by (a person's name or Righty). The result also says whether undo and redo are available.
restore-page-revision
Undoes, redoes, or restores a version of a page or the site styles. Send action (undo, redo, or restore), expect_revision_id (the current version), revision_id for a restore, and page_id or site_styles: true. Each action adds a new version, so nothing is lost. Scripts and the page's address never change.
update-page-address
Renames a page or moves it to a new path. If the move means a campaign stops covering the page, or a running A/B test would restart, the result starts Nothing was saved. and explains why. Call again with confirm: true to go ahead. Campaign page rules that match the page exactly move with it. Once you publish, the old address redirects to the new one.
delete-page
Deletes a page with its version history and the widgets it owns. A published page goes offline at once, and you can't undo it. Pass delete_campaign_id to also delete the campaign made for the page. Righty asks you to approve a delete first.
unpublish-page
Takes a live page offline. Its address stops serving within a minute, without a publish. The draft is kept, and the page stays out of later publishes until publish-config names it in include_page_ids. Returns status: "offline".
get-site-styles
Reads the site styles your pages share: tokens, dark_tokens (null without a dark palette), the site css, and the revision_id to send when you update them.
| Token | What it sets |
|---|---|
colorPage, colorText | Page background and text |
colorBrand, colorAccent | Brand and accent colors |
colorButton, colorButtonText | Button fill and text |
fontHeading, fontBody | Heading and body fonts |
radius | Corner radius |
logo, favicon | Images, as usf:// media or https:// URLs |
update-site-styles
Changes the site styles. Send exactly one of:
tokens, merged into the current ones. Inside it,dark: {}makes a dark palette from the light colors,dark: {…}changes some dark colors, anddark: nullremoves it.css_block(ownerandcss) withseen_revision_id, to replace one block of the site CSS.csswithexpect_revision_id, to replace the whole site CSS.
Pages with their own look never use the site styles.
update-page-style
Switches a page between the site styles and its own look. use_site_styles: false copies the current site styles into the page's own look, and true drops it. tokens changes the page's own look, including its dark palette.
recapture-site-styles
Reads your website's colors, fonts, and corner radius again into the site styles draft. The logo, favicon, and site CSS stay. It needs a website in your project settings and runs at most once a minute. It returns status: "capturing" straight away, including when a capture is already running; read the result with get-site-styles about a minute later.
get-page-domains
Reads where your pages live: the slug, the subdomain_host (like workforge.rightmessage.page), the serving_host, and any custom_domain with its status, problem, the CNAME dns_record to add, and check times. Custom domain statuses are pending_dns, pending_certificate, active, and failed. This is Settings › Page domains, not your website's domains.
update-page-domains
Changes where your pages live, straight away and without a publish. Campaign page rules follow.
action | Argument | What it does |
|---|---|---|
change_slug | slug | Picks a new subdomain. The old one redirects. |
add_custom_domain | hostname | Adds a subdomain you own, like go.workforge.com. One per project. |
check_custom_domain | Checks DNS and the certificate now. | |
remove_custom_domain | Disconnects it. Your pages move back to the subdomain. |
create-page-audience
Adds an audience to a page's campaign, creating the campaign the first time. Pass page_id with either segment_ids or link (name, parameter, an operator of equals, contains, or starts with, and value), which makes a new "Visitors from a link" segment. name and campaign_id are optional.
A new page campaign takes the page's name and address, holds back 10% of visitors to measure lift, and uses the page's form as its goal when there is one. Change the audience's content with set-audience-changes. Without the Scale plan, plan_note says the setup is saved but won't go live until the project upgrades.
update-page-audience
Renames an audience on a page (name) or retargets it (segment_ids or link). Pass page_id and audience_id (var_…). An audience whose test is running can't change until the test ends.
create-page-test
Sets up an A/B test of the page for everyone (leave out audience_id, or send "original") or of one audience's version. campaign_id picks another campaign on the page; it defaults to the audience's campaign, or to the page campaign, created if needed. An existing setup comes back as it is. For a campaign without goals, form_goal: true measures form submissions on the page. Start the test with start-audience-test and publish. Starting a test requires Pro; on another plan, plan_note says the setup is saved in the draft. A test already running live refuses: End the running page test first. for the page, or End the running test for this audience first. for an audience.