Model Context Protocol (MCP) server for Sitecore Customer Data Platform APIs
npm install @markstiles/sitecore-cdp-mcpbash
npm install @markstiles/sitecore-cdp-mcp
`
Configuration
$3
Create a .env file in your project root:
`env
Required: Your CDP instance base URL
CDP_BASE_URL=https://api-engage-us.sitecorecloud.io
Required: Basic Auth credentials (for Guest and Order APIs)
CDP_CLIENT_KEY=your_client_key
CDP_API_TOKEN=your_api_token
Optional: OAuth 2.0 credentials (for Audience Export API)
Note: Only required if using Audience Export features
These are different from Basic Auth credentials above
CDP_OAUTH_KEY=your_oauth_client_id
CDP_OAUTH_SECRET=your_oauth_client_secret
Optional: Retry configuration
CDP_RETRY_MAX_ATTEMPTS=3
CDP_RETRY_DELAY_MS=1000
`
$3
#### Basic Auth Credentials (Guest & Order APIs)
In Sitecore CDP:
1. Navigate to Settings > API Access
2. Client Key = Your username for Basic Auth (CDP_CLIENT_KEY)
3. API Token = Your password for Basic Auth (CDP_API_TOKEN)
#### OAuth 2.0 Credentials (Audience Export API)
For Audience Export functionality, you need separate OAuth credentials:
1. Navigate to Settings > API Access > OAuth
2. Create or use existing OAuth client credentials
3. OAuth Client ID = CDP_OAUTH_KEY
4. OAuth Client Secret = CDP_OAUTH_SECRET
Note: OAuth tokens are managed automatically by the server with in-memory caching (24-hour expiry with 5-minute refresh buffer).
MCP Server Setup
$3
Add to your Claude Desktop configuration file:
macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
Windows: %APPDATA%\Claude\claude_desktop_config.json
`json
{
"mcpServers": {
"sitecore-cdp": {
"command": "node",
"args": [
"/path/to/node_modules/@markstiles/sitecore-cdp-mcp/dist/index.js"
],
"env": {
"CDP_BASE_URL": "https://api-engage-us.sitecorecloud.io",
"CDP_CLIENT_KEY": "your_client_key",
"CDP_API_TOKEN": "your_api_token",
"CDP_OAUTH_KEY": "your_oauth_client_id",
"CDP_OAUTH_SECRET": "your_oauth_client_secret"
}
}
}
}
`
Note: OAuth credentials are only required if you plan to use Audience Export features. Guest and Order management only require Basic Auth credentials.
Or if installed globally:
`json
{
"mcpServers": {
"sitecore-cdp": {
"command": "sitecore-cdp-mcp",
"env": {
"CDP_BASE_URL": "https://api-engage-us.sitecorecloud.io",
"CDP_CLIENT_KEY": "your_client_key",
"CDP_API_TOKEN": "your_api_token",
"CDP_OAUTH_KEY": "your_oauth_client_id",
"CDP_OAUTH_SECRET": "your_oauth_client_secret"
}
}
}
}
`
Available MCP Tools
$3
#### cdp_guest_create
Create a new guest profile in Sitecore CDP.
Important: Always search for existing guests by email before creating to avoid duplicates.
`typescript
// Example usage in Claude
{
"guestType": "customer",
"firstName": "John",
"lastName": "Doe",
"email": "john.doe@example.com",
"phoneNumbers": ["+353161123345"],
"city": "Dublin",
"country": "IE"
}
`
Parameters:
- guestType (required): "visitor", "customer", or "traveller"
- firstName: Guest's first name
- lastName: Guest's last name
- email: Primary email address
- emails: Array of email addresses
- phoneNumbers: Array of phone numbers (E.164 format)
- dateOfBirth: ISO 8601 date-time (must be in the past)
- gender: "male", "female", or "unknown"
- title: Title (e.g., "Mr", "Mrs", "Dr")
- city, state, country, postCode, street: Address fields
- nationality, passportNumber, passportExpiry: Travel fields
- identifiers: Array of {provider, id} objects for external system linking
#### cdp_guest_search
Search for guests by email, identifiers, or order information.
`typescript
{
"email": "john.doe@example.com",
"limit": 10,
"offset": 0
}
`
Parameters:
- email: Search by email address
- identifiers: Search by identifier (format: "provider:id")
- orderReferenceId: Search by order reference ID
- orderRef: Search by order reference
- offset: Pagination offset (default: 0)
- limit: Results per page (default: 10, max: 100)
- sort: Sort field (e.g., "createdAt")
- expand: Include related data (default: false)
#### cdp_guest_get
Retrieve a guest profile by reference ID.
`typescript
{
"guestRef": "guest-reference-id",
"expand": false
}
`
Parameters:
- guestRef (required): The guest reference ID
- expand: Include data extensions and related data
#### cdp_guest_update
Update a guest profile with full replacement (PUT). All fields must be provided.
`typescript
{
"guestRef": "guest-reference-id",
"guestType": "customer",
"firstName": "John",
"lastName": "Doe",
"email": "john.doe@example.com",
"city": "London"
}
`
Note: This is a full replacement. Use cdp_guest_patch for partial updates.
#### cdp_guest_patch
Update specific fields of a guest profile (PATCH). Only provided fields are updated.
`typescript
{
"guestRef": "guest-reference-id",
"city": "London",
"country": "GB"
}
`
Parameters: Same as create/update, but all fields are optional except guestRef.
$3
#### cdp_order_create
Create a new order in Sitecore CDP.
`typescript
{
"referenceId": "ORDER-12345",
"orderedAt": "2024-01-15T10:30:00Z",
"currencyCode": "USD",
"price": 99.99,
"status": "PURCHASED",
"channel": "WEB"
}
`
Required Parameters:
- referenceId: Unique order identifier from your system
- orderedAt: ISO 8601 timestamp when order was placed
- currencyCode: ISO 4217 3-letter currency code (e.g., USD, EUR, GBP)
- price: Order amount
Optional Parameters:
- status: Order status - PENDING, CONFIRMED, PURCHASED, CANCELLED, etc.
- channel: Sales channel - WEB, MOBILE_APP, CALL_CENTER, BRANCH, etc.
- pointOfSale: Point of sale location
- total: Total including taxes and shipping
- subtotal: Subtotal before taxes
- paymentType: Payment method
- cardType: Card type if applicable
#### cdp_order_get
Retrieve an order by reference.
`typescript
{
"orderRef": "order-reference-id",
"expand": true
}
`
#### cdp_order_search
Search for orders by reference ID or guest.
`typescript
{
"guestRef": "guest-reference-id",
"limit": 10,
"offset": 0
}
`
Parameters:
- referenceId: Filter by order reference ID
- guestRef: Filter by guest reference
- offset, limit, sort, expand: Pagination options
#### cdp_order_update
Update an order (full replacement - all fields required).
#### cdp_order_patch
Partially update an order (only provided fields updated).
#### cdp_order_item_add
Add an item to an existing order.
`typescript
{
"orderRef": "order-reference-id",
"type": "product",
"name": "Premium Widget",
"price": 49.99,
"currencyCode": "USD",
"status": "CONFIRMED",
"productId": "WIDGET-001",
"referenceId": "ITEM-12345",
"quantity": 2
}
`
Required Parameters:
- orderRef: The order to add the item to
- type: Item type (e.g., product, service)
- name: Item name/description
- price: Item price
- currencyCode: Currency code
- status: Item status (e.g., CONFIRMED)
- productId: Product identifier
- referenceId: Item reference
#### cdp_order_contact_create
Create an order contact to link an order to a guest.
`typescript
{
"orderRef": "order-reference-id",
"guestRef": "guest-reference-id",
"firstName": "John",
"lastName": "Doe",
"emails": ["john.doe@example.com"]
}
`
Parameters:
- orderRef (required): The order reference
- guestRef (optional): Link to existing guest
- Contact fields: firstName, lastName, emails, phoneNumbers, street, city, etc.
Programmatic Usage
You can also use this package programmatically in your Node.js applications:
`typescript
import { GuestClient } from '@markstiles/sitecore-cdp-mcp';
const client = new GuestClient();
// Create a guest
const result = await client.createGuest({
guestType: 'customer',
firstName: 'Jane',
lastName: 'Smith',
email: 'jane.smith@example.com',
});
console.log('Guest created:', result.ref);
// Search for guests
const searchResults = await client.searchGuests({
email: 'jane.smith@example.com',
});
console.log('Found guests:', searchResults.items.length);
// Get guest details
const guest = await client.getGuest(result.ref);
console.log('Guest details:', guest);
// Update guest
const updated = await client.patchGuest(result.ref, {
city: 'Dublin',
country: 'IE',
});
// Delete guest
await client.deleteGuest(result.ref);
`
$3
`typescript
import { OrderClient, GuestClient } from '@markstiles/sitecore-cdp-mcp';
const orderClient = new OrderClient();
const guestClient = new GuestClient();
// Create an order
const order = await orderClient.createOrder({
referenceId: 'ORDER-12345',
orderedAt: new Date().toISOString(),
currencyCode: 'USD',
price: 149.99,
status: 'PURCHASED',
channel: 'WEB',
});
console.log('Order created:', order.ref);
// Add items to the order
const item = await orderClient.createOrderItem(order.ref, {
type: 'product',
name: 'Premium Widget',
price: 49.99,
currencyCode: 'USD',
status: 'CONFIRMED',
productId: 'WIDGET-001',
referenceId: 'ITEM-001',
quantity: 3,
});
// Link order to a guest via order contact
const contact = await orderClient.createOrderContact(
order.ref,
{
firstName: 'Jane',
lastName: 'Smith',
emails: ['jane.smith@example.com'],
},
guestRef // Optional: link to existing guest
);
// Search for guest's orders
const guestOrders = await orderClient.searchOrders({
guestRef: guestRef,
limit: 10,
});
console.log('Guest orders:', guestOrders.items.length);
`
Type Exports
All TypeScript types are exported for use in your applications:
`typescript
import {
// Guest types
Guest,
GuestCreateRequest,
GuestUpdateRequest,
GuestPatchRequest,
GuestSearchParams,
// Order types
Order,
OrderCreateRequest,
OrderUpdateRequest,
OrderPatchRequest,
OrderSearchParams,
OrderItem,
OrderItemCreateRequest,
OrderContact,
OrderContactCreateRequest,
// Common types
PaginatedResponse,
CdpError,
Identifier,
GuestType,
} from '@markstiles/sitecore-cdp-mcp';
`
Testing
$3
Integration tests run against your real CDP environment:
1. Set up your .env file with test credentials
2. Run tests:
`bash
npm test
`
Note: Integration tests create and delete real data in your CDP instance. Use a test/development environment.
$3
`bash
npm run test:coverage
`
$3
`bash
npm run test:watch
`
Development
$3
`bash
npm run build
`
$3
`bash
npm run dev
`
Error Handling
All errors from the CDP API are transformed into structured CdpError objects:
`typescript
interface CdpError {
status: number; // HTTP status code
code: number; // CDP error code
message: string; // User-friendly message
developerMessage: string; // Technical details
moreInfoUrl?: string; // Support documentation link
}
`
$3
The client automatically retries failed requests for:
- 5xx server errors
- 429 rate limiting errors
Retry behavior is configurable via environment variables:
- CDP_RETRY_MAX_ATTEMPTS: Maximum retry attempts (default: 3)
- CDP_RETRY_DELAY_MS: Initial delay in milliseconds (default: 1000)
Exponential backoff is applied: delay * 2^retryCount
Regional Endpoints
Sitecore CDP is available in multiple regions. Set your base URL accordingly:
- US: https://api-engage-us.sitecorecloud.io
- EU: https://api-engage-eu.sitecorecloud.io
- AP: https://api-engage-ap.sitecorecloud.io
- JP: https://api-engage-jpe.sitecorecloud.io
Security & Credential Management
$3
This MCP server uses environment variables for credential management, which is the most secure approach for several reasons:
1. Credentials are never exposed in code or logs
2. MCP clients (like Claude Desktop) securely pass environment variables to the server process
3. Credentials are never transmitted over the network or stored in chat history
4. Each user's credentials remain on their local machine
$3
#### Option 1: Tool-Level Parameters (Not Recommended)
Passing credentials as parameters to each tool call would:
- ❌ Expose credentials in chat history and logs
- ❌ Require credentials to be provided with every request
- ❌ Create security risks if the conversation is shared
#### Option 2: MCP Server Prompts (Future Enhancement)
The MCP protocol supports prompting users for input. A future enhancement could:
- ✅ Prompt for credentials on first tool use
- ✅ Cache credentials in memory for the session
- ✅ Provide better UX for non-technical users
- ⚠️ Requires MCP client support for prompts
Current Status: Environment variables provide the best balance of security, simplicity, and compatibility across MCP clients.
$3
For VS Code extensions that provide MCP servers, the resolveMcpServerDefinition method can handle authentication dynamically:
`typescript
resolveMcpServerDefinition(server, token) {
// Extension can prompt for credentials here
// Can integrate with VS Code's authentication API
return {
...server,
env: {
CDP_CLIENT_KEY: await getCredential('clientKey'),
CDP_API_TOKEN: await getCredential('apiToken')
}
};
}
`
This approach is useful for shared/team extensions but requires VS Code-specific implementation.
Roadmap
$3
- Create, search, retrieve, update, and patch guest profiles
- Full CRUD operations with validation
- Pagination and error handling
$3
- Create and manage orders
- Link orders to guests via order contacts
- Add order items with full product details
- Search orders by guest or reference ID
$3
- Guest data extensions
- Order data extensions
- Order item data extensions
- Custom field management
$3
- List and retrieve audience export jobs
- Download exported audience data
- OAuth 2.0 authentication with automatic token refresh
Resources
- Sitecore CDP Developer Documentation
- Model Context Protocol Documentation
- Claude Desktop Documentation
Publishing to npm
This section is for maintainers who want to publish the package to npm.
$3
1. npm Account: Create an account at npmjs.com
2. Login to npm:
`bash
npm login
`
Enter your username, password, and email when prompted.
3. Verify Login:
`bash
npm whoami
`
$3
If publishing a scoped package (like @markstiles/sitecore-cdp-mcp), decide on access level:
Option 1: Public Package (Free)
`bash
npm publish --access public
`
Option 2: Private Package (Requires paid npm account)
`bash
npm publish
`
$3
1. Update Version
Follow Semantic Versioning:
`bash
# Patch release (1.0.0 → 1.0.1) - Bug fixes
npm version patch
# Minor release (1.0.0 → 1.1.0) - New features, backward compatible
npm version minor
# Major release (1.0.0 → 2.0.0) - Breaking changes
npm version major
`
This automatically:
- Updates version in package.json
- Creates a git commit
- Creates a git tag
2. Build the Package
`bash
npm run build
`
The prepublishOnly script will run this automatically, but it's good to verify first.
3. Test the Package Locally (Optional)
`bash
# Create a tarball
npm pack
# This creates @markstiles-sitecore-cdp-mcp-1.0.0.tgz
# Test install in another project:
cd /path/to/test-project
npm install /path/to/cdp2/@markstiles-sitecore-cdp-mcp-1.0.0.tgz
`
4. Run Tests
`bash
npm test
`
Make sure all tests pass before publishing.
5. Publish to npm
`bash
# For scoped packages (first time)
npm publish --access public
# For subsequent releases
npm publish
`
6. Push Git Changes
`bash
git push origin main --follow-tags
`
$3
The published package includes (configured in package.json files array):
- dist/ - Compiled JavaScript and TypeScript declarations
- README.md - Package documentation
- LICENSE - MIT license file
Excluded (via .npmignore):
- Source TypeScript files (src/)
- Tests (test/)
- Environment files (.env*)
- Development configs
$3
1. Verify on npm: Visit https://www.npmjs.com/package/@markstiles/sitecore-cdp-mcp
2. Test Installation:
`bash
npm install @markstiles/sitecore-cdp-mcp
`
3. Create GitHub Release (Optional):
- Go to your GitHub repository
- Create a release from the version tag
- Add release notes describing changes
$3
Recommended approach for this project:
- Patch (1.0.x): Bug fixes, documentation updates, test improvements
- Minor (1.x.0): New tools, new API endpoints, new features (backward compatible)
- Example: Adding Phase 3 (Data Extensions) → 1.1.0
- Example: Adding Phase 4 (Audience Export) → 1.2.0
- Major (x.0.0): Breaking changes to public API, removed tools, changed interfaces
- Example: Changing tool names or parameters → 2.0.0
- Example: Requiring different authentication → 2.0.0
$3
Error: "You do not have permission to publish"
- Make sure you're logged in: npm whoami
- For scoped packages, use --access public
- Verify the package name is available
Error: "Version already published"
- Update version: npm version patch
- Each version can only be published once
Error: "Package name too similar to existing package"
- Choose a different name or add a scope
- Scoped packages (@username/package) are unique to your account
$3
For automated releases, create .github/workflows/publish.yml:
`yaml
name: Publish to npm
on:
release:
types: [created]
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '18'
registry-url: 'https://registry.npmjs.org'
- run: npm ci
- run: npm test
- run: npm publish --access public
env:
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
`
Then add your npm token to GitHub repository secrets as NPM_TOKEN`.