---
title: MCP server for CMS 13
slug: cms-13/docs/mcp-server-for-cms-13
docTags: 
createdAt: 2026-10-05T16:05:27.545Z
---

Mark (Optimizely Agent Platform) is an agent orchestration platform that helps you work smarter in CMS 13. The `Optimizely.Cms.Opal.Tools` package includes a [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) server that exposes the same CMS tools available through Mark chat to any MCP-compatible AI client. Manage CMS content, content types, and display templates from your development environment with an MCP client such as Claude Code or Cursor. The MCP server puts these tools in the editor where you write code, so you can create content types and display templates while building the templates that render them.

The MCP server shares the same tools and descriptions as the Mark protocol. See [Available tools for CMS 13](docId\:v4llE83TvCJ0kzb27dct2) for the full tool reference.

## Prerequisites

- .NET 10.0 or later.
- `Optimizely.Cms.Opal.Tools` 13.2.0 or later.
- An authentication method configured (see [Authentication and authorization](docId\:Y_6KhaT7z0hC9TqQopMq0)).

## Install and configure

### Register the MCP server

Add the MCP server to your service collection in `Startup.cs` or `Program.cs`. Chain an authentication method to configure how MCP clients authenticate.

```csharp
services.AddCmsMcpServer().WithClientSecretAuthentication();
```

`AddCmsMcpServer()` registers the MCP server with stateless HTTP transport and all CMS tools. The chained authentication method (for example, `WithClientSecretAuthentication()`) configures how the server validates incoming requests.

### Map the MCP endpoint

Map the MCP endpoint in your application pipeline and apply the matching authorization policy.

```csharp
app.UseEndpoints(endpoints =>
{
    endpoints.MapContent();
    endpoints.MapMcp("/mcp").RequireClientSecretAuthorization();
});
```

The convenience extension method `RequireClientSecretAuthorization()` applies the correct authorization policy for the authentication method.

## Authentication and authorization

Every MCP tool call executes CMS operations on behalf of an authenticated user. The MCP server requires an authentication method that establishes a user identity so that all content operations respect CMS permissions.

### Choose an authentication method

| Method                  | Use case                                        | Identity                                 | Permissions                 |
| ----------------------- | ----------------------------------------------- | ---------------------------------------- | --------------------------- |
| **Client secret**       | Local development, secure internal environments | Application identity with CmsAdmins role | Full access to all tools    |
| **Custom**              | Integration with existing auth systems          | Depends on implementation                | Depends on identity mapping |
| **Optimizely Identity** | Coming in a future release                      | Individual Opti ID user                  | Per-user CMS permissions    |

Client secret authentication is designed for local development where the network is trusted and permission scoping is not required. For production environments, implement a custom authentication handler that integrates with your existing authentication system. Optimizely Identity (Opti ID) authentication with per-user permission scoping will be available in a future release.

### How tool authorization works

When the MCP server receives a request:

1. The authentication handler validates the credentials (secret or custom token).
2. The handler creates a `ClaimsPrincipal` representing the authenticated identity.
3. Each tool impersonates this identity for all CMS API calls.
4. CMS enforces the standard permission model (the tool can only access content the impersonated user has permission to access).

All tools require an authorized identity. Some tools, such as content type management, require the **CmsAdmins** role. Other tools operate under the authenticated user's own content permissions.

### Optimizely Identity authentication

:::BlockQuote
📘 NoteOptimizely Identity (Opti ID) authentication for the MCP server will be available in a future release. This will enable per-user authentication and permission scoping for production and multi-user environments. For now, use client secret authentication or a custom authentication handler.
:::

### Client secret authentication

Use `WithClientSecretAuthentication()` for local development and secure (non-public) environments. This method authenticates requests with a shared secret in the `Authorization` header.

```csharp
services.AddCmsMcpServer().WithClientSecretAuthentication();
```

```csharp
endpoints.MapMcp("/mcp").RequireClientSecretAuthorization();
```

