OAuth代理服务

一个演示FastMCP服务器通过OAuth代理模式与不支持动态客户端注册(DCR)的Keycloak进行认证的解决方案。

  • by vikrantjain
  • Python
  • 本地部署
  • 1 星标
  • 更新于
在 GitHub 查看 vikrantjain/mcp-oauth-proxy-demo

使用说明

FastMCP Keycloak OAuth代理演示

FastMCP服务器示例演示 OAuth代理模式 用于使用Keycloak进行身份验证,Keycloak是一个不支持动态客户端注册(DCR)的传统OAuth提供程序。

为什么选择OAuth代理?

MCP客户端希望使用动态客户端注册(DCR)-他们希望自动注册并动态获取凭据。然而,Keycloak(与GitHub、Google和Azure等大多数传统OAuth提供商一样)需要通过管理控制台手动注册应用程序。

这 OAuth代理 通过以下方式弥合这一差距:

  • 向MCP客户端展示符合DCR的接口
  • 在幕后使用预先注册的Keycloak凭据
  • 处理动态客户端重定向URI的回调转发
  • 发行FastMCP JWT令牌,而不是直接转发上游令牌

这保持了适当的OAuth 2.0安全边界,同时提供了无缝的MCP客户端集成。

演示的主要功能

  • OAuth代理模式:将DCR不兼容的OAuth提供程序与MCP客户端连接起来
  • 动态客户端注册仿真:接受客户端注册请求并返回预先配置的凭据
  • 双PKCE安全:客户端到代理和代理到上游层的端到端PKCE
  • 令牌工厂模式:发行FastMCP JWT令牌,而不是转发上游令牌
  • 回拨转发:支持动态客户端重定向URI(随机本地主机端口、固定URL)
  • JWT令牌验证:使用Keycloak的JWKS端点验证令牌
  • 同意屏幕:防止混淆的副手攻击
  • FastMCP功能:工具、资源和提示示例

建筑

sequenceDiagram
    participant Client as MCP Client
    participant Proxy as FastMCP OAuthProxy
    participant Keycloak as Keycloak OAuth Provider
    participant User
    
    Note over Client,Keycloak: Phase 1: Discovery & Registration
    Client->>Proxy: 1. POST /mcp (initialize)
    Proxy-->>Client: 401 Unauthorized + metadata URL
    
    Client->>Proxy: 2. GET /.well-known/oauth-protected-resource/mcp
    Proxy-->>Client: OAuth server metadata
    
    Client->>Proxy: 3. POST /register (DCR with redirect_uri)
    Note over Proxy: Records client redirect_uri<br/>Returns pre-configured credentials
    Proxy-->>Client: client_id (fixed upstream credentials)
    
    Note over Client,Keycloak: Phase 2: Authorization with Dual-PKCE
    Client->>Proxy: 4. GET /authorize?code_challenge=...
    Note over Proxy: Stores client PKCE challenge<br/>Generates own PKCE for upstream
    Proxy-->>User: Show consent page
    User->>Proxy: Approve client
    Proxy->>Keycloak: Redirect to /authorize (proxy PKCE)
    
    Keycloak-->>User: Login page
    User->>Keycloak: Authenticate
    Keycloak-->>Proxy: Authorization code
    
    Note over Client,Keycloak: Phase 3: Token Exchange
    Proxy->>Keycloak: POST /token (code + proxy verifier)
    Keycloak-->>Proxy: Upstream access_token
    Note over Proxy: Encrypts & stores upstream token<br/>Issues new FastMCP JWT
    Proxy-->>Client: Redirect to client redirect_uri + code
    
    Client->>Proxy: 5. POST /token (code + client verifier)
    Note over Proxy: Validates client PKCE<br/>Returns FastMCP JWT
    Proxy-->>Client: FastMCP JWT token
    
    Note over Client,Keycloak: Phase 4: Authenticated Requests
    Client->>Proxy: 6. POST /mcp (with FastMCP JWT)
    Note over Proxy: Validates FastMCP JWT<br/>Verifies upstream token
    Proxy-->>Client: Protected MCP resources

