aem-mcp-server 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -118
- package/cli/cli.js +21 -0
- package/dist/aem/aem.config.js +81 -44
- package/dist/aem/aem.connector.js +848 -849
- package/dist/aem/aem.errors.js +156 -123
- package/dist/explorer/api.explorer.js +61 -19
- package/dist/explorer/api.spec.js +105 -78
- package/dist/mcp/mcp.aem-handler.js +178 -150
- package/dist/mcp/mcp.server-handler.js +84 -67
- package/dist/mcp/mcp.server.js +69 -43
- package/dist/mcp/mcp.tools.js +414 -387
- package/dist/mcp/mcp.transports.js +28 -1
- package/dist/server/app.auth.js +47 -25
- package/dist/server/app.server.js +114 -72
- package/package.json +16 -7
- package/.env.example +0 -7
- package/.nvmrc +0 -1
- package/NOTICE.md +0 -7
- package/dist/config.js +0 -11
- package/dist/index.js +0 -3
- package/src/aem/aem.config.ts +0 -79
- package/src/aem/aem.connector.ts +0 -902
- package/src/aem/aem.errors.ts +0 -152
- package/src/config.ts +0 -12
- package/src/explorer/api.explorer.ts +0 -30
- package/src/explorer/api.spec.ts +0 -79
- package/src/index.ts +0 -4
- package/src/mcp/mcp.aem-handler.ts +0 -158
- package/src/mcp/mcp.server-handler.ts +0 -73
- package/src/mcp/mcp.server.ts +0 -51
- package/src/mcp/mcp.tools.ts +0 -397
- package/src/mcp/mcp.transports.ts +0 -5
- package/src/server/app.auth.ts +0 -32
- package/src/server/app.server.ts +0 -94
- package/tsconfig.json +0 -15
package/README.md
CHANGED
|
@@ -10,23 +10,6 @@ This project is designed for AEM developers, content teams, and automation engin
|
|
|
10
10
|
|
|
11
11
|
---
|
|
12
12
|
|
|
13
|
-
## Table of Contents
|
|
14
|
-
|
|
15
|
-
- [Overview](#overview)
|
|
16
|
-
- [Features](#features)
|
|
17
|
-
- [Quick Start](#quick-start)
|
|
18
|
-
- [Usage Examples](#usage-examples)
|
|
19
|
-
- [Configuration](#configuration)
|
|
20
|
-
- [API & Client Usage](#api--client-usage)
|
|
21
|
-
- [AI IDE Integration (Cursor, Cline, etc.)](#ai-ide-integration-cursor-cline-etc)
|
|
22
|
-
- [Security](#security)
|
|
23
|
-
- [Project Structure](#project-structure)
|
|
24
|
-
- [Integrations](#integrations)
|
|
25
|
-
- [Contribution](#contribution)
|
|
26
|
-
- [License](#license)
|
|
27
|
-
|
|
28
|
-
---
|
|
29
|
-
|
|
30
13
|
## Overview
|
|
31
14
|
- **Modern, TypeScript-based AEM MCP server**
|
|
32
15
|
- **REST/JSON-RPC API** for AEM content, component, and asset operations
|
|
@@ -44,7 +27,6 @@ This project is designed for AEM developers, content teams, and automation engin
|
|
|
44
27
|
- **Template & Structure Discovery**: List templates, analyze page/component structure
|
|
45
28
|
- **JCR Node Access**: Legacy and modern node/content access
|
|
46
29
|
- **AI/LLM Integration**: Natural language interface for AEM via OpenAI, Anthropic, Ollama, or custom LLMs
|
|
47
|
-
- **Telegram Bot**: Manage AEM via chat, including conversational commands
|
|
48
30
|
- **Security**: Auth, environment-based config, and safe operation defaults
|
|
49
31
|
|
|
50
32
|
---
|
|
@@ -57,89 +39,16 @@ This project is designed for AEM developers, content teams, and automation engin
|
|
|
57
39
|
|
|
58
40
|
### Installation
|
|
59
41
|
```sh
|
|
60
|
-
|
|
61
|
-
npm install
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
### Build
|
|
65
|
-
```sh
|
|
66
|
-
npm run build
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
### Run (Production)
|
|
70
|
-
```sh
|
|
71
|
-
npm start
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
### Run (Development, hot reload)
|
|
75
|
-
```sh
|
|
76
|
-
npm run dev
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
---
|
|
80
|
-
|
|
81
|
-
## Usage Examples
|
|
82
|
-
|
|
83
|
-
### 1. List all pages under a path
|
|
84
|
-
```sh
|
|
85
|
-
curl -u admin:admin \
|
|
86
|
-
-X POST http://localhost:8080/api \
|
|
87
|
-
-H 'Content-Type: application/json' \
|
|
88
|
-
-d '{"method":"mcp_aem-mcp_listPages","params":{"siteRoot":"/content/we-retail","depth":2,"limit":10}}'
|
|
42
|
+
npm install aem-mcp-server -g
|
|
89
43
|
```
|
|
90
44
|
|
|
91
|
-
###
|
|
45
|
+
### Start the Server
|
|
92
46
|
```sh
|
|
93
|
-
|
|
94
|
-
-X POST http://localhost:8080/api \
|
|
95
|
-
-H 'Content-Type: application/json' \
|
|
96
|
-
-d '{"method":"mcp_aem-mcp_updateComponent","params":{"componentPath":"/content/we-retail/us/en/experience/jcr:content/root/hero_image","properties":{"Heading":"New Heading"}}}'
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
### 3. Use with AI IDEs (Cursor, Cline, etc.)
|
|
100
|
-
- See the [AI IDE Integration](#ai-ide-integration-cursor-cline-etc) section below.
|
|
101
|
-
|
|
102
|
-
---
|
|
103
|
-
|
|
104
|
-
## Configuration
|
|
105
|
-
|
|
106
|
-
### Environment Variables
|
|
107
|
-
Create a `.env` file in the project root with the following (edit as needed):
|
|
108
|
-
|
|
109
|
-
```
|
|
110
|
-
AEM_HOST=http://localhost:4502
|
|
111
|
-
AEM_SERVICE_USER=admin
|
|
112
|
-
AEM_SERVICE_PASSWORD=admin
|
|
113
|
-
SERVER_PORT=3000
|
|
114
|
-
MCP_USERNAME=admin
|
|
115
|
-
MCP_PASSWORD=admin
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
### MCP Client Configuration
|
|
119
|
-
Sample for AI-based code editors or custom clients:
|
|
120
|
-
|
|
121
|
-
```json
|
|
122
|
-
{
|
|
123
|
-
"mcpServers": {
|
|
124
|
-
"aem-mcp": {
|
|
125
|
-
"command": "node",
|
|
126
|
-
"args": [
|
|
127
|
-
"absolute path to dist/index.js"
|
|
128
|
-
]
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
47
|
+
aem-mcp
|
|
132
48
|
```
|
|
133
49
|
|
|
134
50
|
---
|
|
135
51
|
|
|
136
|
-
## API & Client Usage
|
|
137
|
-
- **REST/JSON-RPC**: Exposes all AEM operations via HTTP endpoints
|
|
138
|
-
- **Supported Operations**: Page/asset CRUD, component validation/update, search, rollout, publish, text/image extraction, and more
|
|
139
|
-
- **AI/LLM**: Send natural language commands to the server (via API or Telegram)
|
|
140
|
-
|
|
141
|
-
---
|
|
142
|
-
|
|
143
52
|
## AI IDE Integration (Cursor, Cline, etc.)
|
|
144
53
|
|
|
145
54
|
AEM MCP Server is compatible with modern AI IDEs and code editors that support MCP protocol, such as **Cursor** and **Cline**.
|
|
@@ -150,40 +59,34 @@ AEM MCP Server is compatible with modern AI IDEs and code editors that support M
|
|
|
150
59
|
- Open your IDE's MCP server settings.
|
|
151
60
|
- Add a new server with:
|
|
152
61
|
- **Type:** Custom MCP
|
|
153
|
-
- **
|
|
154
|
-
|
|
155
|
-
- **Port:** `3000` (or as configured)
|
|
156
|
-
- **Auth:** Use `MCP_USERNAME`/`MCP_PASSWORD` from your `.env`
|
|
62
|
+
- **url:** `http://127.0.0.1:3000/mcp`
|
|
63
|
+
|
|
157
64
|
3. **Restart your IDE** and connect. The IDE will now be able to:
|
|
158
65
|
- List, search, and manage AEM content
|
|
159
66
|
- Run MCP methods (CRUD, search, rollout, etc.)
|
|
160
67
|
- Use AI/LLM features if enabled
|
|
161
68
|
|
|
162
|
-
|
|
163
|
-
- You can build your own MCP client in any language that supports HTTP/JSON-RPC.
|
|
164
|
-
- See the [Usage Examples](#usage-examples) for API call patterns.
|
|
165
|
-
- Authenticate using basic auth (`MCP_USERNAME`/`MCP_PASSWORD`).
|
|
166
|
-
- All MCP methods are available via the `/api` endpoint.
|
|
167
|
-
|
|
168
|
-
---
|
|
169
|
-
|
|
170
|
-
## Security
|
|
171
|
-
- Auth required for all operations (see `MCP_USERNAME`/`MCP_PASSWORD`)
|
|
172
|
-
- Environment-based configuration for safe deployment
|
|
173
|
-
- All destructive operations require explicit parameters and validation
|
|
69
|
+
Sample for AI-based code editors or custom clients:
|
|
174
70
|
|
|
175
|
-
|
|
71
|
+
```json
|
|
72
|
+
{
|
|
73
|
+
"mcpServers": {
|
|
74
|
+
"AEM": {
|
|
75
|
+
"url": "http://127.0.0.1:3000/mcp"
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
176
80
|
|
|
177
|
-
|
|
178
|
-
- `src/` — TypeScript source code
|
|
179
|
-
- `dist/` — Compiled JS output
|
|
81
|
+

|
|
180
82
|
|
|
181
|
-
|
|
83
|
+
## Usage
|
|
182
84
|
|
|
183
|
-
|
|
184
|
-
- **AI/LLM**: OpenAI, Anthropic, Ollama, custom HTTP APIs
|
|
85
|
+
@[TOOL_NAME]() params
|
|
185
86
|
|
|
186
|
-
|
|
87
|
+
```
|
|
88
|
+
@scanPageComponents() /content/path/to/page
|
|
89
|
+
```
|
|
187
90
|
|
|
188
91
|
## Contribution
|
|
189
92
|
Contributions are welcome! Please open issues or pull requests for bug fixes, features, or documentation improvements.
|
package/cli/cli.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
const yargs = require('yargs');
|
|
2
|
+
const { hideBin } = require('yargs/helpers');
|
|
3
|
+
const { startServer } = require('../dist/index.js');
|
|
4
|
+
|
|
5
|
+
const argv = yargs(hideBin(process.argv)).options({
|
|
6
|
+
host: { type: 'string', default: 'http://localhost:4502' },
|
|
7
|
+
user: { type: 'string', default: 'admin' },
|
|
8
|
+
pass: { type: 'string', default: 'admin' },
|
|
9
|
+
mcpPort: { type: 'number', default: 3000 },
|
|
10
|
+
explorer: { type: 'boolean', default: false },
|
|
11
|
+
})
|
|
12
|
+
.help()
|
|
13
|
+
.alias('h', 'help')
|
|
14
|
+
.argv;
|
|
15
|
+
|
|
16
|
+
if (argv.help) {
|
|
17
|
+
process.exit(0); // prevent startServer from running
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const { host, user, pass, mcpPort, explorer } = argv;
|
|
21
|
+
startServer({ host, user, pass, mcpPort, explorer });
|
package/dist/aem/aem.config.js
CHANGED
|
@@ -1,49 +1,86 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
},
|
|
10
|
-
replication: {
|
|
11
|
-
publisherUrls: process.env.AEM_PUBLISHER_URLS?.split(',') || ['http://localhost:4503'],
|
|
12
|
-
defaultReplicationAgent: process.env.AEM_DEFAULT_AGENT || 'publish',
|
|
13
|
-
},
|
|
14
|
-
components: {
|
|
15
|
-
allowedTypes: process.env.AEM_ALLOWED_COMPONENTS?.split(',') || [
|
|
16
|
-
'text', 'image', 'hero', 'button', 'list', 'teaser', 'carousel'
|
|
17
|
-
],
|
|
18
|
-
defaultProperties: {
|
|
19
|
-
'jcr:primaryType': 'nt:unstructured',
|
|
20
|
-
'sling:resourceType': 'foundation/components/text'
|
|
21
|
-
},
|
|
22
|
-
},
|
|
23
|
-
queries: {
|
|
24
|
-
maxLimit: parseInt(process.env.AEM_QUERY_MAX_LIMIT || '100'),
|
|
25
|
-
defaultLimit: parseInt(process.env.AEM_QUERY_DEFAULT_LIMIT || '20'),
|
|
26
|
-
timeoutMs: parseInt(process.env.AEM_QUERY_TIMEOUT || '30000'),
|
|
27
|
-
},
|
|
28
|
-
validation: {
|
|
29
|
-
maxDepth: parseInt(process.env.AEM_MAX_DEPTH || '5'),
|
|
30
|
-
allowedLocales: ['en'],
|
|
31
|
-
},
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
32
9
|
};
|
|
33
|
-
|
|
34
|
-
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var aem_config_exports = {};
|
|
20
|
+
__export(aem_config_exports, {
|
|
21
|
+
DEFAULT_AEM_CONFIG: () => DEFAULT_AEM_CONFIG,
|
|
22
|
+
getAEMConfig: () => getAEMConfig,
|
|
23
|
+
isValidComponentType: () => isValidComponentType,
|
|
24
|
+
isValidContentPath: () => isValidContentPath,
|
|
25
|
+
isValidLocale: () => isValidLocale
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(aem_config_exports);
|
|
28
|
+
const DEFAULT_AEM_CONFIG = {
|
|
29
|
+
contentPaths: {
|
|
30
|
+
sitesRoot: process.env.AEM_SITES_ROOT || "/content",
|
|
31
|
+
assetsRoot: process.env.AEM_ASSETS_ROOT || "/content/dam",
|
|
32
|
+
templatesRoot: process.env.AEM_TEMPLATES_ROOT || "/conf",
|
|
33
|
+
experienceFragmentsRoot: process.env.AEM_XF_ROOT || "/content/experience-fragments"
|
|
34
|
+
},
|
|
35
|
+
replication: {
|
|
36
|
+
publisherUrls: process.env.AEM_PUBLISHER_URLS?.split(",") || ["http://localhost:4503"],
|
|
37
|
+
defaultReplicationAgent: process.env.AEM_DEFAULT_AGENT || "publish"
|
|
38
|
+
},
|
|
39
|
+
components: {
|
|
40
|
+
allowedTypes: process.env.AEM_ALLOWED_COMPONENTS?.split(",") || [
|
|
41
|
+
"text",
|
|
42
|
+
"image",
|
|
43
|
+
"hero",
|
|
44
|
+
"button",
|
|
45
|
+
"list",
|
|
46
|
+
"teaser",
|
|
47
|
+
"carousel"
|
|
48
|
+
],
|
|
49
|
+
defaultProperties: {
|
|
50
|
+
"jcr:primaryType": "nt:unstructured",
|
|
51
|
+
"sling:resourceType": "foundation/components/text"
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
queries: {
|
|
55
|
+
maxLimit: parseInt(process.env.AEM_QUERY_MAX_LIMIT || "100"),
|
|
56
|
+
defaultLimit: parseInt(process.env.AEM_QUERY_DEFAULT_LIMIT || "20"),
|
|
57
|
+
timeoutMs: parseInt(process.env.AEM_QUERY_TIMEOUT || "30000")
|
|
58
|
+
},
|
|
59
|
+
validation: {
|
|
60
|
+
maxDepth: parseInt(process.env.AEM_MAX_DEPTH || "5"),
|
|
61
|
+
allowedLocales: ["en"]
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
function getAEMConfig() {
|
|
65
|
+
return DEFAULT_AEM_CONFIG;
|
|
35
66
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
67
|
+
function isValidContentPath(path, config = DEFAULT_AEM_CONFIG) {
|
|
68
|
+
const allowedRoots = Object.values(config.contentPaths);
|
|
69
|
+
return allowedRoots.some((root) => path.startsWith(root));
|
|
39
70
|
}
|
|
40
|
-
|
|
41
|
-
|
|
71
|
+
function isValidComponentType(componentType, config = DEFAULT_AEM_CONFIG) {
|
|
72
|
+
return config.components.allowedTypes.includes(componentType);
|
|
42
73
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
return config.validation.allowedLocales.some(l => l.toLowerCase() === normalized ||
|
|
48
|
-
(normalized === 'en' && l.toLowerCase().startsWith('en')));
|
|
74
|
+
function isValidLocale(locale, config = DEFAULT_AEM_CONFIG) {
|
|
75
|
+
if (!locale) return false;
|
|
76
|
+
const normalized = locale.toLowerCase();
|
|
77
|
+
return config.validation.allowedLocales.some((l) => l.toLowerCase() === normalized || normalized === "en" && l.toLowerCase().startsWith("en"));
|
|
49
78
|
}
|
|
79
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
80
|
+
0 && (module.exports = {
|
|
81
|
+
DEFAULT_AEM_CONFIG,
|
|
82
|
+
getAEMConfig,
|
|
83
|
+
isValidComponentType,
|
|
84
|
+
isValidContentPath,
|
|
85
|
+
isValidLocale
|
|
86
|
+
});
|