内容
# markdown-graph-mcp
一个Model Context Protocol服务器,允许Claude直接读写Logseq格式的markdown知识图谱——除了Python本身之外,没有外部依赖,也不需要Logseq应用程序。
与同样范围的[mcp-logseq](https://github.com/ergut/mcp-logseq)项目无关,也不是竞争对手(该项目与Logseq的实时应用程序API进行交互)。本项目纯粹基于文件运行——参见[docs/adr/0001-file-based-positioning.md](docs/adr/0001-file-based-positioning.md)。
## 功能
指向一个或多个Logseq图谱目录,Claude获得了14种工具来处理您的笔记:捕获思绪到日记,读取和写入页面,按内容或属性搜索,列出最近的条目,维护页面元数据,并在图谱之间解析实体引用和反向链接——所有这些都针对相同的 `.md` 文件,Logseq会读取。
| 工具 | 功能 |
|------|-------------|
| `list_graphs` | 显示所有配置的图谱并确认路径存在 |
| `capture_to_journal` | 将要点追加到日记页面——在Logseq打开时调用是安全的 |
| `get_journal` | 读取日记页面(默认为今天) |
| `read_page` | 按标题读取任何页面,使用 `/` 进行命名空间分隔 |
| `write_page` | 写入或覆盖页面的全部内容——在覆盖之前备份以前的版本 |
| `delete_page` | 软删除页面到 `.trash/` ——永不硬删除 |
| `search_content` | 跨页面和日记的全文关键字搜索 |
| `search_pages` | 按属性值过滤页面,返回选定的字段 |
| `list_pages` | 列出页面标题,可选地按命名空间前缀过滤 |
| `list_recent_journals` | 列出N个最近的日记条目,附带预览 |
| `set_property` | 在页面上添加或更新单个属性 |
| `get_backlinks` | 查找每个 `[[PageName]]` 对页面的引用,跨所有配置的图谱 |
| `find_entity` | 按标题或 `mistoria-reference` 值查找实体,跨所有配置的图谱 |
| `list_entities` | 列出给定类型的每个实体(人/地点/物体/事件/章节),跨图谱 |
## 快速入门
**要求:** Python 3.8+,[Claude Code](https://claude.ai/code)
```bash
git clone https://github.com/pburney/markdown-graph-mcp.git
cd markdown-graph-mcp
cp config.example.json config.json
```
编辑 `config.json` 以指向您的Logseq图谱目录(参见 [配置](#配置))。
为测试运行器创建虚拟环境(服务器本身不需要包):
```bash
python3 -m venv .venv
.venv/bin/pip install pytest
```
注册Claude Code:
```bash
claude mcp add --scope user markdown-graph -- /path/to/markdown-graph-mcp/.venv/bin/python /path/to/markdown-graph-mcp/server.py
```
验证连接:
```bash
claude mcp list
# markdown-graph: ... — ✔ Connected
```
打开Claude Code会话并试用:
```
list my logseq graphs
add this to my journal: MCP server is working
```
### 其他MCP客户端
任何通过stdio(ChatGPT,Gemini,Cursor等)与MCP通信的客户端都可以运行相同的服务器——指向Python解释器和 `server.py`。大多数客户端使用配置文件,其中包含 `mcpServers` 块,例如:
```json
{
"mcpServers": {
"markdown-graph": {
"command": "/path/to/markdown-graph-mcp/.venv/bin/python",
"args": ["/path/to/markdown-graph-mcp/server.py"]
}
}
}
```
不需要API密钥或网络访问——服务器只读取/写入 `config.json` 中列出的本地文件系统路径。
## 配置
`config.json` 将简短的图谱名称映射到文件系统路径:
```json
{
"default_graph": "notes",
"graphs": {
"notes": "/Users/you/Documents/notes",
"work": "/Users/you/Documents/work-kb"
}
}
```
每个键成为您(或Claude)在工具调用中使用的 `graph` 参数。`default_graph` 在未提供 `graph` 参数时使用。
`config.json` 被git忽略——复制 `config.example.json` 即可开始。您的图谱数据永远不会离开您的机器。
### 只读图谱
图谱条目可以是纯路径字符串(可写,默认)或具有 `read_only: true` 的对象:
```json
{
"graphs": {
"notes": "/Users/you/Documents/notes",
"shared": {"path": "/Users/you/Documents/shared-kb", "read_only": true}
}
}
```
`capture_to_journal`、`write_page` 和 `set_property` 在对只读图谱调用时返回错误并且不修改任何内容。在与不应写入的协作者共享图谱时很有用。顶级 `"read_only": true` 强制所有配置的图谱只读,无论每个图谱的设置如何——对于一个锁定的“查看器”实例很有用。
## 实体约定
代表实体的页面(人,地点,物体,事件或章节)可以携带 `mistoria-reference::` 属性。其第一个冒号段是类型;其后的一切是一个类型特定的键——在类型之间没有固定的形状。不需要重命名或命名空间;页面保留其自然标题。
```
icon:: 🏡
mistoria-reference:: place:90805:Poppy-Street:2308
```
`find_entity`/`list_entities`/`get_backlinks` 无论页面是否已采用此约定,都起作用——没有 `mistoria-reference::` 的页面仍然作为相关/近似匹配按标题显示,因此无需预先迁移任何内容。参见 [docs/adr/0002-entity-reference-convention.md](docs/adr/0002-entity-reference-convention.md) 以获取完整的理由。
## 工具参考
所有工具都接受可选的 `graph` 参数(默认为 `default_graph`)。页面标题中的命名空间分隔符使用 `/` ——服务器在内部处理Logseq的三下划线文件名编码。
### capture_to_journal
```
graph — 图谱名称(可选)
content — 要追加的文本;不以 "- " 开头的行会自动添加前缀作为项目符号
date — YYYY-MM-DD(可选,默认为今天)
```
以追加模式将内容追加到日记文件中——在Logseq打开并监视同一文件时调用是安全的。
### read_page / write_page
```
title — 页面标题,例如 "Projects/Website Rewrite"
content — (仅 write_page)完整的页面内容,包括任何属性块
mode — (仅 write_page)"overwrite"(默认)或 "create"(如果页面已经存在,则失败)
graph — 图谱名称(可选)
```
`write_page` 默认使用 `mode="overwrite"` 替换整个文件——当您想要确保不会覆盖现有内容时,请改用 `mode="create"`。请使用 `set_property` 进行有针对性的属性更新。对只读图谱的写入操作被阻止。当 `mode="overwrite"` 替换现有页面时,之前的内容会首先备份到 `.trash/`(参见下面的 `delete_page`)——覆盖操作永远不会是一扇单向门。
### delete_page
```
title — 页面标题,例如 "Projects/Old Draft"
graph — 图谱名称(可选)
```
软删除:将页面移动到 `<graph>/.trash/<timestamp>-<filename>.md` 而不是删除它。被删除的页面会自动从其他所有工具的读取/搜索中排除,因为 `.trash/` 是一个点目录,而所有工具都已经跳过点名前缀的路径组件。`.trash/` 中的内容不会自动清除——请在您确定不再需要时手动清理。 对只读图谱的写入操作被阻止。要在图谱之间移动页面,请使用 `read_page` → `write_page(mode="create")` 到目标 → 在源上 `delete_page`,在删除原始文件之前验证副本。
### search_content
```
query — 关键字或短语(不区分大小写的子字符串匹配)
graph — 图谱名称(可选,省略则搜索所有配置的图谱)
include_journals — 也搜索日记条目(默认:true)
context_lines — 每个匹配项周围的上下文行数(默认:2)
```
跨页面内容和日记条目的全文搜索。返回匹配的文件,附带行号和周围的上下文。一次搜索所有图谱是默认行为——当您不知道哪个图谱包含某个笔记时很有用。
### search_pages
```
filters — "key=value" 字符串列表,逻辑运算符为 AND
例如 ["type=#Project", "status=#Active"]
return_props — 结果中要包含的属性名称列表
"name" 返回页面标题词干,"file" 返回完整路径
graph — 图谱名称(可选)
```
属性值会规范化以便于比较:`[[PageRef]]` 包装器和 `#` 前缀会被剥离,匹配不区分大小写。
### list_pages
```
prefix — 可选的命名空间前缀,例如 "Projects"
graph — 图谱名称(可选)
```
### list_recent_journals
```
n — 要返回的条目数量(默认:7)
graph — 图谱名称(可选)
```
返回每个条目的日期、文件名和简短预览。
### set_property
```
title — 页面标题
key — 属性键,例如 "status"
value — 属性值,例如 "#Complete"
graph — 图谱名称(可选)
```
如果属性不存在,则添加;如果已经存在,则替换。插入在第一个项目符号之前,或追加到属性块中。以原子方式写入。
### get_backlinks
```
title — 目标页面标题,例如 "Poppy Street"
graph — 图谱名称(可选,省略则搜索所有配置的图谱)
include_journals — 也搜索日记条目(默认:true)
context_lines — 每个匹配项周围的上下文行数(默认:1)
```
查找通过 `[[title]]` 维基链接语法链接到 `title` 的每个页面或日记条目。目标不必是每个搜索图谱中的一个页面——它只需要被引用。
### find_entity
```
name — 实体名称,或 mistoria-reference 值/片段,例如 "Carol" 或 "place:90805"
type — 可选的实体类型过滤器:person, place, object, event, 或 chapter
graph — 图谱名称(可选,省略则检查所有配置的图谱)
```
报告确切的 `mistoria-reference::` 匹配项,以及相关页面,这些页面尚未携带引用——在创建新实体页面之前使用,以避免在图谱中重复相同的person/place/object。
### list_entities
```
type — 要列出的实体类型:person, place, object, event, 或 chapter
graph — 图谱名称(可选,省略则搜索所有配置的图谱)
filter_text — 可选的子字符串,用于匹配 mistoria-reference 值
```
枚举给定类型的每个实体。`filter_text` 仅进行子字符串匹配——不进行地理编码或邻近搜索。
## 开发
```bash
.venv/bin/pytest tests/ -v
```
两个文件中有119个测试:
- `tests/test_logseq_graphs.py` — 所有实用函数的单元测试,使用 `tmp_path` 中的最小化虚拟图谱
- `tests/test_server.py` — 集成测试,通过子进程管道在相同的fixture图谱上运行完整的MCP协议
服务器没有运行时依赖—— `pytest` 是 `.venv` 中唯一的包。
## 技术栈
| 层 | 选择 | 原因 |
|-------|--------|-----|
| 服务器 | 纯Python标准库 | 无需安装或版本固定的包;在任何Python环境中都可运行 |
| 协议 | JSON-RPC over stdio | MCP的stdio传输,直接实现——无需 `mcp` SDK 或 `anyio` |
| 图谱访问 | `.md` 文件的读写 | Logseq将所有内容存储为纯markdown;无需Logseq进程或API |
| 测试 | pytest | 隔离的 `tmp_path` fixture图谱;用于端到端覆盖的子进程管道 |
## 许可证
MIT — Copyright (c) 2026 Paul Burney / Burney Web Services