The AEM MCP Server is a production-ready Model Context Protocol server for Adobe Experience Manager that provides comprehensive content management through 35+ REST/JSON-RPC API methods, with advanced AI integration and automation capabilities.
Core Operations:
Page Management: Create, delete, activate/deactivate, list, and extract content from AEM pages
Component Management: Create, update, delete, validate, and perform bulk operations on components; scan pages for component discovery with undo capabilities
Asset Management (DAM): Upload, update, delete assets and manage metadata within AEM DAM
Template Management: Discover available templates and retrieve their detailed structures
Site & Localization: Manage multi-site content, language masters, locales, and publishing workflows
Advanced Features:
Search & Query: Execute Query Builder searches, JCR queries, and intelligent page search strategies
Direct JCR Access: Interact with JCR nodes by getting content and listing child nodes
AI/LLM Integration: Connect with AI providers (OpenAI, Anthropic, Ollama, custom APIs) for natural language AEM management
Automation: Telegram bot integration and custom client support for workflow automation
Developer Tools: Interactive dashboard for API exploration, testing, and documentation with authentication, path validation, structured error handling, retry mechanisms, and performance optimizations.
Uses environment variables through .env files for configuration of AEM connections, API keys, and server settings
Built on Node.js runtime (v18+) for server operations and AEM connectivity
Integrates with Ollama to provide local LLM capabilities for natural language AEM management
Connects to OpenAI's API to enable natural language processing for AEM content management tasks
Features a Telegram bot for conversational AEM management, allowing chat-based content and component operations
Built with TypeScript for type-safe development and modern JavaScript features
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@AEM MCP Servercreate a new page in the marketing site using the article template"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Reach out to me on LinkedIn or Email Me to discuss customizations !
💡 For users interested in MCP server for AEM as a Cloud Service, check out my other GitHub project: AEMaaCS MCP Server - A comprehensive read and write MCP server specifically designed for AEM as a Cloud Service with advanced features and enterprise-grade capabilities.
📜 DUAL LICENSING: This project is licensed under AGPL-3.0 for open source use. Commercial licenses are available for organizations that need to use this software without AGPL obligations. See COMMERCIAL_LICENSE.md for details.
AEM MCP Server (aem-mcp-server)
AEM MCP Server is a comprehensive, production-ready Model Context Protocol (MCP) server for Adobe Experience Manager (AEM). It provides 35+ robust REST/JSON-RPC API methods for complete content, component, asset, and template management, with advanced integrations for AI, chatbots, and automation workflows. This project is designed for AEM developers, content teams, and automation engineers who want to manage AEM programmatically or via natural language interfaces.
Table of Contents
Related MCP server: mcp-after-effects
Overview
Modern, TypeScript-based AEM MCP server
REST/JSON-RPC API for AEM content, component, and asset operations
AI/LLM integration (OpenAI, Anthropic, Ollama, custom HTTP APIs)
Telegram bot for conversational AEM management
Production-ready, modular, and extensible
Features
🚀 Core Capabilities (35+ Methods)
Page Operations (10 methods)
Page Lifecycle: Create, delete, activate/deactivate pages with proper template integration
Content Management: Get page content, properties, text extraction, and image management
Page Discovery: List pages with depth control, pagination, and filtering
Publishing: Activate/deactivate pages with tree operations
Component Operations (7 methods)
Component CRUD: Create, update, delete, and validate components
Bulk Operations: Update multiple components with validation and rollback support
Component Discovery: Scan pages to discover all components and their properties
Image Management: Update image paths with verification
Asset Operations (4 methods)
DAM Management: Upload, update, delete assets in AEM DAM
Metadata Operations: Get and update asset metadata
File Processing: Support for multiple file types with MIME type detection
Search & Query Operations (3 methods)
Advanced Search: QueryBuilder integration with fulltext search
JCR Queries: Execute JCR SQL2-style queries with security validation
Enhanced Page Search: Intelligent search with fallback strategies
Template Operations (2 methods)
Template Discovery: Get available templates for sites and paths
Template Analysis: Detailed template structure and metadata extraction
Site & Localization (3 methods)
Multi-site Management: Fetch sites, language masters, and available locales
Localization Support: Manage content across different languages and regions
Replication & Publishing (2 methods)
Content Replication: Replicate and publish content to selected locales
Unpublishing: Remove content from publish environments
Legacy & Utility Operations (5 methods)
JCR Node Access: Direct node content access and child listing
System Utilities: Method listing, status checking, and workflow management
🔧 Technical Features
REST & JSON-RPC APIs: Dual API support for maximum compatibility
Interactive Dashboard: Web-based interface for API exploration and testing
Comprehensive Testing: Built-in test suite with automated issue tracking
Enhanced Error Handling: Structured error responses with retry mechanisms
Security: Authentication, path validation, and safe operation defaults
Performance: Connection pooling, caching, and optimized queries
Quick Start
Prerequisites
Node.js 18+
Access to an AEM instance (local or remote)
Installation
cd clone
npm installBuild
npm run buildRun (Production)
npm startRun (Development, hot reload)
npm run devUsage Examples
JSON-RPC API Examples
1. List all pages under a path
curl -u admin:admin \
-X POST http://localhost:3001/mcp \
-H 'Content-Type: application/json' \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "listPages",
"params": {
"siteRoot": "/content/mysite",
"depth": 2,
"limit": 10
}
}'2. Create a new page with template
curl -u admin:admin \
-X POST http://localhost:3001/mcp \
-H 'Content-Type: application/json' \
-d '{
"jsonrpc": "2.0",
"id": 2,
"method": "createPage",
"params": {
"parentPath": "/content/mysite/en",
"title": "New Product Page",
"template": "/conf/mysite/settings/wcm/templates/page-template"
}
}'3. Update a component property
curl -u admin:admin \
-X POST http://localhost:3001/mcp \
-H 'Content-Type: application/json' \
-d '{
"jsonrpc": "2.0",
"id": 3,
"method": "updateComponent",
"params": {
"componentPath": "/content/mysite/en/home/jcr:content/root/container/text",
"properties": {
"text": "Updated content",
"textIsRich": true
}
}
}'4. Search for content
curl -u admin:admin \
-X POST http://localhost:3001/mcp \
-H 'Content-Type: application/json' \
-d '{
"jsonrpc": "2.0",
"id": 4,
"method": "searchContent",
"params": {
"type": "cq:Page",
"fulltext": "product",
"path": "/content/mysite",
"limit": 20
}
}'5. Upload an asset to DAM
curl -u admin:admin \
-X POST http://localhost:3001/mcp \
-H 'Content-Type: application/json' \
-d '{
"jsonrpc": "2.0",
"id": 5,
"method": "uploadAsset",
"params": {
"parentPath": "/content/dam/mysite/images",
"fileName": "hero-image.jpg",
"fileContent": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQ...",
"mimeType": "image/jpeg",
"metadata": {
"dc:title": "Hero Image",
"dc:description": "Main hero image for homepage"
}
}
}'REST API Examples
1. Get all available methods
curl -u admin:admin http://localhost:3001/api/methods2. Get method details
curl -u admin:admin http://localhost:3001/api/methods/createPage3. Execute method via REST
curl -u admin:admin \
-X POST http://localhost:3001/api/methods/listPages \
-H 'Content-Type: application/json' \
-d '{
"siteRoot": "/content/mysite",
"depth": 1,
"limit": 10
}'Method Categories and Examples
Page Operations
createPage- Create pages with proper template integrationdeletePage- Remove pages with force optionlistPages- List pages with depth and paginationgetPageContent- Extract complete page contentgetPageProperties- Get page metadata and propertiesactivatePage/deactivatePage- Publish/unpublish pagesgetAllTextContent/getPageTextContent- Extract text contentgetPageImages- Extract image references
Component Operations
validateComponent- Validate component changes before applyingupdateComponent- Update component properties with verificationscanPageComponents- Discover all components on a pagecreateComponent- Add new components to pagesdeleteComponent- Remove componentsupdateImagePath- Update image component referencesbulkUpdateComponents- Update multiple components atomically
Asset Operations
uploadAsset- Upload files to DAM with metadataupdateAsset- Update asset metadata and contentdeleteAsset- Remove assets from DAMgetAssetMetadata- Retrieve asset metadata
Search Operations
searchContent- Query Builder search with flexible parametersexecuteJCRQuery- Execute JCR queries (QueryBuilder wrapper)enhancedPageSearch- Intelligent page search with fallbacks
Template Operations
getTemplates- List available templates for sitesgetTemplateStructure- Get detailed template structure
Site & Localization
fetchSites- Get all available sitesfetchLanguageMasters- Get language masters for sitesfetchAvailableLocales- Get available locales
Interactive Dashboard
Access the web dashboard at http://localhost:3001/dashboard for:
Interactive method testing
Parameter validation
Response visualization
API documentation
Batch testing capabilities
Configuration
Environment Variables
Create a .env file in the project root with the following (edit as needed):
AEM_HOST=http://localhost:4502
AEM_SERVICE_USER=admin
AEM_SERVICE_PASSWORD=admin
MCP_PORT=8080
GATEWAY_PORT=3001
MCP_USERNAME=admin
MCP_PASSWORD=adminMCP Client Configuration
Sample for AI-based code editors or custom clients:
{
"mcpServers": {
"aem-mcp": {
"command": "node",
"args": [
"absolute path to dist/mcp-server.js"
]
}
}
}Advanced Configuration Options
# Optional: Advanced AEM Configuration
AEM_SITES_ROOT=/content
AEM_ASSETS_ROOT=/content/dam
AEM_TEMPLATES_ROOT=/conf
AEM_XF_ROOT=/content/experience-fragments
AEM_PUBLISHER_URLS=http://localhost:4503
AEM_DEFAULT_AGENT=publish
AEM_ALLOWED_COMPONENTS=text,image,hero,button,list,teaser,carousel
AEM_QUERY_MAX_LIMIT=100
AEM_QUERY_DEFAULT_LIMIT=20
AEM_QUERY_TIMEOUT=30000
AEM_MAX_DEPTH=5
# Optional: AI Integration (if needed)
# OPENAI_API_KEY=your-openai-key
# TELEGRAM_BOT_TOKEN=your-telegram-bot-tokenAPI & Client Usage
REST/JSON-RPC: Exposes all AEM operations via HTTP endpoints
Supported Operations: Page/asset CRUD, component validation/update, search, rollout, publish, text/image extraction, and more
AI/LLM: Send natural language commands to the server (via API or Telegram)
Telegram Bot: Connect your bot using
TELEGRAM_BOT_TOKENand chat with your AEM instance
AI IDE Integration (Cursor, Cline, etc.)
AEM MCP Server is compatible with modern AI IDEs and code editors that support MCP protocol, such as Cursor and Cline.
How to Connect:
Install and run the AEM MCP Server as described above.
Configure your IDE to connect to the MCP server. Example for Cursor/Cline:
Open your IDE's MCP server settings.
Add a new server with:
Type: Custom MCP
Command:
nodeArgs:
["/absolute/path/to/dist/mcp-server.js"]Port:
8080(or as configured)Auth: Use
MCP_USERNAME/MCP_PASSWORDfrom your.env
Restart your IDE and connect. The IDE will now be able to:
List, search, and manage AEM content
Run MCP methods (CRUD, search, rollout, etc.)
Use AI/LLM features if enabled
Custom MCP Clients
You can build your own MCP client in any language that supports HTTP/JSON-RPC.
See the Usage Examples for API call patterns.
Authenticate using basic auth (
MCP_USERNAME/MCP_PASSWORD).All MCP methods are available via the
/apiendpoint.
Security
Auth required for all operations (see
MCP_USERNAME/MCP_PASSWORD)Environment-based configuration for safe deployment
All destructive operations require explicit parameters and validation
Project Structure
src/— TypeScript source codedist/— Compiled JS output
Integrations
AI/LLM: OpenAI, Anthropic, Ollama, custom HTTP APIs
Telegram: Chat-based AEM management
Contribution
Contributions are welcome! Please open issues or pull requests for bug fixes, features, or documentation improvements.
Troubleshooting
Common Issues
Connection Issues
# Test AEM connection
curl -u admin:admin http://localhost:4502/libs/granite/core/content/login.html
# Check server health
curl http://localhost:3001/healthAuthentication Problems
Verify AEM credentials in
.envfileCheck MCP_USERNAME and MCP_PASSWORD for API access
Ensure AEM user has sufficient permissions
Page Creation Issues
Empty pages without jcr:content: Use proper template parameter
Pages not visible in Author: Ensure template exists and is valid
Template not found: Verify template path and permissions
Component Update Failures
Component not found: Verify component path exists
Update failed: Check component properties and validation
Permission denied: Ensure user has write access
Performance Optimization
Use pagination with
limitparameter for large result setsSet appropriate
depthvalues for page listingConfigure
AEM_QUERY_TIMEOUTfor slow queriesUse bulk operations for multiple component updates
Debugging
# Enable debug logging
DEBUG=aem-mcp:* npm run dev
# Check detailed health status
curl http://localhost:3001/health
# List all available methods
curl -u admin:admin http://localhost:3001/api/methodsCommon Use Cases
Content Migration
// 1. List source pages
const pages = await listPages({ siteRoot: '/content/source', depth: 3 });
// 2. Create target pages with templates
for (const page of pages.data.pages) {
await createPage({
parentPath: '/content/target',
title: page.title,
template: '/conf/target/settings/wcm/templates/page'
});
}
// 3. Copy components
const components = await scanPageComponents({ pagePath: sourcePage });
for (const component of components.data.components) {
await createComponent({
pagePath: targetPage,
componentType: component.resourceType,
properties: component.properties
});
}Bulk Content Updates
// Update multiple text components
const updates = [
{
componentPath: '/content/site/page1/jcr:content/text1',
properties: { text: 'Updated content 1' }
},
{
componentPath: '/content/site/page2/jcr:content/text2',
properties: { text: 'Updated content 2' }
}
];
await bulkUpdateComponents({
updates,
validateFirst: true,
continueOnError: false
});Asset Management Workflow
// 1. Upload assets
await uploadAsset({
parentPath: '/content/dam/project',
fileName: 'hero.jpg',
fileContent: base64Content,
metadata: { 'dc:title': 'Hero Image' }
});
// 2. Update page to use new asset
await updateComponent({
componentPath: '/content/site/home/jcr:content/hero',
properties: { fileReference: '/content/dam/project/hero.jpg' }
});
// 3. Publish changes
await activatePage({ pagePath: '/content/site/home' });Search and Discovery
// Find pages by content
const results = await searchContent({
type: 'cq:Page',
fulltext: 'product launch',
path: '/content/mysite'
});
// Get detailed page information
for (const result of results.data.results) {
const content = await getPageContent({ pagePath: result.path });
const components = await scanPageComponents({ pagePath: result.path });
}API Reference
Authentication
All API endpoints require HTTP Basic Authentication:
Authorization: Basic base64(username:password)Response Format
All responses follow this structure:
{
"success": true,
"operation": "methodName",
"timestamp": "2024-01-01T00:00:00.000Z",
"data": {
// Method-specific response data
}
}Error Handling
Error responses include structured information:
{
"success": false,
"operation": "methodName",
"timestamp": "2024-01-01T00:00:00.000Z",
"error": {
"code": "ERROR_CODE",
"message": "Human readable error message",
"details": {},
"recoverable": true,
"retryAfter": 5000
}
}Error Handling Best Practices
The AEM MCP Server follows REST API best practices by returning HTTP 200 status codes with structured error information in the response body. This approach provides several benefits:
Consistent Response Format: All responses, whether successful or not, follow the same JSON structure
Detailed Error Information: Error responses include specific codes, messages, and details
Client-Side Processing: Clients can easily parse and handle errors programmatically
Recoverable vs. Fatal Errors: The
recoverableflag indicates if retrying might succeedRetry Guidance: When appropriate,
retryAftersuggests a wait time before retrying
Example Error Handling in Client Code:
async function callMcpMethod(method, params) {
const response = await fetch(`/api/methods/${method}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(params)
});
const result = await response.json();
if (!result.success) {
// Handle error based on error code and details
console.error(`Error in ${method}:`, result.error.message);
if (result.error.recoverable && result.error.retryAfter) {
// Implement retry logic
console.log(`Retrying after ${result.error.retryAfter}ms`);
await new Promise(resolve => setTimeout(resolve, result.error.retryAfter));
return callMcpMethod(method, params); // Recursive retry
}
throw new Error(`${result.error.code}: ${result.error.message}`);
}
return result.data;
}Common Error Codes:
Error Code | Description | Recoverable |
| Missing or invalid parameters | No |
| Specified path does not exist | No |
| Insufficient permissions | No |
| Template does not exist | No |
| Component does not exist | No |
| Connection to AEM failed | Yes |
| Operation timed out | Yes |
| Resource is locked by another process | Yes |
| Server is under heavy load | Yes |
| Content validation failed | No |
License
Open Source License (AGPL-3.0)
This project is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0).
What this means:
✅ Free to use, modify, and distribute
✅ If you run a modified version as a network service, you must provide source code to users
✅ All modifications must also be licensed under AGPL-3.0
✅ Perfect for open source projects and internal use
Read the full license: LICENSE
Commercial License
Need to use this software without AGPL obligations?
We offer commercial licenses for organizations that want to:
❌ Keep modifications private
❌ Integrate into proprietary systems without source disclosure
✅ Get priority support and custom features
✅ Receive legal protection and indemnification
Pricing starts at $X,XXX/year with a free 30-day evaluation license.
Learn more: COMMERCIAL_LICENSE.md
Contact for commercial licensing:
📧 Email: indrasish00@gmail.com
💼 LinkedIn: linkedin.com/in/indrasish/
Why Dual Licensing?
This model allows us to:
Support the open source community with free, powerful tools
Provide enterprise-grade support for commercial users
Continue development with sustainable funding
Ensure compliance with clear licensing terms
If you're unsure which license you need, contact us for guidance.