aem-mcp-server
Version:
AEM MCP server. Chat with your AEM instance for content, component, and asset operations.
193 lines (148 loc) • 8.79 kB
Markdown
# AEM MCP Server (aem-mcp-server)
[](https://npmjs.org/package/aem-mcp-server)
[](https://github.com/easingthemes/aem-mcp-server/actions/workflows/release.yml)
[](https://github.com/easingthemes/aem-mcp-server/actions/workflows/codeql-analysis.yml)
[](https://github.com/semantic-release/semantic-release)
[](LICENSE)
AEM MCP Server is a full-featured Model Context Protocol (MCP) server for Adobe Experience Manager (AEM).
It provides a simple integration with any AI Agent.
This project is designed for non-technical persons who want to manage AEM via natural language.
---
## Overview
- **Manage your AEM instance with natural language** — content, components, assets, workflows
- **Works with any MCP-compatible client:**
- **AI IDEs** — Cursor, VS Code + Copilot, Windsurf, Cline, JetBrains AI Assistant, Zed
- **CLI agents** — Claude Code, GitHub Copilot CLI, Gemini CLI, Amazon Q CLI
- **Chat & desktop apps** — Claude Desktop, ChatGPT Desktop, Goose
- **Supports both AEMaaCS and self-hosted AEM instances**
- **Two transport modes** — stdio via `npx` (recommended, zero install) and streamable HTTP
---
## Quick Start
### Prerequisites
- Node.js 20.19.0+ || 22.12.0+ || 23+
- Access to an AEM instance (local or remote)
### Stdio Transport (recommended)
No installation needed — the AI agent downloads and spawns the process automatically via `npx`.
Add to your project's MCP config (`.mcp.json`, `.vscode/mcp.json`, `.cursor/mcp.json`, etc.):
```json
{
"mcpServers": {
"AEM": {
"command": "npx",
"args": ["-y", "aem-mcp-server", "-t", "stdio", "-H", "http://localhost:4502", "-u", "admin", "-p", "admin"]
}
}
}
```
> **Secrets:** Since MCP config files are typically committed to the repo, avoid hardcoding credentials. Use your client's env var syntax instead:
>
> | Client | Syntax |
> |---|---|
> | Claude Code (`.mcp.json`) | `${AEM_PASSWORD}` or `${AEM_PASSWORD:-admin}` |
> | VS Code / Copilot | `${input:aem-password}` (prompts securely) or `envFile` |
> | Cursor | `${env:AEM_PASSWORD}` |
>
> Example with env var references (Claude Code):
> ```json
> {
> "mcpServers": {
> "AEM": {
> "command": "npx",
> "args": ["-y", "aem-mcp-server", "-t", "stdio", "-H", "${AEM_HOST:-http://localhost:4502}", "-u", "${AEM_USER:-admin}", "-p", "${AEM_PASSWORD:-admin}"]
> }
> }
> }
> ```
### Streamable HTTP Transport (alternative)
For scenarios where you need a persistent server (shared team server, multiple clients connecting simultaneously, etc.), install globally and start the server manually:
```sh
npm install aem-mcp-server -g
aem-mcp -H=http://localhost:4502 -u=admin -p=admin
```
Then point your AI agent to the URL:
```json
{
"mcpServers": {
"AEM": {
"url": "http://127.0.0.1:8502/mcp"
}
}
}
```
[](https://cursor.com/en/install-mcp?name=AEM&config=eyJ1cmwiOiJodHRwOi8vMTI3LjAuMC4xOjg1MDIvbWNwIn0%3D)
### Configuration
```
Options:
--version Show version number [boolean]
-H, --host [string] [default: "http://localhost:4502"]
-u, --user [string] [default: "admin"]
-p, --pass [string] [default: "admin"]
-i, --id clientId [string] [default: ""]
-s, --secret clientSecret [string] [default: ""]
-m, --mcpPort [number] [default: 8502]
-t, --transport Transport mode: http (default) or stdio
[string] [choices: "http", "stdio"] [default: "http"]
-I, --instances Named AEM instances: "local:http://localhost:4502:admin:admin
,qa:https://qa.example.com:user:pass" [string] [default: ""]
-h, --help Show help [boolean]
```
**Authentication:**
- For **AEMaaCS**, use `clientId` and `clientSecret` for OAuth S2S authentication. [More info](https://developer.adobe.com/developer-console/docs/guides/authentication/ServerToServerAuthentication/implementation).
- For **self-hosted AEM**, use `user`/`pass`. Default credentials are `admin:admin`.
**Multi-instance:** Connect to multiple AEM instances simultaneously:
```sh
aem-mcp --instances "author:http://localhost:4502:admin:admin,publish:http://localhost:4503:admin:admin"
```
All tools will get an `instance` parameter to target a specific instance.
---
## Features
- **57 MCP Tools** covering pages, components, assets, workflows, content fragments, and experience fragments
- **MCP Resources** — agents discover components, sites, templates, and workflow models upfront via `resources/list`, eliminating discovery roundtrips
- **Tool Annotations** — every tool tagged with `group`, `readOnly`, and `complexity` so agents can make smarter tool selection decisions
- **Response Verbosity** — `verbosity` parameter (`summary`/`standard`/`full`) on content-reading tools strips JCR internals and truncates long text
- **Actionable Errors** — error responses include `suggestion` and `alternatives` fields for self-healing agent workflows
- **Component Operations**: Update, scan, add, convert, and bulk-manage AEM components (including Experience Fragments)
- **Content & Experience Fragments**: Full CRUD + variation management for both CF and XF, plus server-side JSON-string field merging (`manageContentFragment` action `mergeJsonField`) for CFs that store a whole key→value map inside one JSON-encoded field
- **Advanced Search**: QueryBuilder, fulltext, fuzzy, and enhanced page search
- **Replication & Workflows**: Publish/unpublish content, start/advance/delegate workflow stages
- **Text & Image Extraction**: Extract all text and images from pages, including fragments
- **Template & Structure Discovery**: List templates, analyze page/component structure
- **Multi-instance**: Connect to multiple AEM instances simultaneously; tools and resources are instance-aware
- **Security**: Basic auth and OAuth S2S, environment-based config, safe operation defaults
---
## Usage
Once configured in your AI IDE, just ask in natural language:
```
List all components on MyPage
```
### Merging into a JSON-string field
Some Content Fragments store an entire key→value map inside a single field as a JSON-encoded
string. To upsert a few keys without round-tripping the whole blob, use the `mergeJsonField`
action — the read-merge-write happens server-side:
```jsonc
{
"action": "mergeJsonField",
"fragmentPath": "/content/dam/<site>/.../labels",
"field": "CFMValue", // the field holding the JSON string
"jsonPointer": "/0/content/0/value", // RFC-6901 pointer to the object to merge into ("" = field root)
"merge": { "search": "Search", "clear_search": "Clear search" },
"variation": "master" // default: master
}
```
New keys are added, existing keys overwritten (deep-merge), and untouched keys preserved. The
response reports the keys added/overwritten and the before/after key count at the pointer.
## MCP Resources
The server exposes read-only MCP resources so agents can discover AEM catalogs without tool calls:
| Resource URI | Description |
|---|---|
| `aem://{instance}/components` | All components (name, resourceType, title, group) |
| `aem://{instance}/sites` | Site roots and language structure under /content |
| `aem://{instance}/templates` | Available page templates (path, title) |
| `aem://{instance}/workflow-models` | Workflow models (ID, title, description) |
Resources return summary data only. In multi-instance mode, each instance gets its own set of resource URIs.
## API Documentation
For detailed API documentation, please refer to the [API Docs](docs/API.md).
## Similar Projects
1. https://github.com/easingthemes/aem-mcp-server (Used as a base for this project)
1. https://github.com/indrasishbanerjee/aem-mcp-server (Used as a base for #1)
1. https://www.npmjs.com/package/@myea/aem-mcp-handler (Looks like an original source of #2)