运作原理

  1. 问题:MCP客户端期望动态客户端注册(DCR)-他们希望自动注册并即时获得凭据。Keycloak需要通过其管理控制台手动注册应用程序。

  2. 解决方案:OAuthProxy在幕后使用预先注册的Keycloak凭据时,向MCP客户端提供符合DCR的接口。

  3. 流量:

    • 当客户端注册时,代理返回您的固定Keycloak凭据并存储客户端的回调URL
    • 当客户端授权时,代理使用Keycloak的固定回调URL,然后转发回客户端的动态回调
    • 代理发出自己的FastMCP JWT令牌(用HS256签名),而不是直接转发Keycloak令牌
    • 这保持了适当的OAuth 2.0受众边界,并实现了更好的安全控制

先决条件

  • Python 3.12+:FastMCP需要
  • 码头工人:用于在本地运行Keycloak
  • 紫外线:Python包管理器

安装

1.克隆存储库

git clone https://github.com/vikrantjain/mcp-oauth-proxy-demo.git
cd mcp-oauth-proxy-demo

2.安装依赖项

uv sync

配置

1.使用Docker启动Keycloak

docker run -d \
  --name keycloak \
  -p 8080:8080 \
  -e KEYCLOAK_ADMIN=admin \
  -e KEYCLOAK_ADMIN_PASSWORD=admin \
  quay.io/keycloak/keycloak:latest \
  start-dev

访问Keycloak管理控制台http://localhost:8080(凭据:admin/admin)

2.在Keycloak中创建客户端

  1. 导航到 客户 在左侧边栏中
  2. 点击 创建客户端
  3. 配置客户端:
    • 客户端ID: mcp_server
    • 客户端认证:ON(机密客户)
    • 有效的重定向URI: http://localhost:8000/auth/callback
    • 有效的注销后重定向URI: http://localhost:8000
  4. 保存客户端
  5. 去 凭证 选项卡并复制 客户端密钥

3.配置环境变量

cp .env.example .env
# Edit .env and add your Keycloak client secret

更新 .env 根据您的实际值:

KEYCLOAK_CLIENT_ID=mcp_server
KEYCLOAK_CLIENT_SECRET=<your-client-secret-from-keycloak>
KEYCLOAK_BASE_URL=http://localhost:8080
KEYCLOAK_REALM=master
MCP_SERVER_BASE_URL=http://localhost:8000

运行服务器

uv run fastmcp run mcp-server.py --transport streamable-http --host 0.0.0.0 --port 8000

服务器将于启动http://localhost:8000

使用示例

1.Python客户端(FastMCP客户端)

uv run python mcp-client.py

此客户端演示:

  • 呼叫 greet 工具
  • 阅读 resource://server/config 资源(OAuth配置)
  • 获取 explain_oauth_flow 提示

2.REST客户端(VS代码REST客户端扩展)

安装 REST客户端扩展 对于VS代码。

使用 client-proxy.rest 要使用动态客户端注册测试完整的OAuth代理流,请执行以下操作:

  1. 打开 client-proxy.rest
  2. 遵循OAuth的分步流程:
    • 发现和元数据检索
    • 动态客户端注册
    • 使用PKCE进行授权
    • 代币兑换
    • 经过身份验证的MCP请求

备注: client.rest 包含未经身份验证的引用请求,但由于服务器需要OAuth身份验证,因此将失败。

项目结构

.
├── mcp-server.py           # FastMCP server with OAuthProxy configuration
├── mcp-client.py           # Python client example using FastMCP Client
├── client.rest             # Simple MCP API tests (REST Client)
├── client-proxy.rest       # Complete OAuth flow demonstration
├── pyproject.toml          # Python project dependencies
├── uv.lock                 # Dependency lock file
├── .env.example            # Environment variables template
├── .env                    # Your actual environment variables (gitignored)
├── .gitignore              # Git ignore patterns
├── .python-version         # Python version specification (3.12)
└── README.md               # This file

安全特性

  • 双PKCE:客户端到代理和代理到上游层的端到端PKCE
  • 使用者同意:客户授权前需要明确批准
  • 加密令牌存储:用于存储令牌的AES-128-CBC+HMAC-SHA256加密
  • JWT签名验证:FastMCP令牌的HS256签名验证
  • 受众验证:防止不同服务之间的令牌滥用
  • 困惑的副保护:同意屏幕可防止恶意客户端模拟

了解更多

许可证

MIT许可证-有关详细信息,请参阅许可证文件

贡献

欢迎投稿!请随时提交拉取请求。