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 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
- cd clone
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
- ### 2. Update a component property
45
+ ### Start the Server
92
46
  ```sh
93
- curl -u admin:admin \
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
- - **Command:** `node`
154
- - **Args:** `["/absolute/path/to/dist/index.js"]`
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
- ### Custom MCP Clients
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
- ## Project Structure
178
- - `src/` — TypeScript source code
179
- - `dist/` — Compiled JS output
81
+ ![cursor.png](docs/cursor.png)
180
82
 
181
- ---
83
+ ## Usage
182
84
 
183
- ## Integrations
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 });
@@ -1,49 +1,86 @@
1
- // eslint-disable-next-line @typescript-eslint/triple-slash-reference
2
- /// <reference types="node" />
3
- export const DEFAULT_AEM_CONFIG = {
4
- contentPaths: {
5
- sitesRoot: process.env.AEM_SITES_ROOT || '/content',
6
- assetsRoot: process.env.AEM_ASSETS_ROOT || '/content/dam',
7
- templatesRoot: process.env.AEM_TEMPLATES_ROOT || '/conf',
8
- experienceFragmentsRoot: process.env.AEM_XF_ROOT || '/content/experience-fragments',
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
- export function getAEMConfig() {
34
- return DEFAULT_AEM_CONFIG;
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
- export function isValidContentPath(path, config = DEFAULT_AEM_CONFIG) {
37
- const allowedRoots = Object.values(config.contentPaths);
38
- return allowedRoots.some(root => path.startsWith(root));
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
- export function isValidComponentType(componentType, config = DEFAULT_AEM_CONFIG) {
41
- return config.components.allowedTypes.includes(componentType);
71
+ function isValidComponentType(componentType, config = DEFAULT_AEM_CONFIG) {
72
+ return config.components.allowedTypes.includes(componentType);
42
73
  }
43
- export function isValidLocale(locale, config = DEFAULT_AEM_CONFIG) {
44
- if (!locale)
45
- return false;
46
- const normalized = locale.toLowerCase();
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
+ });