secondbrain-mcp
# secondbrain-mcp
> Local-first personal knowledge base as MCP: Markdown vault + hybrid RAG retrieval + a safety-first gateway with hash locks, audit trail, privacy zones and rollback — so that AI agents can *use* your knowledge base without being able to wreck it.
> 状态:✅ **v0.2** —— 14 个工具 · 单元+e2e 门禁全绿(含真实 stdio 协议端到端)· CI 门禁全过(semantic 门在 CI 口径外,见评测) | License: MIT
## 为什么做这个
2026 年的 AI agent 已经很会「读」,但很少被允许「写」用户的长期知识库——因为写没有安全边界。
本项目把一套**在个人生产环境真实运行**的知识库网关重写为单一 Python 核心,核心是四件事:
1. **哈希锁写入**:所有更新必须携带 `expected_hash`,且在锁内复验;冲突即拒绝并给出恢复指令。
2. **无删除设计**:归档 = 移动到 Archive 区并生成可回滚清单,清单在移动**之前**写入。
3. **隐私分区**:`95_Private` 在读取、写入、索引、检索四层拒绝,分区判定大小写无关。
4. **全量审计**:intent 与 outcome 分开记录,每条带前一条的哈希,形成可校验的链。
## 功能
- [x] MCP server:14 个窄工具(read / list / search / index / review / create / append / patch / meta / move / archive / restore / archive_list_batches)
- [x] 混合检索:BM25 倒排 + 向量余弦 + RRF 融合,两道防噪门禁
- [x] 增量索引:`embed_state` 显式跟踪,失败在下一轮自动重试
- [x] 模型指纹:换模型强制重建向量,杜绝向量空间混用
- [x] 正文编辑:`note_patch` 两阶段确认,先出 diff 再落盘
- [x] 隐私分区与待确认队列
- [x] 合成演示知识库(demo vault,无任何真实个人内容)
- [x] 单元测试 + 对抗性测试 + MCP stdio 端到端 + 可失败的检索门禁
- [x] 部署健康检查(暂存库跑全契约 + live 索引只读快照探针)
## 文档
- [架构总览](docs/architecture.md) — 分层、分区表、索引结构、检索设计
- [评测方法](docs/evaluation.md) — 为什么旧评测报 1.00 而真实只有 60%,以及现在的五道门禁
- [威胁模型](docs/threat-model.md) — 防什么、不防什么、已知限制
- [迁移记录](docs/migration.md) — 从 Node 网关迁到 Python 核心的行为变化与回滚方式
- [脱敏抽取计划](docs/extract-plan.md)
- [路线图](docs/roadmap.md)
## 快速开始
要求 Python 3.10+。两档安装:
```bash
git clone https://github.com/stone1524/secondbrain-mcp
cd secondbrain-mcp
pip install -e ".[semantic]" # 完整混合检索(含 numpy + fastembed,推荐)
pip install -e . # 纯词法模式(无需 numpy,mode=hybrid 自动降级并在返回中说明原因)
```
**试用合成 demo vault**(不接你自己的数据,仓库自带、全部为合成内容):
```bash
secondbrain-mcp # 不设 SB_VAULT_ROOT 时默认服务仓库内 demo-vault/
```
**接入自己的知识库 / MCP 客户端**(Claude Code、Cursor 等任何支持 MCP 的客户端):
```json
{
"mcpServers": {
"secondbrain": {
"command": "python",
"args": ["-m", "secondbrain_mcp.adapters.mcp_stdio"],
"env": {
"SB_VAULT_ROOT": "C:/path/to/your/markdown-vault",
"SB_STATE_ROOT": "C:/path/to/state",
"SB_AGENT_LABEL": "claude"
}
}
}
}
```
环境变量:
| 变量 | 默认 | 说明 |
|---|---|---|
| `SB_VAULT_ROOT` | 仓库内 `demo-vault/`(按安装位置解析;wheel 安装找不到捆绑目录时回退 `./demo-vault`) | vault 目录 |
| `SB_STATE_ROOT` | `<vault>/.secondbrain` | 索引、审计、锁的根目录 |
| `SB_RAG_DB` | `<state>/index.db` | 索引库路径 |
| `SB_AGENT_LABEL` | 无 | 审计归因标签,多客户端共用时区分写入者 |
| `SB_RAG_SEMANTIC` | `1` | 设为 `0` 走纯词法(纯词法模式无需 numpy) |
| `SB_RAG_MODEL` | `BAAI/bge-small-zh-v1.5` | 嵌入模型 |
| `SB_RAG_MODEL_CACHE` | 无 | 模型缓存目录(离线场景必填,直通 fastembed) |
| `SB_RAG_EMBED_BATCH` | `0`(后端默认) | 嵌入批大小,直通 fastembed |
| `SB_SEMANTIC_FLOOR` | `0.55` | 语义命中相似度下限(查询与笔记同语言时) |
| `SB_SEMANTIC_FLOOR_CROSS` | `0.42` | 跨中英语言对的语义命中下限(zh 调优模型跨语言余弦偏低,按语言对单独校准) |
| `SB_SEMANTIC_MIN_TOKENS` | `20` | 语义命中最小 token 数,按整篇笔记计量(命中分块或全篇分块合计过线均可) |
索引在首次 `search` 时按需自动构建或修复(大库首次调用会慢);`index_rebuild` 用于手动/强制重建(换嵌入模型后加 `force=true`)。`note_read` 才是取证。
## 安全模型
- **写**:`note_create` 默认只进 inbox 且重名加后缀(不覆盖);`overwrite=true` 提供带 `expected_hash` 哈希锁的受控覆盖(锁内复验);`note_append` / `note_patch` / `note_meta` / `note_move` 全部要求 `expected_hash`,并在文件锁内复验
- **删**:不存在。唯一移除路径是带批次回滚清单的归档,restore 可整批或按条恢复
- **隐私**:私有前缀在读、写目的地、索引、搜索四层拒绝,且大小写无关;泄漏探针在单元与线上两层测试
- **审计**:每次写落 `intent` 与 `outcome` 两条,带哈希链;`AuditLog.verify()` 可校验
- **内容即数据**:所有读取与检索结果带 `trust: untrusted_note`,提示调用方不得把笔记内容当作指令
## 评测
```bash
python -m secondbrain_mcp.eval.run --cases eval/cases-dev.json --semantic
```
五道门禁,每一道都能真的失败:`recall@5 ≥ 0.85`(标题派生用例口径;零重叠探针 `no_shared_term` 由下述 semantic 门与 by_category 读数单独承担,headline recall 仍计全量)、`semantic rank-1 wins ≥ 1`(仅在 `--semantic` 下生效,词法模式报告为 not-applicable 而不是静默通过;CI 无模型缓存、从不跑 `--semantic`,向量通道在 CI 口径中为 uncovered)、`null vectors == 0`、`privacy leakage == 0`(读侧四种拼写探测)、`index_side_leak == 0`(直接读库,抓读侧门禁看不见的入库泄漏)。CI 会先建 demo 索引,再跑门禁与部署契约检查,并再生成 `eval/cases-dev.json` 与提交版本比对(用例文件不得滞后 policy 变更)。
当前结果与旧系统的对照见 [docs/evaluation.md](docs/evaluation.md)。
## License
MIT
TDQS
Scored across 13 tools
Most tools are clearly separated by action and resource, and the archive/restore group is unambiguous. However, search_notes and rag_search both offer retrieval over notes, and list_notes' substring filter partially overlaps with search_notes, so an agent could occasionally pick the wrong one.
Tool names follow a consistent snake_case verb_noun pattern: read_note, list_notes, move_note, append_note, update_metadata, archive_notes, restore_archive. The rag_* tools use a domain prefix but still read predictably, so the naming convention is coherent throughout.
Thirteen tools is a well-scoped count for a note-management server covering capture, retrieval, organization, metadata, and archiving. Each tool has a clear role and none feel redundant or extraneous.
The core note lifecycle is well covered: create via inbox, read, list, search, move, append, metadata update, archive, and restore. The main gaps are the lack of a direct content-replacement operation and a permanent delete/purge, though append and archive/restore mitigate most practical needs.