---
name: block-registry-mcp
description: Read and update CMS block content through the block-registry MCP server. Use when asked to read a block definition, edit or update a placed block's field values, change block content, publish or draft a block, or inspect block field definitions via MCP. Covers the ContentAI Block Registry Server exposed at /mcp/block-registry.
---

# block-registry MCP

The ContentAI module exposes an MCP server, `Block Registry Server`, over HTTP at
`/mcp/block-registry` on the site (e.g. `http://localhost/mcp/block-registry`). It lets an
MCP client (Claude Code, Claude Desktop, etc.) read block field definitions and update the
field values of placed blocks.

The server is only mounted when it is enabled on the admin **AI Settings** page. If it is off,
the endpoint is not registered and the client will not see the tools.

## Connecting a client

The server is streamable-HTTP. Point the client at the URL:

- **Claude Code** — `claude mcp add --transport http block-registry http://<site>/mcp/block-registry`
  (or a project `.mcp.json` entry — see `.mcp.json` in this repo).
- **Claude Desktop** — add an HTTP MCP server with the same URL in its config.

Once connected, two tools appear: `read-block-data-tool` and `update-block-data-tool`.

## The two tools

### `read-block-data-tool` — inspect a block *type*

Argument `block`: a block **definition** — its numeric id **or** slug (e.g. `rich_text`).

Returns the block's metadata and its **field schema**: each field's `name`, `label`, and `type`.
Call this first before an update to get the exact field names.

### `update-block-data-tool` — write values onto a *placed* block

Arguments:
- `id` (required): the **placed instance** id — the number in `/admin/blocks/data/{id}`.
- `fields` (required): map of field `name` => new value.
- `status` (optional): `"draft"` or `"published"`. Omit to leave unchanged.

Returns the updated status, the list of fields written, and the block's new data.

## The one thing to get right: two id spaces

`read`'s `block` and `update`'s `id` are **not** the same number.

| Tool | Arg | Refers to | Source |
|---|---|---|---|
| `read-block-data-tool` | `block` | block **definition** (the type) | numeric id or slug, e.g. `rich_text` |
| `update-block-data-tool` | `id` | **placed instance** (one block on a page) | the number in `/admin/blocks/data/{id}` |

Passing a definition id to `update` gives `No block data found for id [N]`.

## Editing workflow

1. `read-block-data-tool` with the block slug → note the exact field `name`s.
2. `update-block-data-tool` with the placed instance `id` and only the fields you want to change.

Example — a `rich_text` block exposes fields `Title` (text) and `Content` (textarea):

```jsonc
// read
{ "block": "rich_text" }
// update instance 89
{ "id": 89, "fields": { "Title": "New heading", "Content": "<p>New body</p>" }, "status": "published" }
```

## Field value shapes

- **text / textarea** — a string.
- **checkbox** — `true` / `false`.
- **repeater** — an array of row objects.
- **image / file / link** — an object; stored verbatim (no crop/srcset processing is applied here).

## Gotchas

- **Field names are case-sensitive labels.** Use the exact `name` from `read` (`Title`, not `title`).
  Unknown names are rejected with an error listing the allowed fields — nothing is written.
- **Partial updates preserve other fields.** Only the keys you send change; omitted fields keep
  their current values. There is no way to clear a field to empty/NULL through this tool.
- **`status` is sticky.** Omit it to keep the current publish state.
- **Updates take effect immediately.** A successful write clears that block's render cache, so
  the front end reflects the change on next render.

## Troubleshooting

- **Client sees no tools / endpoint 404s** — the MCP is disabled. Enable it on the admin
  **AI Settings** page, and confirm the site is running.
- **`Unknown field(s) for this block: X`** — wrong field name or case. `read` the block and copy
  the exact `name`.
- **`No block data found for id [N]`** — `N` isn't a placed-instance id (you likely used a block
  definition id). Use the number from `/admin/blocks/data/{id}`.
