Files
qinglong/docs/adr/ADR-0354-exact-local-mcp-approval-preview.md
T

4.6 KiB
Raw Blame History

ADR-0354:精确、双授权的本机 MCP Approval 预览

  • 状态:Accepted
  • 日期:2026-08-10
  • 关联 RFCQL-RFC-0001 D-05、D-06、D-08、D-13、D-17、D-28、D-75、D-85、D-87、D-157、D-257、D-259、D-260、D-263、D-265、D-266
  • 关联 ADRADR-0138、ADR-0347、ADR-0351、ADR-0353

背景

qinglong.approval.list 可以说明动作处于 pending、approved、rejected 或 consumed,但故意不返回 preview。AI Client 若无法看见经过 redaction contract 生成的动作摘要,就不能做有意义的人工转交;若直接取得完整 Approval 或 Tool Invocation Artifact,又会泄露 action reference、digest、主体与密文入口。现有 Approval 和 Tool preview 表已经分别保存 同一个 Project/action binding,缺口是最窄的精确关联读端口,而不是新表、Artifact 解密或审批写流程。

决策

  1. 增加 qinglong.approval.get@1.0.0,输入只允许 requestIdProject 只能来自私有 MCP 配置。
  2. 调用固定要求 exact tool.call:qinglong.approval.getapproval.readartifact.read。两个既有只读权限缺一不可; 之后仍须 durable Security Audit 和 credential fence confirm。
  3. SQLite/PostgreSQL 先按 Project+request ID 读取并复验 canonical Approval、request digest 与更新时间镜像;只有 tool.invoke 才按 projectId/actionRef/actionDigest/previewDigest 四元组 LEFT JOIN 已有 preview 表。
  4. Adapter 必须规范化完整 preview Artifact,并复验 artifact/project/action/digest/redaction/size/time 的所有镜像;任何 漂移映射为稳定 unavailable。无匹配 preview 是合法的 previewAvailable=false,不得猜测或扫描。
  5. Runtime read port 只携带 Approval record 与已经验证的 preview document。MCP package 不得 import Tool Invocation Artifact subpath,不得取得 artifact ID、repository、input ciphertext、key、nonce、auth tag、任一 digest 或解密 authority。
  6. 输出只含 Approval list 已公开的低敏元数据、previewAvailable,以及有界 title、summary、最多 16 个 field 和 8 个 warning。redacted field 省略 value;不返回 Project、action reference、主体 ID、fence 或决定/消费/派发证据。
  7. 不新增 package、dependency、migration、连接、listener、timer、watcher、cache 或写 authority。SQLite 复用 MCP 的唯一 connection/operation queue/close fencePostgreSQL 实现同一 port 供未来 Cluster 产品组合使用,但本 ADR 不建立 Cluster MCP。

Package 粒度裁决

公共 read contract 属于 Runtime Core 的现有 approved-action/ domain;双方言完整 Artifact 关联归各自 storage adapter; 单一 MCP 消费者的字段投影归现有 local-mcp-server/tool-projection/。因此只新增一个嵌套 projection 文件,没有新 workspace package。当前为 17 package/999 source、973 nested、26 root,无单源或 shallow package。

被否决方案

  1. 只要求 approval.read:把索引观察权限隐式扩大为 Artifact 内容权限。
  2. MCP 直接使用 Artifact repository:会把密文存储面和未来解密能力带入协议进程。
  3. Client 提供 action reference/digest 或 artifact ID:暴露内部证据,并形成跨请求枚举面。
  4. 把 preview 复制进 Approval 表:需要 migration、重复事实和双写一致性协议。
  5. 为 detail/source/projection 新建 package:没有独立制品、依赖、authority 或版本生命周期收益。
  6. 同时开放 approve/consume:缺少强人类 ceremony、事务 start barrier 与写恢复产品门。

验证

  • Runtime Core 451/451、Local SQLite 208/208、Local MCP 38/38、PostgreSQL 290 pass/1 条件 skip。
  • 真实 SQLite migration/row corruption、PostgreSQL 参数化关联、in-memory MCP admission 与真实 stdio/API Credential/Audit 均覆盖。
  • package boundary、dependency 和 edge import 审计 compatibleMCP 对 Artifact subpath 的一次越权 import 被门禁发现并通过 document-only port 消除,而不是放宽规则。
  • 十二档 artifact compatible。Standalone Application AI 为 6,261,021 bytes/637 files,余 30,435 bytesStandalone MCP 为 9,857,149 bytes/947 files/203 modulesRSS 40,632,320 bytes。
  • PostgreSQL 18.4 arm64 HA gates.passed=true,结束后 QingLong 临时 Docker 容器、卷、网络均为零。

后续约束

人工 approve/reject、consume/dispatch 和实际 Tool execution 必须分别定义强认证、职责分离、幂等命令、原子审计、start barrier 与响应丢失恢复协议。不得因为 preview 已可读就把任何写能力加入当前 MCP read authority。