Adobe Journey Optimizer Content API MCP server
Enables interaction with Adobe Journey Optimizer content through the Content API, supporting sandbox configuration and secure credential management.
README
Adobe Journey Optimizer Content API MCP server
This project exposes Adobe Journey Optimizer Content API operations as MCP tools.
Quickstart
Follow these steps if you want to get the server running quickly.
- Create a
configfolder. - Add
config/credentials.jsonwith your Adobe credentials export. - Add
config/settings.jsonwith your sandbox name. - Build the Docker image.
- Start the server in either HTTP mode or stdio mode.
- Point your MCP client at the running server.
If you are not sure which transport to use:
- Use HTTP when your client connects to a URL like
http://localhost:3000/mcp. - Use stdio when your client launches this server as a subprocess.
Prerequisites
- Docker, if you want to run the containerized server
- Node.js 20+, if you want to run the server directly
- Adobe Journey Optimizer credentials exported as JSON
- The Adobe sandbox name you want the server to use
Recommended workspace layout
my-workspace/
├── config/
│ └── credentials.json
├── docker-compose.yml
└── ajo-content-mcp-server/
├── Dockerfile
└── ...
Place the exported Adobe environment JSON at config/credentials.json and create a small config/settings.json for the sandbox name. Mount ./config into the container.
Dedicated settings file
Create config/settings.json before starting the server.
Create config/settings.json like this:
{
"sandboxName": "dev"
}
The container reads this file by default from /app/config/settings.json and uses it to populate AJO_SANDBOX_NAME.
You can override the path with:
AJO_SETTINGS_FILE=/custom/path/settings.json
Behavior
At startup, the container:
- Looks for
/app/config/settings.jsonand loads the sandbox name. - Looks for
/app/config/credentials.jsonand loads the Adobe credentials. - Converts those JSON files into generated env files.
- Sources the generated env files.
- Starts the MCP server.
You can override the JSON path with:
AJO_CREDENTIALS_FILE=/custom/path/credentials.json
The credentials loader expects the Adobe credentials export to provide values such as CLIENT_SECRET, API_KEY, ACCESS_TOKEN, SCOPES, TECHNICAL_ACCOUNT_ID, IMS, and IMS_ORG. It maps those into the internal AJO_* environment variables used by the app.
Build
docker build -t ajo-content-api-mcp-server .
Run
Choose one of the following runtime modes.
The default container mode is HTTP:
docker run --rm -it \
-p 3000:3000 \
-v "$(pwd)/config:/app/config:ro" \
ajo-content-api-mcp-server
Run in HTTP mode
docker run --rm -it \
-p 3000:3000 \
-e MCP_TRANSPORT=http \
-e MCP_PORT=3000 \
-v "$(pwd)/config:/app/config:ro" \
ajo-content-api-mcp-server
Run in stdio mode
docker run --rm -i \
-e MCP_TRANSPORT=stdio \
-v "$(pwd)/config:/app/config:ro" \
ajo-content-api-mcp-server
Use stdio mode when your MCP client launches the containerized server as a subprocess and communicates over stdin/stdout.
Run Directly with Node.js
Build the project first:
npm install
npm run build
Run in HTTP mode:
AJO_SETTINGS_FILE="$(pwd)/config/settings.json" \
AJO_CREDENTIALS_FILE="$(pwd)/config/credentials.json" \
MCP_TRANSPORT=http \
MCP_PORT=3000 \
node dist/index.js
Run in stdio mode:
AJO_SETTINGS_FILE="$(pwd)/config/settings.json" \
AJO_CREDENTIALS_FILE="$(pwd)/config/credentials.json" \
MCP_TRANSPORT=stdio \
node dist/index.js
Docker Compose
services:
ajo-content-mcp:
build: .
image: ajo-content-api-mcp-server
environment:
MCP_TRANSPORT: http
MCP_PORT: 3000
ports:
- "3000:3000"
volumes:
- ./config:/app/config:ro
ajo-content-mcp-stdio:
build: .
image: ajo-content-api-mcp-server
command: ["node", "dist/index.js"]
environment:
MCP_TRANSPORT: stdio
stdin_open: true
tty: true
volumes:
- ./config:/app/config:ro
With this layout, credentials.json and settings.json both live under the same mounted folder. Use ajo-content-mcp for HTTP clients and ajo-content-mcp-stdio for subprocess-based stdio clients.
Connecting to the MCP Server
This MCP server supports both stdio and HTTP-streamable transports.
Best settings for local LLMs like Gemma
If you are connecting a smaller local model, prefer these settings:
- Use
stdiotransport when possible. - Start with the simplified wrapper tools:
list_fragmentsget_fragmentcreate_fragmentpublish_fragmentlist_templatesget_template
- Use the discovery resources first if your client supports MCP resources:
overview://capabilitiesoverview://operationsoverview://examples
- Fall back to the generated OpenAPI tools only when you need a less common API operation.
Why this helps:
- local LLMs often handle flat tool arguments better than nested
path/query/headers/bodyobjects - some MCP clients discover servers more reliably when resources are exposed
stdiois usually simpler for local MCP clients than session-based HTTP transports
Example stdio startup for local clients:
AJO_SETTINGS_FILE="$(pwd)/config/settings.json" \
AJO_CREDENTIALS_FILE="$(pwd)/config/credentials.json" \
MCP_TRANSPORT=stdio \
node dist/index.js
Transport selection
MCP_TRANSPORT=stdio— runs as a stdio MCP serverMCP_TRANSPORT=http— runs the HTTP-streamable server at/mcp(default)
Example stdio startup:
MCP_TRANSPORT=stdio node dist/index.js
This mode is intended for MCP clients that launch the server as a subprocess.
HTTP mode
When MCP_TRANSPORT is unset or set to http, the server exposes an HTTP-streamable MCP endpoint at /mcp.
Default URL
http://localhost:3000/mcp
Environment variables
MCP_PORT— port the server listens on (default:3000)AJO_SETTINGS_FILE— optional custom path tosettings.jsonAJO_CREDENTIALS_FILE— optional custom path tocredentials.json
HTTP endpoints
-
POST /mcp- Used for initialization and normal MCP JSON-RPC requests.
- The client should send the MCP initialize request first when no
mcp-session-idheader is present. - Subsequent requests must include the
mcp-session-idheader returned by the server.
-
GET /mcp- Used to open the streamable event channel for the existing session.
- Must include the same
mcp-session-idheader from the initialization response.
-
DELETE /mcp- Used to terminate an active MCP session.
- Must include the same
mcp-session-idheader.
Example connection flow
- Start the server:
MCP_PORT=3000 docker run --rm -it \
-v "$(pwd)/config:/app/config:ro" \
ajo-content-api-mcp-server
- Initialize the session with a POST to
/mcp. - Open a GET stream to
/mcpusing the returnedmcp-session-id. - Send follow-up POST requests with the same
mcp-session-id. - Close the session with
DELETE /mcp.
The repository test files are lightweight smoke checks. The HTTP example test is skipped unless you manually run the MCP server locally, and the stdio test is skipped unless the required Adobe environment variables are present.
Example curl usage
# 1) Initialize the session and capture the returned MCP session ID
response=$(curl -s -X POST \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"initialize","params":{"clientName":"ajo-mcp"},"id":1}' \
http://localhost:3000/mcp)
session_id=$(echo "$response" | jq -r '.result.sessionId')
# 2) Open the stream using the same session ID
curl -N -H "mcp-session-id: $session_id" http://localhost:3000/mcp
# 3) Send another MCP request over the same session
curl -X POST \
-H "Content-Type: application/json" \
-H "mcp-session-id: $session_id" \
-d '{"jsonrpc":"2.0","method":"someToolCall","params":{"input":{}},"id":2}' \
http://localhost:3000/mcp
Notes
- The server uses the HTTP-streamable transport, so the LLM or MCP client can receive streamed tool results and notifications.
- The server is scoped to the sandbox defined in
config/settings.jsonand authenticated viaconfig/credentials.json.
MCP Client Configuration Examples
Use the following examples based on the client you are configuring. For subprocess-based MCP clients, use MCP_TRANSPORT=stdio. For URL-based MCP clients, point them at http://localhost:3000/mcp.
Claude Desktop example
Example claude_desktop_config.json snippet for a local stdio launch:
{
"mcpServers": {
"ajo-content": {
"command": "node",
"args": ["/absolute/path/to/ajo-content-mcp-server/dist/index.js"],
"env": {
"MCP_TRANSPORT": "stdio",
"AJO_SETTINGS_FILE": "/absolute/path/to/config/settings.json",
"AJO_CREDENTIALS_FILE": "/absolute/path/to/config/credentials.json"
}
}
}
}
For an HTTP-connected client shape, use:
{
"mcpServers": {
"ajo-content": {
"url": "http://localhost:3000/mcp"
}
}
}
Codex example
Example MCP server entry for Codex using the local stdio process:
{
"mcpServers": {
"ajo-content": {
"command": "node",
"args": ["/absolute/path/to/ajo-content-mcp-server/dist/index.js"],
"env": {
"MCP_TRANSPORT": "stdio",
"AJO_SETTINGS_FILE": "/absolute/path/to/config/settings.json",
"AJO_CREDENTIALS_FILE": "/absolute/path/to/config/credentials.json"
}
}
}
}
During development, you can swap the args value to ["--import", "tsx", "/absolute/path/to/ajo-content-mcp-server/src/index.ts"].
Or with Docker:
{
"mcpServers": {
"ajo-content": {
"command": "docker",
"args": [
"run",
"--rm",
"-i",
"-e",
"MCP_TRANSPORT=stdio",
"-v",
"/absolute/path/to/config:/app/config:ro",
"ajo-content-api-mcp-server"
]
}
}
}
Cursor example
Example Cursor MCP configuration using the local stdio process:
{
"mcpServers": {
"ajo-content": {
"command": "node",
"args": ["/absolute/path/to/ajo-content-mcp-server/dist/index.js"],
"env": {
"MCP_TRANSPORT": "stdio",
"AJO_SETTINGS_FILE": "/absolute/path/to/config/settings.json",
"AJO_CREDENTIALS_FILE": "/absolute/path/to/config/credentials.json"
}
}
}
}
Available Tools for LLM Integration
This MCP server exposes the following tools to LLMs for managing Adobe Journey Optimizer content templates and fragments:
Content Template Tools
createTemplate
Create a new content template for use in campaigns and journeys.
- Input:
bodyobject matching the OpenAPI schema, for examplename,description,templateType,channels, andtemplate - Output: Created template with auto-generated ID and metadata
- Hint: Destructive operation
Example email template request body:
{
"body": {
"name": "Test Template",
"description": "Test Description",
"templateType": "html",
"channels": ["email"],
"template": {
"html": "<h1>Hello</h1>"
}
}
}
getTemplates
List all available content templates with optional filtering and pagination.
- Input: Optional filters (by name, channel, template type, creation date, etc.), pagination params
- Output: JSON text payload including
status, response headers, and returned data - Hint: Read-only operation
getTemplate
Fetch a specific content template by ID with full details.
- Input: Template ID, Accept header
- Output: Complete template details including audit information and ETag
- Hint: Read-only operation
putTemplate
Update an existing content template by ID.
- Input: Template ID, updated template payload, If-Match header (ETag for concurrency)
- Output: HTTP 204 No Content (success indicator)
- Hint: Idempotent operation
deleteTemplate
Delete a content template by ID.
- Input: Template ID
- Output: HTTP 204 No Content (success indicator)
- Hint: Destructive operation
patchTemplate
Patch specific fields of a content template using JSON Patch format (RFC 6902).
- Input: Template ID, JSON Patch operations, If-Match header
- Output: Updated template with new ETag
- Supported paths:
/name,/description,/parentFolderId - Hint: Idempotent operation
Content Fragment Tools
createFragment
Create a new reusable content fragment.
- Input: Fragment name, description, channel type, and content
- Output: Created fragment with auto-generated ID and metadata
- Hint: Destructive operation
getFragments
List all available content fragments with optional filtering and pagination.
- Input: Optional filters (by name, channel, fragment type, creation date, etc.), pagination params
- Output: Paginated list of fragment summaries
- Hint: Read-only operation
getFragment
Fetch a specific content fragment by ID with full details.
- Input: Fragment ID, Accept header
- Output: Complete fragment details including audit information and ETag
- Hint: Read-only operation
putFragment
Update an existing content fragment by ID.
- Input: Fragment ID, updated fragment payload, If-Match header (ETag for concurrency)
- Output: HTTP 204 No Content (success indicator)
- Hint: Idempotent operation
patchFragment
Patch specific fields of a content fragment using JSON Patch format (RFC 6902).
- Input: Fragment ID, JSON Patch operations, If-Match header
- Output: HTTP 204 No Content (success indicator)
- Supported paths:
/name,/description,/parentFolderId - Hint: Idempotent operation
publishFragment
Publish a content fragment to freeze its content and make it available for use in campaigns/journeys.
- Input: Fragment ID, publication request
- Output: HTTP 202 Accepted (async operation)
- Note: Publishing is asynchronous and may take a few seconds to complete
- Hint: Destructive operation
getLiveFragment
Fetch the content of a fragment's last successful publication.
- Input: Fragment ID
- Output: Published fragment content ready for use
- Note: Returns the frozen content from the most recent successful publication
- Hint: Read-only operation
getLastPublicationStatus
Fetch the status of the last publication request for a fragment.
- Input: Fragment ID
- Output: Publication status (successful, in progress, or error)
- Note: Use this to check async publication progress
- Hint: Read-only operation
Tool Usage Notes
- Authentication: All tools are automatically authenticated using the credentials loaded from
config/credentials.json - Sandbox Context: All operations are scoped to the sandbox specified in
config/settings.json - Request Tracking: Each request includes a unique
x-request-idheader for tracing - Concurrency Control: Update operations (
put,patch) use ETags for optimistic concurrency control - Async Operations: Publication operations are asynchronous; use
getLastPublicationStatusto monitor progress - Filtering: List operations support powerful filtering by various attributes (name regex, date ranges, creation info, etc.)
- Pagination: List operations support limit and offset-based pagination via
limitandstartparameters
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。