Server OAuth metadata hardcodes token_endpoint_auth_methods_supported, breaking public client flows

用户基于 MCP Python SDK 构建了支持 OAuth 授权的 MCP 远程服务器,并通过 MCP 客户端(如 Claude Code、Cursor、ChatGPT、VS Code)使用动态客户端注册(DCR)进行公客户端 OAuth 2.1 流程时触发。浏览器 OAuth 流程可以完成,授

Server OAuth metadata hardcodes token_endpoint_auth_methods_supported, breaking public client flows

Server OAuth metadata hardcodes token_endpoint_auth_methods_supported, breaking public client flows

快速结论:该报错发生在 MCP Python SDK 构建的 OAuth 授权服务器上,当公客户端(如 Claude Code、Cursor、VS Code)尝试通过动态客户端注册(DCR)完成 OAuth 2.1 流程时,服务器元数据错误地未声明支持 none 认证方法,导致客户端虽然注册成功但令牌交换失败。优先排查服务器端 build_metadata() 函数返回的 token_endpoint_auth_methods_supported 字段是否包含 "none"

问题场景

用户基于 MCP Python SDK 构建了支持 OAuth 授权的 MCP 远程服务器,并通过 MCP 客户端(如 Claude Code、Cursor、ChatGPT、VS Code)使用动态客户端注册(DCR)进行公客户端 OAuth 2.1 流程时触发。浏览器 OAuth 流程可以完成,授权码已收到,但令牌交换失败,客户端显示相关错误信息。

报错原文

"Existing OAuth client information is required when exchanging an authorization code"

(Claude Code 端报错;其他客户端可能有类似表述,但根本原因相同。)

原因分析

build_metadata() 函数在 mcp/server/auth/routes.py 第 168 行硬编码了 token_endpoint_auth_methods_supported["client_secret_post", "client_secret_basic"],遗漏了 "none" 值。这是因为:

  • OAuth 2.1 (draft-ietf-oauth-v2-1-13) 和 RFC 7591 明确定义 "none" 是公客户端的合法认证方法。
  • MCP 授权规范(2025-06-18)要求认证服务器同时支持机密客户端和公客户端,并强烈建议本地客户端作为公客户端实现 OAuth 2.1。
  • 服务器端 register.py:54-60 的注册处理程序已正确支持 token_endpoint_auth_method: "none" 的注册请求(不返回 client_secret)。
  • build_metadata() 返回的元数据声明仅支持需要客户端密钥的认证方法,与服务器实际行为矛盾。

可能原因:开发者意图默认支持机密客户端认证,但未包含公客户端必需的 "none" 方法,导致对协议实现的疏忽。

环境排查

  • MCP Python SDK 版本: mcp==1.27.1(已验证仍存在该问题)
  • FastMCP 版本(如适用): fastmcp==3.3.1(直接调用 build_metadata(),继承相同问题)
  • 服务器端代码: 检查 src/mcp/server/auth/routes.pybuild_metadata() 函数的 token_endpoint_auth_methods_supported 字段
  • 客户端: Claude Code、Cursor、ChatGPT、VS Code 等遵循 MCP 授权规范的客户端

解决步骤

  1. 直接解决方案(等待上游合并 PR #2261): 在服务器端,修改 mcp/server/auth/routes.py 中的 build_metadata() 函数,将 token_endpoint_auth_methods_supported 字段修改为包含 "none",至少补充为 ["none", "client_secret_post", "client_secret_basic"]
  2. 临时解决(ASGI 中间件): 在 ASGI 应用中添加中间件,拦截 /.well-known/oauth-authorization-server 的响应,将 token_endpoint_auth_methods_supported 重写为包含 "none"
    {"token_endpoint_auth_methods_supported": ["none", "client_secret_post", "client_secret_basic"]}
  3. 参考官方示例: 官方 modelcontextprotocol/example-remote-server 使用 token_endpoint_auth_methods_supported: ['none'],可将其作为配置依据。

验证方法

修复后,使用公客户端(如 Claude Code)重新执行完整的 OAuth 2.1 动态客户端注册流程:

  • 客户端发现服务器元数据时,应能看到 "none"token_endpoint_auth_methods_supported 字段中。
  • 客户端使用 token_endpoint_auth_method: "none" 注册后,无需 client_secret 即可完成令牌交换。
  • 浏览器 OAuth 流程完成后,授权码应能成功兑换为访问令牌。

参考来源

modelcontextprotocol/python-sdk #2260

GamsGo AI

AI 工具推荐

想把多个 AI 模型放在一个入口?

GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。

了解 GamsGo AI

推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。

celebrityanime
celebrityanime
文章: 8268

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注