内容
# MCP 中转服务器

一个用于模型上下文协议(MCP)的智能代理/路由器,使 Claude Desktop 和其他 MCP 客户端能够动态发现和使用来自多个 MCP 服务器的工具,同时保持单一连接点。该系统通过智能选择每个任务最相关的工具,防止上下文膨胀。
## 🎯 问题
像 Claude Desktop 这样的 MCP 客户端必须在启动时加载所有服务器,并且无法在对话过程中动态添加服务器。使用多个 MCP 服务器时:
- **Exa 服务器**:7 种搜索工具(网络、研究论文、Twitter、公司等)
- **Puppeteer**:浏览器自动化工具
- **Context7**:文档搜索工具
- **Desktop Commander**:18+ 种桌面自动化工具
直接加载所有服务器会导致:
- 🚨 **上下文膨胀**:100+ 种工具消耗大部分上下文窗口
- 🔒 **静态配置**:无法在不重启 Claude 的情况下添加服务器
- 💸 **增加成本**:每个请求的 token 消耗增加
- 🎯 **工具选择不佳**:AI 难以从太多选项中选择
## 💡 解决方案
MCP 中转服务器作为一个智能代理:
1. **单一连接**:Claude Desktop 只连接到 MCP 中转服务器
2. **后端管理**:维护与多个 MCP 服务器的连接
3. **智能发现**:使用语义搜索跨所有服务器查找相关工具
4. **动态供应**:在 token 预算内仅加载所需工具
5. **透明路由**:在适当的后端服务器上执行工具
**示例**:与其配置 10 个 MCP 服务器和 100+ 种工具,不如配置 MCP 中转服务器。然后动态发现和使用仅需要的 2-3 种工具。
## 🚀 功能
### 核心功能
- **代理架构**:单个 MCP 服务器路由到多个后端服务器
- **动态工具发现**:无需手动配置即可跨所有服务器查找工具
- **语义搜索**:使用自然语言查询查找合适的工具
- **智能供应**:在 token 预算内加载相关工具
- **透明执行**:将工具调用路由到适当的后端服务器
- **原生 MCP 服务器**:通过 mcp-proxy 与 Claude Desktop 直接集成
- **跨服务器智能**:统一 Puppeteer、Exa、Context7 等服务器的工具视图
- **token 优化**:与加载所有服务器相比,上下文使用量减少 90%+
- **零配置**:Claude Desktop 仅需要 MCP 中转服务器配置
### 生产功能(v0.3.0)
- **🔒 DNS 重绑定保护**:使用可配置的主机白名单保护 MCP 端点
- **🔄 连接池**:持久的 stdio 会话,性能提升 10-100 倍
- **📊 结构化日志**:带有请求 ID 和关联的 JSON 格式日志
- **⏱️ 三级超时**:工具 → 服务器 → 全局超时层次结构
- **📝 TOML 配置**:带有注释的人性化配置格式
- **🔁 增强的错误处理**:自动重试,指数退化
- **🏥 健康监测**:具有自动恢复的断路器模式
- **📈 进度跟踪**:长时间运行操作的实时反馈
### 高级功能(v0.4.0)
- **💬 MCP 提示支持**:5 个内置的代理感知提示,用于引导工作流
- `discover_and_execute` - 端到端工具工作流引导
- `server_capabilities` - 综合系统概览
- `semantic_tool_search` - 带有排名解释的搜索
- `execute_with_fallback` - 具有替代方案的弹性执行
- `budget_aware_discovery` - token/count 约束内的工具
- 自动后端提示发现和聚合
- 参见 [提示文档](docs/PROMPTS.md) 获取详细信息
### 管理仪表盘(v0.5.0)
- `/admin/dashboard` 提供只读 HTML 仪表盘,显示实时统计数据:连接的服务器、工具目录、缓存命中率和连接池指标。页面通过调用 `/api/admin/summary` 自动刷新,因此您无需外部工具即可快速了解中转服务器的健康状况。
## 📋 erequisites
- Python 3.12+
- [uv](https://docs.astral.sh/uv/) 包管理器
## 🔧 安装
1. 克隆仓库:
```bash
git clone https://github.com/yourusername/mcp-relay.git
cd mcp-relay
```
2. 创建并激活虚拟环境:
```bash
uv venv
source .venv/bin/activate # 在 Unix/macOS 上
# .venv\Scripts\activate # 在 Windows 上
```
3. 安装依赖项:
```bash
uv sync
```
4. 以开发模式安装包:
```bash
uv pip install -e .
```
## 🏃 运行服务器
### 作为 HTTP API 服务器
```bash
# 启动服务器
mcp-relay
# 或使用 uvicorn 进行开发
uvicorn mcp_relay.main:app --reload
```
服务器将在 `http://localhost:8000` 运行
API 文档可在以下地址访问:
- Swagger UI:`http://localhost:8000/docs`
- ReDoc:`http://localhost:8000/redoc`
- MCP 端点:`http://localhost:8000/mcp` (可流式传输的 HTTP 传输)
### 作为 MCP 服务器(推荐)
MCP 中转服务器现在是一个原生的 MCP 服务器,与 Claude Desktop 直接配合使用:
1. **启动服务器**:
```bash
mcp-relay
```
2. **安装 mcp-proxy** (如果尚未安装):
```bash
uv tool install mcp-proxy
```
3. **添加到 Claude Desktop**:
编辑 `~/Library/Application Support/Claude/claude_desktop_config.json`:
```json
{
"mcpServers": {
"mcp-relay": {
"command": "/Users/YOUR_USERNAME/.local/bin/mcp-proxy",
"args": ["http://localhost:8000/mcp"]
}
}
}
```
注意:将 `YOUR_USERNAME` 替换为您的实际用户名。
4. **重启 Claude Desktop**
您将看到 MCP 中转服务器的工具在 Claude 中可用,包括:
- `discover_tools` - 根据查询查找相关工具
- `provision_tools` - 在 token 预算内选择工具
- `register_tool` - 将新工具添加到注册表中
- `list_mcp_servers` - 查看已注册的 MCP 服务器
- 等等!
参见 [MCP 原生使用指南](docs/MCP_NATIVE_USAGE.md) 获取详细说明。
## 🔍 API 端点
### 工具发现
```bash
POST /api/tools/discover
```
根据语义搜索发现相关工具。
**请求:**
```json
{
"query": "我需要进行计算",
"tags": ["math", "calculation"],
"limit": 5
}
```
**响应:**
```json
{
"tools": [
{
"tool_id": "calculator",
"name": "计算器",
"description": "执行数学计算",
"score": 0.95,
"matched_tags": ["math", "calculation"],
"estimated_tokens": 50
}
],
"query_id": "uuid",
"timestamp": "2024-01-01T00:00:00"
}
```
### 工具供应
```bash
POST /api/tools/provision
```
选择并格式化工具以供 LLM 使用,并强制执行 token 预算。
**请求:**
```json
{
"tool_ids": ["calculator", "web-search"],
"max_tools": 3
}
```
**响应:**
```json
{
"tools": [
{
"name": "计算器",
"description": "执行数学计算",
"parameters": { "type": "object", "properties": {...} },
"token_count": 50
}
],
"metadata": {
"total_tokens": 150,
"gating_applied": true
}
}
```
## 🔄 工作原理
1. **Claude Desktop 配置**:仅配置 MCP 中转服务器
```json
{
"mcpServers": {
"mcp-relay": {
"command": "mcp-proxy",
"args": ["http://localhost:8000/mcp"]
}
}
}
```
2. **后端服务器连接**:MCP 中转服务器连接到多个 MCP 服务器
```
MCP Relay → puppeteer (浏览器工具)
→ exa (搜索工具)
→ context7 (文档)
→ filesystem (文件操作)
```
3. **自然语言发现**: "我需要搜索研究论文"
```
Claude → discover_tools → 语义搜索 → 返回相关工具
```
4. **实时工具执行**:根据需要动态加载工具
```
execute_tool("exa_research_paper_search", {...}) → 验证 → 加载 → 执行
```
不需要供应!工具在需要时动态加载。
## 🎯 使用示例
### 运行演示
```bash
# 确保服务器已启动
mcp-relay
# 在另一个终端,运行交互式演示
python demo.py
```
### 手动测试
```bash
# 测试服务器端点
python test_server.py
```
### 示例:查找数学工具
```python
import httpx
import asyncio
async def find_math_tools():
async with httpx.AsyncClient() as client:
response = await client.post(
"http://localhost:8000/api/tools/discover",
json={
"query": "我需要解方程",
"tags": ["math"],
"limit": 3
}
)
tools = response.json()["tools"]
print(f"找到 {len(tools)} 个相关工具")
for tool in tools:
print(f"- {tool['name']}: {tool['score']:.3f}")
asyncio.run(find_math_tools())
```
## 🧪 测试
```bash
# 运行所有测试
pytest
# 运行覆盖率测试
pytest --cov=mcp_relay
# 运行特定测试文件
pytest tests/test_discovery_service.py -v
# 运行集成测试
pytest tests/test_integration.py -v
```
## 📊 架构详情
1. **工具注册**:工具使用元数据、标签和 token 估计进行注册
2. **语义搜索**:用户查询使用句子转换器嵌入
3. **相关性评分**:工具根据:
- 查询和工具嵌入之间的余弦相似度
- 标签匹配(每个匹配标签增加 0.2 的提升)
4. **实时加载**:工具在执行时动态加载
5. **MCP 格式化**:所选工具根据 MCP 协议格式化
## 🔧 配置
系统使用合理的默认值,但可以配置:
- **最大 token 数**:默认每个请求 2000 token
- **最大工具数**:默认每个请求 10 个工具
- **嵌入模型**:`all-MiniLM-L6-v2`(384 维嵌入)
### 安全配置
**DNS 重绑定保护**(v0.3.0+):`/mcp` 端点通过验证主机和来源标头保护免受 DNS 重绑定攻击。
- **默认**:仅限 localhost 访问(`localhost`、`127.0.0.1`、`::1`)
- **自定义白名单**:通过 `ALLOWED_MCP_HOSTS` 环境变量添加受信任的主机/IP
```bash
# 允许访问特定 LAN IP
export ALLOWED_MCP_HOSTS="localhost,127.0.0.1,192.168.1.100,192.168.1.101"
# 允许访问自定义主机名
export ALLOWED_MCP_HOSTS="localhost,127.0.0.1,myserver.local,app.internal"
# Docker 示例
docker run -p 8000:8000 \
-e ALLOWED_MCP_HOSTS="localhost,127.0.0.1,192.168.1.100" \
mcp-relay
```
**⚠️ 安全注意事项**:仅添加受信任的主机。白名单允许对 MCP 端点和所有连接的后端服务器进行完全访问。
### MCP 服务器配置文件
- 所有后端 MCP 服务器都定义在 `config/mcp-servers.toml` 中。运行 Docker 时,设置 `MCP_DATA_DIR`(默认为 `/data`)并挂载单个主机目录;服务器文件自动解析为 `$MCP_DATA_DIR/config/mcp-servers.toml`。
- 使用 `MCP_SERVERS_PATH` 环境变量覆盖位置(如果需要非标准布局)。
- 每个条目可以启动本地进程(通过 `command`/`args`/`env`)**或**通过 `url` 指向现有的 MCP 端点。远程服务器,设置 `transport`(例如 `"streamable-http"`)和可选 `headers`:
```json
{
"docs-http": {
"url": "http://localhost:8844/mcp",
"transport": "streamable-http",
"headers": {
"Authorization": "Bearer example"
}
},
"legacy-sse": {
"url": "http://localhost:9000/mcp",
"transport": "sse"
}
}
```
当提供 `url` 时,MCP 中转服务器直接连接到远程 MCP 服务器(支持流式 HTTP 和 SSE 传输)而不是启动本地进程。
## 🐳 Docker 使用
使用 Docker 交付代理及其所有依赖项(Python 堆栈以及 Node.js/npm,用于_stdio MCP 服务器和可选的 CUDA 启用 PyTorch 轮子)而不会污染主机环境。
```bash
# 构建镜像
docker build -t mcp-relay .
# 准备持久数据目录(此处存储配置/日志/存储)
mkdir -p data/config data/logs data/storage
cp config/mcp-servers.toml data/config/mcp-servers.toml
# 在 CPU 上运行(单个绑定挂载处理配置、日志和存储)
docker run --rm -p 8000:8000 \
-v $(pwd)/data:/data \
-e MCP_DATA_DIR=/data \
mcp-relay
# 启用 GPU 嵌入(需要 NVIDIA 容器工具包)
docker run --rm -p 8000:8000 --gpus all \
-v $(pwd)/data:/data \
-e MCP_DATA_DIR=/data \
-e MCP_RELAY_ENCODER_DEVICE=cuda:0 \
mcp-relay
```
容器公开 FastAPI + MCP 上的端口 `8000`。覆盖任何运行时选项并添加额外的 `-e VAR=value` 标志(例如 `MCP_RELAY_SKIP_BOOTSTRAP=1` 进行烟雾测试)。单个 `-v $(pwd)/data:/data` 挂载保持配置、日志和存储文件在一起; `/data/config/mcp-servers.toml` 自动更新,当您添加/删除服务器时。
### Docker Compose
`docker-compose.yml` 包装这些默认值,因此您可以仅需一个命令启动代理:```bash
# 自定义环境(可选)
cat <<'EOF' > .env
MCP_DATA_VOLUME=./data
MCP_DATA_DIR=/data
MCP_RELAY_ENCODER_DEVICE=cpu # 设置为 cuda:0 安装 NVIDIA 工具包后
MCP_RELAY_SKIP_BOOTSTRAP=0
EOF
docker compose --env-file .env up --build
```
Compose 服务映射端口 `8000` 并将 `${MCP_DATA_VOLUME}` 挂载到 `/data`,因此配置、日志和存储文件保持在一起。运行 GPU 嵌入时,安装 [NVIDIA 容器工具包](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html),然后设置 `MCP_RELAY_ENCODER_DEVICE=cuda:0`,然后 Compose 启动, Compose 启动后,设置 `MCP_RELAY_ENCODER_DEVICE=cuda:0`,然后 <a href="https://github.com/modelcontextprotocol/python-sdk">MCP 协议</a> <a href="https://www.sbert.net/">句子转换器</a> <a href="https://github.com/Textualize/rich">Rich</a> <a href="https://fastapi.tiangolo.com/">FastAPI</div>