go-mcp网关
用于MCP(模型上下文协议)服务器的OAuth 2.0授权协助器和反向代理网关。该网关使用PKC实现了RFC 6749 OAuth 2.0授权代码流,与Google OIDC集成用于用户身份验证,并将Google访问令牌转发给客户端以访问受保护的MCP资源。
特性
- OAuth 2.0授权服务器:使用PKCE完全实现RFC 6749(RFC 7636)
- 动态客户端注册:符合RFC 7591的客户端注册
- 谷歌OIDC集成:通过Google对用户进行身份验证并转发Google令牌
- 令牌验证:在代理请求之前验证Google访问令牌
- 反向代理:将经过身份验证的请求路由到配置的MCP服务器
- 元数据发现:OAuth 2.0授权服务器元数据(RFC 8414)
- Redis支持的存储:会话管理和OAuth状态存储
- 安全:没有长期存储谷歌凭据,PKCE强制执行
建筑
关键组件
- 身份验证层 (
internal/auth/):OAuth 2.0授权服务器,具有客户端注册、授权码和令牌管理功能 - 处理程序层 (
internal/handler/):OAuth端点和元数据发现的HTTP处理程序 - 谷歌提供商 (
internal/provider/google/):Google OIDC与状态/随机数验证的集成 - 存储层 (
internal/store/):Redis抽象,带命名空间和TTL管理 - 中间件 (
internal/middleware/googletokenvalidator/):谷歌访问令牌验证
运作原理
- 客户注册:客户端向网关注册以接收OAuth凭据
- 授权:客户端启动OAuth流,网关重定向到Google进行身份验证
- 代币交换:经过Google身份验证后,网关将Google的访问/刷新令牌返回给客户端
- 受保护访问:客户端使用Google令牌访问代理的MCP端点
- 令牌刷新:客户端可以使用Google刷新令牌刷新过期的令牌
网关充当 OAuth协调员 -它不发行自己的代币,而是将谷歌的代币转发给客户。这可确保MCP服务器收到有效的Google凭据,以代表经过身份验证的用户访问Google资源。
先决条件
- 达到1.21或更高
- Redis服务器
- 谷歌OAuth 2.0证书
入门指南
1.设置Google OAuth凭据
- 首选 谷歌云控制台
- 创建新项目或选择现有项目
- 启用Google+API
- 创建OAuth 2.0凭据(OAuth客户端ID)
- 添加授权重定向URI:
http://localhost:8080/oauth/callback
2.配置环境变量
创建一个 .env 项目根目录中的文件:
ALLOWED_ORIGINS=*
BASE_URL=http://localhost:8080
PORT=8080
REDIS_ADDR=localhost:6379
REDIS_PASSWORD=
OAUTH_GOOGLE_CLIENT_ID=your-google-client-id
OAUTH_GOOGLE_CLIENT_SECRET=your-google-client-secret
OAUTH_GOOGLE_REDIRECT_URI=http://localhost:8080/oauth/callback
OAUTH_GOOGLE_SCOPES=openid,profile,email3.配置代理路由
编辑 config.yaml 要定义MCP服务器端点,请执行以下操作:
proxies:
- pattern: "/calc/mcp"
target_url: "http://localhost:3000/mcp"
- pattern: "/files/mcp"
target_url: "http://localhost:3001/mcp"4.启动Redis
redis-server5.运行网关
开发模式:
go run cmd/server/main.go或者构建并运行:
go build -o bin/server cmd/server/main.go
./bin/server服务器将于启动 http://localhost:8080 (或您配置的端口)。
部署选项
Kubernetes with Helm(推荐用于生产环境)
使用附带的Helm chart部署到Kubernetes:
# Install from GitHub Container Registry (recommended)
helm install my-gateway oci://ghcr.io/schnurbus/go-mcp-gateway \
--version 0.1.0 \
--set config.oauth.google.clientId=YOUR_CLIENT_ID \
--set config.oauth.google.clientSecret=YOUR_CLIENT_SECRET
# Or install from local chart
helm install my-gateway ./chart \
--set config.oauth.google.clientId=YOUR_CLIENT_ID \
--set config.oauth.google.clientSecret=YOUR_CLIENT_SECRET
# Production install with custom values
helm install my-gateway oci://ghcr.io/schnurbus/go-mcp-gateway \
--version 0.1.0 \
-f values-prod.yaml看 Helm Chart自述 了解详细的配置选项。
Docker部署
使用GHCR的预构建图像
从GitHub容器注册表中提取最新图像:
docker pull ghcr.io/schnurbus/go-mcp-gateway:latest或者拉取一个特定版本:
docker pull ghcr.io/schnurbus/go-mcp-gateway:v1.0.0使用预构建的镜像运行Docker Compose:
docker-compose -f docker-compose.prod.yml up -d使用Docker Compose进行开发(推荐)
使用Redis运行网关的最简单方法:
# Build and start services
docker-compose up -d
# View logs
docker-compose logs -f gateway
# Stop services
docker-compose down
# Stop and remove volumes
docker-compose down -v确保你的 .env 文件是在运行docker compose之前配置的。
使用Docker
塑造形象:
docker build -t go-mcp-gateway .使用外部Redis实例运行:
docker run -d \
--name go-mcp-gateway \
-p 8080:8080 \
-e BASE_URL=http://localhost:8080 \
-e REDIS_ADDR=host.docker.internal:6379 \
-e OAUTH_GOOGLE_CLIENT_ID=your-client-id \
-e OAUTH_GOOGLE_CLIENT_SECRET=your-client-secret \
-e OAUTH_GOOGLE_REDIRECT_URI=http://localhost:8080/oauth/callback \
go-mcp-gateway使用Docker网络和Redis容器运行:
# Create network
docker network create mcp-network
# Start Redis
docker run -d \
--name redis \
--network mcp-network \
redis:7-alpine
# Start gateway
docker run -d \
--name go-mcp-gateway \
--network mcp-network \
-p 8080:8080 \
-e BASE_URL=http://localhost:8080 \
-e REDIS_ADDR=redis:6379 \
-e OAUTH_GOOGLE_CLIENT_ID=your-client-id \
-e OAUTH_GOOGLE_CLIENT_SECRET=your-client-secret \
-e OAUTH_GOOGLE_REDIRECT_URI=http://localhost:8080/oauth/callback \
go-mcp-gateway用法
客户注册
注册您的客户端应用程序以接收OAuth凭据:
curl -X POST http://localhost:8080/oauth/register \
-H "Content-Type: application/json" \
-d '{
"client_name": "My MCP Client",
"redirect_uris": ["http://localhost:5000/callback"],
"grant_types": ["authorization_code", "refresh_token"],
"response_types": ["code"],
"token_endpoint_auth_method": "client_secret_basic"
}'答复:
{
"client_id": "550e8400-e29b-41d4-a716-446655440000",
"client_secret": "generated-secret",
"client_name": "My MCP Client",
"redirect_uris": ["http://localhost:5000/callback"],
...
}授权流程
步骤1:生成PKCE代码验证器和质询
import secrets
import hashlib
import base64
# Generate code verifier
code_verifier = base64.urlsafe_b64encode(secrets.token_bytes(32)).decode('utf-8').rstrip('=')
# Generate code challenge
code_challenge = base64.urlsafe_b64encode(
hashlib.sha256(code_verifier.encode('utf-8')).digest()
).decode('utf-8').rstrip('=')步骤2:将用户重定向到授权端点
http://localhost:8080/oauth/authorize?
client_id=YOUR_CLIENT_ID&
redirect_uri=http://localhost:5000/callback&
response_type=code&
scope=openid email profile&
code_challenge=CODE_CHALLENGE&
code_challenge_method=S256&
state=random-state-value步骤3:代币的交换授权码
用户授权后,他们将被重定向到您的 redirect_uri 使用代码参数:
curl -X POST http://localhost:8080/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-u "CLIENT_ID:CLIENT_SECRET" \
-d "grant_type=authorization_code&code=AUTHORIZATION_CODE&redirect_uri=http://localhost:5000/callback&code_verifier=CODE_VERIFIER"答复:
{
"access_token": "ya29.a0AfH6SMBx...",
"refresh_token": "1//0gw...",
"token_type": "Bearer",
"expires_in": 3599,
"id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6..."
}步骤4:访问受保护的MCP资源
使用Google访问令牌向代理的MCP端点发出请求:
curl http://localhost:8080/calc/mcp \
-H "Authorization: Bearer ya29.a0AfH6SMBx..." \
-H "Content-Type: application/json" \
-d '{"jsonrpc": "2.0", "method": "add", "params": [1, 2], "id": 1}'步骤5:刷新过期的令牌
当访问令牌过期时,使用刷新令牌:
curl -X POST http://localhost:8080/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-u "CLIENT_ID:CLIENT_SECRET" \
-d "grant_type=refresh_token&refresh_token=REFRESH_TOKEN"API终点
OAuth 2.0端点
| 端点 | 方法 | 描述 |
|---|---|---|
/oauth/register | POST | 动态客户端注册(RFC 7591) |
/oauth/authorize | GET | 授权端点-启动OAuth流 |
/oauth/callback | GET | 谷歌OIDC回调处理程序 |
/oauth/token | POST | 令牌端点-令牌或刷新令牌的交换代码 |
元数据发现端点
| 端点 | 方法 | 描述 |
|---|---|---|
/.well-known/oauth-authorization-server | GET | 授权服务器元数据(RFC 8414) |
/.well-known/oauth-protected-resource | GET | 受保护的资源元数据 |
代理路由
路线根据以下内容动态注册 config.yaml。所有代理路由都需要在 Authorization 头球
发展
运行测试
运行所有测试:
go test ./...对特定包运行测试:
go test ./internal/auth运行具有详细输出的测试:
go test -v ./...项目结构
.
├── cmd/
│ └── server/
│ └── main.go # Application entry point
├── internal/
│ ├── auth/ # OAuth 2.0 authorization server
│ │ ├── auth.go
│ │ ├── client.go # Dynamic client registration
│ │ ├── authorization_code.go
│ │ ├── token.go
│ │ └── ...
│ ├── handler/ # HTTP request handlers
│ │ ├── oauth_authorize.go
│ │ ├── oauth_callback.go
│ │ ├── oauth_token.go
│ │ └── ...
│ ├── provider/google/ # Google OIDC integration
│ │ └── google.go
│ ├── middleware/ # HTTP middleware
│ │ └── googletokenvalidator/
│ ├── store/ # Redis storage abstraction
│ ├── config/ # Configuration management
│ ├── logger/ # Structured logging
│ └── utils/ # Utility functions
├── config.yaml # Proxy configuration
├── .env # Environment variables
└── go.mod配置参考
环境变量
| 变量 | 必填 | 默认 | 描述 |
|---|---|---|---|
BASE_URL | 没有 | http://localhost:8080 | 服务器的基本URL |
PORT | 没有 | 8080 | 服务器端口 |
REDIS_ADDR | 没有 | localhost:6379 | Redis服务器地址 |
REDIS_PASSWORD | 否 | Redis密码 | |
OAUTH_GOOGLE_CLIENT_ID | 是 | 谷歌OAuth客户端ID | |
OAUTH_GOOGLE_CLIENT_SECRET | 是 | 谷歌OAuth客户端密码 | |
OAUTH_GOOGLE_REDIRECT_URI | 是 | OAuth回调URL |
代理配置(config.yaml)
proxies:
- pattern: "/endpoint/path" # URL pattern to match
target_url: "http://host:port/path" # Target MCP server URL可以定义多个代理路由。每条路线都需要谷歌令牌验证。
安全考虑
- 需要PKCE:所有授权码流必须使用PKCE和S256方法
- 无长期储存:在OAuth交换期间,Google令牌仅临时存储(5分钟)
- 令牌验证:所有代理请求都使用Google的tokeninfo端点验证Google令牌
- Redis安全:在生产环境中使用强Redis密码并启用TLS
- 超文本传输安全协议:在生产环境中使用HTTPS
- 客户秘密:安全地存储客户端机密,从不承诺版本控制
存储TTL
| 存储类型 | TTL | 用途 |
|---|---|---|
| 授权码 | 5分钟 | OAuth代码与嵌入的Google令牌交换 |
| OAuth状态/随机数 | 5分钟 | 谷歌OIDC流验证 |
| 客户端注册 | 90天 | 已注册OAuth客户端 |
| 会话 | 7天 | 用户会话管理 |
故障排除
Redis连接错误
确保Redis正在运行,并且可以在配置的地址访问:
redis-cli pingGoogle OAuth错误
- 验证您的Google OAuth凭据是否正确
- 确保重定向URI与Google Cloud Console中配置的完全匹配
- 检查所需的Google API是否已启用
令牌验证失败
- 确保访问令牌未过期
- 验证令牌是由Google为正确的客户端颁发的
- 检查令牌是否具有所需的作用域
安全
安全是这个项目的首要任务。请查看我们的安全文档:
关键安全功能
- 没有长期存储Google凭据
- OAuth流的PKCE实施
- 对所有代理请求进行Google令牌验证
- Redis支持的TTL会话管理
- 通过Dependabot自动扫描依赖关系
- CodeQL和Trivy安全扫描
贡献
欢迎捐款。请遵循现有的代码样式:
- 错误处理
fmt.Errorf为了上下文 - 结构化日志记录
internal/logger - PKCE S256方法专用
- 审查 安全.md 在捐款之前
许可证
此项目根据GNU通用公共许可证v3.0获得许可-请参阅 许可证 文件以获取详细信息。
GPL-3.0是什么意思?
- ✅ 您可以将此软件用于任何目的
- ✅ 您可以修改软件
- ✅ 您可以分发该软件
- ✅ 您可以分发您的修改
- ⚠️ 如果分发修改后的版本,则必须:
- 使源代码可用 - 根据GPL-3.0授权 - 对代码所做的状态更改 - 包含原始版权声明
这确保了软件保持免费和开源。
参考文献
致谢
特别感谢:
