关于 Verified Memory
Verified Memory 是供 Agent 只读访问已验证记忆包的本地离线 MCP 服务。它仅在校验校验和及可选的固定公钥签名后,通过隔离的内存快照提供原文引述记录。
主要功能
- 01离线只读运行
- 02校验校验和及签名
- 03提供精确引述的记忆记录
- 04隔离的内存快照
- 05记忆包构建与签名工具
适用场景
- 01从签名记忆包检索带引文的事实
- 02防止付款信息被悄然篡改
- 03从聊天导出内容构建并验证记忆包
MCP 相关
stdio MCP 服务仅提供 `verified_memory_search` 和 `verified_memory_get`。它不提供资源、提示词、文件系统工具或命令工具。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
verified-memory-mcp
为什么
AI Agent 开始代为支付发票和购买商品。Agent 会按照记忆中的信息付款。如果有人替换了记忆中的账号,Agent 就会把钱付给攻击者。这种供应商付款欺诈正从欺骗办事员转向欺骗 AI。
Verified Memory 只提供由你固定的密钥签名的事实,并拒绝任何签名后被更改的内容。一个 AI 攻击者对它进行了 12 种篡改攻击的红队测试(替换文件、破坏签名、伪造时钟、涌入 5,000 个文件、运行期间替换文件夹)。没有任何攻击能让篡改后的数据被提供 (完整日志)。 最新版本:Verified Memory 0.4.1。
免费的 MIT 许可本地 stdio MCP 服务,通过官方
MCP TypeScript SDK
(@modelcontextprotocol/sdk 1.32.1)提供 verified_memory_search
和 verified_memory_get。已发布到 npm,包名为 @python1/verified-memory-mcp,
并收录于 MCP Registry,标识为 io.github.python1/verified-memory。
运行时为只读且离线:不使用网络传输、套接字、遥测、嵌入、账户、文件系统写入、子进程或 Shell 执行。它会在启动时读取一个已配置的数据包,并提供隔离的内存快照。每次收到请求时,它只通过文件元数据检查数据包文件夹是否仍是已验证的那个;如果不是,就停止提供服务(不使用监视器,也不会重新读取任何内容)。标准输出专用于 MCP 协议输出;启动错误会写入标准错误并以非零状态码退出。只公开这两个工具;不提供资源、提示词、文件系统或命令工具。
使用 npx 运行
npm 包仅包含 dist/、数据包构建器、本 README 和 LICENSE。它不附带 任何数据包,
因此必须指定 --pack:
npx -y @python1/verified-memory-mcp --pack /absolute/path/to/pack
Claude Code:claude mcp add verified-memory -- npx -y @python1/verified-memory-mcp --pack /absolute/path/to/pack。
通过 npx 运行不会启用 Node 的权限模式,因为 npx 会启动自己的
Node 进程。若要使用下文所述的只读文件系统允许列表,请安装
此包,并直接使用 node 运行其 dist/index.js。
构建自己的数据包
数据包是一个包含四个文件的目录:records.jsonl、MEMORY.md、
README.md 和 SHA256SUMS,还可选包含 PACK.json(创建和到期日期)
以及签名文件 SHA256SUMS.sig
(参见已签名且带日期的数据包)。最简单的制作方式是使用附带的离线
构建器。它会读取你的消息和想要记住的记录,找出每条记录在消息中的原文引述,计算偏移量和哈希值,写入数据包,然后使用服务自身的验证器加载数据包。如果任何引述与消息中的原文不完全一致,它就不会写入任何内容。
在浏览器中从 ChatGPT 或 Claude 导出内容
数据包制作器(Beta):https://python1.github.io/data-lore-hive/。 加载数据导出文件,搜索聊天记录,选择要记住的确切句子,然后下载现成的数据包。它完全在浏览器中运行(不使用服务器,其 Content-Security-Policy 禁止网络请求),使用与命令行构建器相同的构建代码,并在提供下载之前使用服务自身的验证器检查数据包。它不会为数据包签名或添加日期(请使用下文的 sign-pack),但其中的 检查已签名数据包 面板会对已签名数据包及你粘贴的公钥运行相同的验证器。源代码位于 web/;如果要从代码检出目录运行,请在该目录中执行 npm install && npm run build,然后打开
web/dist/index.html。参见 web/README.md。
快速开始
-
将源消息放入
messages.jsonl,每行一个 JSON 对象:{"id": 3, "date": "2026-03-02T08:20:00Z", "speaker": "Rowan", "text": "Quick thing first: the shed code changed. Also, the café on the corner sells seedlings on Saturdays."}字段 规则 id正整数,且唯一 dateUTC ISO 8601 格式,以 Z或+00:00结尾,例如2026-03-02T08:20:00Zspeaker非空字符串 text非空字符串;引文会与其进行精确匹配 -
将要记住的内容放入
records.jsonl,每行一条记录,每条记录都要引用 这些消息中的准确原文:{"record_id": "M-garden-3", "role": "user", "topic": "Seedlings", "category": "places", "quotes": [{"message_id": 3, "quote": "the café on the corner sells seedlings on Saturdays."}]}字段 规则 record_id以 M-开头,后接 1–127 个字母、数字、_或-;且唯一role"user"(此人)或"agent"(助手)topic、category自选的非空字符串 quotes非空的 {"message_id", "quote"}列表;引文必须在该消息中逐字出现。如果出现多次,请添加"start"(构建器会列出可选位置)statement可选摘要;默认值为用空格连接的引文 speaker可选;默认为所引用消息的发言者;若发言者不同则必填
不接受未知字段,因此拼写错误会明确报错。
-
构建到一个尚不存在的目录中,然后将服务指向该目录:
npx -y -p @python1/verified-memory-mcp verified-memory-build-pack \ --messages messages.jsonl --records records.jsonl \ --out /absolute/path/to/my-pack --title "My memory" --description "Optional text for the pack README" npx -y @python1/verified-memory-mcp --pack /absolute/path/to/my-pack在仓库检出目录中,运行
npm run build后执行node tools/build-pack.mjs ...。 构建规则(逐字引文、码点偏移量、哈希、文件布局)位于tools/pack-core.mjs中;该文件没有导入项,因此浏览器也可以运行相同代码。 构建器不会进行网络调用,也绝不会覆盖现有内容:它会先在同级隐藏目录中暂存, 只有通过验证后才将其重命名到目标位置。
examples/input/ 包含虚构的示例输入(一个虚构的社区花园,
并非真实人物),examples/pack/ 是据此构建的包;测试套件会逐字节重建它。这两者都不会随 npm 包发布。
records.jsonl 格式(服务验证的内容)
每行一个 JSON 对象,编码为 UTF-8,最多 10,000 条记录,且 record_id 唯一。
除非标记为可选,否则下列字段均为必填:
| 字段 | 规则 |
|---|---|
record_id | ^M-[A-Za-z0-9_-]{1,127}$ |
role | "user" 或 "agent" |
speaker、statement、topic、category | 非空字符串 |
date_first_utc、date_last_utc | UTC ISO 8601 格式(Z 或 +00:00),且前者 ≤ 后者 |
evidence | 非空的引文列表(见下文) |
| 其他任何字段 | 可选;会保留并由 verified_memory_get 作为元数据返回(例如 supersedes、approval、audits) |
evidence 中的每条引文:
| 字段 | 规则 |
|---|---|
message_id | 正整数 |
date_utc | UTC ISO 8601 格式,且介于记录的首末日期之间 |
quote | 来自消息的非空精确文本 |
start、end | 整数,start ≥ 0,end − start = 引文的 Unicode 码点长度(偏移量按码点对消息文本索引,与 Python 字符串切片方式相同) |
message_sha256 | 64 个小写十六进制字符:完整消息文本编码为 UTF-8 后的 SHA-256 |
示例(文件中的一行;此处换行以便阅读):
{"record_id":"M-garden-3","role":"user","speaker":"Rowan","category":"places","topic":"Seedlings",
"statement":"the café on the corner sells seedlings on Saturdays.",
"date_first_utc":"2026-03-02T08:20:00Z","date_last_utc":"2026-03-02T08:20:00Z",
"evidence":[{"message_id":3,"date_utc":"2026-03-02T08:20:00Z",
"quote":"the café on the corner sells seedlings on Saturdays.","start":48,"end":100,
"message_sha256":"e3aebbd25f7b809dd5b0b8d55b9ad7df6566464dc2a5033d02e3c5aa7ed8eeb2"}]}
构建包时会对照源消息检查引文,之后则由签名保护引文。 构建器(或
agent-memory/)会拒绝任何未在对应消息中逐字出现的引文,并根据该消息计算
message_sha256。服务永远看不到你的原始消息,因此在加载和提供服务时,它只会检查
引文结构、偏移量的计算结果以及哈希格式;不会根据 message_sha256 再次核对引文。
包密封后,SHA256SUMS(对于已签名的包,则为 SHA256SUMS.sig)负责保护引文不被
后续更改。加载时会拒绝不含记录的包(自 0.4.1 起)。
MEMORY.md 和包内的 README.md
这两个文件都必须存在、采用有效的 UTF-8 编码,并与 SHA256SUMS 一致。服务不会解析它们,也不会通过任一工具返回它们;它们是供直接阅读该包的人和 Agent 使用的。按照惯例,并且构建器也会按此写入:
MEMORY.md:包含一个# Title标题,然后对每条记录列出其 ID 和发言者、其陈述,以及每条带有消息 ID 和日期的引文,并标记为历史数据。README.md:说明该包是什么、来源于何处(输入文件的 SHA-256、记录数),并声明引文是数据而非指令,校验和只能证明完整性,不能证明真实性或获得认可。
SHA256SUMS 格式
每个其他文件恰好占一行(三个文件,或加上 PACK.json 后为四个),格式为 <64 位小写十六进制数> + 两个空格 + 文件名;不得包含 SHA256SUMS 或 SHA256SUMS.sig 条目;大小最多为 4 KiB:
f3ed88bca6a7a451a892f49bd6d2970f5671b8c704d0bc6cae7646c46978bc69 MEMORY.md
0685a25133fd3e7f60e70ba1e836a2e8b045ace1e2be2ecbd306a4fc656f558f README.md
34212f199411c8e4ef52cb341b0c68d970b5b30d9b8117c2eae5729b0d71dfa5 records.jsonl
如果你手动编辑了一个包,请在包目录内重新生成校验和:
shasum -a 256 MEMORY.md README.md records.jsonl > SHA256SUMS # macOS
sha256sum MEMORY.md README.md records.jsonl > SHA256SUMS # Linux
手动重新封装只能让校验和再次匹配;它不会重新检查引文。建议使用构建器重新构建。重新封装也会使任何签名失效:请重新签名。
已签名且带日期的包
一个包可以包含两个可选附加项:
SHA256SUMS.sig:对SHA256SUMS的确切字节进行签名的 OpenSSH 签名,其中固定了其他所有文件。只接受 Ed25519 密钥、sha512哈希和命名空间verified-memory-pack-v1,因此不能将 git 或代码发布签名重复用作包签名。PACK.json(自 0.3.0 起):记录包的创建时间和失效时间;自 0.4.0 起,还可包含可选的sequence序号。它与其他文件一样列在SHA256SUMS中,因此签名也涵盖日期和序号。
{
"format": "verified-memory-pack",
"version": 2,
"created_utc": "2026-10-12T18:00:00Z",
"expires_utc": "2027-01-10T18:00:00Z",
"sequence": 3
}
只能包含这四个键,以及可选的 sequence;日期采用 UTC ISO 8601 格式,且 created_utc 必须早于 expires_utc。version 是格式版本,固定为 2;sequence 是大于或等于 0 的整数,签名者每发布一个包都会递增该值,以便主机拒绝较旧的包(参见回滚保护)。格式错误的 PACK.json 会导致加载失败。包制作器和构建器都不会写入该文件,因此它们生成的包仍可在 0.2.0 主机上加载;包含 PACK.json 的包需要 0.3.0 或更高版本(较旧的主机会拒绝额外文件),包含 sequence 的包需要 0.4.0 或更高版本(0.3.0 主机会拒绝额外键)。
签名:sign-pack
在你信任的机器上使用受口令保护的密钥进行签名。自 0.4.1 起,sign-pack
随 npm 包一起发布,命令为 verified-memory-sign-pack(在代码库检出中,它是
tools/sign-pack.mjs)。它会将已验证的包复制到新文件夹,
写入 PACK.json、重新封存 SHA256SUMS,并运行 ssh-keygen -Y sign。它绝不会自行打开
私钥:ssh-keygen 会读取私钥并提示输入口令(或使用
ssh-agent)。在将结果移至目标位置之前,它会以严格模式使用主机自己的
验证器加载结果,并且只信任你的 .pub 文件。它需要 Node 22+ 和 OpenSSH 8.1+。
ssh-keygen -t ed25519 -f ~/.ssh/verified-memory-pack -C "my packs" # once; set a passphrase
npx -y -p @python1/verified-memory-mcp verified-memory-sign-pack \
--pack /path/to/pack --key ~/.ssh/verified-memory-pack --expires 90d --sequence 1 --out /path/to/pack-signed
在代码库检出目录中,先运行一次 npm ci && npm run build,然后
使用相同的参数运行 node tools/sign-pack.mjs ...。
--expires 的值可以是天数(90d,最多 1825d),也可以是准确的 UTC 时间
(2027-01-31T00:00:00Z)。--sequence(可选,自 0.4.0 起)会写入
PACK.json;每次发布新包时都要递增它(1、2、3……)。--out 指定的路径必须
尚不存在。任何操作失败时(口令错误、包未通过验证),都不会写入任何内容。对已签名的包再次签名,会替换其日期、序号和签名。该脚本会输出密钥指纹、用于在主机上固定该指纹的 --trusted-fingerprint 行,以及一行受信任密钥配置。
不要将私钥放入包中、任何代码库中,也不要放在共享机器上。
只分享 .pub 文件。
直接运行 ssh-keygen -Y sign -f KEY -n verified-memory-pack-v1 pack/SHA256SUMS 仍会生成
有效签名,但该包没有到期日期(freshness: unknown)或序号,因此 --strict 和 --min-sequence 会拒绝它。
推荐设置:固定签名者
verified-memory-mcp --pack /absolute/path/to/pack \
--trusted-fingerprint SHA256:…the-fingerprint-sign-pack-printed… \
--min-sequence 3 --strict
--trusted-fingerprint 用于指定唯一允许为你的包签名的密钥,其值为 sign-pack
(或 ssh-keygen -l -f KEY.pub)打印的指纹。可重复指定该标志,或用逗号分隔多个指纹,以允许多个密钥。指定此标志后,任何其他密钥签名的包都会被拒绝,即使该密钥位于 --trusted-keys 中;未签名的包也会被拒绝(固定指纹即意味着启用 --require-signature)。此时,--trusted-keys 仅用于提供固定密钥的名称;如果不指定它,签名者会显示为 "pinned"。
原因:在第 4 轮红队测试中,一台共享机器上的攻击者机器人能够改写受信任密钥文件,于是将自己的密钥加入其中,并用该密钥重新签署了一个投毒包;信任该文件的主机随后将它作为 verified 提供。固定指纹保存在主机自己的配置中(MCP 客户端配置或 Claude Desktop 设置),而不是与包放在一起的文件中,因此此类攻击会被拒绝:pack is signed by SHA256:…, which is not a pinned signer fingerprint。确保主机配置只有你能写入;如果攻击者能够编辑主机自身的配置,这些措施都无法保护主机。
撤销密钥:--revoked-keys
--revoked-keys /absolute/path/to/revoked_keys 用于列出你不再信任的指纹,每行
一个,格式与 ssh-keygen -l 的输出一致;允许使用 # 注释,也允许在
指纹后添加行尾注释:
# laptop lost 2026-10-15
SHA256:…the-old-key-fingerprint… old laptop
被撤销密钥签名的包始终会被拒绝,即使该密钥已固定或受信任,也不要求必须存在签名:pack is signed by SHA256:…, which is revoked。撤销操作本身不会强制要求签名,因此未签名的包仍会加载,除非你同时固定指纹或要求签名。该文件与受信任密钥文件一样,只会在启动时读取;请将它放在只有你能写入的位置。
回滚保护:--min-sequence
--min-sequence N 会拒绝任何已签名 PACK.json 中 sequence 缺失或小于 N 的资源包,因此无法用更旧的资源包替换当前资源包,即使该资源包的签名有效且尚未过期:pack sequence 3 is lower than the minimum 5; refusing a possible rollback to an older pack。由你设置 N,并在安装较新的资源包时提高它;服务端不保留状态文件,也不会写入任何内容,因此无法记住它见过的最高序列号。只有由你固定或信任的密钥签名时,序列号才会被计入,因此 --min-sequence 隐含 --require-signature。
检查顺序
每次拒绝都会给出一个具体错误,即第一个未通过检查的错误:
- 资源包的文件、校验和及记录(任何编辑都会在此处失败);
- 如果存在签名,该签名必须有效;
- 已撤销(无论设置了什么,都会拒绝),然后是已固定(设置了固定密钥时,只有固定的签名者才能通过),然后是受信任密钥(状态为
verified、untrusted或unsigned;--require-signature会拒绝除verified以外的所有状态); - 根据
--min-sequence检查序列号; - 在
--strict下检查过期状态(并且每次请求时都会再次判断)。
检测更改后停止服务
服务端在启动时读取并验证一次资源包。每次工具调用时,都会将资源包文件夹的文件列表以及每个文件的大小、修改时间、更改时间和标识(设备和 inode)与已验证的信息进行比较。如果有任何差异(文件被编辑、新增或移除,文件或整个文件夹被替换),两个工具都会返回 isError,错误为 verified-memory: pack files changed on disk since startup, so the verified snapshot no longer matches them; restart to verify the pack again,且不会返回任何记录数据,直到你重启服务。该拒绝状态会在内存中锁定:移除新增的文件或恢复原文件夹都不会恢复服务;只有重启并重新验证资源包后才能恢复。这些检查仅使用元数据:没有后台监视器、不会重新读取,也不会写入。普通用户无法将更改时间设回原值,因此恢复文件的修改时间无法掩盖编辑;能够更改系统时钟或文件系统本身的管理员不在此检测范围内。
选择信任对象
信任的始终只是你列出的公钥。没有内置密钥、网络、密钥服务器或注册表。将密钥放入文件,每行一个,格式为 allowed_signers 格式的 name ssh-ed25519 AAAA… [comment](允许空行和 # 注释):
alice ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA… alice's laptop
维护者用于签署资源包的公钥位于 keys/,任何人都可以选择信任由该密钥签署的资源包。除非你列出该密钥,否则任何主机都不会信任它。
verified-memory-mcp --pack /absolute/path/to/pack --trusted-keys /absolute/path/to/trusted_keys
verified-memory-mcp --pack /absolute/path/to/pack --trusted-keys /absolute/path/to/trusted_keys --require-signature
verified-memory-mcp --pack /absolute/path/to/pack --trusted-keys /absolute/path/to/trusted_keys --strict
也接受 --flag=value、--require-signature=true|false 和 --strict=true|false 格式;空的 --trusted-keys=、--trusted-fingerprint=、--revoked-keys= 或 --min-sequence= 表示关闭相应设置。--require-signature 保留其 0.2.0 版本中的含义:必须由你列出的密钥签名,并会报告新鲜度但不强制执行,因此使用普通 ssh-keygen 为 0.2.0 签名的资源包仍可在此设置下加载。--strict 要求签名受信任,且 PACK.json 是最新的(它隐含 --require-signature)。
主机的作用
每个工具结果都带有 verification.signature 和 verification.freshness。
每次调用时,都会根据这台计算机的时钟判断新鲜度,而不仅仅是在启动时判断。
| 内容包 | 默认 | --require-signature | --strict |
|---|---|---|---|
| 未签名(所有 0.1 内容包) | 启动;signature.status: "unsigned" | 拒绝启动 | 拒绝启动 |
| 存在签名但格式错误或无效 | 拒绝启动 | 拒绝启动 | 拒绝启动 |
| 签名有效,但密钥不在你的文件中 | 启动;状态为 untrusted,并显示密钥指纹 | 拒绝启动 | 拒绝启动 |
| 签名有效,密钥在你的文件中 | 启动;状态为 verified,并显示 signer(你为该密钥设置的名称)和 fingerprint | 启动 | 如果新鲜(见下文),则启动 |
没有 PACK.json | 启动;freshness.status: "unknown" | 启动;状态为 unknown | 拒绝启动 |
存在 PACK.json,尚未过期 | 启动;状态为 fresh,并显示 created_utc、expires_utc | 启动;状态为 fresh | 启动 |
PACK.json 已过期 | 启动;状态为 stale,并在 stderr 上显示警告 | 启动;状态为 stale,并显示警告 | 拒绝启动;运行中的服务会在过期后停止提供服务(工具错误) |
created_utc 比当前时间晚超过 5 分钟 | 启动;状态为 not_yet_valid,并在 stderr 上显示警告 | 启动;状态为 not_yet_valid,并显示警告 | 拒绝启动 |
PACK.json 或其校验和遭到篡改 | 拒绝启动 | 拒绝启动 | 拒绝启动 |
| 运行期间内容包文件夹发生变化 | 工具返回 isError,直到重启 | 同左 | 同左 |
使用 0.4.0 选项时,在上述任意模式下:
| 内容包 | 结果 |
|---|---|
由 --revoked-keys 中的密钥签名 | 拒绝启动,并显示指纹,即使该密钥已固定或受信任 |
设置了 --trusted-fingerprint;由固定密钥签名 | 启动;状态为 verified,pinned: true,signer 取自 --trusted-keys,否则为 "pinned" |
设置了 --trusted-fingerprint;由任何其他密钥签名,即使该密钥在 --trusted-keys 中 | 拒绝启动 |
设置了 --trusted-fingerprint 或 --min-sequence;内容包未签名 | 拒绝启动 |
--min-sequence N;已签名的 sequence ≥ N | 启动;freshness.sequence 会报告该值 |
--min-sequence N;sequence 小于 N 或缺失 | 拒绝启动 |
存在 sequence,但未设置 --min-sequence | 启动;报告 freshness.sequence,但不强制执行 |
只有在你列出的密钥签署了日期时,freshness.authenticated 才为 true;未签名或不受信任的内容包中的日期可能由任何人填写。未设置固定指纹或受信任密钥时,使用 --require-signature 或 --strict 会导致拒绝启动;如果受信任密钥行不是仅含单个名称的 ssh-ed25519 条目,也会拒绝启动。签署者名称始终取自你的文件,而不是内容包;指纹格式与 ssh-keygen -l 相同。任何人都可以不通过此服务检查内容包:
ssh-keygen -Y verify -f trusted_keys -I alice -n verified-memory-pack-v1 -s SHA256SUMS.sig < SHA256SUMS
签名能证明签署者身份,但不能证明内容属实。 它表明持有该密钥的人签署了这些确切的字节,但不能证明引文准确或完整,也不能证明密钥所有者就是你认为的那个人。“新鲜”表示签署者设置的有效期尚未届满,而不表示这是他们最新的内容包:如果未设置 --min-sequence,同一密钥签署的旧内容包仍会在过期前加载。密钥撤销和最小序列号的状态只与配置一样及时:没有网络时,新近撤销的密钥或更新的序列号只有在你编辑设置后才会传达到主机。新鲜度取决于这台计算机的时钟。版本 0.1.0 会拒绝已签名的内容包(五个文件);要在该版本中加载,请移除 SHA256SUMS.sig。
构建和运行
在此仓库的检出目录中,使用 Node 22.0.0 或更高版本(使用所选 Node 版本线的最新补丁版本),并进入 plugins/verified-memory-mcp:
npm ci --ignore-scripts
npm run build
npm test
node --experimental-permission --allow-fs-read="$PWD" "$PWD/dist/index.js"
最后一条命令会启动 stdio 服务,并等待 MCP 客户端通过 stdin 连接。它不是交互式终端搜索界面。请通过 Claude Desktop 或其他 MCP 客户端连接,然后请求搜索陶器并检索 M-sample-2。Node 的权限模式仅允许读取此项目目录下的内容;文件系统写入、子进程、工作线程和原生插件均会被拒绝。在 Node 22.0.0 的最低版本上可使用 --experimental-permission 写法;早期 Node 22 版本会在 stderr 输出实验性警告。在 Node 22.13+ 上,可以改用 --permission。Node 22 不会强制执行网络权限;此服务不会发起网络调用。Node 25.8.0 还通过了套接字拒绝探测。请参阅 Node 22.0 权限文档和 Node 22.13 权限文档。运行时请直接调用 node,不要使用 npm/npx 或 Shell 包装器。
构建、安装依赖和运行测试属于开发操作:它们会写入本地输出;安装依赖时会访问 npm 注册表。运行时不会执行这些操作。测试框架会启动本地 Node 进程,并为这个虚构的资源包创建隔离的临时副本;服务本身绝不会启动其他进程。
Claude Desktop 一键安装
从最新版本下载 verified-memory-<version>.mcpb。
verified-memory-<version>.mcpb 是适用于 macOS 和 Windows 上 Claude Desktop 的 MCP Bundle;已在 macOS 和 Windows 上手动测试。它使用 Claude Desktop 内置的 Node.js 运行,因此无需安装 Node,也无需使用终端。
- 双击
.mcpb文件。Windows 可能会询问使用哪个应用打开:请选择 Claude。 也可以将文件拖到 Claude Desktop → 设置 → 扩展,或使用 设置 → 扩展 → 高级设置 → 安装扩展…。 - 先解压安装包(Windows:右键单击 → 全部解压)。选择包含
MEMORY.md、README.md、records.jsonl和SHA256SUMS的文件夹。 文件夹选择器只显示文件夹,因此安装包文件夹看起来会是空的;这是正常现象。你也可以粘贴文件夹路径。 - 提问前,请确保扩展已开启(设置 → 扩展 → 已启用)。 示例问题:“使用 verified memory,……发生了什么?”
设置表单包含以下字段:
| 设置 | 必填 | 传递为 |
|---|---|---|
| Memory pack 文件夹 | 是 | --pack=<folder> |
| 可信密钥文件 | 否(留空 = 无) | --trusted-keys=<file> |
| 固定签名者指纹(推荐用于已签名的 pack) | 否(留空 = 无) | --trusted-fingerprint=<SHA256:…[,SHA256:…]> |
| 已撤销密钥文件 | 否(留空 = 无) | --revoked-keys=<file> |
| 最小 pack 序列号 | 否(留空 = 关闭) | --min-sequence=<N> |
| 要求固定或可信签名 | 否(关闭) | --require-signature=true|false |
| 严格模式:要求固定或可信签名,且 pack 未过期 | 否(关闭) | --strict=true|false |
对于已签名的 pack,请将 sign-pack 输出的指纹粘贴到固定签名者指纹中;这样就不需要可信密钥文件。安装较新的 pack 时,请提高最小 pack 序列号。对于带有过期日期的 pack(sign-pack 总会添加过期日期),请开启严格模式。所有新增设置默认均为关闭,因此从 0.3.0 升级的扩展行为与之前一致(发生变更时停止除外)。
之后可在设置 → 扩展 → Verified Memory中修改这些设置。该 Bundle 包含与 npm 包相同的 dist/ 及其生产依赖,不包含其他内容:没有 pack、密钥、签名或测试。它未使用 mcpb sign 进行代码签名,因为这需要私钥。它不使用 Node 的权限模式,因为 Claude Desktop 会自行启动服务。
使用 npm ci && npm run build:mcpb 在本地构建(输出:build/verified-memory-<version>.mcpb)。
npm run test:mcpb 会构建并运行 test/mcpb/。这些测试会使用
@anthropic-ai/mcpb 解包 Bundle,并使用 getMcpConfigForManifest 根据示例设置生成的参数启动服务。
Claude Desktop 配置示例
将此示例合并到 Claude Desktop 的 MCP 配置中,并在构建后重启 Claude Desktop。以下所有路径均为占位符,并非真实的用户路径。 请将它们替换为 Node 可执行文件和此构建目录的绝对路径。 不会自动安装或编辑任何配置。
{
"mcpServers": {
"verified-memory": {
"command": "/absolute/path/to/node",
"args": [
"--experimental-permission",
"--allow-fs-read=/absolute/path/to/hive-public/plugins/verified-memory-mcp",
"/absolute/path/to/hive-public/plugins/verified-memory-mcp/dist/index.js"
]
}
}
}
在仓库构建中,省略 --pack 时,无论客户端的工作目录是什么,都会使用打包的虚构 Juniper Vale/Wren
示例。npm 安装中没有示例,并且若未指定 --pack,服务会拒绝启动。若要使用自己的 pack,请在
args 中追加
"--pack", "/absolute/path/to/pack",并在入口点参数之前添加
"--allow-fs-read=/absolute/path/to/pack"。使用
--trusted-keys 时,也要以相同方式允许读取该文件。
请选择连接的客户端有权读取的 pack。
相对 pack 路径和未知 CLI 标志都会被拒绝。工具无法选择路径。
不会探测主目录、其他 Agent、真实记忆或配置。
没有监视器或重新加载机制:如果服务运行时 pack 文件夹发生更改,工具就会停止响应并返回错误,即使撤销了更改也一样;必须重启
服务以验证新的 pack。以相同方式将
--trusted-fingerprint、--revoked-keys(及其 --allow-fs-read)和
--min-sequence 添加到 args 中。
工具契约
verified_memory_search:
{"type":"object","properties":{"query":{"type":"string","minLength":1,"maxLength":512}},"required":["query"],"additionalProperties":false}
返回 matches、matched、verification 和 notice。搜索会在 statement/topic/quotes 中查找所有经过 Unicode 规范化的词,最多包含 32 个不重复词。
最多返回 10 条匹配项,按词项出现次数、日期从新到旧、记录 ID 排序。
匹配项保留原样引文、源消息 ID、日期和发言者。
不进行词干提取、语义推断或网络查询。没有匹配项并不能证明内容不存在。
verified_memory_get:
{"type":"object","properties":{"id":{"type":"string","pattern":"^M-[A-Za-z0-9_-]{1,127}$"}},"required":["id"],"additionalProperties":false}
返回 found、完整的 record(或 null)、verification 和 notice,并将引文、来源信息、审计、审批和取代元数据保留为历史数据。
成功的 MCP 结果会在 content 中包含 JSON 文本,并在 structuredContent 中包含相同的对象(等同于 OpenClaw 工具的 details)。
无效的工具参数会返回 isError: true;未知工具名称会返回协议错误。
这两个工具都声明为只读、非破坏性、幂等且采用封闭世界的注解。
SDK 的底层 Server API 会保持已发布的 JSON Schema 原样,包括 additionalProperties: false;参数会经过显式检查和共享验证器检查。构建或运行此服务不需要 OpenClaw 运行时或依赖。
共享验证器与失败关闭启动
仅用于开发的 scripts/prepare.mjs 会将原始
../verified-memory/src/pack.ts 和 verify.ts 逐字节复制到被忽略的 src/,并
将其公开的虚构样例复制到被忽略的 sample-pack/。TypeScript 会将
同一个验证器编译为 dist/pack.js(读取文件)和 dist/verify.js(实际执行检查,
不含导入)。不存在第二个需要维护的验证器,此构建也绝不会修改 OpenClaw 插件。请从仓库
检出目录进行构建,以确保同级源文件和样例存在。生成文件不会提交。
必须先验证整个包,之后才能创建服务或连接 stdio。
验证失败的包无法初始化、列出工具或返回记录。确切格式为四个常规文件:records.jsonl、MEMORY.md、README.md 和 SHA256SUMS,
另可包含由同一个共享验证器检查的 PACK.json 和 SHA256SUMS.sig。
检查包括文件清单精确匹配、对实际解析的字节计算 SHA-256 哈希、UTF-8、JSON、唯一 ID、引用结构与偏移量、日期范围、清单语法、符号链接根目录/条目以及文件大小/数量限制。限制仍为每个数据文件 16 MiB、清单 4 KiB、10,000 条记录。不提供宽松回退。后续对磁盘文件的修改无法更改已验证的内存快照;自 0.4.0 起,这类修改还会阻止快照被提供服务(参见变更时停止);检索会返回副本。
继承的文件系统检查无法防范能够抢先修改祖先目录的攻击者。请使用可信且稳定的本地目录,并遵守 Node 读取白名单。
完整性不代表真实性或正确性。 替换数据和校验和即可生成验证通过的包,除非你固定签名者(--trusted-fingerprint),或仅列出信任文件无法被攻击者写入的密钥。运行时无法根据原始消息重新核验引文。
历史引文是数据,而非指令或权限;每个成功结果都会附带此声明。主机模型行为和自动工具选择均未经过验证。请要求主机逐字引用工具文本,并注明记录和消息 ID。
仅使用现有的公开虚构源文件
agent-memory/sample/telegram-export.json。不包含任何私人记录、操作路径、IP 地址、密钥或其他 Agent 的文件。样例审计/审批元数据并非真实模型审计或人工审批的证据。
文件树
plugins/verified-memory-mcp/
├── .gitignore
├── LICENSE
├── README.md
├── VALIDATION.md
├── RELEASE-NOTES-0.4.0.md # notes for the 0.4.0 release
├── RELEASE-NOTES-0.4.1.md # draft notes for the 0.4.1 release
├── package.json
├── package-lock.json
├── server.json # MCP Registry metadata
├── tsconfig.json
├── scripts/
│ ├── prepare.mjs
│ ├── build-mcpb.mjs # builds the Claude Desktop bundle into build/
│ └── test-all.mjs # every automated suite, as CI runs it on macOS and Windows
├── mcpb/manifest.json # Claude Desktop bundle manifest (settings form, tools)
├── src/
│ ├── index.ts
│ ├── server.ts
│ ├── pack.ts # generated, ignored; exact shared source
│ └── verify.ts # generated, ignored; exact shared source
├── web/ # repo-only: browser pack maker (see web/README.md)
├── tools/
│ ├── build-pack.mjs # offline pack builder (ships in npm)
│ ├── pack-core.mjs # its import-free building rules (ships in npm)
│ ├── sign-pack.mjs # signs and dates a pack via ssh-keygen (ships in npm)
│ └── export-shape.mjs # repo-only: prints a chat export's structure, never its text
├── examples/
│ ├── input/ # invented messages.jsonl + records.jsonl
│ └── pack/ # pack built from them
├── test/
│ ├── server.test.mjs
│ ├── redteam.test.mjs # red-team rounds R1–R6, revocation, precedence
│ ├── sign-pack.test.mjs
│ ├── build-pack.test.mjs
│ ├── pack-core.test.mjs
│ ├── export-shape.test.mjs
│ └── mcpb/bundle.test.mjs # run by `npm run test:mcpb` against the built bundle
├── validation/
│ ├── tests.txt # Node 25.8.0
│ ├── tests-node22-min.txt # Node 22.0.0
│ └── tests-node22-current.txt # Node 22.23.3
├── sample-pack/ # generated, ignored; four fictional files
├── build/ # generated, ignored; the .mcpb and its staging folder
└── dist/ # generated, ignored; JS and declarations
记录的测试和限制见 VALIDATION.md。
许可证
MIT — LICENSE。功能免费,不设付费层级。
☕ 支持此项目:https://buymeacoffee.com/python1
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。