
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 的 OAuthProxy 在 fastmcp/server/auth/oauth_proxy/proxy.py:895-898 中已经显式抛出 AuthorizeError(error="invalid_target", ...),并添加了 # type: ignore[arg-type] 注解,说明上游 SDK 缺少这一错误码的已知问题。
环境排查
- SDK 版本:
mcp1.27.1 或更新版本(问题在main分支 616476f 和v1.x分支 6213787 均确认存在) - FastMCP 版本:
fastmcp3.3.1(如果使用) - Python 版本:3.13(已知受影响的版本)
- 依赖项:pydantic(触发
ValidationError)
解决步骤
- 打开
src/mcp/server/auth/provider.py文件。 - 找到
AuthorizationErrorCode的Literal定义(约第 63-71 行)。 - 在
Literal列表末尾添加"invalid_target", # RFC 8707。 - 修改后的代码如下(仅展示关键部分):
AuthorizationErrorCode = Literal[ "invalid_request", "unauthorized_client", "access_denied", "unsupported_response_type", "invalid_scope", "server_error", "temporarily_unavailable", "invalid_target", # RFC 8707 ] - 保存文件,无需其他代码修改(
AuthorizationErrorResponse和AuthorizeError已通过引用接受该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 个测试)通过。



