BingoAgentTouch/Personal_MCP
一个给 LLM Agent(如 Claude Code)用的分层长期记忆 MCP 服务器。把对话沉淀成可语义检索的三层记忆,回答"我们上次聊到哪了"时能带出完整上下文。
catalog 简介 / catalog descriptioncatalog description:这是一个用来存放个人搭建的MCP服务的仓库
项目介绍Project Overview
memory-mcp-server 是面向 LLM Agent(如 Claude Code、DSH)的分层长期记忆 MCP 服务器,将对话沉淀为可语义检索的三层记忆:原始逐轮记录(L0)、任务片段(L1,自动生成 embedding)、每日总结与主题索引(L2/L3)。支持本地多语言 MiniLM(384 维)或 OpenAI 兼容嵌入 API。适用于需要跨会话回溯"上次聊到哪"并补齐上下文的场景。本地模型加载失败或 API 不可用时退回关键词检索并告警;存储根相对服务器 CWD,需以目标项目根启动。
memory-mcp-server is a tiered long-term memory MCP server for LLM agents (e.g., Claude Code, DSH), persisting conversations into a three-layer, semantically searchable store: raw per-turn records (L0), task fragments with auto-generated embeddings (L1), and daily summaries plus topic indices (L2/L3). It supports a local multilingual MiniLM (384-dim) or an OpenAI-compatible embedding API. Use it when an agent needs to recall prior sessions and reconstruct full context. If local loading or the API fails, it falls back to keyword search and logs a warning; the storage root is resolved relative to the server's CWD.
请帮我了解并安装插件:【Personal_MCP】【https://github.com/BingoAgentTouch/Personal_MCP】
把上面这条消息直接发给当前会话里的 DSH,让它帮你了解并安装。安装命令不一定准确,发给 DSH 更稳。Send this message to DSH in your current session. CLI install commands may not be accurate across systems — DSH will figure it out for you.
或使用命令行安装(适合开发者)Or use CLI install (for developers)
命令行安装CLI Install
dsh plugin --profile web add @bingo_touth/memory-mcp-server
把 BingoAgentTouch/Personal_MCP 加入你的 DSH 配置(web profile)即可启用。
READMEREADME
memory-mcp-server
一个给 LLM Agent(如 Claude Code)用的分层长期记忆 MCP 服务器。把对话沉淀成可语义检索的三层记忆,回答"我们上次聊到哪了"时能带出完整上下文。
当前版本:0.9.1
- 本地优先,可选 API:默认用本地
@xenova/transformers(多语言 MiniLM,384 维,零云依赖);也可切换到 OpenAI 兼容嵌入 API(MEMORY_EMBED_PROVIDER=api,免下载本地模型,见下文)。 - 分层回溯:命中片段(L1)时自动回填当天总结(L2)和主题脉络(L3)。
- 优雅降级:本地模型加载失败或 API 不可用时退回关键词(Jaccard)检索,并在 stderr 明确告警——不会假装正常。
记忆分层
memory/ # 存储根,相对「服务器进程的工作目录(CWD)」
├── raw/<date>/turns.jsonl # 原始对话,一字不改,全量保留
├── fragments/<date>/ # L1 任务→结果片段 (.md + .embedding 向量)
├── daily/<date>.md # L2 每日总结
└── topics/<topic>.md # L3 跨天主题索引
写入顺序:store_turn(逐轮) → create_fragment(打包几轮为一个片段,自动算 embedding) → create_daily_summary / upsert_topic(汇总)。
重要:存储根是相对 CWD 的(
path.resolve("memory/..."))。服务器进程以哪个目录为工作目录,记忆就写在那个目录的memory/下。让宿主(Claude Code 等)以「你想要记忆的项目根」为 CWD 启动本服务器。
安装 & 构建
下载安装到某个路径
npm install
npm run build # tsc → dist/
(注意,CherryStudio用户可能由于该GUI的路径问题或管道问题无法直接使用,请谨慎安装)
要求 Node ≥ 20(开发用 22 验证)。
从 npm 安装
npm install -g @bingo_touth/memory-mcp-server # 全局安装
memory-mcp # 直接以 stdio 启动
# 或临时运行:npx @bingo_touth/memory-mcp-server
本包发布名:
@bingo_touth/memory-mcp-server(npm 裸名memory-mcp-server/memory-mcp均已被他人占用,故用 scoped 名)。
各 harness 接入片段(参数化)
数据根约定(最重要):记忆库存储在服务器进程 CWD 下的 memory/ 目录。以你想让记忆归属的项目根作为 cwd 启动——下面两个配置的 cwd 字段都是关键。
DeepSeek Harness(DSH):~/.dsh/profiles/<profile>/cordis.patch.yml
- id: mcp-memory
name: '@deepseek-ai/dsh-mcp-client'
config:
serverName: memory
transport: stdio
command: node
args:
- '<安装路径>/dist/index.js' # 或全局安装后:["npx", "memory-mcp"]
cwd: '<项目根>' # 记忆库落在这里的 memory/ 下
toolCallTimeoutMs: 120000
failOnStartupError: true
作为 DSH 插件安装(推荐,0.9.2+)
本包自带 DSH bundle 声明(dsh.bundle.patch),可省去手写整段接入配置:
npm i -g pnpm # dsh plugin 依赖 pnpm(一次性)
dsh plugin --profile web add @bingo_touth/memory-mcp-server
pnpm 10 提示
ERR_PNPM_IGNORED_BUILDS(Ignored build scripts: protobufjs, sharp)时:这是 pnpm 10 默认拦截依赖构建脚本,会让dsh plugin add以非零退出、登记不生效。文本嵌入用不到这两个构建产物——编辑~/.dsh/profiles/web/pnpm-workspace.yaml(pnpm 已自动写好占位符),把protobufjs/sharp的allowBuilds置为false,然后重跑一次dsh plugin add即可。
安装后 bundle 已注册 mcp-memory 行(默认 MEMORY_SKIP_INJECT=1、cwd=DSH 启动目录、failOnStartupError=false 不阻断启动)。唯一要做的:把服务器绝对路径换成你的——在你自己的 ~/.dsh/profiles/<profile>/cordis.patch.yml 里用同 id 覆盖(用户层覆盖 bundle 层):
- id: mcp-memory
name: '@deepseek-ai/dsh-mcp-client'
config:
serverName: memory
transport: stdio
command: node
args: ['C:/<你的绝对路径>/dist/index.js'] # npm i -g 后可用 `npm root -g` 查
cwd: '<你的项目根>' # 记忆库落在这里的 memory/ 下
toolCallTimeoutMs: 120000
failOnStartupError: true
为什么不能全自动:DSH 以
shell:false启动 MCP 子进程,Windows 上npx/.cmd直启不可用(实测 ENOENT/EINVAL),必须node + 绝对路径,而绝对路径只有你本机知道——所以保留这一行替换。⚠️ 覆盖行必须是上面的普通
- id:形式,不要再用- insert:包同一个 id——bundle 已插入该行,再 insert 会产生重复条目,DSH 启动直接报错duplicate loader entry id: mcp-memory(实测踩坑)。卸载插件后这一行会因找不到条目而自动跳过(告警无害)。卸载:
dsh plugin --profile web remove @bingo_touth/memory-mcp-server。
Claude Code:项目根的 .mcp.json
{
"mcpServers": {
"memory": {
"type": "stdio",
"command": "node",
"args": ["<安装路径>/dist/index.js"],
"env": {}
}
}
}
或直接给 Claude Code 文件已安装的路径,让其智能注册,然后重启 Claude Code。
发布友好开关:服务器启动时会向 CWD 项目的 harness 规则文件(AGENTS.md 等)注入「记忆使用规范」。对他人机器这是侵入性行为——设
MEMORY_SKIP_INJECT=1(或true/yes)可跳过;本机不设则保留现状。
⚠ Embedding 模型:首次运行需要它,离线环境要手动放
语义检索默认用 Xenova/paraphrase-multilingual-MiniLM-L12-v2(quantized,约 118MB,多语言,中文检索排序正确)。联网时 transformers.js 首次运行会自动下载到:
node_modules/@xenova/transformers/.cache/Xenova/paraphrase-multilingual-MiniLM-L12-v2/
想换模型:设环境变量
MEMORY_EMBED_MODEL=<repo/model>即可覆盖默认(见src/embedding/provider.ts的MODEL_ID)。若换成非 384 维的模型,务必回填历史片段(见下文),新旧维度/模型的向量不可混用。早期版本用的是
Xenova/all-MiniLM-L6-v2(英文模型,约 23MB)——它对中文语义排序会倒挂(无关闲聊的 cosine 会压过正确答案),已弃用。
如果网络访问 huggingface.co 受阻(常见于国内/隔离网络),自动下载会以 TypeError: fetch failed 失败,服务器会退回关键词检索(召回质量明显下降)。此时手动放置模型即可,用镜像下载:
BASE="https://hf-mirror.com/Xenova/paraphrase-multilingual-MiniLM-L12-v2/resolve/main"
DEST="node_modules/@xenova/transformers/.cache/Xenova/paraphrase-multilingual-MiniLM-L12-v2"
mkdir -p "$DEST/onnx"
curl -sL "$BASE/config.json" -o "$DEST/config.json"
curl -sL "$BASE/tokenizer.json" -o "$DEST/tokenizer.json"
curl -sL "$BASE/tokenizer_config.json" -o "$DEST/tokenizer_config.json"
curl -sL "$BASE/onnx/model_quantized.onnx" -o "$DEST/onnx/model_quantized.onnx"
验证离线可加载:
node --input-type=module -e '
import { pipeline, env } from "@xenova/transformers";
env.allowRemoteModels = false; // 强制只用本地缓存
const ex = await pipeline("feature-extraction","Xenova/paraphrase-multilingual-MiniLM-L12-v2",{quantized:true});
const r = await ex("你好",{pooling:"mean",normalize:true});
console.log("OK dim=", r.data.length); // 期望 384
'
放好后重启 MCP 服务器(常驻进程,不热更新;在 Claude Code 里即重启客户端)。
怎么判断当前跑在哪种模式
看服务器 stderr 与 create_fragment 返回的 embedding_mode 字段(取值为 api / transformers / fallback):
embedding_mode: "api"→ 走 OpenAI 兼容嵌入 API。embedding_mode: "transformers"→ 本地 MiniLM 语义模式正常。embedding_mode: "fallback"→ 模型没加载 / API 不可用,在用关键词检索,按上面步骤修。memory_search返回分数普遍在 0.2+(且同义改写也能命中)→ 语义模式正常。
嵌入模型 API 后端(可选,免下载本地模型)
不想下载/运行本地 384 维模型时,设 MEMORY_EMBED_PROVIDER=api 即可切到 OpenAI 兼容的 /v1/embeddings(覆盖 OpenAI、智谱、通义、月之暗面、Ollama、PPInfra 等):
MEMORY_EMBED_PROVIDER=api
MEMORY_EMBED_API_URL=https://api.openai.com/v1 # 必填,含 /v1 的 base URL
MEMORY_EMBED_API_KEY=sk-xxxx # 必填
MEMORY_EMBED_API_MODEL=text-embedding-3-small # 可选,默认这个
MEMORY_EMBED_API_MAX_TOKENS=8191 # 可选,文档预算上限
MEMORY_EMBED_API_DIM=1536 # 可选,固定维度;缺省则首次编码自动探测
MEMORY_EMBED_API_MAX_RETRIES=4 # 可选,429/5xx/网络异常的退避重试次数
MEMORY_EMBED_API_RETRY_BASE_MS=2000 # 可选,重试退避基数(指数增长,上限 60s)
MEMORY_EMBED_API_DELAY_MS=0 # 可选,相邻请求最小间隔;严格限流档(如 5/min)设 12000+
要点:
- API 模式不做本地分词:文档预算截断用字符近似计数(
tokenizer_id = char-approx-v1),不下载任何模型文件。 - API 模型与本地 MiniLM 的向量不可混用:切换模型后
representation_identity_hash变化,必须migrate_embeddings.mjs build/validate/switch重建;建议用--representation single(multiview 证据门阈值是按 MiniLM 384 校准的,不随 API 迁移)。 - 失败语义分层:检索路径(编码失败)快速回退关键词,不等待重试;构建/迁移路径严格失败,绝不出半成品向量。429/5xx/网络异常自动指数退避重试(优先
Retry-After头)。 - 免费档限流:如 PPInfra 免费档 5 请求/分钟,建库必须配
MEMORY_EMBED_API_DELAY_MS=12000+(76 片段 ≈ 16 分钟)。
回填历史片段
如果某段时间跑在降级模式,那期间的片段没有向量(或为空),且当前存在 active embedding generation 时不能直接运行旧回填脚本。D0 会保护性拒绝对 active generation 的写入,避免把不可变快照当作可写目录。
cd <记忆库所在的项目根> # 必须,存储根相对 CWD
node <绝对路径>/backfill_embeddings.mjs
脚本仅在没有 active generation 时回填 legacy .embedding;如果检测到 active generation,会以非零状态退出并提示使用:
node <绝对路径>/migrate_embeddings.mjs build --generation gen_YYYYMMDD_xxx
node <绝对路径>/migrate_embeddings.mjs validate --generation gen_YYYYMMDD_xxx
node <绝对路径>/migrate_embeddings.mjs switch --generation gen_YYYYMMDD_xxx
当前简化模型下,服务器启动不会自动做 orphan reconcile 或后台修复;如果你怀疑 delta/base 状态不一致,直接走手动 rebuild + switch。
Multiview evidence calibration(离线维护者流程)
多窗口 evidence gate 只允许使用通过 development 与 hold-out 验证的、版本化 fixture calibration artifact;不能把 src/search/retriever.ts 中的旧候选阈值当作 production policy。评测工具只读取 bench/datasets/,不会读取或修改任何 memory/ root;它不切 active pointer,也不生成真实 generation。
node bench/run-multiview-eval.mjs calibrate \
--max-fpr 0 \
--min-evidence-recall 1 \
--output <https://github.com/BingoAgentTouch/Personal_MCP/blob/HEAD/candidate-report.json>
# 从 candidate-report.json 提取 candidate_artifact 后,使用 untouched hold-out:
node bench/run-multiview-eval.mjs validate \
--artifact <https://github.com/BingoAgentTouch/Personal_MCP/blob/HEAD/candidate-artifact.json> \
--output <https://github.com/BingoAgentTouch/Personal_MCP/blob/HEAD/holdout-report.json>
node bench/run-multiview-eval.mjs evaluate \
--threshold <validated-threshold> \
--output <https://github.com/BingoAgentTouch/Personal_MCP/blob/HEAD/shadow-report.json>
validate 只有在 hold-out 满足冻结目标时才会输出 validated artifact;失败时报告 no_go,不得手动把 candidate 标为 validated。artifact 绑定 model/tokenizer、recipe、窗口策略、aggregation/raw-similarity mode、development/hold-out dataset hash 和 canonical artifact hash。
新的 multiview generation、activation、delta 写入与 compaction 都必须携带并校验该 immutable validated snapshot;compaction 的 artifact 还必须与 active generation 的 snapshot 完全一致。历史 policy-less multiview generation 仍可读取,并在 search 中保持 summary-only shadow;它们不能重新激活或创建/重置/写入 delta。
本项目采用简单、手动维护优先的落地策略,不把大规模生产级 calibration、长时间 shadow observation 或复杂自动运维作为首次启用的前置条件。真实库首次启用时只需在维护窗口完成 multiview build → validate → switch,保留旧 generation,并用少量真实查询做 sanity check;必要时手动回切旧 generation。fixture artifact 不能冒充真实生产阈值,但不再阻塞首次使用。
Compaction 日常维护流程(手动维护)
日常写入走 delta 增量层(generation 是不可变快照,写入只更新 memory/embedding_delta/)。delta 条目数 D 增长后:① 每次 create_fragment 重写 delta_index.json 的写放大 ≈ O(D²);② 检索多一层校验。compaction 把 base + delta 合并进一个全新 generation 并清空 delta(两层变一层)。
什么时候做:delta 条目数(memory/embedding_delta/delta_index.json 的键数)≥ 100~300、create_fragment/memory_search 明显变慢、或按使用强度定期(如每月/每 200 片段)。全程在维护窗口执行,先备份 memory 根。
cd <记忆库所在的项目根> # 存储根相对 CWD,必须
node <绝对路径>/compact_embeddings.mjs preflight --generation gen_YYYYMMDD_compaction --representation multiview --evidence-policy <https://github.com/BingoAgentTouch/Personal_MCP/blob/HEAD/validated-artifact.json>
node <绝对路径>/compact_embeddings.mjs build --generation gen_YYYYMMDD_compaction
node <绝对路径>/compact_embeddings.mjs validate --generation gen_YYYYMMDD_compaction
node <绝对路径>/compact_embeddings.mjs switch --generation gen_YYYYMMDD_compaction
--representation必须与当前 active generation 一致;multiview 时必须携带 validated evidence policy(run-multiview-eval.mjs validate产出,candidate 不可用)。- preflight 会上 compaction 锁 + 封存 delta + 写 merge contract;validate 不通过不得 switch;异常中断先用
compact_embeddings.mjs unlock确认解锁,不要把 unlock 当通用恢复手段。 - switch 后旧 generation 保留在
previous_generation_id,可手动回切。 - 换模型/换表示请用
migrate_embeddings.mjs,不要用 compaction 顶替。 - 详细判定信号、故障处理与操作前检查清单见《项目维护/memory-mcp-server_compaction维护手册_20260809.md》;archive 恢复场景见下一节。
Compaction archive recovery(维护者手动流程)
此流程只用于恢复一个 C3-3B v2 compaction archive:把 archive 中的 sealed delta 和记录的 base active pointer 原样恢复。它不是通用 JSON 修复、migrate_embeddings.mjs 的 rollback、orphan reconcile,也不是面向日常用户的操作。
当前没有公开的 restore CLI 或 MCP tool;仅维护者可在受控环境中调用内部 API:verifyArchivedDelta(archivePath)、restoreArchivedDelta(archivePath)、recoverDeltaRestoreTransaction()。不要手动复制 archive 文件、改写 embedding_active.json、删除 transaction,或把 compact_embeddings.mjs unlock 当作通用恢复手段。
恢复前按顺序完成:
- 停止 MCP server 和全部写入方,记录绝对 memory root、候选 archive 路径、当前 active pointer、delta manifest/index 摘要、compaction lock,以及
memory/embedding_delta/transactions/restore-*目录。 - 对整个 memory root 做独立的字节级备份;恢复流程不会替代这一份操作前备份。
- 只选择
memory/embedding_delta/archive/<delta-id>-into-<target-generation-id>/下的 archive。它必须包含merge_receipt.json、merge_contract.json、manifest.json、delta_index.json;有 materialized record 时还必须有对应vectors/payload。 - 先执行
verifyArchivedDelta(archivePath),只有返回valid: true才能继续。v1 receipt、任意 payload/receipt/contract/pointer 校验失败都必须停止,不能尝试“修好” archive 后继续。 restoreArchivedDelta(archivePath)会再次拒绝 source inventory 漂移、active pointer 不等于 receipt target pointer、非空的 post-compaction target delta、或已有未完成 restore transaction。满足条件后它才会恢复 archive 的 sealed delta,并最后写入 receipt base pointer。- 成功后确认:active pointer 等于
receipt.pointer_snapshots.base;live delta 的 ID/payload 等于 archive、状态为sealed、兼容性正常;target generation 与 archive 均仍存在;没有遗留restore-*transaction。
正常调用返回 { restored: true, idempotent: false };若已经完全处于 archive 记录的 base+sealed-delta 状态,会返回 { restored: false, idempotent: true }。若出现 recovery_failed: true,保留其 transaction_path、archive、pointer/manifest 快照和错误输出,不要重跑 restore 或手动清理;由维护者先调用一次 recoverDeltaRestoreTransaction()。多个 restore transaction、未知 transaction schema、archive 验证失败或 recovery 再次失败都属于停止并人工检查的条件,不能 force-unlock。
当没有有效 archive、source 已变化或 pointer 状态不满足恢复前提时,走受控 rebuild:
node <绝对路径>/migrate_embeddings.mjs build --generation gen_YYYYMMDD_xxx
node <绝对路径>/migrate_embeddings.mjs validate --generation gen_YYYYMMDD_xxx
node <绝对路径>/migrate_embeddings.mjs switch --generation gen_YYYYMMDD_xxx
对真实 memory root 的复制副本演练、自动启动恢复、公开 restore CLI 和 MCP restore tool 都是后续独立授权事项;本文档不启用它们。
MCP 工具一览
| 工具 | 作用 |
|---|---|
memory_store_turn |
追加一轮对话到 raw(全量原文) |
memory_create_fragment |
把若干轮打包成 L1 片段,自动算 embedding |
memory_create_daily_summary |
写 L2 每日总结 |
memory_upsert_topic |
创建/更新 L3 跨天主题索引 |
memory_search |
语义检索 → 命中 L1 并回填 L2/L3 上下文 |
memory_get_fragment / memory_get_daily / memory_get_topic |
按 ID 读取完整内容 |
memory_list_dates |
列出所有有记录的日期 |
memory_get_raw_turns |
按 exact/range/recent/all 四种互斥模式读取 L0 逐轮原文,可先按 agent_id 过滤 |
memory_consolidate_topics |
检测中文相似 Topic;经审阅后支持 dry-run、整批预检、执行合并与 fragment 回指修复 |
Topic 合并说明
memory_consolidate_topics(action="execute") 会先做整批校验。任一 active 合并组存在 source/target 冲突、非法 fragment ID、路径越界、fragment 缺失或旧 Topic 回指不唯一时,整批返回 validated: false 和 MCP isError: true,不会改写 live 文件。
dry_run: true 使用与正式执行相同的计划和预检,只返回 changes,不写文件。正式执行会更新 target、改写 fragment 回指,并把 source 主题备份到 .trash 后删除。
这是面向个人项目的简化维护模型:优先保证行为直白、出问题后可人工检查;不承诺工业级自动恢复或复杂维护编排。
和宿主自带记忆的分工(避免双写)
很多 Agent 宿主(如 Claude Code)自身已有一套"始终加载进上下文"的轻量记忆。本 MCP 与它职责不同,不要重复存:
- 宿主自带记忆 = 蒸馏后的常驻规则/偏好,需要每个会话都在上下文里、无需检索。少而精,一条一行。
- 本 MCP = 可检索的情节档案:完整对话、任务片段、每日/主题脉络。按需
memory_search取用,不常驻。
一条经验值得记时问自己:它需要每个会话都在场,还是只在我去翻的时候才要? 前者进宿主记忆(一行),后者进本 MCP(带证据的片段)。宿主里的那一行可以引用 MCP 的主题名做下钻,但不要复制正文。
仓库卫生
memory/ 里是原始对话逐字记录。若把本服务器的记忆库放在某个 git 项目内,记得在该项目 .gitignore 忽略它,别把对话原文和向量提交进版本库:
/memory/
记忆重要性评分
新建 fragment 时请保守填写 importance,不要把普通记忆默认评为 0.7 以上:
0.35~0.4:临时、局部、低复用信息0.5:普通可复用记忆0.6~0.7:持续有帮助或明确重要0.8:关键架构、重要约束0.9~1.0:核心事实,错误代价高,应该很少使用
历史 fragment 的 importance 不因这次规则调整而批量改写。P3 Phase 1c 检索时使用 max(importance, earned_importance),earned 只提升有效重要性,不会降低已有权重。
已知取舍
- MiniLM 的相似度整体偏低,0.2–0.35 就是可靠命中,不要按 0.8 的直觉设阈值。
- 检索质量高度依赖写入方给的
task_desc/result_desc/片段浓缩质量——工具负责结构与召回,浓缩得好不好看用的人。 - embedding 文本 =
task_desc + result_desc + turns_text(查询多针对结论,纳入后召回更准)。
开发
npm run dev # tsx 直跑 src/index.ts
npm run check # tsc --noEmit 类型检查
npm run watch # 文件监听(如启用 watcher)
ruvnet/ruflo
amruthpillai/reactive-resume
volcengine/OpenViking
Molunerfinn/PicGo
titanwings/colleague-skill
nocobase/nocobase
Tencent/WeKnora