安全与可见性
让 agent 直接访问存储引擎,等于凑齐了「致命三要素」:私有数据 × 不可信的笔记内容 × 对外通道。任何一个维度单独存在都无害,但三者合流,笔记里的一次注入就能把你的数据带出门外。Notarium MCP 网关从构造层面斩断每一个维度——靠的是设计,而不是配置。这不是一层图方便的封装,而是一道信任边界。
从构造上斩断三要素
- 没有对外通道。 每个工具都带有
openWorldHint:false——没有工具能触达网络。空间之间既不能搬运也不能复制,内部数据外泄同样被堵死。数据无处可带。 - 不可信内容被拆除。 服务端的指令是静态的,从不与笔记内容混合:笔记里的任何东西都不会被塞进工具描述,也不会被塞进服务端的
instructions。这样一来,笔记正文里的注入永远变不成对 agent 的命令。 - 破坏性操作始终可逆。
delete_note把笔记送进回收站;恢复它、以及彻底清除,都由人来做,而非 agent。这就是「agent 不做任何不可逆之事」这条底线。
每次调用都校验权限
权限会校验两次。首先,tools/list 会按令牌的权限上限过滤——read 令牌根本看不到写入类工具。然后,每次 tools/call 还会额外校验对具体空间的访问权(can(principal, action, {space}))。权限公式为 effective = scopes(token) ∩ grants(principal):令牌的作用域(其动作上限)与在各空间中的实时成员资格取交集。撤销一项授权会立刻收窄令牌。
管理类动作(签发令牌、管理成员)位于 write 之上——一个泄露的 write 级令牌既签发不了新令牌,也授不出访问权。
拒绝 = 404,而非 403
访问被拒时返回的是 404(「查无此物」),而非 403(「不允许」)。这样就无法通过响应码来枚举,在你获授的权限之外还存在哪些笔记或空间。别人的空间从根本上就无法触达,与一个不存在的空间毫无区别。
flowchart TD
call[tools/call] --> listed{工具在令牌<br/>权限上限内?}
listed -->|否| gone[工具不出现在 tools/list]
listed -->|是| acl{can principal,<br/>action, space?}
acl -->|否| notfound[404 · 反枚举]
acl -->|是| exec[执行 · 溯源写入日志]
拆除不可信内容
发给 agent 的一切——title、snippet、content、frontmatter——在发送前都会被清洗:伪控制标签(<system>、<instructions> 及类似标签)的尖括号会被拆除。有人在里面写下「系统指令」的笔记,抵达 agent 时是一段普通文本,而非一条命令。
编辑历史可见
每次编辑都会把是谁改的——某个具体的人或 agent——记入编辑历史。get_note 和 recall 能返回是谁编辑了笔记:是人还是 agent,具体是哪一个。经由 agent 的注入,始终可见、可追溯。
即便一个 agent 被提示词彻底攻陷,它仍被自己的令牌所限:它触达不了网络,够不到别的空间,做不出不可逆的删除,也给不了自己权限。它能造成的最坏后果,不过是在自身权限范围内做一次可逆的编辑,且在日志中留有完整溯源。
边界:不做 E2EE
Notarium 刻意不做端到端加密。一个聪明的服务端——搜索、语义、历史、agent——需要访问明文。这里的隐私建立在自托管与拥有自己的文件之上,而非建立在 E2EE 之上。网关的威胁模型防的是被攻陷的 agent,而不是被攻陷的主机——反正你的文件本来就已经托付给它了。