# Agility CMS MCP Server

> Source: https://agilitycms.com/docs/developers/agility-cms-mcp-server

The Agility CMS MCP Server connects AI assistants directly to your Agility CMS instances, letting you manage content through natural-language conversations. It implements the [Model Context Protocol](https://modelcontextprotocol.io) (MCP) — an open standard supported by Claude, ChatGPT, GitHub Copilot, Cursor, Windsurf, Gemini, and other MCP-compatible clients.

Ask your AI assistant to model content, create pages, bulk-edit items, audit your schema, publish updates, or run a multilingual migration — and it calls the right Agility Management APIs on your behalf, always within your existing permissions.

- **Endpoint:** `https://mcp.agilitycms.com/api/mcp`
- **Transport:** Streamable HTTP
- **Authentication:** OAuth 2.0
- **Status:** Generally Available — **v2.0.0**
- **Docs & one-click install:** [mcp.agilitycms.com](https://mcp.agilitycms.com)

---

## What's new in 2.0

Version 2.0 grows the toolset from **20 to 27 tools** and adds full authoring and publishing workflows — with a human-in-the-loop confirmation model for anything destructive.

- **Publishing & workflow** — new `manage_content_workflow` and `manage_page_workflow` tools publish, unpublish, approve, decline, or request approval for content items and pages.
- **Delete support** — new `delete_content_item`, `delete_page`, and `delete_media` tools, each gated behind explicit confirmation.
- **Media library browsing** — `list_media` lists assets (paged) and returns the Edge (CDN) URL; pairs with the existing upload flow and the new `delete_media`.
- **Identity check** — `get_current_user` is a read-only "whoami" that confirms which user the active token authenticates as (it never returns credentials).
- **Human-in-the-loop confirmation** — publish, unpublish, and delete actions are confirmed before they run. On clients that support MCP elicitation, you get a real "Are you sure?" / "type `DELETE`" prompt in your own UI.
- **Safer authoring** — `save_page` now validates zone names against the page template (instead of silently dropping mismatched modules), linked-content reference names are normalized to their canonical case, and permission denials surface as clear messages without ever leaking your token.

> There are **no breaking changes** to the tools that existed in 1.0. Existing setups keep working — you simply gain the new tools.

---

## Available tools

The server exposes **27 tools** across five categories. Each tool is annotated so MCP clients know whether it only reads data or can modify your instance. Destructive actions (publish, unpublish, delete) ask for confirmation before they run — see [Confirmation for destructive actions](#confirmation-for-destructive-actions).

### Discovery & setup

| Tool | What it does |
|------|--------------|
| `get_available_instances` | Lists the Agility instances you can access |
| `get_current_user` | Identifies the user the current token authenticates as (read-only whoami) |
| `get_locales` | Returns the locale codes configured for an instance |
| `get_containers` | Lists content containers (content lists and single items) |

### Models & schema

| Tool | What it does |
|------|--------------|
| `get_content_models` | Lists content model definitions |
| `get_component_models` | Lists component (page module) model definitions, including Agility's built-in components |
| `get_content_model_details` | Returns the full field schema for a content model |
| `get_component_model_details` | Returns the full field schema for a component model (always includes the numeric model ID) |
| `save_content_model` | Creates or updates a content model |
| `save_component_model` | Creates or updates a component model |
| `save_container` | Creates or updates a container |

### Content

| Tool | What it does |
|------|--------------|
| `get_content_items` | Retrieves a list of items from a container, with filtering and pagination |
| `get_content_item` | Fetches one or more items by ID (batch supported) |
| `save_content_items` | Creates or updates one or more content items in a single batch. Returns each item's `contentID` and a ready-made editor URL. |
| `manage_content_workflow` | Publishes, unpublishes, approves, declines, or requests approval for items *(publish/unpublish are confirmed)* |
| `delete_content_item` | Deletes one or more content items *(confirmed — type `DELETE`)* |

### Pages & sitemaps

| Tool | What it does |
|------|--------------|
| `get_sitemaps` | Lists all sitemaps (channels) for an instance |
| `get_sitemap` | Retrieves a specific sitemap, with depth/path filtering and flat mode |
| `get_page` | Retrieves a page by ID, including zones, SEO, and dynamic config |
| `get_page_models` | Lists available page models (templates), with zone definitions |
| `save_page` | Creates or updates a page — static, dynamic, folder, or link (validates zone names) |
| `reorder_page_modules` | Reorders the modules within a page zone |
| `manage_page_workflow` | Publishes, unpublishes, approves, declines, or requests approval for pages *(publish/unpublish are confirmed)* |
| `delete_page` | Deletes one or more pages *(confirmed — type `DELETE`)* |

### Media

| Tool | What it does |
|------|--------------|
| `initialize_media_upload` | Starts a media upload and returns a temporary signed URL to POST the file to |
| `list_media` | Lists assets in the media library (paged), returning the Edge (CDN) URL — find a `mediaID`, spot duplicates |
| `delete_media` | Deletes a media asset by `mediaID` *(confirmed — type `DELETE`)* |

---

## Confirmation for destructive actions

Actions that change what's live or remove data are gated:

| Action | Confirmation |
|--------|--------------|
| `delete_content_item`, `delete_media`, `delete_page` | Type **`DELETE`** to proceed |
| `manage_content_workflow` / `manage_page_workflow` — `publish` / `unpublish` | A yes/no "Are you sure?" prompt |
| `approve` / `decline` / `request-approval` | Not gated (low risk) |

How an action is confirmed depends on what your MCP client supports (negotiated at connection):

1. **Client permission prompt.** These tools are annotated as *destructive*, so MCP clients prompt before running them ("Allow this tool to run?"). Choosing **"always allow"** in your client opts out of that prompt for that tool — that's a client-side setting, not something the server can override.
2. **Server elicitation (true human gate).** On clients that support **MCP elicitation** (e.g. Claude Code), the server renders the confirmation form (yes/no, or "type `DELETE`") in your own UI — a gate the AI assistant can't satisfy on its own.
3. **No elicitation → your Agility permissions enforce.** On clients that don't support elicitation, the action runs with your own OAuth token and the **Agility Management API enforces your permissions** — if your account can't publish or delete, the API denies it. The response notes that no interactive prompt was shown (`humanConfirmed: false`).

---

## Installation

The hosted server uses the streamable-HTTP endpoint `https://mcp.agilitycms.com/api/mcp`. On first connection your client opens a browser window to authenticate with Agility via OAuth — no API keys or passwords to copy around.

> **Fastest path:** visit **[mcp.agilitycms.com/instructions](https://mcp.agilitycms.com/instructions)** for one-click install buttons (VS Code, Cursor, and more) and copy-paste setup for every supported client.

### One-click install

For supported editors, a single click adds the hosted server and kicks off the OAuth sign-in:

- **VS Code** — `vscode:mcp/install` deep link
- **VS Code Insiders** — `vscode-insiders:mcp/install` deep link
- **Cursor** — `cursor://anysphere.cursor-deeplink/mcp/install` deep link
- **LM Studio** — `https://lmstudio.ai/install-mcp` deep link

Grab the buttons from [mcp.agilitycms.com/instructions](https://mcp.agilitycms.com/instructions). For everything else, use the manual steps below.

### Claude (Desktop & Web)

1. Open **Settings → Connectors** (or **Custom Connectors**).
2. Add a new connector with the URL:
   ```
   https://mcp.agilitycms.com/api/mcp
   ```
3. Complete the OAuth sign-in when prompted. The Agility tools appear in your tool menu.

### Claude Code (CLI)

```bash
claude mcp add --transport http "Agility-CMS" https://mcp.agilitycms.com/api/mcp
```

### Gemini CLI

Add the server with a single command:

```bash
gemini mcp add --transport http agility-cms https://mcp.agilitycms.com/api/mcp
```

Or add it manually to `~/.gemini/settings.json`:

```json
{
  "mcpServers": {
    "agility-cms": {
      "httpUrl": "https://mcp.agilitycms.com/api/mcp"
    }
  }
}
```

On first connection, follow the OAuth flow to grant access. Run `/mcp` inside Gemini CLI to confirm the Agility tools are loaded.

### Cursor

1. Open **Settings → MCP → Add new MCP server**.
2. Choose the **HTTP** transport and enter:
   ```
   https://mcp.agilitycms.com/api/mcp
   ```
3. Authenticate via OAuth when prompted.

### Windsurf

1. Open **Settings → Cascade → MCP Servers → Add Server**.
2. Use the HTTP/streamable transport with the endpoint:
   ```
   https://mcp.agilitycms.com/api/mcp
   ```

### Google Antigravity

1. In an Agent session, open the **"…"** dropdown at the top of the side panel → **MCP Servers**.
2. Add a server with the HTTP endpoint:
   ```
   https://mcp.agilitycms.com/api/mcp
   ```
3. Complete the OAuth sign-in when prompted.

### ChatGPT

In a context that supports MCP connectors, add the server URL:
```
https://mcp.agilitycms.com/api/mcp
```

> **Note:** Custom MCP connectors in ChatGPT require a Pro plan or a Business/Enterprise/Education workspace, and are currently usable in Deep Research mode.

### Local / stdio (advanced)

For clients that launch a local process instead of connecting over HTTP, the package can be run via `npx`:

```json
{
  "mcpServers": {
    "agility-cms": {
      "command": "npx",
      "args": ["-y", "agility-mcp-server"]
    }
  }
}
```

---

## Authentication

The server uses **OAuth 2.0** with short-lived access tokens. You sign in through Agility's standard login, and the server acts strictly within your existing permission boundaries — it can only see and change what your account is allowed to. No passwords are ever stored by the MCP server.

---

## Field type support

The model and content tools understand Agility's full field catalog, including:

- **Basic:** text, multi-line text, HTML/rich text, numbers, booleans, dates
- **Selection:** dropdowns, checkbox lists, link fields
- **Media:** image attachments, file attachments, image galleries
- **Relationships:** linked content (shared and nested), with companion text/value fields for searchable lists

When creating or updating models, include all relevant field properties — undefined properties are treated as empty or null.

---

## Working with media

Media uploads use a secure signed-URL flow rather than embedding file bytes in the conversation:

1. Call `initialize_media_upload` to receive a temporary `uploadUrl` (valid for 5 minutes).
2. `POST` the file to that URL as multipart form-data (field name `file`).
3. Use the returned asset URL in an attachment field when you call `save_content_items` or `save_page`.

Use `list_media` to browse the library (and spot duplicates before re-uploading), and `delete_media` to remove an asset by its `mediaID`.

---

## Publishing & workflow

`save_content_items` always saves to the instance's default workflow state (typically **Staging**) — a `state` value passed on save is **not** honored, and the tool flags this in its response. To take content live or move it through approval, use `manage_content_workflow` (`publish`, `unpublish`, `approve`, `decline`, `request-approval`). Pages follow the same pattern with `manage_page_workflow`.

For **User Selectable** linked-content fields, the stored value is the linked container's reference name. The editor matches that name case-sensitively, so the server normalizes whatever case you supply to the container's canonical case from `get_containers` on save (and returns the canonical case on read) — preventing the "dropdown renders blank" problem.

---

## Example use cases

- **Content modeling** — "Create a BlogPost model with a title, hero image, rich-text body, and author reference."
- **Page composition** — "Build a `/pricing` landing page with a hero, a 3-up feature grid, and a CTA."
- **Bulk operations** — "Update every BlogPost missing a meta description and set one based on the intro paragraph."
- **Content auditing** — "List all content models and flag fields that aren't used by any container."
- **Multilingual workflows** — "Show me which pages exist in en-us but are missing in fr-ca."
- **Migration** — "Create these 30 product items from the spreadsheet I'm describing."
- **Publishing** — "Publish content items 272 and 273." (you'll be asked to confirm)
- **Cleanup** — "Delete the test articles I just created, and remove any duplicate uploads from the media library."

---

## Support

- **Documentation & setup:** [mcp.agilitycms.com](https://mcp.agilitycms.com)
- **Tool catalog:** [mcp.agilitycms.com/tools](https://mcp.agilitycms.com/tools)
- **Help & feedback:** support@agilitycms.com
- **Source:** [github.com/agility/agility-mcp-server](https://github.com/agility/agility-mcp-server)
