# MCP tools for publication, backups, and undo

Publish draft configuration, inspect change history, restore saved states, and undo changes through MCP.

Available on the Grow, Scale, and Pro plans.

Publication changes the configuration served to your live website. Restoring and undoing replace the draft, not the live configuration. Confirm the project and intended change before calling a mutating operation.

## MCP publication access and version IDs

Every operation accepts an optional string `project_id` and follows the [shared MCP authorization and project-selection rules](https://rightmessage.com/help/mcp-authorization-reference). Missing project selection, invalid IDs, inaccessible projects, and unavailable MCP access return errors.

There are three different configuration identifiers:

- `version_id` identifies a backup snapshot returned by `list-config-versions`.
- `version_number` is that snapshot's display sequence, not an input ID.
- `published_config_id` identifies a published configuration returned in publication history or the `publishes` list.

Snapshots preserve configuration, not every account record. They do not undo integration connections, external provider writes, exports, stored personalized emails, or deleted split-test records.

Restores and undo must also respect running question-test locks. A replacement that changes a locked question's wording, options, display, behavior, segment values, or non-sync Auto-Segment rules is rejected. End the test and choose its winner before restoring conflicting configuration.

Examples are illustrative and were not executed. Requests show `tools/call` parameters. Responses show decoded JSON or plain text, not the MCP envelope.

## `publish-config`

Compiles and publishes the project's existing draft. This is the explicit live-site boundary.

| Argument                | Type    | Required | Default and behavior                                                               |
| ----------------------- | ------- | -------- | ---------------------------------------------------------------------------------- |
| `project_id`            | string  | No       | Active or eligible project.                                                        |
| `message`               | string  | No       | Publication note.                                                                  |
| `auto_generate_message` | boolean | No       | `false`; can derive a note from recent MCP snapshot actions when a note is needed. |
| `tabId`                 | string  | No       | Optional dashboard tab identifier used by publication notifications.               |

Automatic notes use up to 50 recent action records; this option does not ask an AI model to inspect the full configuration.

```json
{"name":"publish-config","arguments":{"project_id":"123456789","message":"Publish WorkForge welcome survey","auto_generate_message":false}}
```

```text
Configuration published successfully at 2026-10-13T12:00:00+00:00.
```

The response is text, not `{published_at: ...}`. The operation saves a snapshot, queues the draft, then compiles and publishes it. It can publish all pending draft changes, not only changes made by the calling assistant. Review the complete draft first.

No draft returns `No draft changes to publish.` Validation or compilation failures return errors. Concurrent experiment activation can return `experiment_activation_busy: ...`. Don't assume every failure means nothing changed. Inspect publication history and its live marker before retrying an uncertain result.

## `get-publish-history`

Lists recent publication records and identifies the currently live configuration.

**Arguments:** optional `project_id` string; optional `limit` number, default `10`, converted to an integer and clamped to `1`–`25`.

```json
{"name":"get-publish-history","arguments":{"project_id":"123456789","limit":5}}
```

```json
{"total_publishes":1,"last_published_at":"2026-10-13T12:00:00Z","history":[{"config_id":210,"published_at":"2026-10-13T12:00:00Z","message":"Publish WorkForge welcome survey","status":"published","is_live":true}]}
```

The envelope contains `total_publishes`, nullable `last_published_at`, and `history`. Each item contains `config_id`, `published_at`, `message`, `status`, and `is_live`. Queued-for-publication records can appear alongside published records. Use `is_live`, not list position or a timestamp alone, to identify the active configuration. This read does not publish or cancel pending work.

## `list-config-versions`

Lists recoverable configuration snapshots and, on the first page, recent published configurations.

| Argument     | Type    | Required | Default and limits                                    |
| ------------ | ------- | -------- | ----------------------------------------------------- |
| `project_id` | string  | No       | Active or eligible project.                           |
| `limit`      | integer | No       | `20`; nonpositive values reset to `20`; maximum `50`. |
| `offset`     | integer | No       | `0`; negative values become `0`.                      |

```json
{"name":"list-config-versions","arguments":{"project_id":"123456789","limit":20,"offset":0}}
```

Illustrative response with an empty history:

```json
{"versions":[],"total":0,"limit":20,"offset":0,"retention":{"keep_count":50,"daily_days":30},"publishes":[]}
```

Each `versions` item contains `id`, `version_number`, `source`, `source_detail`, `description`, `ai_description`, `checksum`, `created_by` (`{name,email}` or `null`), and `created_at`. Retention metadata reports the snapshot policy: keep-count `50` and daily history `30` days.

Only `offset: 0` adds `publishes`, up to 50 entries with `id`, `publish_message`, `published_at`, and `is_live`. This is metadata, not a full JSON backup payload. The operation does not create a new snapshot.

## `get-config-version-changes`

Explains the change associated with a pre-change snapshot by comparing it to the next saved state, or current configuration if no newer snapshot exists.

**Arguments:** optional `project_id` string; required `version_id` integer; optional `limit` integer, default `100`, maximum `200`, nonpositive values reset to `100`; optional `offset` integer, default `0`, clamped to at least `0`.

```json
{"name":"get-config-version-changes","arguments":{"project_id":"123456789","version_id":81,"limit":100,"offset":0}}
```

```json
{"version_id":81,"compared_to":{"type":"version","version_id":82},"changes":[{"path":"phrases[phr_example].fallbackText","type":"changed","before":"Welcome","after":"Welcome to WorkForge"}],"total":1,"limit":100,"offset":0}
```

`compared_to` is `{type:"version",version_id}`, `{type:"current"}`, or `null`. Changes contain `path` and `type`. Added/removed entries have `value`; changed entries have `before` and `after`.

This is a summarized diff. Strings have markup stripped and are truncated to 160 characters. Arrays are limited to five items, and objects retain selected identifying fields. Do not use these values as a restoration payload. There is no argument for choosing an arbitrary second version. Unknown or cross-project versions and unavailable stored payloads return errors. The read does not alter either state.

## `describe-config-version`

Returns a short AI-generated explanation of a snapshot's associated change.

**Arguments:** optional `project_id` string and required `version_id` integer.

```json
{"name":"describe-config-version","arguments":{"project_id":"123456789","version_id":81}}
```

```json
{"version_id":81,"description":"Via MCP, updated the default WorkForge welcome text.","stored":true}
```

The model receives up to 60 summarized changes. A saved description is reused. Descriptions are stored only when a newer snapshot makes the comparison final; a description of the latest still-changing draft can return `stored: false`. No differences or an AI-service failure can return `description: null`, `stored: false`.

This may call an AI service and persist description metadata. It does not restore, edit, or publish configuration. A nonexistent or inaccessible version returns an error.

## `restore-config-version`

Replaces the **entire draft** with a saved snapshot, including when that snapshot predates a publication.

**Arguments:** optional `project_id` string and required `version_id` integer.

```json
{"name":"restore-config-version","arguments":{"project_id":"123456789","version_id":81}}
```

Illustrative text response:

```text
Restored the draft to version 4 (from mcp (update-phrase), originally created at 2026-10-12T12:00:00+00:00). The live site remains unchanged until you publish again.
```

Get explicit approval for the target timestamp and summary first. Restoring can overwrite unrelated unsaved work. RightMessage saves a snapshot of the current draft before replacing it and notifies connected editors. This is not a selective restore of one phrase, flow, or campaign.

Unknown or cross-project IDs, missing configuration, unavailable archived payloads, and validation/storage failures return errors. No live change occurs until a separate successful `publish-config` call.

## `restore-published-config`

Copies a prior publication's full configuration into the draft.

**Arguments:** optional `project_id` string and required `published_config_id` integer.

```json
{"name":"restore-published-config","arguments":{"project_id":"123456789","published_config_id":205}}
```

Illustrative response excerpt:

```text
The live site remains unchanged until you publish again.
```

The full text identifies the restored publication and its timestamp. Only a project-owned published or queued-for-publication configuration can be selected. The current live configuration is rejected as a restoration target.

This destructively replaces the draft after saving a pre-restore snapshot. It does not switch the live-site pointer directly. Confirm the exact publication and review the resulting draft before publishing. Missing IDs, invalid status, unavailable payloads, and storage failures return errors.

## `undo-last-change`

Restores the most recent eligible non-undo snapshot associated with the current configuration.

**Arguments:** optional `project_id` string only. There is no count, resource ID, or cross-publication target argument.

```json
{"name":"undo-last-change","arguments":{"project_id":"123456789"}}
```

Illustrative response excerpt:

```text
Restored to version 4 (from mcp (update-phrase), created 1 hour ago).
```

The response identifies the restored version, source, description, and age where available. RightMessage saves a snapshot of the current state before replacing the draft. Undo does not necessarily reverse your last tool call. Other dashboard or assistant edits may be newer. It also does not restore a state across publications. Use a selected `version_id` when the target state matters.

No prior eligible snapshot returns an operation error. Undo remains a draft action and does not reverse publication, provider writes, account-record deletion, or other non-configuration side effects.
