用事件推送自动同步代理工具目录
文章利用 CloudTrail、EventBridge、Lambda 和 AgentCore Identity,检测 MCP 服务器变化并向 AWS Agent Registry 推送工具元数据。方案无需存储密钥,支持单账号和多账号环境。
AI 深度解读
MCP server 上线了新工具,目录里却还是旧参数,调用方就可能漏掉能力,甚至按过期 schema 发起请求。AWS 给出的方案,是把运行时更新事件接到同步流水线:部署后自动读取工具定义,有变化才更新 AWS Agent Registry。
这套方案值得看的地方,是它把「同步元数据」和「批准发布」分开了。但它也有明确边界:事件存在约 5–15 分钟延迟,只更新预先登记的记录,新定义还要经过审批才能被消费者看到。
部署事件负责报信,工具定义还得现场读取
AWS Agent Registry 是 Amazon Bedrock AgentCore 的一项能力,用来集中保存 MCP server 及其工具 schema。目录能否被信任,取决于里面的信息是否跟运行中的服务一致。
作者描述的故障很常见:工程师给服务加了工具,却忘了更新目录。调用方可能完全不知道新能力存在,也可能继续使用旧 schema,产生运行异常或不易察觉的流程偏差。久而久之,大家会绕开目录,重新依赖硬编码地址、口头沟通和过时文档。
方案的触发点是 UpdateAgentRuntime。无论通过 AgentCore CLI 的 agentcore deploy,还是直接调用 API 更新运行时,AWS CloudTrail 都会把这次调用记录为管理事件,再由 Amazon EventBridge 路由给同步 Lambda。
下面这条规则负责筛选运行时更新事件:
{
"source": ["aws.bedrock-agentcore"],
"detail-type": ["API Call via AWS CloudTrail"],
"detail": { "eventName": ["UpdateAgentRuntime"] }
}
关键是 eventName:流水线监听的是运行时更新,并没有直接订阅「工具 schema 发生变化」。
Lambda 收到完整事件后,从 responseElements.agentRuntimeArn 提取运行时 ARN,取得账号和 Region,把 ARN 中的 :、/ 分别编码成 %3A、%2F,构造调用地址,参数使用 qualifier=DEFAULT。示例缺省 Region 是 us-west-2。
随后,它访问目标 MCP server,读取当前工具列表,再与目录比较。
这里的 push,是部署事件推送同步信号;最新 schema 仍由 Lambda 主动查询。
这也解释了一个前提:如果工具定义发生变化,却没有触发 UpdateAgentRuntime,仅靠文中的事件入口就无法发现。原文没有提供额外的定期核对机制。
跨账号的关键,是事件路由和身份映射
示例分成两个账号:Account A 保存 Registry、EventBridge 规则、同步 Lambda 和文中列出的 CloudTrail 日志资源;Account B 运行 MCP server,并配置用于认证的 Amazon Cognito OAuth provider。
更新事件在 Account B 被捕获,经跨账号 EventBridge 规则送到 Account A 的中央事件总线。扩展到更多账号时,继续把事件汇入 Account A。单账号部署则省去转发步骤,直接在本账号内调用 Lambda。
身份认证由 AgentCore Identity 完成,分两步:
- Lambda 用
get_workload_access_token,根据WORKLOAD_IDENTITY_NAME获取临时工作负载令牌。 - 再调用
get_resource_oauth2_token,使用oauth2Flow="M2M",换取指定 scope 的 OAuth bearer token。
Lambda 环境变量保存的是配置引用。账号专属配置使用 CREDENTIAL_PROVIDER_{ACCT_ID} 和 CREDENTIAL_SCOPE_{ACCT_ID},找不到时回退到 CREDENTIAL_PROVIDER、CREDENTIAL_SCOPE。这样,一个 Lambda 可以按目标账号选择认证配置,client secret 则交给凭据提供方管理。
取到 token 后,示例通过 MCP streamable-HTTP 先发 initialize,再发 tools/list。初始化参数包含协议版本 2025-03-26,客户端名为 tool-sync-lambda、版本为 1.0.0;两次请求的 timeout 都是 30。如果服务器返回 Mcp-Session-Id,后续请求会带上它。
这些细节说明,同步器实际承担了一个 MCP 客户端的工作,需要处理认证、初始化和会话,不能只把它看成简单的目录写入脚本。
自动更新之后,为什么目录仍可能显示旧版本
同步之前,Registry 必须已有对应记录。初始化登记通过 create_registry_record 创建,使用 recordType="MCP"、recordVersion="1.0",并把包含运行时 ARN 的调用 URL 写入 mcpServer.data 中的 websiteUrl。
ARN 是部署事件与目录记录之间的关联依据。示例调用 list_registry_records,再用 get_registry_record 读取详情,依次尝试匹配解码后的 ARN、编码后的 ARN和完整 MCP URL。找不到记录就跳过,不会自动创建。
匹配成功后,工具列表先按名称排序,再比较三个字段:
def _normalize_tools(tools):
"""Normalize tool list for comparison — extract name, description, inputSchema."""
normalized = []
for t in sorted(tools, key=lambda x: x.get("name", "")):
normalized.append(
{
"name": t.get("name", ""),
"description": t.get("description", ""),
"inputSchema": t.get("inputSchema", {}),
}
)
return normalized
要看的是 name、description、inputSchema 这三行:示例只比较这些字段。工具顺序变化不会触发更新,其他字段变化也不在这段比较逻辑的覆盖范围内。
有差异时,Lambda 记录工具增删或定义变化,再调用 update_registry_record 写入新定义;没有差异则返回 no_change。
但写入完成不等于发布完成。
Registry 的治理流程是 Draft → Pending Approval → Approved,也可能进入 Rejected 或 Deprecated。更新记录后,它会回到 Draft,消费者继续看到此前批准的版本。新内容需要通过 submit_registry_record_for_approval 提交,再由 update_registry_record_status 将状态设为 APPROVED,才能被搜索、目录浏览或 Registry 的 MCP endpoint 发现。
自动化消除了手工抄录,审批等待仍然决定新元数据何时可见。
我的判断
这个设计合理的地方,是把运行中的服务作为工具定义的读取来源,再把结果送入现有治理流程。对于已经使用 AgentCore、需要跨账号统一目录的团队,认证和事件路由都有明确落点。
不过,原文给出的是架构与示例代码,没有同步成功率、运行成本、规模测试,也没有与定时轮询的对照数据。因此,减少无效查询或改善维护体验可以作为设计动机,不能据此认定它在所有规模下更快、更便宜。
还有几处边界需要落实。CloudTrail 约 5–15 分钟的投递延迟,加上审批时间,使它适合接受延迟更新的目录。相比之下,在 CI/CD 部署步骤里直接触发同步,触发时点更明确,但需要接入各条发布链路;定时轮询则能补查遗漏,但会持续产生查询。
代码也有需要复核的地方。文字称只同步 APPROVED 记录,展示的查找函数却只显式跳过 DRAFT;list_registry_records 的示例调用没有展示分页处理;tools/list 同样没有展示分页。目录或工具列表较大时,不能直接假设已经读全。
提供的原文还在 sync_registry_if_changed 返回值和环境变量片段处截断,未交代完整错误处理、重试和部署配置。它适合用来理解方案,距离可直接上线的完整实现还有差距。
能拿来做什么
- 如果团队在维护 AgentCore 上的 MCP server,可以先统一初次登记规范,把运行时 ARN 固定写入记录,保证部署事件能够准确关联目录。
- 如果你在写 Node 同步器,可以复用「初始化、读取工具、规范化比较、按需更新」的流程,并明确比较字段,避免工具排序变化触发无效写入。
- 如果日常 AI 编程依赖企业 MCP 目录,应分别观察服务部署时间、同步完成时间和审批完成时间,排查能力缺失时才能定位卡在哪一步。
- 正式接入前,应验证分页读取、连续更新期间的记录状态,以及同步失败后的恢复方式;这些问题在原文示例里没有完整解决。