内容
# MCP 过滤器
MCP 服务器的语义代理。解决了 **工具选择退化** 的问题 —— 当大型语言模型(LLM)拥有太多工具时,它会选择错误的工具。
过滤器位于客户端(Claude Code、Hermes、任何 MCP 客户端)和下游 MCP 服务器之间。客户端看到 **2 个工具** 而不是数十个:`mcp_router_select` + `mcp_router_call`。第一个通过嵌入式查找相关工具,第二个代理调用。
## 工作原理
```
客户端(Claude Code / Hermes)
↓ 看到 2 个工具
mcp_router_select(task="...") → 嵌入式查找 → 排名前 N 的相关工具
mcp_router_call(tool_name, arguments) → 代理到下游
↓
下游 MCP 服务器(时间、获取、git、arxiv、playwright、...)
```
**两条调用路径:**
1. **路径 1(notifications/tools/list_changed):** `select` 查找工具 → 过滤器更新 `tools/list` → 客户端直接调用工具。适用于支持动态工具集更新的客户端。
2. **路径 2(mcp_router_call 代理):** 适用于具有 **固定工具集** 的客户端(Hermes、带有提示缓存的 Claude Code)。`select` 返回带有 `inputSchema` 的工具 → `call` 代理执行。新下游工具被发现时,无需 `/reset`。
## 安装
```bash
git clone <仓库> ~/Projects/mcp-sieve
cd ~/Projects/mcp-sieve
uv pip install -e .
```
需要 [Ollama](https://ollama.com) 带有嵌入式模型:
```bash
ollama pull nomic-embed-text
```
## 快速开始
复制示例配置文件并编辑:
```bash
cp config.example.yaml config.yaml
# 编辑 config.yaml — 添加下游服务器和路径
```
独立运行:
```bash
python -m mcp_router.server
```
服务器监听标准输入输出(JSON-RPC)。
## 连接到 Claude Code
在 `~/.claude.json` → `projects["<path>"].mcpServers` 中:
```json
"sieve": {
"type": "stdio",
"command": "uvx",
"args": ["--from", "/path/to/mcp-sieve", "mcp-sieve"],
"env": {
"MCP_ROUTER_CONFIG": "/path/to/mcp-sieve/config.yaml"
}
}
```
或通过 CLI:
```bash
claude mcp add sieve -- uvx --from /path/to/mcp-sieve mcp-sieve
```
> **Windows:** 需要 `MCP_ROUTER_CONFIG` — `uvx` 将软件包安装到隔离的 venv 中,`__file__` 指向 uv-cache。参见下面的 [Windows 注意事项](#windows-注意事项)。
## 连接到 Hermes
```bash
hermes mcp add sieve --command uvx --args "--from" --args "/path/to/mcp-sieve" --args "mcp-sieve"
hermes mcp test sieve
# 聊天中输入 /reset
```
## 配置
`config.yaml`(参见 `config.example.yaml` 获取完整模板):
```yaml
downstream:
- name: time
command: uvx
args: ["mcp-server-time"]
- name: fetch
command: uvx
args: ["mcp-server-fetch"]
- name: git
command: uvx
args: ["mcp-server-git", "--repository", "/path/to/your/repo"]
# Windows:npx 是 .cmd 文件 — 需要 cmd /c
- name: context7
command: cmd
args: ["/c", "npx", "-y", "@upstash/context7-mcp@latest"]
- name: filesystem
command: cmd
args: ["/c", "npx", "-y", "@modelcontextprotocol/server-filesystem", "/path/to/dir"]
# 通过 HTTP(可流式传输)或 SSE 的远程 MCP — 无本地进程。
# 传输方式默认为 stdio;裸 URL 意味着 http。
- name: gitmcp
transport: http
url: "https://gitmcp.io/docs"
embeddings:
ollama_url: "http://127.0.0.1:11434/api/embeddings"
model: "nomic-embed-text"
top_n: 10
```
环境变量:
- `MCP_ROUTER_CONFIG` — `config.yaml` 的路径(否则在当前工作目录或源码旁边查找)
- `MCP_SIEVE_DOWNSTREAM_<N>_NAME` / `_COMMAND` / `_ARGS` / `_URL` / `_TRANSPORT` — 无需文件定义下游服务器(Docker/k8s)。`N` 从 1 开始,遇到第一个间隙时停止。`_ARGS` 是 JSON 数组或空格分隔的字符串。同名条目会覆盖 yaml 配置。
- `MCP_SIEVE_OLLAMA_URL` / `MCP_SIEVE_EMBED_MODEL` / `MCP_SIEVE_TOP_N` — 嵌入式查找覆盖
崩溃的下游服务器(Ollama、npx)会自动重新连接,呈指数级回退 — 无需重启。
## Windows 注意事项
1. **npx → `cmd /c npx`:** `npx` 是 `.cmd` 文件,Python 子进程(MCP SDK)无法在没有 shell 的情况下找到它。`uvx` 是真正的二进制文件,直接工作。
2. **uvx --from 和依赖项:** `uvx --from <project>` 将软件包安装到隔离的 uv-cache venv 中。所有导入必须位于 `pyproject.toml` `[project.dependencies]` 中 — 开发环境中的隐式依赖不会被拾取。
3. **uv 缓存清理:** 如果缓存被锁定(`os error 32`),请先杀死 MCP 服务器进程:
```bash
powershell -Command "Get-Process | Where-Object { $_.ProcessName -match 'mcp|uv' } | Stop-Process -Force"
uv cache clean --force
```
4. **调试连接失败:** `claude --debug` 写入 `~/.claude/debug/<session>.txt`。在 `Server stderr:` 中查找实际的服务器跟踪信息。
## 技术栈
- **MCP Python SDK** (`mcp`) — stdio + HTTP/SSE 传输,`notifications/tools/list_changed`
- **Ollama** — 局部嵌入式模型(`nomic-embed-text`),免费
- **numpy** — 余弦相似度
- **httpx** — Ollama API 的 HTTP 客户端
## 备用方案
如果 Ollama 不可用 — 过滤器不会崩溃。`mcp_router_select` 返回 **所有** 下游工具,而不进行排名,并在响应中带有警告。
## 性能
在 9 个下游服务器(74 个工具)下测试:
- `mcp_router_select`:83–166ms
- `mcp_router_call`:15–774ms(最长:playwright 浏览器导航)
- 启动:~16s(所有 9 个下游连接 + 74 个嵌入式模型构建)
## 状态
在 Claude Code 和 Hermes 中工作正常。参见 `TASKS.md` 获取路线图和基准测试结果。