Tools
The tools the Surface MCP server offers, with their arguments, results and errors.
Every tool takes a surface_id — never a content source id. Results are scoped to the key
holder's workspace: another workspace's surface reads as not found. No tool deletes anything;
archive instead, or use the dashboard.
surface_list
List surfaces. Every surface in the key holder's organization.
No arguments.
Returns { surfaces: Surface[] }
surface_get
Get a surface. Full details for one surface, including its edge_url and dashboard_url. To open the surface in the dashboard, open dashboard_url.
| Argument | Type | Required | Description |
|---|---|---|---|
surface_id | integer | Yes | The surface id, from surface_list. |
Returns { surface: Surface, dashboard_url: string }
Errors SURFACE_NOT_FOUND, INVALID_ARGUMENTS
{
"surface_id": 52
}surface_create
Create a surface. Creates the surface and its content source. Add content with variant_create.
| Argument | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Unique within the organization. |
page_url | string | Yes | The page the surface appears on. |
paradigm | RANKING | VARIANT_SELECTION | Yes | How variants are chosen. |
description | string | No | Free text. |
Returns { surface: Surface, dashboard_url: string }
Errors PLAN_LIMIT_REACHED, INVALID_ARGUMENTS
{
"name": "Homepage hero",
"page_url": "https://example.com/",
"paradigm": "VARIANT_SELECTION"
}surface_setup
Set up a surface on a page. One step from a page to a deployed surface: the fields variants replace, the goals to optimize, and the variants, with the integration bundle built and deployed. Variants are active; nothing shows until the snippet is on the page. The setup_surface prompt walks an agent through it.
| Argument | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Unique within the organization. |
page_url | string | Yes | The live URL of the page. |
fields | { key, selector, value_type, description? }[] | Yes | Keys match ^[a-z][a-z0-9_]*$. value_type: text | html | image | video | input_value. |
goals | { name, selector, dom_event }[] | Yes | dom_event: click | submit. The first is the one the bandit optimizes. |
variants | { contents, is_control? }[] | Yes | At least two; exactly one control, setting every field. |
description | string | No | Free text. |
Returns { surface: Surface, dashboard_url: string, variants: Variant[], events: string[], install_guide: string }
Errors PLAN_LIMIT_REACHED, INVALID_ARGUMENTS, SETUP_FAILED
{
"name": "Pricing hero",
"page_url": "https://example.com/pricing",
"fields": [
{
"key": "headline",
"selector": "[data-surface-field=\"headline\"]",
"value_type": "text"
}
],
"goals": [
{
"name": "Book a demo",
"selector": "[data-surface-goal=\"book_demo\"]",
"dom_event": "click"
}
],
"variants": [
{
"contents": {
"headline": "Pricing"
},
"is_control": true
},
{
"contents": {
"headline": "Plans that pay for themselves"
}
}
]
}surface_update
Update a surface. Change one or more fields. Only the fields listed here are writable.
| Argument | Type | Required | Description |
|---|---|---|---|
surface_id | integer | Yes | The surface id, from surface_list. |
name | string | No | Unique within the organization. |
description | string | No | Free text. |
status | ACTIVE | ARCHIVED | No | Archive to stop serving. |
paradigm | RANKING | VARIANT_SELECTION | No | How variants are chosen. |
edge_route | string | No | The /api/<route> the surface serves on. |
page_url | string | No | The page the surface appears on. |
location | WORLDWIDE | UNITED_STATES | EUROPE | ASIA_PACIFIC | No | Serving region. |
Returns { surface: Surface }
Errors SURFACE_NOT_FOUND, INVALID_ARGUMENTS — also when no field is given
{
"surface_id": 52,
"description": "Updated from Claude Code"
}variant_list
List variants. The content variants a surface serves.
| Argument | Type | Required | Description |
|---|---|---|---|
surface_id | integer | Yes | The surface id, from surface_list. |
Returns { variants: Variant[] }
Errors SURFACE_NOT_FOUND
{
"surface_id": 52
}variant_create
Create variants. Adds variants as DRAFT. Fields other than is_control and segment_id are stored as the variant's content.
| Argument | Type | Required | Description |
|---|---|---|---|
surface_id | integer | Yes | The surface id, from surface_list. |
variants | object[] | Yes | At least one. Optional is_control (one per segment) and segment_id. |
Returns { variants: Variant[] } — the surface's full list
Errors MULTI_SURFACE_SOURCE, SURFACE_NOT_FOUND, INVALID_ARGUMENTS
{
"surface_id": 52,
"variants": [
{
"headline": "Ship faster"
},
{
"headline": "Launch today"
}
]
}variant_update
Edit a draft variant. Replace a draft variant's contents. Only drafts can be edited.
| Argument | Type | Required | Description |
|---|---|---|---|
surface_id | integer | Yes | The surface id, from surface_list. |
variant_id | integer | Yes | The variant id, from variant_list. |
contents | object | Yes | The new contents, in the shape variant_create takes. |
Returns { variant: Variant }
Errors VARIANT_NOT_FOUND, INVALID_ARGUMENTS — e.g. the variant isn't a draft
{
"surface_id": 52,
"variant_id": 300,
"contents": {
"headline": "Ship faster"
}
}variant_set_status
Set a variant's status. Activate, pause or archive a variant. Only active variants are served. Same rules as the dashboard.
| Argument | Type | Required | Description |
|---|---|---|---|
surface_id | integer | Yes | The surface id, from surface_list. |
variant_id | integer | Yes | The variant id, from variant_list. |
status | ACTIVE | PAUSED | ARCHIVED | Yes | The new status. |
Returns { variant: Variant }
Errors VARIANT_NOT_FOUND, MULTI_SURFACE_SOURCE, INVALID_ARGUMENTS
{
"surface_id": 52,
"variant_id": 300,
"status": "ACTIVE"
}variant_set_control
Set the control variant. Make a variant the control of its segment, replacing the current control.
| Argument | Type | Required | Description |
|---|---|---|---|
surface_id | integer | Yes | The surface id, from surface_list. |
variant_id | integer | Yes | The variant id, from variant_list. |
Returns { variant: Variant }
Errors VARIANT_NOT_FOUND, INVALID_ARGUMENTS — archived target, or no control to swap
{
"surface_id": 52,
"variant_id": 301
}