Skip to main content
Glama
cmssy-io

@cmssy/mcp-server

Official
by cmssy-io
README.md
# @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": "<h2>Environment Variables</h2>",
      "html": "<hr><h2>cmssy skills install</h2><p>...</p>",
    },
  ],
}
```

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).

### 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
```

TDQS

B3.4/5.0

Scored across 87 tools

Disambiguation3/5

Most tools follow clear resource+action pairs, but several clusters overlap: mark_order_paid/record_order_payment, update_block_content/patch_block_content, and list_records/list_products can be misselected. The detailed descriptions disambiguate, but with 87 tools the boundary between 'full' vs 'partial' payment and 'replace' vs 'patch' block content is not obvious from names alone.

Naming Consistency4/5

The dominant verb_noun pattern (list_*, get_*, create_*, update_*, delete_*) is consistent and predictable across resources. Minor deviations (edit_order, mark_order_paid, patch_block_content, clear_cart_config, take_over_page_lock) break the pattern slightly but remain readable.

Tool Count1/5

87 tools is far beyond the 50+ threshold and would overwhelm an agent even though the server covers multiple domains. The same surface would be more coherent split into content, commerce, and webhook-focused servers.

Completeness3/5

Most modules have solid CRUD coverage: forms, models/records, pages, and webhooks are nearly complete. Notable gaps remain: individual media assets cannot be deleted/updated, discounts can only be disabled not deleted, and there is no dedicated cart detail tool—these create dead ends for common admin workflows.

Maintenance

ActivityActive
ResponsivenessNo issues