关于 MCP Gateway
MCP Gateway 是一个反向代理服务,可将客户端请求转发至后端 MCP 服务,或通过统一入口使用网关下的全部 MCP 服务。它支持 SSE 与 Streamable HTTP 两种传输协议,并提供 OAuth 2.1 资源服务器认证。
主要功能
- 01统一入口聚合多个 MCP 服务的工具与 SSE 流
- 02支持 SSE 与 Streamable HTTP 两种传输协议
- 03Streamable HTTP 下通过 Mcp-Session-Id 管理会话
- 04基于 Bearer Token 的认证,支持 OAuth 2.1 元数据发现
- 05通过 config.json 配置协议、认证与会话参数
适用场景
- 01将多个 MCP 服务部署在一个统一端点后供客户端调用
- 02为 MCP 服务添加 Bearer Token 或 OAuth 认证
- 03在本地开发时以无认证方式访问 MCP 服务
MCP 相关
该网关作为 MCP 服务的反向代理,向客户端暴露聚合后的工具列表与 SSE 或 Streamable HTTP 端点,并将请求转发至下游的各个 MCP 服务。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
MCP Gateway
描述
MCP 网关是一个反向代理服务,可将客户端的请求转发到 MCP 服务,也可以通过统一入口使用网关下的所有 MCP 服务。
支持两种传输协议(可在启动时切换):
- SSE(默认,旧版 MCP 传输协议)
- Streamable HTTP(MCP 规范
2025-03-26)
功能
- 部署多个 MCP 服务
- 连接到 MCP 服务
- 使用网关调用 MCP 服务
- 获取所有 MCP 服务的 SSE 流
- 获取所有 MCP 服务的工具
- 提供支持通过
Mcp-Session-Id标头管理会话的 Streamable HTTP 聚合端点 - 动态聚合能力(网关只公布至少一个下游 MCP 服务支持的能力)
- 支持通过受保护资源元数据发现进行 MCP OAuth 2.1 资源服务器身份验证
安装
- 拉取 GitHub 软件包
docker pull ghcr.io/lucky-aeon/mcp-gateway:latest
- 自行构建 Docker 镜像
docker build -t mcp-gateway .
使用
运行 GitHub Docker 容器
docker run -d --name mcp-gateway -p 8080:8080 ghcr.io/lucky-aeon/mcp-gateway
运行自行构建的 Docker 容器
docker run -d --name mcp-gateway -p 8080:8080 mcp-gateway
配置
网关会从配置目录读取 config.json(若存在 ./vm,则默认为该目录;否则默认为 .)。最简示例如下:
{
"LogLevel": 0,
"Bind": "[::]:8080",
"Auth": {
"Enabled": true,
"AuthorizationServers": ["https://auth.example.com"],
"TokenIssuer": "https://auth.example.com",
"TokenJWKSURI": "https://auth.example.com/.well-known/jwks.json",
"TokenAudience": "http://localhost:8080/stream",
"RequiredScopes": ["mcp:read"],
"ScopesSupported": ["mcp:read"]
},
"GatewayProtocol": "all",
"McpServiceMgrConfig": {
"McpServiceRetryCount": 3
}
}
关键字段:
| 字段 | 默认值 | 描述 |
|---|---|---|
Bind | [::]:8080 | 服务监听地址。 |
GatewayProtocol | all | 对外提供的网关协议:all、sse 或 streamhttp。也可通过 --protocol 标志覆盖。 |
Auth.Enabled | true | 是否强制进行身份验证。本地无需身份验证即可使用 MCP 时设为 false。 |
Auth.ApiKey | 123456 | 旧版单密钥管理 API 登录令牌;不用于 MCP 身份验证。 |
Auth.Mode | single-key | single-key 或 saas。SaaS 模式使用 MCP Gateway 账户和密码登录。 |
Auth.AuthorizationServers | 空 | 可选的外部 OAuth 颁发方 URL。SaaS 模式下若为空,网关将公布自身为授权服务器。 |
Auth.TokenIssuer | 第一个授权服务器 | MCP OAuth 访问令牌预期的 iss 声明。 |
Auth.TokenJWKSURI | 从颁发方发现 | 用于验证 JWT 访问令牌的 JWKS URL。 |
Auth.TokenIntrospectionURL | 空 | 不透明访问令牌的 RFC 7662 内省端点。若设置,则使用内省而非 JWKS。 |
Auth.TokenAudience | 请求资源 URL | 预期的 aud 声明。请配置为授权服务器使用的 MCP 资源指示符。 |
Auth.RequiredScopes | 空 | MCP 请求所需的作用域,并在 WWW-Authenticate 中公布。 |
Auth.ScopesSupported | 空 | 在受保护资源元数据中公布的作用域。 |
SessionGCInterval | 10s | 垃圾回收空闲代理会话的间隔。 |
ProxySessionTimeout | 1m | 垃圾回收前空闲代理会话的超时时间。 |
McpServiceMgrConfig.McpServiceRetryCount | 3 | MCP 服务失败后将其标记为 failed 前的最大重试次数。 |
选择网关协议
可在 config.json 中设置 GatewayProtocol:
{ "GatewayProtocol": "all" }
也可传入 CLI 标志(优先级更高):
./mcp-gateway --protocol=streamhttp
有效值:all(默认)、sse 或 streamhttp。
身份验证
当 Auth.Enabled 为 true 时,每个 MCP 协议请求都必须提供 Bearer 令牌:
Authorization: Bearer <access-token>
网关不再将 api_key、sessionId、Mcp-Session-Id 或 X-Session-Id 视为身份验证凭据。Mcp-Session-Id 仍是传输会话标识符,在经过身份验证的 Streamable HTTP 请求中,必须与 Bearer 令牌一同发送。
对于 MCP OAuth 发现,网关会提供 OAuth 受保护资源元数据:
GET /.well-known/oauth-protected-resource
GET /.well-known/oauth-protected-resource/stream
当 OAuth 发现可用时,未经授权的 MCP 请求会返回 401,并附带 WWW-Authenticate: Bearer ... resource_metadata="..." 挑战。若要在本地进行无需身份验证的开发,请将 Auth.Enabled 设为 false。
在 Auth.Mode = "saas" 且未配置外部 Auth.AuthorizationServers 时,网关会使用自身的账户系统进行 MCP 登录。发现信息会将网关源站公布为授权服务器,并提供:
GET /.well-known/oauth-authorization-server
POST /oauth/token
POST /oauth/register
/oauth/token 接受采用表单编码的 grant_type=password,以及 username/password,并返回与 /api/v1/auth/login 相同的网关 JWT。仅当需要使用 Keycloak、Auth0 或其他外部 OAuth 提供方时,才配置 Auth.AuthorizationServers。
基于浏览器的 MCP 客户端也可以使用公布的授权端点:
GET /oauth/authorize
内置授权端点会显示网关账户登录表单,并完成 OAuth 授权码流程,包括 PKCE。
/oauth/register 实现了精简的动态客户端注册,适用于 MCP Inspector 等客户端。
API
部署
支持:uvx、npx,或 SSE URL
POST /deploy HTTP/1.1
Host: localhost:8080
Content-Type: application/json
{
"mcpServers": {
"time": {
"url": "http://mcp-server:8080", // url 和 command 二选一
"command": "uvx", // url 和 command 二选一
"args": ["mcp-server-time", "--local-timezone=America/New_York"], // 可选,command 的参数
"env": { // 可选,环境变量
"KEY1": "VALUE1",
"KEY2": "VALUE2"
}
}
}
}
使用 MCP(SSE 模式)
当
GatewayProtocol为all(默认值)或sse时可用。
GET SSE
GET /{mcp-server-name}/sse HTTP/1.1
Host: localhost:8080
POST 消息
POST /{mcp-server-name}/message HTTP/1.1
Host: localhost:8080
Content-Type: application/json
{
"method": "tools/call",
"params": {
"name": "get_current_time",
"arguments": {
"timezone": "Asia/Seoul"
}
},
"jsonrpc": "2.0",
"id": 2
}
使用网关(SSE 模式)
当
GatewayProtocol为all(默认值)或sse时可用。
网关与直连 MCP 的区别在于,你只需与网关交互,网关会自动将请求转发到对应的 MCP 服务。调用时,需要在 method 前面添加 mcpServerName,用于标识该请求来自哪个 MCP 服务。
GET SSE
GET /sse HTTP/1.1
Host: localhost:8080
这里的 SSE 是整个网关下所有 MCP 服务的 SSE 流。
当客户端订阅 SSE 时,网关会为每个 MCP 服务创建一个 SSE 连接,并将所有 MCP 服务的 SSE 流合并到一起。
在所有 tools/call 响应的结果中,都会在 method 前面添加 mcpServerName,用于标识该结果来自哪个 MCP 服务。
POST 消息
POST /message HTTP/1.1
Host: localhost:8080
Content-Type: application/json
{
"method": "tools/call",
"params": {
"name": "{mcp-server-name}-get_current_time",
"arguments": {
"timezone": "Asia/Seoul"
}
},
"jsonrpc": "2.0",
"id": 2
}
获取网关下的所有工具
POST /message HTTP/1.1
Host: localhost:8080
Content-Type: application/json
{
"method": "tools/list",
"jsonrpc": "2.0",
"id": 1
}
# SSE 响应 message event
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"tools": [
{
"name": "{mcpServerName}-get_current_time",
"description": "Get current time in a specific timezones",
"inputSchema": {
"type": "object",
"properties": {
"timezone": {
"type": "string",
"description": "IANA timezone name (e.g., 'America/New_York', 'Europe/London'). Use 'America/New_York' as local timezone if no timezone provided by the user."
}
},
"required": [
"timezone"
]
}
},
{
"name": "{mcpServerName}-convert_time",
"description": "Convert time between timezones",
"inputSchema": {
"type": "object",
"properties": {
"source_timezone": {
"type": "string",
"description": "Source IANA timezone name (e.g., 'America/New_York', 'Europe/London'). Use 'America/New_York' as local timezone if no source timezone provided by the user."
},
"time": {
"type": "string",
"description": "Time to convert in 24-hour format (HH:MM)"
},
"target_timezone": {
"type": "string",
"description": "Target IANA timezone name (e.g., 'Asia/Tokyo', 'America/San_Francisco'). Use 'America/New_York' as local timezone if no target timezone provided by the user."
}
},
"required": [
"source_timezone",
"time",
"target_timezone"
]
}
}
]
}
}
使用网关(Streamable HTTP 模式)
当
GatewayProtocol为all(默认值)或streamhttp时可用。实现规范
2025-03-26中定义的 MCP Streamable HTTP 传输。网关提供单一聚合端点/stream,支持POST、GET和DELETE。会话标识符通过 HTTP 标头Mcp-Session-Id传递。
1. 建立会话(初始化)
POST /stream HTTP/1.1
Host: localhost:8080
Authorization: Bearer <access-token>
Accept: application/json, text/event-stream
Content-Type: application/json
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-03-26",
"capabilities": {},
"clientInfo": {"name": "my-client", "version": "1.0.0"}
}
}
响应:
HTTP/1.1 200 OK
Content-Type: application/json
Mcp-Session-Id: 7782f2f9-563c-4379-b961-df06e49e54c0
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2025-03-26",
"serverInfo": {"name": "mcp-gateway", "version": "1.0.0"},
"capabilities": { /* OR-merged from all downstream MCP servers */ },
"instructions": "MCP Gateway aggregates multiple MCP servers. Tools are namespaced as <serverName>_<toolName>."
}
}
保留返回的 Mcp-Session-Id,并在后续每个请求中发送。
2. 完成握手(通知)
POST /stream HTTP/1.1
Host: localhost:8080
Authorization: Bearer <access-token>
Content-Type: application/json
Mcp-Session-Id: 7782f2f9-563c-4379-b961-df06e49e54c0
{"jsonrpc": "2.0", "method": "notifications/initialized"}
响应:202 Accepted(空响应体)。
3. 调用工具或列出资源
POST /stream HTTP/1.1
Host: localhost:8080
Authorization: Bearer <access-token>
Accept: application/json, text/event-stream
Content-Type: application/json
Mcp-Session-Id: 7782f2f9-563c-4379-b961-df06e49e54c0
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "{mcp-server-name}_get_current_time",
"arguments": {"timezone": "Asia/Seoul"}
}
}
聚合工具名称遵循 <serverName>_<toolName> 模式,与 SSE 网关模式使用相同的规则。
响应会同步返回在 HTTP 响应体中:
{"jsonrpc": "2.0", "id": 2, "result": { /* ... */ }}
通知(不含 id 的 JSON-RPC 消息)会收到 202 Accepted 响应,并以异步方式转发。
4. 订阅服务器发起的事件(可选)
GET /stream HTTP/1.1
Host: localhost:8080
Authorization: Bearer <access-token>
Accept: text/event-stream
Mcp-Session-Id: 7782f2f9-563c-4379-b961-df06e49e54c0
网关会保持连接打开,并为服务器 → 客户端的 JSON-RPC 请求和通知(例如进度更新、日志消息)发送 event: message 帧。JSON-RPC 响应不会在此推送,而是通过发起该请求的 POST /stream 请求的 HTTP 响应返回。
以 : 开头的行是 SSE 保活注释,可以忽略。
5. 关闭会话
DELETE /stream HTTP/1.1
Host: localhost:8080
Authorization: Bearer <access-token>
Mcp-Session-Id: 7782f2f9-563c-4379-b961-df06e49e54c0
响应:200 OK。
单服务器直通
在 Streamable HTTP 模式下,你也可以直接访问单个 MCP 服务:
POST /{mcp-server-name} HTTP/1.1
GET /{mcp-server-name} HTTP/1.1
网关会将请求转发到目标 MCP 的 message 端点。在此模式下,会话管理由下游服务负责。
使用 MCP Inspector 连接
- 在 Inspector 中选择 传输类型:
Streamable HTTP。 - URL:
http://localhost:8080/stream。 - 在授权服务器中完成 OAuth 流程,并提供
Authorization: Bearer <access-token>。 - 点击 连接。Inspector 会自动处理
Mcp-Session-Id交换。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。