内容
# Wiki Explorer V2
MCP 服务器用于 Wiki 管理,支持 PostgreSQL。具备语义搜索、向量嵌入、写操作、自动反向链接、访问跟踪和版本历史等功能。
## 架构
```
┌─────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ MCP 客户端 │────▶│ wiki-v2 服务器 │────▶│ PostgreSQL 16 │
│ (Claude 代码)│◀────│ (Node.js) │◀────│ + pgvector │
└─────────────┘ └──────────────────┘ └─────────────────┘
│
┌──────┴──────┐
│ wiki-cron │ 每日自动重新链接于凌晨3点
└─────────────┘
```
### 代码架构
- **`src/index.js`** — MCP 服务器控制器(工具注册、请求路由)
- **`src/transport.js`** — 传输层(本地_stdio,远程_HTTP)
- **`src/service.js`** — 业务逻辑(验证、数据转换、编排)
- **`src/db.js`** — 数据库查询和连接池
- **`src/migrate.js`** — 前向迁移运行器(启动时自动运行)
- **`src/embedding.js`** — 延迟加载的 `@xenova/transformers` 嵌入模型
- **`src/import.js`** / **`src/export.js`** — Markdown 导入/导出逻辑
## 快速开始
### 先决条件
- [Docker](https://docs.docker.com/get-docker/) (包含 Docker Compose)
- **Windows 用户:** 从 WSL2 运行所有内容 — Docker Desktop on Windows 要求使用 WSL2
### 1. 运行启动脚本
```bash
./start.sh
```
此脚本处理首次运行和重启时的所有操作:
- 检测您的 Docker Compose 版本(`docker compose` vs `docker-compose`)
- 关闭并重新启动容器
- 如果缺少,在容器内安装 `node_modules` (无需本地 Node.js)
- 打印容器健康状况、Wiki 实例计数和您的 MCP 配置路径
启动的三个容器:
- **wiki-db** — PostgreSQL 16 with pgvector (端口 5433)
- **wiki-server** — Node.js MCP 服务器(卷挂载以便实时编辑)
- **wiki-cron** — 每日自动重新链接作业于凌晨3点
`sql/` 中的迁移在首次启动时自动应用。初始设置后,容器在机器重启时自动重新启动 — 您只需在手动 `docker compose down` 或拉取更新后再次运行 `start.sh`。
### 2. 将 MCP 配置添加到 Claude Code
打开 `~/.claude.json` (由 `start.sh` 打印),并在 `mcpServers` 下添加:
```json
{
"mcpServers": {
"wiki": {
"command": "docker",
"args": ["exec", "-i", "wiki-v2-server", "node", "src/index.js"]
}
}
}
```
保存后重启 Claude Code。Wiki 工具将自动出现。
### 3. 导入现有的 Markdown 文件(可选)
将带有 YAML 前置信息的 Markdown 文件放入 `import/staging/`,然后使用 Claude Code 中的 `import` 工具,或运行:
```bash
docker exec wiki-v2-server node scripts/import-wiki-to-db.js
```
## 代理设置(Claude Code)
在 `~/.claude.json` 下的 `mcpServers` 中添加。服务器在 Docker 容器内运行 — 通过 `docker exec` (或 SSH 如果主机是远程的)连接。
### 本地(docker exec)
```json
{
"mcpServers": {
"wiki": {
"command": "docker",
"args": ["exec", "-i", "wiki-v2-server", "node", "src/index.js"]
}
}
}
```
### 远程(SSH + docker exec)
```json
{
"mcpServers": {
"wiki": {
"command": "ssh",
"args": [
"-T",
"-o",
"StrictHostKeyChecking=no",
"user@host",
"docker exec -i wiki-v2-server node src/index.js"
]
}
}
}
```
### 双服务器模式(固定 Wiki 实例)
将同一个服务器注册两次,名称不同 — 一个没有 `WIKI_ID` (代理必须传递),一个强制通过 env 传递 `WIKI_ID`(代理从不传递)。这允许您为特定 Wiki 实例指定一个命名工具集:
```json
{
"mcpServers": {
"wiki": {
"command": "ssh",
"args": [
"-T",
"-o",
"StrictHostKeyChecking=no",
"user@host",
"docker exec -i wiki-v2-server node src/index.js"
]
},
"memory": {
"command": "ssh",
"args": [
"-T",
"-o",
"StrictHostKeyChecking=no",
"user@host",
"docker exec -i -e WIKI_ID=memory wiki-v2-server node src/index.js"
]
}
}
}
```
- `wiki` — 通用;代理每次调用选择 Wiki 实例
- `memory` — 始终针对 `memory` Wiki;`wikiId` 在所有工具模式中缺失,因此代理无需传递它
此模式可扩展到任意数量的固定实例(`notes`、`docs`等),通过添加更多指向同一容器的条目,并使用不同的 `WIKI_ID` 值。
### 远程托管(HTTP 传输)
设置 `TRANSPORT=http` 以通过 HTTP 而不是 stdio 公开服务器。在 HTTP 模式下,每个客户端都使用从管理员 TUI 生成的 API 密钥进行身份验证。每个密钥映射到其自己的隔离 PostgreSQL 数据库 — 客户端无法访问彼此的数据。
```bash
# 在本地启动 HTTP 传输
TRANSPORT=http PORT=3000 DB_HOST=localhost DB_PORT=5433 node src/index.js
```
或在 Docker 中:
```yml
# docker-compose 覆盖示例
services:
wiki-server-http:
build: .
container_name: wiki-v2-server-http
environment:
DB_HOST: wiki-db
TRANSPORT: http
PORT: 3000
ports:
- '3000:3000'
command: node src/index.js
depends_on:
wiki-db:
condition: service_healthy
```
#### 客户端 MCP 配置(Claude Code)
客户端使用管理员颁发的 API 密钥将服务器添加到其 `~/.claude.json` 中:
```json
{
"mcpServers": {
"wiki": {
"transport": "http",
"url": "https://your-host.example.com",
"headers": {
"Authorization": "Bearer wk_v2_..."
}
}
}
}
```
用创建时显示的纯密钥替换 `wk_v2_...`。密钥确定客户端的 Wiki 数据存储在哪个数据库中 — 无需 `wikiId` 参数,服务器会自动从密钥中解析。
健康检查端点(`GET /health`)始终开放,无需身份验证。所有其他端点都需要有效的 bearer token。
#### 速率限制
HTTP 模式应用每个 IP 的速率限制:每分钟 10 次身份验证失败尝试,然后返回 `429 Too Many Requests`。在运行反向代理时,设置 `TRUST_PROXY=true` 以便从 `X-Forwarded-For` 读取真实客户端 IP 而不是代理的套接字地址。
## MCP 工具
### 发现
| 工具 | 描述 |
| ---------- | -------------------------------------------------------------------------------------------------------------- |
| `get_info` | 获取实例元数据和章节计数 |
| `browse` | 按父主题分组浏览章节;支持 `limit` 和 `offset` 进行分页 |
| `list` | 列出所有章节,可选按 `wikiId` 过滤;支持 `limit` 和 `offset`;包括标签和 linkCount |
### 阅读
| 工具 | 描述 |
| -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `search` | 按含义进行语义搜索(如果嵌入不可用,则回退到关键字);支持 `parent` 过滤和 `offset` 分页;结果包括内容片段 |
| `get_section` | 获取具有内容分页的单个章节;可选 `includeBacklinks`;当反向链接分页时返回 `backlinksHasMore` |
| `get_sections` | 批量检索多个章节(一次最多 20 个) |
### 编写
| 工具 | 描述 |
| ----------------- | --------------------------------------------------------------------------------------------------- |
| `create` | 创建一个没有父级的根级章节(新实例的入口点) |
| `create_sections` | 批量创建多个章节;所有章节相互链接后创建(最多 20 个) |
| `update_sections` | 批量更新现有章节(自动重新生成嵌入,自动跟踪历史) |
| `delete_section` | 删除一个章节及其反向链接(先运行 `get_backlinks`) |
### 导入/导出
| 工具 | 描述 |
| -------- | ------------------------------------------------------------------------ |
| `import` | 从 `import/staging/` 导入 Markdown 文件(自动生成嵌入) |
| `export` | 将章节导出到 Markdown 文件 |
### 管理
| 工具 | 描述 |
| --------------------- | ----------------------------------------------------------------------------------- |
| `get_backlinks` | 查找链接到给定章节的章节;接受 `limit`,返回 `hasMore` |
| `validate` | 查找空章节、孤立章节和未链接章节;返回计数和 `healthy` 布尔值 |
| `get_section_history` | 查看章节的编辑历史(可选 `wikiId`) |
| `auto_link_sections` | 通过嵌入相似性自动链接章节(后台作业;返回 `jobId`) |
| `get_job_status` | 通过 `jobId` 轮询后台作业的状态 |
### `auto_link_sections` 选项
| 选项 | 描述 |
| --------------- | ------------------------------------------------------- |
| `override` | 重新链接已经有链接的章节 |
| `reembed` | 在链接前重新生成嵌入 |
| `parallel` | 并行处理章节(默认:true) |
| `minSimilarity` | 最小余弦相似性阈值(0-1,默认 0.1) |
| `maxLinks` | 每个章节的最大相关链接数(默认 4) |
此工具在后台运行,并立即返回状态消息。cron 作业还会在每天凌晨 3 点通过 `wiki-cron` 容器运行它。
## 脚本
| 脚本 | 目的 |
| --------------------------------- | ------------------------------------------------------------------------- |
| `./start.sh` | 启动所有容器,安装依赖(如果需要),打印状态和 MCP 配置 |
| `npm start` | 启动 MCP 服务器(在 Docker 外部) |
| `npm run dev` | 启动调试用的 MCP 检查器 |
| `npm run import` | 从 `import/staging/` 导入 Markdown |
| `npm run export` | 将所有 Wiki 导出到 `export/` 目录 |
| `npm run db:up` | 通过 docker-compose 启动数据库 |
| `npm run db:down` | 通过 docker-compose 关闭数据库 |
| `npm run lint` / `lint:fix` | 运行 ESLint |
| `npm run format` / `format:check` | 运行 Prettier |
| `npm run check` | 运行 lint + format 检查 |
| `npm run fix` | 运行 lint:fix + format |
| `npm run admin` | 打开管理员 TUI 仪表盘(blessed) |
| `npm test` | 运行完整测试套件(单元 + 集成) |
| `npm run test:unit` | 仅运行单元测试 |
| `npm run test:integration` | 仅运行集成测试(需要 DB) |
### 导入目录结构
```
import/
├── staging/ ← 将 Markdown 文件放在此处导入
├── success/ ← 成功导入的文件将移动到此处
└── fail/ ← 导入失败的文件将移动到此处,附带错误信息
```
`staging/` 中的文件必须具有 YAML 前置信息,包含 `key`、`parent` 和 `title`。第一个章节的前置信息中的 `wiki_id` 字段覆盖从文件名派生的 Wiki ID — 如果文件名与预期的 Wiki 实例不匹配,则此功能很有用。
### 嵌入
嵌入在每次写入操作(创建、更新、导入)时自动生成。无需手动播种。
使用 `@xenova/transformers` 和 `all-MiniLM-L6-v2` (384-dim,量化)— 在本地运行,无需 API 密钥。
## 数据库模式
| 表 | 目的 |
| ----------------- | ----------------------------------------------------------------- |
| `wiki_sections` | 主内容表,包含全文搜索、向量和访问跟踪列 |
| `section_links` | Wiki 关系的规范真实来源(自动填充) |
| `section_history` | 版本历史(在更新时自动填充) |
| `migrations` | 跟踪已应用的迁移文件 |
### `wiki_sections` 列
| 列 | 类型 | 描述 |
| --------------- | ----------- | --------------------------------------- |
| `key` | VARCHAR | 唯一 slug 键(PK) |
| `wiki_id` | VARCHAR | Wiki 实例 ID |
| `title` | VARCHAR | 显示标题 |
| `parent` | VARCHAR | 父主题/分组 |
| `content` | TEXT | Markdown 内容 |
| `tags` | TEXT[] | 类别标签 |
| `embedding` | vector(384) | 语义嵌入(自动生成) |
| `search_vector` | tsvector | 全文搜索索引(自动填充) |
| `access_count` | INT | 阅读计数(上限 9999) |
| `last_accessed` | TIMESTAMPTZ | 最后阅读时间戳 |
| `created_at` | TIMESTAMPTZ | 创建时间戳 |
| `updated_at` | TIMESTAMPTZ | 最后更新时间戳 |
### 关键特性
- **全文搜索**:`tsvector` 列,带权重排名(标题 > 内容 > 标签)
- **模糊搜索**:pg_trigram 相似度,用于容错
- **向量搜索**:384-dim 嵌入 via pgvector(HNSW 索引)
- **智能链接**:`relatedKeys` 在创建/更新时插入显式链接(针对现有章节验证);嵌入式自动链接作为无显式键时的回落
- **内容更改时重新链接**:更新 `content` 或 `title` 会重新生成嵌入并立即自动重新链接
- **自动反向链接**:`section_links` 表是规范真实来源,通过 `relatedKeys` 参数和 `auto_link_sections` 填充
- **自动历史记录**:触发器记录内容更改并带有时间戳
- **自动搜索向量**:触发器在插入/更新时填充 FTS 索引
- **访问跟踪**:每次读取时更新 `access_count` 和 `last_accessed`
- **读取触发的链接**:具有链接的章节在第一次读取时自动链接(孤儿的安全网);已经有链接的章节被跳过
## 迁移
迁移位于 `sql/` 并在服务器启动时由 `src/migrate.js` 自动应用:
- **`001_initial_schema.sql`** — 核心表、触发器、扩展
- **`002_access_tracking.sql`** — 添加 `access_count` 和 `last_accessed` 列
- **`003_foreign_key_cascade.sql`** — 为关系添加级联删除
- **`004_trigger_fk.sql`** — 禁用 `extract_backlinks()` DB 触发器(应用层管理所有链接);添加 `section_history` FK 并带有 `ON DELETE CASCADE`
迁移运行器创建一个 `migrations` 表来跟踪已应用的文件。在首次运行时,它将现有 SQL 文件标记为已应用(与 `docker-entrypoint-initdb.d` 兼容)。
## 环境变量
| 变量名 | 默认值 | 描述 |
| -------------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `DB_HOST` | `localhost` | PostgreSQL主机 |
| `DB_PORT` | `5433` | PostgreSQL端口 |
| `DB_USER` | `wiki` | 数据库用户名 |
| `DB_PASSWORD` | `wiki` | 数据库密码 |
| `DB_NAME` | `wiki` | 数据库名 |
| `TRANSPORT` | `stdio` | 传输模式:`stdio`(本地)或 `http`(远程) |
| `PORT` | `3000` | HTTP端口(仅在`TRANSPORT=http`时使用) |
| `WIKI_ID` | _(未设置)_ | stdio模式下的默认wiki ID。当设置后,`wikiId` 将从所有工具模式中省略并自动解析。在HTTP模式下,这将被忽略 — wiki ID来自API密钥。 |
| `TRUST_PROXY` | _(未设置)_ | 设置为 `true` 以从 `X-Forwarded-For` 读取真实的客户端IP(在反向代理后启用以进行正确的速率限制) |
| `AUTH_CACHE_TTL_MS` | `300000` | 成功身份验证缓存的时间(毫秒),在重新验证之前(默认为5分钟) |
| `AUTH_FAILED_CACHE_TTL_MS` | `60000` | 失败令牌尝试缓存的时间(毫秒),跳过 bcrypt 重新评估(默认为 1 分钟) |
| `CLIENT_POOL_MAX` | `5` | 每个客户端池的最大 PostgreSQL 连接数(仅限 HTTP 模式) |
| `POOL_IDLE_TIMEOUT_MS` | `1800000` | 客户端池可以空闲多久(毫秒)才会被清理(默认为 30 分钟,仅限 HTTP 模式) |
| `POOL_SWEEP_INTERVAL_MS` | `300000` | 空闲池清理器多久运行一次(毫秒)(默认为 5 分钟,仅限 HTTP 模式) |
| `MAX_LINKS_PER_SECTION` | `4` | 自动链接的最大外部链接数 |
| `SIMILARITY_THRESHOLD` | `0.1` | 使用语义搜索结果的最低余弦相似度分数(低于此值时回退到关键词) |
| `RELINK_DEBOUNCE_MS` | `300000` | 读取时自动重新链接的相同章节之间的最小间隔(毫秒)(默认为 5 分钟) |
| `AUTO_LINK_CONCURRENCY` | `10` | `auto_link_sections`期间使用的最大并行DB连接数 |
| `LOG_LEVEL` | `info` | 日志级别(debug, info, warn, error) |
| `LOG_DIR` | `logs` | 日志目录 |
## 从 V1 迁移
V1 (`/home/dev/mcp/wiki/`) 使用基于文件的解析。V2 使用 PostgreSQL。两者可以在过渡期间共存。
1. V2 从 V1 读取的相同 markdown 文件导入
2. V2 增加了 V1 没有的写入功能
3. V2 导出回 markdown 以进行 git 跟踪或外部使用
MCP 配置
以下是此 MCP Server 的配置信息,可直接复制到 Cursor 或其他 MCP 客户端中使用。
mcp.json
连接信息
猜你喜欢
暂无推荐服务器