Add `invalid_target` to `AuthorizationErrorCode` (RFC 8707)

在使用 MCP Python SDK( mcp 1.27.1 / fastmcp 3.3.1,Python 3.13)开发 OAuth 授权流程时,当 MCP proxy 或 authorization server 收到客户端请求中带有不匹配的 resource 参数(RFC 8707 资源指示器

Add `invalid_target` to `AuthorizationErrorCode` (RFC 8707)

Add `invalid_target` to `AuthorizationErrorCode` (RFC 8707)

快速结论:当使用 MCP Python SDK 进行 OAuth 授权时,如果客户端请求的 resource 参数与受保护资源不匹配,开发者会看到 pydantic ValidationError,客户端收到模糊的 server_error 而非规范的 invalid_target 错误。优先排查 AuthorizationErrorCode 类型定义中是否缺少 "invalid_target" 字面量。

问题场景

在使用 MCP Python SDK(mcp 1.27.1 / fastmcp 3.3.1,Python 3.13)开发 OAuth 授权流程时,当 MCP proxy 或 authorization server 收到客户端请求中带有不匹配的 resource 参数(RFC 8707 资源指示器),框架本应返回 invalid_target 错误码,但却抛出 pydantic 验证异常,最终返回通用 server_error

报错原文

pydantic_core._pydantic_core.ValidationError: 1 validation error for AuthorizationErrorResponse
error
  Input should be 'invalid_request', 'unauthorized_client', 'access_denied', 'unsupported_response_type',
  'invalid_scope', 'server_error' or 'temporarily_unavailable'
  [type=literal_error, input_value='invalid_target', input_type=str]

原因分析

可能原因:mcp/server/auth/provider.py 中,AuthorizationErrorCode 被定义为 Literal 类型,但只包含了 7 个标准 OAuth 2.0 错误码,缺少 RFC 8707 第 2 节定义的 "invalid_target"。当授权处理器(mcp/server/auth/handlers/authorize.py:218-220)尝试将 AuthorizeError(error="invalid_target", ...) 构建为 AuthorizationErrorResponse 时,pydantic 会因为字面量类型不匹配而抛出 ValidationError。该异常被一个宽泛的 except Exception 块(authorize.py:222-225)捕获,最终向客户端返回 server_error,完全掩盖了真正的 invalid_target 原因。

此外,FastMCP 的 OAuthProxyfastmcp/server/auth/oauth_proxy/proxy.py:895-898 中已经显式抛出 AuthorizeError(error="invalid_target", ...),并添加了 # type: ignore[arg-type] 注解,说明上游 SDK 缺少这一错误码的已知问题。

环境排查

  • SDK 版本:mcp 1.27.1 或更新版本(问题在 main 分支 616476f 和 v1.x 分支 6213787 均确认存在)
  • FastMCP 版本:fastmcp 3.3.1(如果使用)
  • Python 版本:3.13(已知受影响的版本)
  • 依赖项:pydantic(触发 ValidationError

解决步骤

  1. 打开 src/mcp/server/auth/provider.py 文件。
  2. 找到 AuthorizationErrorCodeLiteral 定义(约第 63-71 行)。
  3. Literal 列表末尾添加 "invalid_target", # RFC 8707
  4. 修改后的代码如下(仅展示关键部分):
    AuthorizationErrorCode = Literal[
        "invalid_request",
        "unauthorized_client",
        "access_denied",
        "unsupported_response_type",
        "invalid_scope",
        "server_error",
        "temporarily_unavailable",
        "invalid_target",  # RFC 8707
    ]
  5. 保存文件,无需其他代码修改(AuthorizationErrorResponseAuthorizeError 已通过引用接受该 Literal 类型)。

验证方法

方法 1(直接验证):运行以下测试脚本,确认 AuthorizationErrorResponse(error="invalid_target", ...) 能够成功构造且不再抛出 ValidationError

from mcp.server.auth.provider import AuthorizationErrorCode
from mcp.server.auth.handlers.authorize import AuthorizationErrorResponse

# 验证 Literal 中包含 invalid_target
assert "invalid_target" in AuthorizationErrorCode.__args__

# 验证构造成功
resp = AuthorizationErrorResponse(error="invalid_target", error_description="resource mismatch")
print(f"OK: {resp}")

方法 2(集成测试):tests/server/auth/test_error_handling.py 中添加测试用例 test_authorize_error_handling_invalid_target,验证 AuthorizeError(error="invalid_target", ...) 在授权流程中最终以 error=invalid_target 形式返回给重定向客户端(而非被降级为 server_error),并确认完整测试套件(1709 个测试)通过。

参考来源

modelcontextprotocol/python-sdk #2641

GamsGo AI

AI 工具推荐

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

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

了解 GamsGo AI

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

celebrityanime
celebrityanime
文章: 8178

发表回复

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