MCP代理服务

一个无状态的HTTP代理服务,用于远程Model Context Protocol (MCP)服务器,通过RESTful API与MCP工具交互,无需直接使用JSON-RPC通信。

  • by manasnilorout
  • JavaScript
  • 本地部署
  • 更新于
在 GitHub 查看 manasnilorout/simple-mcp-proxy

使用说明

MCP代理服务

用于远程模型上下文协议(MCP)服务器的无状态HTTP代理服务。此服务公开了RESTful API以与MCP工具交互,而不需要直接JSON-RPC通信。

特性

  • RESTful API 用于MCP操作
  • 无状态设计 -无需会话管理
  • 多服务器支持 -配置多个MCP服务器
  • SSE到JSON转换 -服务器发送事件的自动处理
  • 标准错误代码 -HTTP兼容错误处理
  • 简单配置 -基于JSON的服务器配置

先决条件

  • Node.js 18.x或更高版本
  • 访问远程MCP服务器(基于HTTP)

安装

  1. 克隆或下载此存储库
  2. 安装依赖项:
npm install
  1. 创建服务器配置文件:
cp mcp.servers.example.json mcp.servers.json
  1. 编辑 mcp.servers.json 您的服务器详细信息:
{
  "mcpServers": {
    "MyMcpServer": {
      "url": "https://your-mcp-server.com/endpoint",
      "headers": {
        "Authorization": "Bearer your-token-here"
      },
      "type": "http"
    }
  }
}

配置

这 mcp.servers.json 文件定义了所有可用的MCP服务器:

  • mcpServers:包含服务器配置的对象
    • 钥匙:服务器名称(用于API路由)
    • 价值:服务器配置对象
      • url:MCP服务器端点URL
      • headers:要包含的HTTP标头(例如,身份验证)
      • type:必须是 "http" 用于远程服务器

用法

启动服务器:

npm start

对于自动重新加载的开发:

npm run dev

服务器将于启动 http://localhost:8080 (可通过以下方式配置 PORT 环境变量)。

API终点

1.列出服务器

列出所有已配置的MCP服务器。

请求:

GET /api/list-servers

答复:

{
  "servers": [
    {
      "name": "MyMcpServer",
      "url": "https://your-mcp-server.com/endpoint",
      "type": "http"
    }
  ],
  "count": 1
}

2.初始化服务器

初始化与MCP服务器的连接并检索服务器功能。服务器可能会返回一个会话ID,该ID必须在后续请求中使用。

请求:

POST /api/mcp/{server_name}/initialize

答复:

{
  "protocolVersion": "2024-11-05",
  "capabilities": {
    "tools": {
      "listChanged": true
    }
  },
  "serverInfo": {
    "name": "example-server",
    "version": "1.0.0"
  },
  "sessionId": "abc123-session-id-xyz"
}

响应标头:

Mcp-Session-Id: abc123-session-id-xyz

注: 保存 sessionId 从响应到在后续请求中使用。一些服务器(如GitHub MCP)需要它。

3.列出工具

从MCP服务器获取所有可用工具。

请求:

GET /api/mcp/{server_name}/tools?init=false

可选查询参数:

  • cursor:来自上一个响应的分页光标
  • init:在列出工具之前初始化会话(默认值: false)
    • true:首先初始化连接
    • false:跳过初始化(假设会话已初始化)
  • sessionId:初始化时的MCP会话ID(替代标头)

可选标题:

  • Mcp-Session-Id:初始化时的MCP会话ID

答复:

{
  "tools": [
    {
      "name": "get_weather",
      "description": "Get current weather for a location",
      "inputSchema": {
        "type": "object",
        "properties": {
          "location": {
            "type": "string",
            "description": "City name"
          }
        },
        "required": ["location"]
      }
    }
  ],
  "nextCursor": "optional-cursor-for-next-page"
}

4.执行工具

使用提供的参数执行特定工具。

请求:

POST /api/mcp/{server_name}/tools/{tool_name}/execute?init=false
Content-Type: application/json

{
  "location": "San Francisco",
  "units": "celsius"
}

可选查询参数:

  • init:在执行工具之前初始化会话(默认值: false)
    • true:首先初始化连接
    • false:跳过初始化(假设会话已初始化)
  • sessionId:初始化时的MCP会话ID(替代标头)

可选标题:

  • Mcp-Session-Id:初始化时的MCP会话ID

答复:

{
  "content": [
    {
      "type": "text",
      "text": "Temperature: 22°C, Conditions: Sunny"
    }
  ],
  "isError": false
}

错误处理

