DEBUG.WIKI
京东云;让 AI 进入真实业务;零售 · 物流 · 客服 · 硬件;查看方案 →
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
Evoxt;最高 6.0GHz CPU;高频云服务器 · 免费每周备份;查看配置 →

MCP OAuth报resource不匹配,核对公开端点与metadata

对照公开端点、metadata与授权资源参数,避免无条件追加内部路由或把资源身份混同回调和会话。

给MCP服务开启认证后,客户端提示:

Protected Resource Metadata resource "http://localhost:8000/"
does not match MCP server resolved resource "http://localhost:8000/mcp"

这里先检查受保护资源的身份地址。metadata中的 resource 是根地址,客户端访问的是 /mcp,严格校验就会拒绝。它不等于OAuth回调失败,也不能直接按访问令牌的audience错误处理。

已核对的旧配置使用Python MCP SDK 1.12.4。后续接口和默认值可能变化,应按实际安装版本查看 AuthSettings 与公开metadata,不能用开发分支的配置字段推断所有发行版。

三个位置应指向同一份资源

先比较客户端配置的MCP公开端点、Protected Resource Metadata里的 resource,以及授权和换取令牌时使用的 resource 参数。它们应表达客户端真正要访问的受保护MCP资源。

issuer 标识授权服务器,redirect_uri 是客户端回调地址,resource 标识受保护服务。这些值用途不同,不能把授权服务器地址填入MCP资源字段,也不能把会话ID当作资源身份。

RFC9728要求校验metadata返回的资源标识。通过资源响应的 WWW-Authenticate 头找到metadata时,返回的 resource 必须与客户端请求资源服务器时使用的URL一致;不一致的metadata不能继续使用。

因此,先查看脱敏的公开metadata,不需要为了确认路径就解码或公开完整令牌。协议、主机、端口、公开路径和有意义的尾斜杠都要核对,不能认为地址最终经过重定向到同一应用,字符串身份就可以随意混用。

使用公开地址,别从内部挂载路径拼接

如果外部端点实际是 https://mcp.example.com/service/mcp,应用内部可能只挂载在 / 或 /mcp。应把完整公开资源地址作为受控配置,再检查metadata如何生成。这里的域名和路径只是示例。

Python SDK的 resource_server_url 用于资源标识与metadata发现。使用这一接口时,核对所用版本对完整端点的约定。不要无条件给它追加 /mcp:配置已经含路径时会变成 /mcp/mcp,代理增加或去掉前缀时,内部路由也不能推导出外部身份。

同样,不应直接信任任意 Forwarded 或 X-Forwarded-Host 来生成身份地址。需要知道哪些代理受信任,并确认应用的公开地址配置;否则只修正本机测试URL,外部客户端仍可能得到另一份metadata。

如果确需在应用层替换metadata路由,保留原有认证与授权服务器信息,确认只公布正确的资源身份。不能用“所有令牌都有效”的示例校验器来让错误消失,也不能靠关闭严格资源校验完成修复。

metadata正确之后,再看令牌校验

路径修正只解决metadata身份不一致。MCP客户端仍需在授权请求和token请求中带上资源参数,服务器仍要验证访问令牌是签发给自己使用的。能解码JWT内容不等于签名、签发方和audience已验证;不透明令牌也不能按JWT解码,ID token则不能直接代替访问令牌。

回查时从实际外部客户端重新走发现和授权,确认公开metadata的资源值匹配,取得的访问令牌符合该资源的约束,并能在权限范围内完成一次只读请求。另一种客户端能连上,不足以证明严格校验路径正确。

如果错误发生在SSE已建立后的POST路由,可以接着看endpoint事件与406检查。携带旧会话ID收到404则按会话失效后的恢复排查,不用修改资源身份来修复会话生命周期。