Skip to content

MCP ​

What you'll learn

How to let AI assistants such as Claude, Cursor or VS Code read and write your content through the Model Context Protocol, with an API key that limits what they can do.

Before this page: API keys and Plugins.

@easy-cms/plugin-mcp turns your CMS into an MCP server. An assistant connected to it can search posts, draft new ones, fix typos across pages or upload images, and only in the collections and actions its API key allows. Everything it writes goes through the same validation, hooks and access rules as the admin.

Set it up ​

bash
npm install @easy-cms/plugin-mcp
bash
pnpm add @easy-cms/plugin-mcp
bash
yarn add @easy-cms/plugin-mcp
bash
bun add @easy-cms/plugin-mcp
ts
import { mcpPlugin } from '@easy-cms/plugin-mcp'

export default defineConfig({
  // …
  apiKeys: true,
  plugins: [mcpPlugin()],
})

The server is at <routes.api>/mcp, e.g. https://example.com/api/cms/mcp. It uses Streamable HTTP without sessions, so it works on serverless hosts too.

Then create an API key for the assistant under Settings → API keys, ticking only what it needs. For a writing assistant, for example: posts read, create and update, but not publish or delete.

Connect an assistant ​

Replace the URL and key with yours.

bash
claude mcp add --transport http easy-cms https://example.com/api/cms/mcp \
  --header "Authorization: Bearer ecms_…"
json
{
  "mcpServers": {
    "easy-cms": {
      "url": "https://example.com/api/cms/mcp",
      "headers": { "Authorization": "Bearer ecms_…" }
    }
  }
}
json
{
  "servers": {
    "easy-cms": {
      "type": "http",
      "url": "https://example.com/api/cms/mcp",
      "headers": { "Authorization": "Bearer ${input:easy-cms-key}" }
    }
  },
  "inputs": [{ "id": "easy-cms-key", "type": "promptString", "description": "Easy CMS API key", "password": true }]
}
json
{
  "mcpServers": {
    "easy-cms": {
      "command": "npx",
      "args": ["mcp-remote", "https://example.com/api/cms/mcp", "--header", "Authorization: Bearer ${EASY_CMS_KEY}"],
      "env": { "EASY_CMS_KEY": "ecms_…" }
    }
  }
}

Assistants and their settings change often; check your client's documentation for how it adds a remote MCP server with a header.

The tools ​

Tools are made for each collection and global, only for what the key allows:

ToolNeeds
find_<collection>readList with where, sort, limit (≤ 100), page, locale. Includes drafts.
get_<collection>readOne document by id, relationships populated.
create_<collection>createCreate; the input schema comes from your fields.
update_<collection>updateChange the given fields.
delete_<collection>deleteDelete.
publish_<collection>, unpublish_<collection>publishCollections with drafts.
schedule_<collection>publishPublish or unpublish later (collections with schedule).
upload_mediacreate on MediaA file as base64, with alt text.
get_global_<slug>, update_global_<slug>, publish_global_<slug>read, update, publishGlobals.
  • Drafts stay drafts. In collections with drafts, create_ and update_ always save a draft, whatever the assistant sends; only publish_ puts it live. With versions as well, the published page stays as it is until then. (Without versions, updating a published document as a draft takes it offline until it is published again, as in the admin.)
  • Rich text accepts plain text (blank lines start new paragraphs) or Tiptap JSON.
  • Relationships and uploads take ids; the assistant finds them with find_ or upload_media.
  • Localized fields are read and written in locale (the default locale when left out).
  • Users and API keys are never offered, whatever the key says.
  • Errors come back as messages the assistant can act on, e.g. Invalid data: title: is required.

Options ​

OptionDefault
path/mcpWhere under routes.api the server is.
nameeasy-cmsThe server's name in the assistant.
instructions—Extra guidance for the assistant, e.g. your house style. Added to the built-in notes.
collectionsallCollections to offer at all (the key still decides).
globalsallGlobals to offer at all.
ts
mcpPlugin({
  name: 'acme-blog',
  instructions: 'Write in British English. Posts need an excerpt of one sentence.',
  collections: ['posts', 'categories', 'media'],
})

Safety ​

  • Give each assistant its own key, with the fewest actions and an expiry. Leave out publish and delete unless you want the assistant to do that on its own.
  • Read what the assistant drafted in the admin before publishing; history keeps every version.
  • The server never fetches URLs the assistant sends: uploads come as file contents.
  • Revoke the key under Settings → API keys to cut an assistant off at once.

Next steps ​

Released under the MIT License.