MCP Server
Manage Cmssy workspace content from AI agents with `@cmssy/mcp-server` — an MCP bridge exposing pages, blocks, forms and media tools over stdio.
Overview
@cmssy/mcp-server is a Model Context Protocol server that bridges AI agents (Claude Code, Claude Desktop, any MCP-aware tool) to a Cmssy workspace. Once configured, the agent can list and edit pages, add or remove blocks, publish drafts, manage forms, and more — without ever leaving its editor.
It ships on npm and talks stdio, so you don't run a long-lived server: the agent launches it on demand via npx.
What makes it different from the HTTP API
- Workspace-scoped — a single token + workspace ID pair, everything enforced server-side
- High-level tools —
add_block_to_page,publish_page,patch_block_content, not raw GraphQL - Tenant isolation built in — every query is filtered by your workspace; you can't accidentally touch another tenant
Setup
1. Create an API token
Workspace Settings → API Tokens → Create token. Copy the cs_… value immediately — tokens are shown once. Scope is authentication only; what the token can do is determined by your role and isSuperAdmin flag.
2. Find your workspace ID
Workspace Settings → General has a copy button next to the ID. It's the same workspace tied to your API token.
3. Add it to your editor's MCP config
For Claude Code, edit .mcp.json in your project root (or ~/.claude/mcp.json for a global install):
{
"mcpServers": {
"cmssy": {
"command": "npx",
"args": [
"-y",
"@cmssy/mcp-server@latest",
"--token", "cs_your_token_here",
"--workspace-id", "507f1f77bcf86cd799439011",
"--api-url", "https://api.cmssy.io/graphql"
]
}
}
}Environment-variable equivalents are also supported: CMSSY_API_TOKEN, CMSSY_WORKSPACE_ID, CMSSY_API_URL. Useful if you don't want the token in a committed config file.
4. Restart the editor
Claude Code picks up the server on the next session start. You should see a cmssy MCP entry with the available tools listed.
Available tools
0.50.2 exposes 81 tools. They share one naming shape - list_* and get_* to read, create_* / update_* / delete_* to write, plus verbs for state transitions - so the group matters more than the individual name.
Pages and blocks
list_pages,get_page- the page tree, and one page with all its blocks and languages. Full-textsearch_contentis defined in the shared tool core but is not bound by the MCP server; it is reachable from the in-admin assistant.create_page,update_page_settings,delete_page.update_page_settingsalso reparents a page throughparentId, which recomputes the slug of the whole subtree.publish_page,unpublish_page,revert_to_published.add_block_to_page,update_block_content,patch_block_content,remove_block_from_page,update_page_blocks,update_page_layout.list_block_types- the block types your site actually registers, read from the manifest the editor handshake stores. Call it before adding a block: it is how you know what the frontend can render.list_page_types,create_page_type.
Models and records
list_models,get_model,create_model,update_model,delete_model- deleting a model cascades to every record in it.list_records,get_record,create_record,update_record,delete_record,import_records(up to 1000 per call).
delete_record refuses when a block still uses the record, and answers with the pages that use it. Pass force: true to delete anyway.
Media
list_media,upload_media,move_media.list_media_folders,create_media_folder,update_media_folder,delete_media_folder.
Forms
list_forms,get_form,create_form,update_form,delete_form.list_form_submissions,get_form_submission,update_form_submission_status,delete_form_submission.
Commerce
- Orders -
list_orders,get_order,create_manual_order,edit_order,update_order_details,mark_order_paid,record_order_payment,record_order_invoice,refund_order,cancel_order,transition_order_fulfillment,get_order_pipeline,set_order_pipeline_stage. - Products -
list_products,bulk_update_products,bulk_delete_products,set_product_tiers. - Carts and discounts -
list_carts,update_cart_config,clear_cart_config,list_discounts,get_discount,create_discount,update_discount,set_discount_enabled.
Webhooks
list_webhooks,create_webhook,update_webhook,delete_webhook,rotate_webhook_secret,list_webhook_deliveries.list_webhook_event_types- the authoritative allowlist of subscribable events. Read it rather than guessing an event name.
A signing secret is returned once, on create and on rotate, and never again.
Workspace
get_workspace_info- name, plan, limits and usage.get_site_config- languages, navigation, enabled features, cart settings.list_members,list_roles- read-only.
Nothing in the set touches your code. No tool writes a file, edits a component or opens a pull request: AI edits content, and block schemas stay in your repository under review.
Dev drafts: a block that is not deployed yet
Every write tool takes an optional target. "draft" (the default) edits the shared page draft; "devDraft" edits your own per-user overlay, which starts from the current page and changes nobody else's preview.
That is what makes it safe to compose a page around a block type that so far exists only on your machine. When the block ships, promote_dev_draft moves your overlay onto the shared draft. get_page with target: "devDraft" returns the overlay next to the shared draft, or null when you have none.
patch_block_content — surgical edits
For targeted edits on multi-KB content (docs articles, long blog posts), patch_block_content sends only the diff — not the full string. Backed by MongoDB findOneAndUpdate with $set + arrayFilters, tenant-scoped, atomic. Typically ~10× cheaper in tokens than re-sending the whole HTML via update_block_content.
Three operation types
insert_before / insert_after
Insert HTML directly before/after a unique marker. The marker MUST match exactly one location — zero or multiple occurrences reject the op with BAD_USER_INPUT.
{
"op": "insert_after",
"marker": "<h2>Pricing</h2>",
"html": "<p>Plans start at $0/month.</p>"
}replace_section
Replace everything from startMarker (inclusive) to endMarker (exclusive). Both markers must resolve uniquely.
{
"op": "replace_section",
"startMarker": "<h2>Pricing</h2>",
"endMarker": "<h2>FAQ</h2>",
"html": "<h2>Pricing</h2><p>New plans here.</p>"
}Multiple ops in one call
Operations apply in order on the running result. Any failure (missing marker, ambiguous, etc.) aborts the whole patch — no half-applied state.
{
"pageId": "...",
"blockId": "...",
"locale": "en",
"operations": [
{
"op": "insert_before",
"marker": "<h2>Appendix</h2>",
"html": "<h2>New Section</h2><p>…</p>"
},
{
"op": "replace_section",
"startMarker": "<h2>Pricing</h2>",
"endMarker": "<h2>FAQ</h2>",
"html": "<h2>Pricing</h2><p>Updated.</p>"
}
]
}When an operation fails
- 0 matches — marker not found. Check for an exact character-level match; whitespace and attribute order matter.
- 2+ matches — marker isn't unique. Add surrounding HTML to disambiguate. Overlapping matches count (
"aa"in"aaa"counts as 2), so avoid ultra-short markers. - Field not a string — the targeted
fieldPathresolves to an array or object. Useupdate_block_contentfor structured fields. - Layout blocks not supported — header/footer and other layout blocks go through
update_block_content.
patch_block_content vs update_block_content
patch_block_content | update_block_content | |
|---|---|---|
| When to use | Targeted edits on an HTML string | Full content rewrite, any shape |
| Token cost | Proportional to the diff | Proportional to the full content |
| Typical savings | ~10× on multi-KB content | – |
| Field types | String only (via fieldPath) | Any (strings, arrays, nested objects) |
| Partial failure | Whole patch aborts — no half-applied state | Whole write applies or fails |
| Layout blocks | Not supported | Supported |
Rule of thumb: if you'd previously re-send the entire HTML to change one paragraph, use patch_block_content. Otherwise stick with update_block_content.
Troubleshooting
- “Workspace not found” — the user behind the token is not a member of the given
--workspace-id, or the id is wrong. A token authenticates a person; what it may do comes from that person's role in that workspace. Check the pair in Workspace Settings. - “Not authenticated” — token expired or revoked. Create a new one from Workspace Settings → API Tokens.
- MCP server not visible in the editor — restart the editor after config changes. In Claude Code, check Settings → MCP → cmssy for startup logs.
- Rate limits / plan limits — the MCP server respects the workspace's plan limits (max pages, storage, AI tokens).
get_workspace_infoshows current usage vs limits.
Response mode
Since 0.6.0, every write tool accepts an optional response: "minimal" | "full" param (default "minimal"). Minimal returns a small compact-JSON ack (~100-200 bytes) with just the IDs and state you need to chain the next call — not the full mutated resource.
Typical bulk edit sessions (agents touching the same docs page ~6 times) were burning ~170kB of echoed HTML per page pre-0.6. Minimal mode cuts that to ~1kB total — ~95% reduction in response token cost.
Minimal ack shapes
- Page tools (
create_page,update_page_blocks,update_page_settings,publish_page,unpublish_page,revert_to_published,update_page_layout) —{id, slug, hasUnpublishedChanges, updatedAt}(+publishedon publish/unpublish) - Block-on-page tools (
add_block_to_page,update_block_content,remove_block_from_page) —{pageId, blockId, hasUnpublishedChanges, updatedAt} - Form tools (
create_form,update_form) —{id, slug, status, updatedAt} - Model tools (
create_model,update_model) —{id, slug, updatedAt} - Record tools (
create_record,update_record) —{id, status, updatedAt}
When to opt into full
Pass response: "full" when you actually need the full mutated resource in the same call — e.g. to verify a complete transformation, read a server-generated field, or debug. Otherwise chain a follow-up read tool (get_page / get_form / get_model / get_record).
Tools that don't take response
Already return a compact ack and are unchanged: patch_block_content, all delete_*, update_form_submission_status, import_records.
Version
These docs describe @cmssy/mcp-server 0.50.2, which binds 81 tools from @cmssy/ai-tools 0.34.0. Landmarks worth knowing: patch_block_content shipped in 0.5.0, minimal responses in 0.6.0, list_block_types in 0.45.0, the dev-draft target in 0.48.0 - though promote_dev_draft itself was only bound in 0.50.2, safe record deletion with force in 0.48.0, media folder tools in 0.49.2, clear_cart_config in 0.50.1. Pin @cmssy/mcp-server@latest in .mcp.json to always get the newest tools.