MCP网关
一个功能齐全的模型上下文协议(MCP)网关,具有用于注册和管理本地和远程MCP服务器的web UI,包括对Atlassian、GitHub等远程服务器的自动OAuth 2.0身份验证。
概述
MCP网关充当一个集中式代理和聚合器,连接到多个MCP服务器,并通过一个统一的界面公开它们的工具、资源和提示。它提供:
- 网页用户界面 用于注册、配置和监视MCP服务器
- 本地服务器支持 通过stdio传输(生成子进程)
- 远程服务器支持 通过SSE和流式HTTP传输
- 灵活的身份验证 -支持多种身份验证模式:带有自动身份验证、静态承载令牌、API密钥和自定义头的OAuth 2.0
- OAuth 2.0自动发现 --只需提供服务器URL(例如。
https://mcp.atlassian.com/v1/mcp)网关通过以下方式自动发现授权端点.well-known/oauth-authorization-server和.well-known/oauth-protected-resource - PKCE+动态客户端注册 --支持预先注册的客户端ID和RFC 7591开箱即用的动态注册
- 承载令牌支持 --适用于需要预认证令牌的GitHub Copilot MCP等API
- 实时状态更新 通过服务器发送事件(SSE)
- 自动重新连接 指数回退
- 持久配置 以JSON格式存储在磁盘上
建筑
┌─────────────────────────────────────────────────────────┐
│ MCP Gateway │
│ │
│ ┌──────────┐ ┌──────────┐ ┌────────────────────┐ │
│ │ React UI │ │ REST API │ │ OAuth Handler │ │
│ │ (Vite) │◄►│ (Express)│◄►│ (Auth Code + PKCE) │ │
│ └──────────┘ └────┬─────┘ └────────────────────┘ │
│ │ │
│ ┌──────┴──────┐ │
│ │ Gateway │ │
│ │ Engine │ │
│ └──────┬──────┘ │
│ │ │
│ ┌────────────────┼─────────────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌──────┐ ┌──────────┐ ┌──────────────┐ │
│ │stdio │ │ SSE │ │ Streamable │ │
│ │Client│ │ Client │ │ HTTP Client │ │
│ └──┬───┘ └────┬─────┘ └──────┬───────┘ │
└────┼──────────────┼──────────────────┼──────────────────┘
│ │ │
▼ ▼ ▼
┌─────────┐ ┌───────────┐ ┌───────────────┐
│ Local │ │ Remote │ │ Remote │
│ MCP │ │ MCP │ │ MCP │
│ Server │ │ Server │ │ Server │
│ (stdio) │ │ (SSE) │ │ (HTTP) │
└─────────┘ │ + OAuth │ │ + OAuth │
└───────────┘ └───────────────┘关键组件
| 组件 | 路径 | 描述 |
|---|---|---|
| 服务器条目 | src/server/index.ts | 快速应用程序设置、启动和优雅关闭 |
| 网关引擎 | src/server/gateway.ts | 核心逻辑:连接到MCP服务器,发现功能,管理生命周期 |
| API路线 | src/server/api.ts | CRUD、连接控制、工具调用和SSE事件的REST端点 |
| OAuth管理器 | src/server/oauth.ts | OAuthClientProvider 由MCP SDK的本地身份验证流支持的实现,具有自动发现功能 |
| 商店 | src/server/store.ts | 基于JSON文件的服务器配置和OAuth状态持久化 |
| 类型 | src/server/types.ts | 共享TypeScript类型定义 |
| React应用程序 | src/client/App.tsx | 具有服务器列表、统计数据和模式管理的主UI组件 |
| 服务器卡 | src/client/components/ServerCard.tsx | 显示单个服务器的状态、功能和操作 |
| 添加模态 | src/client/components/AddServerModal.tsx | 注册新本地或远程服务器的表格 |
| 编辑模态 | src/client/components/EditServerModal.tsx | 更新现有服务器配置的表单 |
| API客户端 | src/client/api.ts | 所有API终结点的类型化获取包装器 |
入门指南
先决条件
- Node.js >=18.x
- npm >=9.x
安装
# Clone the repository
git clone mcp-gateway
cd mcp-gateway
# Install dependencies
npm install发展
同时运行API服务器和Vite-dev服务器:
npm run dev这将开始:
- API服务器 上
http://localhost:3099 - UI开发服务器 上
http://localhost:5173(带有API的代理)
打开 http://localhost:5173 在您的浏览器中。
生产建设
# Build both client and server
npm run build
# Start the production server (serves the UI as static files)
npm start生产服务器在端口上运行 3099 默认情况下,它从构建的静态文件中提供UI。
使用PM2作为后台服务运行
PM2 是Node.js的进程管理器,它使网关在后台运行,在崩溃时重新启动,并可以在系统启动时自动启动。
全局安装PM2:
npm install -g pm2构建,然后通过附带的生态系统配置开始:
npm run build
npm run pm2:start这 ecosystem.config.cjs 项目根目录下的文件配置流程名称、日志文件位置、时间戳和自动重启行为。日志被写入 logs/mcp-gateway.log 在项目目录中。
其他有用的命令:
| 动作 | npm脚本 | pm2等效 |
|---|---|---|
| 开始 | npm run pm2:start | pm2 start ecosystem.config.cjs |
| 停下 | npm run pm2:stop | pm2 stop ecosystem.config.cjs |
| 重新启动 | npm run pm2:restart | pm2 restart ecosystem.config.cjs |
| 查看日志 | pm2 logs mcp-gateway | |
| 进程列表 | pm2 status |
系统启动时自动启动:
至少启动一次该过程后,运行:
pm2 save # snapshot the current process list
pm2 startup # generate and register the startup scriptpm2 startup 将打印一个要运行的命令(使用 sudo)--复制并执行它。之后,PM2和网关将自动重启。
注: 生态系统配置运行npm start,这需要生产构建(npm run build)先存在。请勿将PM2指向npm run dev对于持久服务,开发服务器(Vite+tsx-watch)不适合长时间运行的后台操作。
配置
环境变量
| 变量 | 默认值 | 描述 |
|---|---|---|
PORT | 3099 | API/HTTP服务器的端口 |
HOST | 0.0.0.0 | 将服务器绑定到的主机 |
GATEWAY_BASE_URL | http://localhost:3099 | 网关的公共URL(用于OAuth回调) |
DATA_DIR | ./data | 持久存储目录 |
数据存储
服务器配置和OAuth令牌存储在 data/gateway-store.json。此文件在首次运行时自动创建。您可以根据需要备份或版本控制此文件。
安全说明: OAuth令牌(包括刷新令牌)存储在此文件中。确保在生产环境中具有适当的文件权限。
使用指南
添加本地MCP服务器(stdio)
- 点击 “添加服务器” 在右上角
- 选择 “本地服务器”
- 填写:
- 名字:友好名称(例如“文件系统服务器”) - 命令:可执行文件(例如。, npx) - 参数:命令参数(例如。, -y @modelcontextprotocol/server-filesystem /tmp) - 工作目录 (可选):在何处运行命令 - 环境变量 (可选):键值对
- 点击 “添加服务器”
网关将生成进程并通过stdio连接。
添加远程MCP服务器(SSE或流式HTTP)
- 点击 “添加服务器”
- 选择 “远程服务器”
- 选择传输协议:
- 上海证券交易所 (服务器发送事件)--适用于使用SSE传输的服务器 - 可流式传输的HTTP --适用于使用较新的Streamable HTTP传输的服务器
- 填写:
- 名字:一个友好的名字 - 统一资源定位符:服务器的端点URL - 自定义头 (可选):其他HTTP标头
- 点击 “添加服务器”
远程服务器的身份验证选项
网关支持远程MCP服务器的多种身份验证模式:
| 模式 | 用例 | 示例 |
|---|---|---|
| 无 | 无身份验证的公共服务器 | 开发/测试服务器 |
| OAuth | 实施MCP OAuth 2.0规范的服务器 | 符合Atlassian标准的MCP服务器 |
| 持有者 | 预认证的承载令牌 | GitHub Copilot MCP,自定义API |
| API密钥 | 自定义标头中的API密钥 | 第三方服务 |
| 自定义 | 任意身份验证标头 | 传统或自定义身份验证方案 |
使用OAuth添加远程服务器(例如Atlassian)
对于需要OAuth 2.0身份验证的远程MCP服务器(如 https://mcp.atlassian.com/v1/mcp):
- 按照上述步骤添加远程服务器
- 输入服务器URL(例如。
https://mcp.atlassian.com/v1/mcp) - 在 认证 部分,选择 OAuth
- 可选择填写:
- 客户端ID --如果服务器需要预先注册的OAuth应用程序,则需要;留空可自动尝试RFC 7591动态客户端注册 - 客户端密钥 (可选)——仅机密客户需要;公共客户端忽略了这一点 - 范围 (可选)--如果省略,则使用服务器的默认作用域
- 点击 “添加服务器”
就这样 你做 _不_ 需要手动输入授权URL、令牌URL或任何其他OAuth端点详细信息。网关通过获取服务器的数据自动发现它们 .well-known/oauth-authorization-server 和 .well-known/oauth-protected-resource 元数据——完全符合MCP规范的要求。
启用服务器或单击 验证,网关:
- 从以下位置发现OAuth授权服务器元数据
.well-known端点 - 如果未提供客户端ID,则尝试动态客户端注册
- 生成一个PKCE代码挑战,并将您重定向到授权页面
- 在回调时交换令牌的授权码
- 安全地存储令牌,并在令牌过期时自动刷新
您可以随时从服务器的详细信息面板中撤销令牌。
添加带有承载令牌的远程服务器(例如GitHub Copilot)
对于需要预认证承载令牌的API(如 https://api.githubcopilot.com/mcp/):
- 按照上述步骤添加远程服务器
- 输入服务器URL(例如。
https://api.githubcopilot.com/mcp/) - 在 认证 部分,选择 持有者
- 在中输入您的访问令牌 承载令牌 领域
- 点击 “添加服务器”
网关将包括令牌 Authorization: Bearer 每一个请求。
注: GitHub Copilot的MCP端点没有实现标准的OAuth发现端点(.well-known/oauth-authorization-server),因此OAuth自动发现不起作用。请使用Bearer令牌模式,并使用有效的GitHub Copilot访问令牌。添加具有API密钥的远程服务器
对于使用API密钥身份验证的服务:
- 按照上述步骤添加远程服务器
- 在 认证 部分,选择 API密钥
- 填写:
- API密钥 -您的API密钥值 - 标题名称 (可选)--默认为 X-API-Key - 值前缀 (可选)-例如。, ApiKey 发送 ApiKey your-key
- 点击 “添加服务器”
添加具有自定义标头的远程服务器
对于自定义身份验证方案:
- 按照上述步骤添加远程服务器
- 在 认证 部分,选择 自定义
- 添加一个或多个身份验证标头(键值对)
- 点击 “添加服务器”
这允许您为身份验证配置任意标头,例如自定义令牌、签名或多头身份验证方案。
管理服务器
UI中的每个服务器卡都提供:
- 状态指示器:已连接(绿色)、正在连接(黄色)、错误(红色)、已断开连接(灰色)、等待OAuth(蓝色)
- 启用/禁用切换:控制服务器是否应处于活动状态
- 连接/断开/重新连接:手动连接控制
- 编辑:修改服务器配置
- 删除:完全删除服务器
- 扩展:查看详细的配置、OAuth状态和发现的功能(工具、资源、提示)
API 参考
服务器管理
| 方法 | 端点 | 描述 |
|---|---|---|
GET | /api/servers | 列出所有服务器的状态 |
GET | /api/servers/:id | 获取特定服务器 |
POST | /api/servers | 注册新服务器 |
PATCH | /api/servers/:id | 更新服务器配置 |
DELETE | /api/servers/:id | 删除服务器 |
连接控制
| 方法 | 端点 | 描述 |
|---|---|---|
POST | /api/servers/:id/connect | 连接到服务器 |
POST | /api/servers/:id/disconnect | 断开与服务器的连接 |
POST | /api/servers/:id/reconnect | 重新连接到服务器 |
POST | /api/servers/:id/refresh | 刷新发现的功能 |
POST | /api/servers/:id/enable | 启用服务器 |
POST | /api/servers/:id/disable | 禁用服务器 |
OAuth
| 方法 | 端点 | 描述 |
|---|---|---|
GET | /api/servers/:id/auth/status | 检查OAuth状态 |
POST | /api/servers/:id/auth/initiate | 启动OAuth流(自动发现端点,返回auth URL) |
POST | /api/servers/:id/auth/revoke | 撤销OAuth令牌并清除存储状态 |
GET | /oauth/callback/:serverId | 每服务器OAuth重定向回调(自动处理) |
聚合能力
| 方法 | 端点 | 描述 |
|---|---|---|
GET | /api/tools | 列出连接服务器上的所有工具 |
GET | /api/resources | 列出连接服务器上的所有资源 |
GET | /api/prompts | 列出连接服务器上的所有提示 |
POST | /api/tools/call | 调用工具(自动路由或指定服务器) |
实时更新
| 方法 | 端点 | 描述 |
|---|---|---|
GET | /api/events | SSE网关事件流 |
GET | /api/health | 使用服务器统计信息进行健康检查 |
示例:通过API注册服务器
# Local server
curl -X POST http://localhost:3099/api/servers \
-H "Content-Type: application/json" \
-d '{
"name": "Filesystem Server",
"transport": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"],
"enabled": true
}'
# Remote server with OAuth (auto-discovery — no manual URLs needed!)
curl -X POST http://localhost:3099/api/servers \
-H "Content-Type: application/json" \
-d '{
"name": "Atlassian MCP",
"transport": "streamable-http",
"url": "https://mcp.atlassian.com/v1/mcp",
"auth": {
"mode": "oauth"
},
"enabled": true
}'
# Remote server with a pre-registered OAuth client ID
curl -X POST http://localhost:3099/api/servers \
-H "Content-Type: application/json" \
-d '{
"name": "My Remote MCP",
"transport": "sse",
"url": "https://mcp.example.com/sse",
"auth": {
"mode": "oauth",
"clientId": "my-client-id",
"clientSecret": "my-client-secret",
"scopes": ["read", "write"]
},
"enabled": true
}'
# Remote server with bearer token (e.g. GitHub Copilot)
curl -X POST http://localhost:3099/api/servers \
-H "Content-Type: application/json" \
-d '{
"name": "GitHub Copilot MCP",
"transport": "streamable-http",
"url": "https://api.githubcopilot.com/mcp/",
"auth": {
"mode": "bearer",
"token": "your-access-token-here"
},
"enabled": true
}'
# Remote server with API key
curl -X POST http://localhost:3099/api/servers \
-H "Content-Type: application/json" \
-d '{
"name": "My API Service",
"transport": "sse",
"url": "https://api.example.com/mcp",
"auth": {
"mode": "api-key",
"key": "your-api-key",
"headerName": "X-API-Key"
},
"enabled": true
}'
# Remote server with custom auth headers
curl -X POST http://localhost:3099/api/servers \
-H "Content-Type: application/json" \
-d '{
"name": "Custom Auth Server",
"transport": "streamable-http",
"url": "https://custom.example.com/mcp",
"auth": {
"mode": "custom",
"headers": {
"X-Custom-Token": "token-value",
"X-Tenant-ID": "my-tenant"
}
},
"enabled": true
}'技术栈
- 后端:Node.js、Express、TypeScript
- 前端:React 19,快速6,尾风CSS 3,清晰图标
- MCP-SDK:
@modelcontextprotocol/sdkv1.12+(原生OAuthClientProvider接口) - OAuth:使用PKCE的授权代码流(RFC 7636)、自动服务器元数据发现(RFC 8414/RFC 9728)、可选的动态客户端注册(RFC 7591)
- 存储:基于JSON文件的持久性
- 实时更新:服务器发送事件(SSE)
OAuth自动发现的工作原理
当您为远程服务器启用OAuth时,MCP SDK的传输层会处理整个流程:
- 401检测 --传输尝试连接。如果服务器返回
401 Unauthorized,身份验证流程开始。 - 受保护资源元数据 --SDK获取
/.well-known/oauth-protected-resource从服务器查找授权服务器URL。 - 授权服务器元数据 --SDK获取
/.well-known/oauth-authorization-server(RFC 8414)或回退到OpenID连接发现以了解authorization_endpoint,token_endpoint,registration_endpoint,支持的范围、PKCE方法等。 - 动态客户端注册 --如果没有
clientId如果提供了,SDK会尝试在发现的位置注册RFC 7591registration_endpoint. - PKCE授权 --生成代码验证器/挑战对,并将用户重定向到授权端点。
- 代币兑换 --同意后,回拨
/oauth/callback/{serverId}将授权码替换为令牌。 - 自动刷新 --在后续连接中,使用存储的刷新令牌透明地刷新过期的令牌。
项目结构
mcp-gateway/
├── src/
│ ├── server/ # Backend (Express + MCP SDK)
│ │ ├── index.ts # Server entry point
│ │ ├── gateway.ts # Core gateway engine
│ │ ├── api.ts # REST API routes
│ │ ├── oauth.ts # OAuth 2.0 handler
│ │ ├── store.ts # JSON file persistence
│ │ └── types.ts # Shared type definitions
│ └── client/ # Frontend (React + Vite)
│ ├── index.html # HTML entry
│ ├── main.tsx # React entry
│ ├── index.css # Tailwind + custom styles
│ ├── App.tsx # Main application component
│ ├── api.ts # API client
│ └── components/
│ ├── ServerCard.tsx # Server display card
│ ├── AddServerModal.tsx # Add server form
│ ├── EditServerModal.tsx # Edit server form
│ └── OAuthNotification.tsx # OAuth callback notification
├── data/ # Persistent storage (auto-created)
│ └── gateway-store.json # Server configs + OAuth state (tokens, client info, PKCE verifiers)
├── package.json
├── tsconfig.json
├── tsconfig.server.json
├── vite.config.ts
├── tailwind.config.js
├── postcss.config.js
└── README.md安全注意事项
- OAuth状态 (令牌、客户端信息、PKCE验证器)存储在磁盘上
data/gateway-store.json。限制生产中的文件权限。 - 客户机密 在API响应中被屏蔽(显示为
••••••••). - PKCE (代码交换的证明密钥)用于所有OAuth流,以防止授权代码被拦截。
- 每台服务器的回调URL (
/oauth/callback/{serverId})确保回调被路由到正确的提供者,而没有共享状态。 - OAuth元数据是 始终从服务器获取
.well-known端点 --不信任用户输入的手动端点URL。 - 网关的
OAuthClientProvider实现支持SDKinvalidateCredentials()回调以自动清除过时的令牌或客户端注册。 - 网关 不 通过UI或API响应公开MCP服务器凭据。
许可证
麻省理工学院
