关于 AEM Content Manager (ACM)
面向 Adobe Experience Manager 上 ACM 的 MCP 服务,可连接 AI Agent 与 AEM。它支持 Groovy 脚本校验和执行、跟踪运行状态,并浏览多个已配置实例中的脚本。
主要功能
- 01运行前校验 Groovy
- 02运行或中止 Groovy 脚本
- 03跟踪执行状态与历史
- 04浏览已存脚本和输出
- 05配置多个 AEM 实例
适用场景
- 01在 AEM 上运行前检查脚本
- 02查看执行日志和输出文件
- 03比较多个实例的只读结果
MCP 相关
向 MCP 客户端提供 ACM 实例健康检查、Groovy 脚本操作、执行历史、已存脚本和脚本指南。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
npx -y @wppes/acm-mcp-serverACM_CONFIG_FILEPath to the ACM config document: the acm.instances list (with per-instance authMode, secret, readonly, enabled), acm.activeInstance and timing keys, same keys as the VS Code extension settingsACM_CONFIG密钥The same config document inline instead of a file; takes precedence over ACM_CONFIG_FILE本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
ACM MCP 服务
一个 Model Context Protocol 服务,可将 AI Agent(Claude Code、Claude Desktop、VS Code、Cursor 和其他 MCP 客户端)连接到运行于 Adobe Experience Manager 上的 AEM Content Manager (ACM),包括 AEM as a Cloud Service。
Agent 可以通过 ACM 在 AEM 上验证并运行 Groovy 脚本、跟踪长时间运行的执行、读取执行历史记录和控制台输出,以及浏览实例上存储的脚本——支持所有已配置的实例,因此还可以比较作者实例与发布实例,或与其他环境进行比较。每次调用都以你配置的凭据所属用户的身份运行。
graph LR
client["MCP client<br>(Claude, ...)"] <-- "stdio (MCP)" --> server["acm-mcp-server<br>(your machine)"]
server <-- "HTTPS" --> aem["AEM instances + ACM<br>/apps/acm/api/*.json"]
警告
此服务允许 AI Agent 使用你的权限在 AEM 上运行任意 Groovy 代码。将其连接到共享实例或生产实例前,请阅读安全性。
提示
使用 VS Code?ACM 扩展已捆绑此服务,并会为所有已启用的实例注册它,凭据取自 VS Code 的机密存储。无需进行以下设置——而且 ACM: Export MCP Config 可为其他 Agent 写入即用型配置文件。
要求
- Node.js 22 或更高版本。
- 每个 AEM 实例都已安装 ACM。运行代码但不保留历史记录(
history: false)需要 ACM 0.9.74 或更高版本。 - 每个实例上都有可访问 ACM API 的用户(参见权限)。
设置
此服务通过 JSON 文档进行配置,使用与 VS Code 扩展设置相同的键,包括 acm. 前缀——从 settings.json 复制的代码块就是有效配置:
{
"acm.instances": [
{ "name": "local-author", "url": "http://localhost:4502", "authMode": "basic", "user": "admin" },
{ "name": "local-publish", "url": "http://localhost:4503", "authMode": "basic", "user": "admin" },
{ "name": "dev", "url": "https://author-pXXXX-eYYYY.adobeaemcloud.com", "authMode": "bearer",
"secret": { "env": "ACM_DEV_TOKEN" }, "readonly": true },
{ "name": "prod", "url": "https://author.example.com", "authMode": "cookie",
"secret": { "file": "~/.config/acm/prod.cookie" }, "enabled": false }
],
"acm.activeInstance": "local-author",
"acm.http.timeout": 30000,
"acm.run.timeout": 120000,
"acm.run.pollInterval": 1000
}
超时键为可选项;其默认值已显示。未知键会被忽略,因此可以粘贴整个设置代码块。
1. 创建配置文件
实例字段:
| 字段 | 说明 |
|---|---|
name | 唯一名称;工具会将其作为可选的 instance 参数。 |
url | AEM URL,作者或发布实例,例如 http://localhost:4502。 |
authMode | bearer、cookie 或 basic。 |
user | Basic 身份验证用户(basic 模式必填)。 |
secret | 凭据——参见机密。本地 admin/admin SDK 无需填写。 |
readonly | true 会禁用在此实例上运行或中止代码的工具。生产环境建议启用;参见安全性。 |
enabled | false 会使所有工具都隐藏此实例,例如暂时停用生产实例(默认值为 true)。 |
选择凭据:
authMode | 适用场景 | 获取机密的方法 |
|---|---|---|
bearer | AEM as a Cloud Service(推荐) | Cloud Manager → 环境的 Developer Console → Integrations → Local token → “Get Local Development Token”。有效期为 24 小时,并以你的用户身份运行。 |
cookie | AEM as a Cloud Service,快速开始;也适用于任何你可以登录的实例 | 登录 AEM 后,获取 login-token Cookie 的值(DevTools → Application → Cookies)。CSRF 令牌会自动处理。 |
basic | 本地 AEM SDK、本地部署环境 | 通常为 admin / admin。 |
login-token Cookie 大约 12 小时后过期;使用 secret: { "file": "path" } 可在不重启服务的情况下刷新它。
密钥
secret 是持有者令牌、login-token cookie(值或 name=value)或 Basic Auth 密码,可按以下方式提供:
- 字面值 — 方便开发。确保配置文件只有你能读取(
chmod 600);否则服务器会发出警告。 { "env": "NAME" }— 从服务器进程的环境变量中读取。不会写入配置文件。{ "file": "path" }— 会展开~,相对路径则相对于配置文件解析。每次请求都会重新读取,因此在磁盘上刷新令牌无需重启。文件缺失或为空时,仅该实例会失败。
对于本地 URL,使用用户 admin 的 Basic Auth 默认密码为 admin,因此本地 SDK 完全不需要密钥。
2. 向 Agent 注册服务
所有 MCP 客户端都需要相同的信息。信息的放置位置和格式取决于客户端,因此本指南不列出特定客户端的文件:
| 设置 | 值 |
|---|---|
| 传输方式 | stdio |
| 命令 | npx |
| 参数 | -y、@wppes/acm-mcp-server |
| 环境变量 | ACM_CONFIG_FILE,值为步骤 1 中的路径 |
你也可以通过 ACM_CONFIG 内联传入文档,以此代替 ACM_CONFIG_FILE;内联配置的优先级更高。
最简单的方法是询问你的 Agent,它了解自己的配置方式:
将 ACM MCP 服务添加到此工具的 MCP 配置中:传输方式为 stdio,命令为
npx,参数为-y @wppes/acm-mcp-server,环境变量ACM_CONFIG_FILE指向一个 JSON 文件,其中包含我在下面列出的 ACM 实例。不要将密钥放入该文件 — 请改为引用环境变量或文件 — 并且绝不要将密钥写入可能会提交的文件;请告诉我应该在哪里填写这些值。查阅此工具的文档,了解 MCP 服务的配置位置和格式。然后调用acm_list_instances和acm_health进行验证。
3. 检查连接
让 Agent 依次调用 acm_list_instances 和 acm_health。前者会显示每个已启用实例及其身份验证模式和凭据配置状态;后者会报告 ACM 对每个实例报告的状态。
实例
工具每次只对一个实例执行操作,实例按以下方式选择:
- 如果提供了可选的
instance参数,则使用该参数 — 它必须指定一个已启用的实例; - 否则,如果
acm.activeInstance指定了一个已启用的实例,则使用该实例; - 否则,如果只配置了一个已启用的实例,则使用该实例;
- 否则调用会失败,并列出所有已启用实例的名称,以免意外在错误的实例上运行。
如果 acm.activeInstance 指定了未知或已禁用的实例(例如拼写错误),服务器会在启动时向 stderr 发出警告,acm_list_instances 也会重复此警告,以便 Agent 能够告知你;之后上述规则会按该设置未配置的情况执行。
acm_list_instances 会显示哪个实例处于活动状态,以及哪些实例已配置凭据。写入类工具(acm_run_code、acm_abort_execution、acm_describe_inputs)始终只对一个实例执行操作 — 特意不提供一次对所有实例运行的调用。若要比较实例(例如作者环境与发布环境之间的差异),请在每个实例上运行相同的只读代码,并对结果进行差异比较;随附的脚本指南介绍了这一模式。这要求 ACM 在两端都可访问,本地、内部部署和 AMS(直接发布 URL)均可使用 — AEMaaCS 发布环境无法访问。
工具
| 工具 | 描述 |
|---|---|
acm_list_instances | 列出已启用的实例:名称、URL、身份验证模式、只读标志、当前活动实例,以及是否已配置凭据。 |
acm_health | 检查连接、身份验证以及 ACM 报告的实例状态(/apps/acm/api/state.json);如果 ACM 的运行状况检查发现实例不健康,则发出警告。不指定 instance 时,会检查所有已启用的实例。请先调用此工具。 |
acm_validate_code | 编译检查 Groovy 代码,但不运行(mode=parse)。返回包含行号和列号的编译错误。不会记录在执行历史中。 |
acm_run_code | 将 Groovy 代码加入执行队列,轮询直到执行完成或超时,并返回状态和完整的控制台输出。支持为包含 describeRun() 的脚本传入 inputs。设置 history: false 时会同步运行,且不会记录在历史中(见下文)。 |
acm_get_execution | 根据 ID 获取执行的状态、输入、错误和控制台输出,包括排队中、运行中或已归档的执行。 |
acm_abort_execution | 中止排队中或运行中的执行。调用 context.checkAborted() 的脚本会正常停止。 |
acm_list_executions | 列出执行历史记录,最新的排在前面;也可选择仅列出排队中和运行中的执行。 |
acm_list_scripts | 按类型(MANUAL、AUTOMATIC、…)列出存储在 /conf/acm/settings/script 下的 Groovy 脚本。 |
acm_get_script | 根据 ID 或路径读取已存储脚本的 Groovy 内容。 |
acm_describe_inputs | 解析脚本在 describeRun() 中声明的输入:名称、类型和默认值。ACM 会运行 describeRun() 来完成解析,因此这也算运行代码。 |
acm_get_output_file | 下载指定的执行输出:console,或通过 outputs.file(...) / outputs.text(...) 创建的输出。 |
每个工具都接受可选的 instance 参数;默认值请参见实例。
裸 Groovy 代码片段会自动封装在 canRun()/doRun() 结构中,因此 println "hello" 可作为 acm_validate_code 和 acm_run_code 的有效输入。
不记录历史的运行
每次排队运行都会存储在 ACM 执行历史中,因此快速迭代脚本会很快填满历史记录。设置 history: false 时,acm_run_code 会直接调用 /apps/acm/api/execute-code.json,且不会记录该次运行。此类运行:
- 没有可用于轮询或中止的执行 ID,也不会保留输出文件;
- 会在
waitMs后由客户端中止,但脚本可能仍会在 AEM 上继续运行。
开发脚本时,可将其用于简短的只读运行或试运行。请使用默认的 history: true 运行最终版本,以及任何会更改内容的脚本,以便保留可审计的更改记录。
不记录历史的运行需要 ACM console/execute/nohistory 功能(默认仅限管理员);如果没有该功能,调用会失败并返回 403。此类运行仍会出现在 ACM 的审计日志中。
脚本编写指南
服务附带 ACM Groovy 脚本技能,因此 Agent 无需额外设置即可编写有效且安全的脚本:
- 说明。 技能中的核心要点(绝不臆造 API、进行试运行、检查中止状态、运行前先验证)会在客户端连接时发送给客户端。客户端会将其添加到模型的上下文中。
- 提示词。
acm-groovy-script会返回完整指南。 - 资源。 指南及其参考资料可通过
acm://skill/SKILL.md、acm://skill/references/api.md(每个 ACM 变量、类和方法,均根据 ACM 源代码生成)、acm://skill/references/scripts.md以及acm://skill/templates/下的脚本模板获取。
示例
可以向 Agent 提出类似这样的请求:
使用 ACM 统计
/content/wknd/us/en下有多少个wknd/components/teaser组件。
它会调用 acm_health,然后验证并运行类似这样的脚本:
boolean canRun() {
return conditions.always()
}
void doRun() {
def sql = "SELECT * FROM [nt:base] AS n WHERE ISDESCENDANTNODE(n, '/content/wknd/us/en') AND n.[sling:resourceType] = 'wknd/components/teaser'"
def count = 0
repo.queryRaw(sql).forEach { resource ->
context.checkAborted()
count++
}
out.info("Found ${count} instance(s)")
}
权限
ACM 会在三个层级检查访问权限。凭据对应的用户需要对以下每一项拥有 jcr:read 权限:
/apps/acm/api下的 API 节点;/apps/acm/feature下的功能节点;/conf/acm/settings/script下的脚本路径。
默认情况下,只有管理员可以访问。请参阅 工具访问配置。任何工具返回 403 时都会包含此提示。401 表示令牌或 Cookie 已过期。
安全
- Agent 以你的身份操作。 每个脚本都会以已配置用户的权限运行。模型可能会出错,而它读取的内容(页面、脚本、执行输出)也可能试图引导它。请使用能够完成任务的权限最低的用户。
- 将生产实例标记为
readonly。 健康检查、验证、历史记录和脚本读取工具仍可使用;在该实例上运行、描述和中止代码的操作会被阻止。这只能阻止 Agent 调用这些工具,并非安全边界:验证仍会在 AEM 上编译提交的 Groovy 代码,而 Groovy 编译时转换可以运行代码。真正的控制措施是已配置用户在 AEM 中的权限。enabled: false会完全隐藏实例。 - 运行记录可追踪。 已排队的运行会保存在 ACM 历史记录中;未留下历史记录的运行(未启用历史记录,或未通过
canRun()排队)会连同用户信息和代码校验和写入 ACM 的审计日志。仅向有此需要的用户授予console/execute/nohistory权限。 - 仅向 Agent 授予所需权限。 拥有
script/execute功能但没有console/execute权限的用户,只能按原样运行已存储的脚本。 - 在共享实例上运行脚本前先进行审查。 对这些实例,请勿在 MCP 客户端中自动批准
acm_run_code。 - 破坏性更改优先使用试运行。 使用 ACM 的
repo.dryRun(...)模式;内置的脚本编写指南会引导模型采用这种方式。 - 凭据保留在本地。 服务在你的计算机上运行,只与已配置的实例 URL 通信。建议使用
{ "env" }和{ "file" }密钥引用,或将明文密钥保存在chmod 600配置文件中——切勿将密钥放入提交的文件中。
贡献
如需构建、测试和发布服务,请参阅开发指南。
许可证
这是 AEM Content Manager 的一部分,采用 Apache License, Version 2.0 授权。按“原样”提供,不提供任何形式的担保;使用风险由你自行承担(请参阅许可证第 7 和第 8 节)。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。