关于 memshelf-mcp
memshelf-mcp 是面向 Agent 的本地优先工作记忆系统,将已结束的话题和大量上下文保存为带索引的 Markdown 片段,并验证摘要。它通过 MCP 和命令行支持按需回忆,默认使用本地 git 仓库存储。
主要功能
- 01将话题保存为 Markdown 片段
- 02验证片段摘要
- 03按需回忆单个章节
- 04搜索并检查记忆架
- 05重建索引及派生文件
- 06可选语义搜索侧车
适用场景
- 01在 Agent 会话间保留决策
- 02从过往研究中提取单个章节
- 03导入并整理导出的对话
- 04跟踪记忆规模和 token 节省
MCP 相关
它向 MCP 客户端提供记忆架创建、片段存储、索引、回忆、搜索和维护工具。相同的核心操作也可通过命令行使用。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
15收录的工具列表 · 更新于 2 周前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| params | any | 是 |
详细介绍
memshelf-mcp
把 Agent 的记忆放上架,并把索引交给它。
_ _ __
_ __ ___ ___ _ __ ___ ___| |__ ___| |/ _|
| '_ ` _ \ / _ \ '_ ` _ \/ __| '_ \ / _ \ | |_
| | | | | | __/ | | | | \__ \ | | | __/ | _|
|_| |_| |_|\___|_| |_| |_|___/_| |_|\___|_|_|
____________________________________________
| INDEX >> | E-01 | E-02 | E-03 | E-04 | ... |
|__________|______|______|______|______|_____|
memory shelves for AI agents
项目介绍
长期运行的 Agent 会话会因反复发送历史记录而消耗大量令牌,也会因有损自动压缩而丢失细节。memshelf 将 docshelf 的模式——在上下文中保留小型索引,按需获取正文——应用于 Agent 自身的工作记忆:
- 已结束的对话主题、研究资料和庞大的工具输出会作为 Markdown 片段转存到本地存储架。
- 每个片段都带有由大模型编写、经过契约验证的摘要,保留决策、被否决的替代方案、产物和未解决事项。
- Agent 只需在上下文中保留
INDEX.md(几 KB)和摘要,并通过 MCP 按 INDEX → 片段 → 章节切片的路径回忆确切内容。
一句话定位:claude-mem 的循环、git 的底层、docshelf 的导航——可用 grep 搜索、比较差异、审阅并在主机之间携带的情景记忆。默认私密且存储在本地:标准存储模式是一个未配置远程服务的本地 git 仓库。工具是公开的,记忆永远不会公开。
实测,而非承诺
在实际存储架上进行一周的自用测试——完整数据和方法见
docs/demo.md:
| 指标 | 结果 |
|---|---|
| 存储架上的片段数 | 34 |
| 每次会话固定占用(INDEX + 摘要) | ~8.6K 个令牌 |
| 这些片段取代的存储内容 | ~1.9M 个令牌 — ≈220 : 1 |
| 从记忆中回答一个问题 | ~1.8K 个令牌(INDEX + 一个片段) |
| 回忆测试:全新 Agent,仅使用 INDEX 路径 | 5 / 5 — 零遗漏,零过量获取 |
所有令牌数均按字符数/4 计算,因此比率不受估算器影响;绝对数值会随分词器而变化。
快速开始
作为 MCP 服务:
# Claude Code
claude mcp add memshelf -- uvx memshelf-mcp
// Claude Desktop (claude_desktop_config.json)
{
"mcpServers": {
"memshelf": { "command": "uvx", "args": ["memshelf-mcp"] }
}
}
作为 Claude Desktop 扩展 — adapters/claude-desktop/:
一个 .mcpb 捆绑包,可从设置 → 扩展安装,并提供默认存储架设置,因此调用时无需重复指定路径。无需额外安装任何内容,甚至不需要 Python。
作为 Claude Code 插件 — adapters/claude-code/:
包含一个 /shelve 技能,以及 SessionStart / SessionEnd / PreCompact 钩子。
也可以通过命令行使用(pip install memshelf-mcp,Python ≥ 3.10)——相同的工作流程,无需 MCP:
memshelf init --shelf ~/my-shelf --name "My working memory"
memshelf shelve --shelf ~/my-shelf --slug 2026-07-23-topic --kind topic \
--digest "What was decided, what was rejected and why, what stays open." \
--section "Decisions=What was decided, and what was rejected instead — one line each."
memshelf recall --shelf ~/my-shelf --id 2026-07-23-topic --section Decisions --log
memshelf rebuild --shelf ~/my-shelf # render ledger/INDEX from the episode (a bot's job on shelves that have one)
memshelf stats --shelf ~/my-shelf # claimed + realized savings
memshelf doctor --shelf ~/my-shelf # exit 1 on integrity errors
pip install 'memshelf-mcp[semantic]' 会添加一个嵌入向量辅助组件,让 search 也能找到释义相同的内容和另一种语言的内容(执行一次 memshelf semantic build --shelf ~/my-shelf;设置 MEMSHELF_SEMANTIC=off 可关闭)。此项为可选功能:
基础安装仍仅使用 grep 搜索,保持轻量不变。
工具范围
每项任务对应一个动词;MCP 中(memshelf_*)和 CLI 中的名称相同
(完整描述见:docs/tools.md):
| 工具 | 功能 |
|---|---|
init | 创建(或补全)记忆架:采用 docshelf 布局和固定分类 |
shelve | 将一个已结束的话题归档为持久化、带索引的事件;--amend 会原位重写 |
lint_digest | 根据契约验证摘要,不触碰记忆架 |
import | 将整个导出的对话回溯归档,无需将其载入上下文 |
index | 返回记忆架的 INDEX——轻量的回忆入口 |
recall | 按 ID 获取事件,或获取其中单个 ## Section |
search | 在记忆架中 grep;返回匹配的事件 |
stats | 记忆架的 Token 经济账:常驻成本与归档总量、声称值与实际值 |
advise | 展示上下文由什么构成,以及可以放下什么——仅提供建议 |
rebuild | 从事件重新生成所有派生文件 |
rollup | 将一个时期归档为一份摘要的摘要 |
purge | 删除超过 retain_until 的事件,然后重新建立索引——默认试运行 |
resolve | 解决多写入者冲突:重新生成派生文件,合并回忆日志 |
doctor | 诊断:事件架构、静态摘要契约、密钥形态、索引膨胀情况 |
freshness | 仅限 CLI——检查哪个已安装的使用方(pipx、Desktop 扩展)会响应调用,以及哪些更改已合并但尚未发布(#125) |
sync | 仅限 CLI——获取记忆架克隆,并快进到其远程版本(#157) |
prune-splits | 仅限 CLI——移除 git 未跟踪到的 H2 拆分目录(#109 的迁移工具) |
tags | 仅限 CLI——按 frontmatter 标签分组事件(#18) |
graph | 仅限 CLI——谁提到了谁:以 JSON 或 Mermaid 格式展示跨事件 ID 引用(#18) |
retro | 仅限 CLI——将记忆架的一个季度内容整理为 Markdown 回顾(#18) |
fork | 仅限 CLI——从 INDEX 和选定的事件或章节引导一个新会话(#18) |
mirror | 仅限 CLI——将 INDEX(± 事件)整理为一个独立的 HTML 页面,方便在手机上阅读(#18) |
semantic | 仅限 CLI——build / status / drop 将 search 转为混合搜索的嵌入旁文件;位于记忆架之外,需运行 pip install 'memshelf-mcp[semantic]'(#17) |
search-bench | 仅限 CLI——在 query<TAB>expected-id 文件上测量 grep 与混合搜索的 hit@1 / hit@k / MRR(#17) |
工具执行的规则
摘要是契约,不是惯例。 回忆时,获取正文前唯一会读取的就是摘要,因此摘要质量差会降低整个事件的价值。
lint_digest 会运行与 shelve 相同的验证器,且不会产生副作用
(--strict 会将警告视为失败);错误会阻止归档,警告则不会——纯引用摘要不带决策标记也完全合理。摘要被拒绝是件好事:工具会明确指出需要修正的内容,且不会写入任何内容。
--amend 会重新运行整个流程——脱敏、摘要契约、内容编排——因此修订后的事件受到的保护与新事件完全相同,而手动编辑文件永远无法做到这一点。修订不在记忆架中的 slug 会报错,不会创建新事件。
事件是数据源;其他一切都是输出。 ledger.tsv、
INDEX.md、stats.svg 和各分类中的 .meta.json 都是派生文件:
shelve 只写入并提交事件本身,rebuild 则生成其余内容——删除这四类文件后,运行 rebuild 就会逐字节还原它们。正因如此,两个会话并行归档不会引发问题:合并从设计上就不会产生冲突。在共享记忆架上,让机器人在 main 分支负责派生文件——可直接复制使用的工作流见 adapters/shelf-repo/;
rebuild --adopt 可一次性迁移旧版记忆架,rebuild --check 则是 CI 防护措施。
有两点值得明确说明,因为弄错了会导致合并冲突:
- 正确执行一次
shelve后,doctor会立即报告no-ledger-row和stale-index——所有分支都如此,包括main。 这并不代表出了问题:片段已写入,但派生文件尚未渲染。下一次rebuild后它们就会消失——对于有机器人的 shelf 来说,就是机器人运行时。 - 不要手动重建并提交派生文件来消除这些警告。 这正是拆分要消除的冲突类型:手动重新生成的
ledger.tsv/INDEX.md/stats.svg会与机器人的版本相遇,合并从一开始就无法保持干净。请等待渲染器;对于没有机器人的 shelf,请单独执行memshelf rebuild --shelf .。
如果这些警告持续了一天,期间仍不断有片段到来,那就是另一种情况——渲染器不是延迟,而是已停止——doctor 会另行以错误严重级别报告 derived-stale。这一天从渲染器首次能够看到这些工作时开始计算,而不是从账本最近一次提交时开始:几分钟前才推送到 shelf 的片段,如果所在 shelf 的账本自昨天以来都没有变动,并不能说明渲染器的状况;过去说成相反的情况,会让读者去手动执行 rebuild,而这正是整个拆分要避免的冲突。
这个到达时间取自此克隆中跟踪上游分支的 reflog——这是唯一能记录引用何时移动到此处的本地记录。提交日期不能替代它:提交日期表示片段的写入时间,而“先 shelve,确认后再推送”是有文档记录的工作方式,因此两者可能相隔一个工作日。如果 reflog 无法提供信息——新克隆的 reflog 为空,CI 和临时 Agent 会话运行时就是如此——doctor 会以 unknown 级别报告 renderer-wait-unknown,而不是擅自判断:此时“已停止”和“刚在一分钟前交付工作”看起来一样,因此必须在可观察到渲染器的地方,也就是它自己的任务运行中,判断它的状态。对于没有上游分支的 shelf,不必为渲染器考虑,账本自身的更新时间仍是计时依据。
判断渲染器所依据的引用是渲染分支,而不是检出分支碰巧跟踪的分支(#180)。机器人只渲染一个分支——远程仓库的默认分支:克隆中存在 origin/HEAD 时读取它,否则使用 origin/main,再否则使用 origin/master——因此,处于 PR 分支的克隆不会因为某个片段只存在于 origin/<pr-branch> 上而被报告 derived-stale。该片段要等的是合并,而不是渲染器;doctor 会用警告 upstream-not-rendered 说明这一点。若片段确实已到达渲染分支,则即使当前处于 PR 分支,也会在那里判断;任一分支上的本地提交仍会标为 episode-unpushed。
以前还有第三种会让 stale-index 永远存在的情况;现在已修复,无需再写进文档:docshelf 会把超过 50 KiB 的片段拆分成与其相邻的章节文件,shelve 只提交片段本身,从此这个工作副本渲染出的 INDEX 便成了其他检出都无法生成的版本——任何 rebuild 都无法清除它,而且 search 返回的地址只在一台机器上存在(#109)。shelve 不再拆分片段。已包含此类目录的 shelf 会继续报告 local-split-dir,直到执行 memshelf prune-splits --shelf . --apply 将其移除;片段文件包含所有章节,因此不会丢失内容。若不带 --apply,该操作会进行试运行;已提交的拆分目录会被报告,但不会改动。
advise 只提出建议,绝不写入。 它回答的是项目创立之初就关注的问题——一个已失效的话题占用了 30K 个令牌达四十分钟。工具看不到你的窗口,因此需要你告诉它窗口里有什么:
memshelf advise --shelf ~/my-shelf \
--occupant 'auth refactor=42000,closed' \
--occupant 'search dump=9000,idle=18' \
--occupant 'Case B verdict=12000,live,episode=2026-07-22-case-b-verdict'
有三件事能确保它诚实:它会将自身计入(INDEX 和摘要包含在报告中,不会被漏掉);它会在建议移除前验证 episode= 声明;它会报告净值——如果一个话题太小,连自己的摘要成本都无法弥补,就不会被建议移除。
Rollup 只精简导航,不会做其他事。 当 INDEX 在窗口中占据的空间越来越大时,rollup 会将一个时期折叠为一份摘要的摘要,并把原始内容移到 archive/——仍可通过 recall 和 search 访问,账本中的每一行也都完整保留。Rollup 摘要由你撰写,而不是工具:综合一个季度的内容,是工具无法完成的部分。
index-bloat 不是 rollup 要解决的问题。 INDEX 列出你的经历,因此它的大小会随着存档架的增长而有意增长;它的预算也会随存档架增长(INDEX_BASE_TOKENS + INDEX_TOKENS_PER_ENTRY × listed)。因此,超出预算意味着条目定价过高,绝不是条目太多——所以 doctor 会报告每一行的成本,解决办法是精简内容并 rebuild。Rollup 会同时移除条目及其对应的预算额度,价格却维持不变。将这两者配对反了,才会让“归档三分之一的记忆”成为解决格式问题的常规做法。
purge 删除的是工作树,不是历史记录。 保留策略需按经历单独启用(--retain-until);在指定 --apply 前,purge 都只是试运行——即便指定了,文件仍保留在 git 历史记录中。真正的彻底删除需要对整个仓库有意执行 filter-repo,绝不会作为工具调用的副作用发生;purge 报告也会明确说明这一点。
resolve 会重新生成派生路径,绝不会合并它们——派生文件没有历史记录,只有当前的正确值。它会合并的唯一文件是 recall-log.tsv,因为 recall 是一个事件,而不是关于这些经历的事实。冲突的经历属于内容问题,不是机制问题:resolve 会报告它们,然后不再处理。
工具响应会说明其背后的代码是否过时。 同一份代码以五种方式发布,版本号在各个版本间不会变化;此前两次,合并后的修复都未生效,因为响应调用的副本落后于 main(#125、#158)——几个小时后才旁敲侧击地发现问题,起初看起来像是工具故障。doctor 会将这种差异报告为 served-code-differs;由于只有运行 doctor 的人才能看到 doctor 的发现,MCP 服务现在会直接在响应中说明:当已提供服务的包的哈希与存档架旁边的 memshelf-mcp 检出版本(或 $MEMSHELF_CHECKOUT)不同时,每个信封——无论成功还是出错——都会以一条 warning 开头,其中包含该代码、两个短哈希及各自的位置。代码相同时不会添加任何内容。每次调用时,如果没有可供比对的检出版本,也不会添加任何内容;但 initialize 说明会指出新旧状态未知,以及如何确定。若这种差异是有意的,可通过 MEMSHELF_FRESHNESS_WARNING=0 关闭每次调用的警告。
每条规则背后的设计依据见
docs/DECISIONS.md 和
docs/ARCHITECTURE.md。
一个记忆,多个 AI
这种记忆可跨厂商使用,而且这是经过验证的事实,并非设计意图:同一个正在使用的存档架已通过一个 shelf-spec 服务,由 Claude Code(Anthropic)和 Gemini CLI(Google)读取并交叉写入——协议和实测记录见 docs/portability.md。
状态
M0 已完成:该模式已在一个正在使用的存档架上通过零代码验证——回溯导入数月的材料,然后连续一周在关闭时收纳
(docs/M0.md)。M1 已发布用于执行该模式的服务/CLI,以及 Claude Code 插件。带有退出标准的后续里程碑:
docs/ROADMAP.md;发布历史:
CHANGELOG.md。
文档
渲染后的站点:https://ignatenkofi.github.io/memshelf-mcp/ — 包含来自内部试用记忆架的周报信息图。
| 文档 | 内容 |
|---|---|
docs/MANIFEST.md | 问题、核心设想、核心场景、原则、非目标 |
docs/tools.md | 工具参考:每个 memshelf_* 工具的详细说明(MCP schema 中只包含简短说明) |
docs/ARCHITECTURE.md | 片段格式、摘要约定、存储模式、触发条件、MCP 工具接口、可移植性模型、隐私、故障模式 |
docs/LANDSCAPE.md | 先例调研(2026-07)、平台内置功能、定位、风险 |
docs/ROADMAP.md | 里程碑 M0–M3 及退出标准 |
docs/DECISIONS.md | 决策日志 |
docs/M0.md | M0 实验方案与结果:案例、令牌账本、回忆测试 |
docs/demo.md | 内部试用记忆架的测量数据:压缩、回忆测试、检查结果 |
docs/portability.md | 一份记忆,多个 AI:跨供应商实验 |
docs/chat-projects.md | 不使用 hooks 的 Claude Desktop 和 claude.ai 项目:设置、回忆、存入记忆架、保持索引最新 |
docs/examples/ | 一份完整的片段文件示例和一个记忆架 INDEX |
adapters/claude-code/ | Claude Code 插件:/shelve 技能 + SessionStart/SessionEnd/PreCompact hooks |
adapters/claude-desktop/ | Claude Desktop .mcpb 扩展:构建器、打包检查器、默认记忆架设置 |
adapters/claude-account/ | claude.ai 账户技能的存档镜像 — 不可安装,仅用于对照 |
项目记忆架
shelf/ 是本项目自己的记忆架,用它所发布的工具进行内部试用:
其中保存了包含决策、被否决的选项及其原因的会话片段。在断言此处任何有关过往工作的内容前,
请先阅读 shelf/INDEX.md
并获取它指向的那份片段 — 对过往决策的猜测是缺陷,
不是估算。派生文件(ledger.tsv、INDEX.md、stats.svg、
.meta.json)与片段在同一次提交中写入
(memshelf rebuild --shelf shelf);若这些文件发生偏差,shelf-pr-guard 工作流会阻止 PR 或
推送到 main。
起源
本项目最初以 RFC-0001 的形式在 docshelf-mcp 仓库中设计 (#42, #43, #44);自 2026-07-13 起,本仓库成为 该项目的主仓库。docshelf 中的副本已冻结为 历史快照。
相关项目
- docshelf-mcp — 关联项目和存储层:PDF/Markdown → 适合聊天项目的 文档架,采用相同的索引与按需获取机制 (测量数据: 每个问题约 3.7K 个令牌,而非 1.2M)。memshelf 最初作为 RFC-0001 在其仓库中诞生,并逐字复用了其拆分器/索引器/读取/搜索功能。
- 内部试用记忆架是一个私有仓库 — 这是有意为之 (MANIFEST 原则 5)。
许可证
MIT — 参见 LICENSE。
mcp-name: io.github.ignatenkofi/memshelf-mcp
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。