Skip to main content
Glama
README.md
# Sitecore XM Cloud MCP Server — Complete Documentation

This repository is a **Next.js application** that exposes a **Model Context Protocol (MCP) server** for **Sitecore XM Cloud**. AI clients (Cursor, Sitecore Agentic Studio, Claude Desktop, etc.) can connect to it and invoke tools that perform Sitecore authoring operations — today, primarily **creating data templates** via the Sitecore Authoring GraphQL API.

The app is designed to run locally or on **Vercel**, and it implements the **OAuth discovery and proxy routes** required for **Sitecore Agentic Studio** to authenticate against the MCP endpoint.

---

## Table of Contents

1. [Repo details](#1-repo-details)
2. [High-level architecture](#2-high-level-architecture)
3. [Two separate authentication systems](#3-two-separate-authentication-systems)
4. [Project structure](#4-project-structure)
5. [Route reference — what each endpoint does and why it exists](#5-route-reference--what-each-endpoint-does-and-why-it-exists)
6. [MCP tools](#6-mcp-tools)
7. [Core library modules](#7-core-library-modules)
8. [Environment variables](#8-environment-variables)
9. [Setup and running locally](#9-setup-and-running-locally)
10. [Usage examples](#10-usage-examples)
11. [Quick reference — all endpoints](#11-quick-reference--all-endpoints)

---

## 1. Repo Details



| Capability | How |
|---|---|
| AI-driven Sitecore operations | MCP tool `createTemplate` wraps Sitecore GraphQL |
| XM Cloud authentication | Server-side client credentials flow, token cached |
| MCP over HTTP | `mcp-handler` provides Streamable HTTP + SSE transports |
| Sitecore Agentic Studio compatibility | OAuth discovery + proxy routes backed by Auth0 |
| Direct REST testing | `/api/sitecore/templates` and `/api/sitecore/token` |

In short: **this repo is a bridge between AI MCP clients and Sitecore XM Cloud**, with OAuth plumbing so enterprise Sitecore tools can connect securely.

---

## 2. High-level architecture

```mermaid
flowchart TB
    subgraph clients [AI Clients]
        Cursor[Cursor / Claude Desktop]
        Agentic[Sitecore Agentic Studio]
        REST[Direct REST callers]
    end

    subgraph nextjs [Next.js App - sitecore-mcp]
        MCP["/api/mcp"]
        OAuth["OAuth routes<br/>/.well-known/*"]
        SitecoreAPI["/api/sitecore/*"]
        Lib["src/lib/sitecore/*"]
    end

    subgraph external [External Services]
        Auth0[Auth0]
        XMCloud["Sitecore XM Cloud<br/>auth.sitecorecloud.io"]
        GraphQL["Authoring GraphQL API"]
    end

    Cursor -->|MCP HTTP optional Bearer| MCP
    Agentic -->|OAuth discovery + MCP| OAuth
    Agentic --> MCP
    REST --> SitecoreAPI

    OAuth --> Auth0
    MCP --> Lib
    SitecoreAPI --> Lib
    Lib -->|client_credentials| XMCloud
    Lib -->|Bearer token| GraphQL
```

**Data flow for a template creation:**

1. MCP client calls `createTemplate` tool on `/api/mcp`.
2. MCP handler invokes `createSitecoreTemplate()` in the library layer.
3. Library obtains (or reuses cached) XM Cloud bearer token.
4. Library resolves parent folder path → GUID, then runs `createItemTemplate` GraphQL mutation.
5. Result is returned to the AI client as JSON text content.

---

## 3. Two separate authentication systems


### A. Sitecore XM Cloud auth (server → Sitecore)

- **Who uses it:** The Next.js server itself, when calling Sitecore GraphQL.
- **How:** OAuth 2.0 `client_credentials` with an **XM Cloud Automation Client**.
- **Env vars:** `SITECORE_CLIENT_ID`, `SITECORE_CLIENT_SECRET`, `SITECORE_AUTHORING_ENDPOINT`
- **Token endpoint:** `https://auth.sitecorecloud.io/oauth/token`
- **Audience:** `https://api.sitecorecloud.io`
- **Implementation:** `src/lib/sitecore/auth.ts` — tokens are cached in memory until near expiry.

This auth is **never exposed to MCP clients**. The server holds Sitecore credentials and acts on behalf of the connected AI user.

### B. MCP client OAuth (client → this app)

- **Who uses it:** MCP clients like **Sitecore Agentic Studio** that require OAuth before accessing `/api/mcp`.
- **How:** OAuth 2.0 Authorization Code flow with PKCE, proxied through this app to **Auth0**.
- **Env vars:** `AUTH0_DOMAIN`, `AUTH0_AUDIENCE`, `AUTH0_WEB_CLIENT_ID`, `AUTH0_WEB_CLIENT_SECRET`, `MCP_BASE_URL`
- **Implementation:** OAuth routes under `/oauth/*` and `/.well-known/*`.

When a client hits `/api/mcp` without a `Bearer` token, `withMcpOAuthChallenge` returns **401 Unauthorized** with a `WWW-Authenticate` header pointing to resource metadata — this triggers the client's OAuth discovery flow.

> **Note:** The current OAuth middleware only checks that a Bearer token **is present**; it does not validate the JWT against Auth0. Full token verification would be a natural next hardening step.

---

## 4. Project structure

```
sitecore-mcp/
├── src/
│   ├── app/
│   │   ├── page.tsx                          # Landing page with setup hints
│   │   ├── layout.tsx                        # Root layout
│   │   ├── api/
│   │   │   ├── mcp/
│   │   │   │   ├── route.ts                  # Main MCP endpoint (auth-wrapped)
│   │   │   │   ├── mcpServer.ts              # MCP tool definitions
│   │   │   │   ├── sse/route.ts              # SSE transport (GET)
│   │   │   │   └── message/route.ts          # SSE message channel (POST)
│   │   │   └── sitecore/
│   │   │       ├── token/route.ts            # Debug: verify Sitecore auth
│   │   │       └── templates/route.ts        # REST alternative to MCP tool
│   │   ├── oauth/
│   │   │   ├── authorize/route.ts            # Start OAuth → redirect to Auth0
│   │   │   ├── callback/route.ts             # Auth0 callback → redirect to Sitecore
│   │   │   ├── token/route.ts                # Exchange code for Auth0 tokens
│   │   │   └── register/route.ts             # Dynamic client registration (stub)
│   │   └── .well-known/
│   │       ├── oauth-authorization-server/   # OAuth server metadata
│   │       └── oauth-protected-resource/     # Protected resource metadata
│   │           └── api/mcp/                  # Resource-specific metadata for MCP
│   └── lib/
│       └── sitecore/
│           ├── config.ts                     # Sitecore env config
│           ├── auth.ts                       # XM Cloud token acquisition + cache
│           ├── graphql.ts                    # GraphQL client with 401 retry
│           ├── createTemplate.ts             # Template creation business logic
│           ├── oauthMetadata.ts              # OAuth discovery JSON builders
│           └── withMcpOAuthChallenge.ts      # 401 + WWW-Authenticate middleware
├── .env.example
├── vercel.json                               # 60s maxDuration for MCP routes
└── package.json
```

**Key dependencies:**

| Package | Role |
|---|---|
| `next` | App framework and API route hosting |
| `mcp-handler` | Vercel adapter for MCP (Streamable HTTP + SSE) |
| `@modelcontextprotocol/sdk` | MCP protocol SDK |
| `zod` | Tool input schema validation |

---

## 5. Route reference — what each endpoint does and why it exists

### MCP routes

| Route | Methods | Auth | Purpose |
|---|---|---|---|
| `/api/mcp` | GET, POST, DELETE | Bearer required (GET/POST) | **Primary MCP endpoint.** Streamable HTTP transport. Sitecore Agentic Studio connects here. Wrapped with `withMcpOAuthChallenge`. DELETE is unwrapped for MCP session cleanup. |
| `/api/mcp/sse` | GET | None | **SSE transport entry point.** Required by `mcp-handler` when clients use Server-Sent Events instead of Streamable HTTP. Uses `basePath: "/api"` so sibling routes are `/api/mcp/sse` and `/api/mcp/message`. |
| `/api/mcp/message` | POST | None | **SSE message channel.** Clients POST MCP messages here when using the SSE transport pattern. |

**Why three MCP routes?**  
The MCP spec supports multiple transports. `mcp-handler` splits SSE into an event stream (`/sse`) and a message POST endpoint (`/message`), while Streamable HTTP uses a single `/mcp` route. Supporting both maximizes client compatibility (Cursor, Claude, Agentic Studio, etc.).

---

### OAuth discovery routes (`.well-known`)

| Route | Method | Purpose |
|---|---|---|
| `/.well-known/oauth-protected-resource` | GET | Returns **protected resource metadata** — tells OAuth clients which authorization server protects this resource. |
| `/.well-known/oauth-protected-resource/api/mcp` | GET | **Resource-specific metadata** for the MCP endpoint. Referenced in the `WWW-Authenticate` header when `/api/mcp` returns 401. |
| `/.well-known/oauth-authorization-server` | GET | Returns **authorization server metadata** — issuer, authorize/token/register endpoints, supported grant types, PKCE methods, scopes. |

**Why these exist?**  
Sitecore Agentic Studio (and the MCP OAuth spec) require clients to **auto-discover** how to authenticate. When `/api/mcp` returns 401 with `resource_metadata=".../.well-known/oauth-protected-resource/api/mcp"`, the client fetches that URL, learns the authorization server, and starts the OAuth flow — no manual OAuth config in the client.

---

### OAuth proxy routes

| Route | Method | Purpose |
|---|---|---|
| `/oauth/register` | POST | **Dynamic Client Registration (DCR) stub.** Returns a fixed client ID/secret so Agentic Studio can "register" without a real DCR server. |
| `/oauth/authorize` | GET | **Authorization entry point.** Receives PKCE params from Sitecore, encodes state, redirects user to Auth0 login. |
| `/oauth/callback` | GET | **Auth0 callback handler.** Receives Auth0 auth code, fixes localhost redirect quirks, redirects back to Sitecore with the code. |
| `/oauth/token` | POST | **Token exchange proxy.** Sitecore sends the auth code here; this route exchanges it with Auth0 and returns access/id/refresh tokens. |

**Why a proxy instead of pointing Sitecore directly at Auth0?**  
Sitecore Agentic Studio expects the MCP server's own domain to be the OAuth issuer (per MCP protected-resource spec). This app acts as an **OAuth facade**: discovery endpoints live on your MCP domain, while Auth0 handles real identity. The callback route also contains a workaround for Sitecore's `https://0.0.0.0:3000` localhost redirect issue.

---

### Sitecore REST routes (testing / direct API)

| Route | Method | Purpose |
|---|---|---|
| `/api/sitecore/token` | GET | Verifies XM Cloud credentials work. Returns auth endpoint, audience, token expiry — **does not return the raw token** (security). |
| `/api/sitecore/templates` | POST | REST alternative to the MCP `createTemplate` tool. Same underlying logic, useful for Postman/curl testing. |

**Why REST routes when MCP exists?**  
They let developers **debug Sitecore connectivity independently** of MCP/OAuth complexity. If template creation fails, you can isolate whether the problem is Sitecore auth or MCP client auth.

---

### UI

| Route | Purpose |
|---|---|
| `/` | Simple landing page documenting endpoints, auth flow. |

---

## 6. MCP tools

Currently one tool is registered in `mcpServer.ts`:

### `createTemplate`

Creates a Sitecore **data template** under a parent folder using the `createItemTemplate` GraphQL mutation.

**Input parameters:**

| Parameter | Type | Required | Description |
|---|---|---|---|
| `templateName` | string | Yes | Name of the new data template |
| `parentPath` | string | Yes | Parent folder item path (e.g. `/sitecore/templates/Feature`) or parent item GUID |
| `sections` | array | No | Template sections with fields. Currently only the **first section** is sent to GraphQL. |

**Section/field shape:**

```json
{
  "sections": [
    {
      "name": "Content",
      "fields": [
        { "name": "Title", "type": "Single-Line Text" },
        { "name": "Body", "type": "Rich Text" }
      ]
    }
  ]
}
```

**Success response:**

```json
{
  "success": true,
  "template": {
    "id": "{GUID}",
    "name": "My Template",
    "fields": [{ "name": "Title", "type": "Single-Line Text" }]
  }
}
```

**Internal steps:**

1. Resolve `parentPath` → parent GUID (path lookup via GraphQL, or normalize if already a GUID).
2. Build and execute `createItemTemplate` mutation against the Authoring GraphQL endpoint.
3. Return created template ID, name, and fields.

---

## 7. Core library modules

### `config.ts`
Loads and validates Sitecore environment variables. Defaults auth endpoint and audience to standard XM Cloud values.

### `auth.ts`
- Calls `client_credentials` against Sitecore auth endpoint.
- Caches token in memory with 60-second expiry buffer.
- Exposes `clearSitecoreTokenCache()` for retry on 401.

### `graphql.ts`
- Generic GraphQL executor for the Authoring API.
- Automatically attaches Sitecore bearer token.
- Retries once on 401 after clearing token cache.
- Throws on HTTP errors or GraphQL `errors` array.

### `createTemplate.ts`
- Business logic for template creation.
- Path → GUID resolution.
- GraphQL mutation builder with string escaping.
- Structured `{ success, template?, error? }` result type.

### `oauthMetadata.ts`
- Builds OAuth discovery JSON payloads.
- Reads `AUTH0_AUDIENCE` as the protected resource identifier.
- Points authorization server metadata back to this app's `/.well-known/oauth-authorization-server`.

### `withMcpOAuthChallenge.ts`
- Middleware wrapper for MCP routes.
- Returns 401 + `WWW-Authenticate: Bearer resource_metadata="..."` when no Bearer token.
- Passes through to handler when Bearer is present.

---

## 8. Environment variables

Copy `.env.example` to `.env.local` for local development.

### Sitecore XM Cloud (required for template operations)

| Variable | Description |
|---|---|
| `SITECORE_CLIENT_ID` | XM Cloud Automation Client ID |
| `SITECORE_CLIENT_SECRET` | XM Cloud Automation Client secret |
| `SITECORE_AUTHORING_ENDPOINT` | Authoring GraphQL URL, e.g. `https://your-instance.sitecorecloud.io/sitecore/api/authoring/graphql/v1` |
| `SITECORE_AUTH_ENDPOINT` | Optional. Default: `https://auth.sitecorecloud.io/oauth/token` |
| `SITECORE_AUDIENCE` | Optional. Default: `https://api.sitecorecloud.io` |

### Auth0 / MCP OAuth (required for Sitecore Agentic Studio)

| Variable | Description |
|---|---|
| `AUTH0_DOMAIN` | Auth0 tenant domain, e.g. `your-tenant.us.auth0.com` |
| `AUTH0_AUDIENCE` | Auth0 API identifier — also used as the protected resource URL (typically your deployed app URL) |
| `AUTH0_WEB_CLIENT_ID` | Auth0 application client ID |
| `AUTH0_WEB_CLIENT_SECRET` | Auth0 application client secret |
| `MCP_BASE_URL` | Public base URL of this app, e.g. `https://your-app.vercel.app` or `http://localhost:3000` |

### App

| Variable | Description |
|---|---|
| `NEXT_PUBLIC_APP_URL` | Public app URL (referenced in `.env.example`; some OAuth routes use `MCP_BASE_URL` instead) |


---

## 9. Setup and running locally

### Prerequisites

- Node.js 18+
- XM Cloud Automation Client credentials (from XM Cloud Deploy)
- Auth0 tenant (only if using Sitecore Agentic Studio OAuth)

### Steps

```bash
# 1. Install dependencies
npm install

# 2. Configure environment
cp .env.example .env.local
# Edit .env.local with your credentials

# 3. Add MCP_BASE_URL to .env.local
# MCP_BASE_URL=http://localhost:3000

# 4. Start dev server
npm run dev
```

App runs at `http://localhost:3000`.

### Verify Sitecore connectivity

```bash
curl http://localhost:3000/api/sitecore/token
```

Expected: `{ "success": true, "expiresIn": ..., ... }`

### Create a template via REST

```bash
curl -X POST http://localhost:3000/api/sitecore/templates \
  -H "Content-Type: application/json" \
  -d '{
    "templateName": "Test Template",
    "parentPath": "/sitecore/templates/Feature",
    "sections": [{
      "name": "Content",
      "fields": [{ "name": "Title", "type": "Single-Line Text" }]
    }]
  }'
```

---



## 10. Usage examples



### Sitecore Agentic Studio

Point Agentic Studio at your deployed MCP URL:

```
https://your-app.vercel.app/api/mcp
```

Agentic Studio will automatically run the OAuth discovery flow using the `/.well-known` and `/oauth` routes.

---


---

## 11. Quick reference — all endpoints

| Endpoint | Method | Category |
|---|---|---|
| `/` | GET | UI |
| `/api/mcp` | GET, POST, DELETE | MCP (auth on GET/POST) |
| `/api/mcp/sse` | GET | MCP SSE transport |
| `/api/mcp/message` | POST | MCP SSE messages |
| `/api/sitecore/token` | GET | Sitecore debug |
| `/api/sitecore/templates` | POST | Sitecore REST |
| `/.well-known/oauth-protected-resource` | GET | OAuth discovery |
| `/.well-known/oauth-protected-resource/api/mcp` | GET | OAuth discovery (MCP) |
| `/.well-known/oauth-authorization-server` | GET | OAuth discovery |
| `/oauth/register` | POST | OAuth DCR stub |
| `/oauth/authorize` | GET | OAuth start |
| `/oauth/callback` | GET | OAuth Auth0 callback |
| `/oauth/token` | POST | OAuth token exchange |