mcp-router


Namemcp-router JSON
Version 1.0.8 PyPI version JSON
download
home_pageNone
SummaryA routing/proxy system for MCP servers
upload_time2025-10-29 04:26:22
maintainerNone
docs_urlNone
authorNone
requires_python>=3.10
licenseMIT
keywords ai llm mcp proxy router
VCS
bugtrack_url
requirements fastapi uvicorn httpx pydantic watchdog python-dotenv mcp starlette pytest pytest-asyncio
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # MCP Router

[![PyPI Publish](https://github.com/ChuranNeko/mcp_router/actions/workflows/python-publish.yml/badge.svg)](https://github.com/ChuranNeko/mcp_router/actions/workflows/python-publish.yml)
[![Code style: ruff](https://img.shields.io/badge/code%20style-ruff-000000.svg)](https://github.com/astral-sh/ruff)
[![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

MCP Router 是一个模型上下文协议(MCP)路由/代理系统,作为MCP服务端和客户端,支持动态管理MCP工具配置,解决LLM无法区分同名工具的问题。

## 特性

- **动态路由**: 文件系统路由,使用 `mcp_settings.json` 配置
- **快速启动**: 后台加载客户端,启动时间<0.1秒
- **热加载**: 自动检测配置变化并重新加载
- **多传输支持**: Stdio、SSE、HTTP 传输协议
- **实时日志**: WebSocket实时日志流(可选)
- **权限控制**: 可配置的LLM实例管理权限
- **智能端口**: 端口占用时自动查找可用端口
- **安全认证**: Bearer Token认证,输入验证
- **REST API**: 完整的HTTP API用于配置管理

<details>
<summary><b>📁 项目结构</b></summary>

```
mcp_router/
├── main.py                 # 项目入口
├── config.json            # 全局配置文件
├── requirements.txt       # 依赖文件
├── pyproject.toml         # uv项目配置
│
├── src/
│   ├── core/              # 核心模块
│   │   ├── logger.py      # 日志系统
│   │   ├── config.py      # 配置管理器
│   │   └── exceptions.py  # 自定义异常
│   │
│   ├── mcp/               # MCP模块
│   │   ├── client.py      # MCP客户端管理
│   │   ├── server.py      # MCP服务端
│   │   ├── router.py      # 路由核心逻辑
│   │   └── transport.py   # 传输层
│   │
│   ├── api/               # API模块
│   │   ├── app.py         # FastAPI应用
│   │   └── routes.py      # API路由处理
│   │
│   └── utils/             # 工具模块
│       ├── validator.py   # 输入验证
│       ├── watcher.py     # 文件监视器
│       └── security.py    # 安全工具
│
├── data/                  # MCP配置目录
│   ├── example/
│   │   └── mcp_settings.json
│   └── ...
│
└── test/                  # 测试文件
    ├── test_router.py
    ├── test_api.py
    └── test_security.py
```

</details>

## 快速开始

### 安装

**从 PyPI 安装(推荐):**

```bash
pip install mcp-router
```

<details>
<summary><b>从源码安装</b></summary>

```bash
# 使用 uv (推荐)
uv venv .venv
uv pip install -e ".[dev]"

# 或使用 pip
python -m venv .venv
.venv\Scripts\activate  # Windows
source .venv/bin/activate  # Linux/Mac
pip install -e ".[dev]"

# 或使用 conda
conda env create -f environment.yml
conda activate mcp_router
```

</details>

### 配置

编辑 `config.json` 文件:

```json
{
  "api": {
    "enabled": false,
    "port": 8001,
    "host": "0.0.0.0"
  },
  "server": {
    "host": "0.0.0.0",
    "http": { "enabled": true, "port": 3000 },
    "sse": { "enabled": true, "port": 3001 }
  },
  "security": {
    "bearer_token": "",
    "enable_validation": true
  },
  "logging": {
    "level": "INFO",
    "directory": "logs"
  }
}
```

<details>
<summary><b>⚙️ 配置项说明</b></summary>

- `server.host`: HTTP/SSE模式的监听地址(默认:0.0.0.0)
- `server.http.port`: HTTP模式的监听端口(默认:3000)
- `server.sse.port`: SSE模式的监听端口(默认:3001)
- `server.allow_instance_management`: 允许LLM管理实例(默认:false)
- `api.enabled`: 是否启动REST API服务器(默认:false)
- `api.port`: REST API端口(默认:8001)
- `api.auto_find_port`: 端口占用时自动递增查找可用端口
- `api.enable_realtime_logs`: 启用WebSocket实时日志 (ws://host:port/ws)
- `logging.directory`: 日志目录,使用Minecraft风格 (latest-{mode}.txt + 时间戳备份)
- `logging.level`: 日志级别(DEBUG/INFO/WARNING/ERROR/OFF)

**注意**:传输模式(stdio/http/sse)通过命令行参数指定,不在配置文件中设置。

</details>

### 添加MCP配置

在 `data/{provider}/mcp_settings.json` 中添加MCP服务器配置:

```json
{
  "provider": "example",
  "isActive": true,
  "name": "example_instance",
  "type": "stdio",
  "command": "python",
  "args": ["-m", "example_mcp"],
  "env": {}
}
```

### 运行

```bash
# 直接指定传输模式
python main.py              # Stdio模式(默认)
python main.py stdio        # Stdio模式
python main.py http         # HTTP模式
python main.py sse          # SSE模式
python main.py api          # API服务器模式

# 查看帮助
python main.py help
python main.py -h
```

## MCP 工具

MCP Router 提供以下工具给 LLM 使用:

**基础工具** (总是可用):
- `mcp.router.list()` - 列出所有已注册的MCP客户端实例
- `mcp.router.help()` - 返回所有实例的工具列表和使用说明
- `mcp.router.use(instance_name)` - 使用指定的MCP实例
- `mcp.router.call(instance_name, tool_name, **kwargs)` - 调用指定实例的指定工具

**管理工具** (需启用 `allow_instance_management`):
- `mcp.router.add(provider_name, config)` - 动态添加新的MCP配置
- `mcp.router.remove(instance_name)` - 移除MCP配置
- `mcp.router.enable(instance_name)` - 启用MCP实例
- `mcp.router.disable(instance_name)` - 禁用MCP实例

<details>
<summary><b>📡 REST API 端点</b></summary>

当 API 模式启用时,可通过以下端点管理 MCP Router:

**实例管理**:
- `GET /api/instances` - 列出所有实例
- `GET /api/instances/{name}` - 获取实例详情
- `POST /api/instances` - 添加新实例
- `PATCH /api/instances/{name}` - 更新实例配置
- `DELETE /api/instances/{name}` - 删除实例
- `POST /api/instances/{name}/enable` - 启用实例
- `POST /api/instances/{name}/disable` - 禁用实例

**工具管理**:
- `GET /api/tools` - 列出所有工具
- `GET /api/tools/{instance_name}` - 获取实例的工具列表
- `POST /api/call` - 调用工具

**其他**:
- `GET /` - 服务状态
- `GET /health` - 健康检查
- `GET /api/config` - 获取配置
- `WS /ws` - 实时日志流 (需启用 `enable_realtime_logs`)

</details>

## 与 LLM 集成

### Stdio 模式(推荐)

适用于单个LLM客户端(如Claude Desktop、Cursor)。

**客户端配置示例** (mcp.json):
```json
{
  "mcpServers": {
    "mcp_router": {
      "command": "uv",
      "args": [
        "--directory",
        "C:/path/to/mcp_router",
        "run",
        "python",
        "main.py"
      ],
      "transport": "stdio"
    }
  }
}
```

### HTTP 模式

适用于多客户端并发连接(端口 3000)。

**客户端配置示例** (mcp.json):
```json
{
  "mcpServers": {
    "mcp_router_http": {
      "url": "http://localhost:3000/mcp",
      "transport": "streamableHttp"
    }
  }
}
```

<details>
<summary><b>HTTP 使用示例(curl / Python)</b></summary>

**curl 示例**:
```bash
# 初始化会话
curl -X POST http://localhost:3000/mcp \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0.0"}}}'

# 列出工具
curl -X POST http://localhost:3000/mcp \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
```

**Python 客户端示例**:
```python
import httpx

class MCPHTTPClient:
    def __init__(self, base_url="http://localhost:3000"):
        self.client = httpx.Client()
        self.base_url = base_url
        self.request_id = 0
        self.initialized = False
    
    def call_method(self, method, params=None):
        self.request_id += 1
        response = self.client.post(f"{self.base_url}/mcp", json={
            "jsonrpc": "2.0",
            "id": self.request_id,
            "method": method,
            "params": params or {}
        })
        return response.json()
    
    def initialize(self):
        result = self.call_method("initialize", {
            "protocolVersion": "2024-11-05",
            "capabilities": {},
            "clientInfo": {"name": "python-client", "version": "1.0.0"}
        })
        self.initialized = True
        return result
    
    def list_tools(self):
        if not self.initialized:
            self.initialize()
        return self.call_method("tools/list")

# 使用示例
client = MCPHTTPClient()
tools = client.list_tools()
print(tools)
```

</details>

### SSE 模式

适用于实时推送场景(端口 3001)。

**客户端配置示例** (mcp.json):
```json
{
  "mcpServers": {
    "mcp_router_sse": {
      "url": "http://localhost:3001/sse",
      "transport": "sse"
    }
  }
}
```

<details>
<summary><b>SSE JavaScript 客户端示例</b></summary>

```javascript
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";

const transport = new SSEClientTransport(
  new URL("http://localhost:3001/sse")
);
const client = new Client(
  { name: "my-client", version: "1.0.0" }, 
  { capabilities: {} }
);

await client.connect(transport);
const tools = await client.listTools();
console.log(tools);
```

</details>

### REST API 模式

独立的配置管理接口(端口 8001)。

```bash
# 单独启动API模式
python main.py api

# 或在任意MCP模式下同时启用API(需config.json中配置api.enabled: true)
python main.py http
```

<details>
<summary><b>REST API 使用示例</b></summary>

**curl 示例**:
```bash
# 列出所有实例
curl http://localhost:8001/api/instances \
  -H "Authorization: Bearer your-token"

# 调用工具
curl -X POST http://localhost:8001/api/call \
  -H "Authorization: Bearer your-token" \
  -H "Content-Type: application/json" \
  -d '{"instance": "openai_doc", "tool": "read_project_oas", "params": {}}'
```

**Python 客户端示例**:
```python
import httpx

client = httpx.Client(
    base_url="http://localhost:8001",
    headers={"Authorization": "Bearer your-token"}
)

# 列出实例
instances = client.get("/api/instances").json()

# 调用工具
result = client.post("/api/call", json={
    "instance": "openai_doc",
    "tool": "read_project_oas",
    "params": {}
}).json()
```

</details>

### 混合模式(MCP + API)

同时运行MCP服务器和REST API,使用独立端口互不干扰。

**配置**:
```json
{
  "api": {"enabled": true, "port": 8001},
  "server": {
    "host": "0.0.0.0",
    "http": {"enabled": true, "port": 3000}
  }
}
```

**启动**:
```bash
python main.py http  # MCP@3000 + API@8001
```

## 开发

### 代码风格

本项目使用 [Ruff](https://github.com/astral-sh/ruff) 进行代码格式化和 linting:

```bash
# 格式化代码
ruff format .

# 检查代码
ruff check .

# 自动修复
ruff check --fix .
```

<details>
<summary><b>🧪 运行测试</b></summary>

```bash
# 运行所有测试
pytest

# 运行特定测试
pytest test/test_router.py

# 带覆盖率
pytest --cov=src --cov-report=html
```

</details>

## 安全性

- **输入验证**: 防止SQL注入、XSS攻击、路径遍历
- **Bearer Token**: 可选的API认证
- **CORS配置**: 灵活的跨域请求控制
- **文件大小限制**: 防止DOS攻击
- **HTTP安全头**: X-Frame-Options, CSP, HSTS等

## 许可证

[MIT License](LICENSE)

## 贡献

欢迎提交 Issue 和 Pull Request!

请确保:
- 代码通过 `ruff` 检查
- 添加或更新相关测试
- 更新文档(如果需要)


            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "mcp-router",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.10",
    "maintainer_email": "ChuranNeko <churanneko@qq.com>",
    "keywords": "ai, llm, mcp, proxy, router",
    "author": null,
    "author_email": "ChuranNeko <churanneko@qq.com>",
    "download_url": "https://files.pythonhosted.org/packages/e2/8a/7e364a9e0444397f20ae358a2b53db535445b2aadbce24d8cb60c5b1e889/mcp_router-1.0.8.tar.gz",
    "platform": null,
    "description": "# MCP Router\n\n[![PyPI Publish](https://github.com/ChuranNeko/mcp_router/actions/workflows/python-publish.yml/badge.svg)](https://github.com/ChuranNeko/mcp_router/actions/workflows/python-publish.yml)\n[![Code style: ruff](https://img.shields.io/badge/code%20style-ruff-000000.svg)](https://github.com/astral-sh/ruff)\n[![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nMCP Router \u662f\u4e00\u4e2a\u6a21\u578b\u4e0a\u4e0b\u6587\u534f\u8bae\uff08MCP\uff09\u8def\u7531/\u4ee3\u7406\u7cfb\u7edf\uff0c\u4f5c\u4e3aMCP\u670d\u52a1\u7aef\u548c\u5ba2\u6237\u7aef\uff0c\u652f\u6301\u52a8\u6001\u7ba1\u7406MCP\u5de5\u5177\u914d\u7f6e\uff0c\u89e3\u51b3LLM\u65e0\u6cd5\u533a\u5206\u540c\u540d\u5de5\u5177\u7684\u95ee\u9898\u3002\n\n## \u7279\u6027\n\n- **\u52a8\u6001\u8def\u7531**: \u6587\u4ef6\u7cfb\u7edf\u8def\u7531\uff0c\u4f7f\u7528 `mcp_settings.json` \u914d\u7f6e\n- **\u5feb\u901f\u542f\u52a8**: \u540e\u53f0\u52a0\u8f7d\u5ba2\u6237\u7aef\uff0c\u542f\u52a8\u65f6\u95f4<0.1\u79d2\n- **\u70ed\u52a0\u8f7d**: \u81ea\u52a8\u68c0\u6d4b\u914d\u7f6e\u53d8\u5316\u5e76\u91cd\u65b0\u52a0\u8f7d\n- **\u591a\u4f20\u8f93\u652f\u6301**: Stdio\u3001SSE\u3001HTTP \u4f20\u8f93\u534f\u8bae\n- **\u5b9e\u65f6\u65e5\u5fd7**: WebSocket\u5b9e\u65f6\u65e5\u5fd7\u6d41\uff08\u53ef\u9009\uff09\n- **\u6743\u9650\u63a7\u5236**: \u53ef\u914d\u7f6e\u7684LLM\u5b9e\u4f8b\u7ba1\u7406\u6743\u9650\n- **\u667a\u80fd\u7aef\u53e3**: \u7aef\u53e3\u5360\u7528\u65f6\u81ea\u52a8\u67e5\u627e\u53ef\u7528\u7aef\u53e3\n- **\u5b89\u5168\u8ba4\u8bc1**: Bearer Token\u8ba4\u8bc1\uff0c\u8f93\u5165\u9a8c\u8bc1\n- **REST API**: \u5b8c\u6574\u7684HTTP API\u7528\u4e8e\u914d\u7f6e\u7ba1\u7406\n\n<details>\n<summary><b>\ud83d\udcc1 \u9879\u76ee\u7ed3\u6784</b></summary>\n\n```\nmcp_router/\n\u251c\u2500\u2500 main.py                 # \u9879\u76ee\u5165\u53e3\n\u251c\u2500\u2500 config.json            # \u5168\u5c40\u914d\u7f6e\u6587\u4ef6\n\u251c\u2500\u2500 requirements.txt       # \u4f9d\u8d56\u6587\u4ef6\n\u251c\u2500\u2500 pyproject.toml         # uv\u9879\u76ee\u914d\u7f6e\n\u2502\n\u251c\u2500\u2500 src/\n\u2502   \u251c\u2500\u2500 core/              # \u6838\u5fc3\u6a21\u5757\n\u2502   \u2502   \u251c\u2500\u2500 logger.py      # \u65e5\u5fd7\u7cfb\u7edf\n\u2502   \u2502   \u251c\u2500\u2500 config.py      # \u914d\u7f6e\u7ba1\u7406\u5668\n\u2502   \u2502   \u2514\u2500\u2500 exceptions.py  # \u81ea\u5b9a\u4e49\u5f02\u5e38\n\u2502   \u2502\n\u2502   \u251c\u2500\u2500 mcp/               # MCP\u6a21\u5757\n\u2502   \u2502   \u251c\u2500\u2500 client.py      # MCP\u5ba2\u6237\u7aef\u7ba1\u7406\n\u2502   \u2502   \u251c\u2500\u2500 server.py      # MCP\u670d\u52a1\u7aef\n\u2502   \u2502   \u251c\u2500\u2500 router.py      # \u8def\u7531\u6838\u5fc3\u903b\u8f91\n\u2502   \u2502   \u2514\u2500\u2500 transport.py   # \u4f20\u8f93\u5c42\n\u2502   \u2502\n\u2502   \u251c\u2500\u2500 api/               # API\u6a21\u5757\n\u2502   \u2502   \u251c\u2500\u2500 app.py         # FastAPI\u5e94\u7528\n\u2502   \u2502   \u2514\u2500\u2500 routes.py      # API\u8def\u7531\u5904\u7406\n\u2502   \u2502\n\u2502   \u2514\u2500\u2500 utils/             # \u5de5\u5177\u6a21\u5757\n\u2502       \u251c\u2500\u2500 validator.py   # \u8f93\u5165\u9a8c\u8bc1\n\u2502       \u251c\u2500\u2500 watcher.py     # \u6587\u4ef6\u76d1\u89c6\u5668\n\u2502       \u2514\u2500\u2500 security.py    # \u5b89\u5168\u5de5\u5177\n\u2502\n\u251c\u2500\u2500 data/                  # MCP\u914d\u7f6e\u76ee\u5f55\n\u2502   \u251c\u2500\u2500 example/\n\u2502   \u2502   \u2514\u2500\u2500 mcp_settings.json\n\u2502   \u2514\u2500\u2500 ...\n\u2502\n\u2514\u2500\u2500 test/                  # \u6d4b\u8bd5\u6587\u4ef6\n    \u251c\u2500\u2500 test_router.py\n    \u251c\u2500\u2500 test_api.py\n    \u2514\u2500\u2500 test_security.py\n```\n\n</details>\n\n## \u5feb\u901f\u5f00\u59cb\n\n### \u5b89\u88c5\n\n**\u4ece PyPI \u5b89\u88c5\uff08\u63a8\u8350\uff09\uff1a**\n\n```bash\npip install mcp-router\n```\n\n<details>\n<summary><b>\u4ece\u6e90\u7801\u5b89\u88c5</b></summary>\n\n```bash\n# \u4f7f\u7528 uv (\u63a8\u8350)\nuv venv .venv\nuv pip install -e \".[dev]\"\n\n# \u6216\u4f7f\u7528 pip\npython -m venv .venv\n.venv\\Scripts\\activate  # Windows\nsource .venv/bin/activate  # Linux/Mac\npip install -e \".[dev]\"\n\n# \u6216\u4f7f\u7528 conda\nconda env create -f environment.yml\nconda activate mcp_router\n```\n\n</details>\n\n### \u914d\u7f6e\n\n\u7f16\u8f91 `config.json` \u6587\u4ef6\uff1a\n\n```json\n{\n  \"api\": {\n    \"enabled\": false,\n    \"port\": 8001,\n    \"host\": \"0.0.0.0\"\n  },\n  \"server\": {\n    \"host\": \"0.0.0.0\",\n    \"http\": { \"enabled\": true, \"port\": 3000 },\n    \"sse\": { \"enabled\": true, \"port\": 3001 }\n  },\n  \"security\": {\n    \"bearer_token\": \"\",\n    \"enable_validation\": true\n  },\n  \"logging\": {\n    \"level\": \"INFO\",\n    \"directory\": \"logs\"\n  }\n}\n```\n\n<details>\n<summary><b>\u2699\ufe0f \u914d\u7f6e\u9879\u8bf4\u660e</b></summary>\n\n- `server.host`: HTTP/SSE\u6a21\u5f0f\u7684\u76d1\u542c\u5730\u5740\uff08\u9ed8\u8ba4\uff1a0.0.0.0\uff09\n- `server.http.port`: HTTP\u6a21\u5f0f\u7684\u76d1\u542c\u7aef\u53e3\uff08\u9ed8\u8ba4\uff1a3000\uff09\n- `server.sse.port`: SSE\u6a21\u5f0f\u7684\u76d1\u542c\u7aef\u53e3\uff08\u9ed8\u8ba4\uff1a3001\uff09\n- `server.allow_instance_management`: \u5141\u8bb8LLM\u7ba1\u7406\u5b9e\u4f8b\uff08\u9ed8\u8ba4\uff1afalse\uff09\n- `api.enabled`: \u662f\u5426\u542f\u52a8REST API\u670d\u52a1\u5668\uff08\u9ed8\u8ba4\uff1afalse\uff09\n- `api.port`: REST API\u7aef\u53e3\uff08\u9ed8\u8ba4\uff1a8001\uff09\n- `api.auto_find_port`: \u7aef\u53e3\u5360\u7528\u65f6\u81ea\u52a8\u9012\u589e\u67e5\u627e\u53ef\u7528\u7aef\u53e3\n- `api.enable_realtime_logs`: \u542f\u7528WebSocket\u5b9e\u65f6\u65e5\u5fd7 (ws://host:port/ws)\n- `logging.directory`: \u65e5\u5fd7\u76ee\u5f55\uff0c\u4f7f\u7528Minecraft\u98ce\u683c (latest-{mode}.txt + \u65f6\u95f4\u6233\u5907\u4efd)\n- `logging.level`: \u65e5\u5fd7\u7ea7\u522b\uff08DEBUG/INFO/WARNING/ERROR/OFF\uff09\n\n**\u6ce8\u610f**\uff1a\u4f20\u8f93\u6a21\u5f0f\uff08stdio/http/sse\uff09\u901a\u8fc7\u547d\u4ee4\u884c\u53c2\u6570\u6307\u5b9a\uff0c\u4e0d\u5728\u914d\u7f6e\u6587\u4ef6\u4e2d\u8bbe\u7f6e\u3002\n\n</details>\n\n### \u6dfb\u52a0MCP\u914d\u7f6e\n\n\u5728 `data/{provider}/mcp_settings.json` \u4e2d\u6dfb\u52a0MCP\u670d\u52a1\u5668\u914d\u7f6e\uff1a\n\n```json\n{\n  \"provider\": \"example\",\n  \"isActive\": true,\n  \"name\": \"example_instance\",\n  \"type\": \"stdio\",\n  \"command\": \"python\",\n  \"args\": [\"-m\", \"example_mcp\"],\n  \"env\": {}\n}\n```\n\n### \u8fd0\u884c\n\n```bash\n# \u76f4\u63a5\u6307\u5b9a\u4f20\u8f93\u6a21\u5f0f\npython main.py              # Stdio\u6a21\u5f0f\uff08\u9ed8\u8ba4\uff09\npython main.py stdio        # Stdio\u6a21\u5f0f\npython main.py http         # HTTP\u6a21\u5f0f\npython main.py sse          # SSE\u6a21\u5f0f\npython main.py api          # API\u670d\u52a1\u5668\u6a21\u5f0f\n\n# \u67e5\u770b\u5e2e\u52a9\npython main.py help\npython main.py -h\n```\n\n## MCP \u5de5\u5177\n\nMCP Router \u63d0\u4f9b\u4ee5\u4e0b\u5de5\u5177\u7ed9 LLM \u4f7f\u7528\uff1a\n\n**\u57fa\u7840\u5de5\u5177** (\u603b\u662f\u53ef\u7528):\n- `mcp.router.list()` - \u5217\u51fa\u6240\u6709\u5df2\u6ce8\u518c\u7684MCP\u5ba2\u6237\u7aef\u5b9e\u4f8b\n- `mcp.router.help()` - \u8fd4\u56de\u6240\u6709\u5b9e\u4f8b\u7684\u5de5\u5177\u5217\u8868\u548c\u4f7f\u7528\u8bf4\u660e\n- `mcp.router.use(instance_name)` - \u4f7f\u7528\u6307\u5b9a\u7684MCP\u5b9e\u4f8b\n- `mcp.router.call(instance_name, tool_name, **kwargs)` - \u8c03\u7528\u6307\u5b9a\u5b9e\u4f8b\u7684\u6307\u5b9a\u5de5\u5177\n\n**\u7ba1\u7406\u5de5\u5177** (\u9700\u542f\u7528 `allow_instance_management`):\n- `mcp.router.add(provider_name, config)` - \u52a8\u6001\u6dfb\u52a0\u65b0\u7684MCP\u914d\u7f6e\n- `mcp.router.remove(instance_name)` - \u79fb\u9664MCP\u914d\u7f6e\n- `mcp.router.enable(instance_name)` - \u542f\u7528MCP\u5b9e\u4f8b\n- `mcp.router.disable(instance_name)` - \u7981\u7528MCP\u5b9e\u4f8b\n\n<details>\n<summary><b>\ud83d\udce1 REST API \u7aef\u70b9</b></summary>\n\n\u5f53 API \u6a21\u5f0f\u542f\u7528\u65f6\uff0c\u53ef\u901a\u8fc7\u4ee5\u4e0b\u7aef\u70b9\u7ba1\u7406 MCP Router\uff1a\n\n**\u5b9e\u4f8b\u7ba1\u7406**:\n- `GET /api/instances` - \u5217\u51fa\u6240\u6709\u5b9e\u4f8b\n- `GET /api/instances/{name}` - \u83b7\u53d6\u5b9e\u4f8b\u8be6\u60c5\n- `POST /api/instances` - \u6dfb\u52a0\u65b0\u5b9e\u4f8b\n- `PATCH /api/instances/{name}` - \u66f4\u65b0\u5b9e\u4f8b\u914d\u7f6e\n- `DELETE /api/instances/{name}` - \u5220\u9664\u5b9e\u4f8b\n- `POST /api/instances/{name}/enable` - \u542f\u7528\u5b9e\u4f8b\n- `POST /api/instances/{name}/disable` - \u7981\u7528\u5b9e\u4f8b\n\n**\u5de5\u5177\u7ba1\u7406**:\n- `GET /api/tools` - \u5217\u51fa\u6240\u6709\u5de5\u5177\n- `GET /api/tools/{instance_name}` - \u83b7\u53d6\u5b9e\u4f8b\u7684\u5de5\u5177\u5217\u8868\n- `POST /api/call` - \u8c03\u7528\u5de5\u5177\n\n**\u5176\u4ed6**:\n- `GET /` - \u670d\u52a1\u72b6\u6001\n- `GET /health` - \u5065\u5eb7\u68c0\u67e5\n- `GET /api/config` - \u83b7\u53d6\u914d\u7f6e\n- `WS /ws` - \u5b9e\u65f6\u65e5\u5fd7\u6d41 (\u9700\u542f\u7528 `enable_realtime_logs`)\n\n</details>\n\n## \u4e0e LLM \u96c6\u6210\n\n### Stdio \u6a21\u5f0f\uff08\u63a8\u8350\uff09\n\n\u9002\u7528\u4e8e\u5355\u4e2aLLM\u5ba2\u6237\u7aef\uff08\u5982Claude Desktop\u3001Cursor\uff09\u3002\n\n**\u5ba2\u6237\u7aef\u914d\u7f6e\u793a\u4f8b** (mcp.json):\n```json\n{\n  \"mcpServers\": {\n    \"mcp_router\": {\n      \"command\": \"uv\",\n      \"args\": [\n        \"--directory\",\n        \"C:/path/to/mcp_router\",\n        \"run\",\n        \"python\",\n        \"main.py\"\n      ],\n      \"transport\": \"stdio\"\n    }\n  }\n}\n```\n\n### HTTP \u6a21\u5f0f\n\n\u9002\u7528\u4e8e\u591a\u5ba2\u6237\u7aef\u5e76\u53d1\u8fde\u63a5\uff08\u7aef\u53e3 3000\uff09\u3002\n\n**\u5ba2\u6237\u7aef\u914d\u7f6e\u793a\u4f8b** (mcp.json):\n```json\n{\n  \"mcpServers\": {\n    \"mcp_router_http\": {\n      \"url\": \"http://localhost:3000/mcp\",\n      \"transport\": \"streamableHttp\"\n    }\n  }\n}\n```\n\n<details>\n<summary><b>HTTP \u4f7f\u7528\u793a\u4f8b\uff08curl / Python\uff09</b></summary>\n\n**curl \u793a\u4f8b**:\n```bash\n# \u521d\u59cb\u5316\u4f1a\u8bdd\ncurl -X POST http://localhost:3000/mcp \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"jsonrpc\":\"2.0\",\"id\":0,\"method\":\"initialize\",\"params\":{\"protocolVersion\":\"2024-11-05\",\"capabilities\":{},\"clientInfo\":{\"name\":\"test\",\"version\":\"1.0.0\"}}}'\n\n# \u5217\u51fa\u5de5\u5177\ncurl -X POST http://localhost:3000/mcp \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/list\",\"params\":{}}'\n```\n\n**Python \u5ba2\u6237\u7aef\u793a\u4f8b**:\n```python\nimport httpx\n\nclass MCPHTTPClient:\n    def __init__(self, base_url=\"http://localhost:3000\"):\n        self.client = httpx.Client()\n        self.base_url = base_url\n        self.request_id = 0\n        self.initialized = False\n    \n    def call_method(self, method, params=None):\n        self.request_id += 1\n        response = self.client.post(f\"{self.base_url}/mcp\", json={\n            \"jsonrpc\": \"2.0\",\n            \"id\": self.request_id,\n            \"method\": method,\n            \"params\": params or {}\n        })\n        return response.json()\n    \n    def initialize(self):\n        result = self.call_method(\"initialize\", {\n            \"protocolVersion\": \"2024-11-05\",\n            \"capabilities\": {},\n            \"clientInfo\": {\"name\": \"python-client\", \"version\": \"1.0.0\"}\n        })\n        self.initialized = True\n        return result\n    \n    def list_tools(self):\n        if not self.initialized:\n            self.initialize()\n        return self.call_method(\"tools/list\")\n\n# \u4f7f\u7528\u793a\u4f8b\nclient = MCPHTTPClient()\ntools = client.list_tools()\nprint(tools)\n```\n\n</details>\n\n### SSE \u6a21\u5f0f\n\n\u9002\u7528\u4e8e\u5b9e\u65f6\u63a8\u9001\u573a\u666f\uff08\u7aef\u53e3 3001\uff09\u3002\n\n**\u5ba2\u6237\u7aef\u914d\u7f6e\u793a\u4f8b** (mcp.json):\n```json\n{\n  \"mcpServers\": {\n    \"mcp_router_sse\": {\n      \"url\": \"http://localhost:3001/sse\",\n      \"transport\": \"sse\"\n    }\n  }\n}\n```\n\n<details>\n<summary><b>SSE JavaScript \u5ba2\u6237\u7aef\u793a\u4f8b</b></summary>\n\n```javascript\nimport { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport { SSEClientTransport } from \"@modelcontextprotocol/sdk/client/sse.js\";\n\nconst transport = new SSEClientTransport(\n  new URL(\"http://localhost:3001/sse\")\n);\nconst client = new Client(\n  { name: \"my-client\", version: \"1.0.0\" }, \n  { capabilities: {} }\n);\n\nawait client.connect(transport);\nconst tools = await client.listTools();\nconsole.log(tools);\n```\n\n</details>\n\n### REST API \u6a21\u5f0f\n\n\u72ec\u7acb\u7684\u914d\u7f6e\u7ba1\u7406\u63a5\u53e3\uff08\u7aef\u53e3 8001\uff09\u3002\n\n```bash\n# \u5355\u72ec\u542f\u52a8API\u6a21\u5f0f\npython main.py api\n\n# \u6216\u5728\u4efb\u610fMCP\u6a21\u5f0f\u4e0b\u540c\u65f6\u542f\u7528API\uff08\u9700config.json\u4e2d\u914d\u7f6eapi.enabled: true\uff09\npython main.py http\n```\n\n<details>\n<summary><b>REST API \u4f7f\u7528\u793a\u4f8b</b></summary>\n\n**curl \u793a\u4f8b**:\n```bash\n# \u5217\u51fa\u6240\u6709\u5b9e\u4f8b\ncurl http://localhost:8001/api/instances \\\n  -H \"Authorization: Bearer your-token\"\n\n# \u8c03\u7528\u5de5\u5177\ncurl -X POST http://localhost:8001/api/call \\\n  -H \"Authorization: Bearer your-token\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"instance\": \"openai_doc\", \"tool\": \"read_project_oas\", \"params\": {}}'\n```\n\n**Python \u5ba2\u6237\u7aef\u793a\u4f8b**:\n```python\nimport httpx\n\nclient = httpx.Client(\n    base_url=\"http://localhost:8001\",\n    headers={\"Authorization\": \"Bearer your-token\"}\n)\n\n# \u5217\u51fa\u5b9e\u4f8b\ninstances = client.get(\"/api/instances\").json()\n\n# \u8c03\u7528\u5de5\u5177\nresult = client.post(\"/api/call\", json={\n    \"instance\": \"openai_doc\",\n    \"tool\": \"read_project_oas\",\n    \"params\": {}\n}).json()\n```\n\n</details>\n\n### \u6df7\u5408\u6a21\u5f0f\uff08MCP + API\uff09\n\n\u540c\u65f6\u8fd0\u884cMCP\u670d\u52a1\u5668\u548cREST API\uff0c\u4f7f\u7528\u72ec\u7acb\u7aef\u53e3\u4e92\u4e0d\u5e72\u6270\u3002\n\n**\u914d\u7f6e**:\n```json\n{\n  \"api\": {\"enabled\": true, \"port\": 8001},\n  \"server\": {\n    \"host\": \"0.0.0.0\",\n    \"http\": {\"enabled\": true, \"port\": 3000}\n  }\n}\n```\n\n**\u542f\u52a8**:\n```bash\npython main.py http  # MCP@3000 + API@8001\n```\n\n## \u5f00\u53d1\n\n### \u4ee3\u7801\u98ce\u683c\n\n\u672c\u9879\u76ee\u4f7f\u7528 [Ruff](https://github.com/astral-sh/ruff) \u8fdb\u884c\u4ee3\u7801\u683c\u5f0f\u5316\u548c linting\uff1a\n\n```bash\n# \u683c\u5f0f\u5316\u4ee3\u7801\nruff format .\n\n# \u68c0\u67e5\u4ee3\u7801\nruff check .\n\n# \u81ea\u52a8\u4fee\u590d\nruff check --fix .\n```\n\n<details>\n<summary><b>\ud83e\uddea \u8fd0\u884c\u6d4b\u8bd5</b></summary>\n\n```bash\n# \u8fd0\u884c\u6240\u6709\u6d4b\u8bd5\npytest\n\n# \u8fd0\u884c\u7279\u5b9a\u6d4b\u8bd5\npytest test/test_router.py\n\n# \u5e26\u8986\u76d6\u7387\npytest --cov=src --cov-report=html\n```\n\n</details>\n\n## \u5b89\u5168\u6027\n\n- **\u8f93\u5165\u9a8c\u8bc1**: \u9632\u6b62SQL\u6ce8\u5165\u3001XSS\u653b\u51fb\u3001\u8def\u5f84\u904d\u5386\n- **Bearer Token**: \u53ef\u9009\u7684API\u8ba4\u8bc1\n- **CORS\u914d\u7f6e**: \u7075\u6d3b\u7684\u8de8\u57df\u8bf7\u6c42\u63a7\u5236\n- **\u6587\u4ef6\u5927\u5c0f\u9650\u5236**: \u9632\u6b62DOS\u653b\u51fb\n- **HTTP\u5b89\u5168\u5934**: X-Frame-Options, CSP, HSTS\u7b49\n\n## \u8bb8\u53ef\u8bc1\n\n[MIT License](LICENSE)\n\n## \u8d21\u732e\n\n\u6b22\u8fce\u63d0\u4ea4 Issue \u548c Pull Request\uff01\n\n\u8bf7\u786e\u4fdd\uff1a\n- \u4ee3\u7801\u901a\u8fc7 `ruff` \u68c0\u67e5\n- \u6dfb\u52a0\u6216\u66f4\u65b0\u76f8\u5173\u6d4b\u8bd5\n- \u66f4\u65b0\u6587\u6863\uff08\u5982\u679c\u9700\u8981\uff09\n\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "A routing/proxy system for MCP servers",
    "version": "1.0.8",
    "project_urls": {
        "Documentation": "https://github.com/ChuranNeko/mcp_router#readme",
        "Homepage": "https://github.com/ChuranNeko/mcp_router",
        "Issues": "https://github.com/ChuranNeko/mcp_router/issues",
        "Repository": "https://github.com/ChuranNeko/mcp_router"
    },
    "split_keywords": [
        "ai",
        " llm",
        " mcp",
        " proxy",
        " router"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "cacaacadd20ec6e6464aae5000ecb9459be0268a64aa1ef1f3cb4b035e35368f",
                "md5": "5f84232aee5486fc5e6e225462054150",
                "sha256": "0967b00ddf76171065d51faec327952844e2b2f3bf2ddbb747abfefac919e427"
            },
            "downloads": -1,
            "filename": "mcp_router-1.0.8-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "5f84232aee5486fc5e6e225462054150",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.10",
            "size": 33439,
            "upload_time": "2025-10-29T04:26:19",
            "upload_time_iso_8601": "2025-10-29T04:26:19.033796Z",
            "url": "https://files.pythonhosted.org/packages/ca/ca/acadd20ec6e6464aae5000ecb9459be0268a64aa1ef1f3cb4b035e35368f/mcp_router-1.0.8-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "e28a7e364a9e0444397f20ae358a2b53db535445b2aadbce24d8cb60c5b1e889",
                "md5": "5e22dd4d23823a5ac44e5aef86ab631c",
                "sha256": "0898f166046919835f0f7913e93827ac1a885bcc69bf109e3fe425f74abd8c14"
            },
            "downloads": -1,
            "filename": "mcp_router-1.0.8.tar.gz",
            "has_sig": false,
            "md5_digest": "5e22dd4d23823a5ac44e5aef86ab631c",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.10",
            "size": 26839,
            "upload_time": "2025-10-29T04:26:22",
            "upload_time_iso_8601": "2025-10-29T04:26:22.198105Z",
            "url": "https://files.pythonhosted.org/packages/e2/8a/7e364a9e0444397f20ae358a2b53db535445b2aadbce24d8cb60c5b1e889/mcp_router-1.0.8.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-10-29 04:26:22",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "ChuranNeko",
    "github_project": "mcp_router#readme",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "requirements": [
        {
            "name": "fastapi",
            "specs": [
                [
                    ">=",
                    "0.104.0"
                ]
            ]
        },
        {
            "name": "uvicorn",
            "specs": [
                [
                    ">=",
                    "0.24.0"
                ]
            ]
        },
        {
            "name": "httpx",
            "specs": [
                [
                    ">=",
                    "0.25.0"
                ]
            ]
        },
        {
            "name": "pydantic",
            "specs": [
                [
                    ">=",
                    "2.0.0"
                ]
            ]
        },
        {
            "name": "watchdog",
            "specs": [
                [
                    ">=",
                    "3.0.0"
                ]
            ]
        },
        {
            "name": "python-dotenv",
            "specs": [
                [
                    ">=",
                    "1.0.0"
                ]
            ]
        },
        {
            "name": "mcp",
            "specs": [
                [
                    ">=",
                    "1.0.0"
                ]
            ]
        },
        {
            "name": "starlette",
            "specs": [
                [
                    ">=",
                    "0.27.0"
                ]
            ]
        },
        {
            "name": "pytest",
            "specs": [
                [
                    ">=",
                    "7.0.0"
                ]
            ]
        },
        {
            "name": "pytest-asyncio",
            "specs": [
                [
                    ">=",
                    "0.21.0"
                ]
            ]
        }
    ],
    "lcname": "mcp-router"
}
        
Elapsed time: 1.75375s