🧪 Audit method. Live capability test of the Webflow MCP server (bothclaude.ai Webflowandwebflow_mcp_testinstallations -- schemas are identical) against the Collection Tests site (id628848057f4f99d7ae0b8128). Each capability was either exercised (called with real arguments and the result observed) or spec-only (schema present but not exercised live). Reference docs used: Webflow Data API v2.0.0 + Webflow Designer Extension API documentation. Test date 2026-05-10.
Two transports, very different prerequisites
The Webflow MCP exposes two separate surfaces that behave nothing like each other operationally.
| Surface | Auth | Designer must be open | Stability | Best for |
|---|---|---|---|---|
| Data tools (REST) | Site / workspace token | No | Stable, fast | CMS, scripts, webhooks, page settings, publishing |
| Designer tools (UI bridge) | App linked into Designer | Yes -- user clicks launch link | Sensitive to tab focus and parallel calls | Building/modifying canvas, classes, variables, components |
⚠️ Designer prerequisite. Every Designer-tool call returns a hard error containing the launch URL until the user clicks it (https://.design.webflow.com?app= ) and brings the Designer tab to the foreground. The bridge then drops if the tab loses focus or if multiple Designer tools are called in parallel. This is the single biggest UX gotcha. There is no headless mode.TL;DR -- The headlines
- The MCP is a curated subset of the public APIs, not a 1:1 wrapper. It gives you the Webflow primitives most often needed for content automation and AI-assisted design -- but Forms, Ecommerce, Memberships, asset upload, interactions/animations, page deletion, and most workspace-level actions are simply absent.
- Component definitions cannot be created from scratch by either API. The only way is
transform_element_to_component-- convert an existing canvas element. Component properties (the named slots/variables that make a component reusable) cannot be defined or overridden via the MCP at all. - Interactions / Animations / Page Transitions are completely missing from both transports. The Webflow Designer's interactions panel is not addressable through the MCP at all.
- Asset binary upload is missing. You can rename, retag, foldering, but no upload tool exists in either transport.
- A real bug: every Data-API endpoint that returns
204 No Content(item delete, field delete, webhook delete) reports"undefined" is not valid JSON-- even though the call succeeded. Verify by re-listing. - Localization requires secondary locales to already exist. The Data API explicitly rejects calls with the primary locale ID:
"The provided locale must be a secondary locale."Without a configured secondary locale you cannot exercise the localization endpoints. - CMS Collection element is a hollow shell on the Designer side. You can create the wrapper, but cannot bind it to a collection or add an Item template -- dynamic CMS templating cannot be built via the MCP.
Coverage map at a glance
| Capability area | Data API | Designer | Notes |
|---|---|---|---|
| Sites -- list, get, publish | ✅ | n/a | Cannot create/duplicate/delete a site |
| CMS -- collections create/get/list | ✅ | n/a | No collection delete/rename/duplicate |
| CMS -- fields (16 types) create/update/delete | ✅ | n/a | Update only changes name/help/required; cannot change type or option choices or reference target |
| CMS -- items create/list/update/archive/publish/delete | ✅ | n/a | Publish blocked until site is first whole-site published |
| CMS items -- separate live vs staged endpoints | ⚠️ | n/a | Only the staged path is exposed; can't create-and-publish in one call |
| Pages -- list, metadata, settings, content (text + props) | ✅ | partial | Designer creates/switches; no delete/duplicate |
| Components -- list, content, properties (read + per-locale write) | ✅ | ✅ | Definitions only via transform_element_to_component; no prop API |
| Elements -- read, query, create (32 types), modify, delete | n/a | ✅ | Form fields placement-restricted; CMS collection child Heading rejected |
| Styles -- class, combo, breakpoints (7), pseudo (16), variable-as-value | n/a | ✅ | Type compatibility enforced (Size cannot bind to padding) |
| Variables -- collections, modes, 5 types, alias, custom CSS | n/a | ✅ | Rename and delete are BETA and silently no-op in our tests |
| Assets -- list, folders, update meta | partial | partial | No upload, no delete, no folder delete/rename |
| Custom code -- register inline, apply to page | partial | n/a | No hosted-URL register; no site-level apply; only delete-all per page/site |
| Webhooks -- CRUD (17 trigger types) | ✅ | n/a | get_webhook doesn't include lastTriggered |
| Comments -- read threads/replies | ✅ | n/a | Read-only by design |
| Enterprise -- 301s, robots.txt, well-known, activity logs | ✅ (plan-gated) | n/a | Returns plan error on non-Enterprise sites |
| Localization -- secondary-locale content + property edits | ✅ | n/a | Primary locale ID is explicitly rejected |
| Forms (read submissions, list forms) | ❌ | ❌ | Entirely missing |
| Ecommerce (products, orders, inventory) | ❌ | n/a | Entirely missing |
| Users / Memberships | ❌ | n/a | Entirely missing |
| Interactions / Animations / Page Transitions | ❌ | ❌ | Not addressable at all |
| Backups, branches, versioning | ❌ | ❌ | UI only |
| Site-level SEO defaults / sitemap / favicon / 404 | ❌ | n/a | Missing |
| Workspace (sites: create, duplicate, delete, transfer) | ❌ | n/a | Missing |
CMS -- Data API surface
Collections
| Action | Status | Notes |
|---|---|---|
get_collection_list | ✅ | Lite list -- no field schema |
get_collection_details | ✅ | Full schema with field types, ids, validations |
create_collection | ✅ | Auto-creates Name (required) and Slug (required, regex-validated) fields |
| delete_collection | ❌ | Webflow REST supports it; MCP omits it |
| rename_collection / change_slug | ❌ | No tool |
| duplicate_collection | ❌ | Manual: read + create + for-each-field + for-each-item |
Field types -- confirmed creatable (16)
PlainText, RichText, Number, Color, DateTime, Email, Phone, Link, VideoLink, Switch, Image, MultiImage, File (via create_collection_static_field); Option (single-select via create_collection_option_field); Reference, MultiReference (via create_collection_reference_field).
Field types not supported via the MCP
Set(multi-select / multi-option)- Ecommerce-specific (
SkuValues,SkuProperties, currency/price) - Membership-specific (
User)
Field-level operations
| Action | Status | Notes |
|---|---|---|
update_collection_field | ✅ | Only changes displayName / helpText / isRequired. Cannot change field type, option list, reference target, number precision. |
delete_collection_field | ⚠️ bug | Returns "undefined" is not valid JSON" -- but the field is deleted (verified) |
Items
| Action | Status | Notes |
|---|---|---|
create_collection_items | ✅ (staged) | Always staged regardless of isDraft:false. No create_item_live exposed. |
list_collection_items | ✅ | limit, offset, name, slug, sortBy, sortOrder, cmsLocaleId. No filter by field value or lastPublished range. |
update_collection_items | ✅ | Bulk array. isArchived, isDraft fields editable. Bad references → 400 |
publish_collection_items | ⚠️ conditional | 409 Conflict: "The site is not published." until the site has been whole-site published once |
delete_collection_items | ⚠️ bug | Same 204 parse error; deletion did happen |
| unpublish_collection_items | ❌ | REST has DELETE /items/live; MCP doesn't expose it |
Field-value gotchas observed
VideoLinkis asymmetric: write"https://youtu.be/...", server stores a structured object includingmetadata.html(embedly iframe),thumb,aspectRatio,videoIdetc. Diff tools must normalise.Optionrequires the option ID (not the name) when writing items.update_collection_itemsrequiresnameandsluginfieldDataeven on partial field updates.- Every item carries a
cmsLocaleIdeven on single-locale sites (the primary locale's id) -- butget_sitedoes not return alocalesarray on single-locale workspaces, so the only way to discover the primary id is to read any item or to receive an error from a localized endpoint.
Pages & Components -- Data API
Pages
| Action | Status | Notes |
|---|---|---|
list_pages | ✅ | Includes collectionId for CMS template pages, publishedPath, branching flags |
get_page_metadata | ✅ | |
get_page_content | ✅ | Returns flat nodes[] of text/image/etc. -- 121 nodes on the test home page |
update_page_settings | ✅ (schema) | Updates SEO/OG, slug, parentId (move), draft, archived, isMembersOnly, canBranch etc. |
update_static_content | ✅ (schema) | Per-locale text + component instance prop overrides. Requires secondary locale id |
Pages -- confirmed gaps
| Capability | In MCP? | Notes |
|---|---|---|
| Delete page | ❌ | Designer Extension API has no documented delete-page either |
| Duplicate page | ❌ | |
| Move page (set parentId) | ✅ | Via update_page_settings.body.parentId |
| Set page is-homepage / set password | ❌ | Read-only flags only |
| Branching lifecycle (create branch / merge / discard) | ❌ | Read-only flags only |
Components (Data API)
| Action | Status | Notes |
|---|---|---|
list_components, get_component_content, get_component_properties | ✅ | Read access independent of Designer |
update_component_content, update_component_properties | ✅ | Per-locale value overrides only -- requires secondary locale id |
| create_component / delete_component | ❌ | Only the Designer side has create (via element transform) and delete (via unregister_component) |
Scripts, Webhooks, Comments, Enterprise -- Data API
Scripts (custom code)
| Action | Status | Notes |
|---|---|---|
list_registered_scripts | ✅ | |
add_inline_site_script | ✅ | Inline only -- limit 2000 chars. Returns hosted CDN URL |
upsert_page_script | ✅ | Replaces all App-applied scripts on that page (header or footer). No granular per-id apply |
get_page_script / list_applied_scripts | ✅ | List returns 404 "Custom code block not found" until the App has applied at least one script |
delete_all_page_scripts / delete_all_site_scripts | ✅ (schema) | No granular delete by script id |
| Register hosted (URL) script | ❌ | REST supports it; MCP doesn't |
| Apply script at site level | ❌ | REST has site upsert; MCP only exposes per-page |
Webhooks
list_webhooks, get_webhook, create_webhook (17 trigger types), delete_webhook -- all confirmed.
delete_webhook exhibits the 204 parse-error bug (succeeds + reports parse error). get_webhook does not include lastTriggered despite Webflow REST exposing it.
Trigger types accepted (verified enum):
form_submission, site_publish, page_created, page_metadata_updated, page_deleted, ecomm_new_order, ecomm_order_changed, ecomm_inventory_changed, user_account_added, user_account_updated, user_account_deleted, collection_item_created, collection_item_changed, collection_item_deleted, collection_item_published, collection_item_unpublished, comment_created.
Comments
Read-only by design -- list_comment_threads, get_comment_thread, list_comment_replies. No create/reply/resolve in REST or MCP.
Enterprise
Schemas exist for 301_redirects CRUD, robots.txt PUT/PATCH/DELETE/GET, well-known files, site activity logs. Every action returns "This site does not have an Enterprise hosting plan." on non-Enterprise sites -- plan-gated.
Designer surface -- live tests
⚙️ Operational notes for the Designer bridge. Foreground-tab requirement, parallel-call sensitivity, and partial-batch returns are reproducible. A write call that times out can still apply its change (create_page did so during testing). See the Quirks table at the bottom for the full list.Pages (de_page_tool)
| Action | Status |
|---|---|
get_current_page | ✅ -- id, name, slug, parentId, description, title, kind (static/cms/utility), isHomepage, isDraft |
create_page | ✅ -- auto-switches to the new page |
create_page_folder | ✅ schema |
switch_page | ✅ -- implicit on create |
| delete_page / rename / SEO write / set homepage / publish single page | ❌ |
Elements (element_tool, element_builder, whtml_builder, element_snapshot_tool)
Section, Container, BlockContainer, Heading (h1-h6), TextBlock, Paragraph, Button, TextLink, LinkBlock, Blockquote, DivBlock, RichText, CodeBlock, HtmlEmbed, Video, YouTubeVideo, Lightbox, Tabs, Slider, Dropdown, DOM (any tag), BY_CUSTOM_TAG, Form (returns as FormWrapper), CMSCollection (returns as DynamoWrapper), ComponentSlot (returns as Slot -- only inside open_component_view).
FormBlockLabel, FormTextInput, FormTextarea, FormCheckboxInput, FormRadioInput, FormSelect, FormFileUploadWrapper, FormButton -- all reject placement outside a Form. Server enforces and fails the entire batch, not just the offending element.
You can create a CMSCollection element (it renders as the design-time placeholder "Double-click to connect to a collection"). You cannot:
- Bind it to a Webflow CMS collection (no
set_collection_sourceaction). - Add an Item template inside it.
Heading(and most non-Block children) rejected with"Heading can not be placed in a Collection List Wrapper."There is noCMSCollectionItemelement type in the enum.
→ Dynamic CMS templating cannot be built via the MCP.
| Action | Status |
|---|---|
set_text / set_link / add_or_update_attribute / update_id_attribute / set_heading_level | ✅ |
set_image_asset | ⚠️ unverified (no assets to bind on this site) |
set_style / select_element / remove_element | ⚠️ schema present, not exercised destructively |
query_elements | ✅ -- filters by type / text / style / tag / attribute / component_name / slot_name; supports scope, depth, return_parent (parent or ancestor). Text filter does not match content of elements created by element_builder (text lives in a child String node) |
get_all_elements | ✅ -- heavy: full body of test page = 175 KB |
| Setting key | Result |
|---|---|
domId (static_text) | ✅ |
attributes (with attribute array, even all-static) | ❌ "Setting "attributes" is not applicable to this element" |
textContent (static_text) | ❌ Not applicable even on DOM tag |
Bindings (source_type of prop/cms/page/locale/localeItem) | ⚠️ Schema present; not exercisable for CMS-bound elements because the only target (CMS Item template) is not creatable |
✅ Confirmed working. Single root element required. CSS may use Webflow breakpoint media queries (max-width: 991px, 767px, 479px). @keyframes and arbitrary @media ranges are documented as not allowed. Classes referenced in CSS are auto-created as Webflow style classes.
element_snapshot_tool ✅ returns inline PNG. Confirmed for both a single element and the entire page body.
Styles (style_tool)
| Action | Status |
|---|---|
create_style (base + combo via parent_style_names) | ✅ |
update_style per breakpoint_id and per pseudo | ✅ |
update_styleremove_properties | ✅ |
update_style with properties[].variable_as_value | ✅ -- but type-compatible only (Size variable rejected on padding with "Property padding does not support setting a variable of type length") |
get_styles / query_styles (BETA) | ✅ list / spec only |
remove_style (base) | ✅ |
remove_style (combo with parent_style_names) | ⚠️ Returned "Style is-large, mcp-test-class not found" even though both existed; cascaded with base removal |
Breakpoint enum:xxl, xl, large, main, medium, small, tiny. Pseudo enum:noPseudo, nth-child(odd), nth-child(even), first-child, last-child, hover, active, pressed, visited, focus, focus-visible, focus-within, placeholder, empty, before, after.
Variables (variable_tool)
| Action | Status |
|---|---|
create_variable_collection / create_variable_mode | ✅ |
All five types: create_color_variable / create_size_variable / create_number_variable / create_percentage_variable / create_font_family_variable | ✅ |
Static value, alias (existing_variable_id), and custom CSS expression (calc(100vh - 80px)) | ✅ |
update_*_variable (with optional mode_id) | ✅ |
query_variables (BETA) | ✅ -- filters by name / css_name / type / collection |
rename_variable (BETA) | ❌ Returned no result; standalone retry returned empty array; variable name unchanged |
delete_variable (BETA) | ❌ Same -- silently no-op |
| Delete variable mode / collection / reorder / move between collections | ❌ Not exposed |
Components (de_component_tool, component_builder)
| Action | Status |
|---|---|
get_all_components / get_component / get_component_metadata | ✅ |
transform_element_to_component (the only definition-create path) | ✅ -- optional replace:false keeps original |
insert_component_instance / set_component_metadata / rename_component | ✅ |
open_component_view / check_if_inside_component_view / close_component_view | ✅ |
unregister_component (DANGEROUS) | ⚠️ schema only |
component_builderinsert_in_slot | ✅ -- slot named "Slot" by default; no slot-rename action found |
| Define component properties (props with defaults) | ❌ Inserted instances always returned props:[]. Designer Extension API has component properties; the MCP does not wrap them. |
| Set per-instance prop overrides | ❌ Schema mentions source_type:"prop" for elements created inside a component -- but no API to define the prop or override it on an instance |
Assets (asset_tool, get_image_preview)
| Action | Status |
|---|---|
get_all_assets_and_folders / update_asset (name, alt, parent folder) | ✅ list; update untested (no assets exist) |
create_folder | ✅ |
get_image_preview (any URL) | ⚠️ untested |
| Upload binary asset | ❌ Missing entirely. Designer Extension API has create-an-asset but the MCP omits it |
| Delete asset / delete folder / rename folder / move folder | ❌ Missing |
Localization
Both the Data API and the underlying REST require a secondary locale id for content updates:
get_page_metadataandget_page_contentacceptlocaleId, but if you supply the primary locale id you get"The provided locale must be a secondary locale."update_static_contentandupdate_component_contentandupdate_component_propertiesare all per-locale write operations, all secondary-locale-only.- The site under test (
Collection Tests) has no secondary locales -- so the write paths cannot be exercised end-to-end here.
Everything should work given a configured secondary locale; the surface itself is wired correctly.
Confirmed bugs and quirks
What is completely missing from the MCP
Surfaces documented in the Webflow Data API or Designer Extension API but not wrapped at all by the MCP:
Absent transports / surfaces
- Forms -- list forms, get form, list/get/update/delete submissions, list submissions by site.
- Ecommerce -- products, SKUs, orders (list/get/update/fulfill/unfulfill/refund), inventory, ecommerce settings.
- Users / Memberships -- list/get/update/delete user, invite user, list access groups.
- Asset upload -- REST
POST /sites/:id/assets; Designer Extensioncreate-an-asset. No MCP equivalent. - Asset delete, asset folder delete/rename/move.
- Custom code: register hosted (URL) script.
- Custom code: site-level apply (only per-page apply is exposed).
- Granular delete of a single applied script (only delete-all per page or per site).
- Token introspection / authorized-by.
- Workspace audit logs
getaction. - Workspace management -- create/update/delete workspace, get site plan.
- Site lifecycle -- cannot create, duplicate, transfer, or delete a site.
Absent capabilities within wrapped surfaces
- CMS -- collection delete / rename / duplicate; field type change; option-list edit; reference-target change; create-and-publish in one call; unpublish item; filter items by field value or
lastPublishedrange; full-text search. - Pages -- delete page; duplicate page; set is-homepage; set password; per-page publish; branching lifecycle; site-level SEO defaults; sitemap config; favicon / webclip; 404 page.
- Components -- define a component definition from scratch; define component properties; override properties on a specific instance; detach a component instance; rename a slot.
- Variables -- rename (BETA tool exists but no-ops); delete (same); delete a mode; delete a collection; reorder; move variables between collections.
- Styles -- rename a class; reorder classes; duplicate a class; detach a class from a single element override.
- Elements -- move an element; reorder children; duplicate an element. (Workaround: read schema + recreate in target.)
- Interactions / Animations / Page Transitions -- completely absent. The Webflow Designer's Interactions 2.0 and Webflow Animations are not addressable.
- Backups, branches, versioning -- UI only.
Recommended workflows & gotchas
✅ For content automation (the strongest use case): CMS via Data API is reliable. Build collections + fields + items + publish. Just remember to (a) publish the site once via UI before publish-items will succeed, (b) ignore the empty-body parse error on deletes, and (c) treat the staged endpoint as the only writer.
🛠️ For AI-assisted design via Designer: keep the Designer tab in the foreground at all times. Issue Designer calls serially -- parallelism is the most common cause of timeouts. Treat write timeouts as "may have succeeded" -- re-query before retrying. Build component definitions by first creating an element on the canvas, then calling transform_element_to_component.🚫 Don't try to: build dynamic CMS templates (CMS Collection element is a hollow shell), wire up interactions/animations, upload images, define component props, or operate on Forms/Ecommerce/Memberships through the MCP. None of those paths exist.
Test artifacts left on the site
These artifacts were created during the audit and remain on the site (the MCP does not expose delete tools for them):
- Page
MCP Test Page(id6a00417e68bd8a66e81e7413) -- no delete-page action in either MCP transport. - Components
MCP Card(id8ba3db6a-ea58-13b5-6d20-13698393f937) andMCP Chip(id53b3c687-2718-269a-d2b8-74d902b865a2) --unregister_componentnot exercised. - Asset folder
MCP Test Folder-- no delete-folder action. - Variable collection
MCP Test Tokensand MCP variables (Brand Color, Spacing Lg, Z Index Modal, Hero Width, Body Font, Hero Height, Brand Alias) --delete_variableBETA action returned empty. - CMS collection
MCP Capability Test(id6a0022ef57fc602a9927b09d) and one itemTest Item One-- nodelete_collectionaction. - Inline script
MCPTest(idmcptest, hosted CDN URL) -- no per-id delete; thedelete_all_site_scriptsaction would be needed. - Webhook for
collection_item_createdwas created and successfully deleted (verified). - Style class
mcp-test-classwas successfully deleted; combois-largereported "not found" (likely cascaded).
These can be cleaned up manually in the Webflow UI when convenient.
Reported (unverified) -- pending verification
📣 Provenance. The items below were relayed by a third party (a CMS-to-Webflow migration team) and have not yet been reproduced against a live test. They are logged here for tracking and should be promoted into the verified audit above once confirmed -- or removed if they fail to reproduce. Reported: 2026-07-17.
1. JSON-LD structured data -- not writable via REST (Reported -- 2026-07-17)
Reported that the Webflow REST API cannot add structured data (JSON-LD) in the dedicated page section. This is not currently covered by the live audit above (the closest existing row is the missing site-level SEO defaults, which is a different capability). To verify: attempt a JSON-LD write via the page SEO / update_page_settings path on the Collection Tests site.
2. Rich Text component-property values -- not writable (Reported -- 2026-07-17)
Reported that Rich Text-type component property values cannot be written:
- Via the MCP -- cannot write to a component property of type Rich Text.
- Via the Designer Extension API (underlying) -- component properties can be updated except Rich Text, where an HTML structure cannot be inserted.
This refines rather than contradicts the verified findings above. The audit records that update_component_properties (Data API) works for per-locale value overrides, and that component props cannot be defined/overridden on the Designer side at all. The reported nuance adds a property-type exception (Rich Text) that the audit did not test. To verify: attempt a Rich Text prop value write in a secondary locale via update_component_properties.
🔀 Layer note (reconciliation). The reporter distinguishes three layers -- the underlying REST API, the MCP wrapper, and the underlying Designer Extension API -- whereas the audit above models two transports inside the MCP (Data tools / Designer tools). The reporter's "Designer API can update props except Rich Text" describes the raw Designer Extension API, not the MCP; the audit's "props can't be touched" describes the MCP wrapper, which does not expose that capability. The two are consistent: the MCP simply does not wrap the Designer Extension API's component-property support.
