A Model Context Protocol (MCP) server for Optimizely CMS, providing AI assistants with comprehensive access to Optimizely's GraphQL API and Content Management API.
- GraphQL Integration: Query content using Optimizely Graph API with multiple authentication methods
- Content Management: Full CRUD operations via Content Management API (Preview3/Experimental)
- Intelligent Content Creation: Automatically handles null values and finds parent pages by name
- Version Management: Create, publish, and manage content versions
- Content Types: Explore and understand content type schemas
- Workflow Support: Manage content approval workflows
- Multi-language Support: Handle content in multiple languages
- Caching: Built-in caching for improved performance
- Type Safety: Full TypeScript support with runtime validation
# Clone the repository git clone https://github.com/your-org/optimizely-mcp-server.git cd optimizely-mcp-server # Install dependencies npm install # Build the project npm run build
Create a .env
file in the project root:
# Server Configuration SERVER_NAME=optimizely-mcp-server SERVER_VERSION=1.0.0 TRANSPORT=stdio # Optimizely Graph Configuration GRAPH_ENDPOINT=https://cg.optimizely.com/content/v2 GRAPH_AUTH_METHOD=single_key # Options: single_key, hmac, basic, bearer, oidc GRAPH_SINGLE_KEY=your-single-key # For HMAC auth: # GRAPH_APP_KEY=your-app-key # GRAPH_SECRET_KEY=your-secret-key # Content Management API Configuration CMA_BASE_URL=https://api.cms.optimizely.com/preview3 CMA_CLIENT_ID=your-client-id # Get from Settings > API Keys in CMS CMA_CLIENT_SECRET=your-client-secret CMA_GRANT_TYPE=client_credentials CMA_TOKEN_ENDPOINT=https://api.cms.optimizely.com/oauth/token CMA_IMPERSONATE_USER= # Optional: User email to impersonate (see Impersonation section) # Optional Configuration CACHE_TTL=300000 # Cache TTL in milliseconds (default: 5 minutes) LOG_LEVEL=info # Options: debug, info, warn, error MAX_RETRIES=3 TIMEOUT=30000
# Run with hot reloading npm run dev # Run with debug logging LOG_LEVEL=debug npm run dev
# Build and run npm run build npm start # Or run directly node dist/index.js
# Run all unit tests npm test # Run tests with coverage npm run test:coverage # Type checking npm run typecheck # Linting npm run lint
MCP servers communicate via stdio (standard input/output), not HTTP ports:
- No port required - The server doesn't listen on any network port
- Process-based - Claude Desktop spawns your server as a child process
- JSON-RPC messages - Communication happens through stdin/stdout pipes
- Secure - No network exposure, runs only when Claude needs it
Open the configuration file in a text editor:
- Windows:
%APPDATA%\Claude\claude_desktop_config.json
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json
- Linux:
~/.config/Claude/claude_desktop_config.json
For Windows, you can open it quickly with:
notepad %APPDATA%\Claude\claude_desktop_config.json
{ "mcpServers": { "optimizely": { "command": "node", "args": ["%USERPROFILE%\\path\\to\\optimizely-mcp-server\\dist\\index.js"], "env": { "LOG_LEVEL": "error", "GRAPH_ENDPOINT": "https://cg.optimizely.com/content/v2", "GRAPH_AUTH_METHOD": "single_key", "GRAPH_SINGLE_KEY": "your-key", "CMA_BASE_URL": "https://api.cms.optimizely.com/preview3/experimental", "CMA_CLIENT_ID": "your-client-id", "CMA_CLIENT_SECRET": "your-client-secret", "CMA_GRANT_TYPE": "client_credentials", "CMA_TOKEN_ENDPOINT": "https://api.cms.optimizely.com/oauth/token", "CMA_IMPERSONATE_USER": "" } } } }
In JSON on Windows, you must use double backslashes (\). If your folder path has spaces, this still works because each argument is a separate JSON string.
- Windows: %USERPROFILE% expands to your home directory (e.g., C:\Users\Alice). If Claude doesn’t expand it automatically, replace it with your actual path (e.g., C:\Users\Alice\path\to\optimizely-mcp-server\dist\index.js). In PowerShell, the equivalent is $env:USERPROFILE, but inside this JSON config you should keep %USERPROFILE% or use the full path.
- macOS/Linux: the equivalent shortcut is ~ or $HOME (e.g., /Users/alice or /home/alice). If ~/$HOME isn’t expanded correctly, replace it with the full path.
After saving the config file:
- Completely quit Claude Desktop (not just close the window)
- Start Claude Desktop again
- The Optimizely tools should now be available
In a new Claude conversation, try:
- "Can you list the available Optimizely tools?"
- "Use the health-check tool to test the connection"
If the server doesn't load:
- Check the file path is correct and uses proper escaping (
\\
for Windows) - Ensure you've built the project (
npm run build
) - Verify the
dist/index.js
file exists - Check Claude's logs for errors
For other MCP-compatible clients, use the stdio transport configuration:
{ "name": "optimizely", "transport": { "type": "stdio", "command": "node", "args": ["/path/to/optimizely-mcp-server/dist/index.js"] }, "env": { // Environment variables as above } }
test_connection
- Test connectivity to Optimizely APIshealth_check
- Check server health statusget_config
- Get current configuration (sanitized)
graph_search
- Full-text content searchgraph_autocomplete
- Get autocomplete suggestionsgraph_facet_search
- Search with faceted filteringgraph_get_by_id
- Get content by numeric IDgraph_get_by_guid
- Get content by GUIDgraph_get_children
- Get child content itemsgraph_get_ancestors
- Get ancestor hierarchygraph_get_descendants
- Get all descendantsgraph_get_by_route
- Get content by route segmentgraph_get_by_url
- Get content by full URL
content_create
- Create new contentcontent_get
- Get content by IDcontent_update
- Update existing contentcontent_patch
- Apply JSON Patch operationscontent_delete
- Delete contentcontent_move
- Move content to new locationcontent_copy
- Copy content
version_list
- List all content versionsversion_get
- Get specific versionversion_create
- Create new versionversion_publish
- Publish a versionversion_set_common_draft
- Set as common draft
type_list
- List available content typestype_get
- Get content type detailstype_get_schema
- Get JSON schema for type
workflow_get
- Get workflow statusworkflow_transition
- Change workflow state
These tools combine GraphQL and CMA to provide smart content creation:
content_find_by_name
- Find content by name (e.g., "Home", "News") to get IDs and GUIDscontent_get_details
- Get full details including GUID for a specific contentcontent_create_under
- Create content under a parent by name (e.g., "create under Home")content_creation_wizard
- Interactive wizard for guided content creation
The MCP server now intelligently handles content creation when Claude sends null values:
- Automatic Parent Finding: If no parent container is provided, it searches for common parent pages (Home, Start, Root)
- Content Type Mapping: Maps human-readable types like "article page" to actual types like "ArticlePage"
- Graceful Fallbacks: Falls back to "StandardPage" if the requested content type doesn't exist
Instead of needing to know the Home page's GUID, you can now:
- Use
content_find_by_name
with "Home" to find the page - Use
content_create_under
to create content directly under it - Or use
content_creation_wizard
for a step-by-step process - Even
content-create
now automatically handles null values intelligently!
optimizely-mcp-server/ ├── src/ │ ├── index.ts # Server entry point │ ├── register.ts # Tool registration │ ├── config.ts # Configuration management │ ├── clients/ # API clients │ │ ├── graph-client.ts │ │ └── cma-client.ts │ ├── logic/ # Tool implementations │ │ ├── utility/ │ │ ├── graph/ │ │ └── content/ │ ├── types/ # TypeScript types │ └── utils/ # Utilities ├── tests/ # Test files ├── dist/ # Built output └── package.json
- Create tool implementation in
src/logic/
- Add tool registration in appropriate section
- Add TypeScript types if needed
- Write tests in
tests/
- Update documentation
- Unit tests for all tool implementations
- Integration tests for API clients
- Mock external API calls
- Test error scenarios
- Maintain >80% coverage
Run automated tests with Vitest:
# Run unit tests npm test # Run with coverage report npm run test:coverage
Unit tests are located in /tests/
and cover:
- GraphQL client functionality
- CMA client operations
- Health check features
Test your setup with these npm scripts:
# Check credentials are valid npm run check:credentials # Test MCP tools npm run test:tools # Test with debug output npm run test:tools:debug # Test GraphQL connection npm run debug:graph # Validate API key format npm run validate:key
The scripts/
directory contains utilities for testing and debugging:
quick-test.js
- Test MCP server tools through stdiotest-with-debug.js
- Detailed API request/response loggingdebug-graph.js
- Direct GraphQL endpoint testingdebug-auth-comprehensive.js
- Test all authentication methodsvalidate-key.js
- Validate GraphQL key formatfind-graphql-endpoint.js
- Discover your GraphQL endpoint
For PowerShell users, set environment variables like this:
$env:LOG_LEVEL="debug"; npm run test:tools:debug
See scripts/TESTING_SCRIPTS.md for detailed documentation.
-
Authentication Errors
- Verify your API credentials in
.env
- For CMA: Create API keys in Settings > API Keys in your Optimizely CMS instance
- Check token expiration for CMA (tokens expire after 5 minutes)
- Ensure correct auth method for Graph
- Verify your API credentials in
-
Connection Issues
- Verify network connectivity
- Check firewall settings
- Confirm API endpoints are accessible
-
Build Errors
- Run
npm install
to ensure dependencies - Check Node.js version (>=18 required)
- Clear
dist/
and rebuild
- Run
-
403 Forbidden Errors (Content Creation)
- This typically means insufficient permissions
- See the Impersonation section below for a solution
- Verify the user has content creation rights
- Check the target container allows the content type
Enable debug logging for troubleshooting:
LOG_LEVEL=debug npm start
Test server connectivity:
# Using the built tool echo '{"method": "tools/call", "params": {"name": "health_check"}}' | node dist/index.js
If you encounter 403 Forbidden errors when creating content, you can use user impersonation to execute API calls as a specific user who has the necessary permissions.
Use impersonation when:
- The API client lacks content creation permissions
- You need to test with different user permission levels
- You want actions attributed to a specific user
-
Enable Impersonation in Optimizely CMS:
- Log into Optimizely CMS as an administrator
- Navigate to Settings > API Clients
- Find your API client
- Enable the "Allow impersonation" option
- Save the changes
-
Configure the MCP Server:
# In your .env file CMA_IMPERSONATE_USER=user@example.com
-
Update Claude Desktop Config (if using environment variables):
{ "mcpServers": { "optimizely": { "env": { "CMA_IMPERSONATE_USER": "user@example.com", // ... other settings } } } }
When impersonation is configured:
- Authentication requests use JSON format with
act_as
field - All content operations execute as the impersonated user
- Created content shows the impersonated user as the author
Test that impersonation is working:
# Run the impersonation test script node scripts/test-impersonation-final.js
This will create test content and show which user created it.
- Only enable impersonation when necessary
- Use accounts with minimal required permissions
- Regularly review API client permissions
- Monitor API usage logs for unusual activity
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests
- Run
npm test
andnpm run typecheck
- Submit a pull request
MIT