# @cmssy/mcp-server MCP server for [Cmssy CMS](https://cmssy.com) — enables AI-driven page creation and management with i18n support. ## Setup ### Prerequisites 1. Your Cmssy backend API URL (e.g. `https://api.your-cmssy.com`) 2. An API token (create in Dashboard > API Tokens, starts with `cs_`) 3. Your workspace ID ### Add to Claude Code Add to `.mcp.json` in your project root: ```json { "mcpServers": { "cmssy": { "type": "stdio", "command": "npx", "args": [ "-y", "@cmssy/mcp-server", "--token", "cs_YOUR_TOKEN", "--workspace-id", "YOUR_WORKSPACE_ID", "--api-url", "https://api.your-cmssy.com" ] } } } ``` ### Environment Variables Instead of CLI args, you can set: - `CMSSY_API_TOKEN` — API token (`cs_xxx`) - `CMSSY_WORKSPACE_ID` — Workspace ID - `CMSSY_API_URL` — API URL (required, e.g. `https://api.your-cmssy.com`) ## Response shape (write tools) As of 0.6.0, most write tools accept an optional `response` arg: - `response: "minimal"` (default) - returns a small ack (~200 bytes): `{id, slug, hasUnpublishedChanges, updatedAt}` for page tools, `{pageId, blockId, hasUnpublishedChanges, updatedAt}` for block tools, `{id, slug, status, updatedAt}` for form tools, `{id, slug, updatedAt}` for model tools, `{id, status, updatedAt}` for record tools, `{id, orderNumber, status, paymentStatus, fulfillmentStatus, total, balanceDue, currency, updatedAt}` for order tools, `{id, code, type, value, enabled, updatedAt}` for discount tools. - `response: "full"` - returns the full mutation response (pre-0.6 behavior). Use `"full"` only if you need the post-write state inline; otherwise issue a follow-up `get_page`/`get_form`/`get_model`/`get_record`. This keeps agent context windows from being eaten by echoed content. Tools that accept `response`: `create_page`, `update_page_blocks`, `update_page_settings`, `publish_page`, `unpublish_page`, `revert_to_published`, `update_page_layout`, `add_block_to_page`, `update_block_content`, `remove_block_from_page`, `create_form`, `update_form`, `create_model`, `update_model`, `create_record`, `update_record`, `create_manual_order`, `edit_order`, `update_order_details`, `mark_order_paid`, `record_order_payment`, `refund_order`, `cancel_order`, `transition_order_fulfillment`, `set_order_pipeline_stage`, `record_order_invoice`, `create_discount`, `update_discount`, `set_discount_enabled`. `patch_block_content` and the various `delete_*` / status-only tools (`update_form_submission_status`, `import_records`) already returned a compact ack and don't take `response`. ## Available Tools ### Read Tools | Tool | Description | | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `list_pages` | Page tree with hierarchy (optional `search` filter) | | `get_page` | Full page with blocks, i18n content and region settings (own `regionSettings` + resolved `resolvedRegions` with inheritance source) by slug or id | | `get_site_config` | Languages, navigation, site name | | `get_workspace_info` | Workspace name, plan, limits | | `list_media` | Media library listing | ### Write Tools | Tool | Description | | ---------------------- | ---------------------------------- | | `create_page` | Create a new page | | `update_page_blocks` | Set full blocks array on a page | | `update_page_settings` | Update page metadata and SEO | | `publish_page` | Publish a page | | `unpublish_page` | Unpublish a page | | `delete_page` | Delete a page | | `revert_to_published` | Discard draft, revert to published | ### Block Helper Tools | Tool | Description | | ------------------------ | ------------------------------------------------------------------------------ | | `add_block_to_page` | Insert a block at position (auto-generates UUID + translations) | | `update_block_content` | Merge content into an existing block | | `patch_block_content` | Surgical HTML patch (insert/replace around unique markers) | | `remove_block_from_page` | Remove a block by ID | | `update_page_layout` | Update layout blocks and overrides | | `update_region_settings` | Set one layout region's settings (manifest-validated; other regions untouched) | #### `update_region_settings` Region (layout position) settings are declared by the workspace's layout manifest and validated against it on write. The tool reads the page's current `layoutRegionSettings`, replaces only the named region and writes the whole list back, so sibling regions keep their values (entries for regions the manifest no longer declares, and keys a region's schema no longer has, are dropped on the way - the same pruning the admin editor does). The backend's own `BAD_USER_INPUT` message is returned verbatim for an unknown region, an unknown key, or a non-empty `values` on a region that declares no settings (such a region accepts `values: {}` only); `blockWarnings` are surfaced when present. ```jsonc { "pageId": "...", "region": "sidebar", "values": { "width": "wide" } } ``` Child pages inherit a region's settings unless they set their own - `get_page` shows the effective value per region in `resolvedRegions` (`settingsAreInherited`, `settingsSourcePageId`). #### `patch_block_content` For small edits on long HTML content strings (e.g. a `docs-article` body), `patch_block_content` is ~10x cheaper in tokens than `update_block_content` and catches marker mistakes before anything writes to the DB. ```jsonc { "pageId": "...", "blockId": "...", "locale": "en", "operations": [ { "op": "insert_before", "marker": "
...
", }, ], } ``` Three ops: `insert_before`, `insert_after`, `replace_section`. Every marker must match **exactly once** - 0 or 2+ matches error out with the actual count (no silent half-applied state). For `replace_section`, `startMarker` is inclusive and `endMarker` is exclusive. Requires `@cmssy/cli`-registered workspace with `PAGES_EDIT` permission. Default `fieldPath` is `"content"` (the HTML body on docs-article); override if patching a different string field. ### Model Tools (Custom Data Models) AI agents can define ModelDefinitions and CRUD their records. Schema/fields follow `PropertyField` from `@cmssy/types`; records are validated against the model on every write. | Tool | Description | | ---------------- | -------------------------------------------------------------------- | | `list_models` | List all ModelDefinitions in the workspace | | `get_model` | Get a model by id (ObjectId) or slug | | `create_model` | Create a model (name, slug, fields, optional statusField) | | `update_model` | Update any field of a model (fields change triggers schema migrate) | | `delete_model` | Delete a model — **cascades to all its records** | | `list_records` | List records with filter (JSON), sort, pagination, optional populate | | `get_record` | Get a record by id | | `create_record` | Create a record; `data` keyed by model field keys | | `update_record` | Update a record's data and/or transition its status | | `delete_record` | Delete a record | | `import_records` | Bulk import up to 1000 records; returns `{ importedCount, errors }` | Requires workspace permissions `MODELS_VIEW` (read) / `MODELS_CREATE` / `MODELS_EDIT` / `MODELS_DELETE` depending on the operation. ### Commerce Tools (Orders, Carts, Discounts) Manage the storefront's orders, carts, and discount codes. **All money fields are integer minor units (cents).** Order/discount write tools accept the `response` arg (see [Response shape](#response-shape-write-tools)). | Tool | Description | | ------------------------------ | ------------------------------------------------------------------- | | `list_orders` | List orders (filter by payment/fulfillment status, customer, dates) | | `get_order` | Get an order with items, payments, and tax summary | | `get_order_pipeline` | Get the workspace's configurable order pipeline stages | | `create_manual_order` | Create an admin-entered order | | `edit_order` | Replace an order's line items (recomputes totals) | | `update_order_details` | Update customer email, notes, and tracking | | `mark_order_paid` | Record a full payment (manual reconciliation, no provider verify) | | `record_order_payment` | Record a partial payment against the balance due | | `refund_order` | Refund an order (full, or partial with `amount`) | | `cancel_order` | Cancel an order | | `transition_order_fulfillment` | Move an order to a new fulfillment status (with optional tracking) | | `set_order_pipeline_stage` | Move an order to a pipeline stage | | `record_order_invoice` | Attach an invoice (number, url, provider) to an order | | `list_carts` | List shopping carts (admin view, optional status filter) | | `list_discounts` | List discount codes (filter by enabled/type/code) | | `get_discount` | Get a discount by id | | `create_discount` | Create a discount (`percentage` / `fixed` / `free_shipping`) | | `update_discount` | Partial update (code/type/currency lock once the code is used) | | `set_discount_enabled` | Enable or disable a discount | | `list_products` | Product catalog with stock + variant info (over a Data Model) | | `bulk_update_products` | Bulk set/adjust status, stock, or price on selected products | | `bulk_delete_products` | Bulk-delete selected product records | Products are records of a Custom Data Model; these tools add product-aware stock/variant reads and bulk writes on top of the generic record tools. The bulk tools target an explicit `ids` list **or** everything matching a `filter` (`allMatching: true`). There is no per-variant stock write and no standalone inventory mutation - stock is set/adjusted in bulk via `patch.setStock` / `patch.adjustStock`. Requires workspace permissions `ORDERS_VIEW` / `ORDERS_MANAGE` (orders), `CARTS_VIEW` (carts), `DISCOUNTS_VIEW` / `DISCOUNTS_MANAGE` (discounts), `MODELS_VIEW` / `MODELS_EDIT` / `MODELS_DELETE` (products). ### Customer Tools Customers are the accounts that sign in to the site - records of a model with accounts enabled - not the team that manages the workspace (`list_team`). | Tool | Description | | -------------------- | --------------------------------------------------------------------------- | | `list_customers` | List customers with status, verification, last login and company (paginated) | | `get_customer` | One customer's account summary plus the profile record's data | | `suspend_customer` | Block sign-in and end every live session (orders and carts stay) | | `unsuspend_customer` | Let a suspended customer sign in again | ### Webhook Tools Manage outbound event webhooks. `create_webhook` and `rotate_webhook_secret` return the signing secret **once** - it cannot be retrieved again. | Tool | Description | | -------------------------- | -------------------------------------------------------- | | `list_webhooks` | List webhook endpoints (secrets never returned) | | `list_webhook_deliveries` | Recent delivery attempts (pending/success/failed) | | `list_webhook_event_types` | The authoritative allowlist of subscribable events | | `create_webhook` | Create an endpoint; returns the endpoint + secret (once) | | `update_webhook` | Partial update; pass `enabled` to enable/disable | | `rotate_webhook_secret` | Rotate the signing secret (returns new secret once) | | `delete_webhook` | Delete an endpoint | Requires workspace permissions `WEBHOOKS_VIEW` (read) / `WEBHOOKS_MANAGE` (create, update, rotate, delete). ## Resources | URI | Description | | ------------------- | ---------------------------- | | `cmssy://sitemap` | Full page tree as JSON | | `cmssy://workspace` | Workspace info + site config | ## Example Workflow ``` > List all pages in my workspace > Search for pages matching "blog" > Show me the available block types > Which pages still use block types the site no longer registers? > Create a new "Features" page with content in English and Polish > Add a hero block to the Features page > Publish the Features page ``` ## Development ```bash pnpm install pnpm dev -- --token cs_xxx --workspace-id xxx --api-url http://localhost:4000 ```