内容
# mcp-citation-research
> **MCP 研究服务器,拒绝幻觉。** 0.90 置信度门控 + 四轴源强制执行(迭代次数、考虑次数、获取次数、唯一域名)+ BM25 句子块引用注入。会话 API **拒绝推进** 到合成,直到强制执行完成 — 大多数公共研究 MCP 服务器会乐意从 3 个来源合成;这个服务器不会。
>
> 混合 Go + Python 设计:Go 中的 I/O 守护进程(原生 goroutine,单个二进制文件),Python MCP 前端用于验证和引用(rank_bm25,FastMCP)。合成保持在调用 MCP 客户端的上下文窗口中 — 您的模型负责编写,服务器强制执行纪律。
[](https://github.com/M00C1FER/mcp-citation-research/actions)



## 安装
```bash
go install github.com/M00C1FER/mcp-citation-research/daemon/cmd/citation-researchd@latest
```
以上命令安装守护进程二进制文件。Python MCP 前端目前从源代码安装(`cd server && pip install -e .`),直到添加专用发布的 前端软件包路径。
## 这里有什么独特之处
在对 [官方注册表](https://registry.modelcontextprotocol.io) 和相邻生态系统(Smithery、Glama、awesome-mcp-servers @ 85k★)中的 70 多个 MCP 服务器进行调查后,差异化因素是:
1. **强制执行硬性规定** — 四轴底线(10 次迭代 / 400 次考虑 / 100 次获取 / 15 个唯一域名,`详尽` 深度)是一种 *拒绝合同*,而非建议。其他研究 MCP 让模型决定何时停止;这个服务器为模型决定。
2. **BM25 句子块引用** — 合成段落的每个段落都带有 `[S#]` 标签,与获取的源内容进行验证。未支持的段落自动标记为 `[UNVERIFIED]`。
3. **0.90 置信度门控** — 引用覆盖率 + token 接地性混合;低于门控,验证器会显示它。
4. **混合 Go+Python** — 大多数 MCP 研究服务器是纯 Python(DeepResearchMCP、Perplexity 代理等)。这个服务器演示了在正确边界处的正确语言。
## 为什么选择混合 Go + Python
| 层 | 语言 | 为什么 |
|---|---|---|
| 守护进程(搜索/获取/迭代/会话) | **Go** | I/O 绑定;原生 goroutine 优于 Python asyncio;单个 9.7 MB 二进制文件 |
| MCP 前端(验证/引用 + 工具表面) | **Python** | LLM 绑定;成熟的 LLM SDK 生态系统;`rank_bm25` + FastMCP |
网络 → Go(原生 goroutine,单个静态二进制文件)。LLM 编排 → Python(成熟的 SDK 生态系统)。大多数 MCP 服务器是纯 Python;这个服务器在正确的边界处分裂。
## 它做了什么
- **原子循环工具**:`research_session_open` / `_update` / `_status` / `_close`,`research_search`,`research_fetch`,`research_decompose`,`research_verify`,`research_cite`。
- **强制执行硬性规定**(默认 `详尽`):10 次迭代 · 400 次考虑 · 100 次获取 · 15 个唯一域名。会话 API 在这些轴未清除时拒绝推进。
- **BM25 引用注入** — 每个段落如果与上述阈值匹配,则获取 `[S#]`;现有的 `[S#]` 被验证或标记为 `[UNVERIFIED]`。
- **0.90 置信度门控** — 引用覆盖率 + token 接地性;返回 `confidence_gate_passed: bool`。
- **CLI 编排** 设计 — 合成发生在调用 MCP 客户端的上下文窗口中(Claude Code、Cursor、Continue.dev),而非服务器中。这保留了调用者的完整 1M-token 上下文。
## 架构
```mermaid
graph TB
A[MCP 客户端<br/>Claude Code / Cursor] -->|tools/call| B[citation-research MCP 服务器<br/>Python · FastMCP]
B -->|HTTP| C[citation-researchd<br/>Go · 9.7 MB 二进制文件]
C -->|/search| D[SearXNG · 端口 8080]
C -->|/fetch| E[net/http + golang.org/x/net/html]
C -->|会话状态| F[(内存中)]
B -->|验证/引用<br/>(无守护进程)| G[Python 中的 rank_bm25]
```
## 快速开始
### 构建守护进程
```bash
cd daemon
go build -o ./citation-researchd ./cmd/citation-researchd
./citation-researchd -addr 127.0.0.1:8090 -searxng http://127.0.0.1:8080 &
```
### 安装 MCP 服务器
```bash
cd server
pip install -e .
```
### 连接到 Claude Desktop
```json
{
"mcpServers": {
"citation-research": {
"command": "citation-research-mcp",
"env": { "CITATION_RESEARCHD_URL": "http://127.0.0.1:8090" }
}
}
}
```
## 工具参考
| 工具 | 目的 |
|---|---|
| `research_session_open` | 启动会话;返回 `session_id` |
| `research_session_update` | 记录迭代指标;跟踪四轴强制执行 |
| `research_session_status` | 当前指标 + `mandate_met: bool` |
| `research_session_close` | 结束会话;最终指标 |
| `research_search` | 多引擎 RRF(k=60);SearXNG 默认 |
| `research_fetch` | 并发提取;16 路有界并行 |
| `research_decompose` | 启发式子问题生成(CLI 应覆盖) |
| `research_verify` | 引用覆盖率 + 接地性;门控在 0.90 |
| `research_cite` | BM25 `[S#]` 注入 + `[UNVERIFIED]` 标记 |
| `research_health` | 前端 + 守护进程活跃度 |
## 与替代方案比较
| 服务器 | 置信度门控 | BM25 引用 | 强制执行 | I/O 语言 |
|---|:-:|:-:|:-:|:-:|
| `mcp-perplexity-ask` | ❌ | ❌ | ❌ | 代理 |
| `mcp-server-fetch` | ❌ | ❌ | ❌ | Python |
| `chroma-mcp` | ❌ | 部分 | ❌ | Python |
| `pinecone-mcp` | ❌ | ❌ | ❌ | Python |
| **`mcp-citation-research`** | **✅ 0.90** | **✅ 句子块** | **✅ 4 轴硬性门控** | **Go 守护进程 + Python 前端** |
## 基准测试
运行 `python benchmarks/mandate_vs_no_mandate.py "your query"` 比较强制执行与单次通过合成质量在相同问题上的表现。
## 测试
```bash
# Go 守护进程
cd daemon && go test ./...
# Python 前端
cd server && pip install -e .[dev] && pytest
```
## 跨平台支持
| 平台 | Go 守护进程 | Python 前端 | 注意 |
|---|:-:|:-:|---|
| Debian 12/13 | ✅ | ✅ | 主要目标 |
| Ubuntu 22.04 / 24.04 | ✅ | ✅ | CI 测试 |
| Alpine(musl libc) | ✅ (`CGO_ENABLED=0`) | ✅ | 静态二进制文件;竞争检测器不可用(musl) |
| WSL 2(Ubuntu 基础) | ✅ | ✅ | 无 `/proc/sys/kernel/osrelease`、systemd 或 `/etc/passwd` 假设在守护进程中 |
| macOS(amd64 / arm64) | ✅(交叉编译验证) | ✅ | 守护进程在 macOS 运行器上尚未 CI 测试 |
| Arch / Fedora | ✅(尽力而为) | ✅(尽力而为) | 不在 CI 矩阵中 |
| **Termux(Android arm64)** | ✅ (`CGO_ENABLED=0`) | ✅ | 参见下面的 [Termux 安装](#termux) |
**多个守护进程实例**:每个实例维护独立的内存中会话状态。只要实例监听不同的地址/端口(例如 `-addr 127.0.0.1:8090` 与 `-addr 127.0.0.1:8091`),在同一主机上运行两个守护进程是安全的。从一个守护进程不可见的会话 ID。
## Termux
在 Android(arm64)上一步安装:
```bash
curl -fsSL https://raw.githubusercontent.com/M00C1FER/mcp-citation-research/main/scripts/install-termux.sh | bash
```
或从本地克隆运行 `scripts/install-termux.sh`。脚本:
1. 通过 `pkg` 安装 `golang`、`python`、`git`、`openssl`。
2. 将仓库克隆到 `~/mcp-citation-research`。
3. 使用 `CGO_ENABLED=0` 构建 `citation-researchd`(完全静态二进制文件)。
4. 将 Python MCP 前端安装到虚拟环境中。
5. 生成 bearer-auth token 并将启动脚本放入 `~/.local/bin`。
6. 运行烟雾测试(healthz + 在临时端口上进行身份验证检查)。
**注意事项**:
- Termux 中不可用 SearXNG;搜索仅使用 DuckDuckGo 抓取。
- 守护进程绑定到 `127.0.0.1`(环回地址)。其他 Android 应用无法访问它。
- Termux 上不可用竞争检测器(需要 CGO + glibc)。
- 要在关闭终端后保持守护进程运行,请使用 [Termux:Boot](https://wiki.termux.com/wiki/Termux:Boot)。
## 许可证
MIT。