aem-mcp-server 1.0.1 → 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 +1 -34
- 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 +7 -4
- package/dist/config.js +0 -11
- package/dist/index.js +0 -3
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
|
|
@@ -59,17 +42,6 @@ This project is designed for AEM developers, content teams, and automation engin
|
|
|
59
42
|
npm install aem-mcp-server -g
|
|
60
43
|
```
|
|
61
44
|
|
|
62
|
-
### Configuration
|
|
63
|
-
|
|
64
|
-
Create a `.env` file in the project root with the following (edit as needed):
|
|
65
|
-
|
|
66
|
-
```
|
|
67
|
-
AEM_HOST=http://localhost:5502
|
|
68
|
-
AEM_SERVICE_USER=admin
|
|
69
|
-
AEM_SERVICE_PASSWORD=admin
|
|
70
|
-
SERVER_PORT=3000
|
|
71
|
-
```
|
|
72
|
-
|
|
73
45
|
### Start the Server
|
|
74
46
|
```sh
|
|
75
47
|
aem-mcp
|
|
@@ -88,7 +60,6 @@ AEM MCP Server is compatible with modern AI IDEs and code editors that support M
|
|
|
88
60
|
- Add a new server with:
|
|
89
61
|
- **Type:** Custom MCP
|
|
90
62
|
- **url:** `http://127.0.0.1:3000/mcp`
|
|
91
|
-
- **env:** add env variables if needed
|
|
92
63
|
|
|
93
64
|
3. **Restart your IDE** and connect. The IDE will now be able to:
|
|
94
65
|
- List, search, and manage AEM content
|
|
@@ -101,11 +72,7 @@ Sample for AI-based code editors or custom clients:
|
|
|
101
72
|
{
|
|
102
73
|
"mcpServers": {
|
|
103
74
|
"AEM": {
|
|
104
|
-
"url": "http://127.0.0.1:3000/mcp"
|
|
105
|
-
"env": {
|
|
106
|
-
"AEM_SERVICE_USER": "admin",
|
|
107
|
-
"AEM_SERVICE_PASSWORD": "admin"
|
|
108
|
-
}
|
|
75
|
+
"url": "http://127.0.0.1:3000/mcp"
|
|
109
76
|
}
|
|
110
77
|
}
|
|
111
78
|
}
|
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
|
+
});
|