内容
# 脑图服务器
MCP 服务器将 Obsidian 第二大脑保险库暴露给任何支持 MCP 的客户端(Claude Code、Claude Desktop、OpenClaw、Cursor 等)。
MCP 是**自我文档化**的:教义、种类目录和工作流程配方都通过工具提供。不需要客户端技能或 CLAUDE.md 警告。
## 安装
```bash
cd ~/github/skalas/brain-mcp
uv sync
```
## 运行(标准输入输出,用于本地客户端)
```bash
VAULT_PATH="/Users/skalas/Documents/Obsidian Vault" uv run brain-mcp
```
## 暴露的工具
### 搜索和读取
| 工具 | 用途 |
|---|---|
| `search_notes(query, type?, updated_since?, k)` | 在 `notes/`、`meetings/`、`conversations/`、`daily/` 中进行子字符串搜索 |
| `search_semantic(query, k, type?)` | 使用本地 `multilingual-e5-large` 嵌入向量对笔记部分进行向量搜索 |
| `search_hybrid(query, k, type?)` | `search_notes` 和 `search_semantic` 的 reciprocal-rank 融合 |
| `read_note(id)` | 读取完整的笔记内容和解析的前置信息 |
| `list_index(name)` | 转储一个 MOC(`people`、`projects`、`topics`、`timeline`、`tags`、`README`) |
### 教义和工作流程
| 工具 | 用途 |
|---|---|
| `get_doctrine()` | 返回 `_system/CLAUDE.md` — 保险库模式、写入规则、语言规范。在第一次写入之前,每个会话调用一次。 |
| `list_workflows()` | `_system/recipes/` 下的多步骤工作流程配方目录 |
| `get_workflow(name)` | 工作流程配方的完整内容(例如 `conversation-append-pass`、`function-first-project-rewrite`) |
### 结构化类型
保险库通过 `_system/recipes/<kind>.md` 下的配方文件声明**类型** — 具有自己的字段模式和行为的实体类型。MCP 在启动时发现它们,并动态公开每个类型的工具。
| 工具 | 用途 |
|---|---|
| `list_kinds()` | 已注册的类型目录(目前为 `book`、`recipe`、`task`) |
| `get_recipe(kind)` | 类型的完整说明:必填字段、富集、副作用、主体形状 |
| `add_<kind>(data, body)` | 创建一个新实体,验证数据是否符合配方模式并运行声明的副作用。 |
| `find_<kind>(where?)` | 筛选 `kind` 条目(仅存档类类型) |
| `update_<kind>(id, patch)` | 修补现有实体的字段(生活列表类型:`task`) |
| `complete_<kind>(id)` | 将状态翻转为第一个终端状态(生活列表类型) |
| `list_<kind>(where?)` | 列出条目;默认情况下终端状态被排除(生活列表类型) |
类型工具在其描述中携带模式 — 必填字段、选填字段、有效 `state` 值、允许的筛选键。不需要客户端配置。
### 非结构化写入
| 工具 | 用途 |
|---|---|
| `append_section(id, body, date?)` | 在现有笔记中追加带有日期的 H2 部分 + 更新 `updated:` + 重新索引 |
| `create_note(type, slug, frontmatter, body)` | 在 `notes/` 中创建新的未类型化实体笔记(人/项目/主题/引用)+ 重新索引 |
| `create_dated(kind, slug, body, frontmatter?, date?)` | 在 `daily/`、`meetings/` 或 `conversations/` 中创建新文件 + 重新索引 |
对于结构化实体,更倾向于使用 `add_<kind>` — 它强制执行配方合同。
### 维护
| 工具 | 用途 |
|---|---|
| `reindex_vectors(full?, note_id?)` | 重建向量索引(每个笔记、完整遍历或首次启动引导) |
## 配方形状(声明新类型)
在 `_system/recipes/<kind>.md` 下放置一个 markdown 文件,其前置信息如下:
```yaml
---
kind: book
class: archive # 或 living-list
description: 简短的人类描述
target:
type: ref # 结果笔记的前置信息类型(person|project|topic|ref)
slug_pattern: "book-{title-kebab}"
fields:
required: [title, author]
optional: [year, rating, themes]
retrieval:
filters: [author, year, rating]
side_effects:
- append_to: notes/books.md
# living-list only:
# states: [open, in-progress, done, snoozed]
# default_state: open
# terminal_states: [done]
---
# 配方正文 — 模型的说明
```
重启 MCP 以获取新的类型。动态工具(`add_<kind>`、`find_<kind>` 等)会自动出现。
## 向量搜索
通过 `sqlite-vec` + `fastembed` 进行本地语义搜索(`intfloat/multilingual-e5-large`,1024 维,多语言 ES/EN)。
- 向量存储在 `<repo>/.vectors.db`(gitignored — 每个机器,重新生成 `reindex_vectors(full=True)`)。覆盖 `BRAIN_VECTOR_DB`。
- 模型默认为 `intfloat/multilingual-e5-large`(覆盖 `BRAIN_EMBED_MODEL` / `BRAIN_EMBED_DIM`)。
- 分块按 H2 部分进行;前置部分包括标题/别名/标签,以便前置信息可搜索。
- 写入会自动重新嵌入受影响的笔记;仅更改内容哈希的部分会重新编码。
- 首次启动引导:安装后调用 `reindex_vectors()` 一次 — 遍历保险库并嵌入所有内容。
### 命令行界面
```bash
# 仅当数据库为空时嵌入保险库(幂等)。
VAULT_PATH="…" uv run brain-reindex --bootstrap
# 遍历每个笔记(并修剪已删除笔记的块)。
VAULT_PATH="…" uv run brain-reindex --full
# 通过 ID 重新索引单个笔记。
VAULT_PATH="…" uv run brain-reindex --note kavak-pricing-q1
# 删除向量存储并从头开始嵌入。
# 在嵌入模型合并/维度更改后,每个机器运行一次
# (例如,fastembed 从 CLS 切换到平均合并)。
VAULT_PATH="…" uv run brain-reindex --rebuild
```
## 防护措施
- 没有删除工具。删除仍然是手动的。
- 没有重命名工具。重命名会破坏 wikilinks(按文件名茎)。
- 在 `_system/`、`_index/`、`_.obsidian/` 中写入被阻止。
- 每次写入都会运行 `_system/scripts/reindex.sh`。
## 连接到客户端
**Claude Code** (推荐,用户范围,因此从任何项目都可访问):
```bash
claude mcp add brain \
--scope user \
-e VAULT_PATH="$HOME/Documents/Obsidian Vault" \
-- uv run --directory ~/github/skalas/brain-mcp brain-mcp
```
**Claude Desktop**:编辑 `~/Library/Application Support/Claude/claude_desktop_config.json`:
```json
{
"mcpServers": {
"brain": {
"command": "uv",
"args": ["run", "--directory", "/Users/<you>/github/skalas/brain-mcp", "brain-mcp"],
"env": { "VAULT_PATH": "/Users/<you>/Documents/Obsidian Vault" }
}
}
}
```
**OpenClaw / Cursor / 其他**:相同的标准输入输出命令 + `VAULT_PATH` 环境变量。任何 MCP 1.x 兼容的客户端都应该有效。
## 架构
```
brain_mcp/
├── server.py FastMCP 工具注册。通用工具 + 动态每个类型工具。
├── vault.py 领域层:笔记解析、路径解析、搜索、教义/工作流程读取。
├── writes.py 应用层:append_section、create_note、create_dated。每次写入重新索引。
├── kinds.py 配方注册表:解析 _system/recipes/*.md 为 Kind 对象。
├── kind_ops.py 每个类型的 add/find/update/complete/list。副作用运行器。
├── vectors.py 本地语义搜索索引(sqlite-vec + fastembed)。
└── cli.py brain-reindex 命令行界面。
```
干净的架构:`kinds`/`vault` 是纯领域;`kind_ops`/`writes` 是应用;`server` 是表示;`vectors` 是基础设施。
## 测试
```sh
uv pip install -e '.[dev]'
uv run pytest
```
测试运行在临时保险库上(`tests/conftest.py` 在临时目录下构建并指向 `VAULT_PATH`/`BRAIN_VECTOR_DB`)。它们涵盖解析、路径遍历/只读防护、链接图、连接查询、中心性、类型/_slug 和写入流程 — 并且从不加载嵌入模型,因此整个套件在不到一秒的时间内运行。