该服务返回标准HTTP错误代码:

  • 400错误请求:请求格式无效
  • 401未经授权:身份验证失败
  • 404未找到:找不到服务器或工具
  • 500内部服务器错误:服务器错误或MCP通信失败

错误响应格式:

{
  "error": "Error type",
  "message": "Detailed error message"
}

示例用法

使用cURL

列出服务器:

curl http://localhost:8080/api/list-servers

初始化服务器并获取会话ID:

# Initialize and capture session ID
RESPONSE=$(curl -i -X POST http://localhost:8080/api/mcp/MyMcpServer/initialize)
SESSION_ID=$(echo "$RESPONSE" | grep -i "mcp-session-id:" | cut -d' ' -f2 | tr -d '\r')

在后续请求中使用会话ID:

通过查询参数:

curl "http://localhost:8080/api/mcp/MyMcpServer/tools?sessionId=$SESSION_ID"

通过标题(推荐):

curl http://localhost:8080/api/mcp/MyMcpServer/tools \
  -H "Mcp-Session-Id: $SESSION_ID"

使用会话ID执行工具:

curl -X POST http://localhost:8080/api/mcp/MyMcpServer/tools/get_weather/execute \
  -H "Content-Type: application/json" \
  -H "Mcp-Session-Id: $SESSION_ID" \
  -d '{"location": "San Francisco"}'

一次性请求(在单次调用中初始化+执行):

curl -X POST "http://localhost:8080/api/mcp/MyMcpServer/tools/get_weather/execute?init=true" \
  -H "Content-Type: application/json" \
  -d '{"location": "San Francisco"}'

使用JavaScript/Refetch

// List tools
const response = await fetch('http://localhost:8080/api/mcp/MyMcpServer/tools');
const { tools } = await response.json();

// Execute a tool
const result = await fetch(
  'http://localhost:8080/api/mcp/MyMcpServer/tools/get_weather/execute',
  {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ location: 'San Francisco' })
  }
);
const data = await result.json();
console.log(data.content);

建筑

无状态设计

每个请求独立:

  1. 创建新的MCP客户端实例
  2. 可选地初始化与服务器的连接(由控制 init 查询参数)
  3. 执行请求的操作
  4. 返回结果

请求之间不保持会话状态。

会话管理:

  • 许多MCP服务器(例如GitHub)在初始化后需要所有请求的会话ID
  • 这 /initialize 端点返回a sessionId 在响应体和 Mcp-Session-Id 头球
  • 通过以下方式在后续请求中包含会话ID:
    • Mcp-Session-Id 标题(推荐)
    • sessionId 查询参数(可选)
  • 会话ID是特定于服务器的,可能会过期

初始化选项:

  • 选项1(推荐): 初始化一次,重用会话ID

    # 1. Initialize
    SESSION=$(curl -X POST .../initialize | jq -r '.sessionId')
    # 2. Use session for multiple requests
    curl .../tools -H "Mcp-Session-Id: $SESSION"
    curl .../tools/my_tool/execute -H "Mcp-Session-Id: $SESSION" -d '{...}'
    
  • 选项2: 一次性请求 init=true

    curl ".../tools?init=true"  # Initializes and lists tools in one call
    
  • 选项3: 不需要会话ID的服务器

    curl .../tools  # Works without initialization or session ID
    

SSE处理

代理自动检测来自MCP服务器的服务器发送事件(SSE)响应,并将其转换为标准JSON响应,将所有事件聚合为一个结果。

MCP协议

该代理实现了模型上下文协议2024-11-05规范,重点关注 工具 能力:

  • JSON-RPC 2.0消息格式
  • HTTP+SSE传输层
  • 工具发现和执行

故障排除

未找到配置文件:

Error: Configuration file not found

解决方案:创建 mcp.servers.json 从示例文件中。

无法访问服务器:

Error: MCP request failed: fetch failed

解决方案:检查服务器URL和网络连接。

身份验证失败:

Error: Authentication failed (401)

解决方案:验证服务器配置中的授权令牌。

未找到工具:

Error: Tool not found (404)

解决方案:使用 /tools 端点以列出可用工具。

发展

项目结构:

mcp-proxy/
├── src/
│   ├── index.js         # Express server and routes
│   ├── mcpClient.js     # MCP client implementation
│   └── config.js        # Configuration loader
├── mcp.servers.json     # Server configuration (gitignored)
├── mcp.servers.example.json
├── package.json
└── README.md

许可证

麻省理工学院

贡献

欢迎投稿!请确保:

  • 代码遵循现有样式
  • 所有路线都经过测试
  • 错误处理全面
  • 文档已更新