Configure the secret in `appsettings.json`:

```json
{
  "Optimizely": {
    "Cms": {
      "Mcp": {
        "Secret": "your-secret-value"
      }
    }
  }
}
```

Or use user secrets for local development:

```shell
dotnet user-secrets set "Optimizely:Cms:Mcp:Secret" "your-secret-value"
```

MCP clients send the secret as the value of the `Authorization` header:

```javascript
Authorization: your-secret-value
```

:::BlockQuote
🚧 ImportantClient secret authentication transmits the secret in plain text. Use this method only on a trusted network, such as localhost, an internal network, or a virtual private network (VPN). Do not use client secret authentication in production environments exposed to the internet.
:::

The client secret handler creates an identity with the **CmsAdmins** role, which grants full access to all CMS tools. This is suitable for development where permission scoping is not required.

### Custom authentication

For scenarios where client secret authentication is not appropriate, you can implement a custom authentication handler. This is useful when you want to authenticate MCP requests with an existing authentication system such as the CMS Management API's OAuth2 flow.

A custom authentication implementation follows a three-part pattern:

1. **Authentication handler** – Create a class that extends `AuthenticationHandler<AuthenticationSchemeOptions>` and override `HandleAuthenticateAsync()`. The handler validates incoming credentials (for example, a JWT or API key) and returns a `ClaimsPrincipal` representing an authenticated identity that CMS can resolve.
2. `IMcpServerBuilder`**&#x20;extension method** – Register the authentication handler with `AddScheme<>()`, define an authorization policy with `AddAuthorizationBuilder().AddPolicy()`, and optionally register an `ISynchronizedApplicationsRepository` interceptor so the MCP application identity is visible in the CMS permission system.
3. `IEndpointConventionBuilder`**&#x20;extension method** – Apply the authorization policy to the MCP endpoint with `RequireAuthorization()`.

Register and map using the same pattern as client secret authentication:

```csharp
services.AddCmsMcpServer().WithYourCustomAuthentication();

endpoints.MapMcp("/mcp").RequireYourCustomAuthorization();
```

The authenticated identity's CMS permissions determine which tools it can use. Some tools, such as content type management, require the **CmsAdmins** role. Other tools operate under the identity's own content permissions. Your authentication handler should verify the identity has the required permissions, not assign roles it does not have.

## Connect an MCP client

After configuring the MCP server, connect your AI development tool by pointing it to the MCP endpoint. The configuration depends on the authentication method you chose.

### Connect with client secret authentication

With client secret authentication, the MCP client sends the secret directly in the `Authorization` header. This works with any MCP client that supports streamable HTTP transport.

### Claude Code

Add to `.mcp.json` or project settings:

```json
{
  "mcpServers": {
    "optimizely-cms": {
      "type": "http",
      "url": "https://YOUR_CMS_HOST/mcp",
      "headers": {
        "Authorization": "your-secret-value"
      }
    }
  }
}
```

### Cursor

Add to `.cursor/mcp.json` in your project root (or `~/.cursor/mcp.json` for global configuration):

```json
{
  "mcpServers": {
    "optimizely-cms": {
      "type": "http",
      "url": "https://YOUR_CMS_HOST/mcp",
      "headers": {
        "Authorization": "your-secret-value"
      }
    }
  }
}
```

### Codex

Add to `~/.codex/config.toml` (or `.codex/config.toml` in a trusted project directory):

```toml
[mcp_servers.optimizely-cms]
type = "http"
url = "https://YOUR_CMS_HOST/mcp"

[mcp_servers.optimizely-cms.headers]
Authorization = "your-secret-value"
```

### Other MCP clients

Any MCP client that supports streamable HTTP transport can connect. Configure the client with:

- **Endpoint URL**: `https://YOUR_CMS_HOST/mcp`
- **Transport**: Streamable HTTP (stateless)
- **Authentication**: The shared secret value in the `Authorization` header
