ADR-0002:MCP 安全网关作为 Agent 访问外部资源的唯一出口
- 状态:已采纳
- 日期:2026-09-15
- 决策者:毕设作者
- 相关文档:
docs/04-MCP安全网关设计.md、docs/adr/0001-dual-database-isolation.md、docs/adr/0004-security-plugin-layer-in-process.md
背景
ADR-0001 已经让 Agent 拿不到业务库凭证。但"拿不到数据库"不等于"访问受控":Agent 还需要读取遥测数据、检索故障知识库、查询工单状态。这些能力必须有人提供。
有三种给法:
- 直接给 Agent 数据库账号或 MQTT 凭证(已被 ADR-0001 否决);
- 在 Agent 进程内写一段"取数逻辑"(连接串进 Agent 环境变量);
- 让 Agent 通过一个受控的外部服务间接取数。
决策
Agent 所有对外部资源的访问,100% 经过 MCP 安全网关。
网关是一个独立部署的 TypeScript 进程,职责:
- 统一入口:同时接收 Agent 调用与 Web 前端人类用户调用,是系统唯一的对外数据出口。
- 身份解析:解析 JWT / 设备令牌,得到调用方身份(工程师 ID 或 Agent ID + 会话 ID)。
- 策略校验:按"调用方 × 工具 × 参数 × 上下文"判定放行、降级还是拒绝。
- 数据裁剪:向下取到原始数据后,按字段白名单裁剪,只回传最小数据集。
- 审计落库:每一次调用(含被拒绝的调用)写入
business-db.audit_log,写入失败即调用失败。 - 向下转发:
ai-db只读检索、MQTT 只读取数、business-db受限查询。
网关对外的接口形态是 MCP 工具,工具清单是封闭的、可枚举的:
| 工具 | 用途 | 读/写 | 主要返回字段 |
|---|---|---|---|
mqtt.read_sensor | 读取指定设备的遥测窗口 | 只读 | temp、vibration、time |
kb.search | 检索故障知识库 | 只读 | chunk、source、score |
db.query_device | 查询设备基础档案 | 只读 | 型号、位置、投运日期 |
db.query_workorder | 查询工单 | 只读 | 工单号、状态、处理记录 |
report.write | 落库 Agent 分析报告 | 写(受限) | 报告 ID |
没有任何工具可以执行任意 SQL,也没有任何工具可以发布 MQTT 消息。
理由
- 把"能不能"变成"契约允不允许"。数据库只读账号回答不了"Agent 该不该看这张表";工具契约可以。工具是安全策略的最小可审计单元。
- 字段裁剪是核心价值,不只是转发。原始遥测行可能含内部序列号、校准系数、产线编码;Agent 做故障分析只需要
temp/vibration/time。网关在返回前裁剪,等于把"最小权限"落实到字段级。 - 人类用户与 Agent 共用入口,审计口径统一。前端查设备数据和 Agent 查设备数据走同一条链路、同一张审计表,答辩时可以用一条 SQL 同时展示两类调用。
- MCP 是标准协议,网关的工具可以被任意 MCP 客户端复用,不绑死在 OpenClaw 上,降低框架锁定风险。
备选方案与拒绝理由
| 方案 | 为什么没选 |
|---|---|
| Agent 进程内直接连库取数 | 连接串必然进入 Agent 环境变量或配置文件,一旦提示注入成功即可被读出;且 Agent 可执行任意 SQL。 |
| 用普通 REST 接口代替 MCP | 可行但失去标准工具发现能力,且与 OpenClaw 的工具生态脱节。MCP 是当前 Agent 工具调用的主流标准。 |
| 网关只做转发不做裁剪 | 那样 Agent 仍能看到全部字段,最小权限落空,等于把数据库只读账号换个包装。 |
| 每个数据源各起一个网关 | 入口一多,"唯一出口"不变量失效,审计需要跨多个服务拼接,答辩论证成本上升。 |
后果
正面
- 系统对外数据出口收敛为 1 个进程 + 5 个工具,安全论证可以逐条列举。
- Agent 的能力边界可枚举:Agent 能做什么,等于工具清单能做什么。
- 审计日志成为系统唯一的"数据访问事实来源"。
负面 / 代价
- 网关成为性能瓶颈与单点,必须 PM2 守护并设计降级策略。
- 新增数据需求需要走"定义工具 → 实现 → 加策略 → 加审计"的完整流程,迭代速度慢于直接写 SQL。
- 网关代码本身成为高价值攻击目标,需要最严格的代码评审与测试覆盖。
验证方式
原型验证阶段需要给出反证:在 Agent 进程内尝试直连 business-db 与订阅 MQTT 主题,均因缺少凭证而失败;同时展示审计表中被拒绝调用的记录。见 docs/09-原型验证方案.md。