[Bug]: MCP sending x-litellm-api-key to a dcr_bridge server returns an empty tool list

当 MCP 服务器使用 auth_type: oauth_delegate 搭配 dcr_bridge: true ,且客户端在每次请求上都同时携带 Authorization: Bearer llm_env_… 与 x-litellm-api-key 时, tools/list 会返回 HTTP

快速结论:当 MCP 服务器使用 auth_type: oauth_delegate 搭配 dcr_bridge: true,且客户端在每次请求上都同时携带 Authorization: Bearer llm_env_…x-litellm-api-key 时,tools/list 会返回 HTTP 200 但工具列表为空。优先排查是否在 MCP 请求上多带了 x-litellm-api-key 头。

适用环境:LiteLLM v1.98.0(镜像 docker.litellm.ai/berriai/litellm-database:v1.98.0)与 v1.101.0;客户端 mcp-remote 0.2.1(Streamable HTTP),另有 Claude Code 及原生 curl 复现;上游为 OAuth 2.0 保护资源(如 GitLab 19.3.1 CE 的内置 MCP)。Issue 未提供操作系统、Python、CUDA 或显卡信息。

最快修复方案:暂无确认的一步修复方案。Issue 中明确说明 dcr_bridge: false 不是可行的替代方案,且 #41390 在关闭时仍为草案。

注意事项:Issue 中确认 #40923(“require admission for delegated OAuth”)并不修复此问题,因为它改动的是旧路径 auth_type: oauth2 + delegate_auth_to_upstream#41390 看起来针对该故障,但当时仍是 draft,且与 #38326#38524 存在互相冲突的策略决定。此外,x-litellm-api-keyPOST /<server>/token 这一步是必需的,去掉它会导致 token 端点报错,因此无法通过客户端配置同时满足两段请求。

问题场景

用户在 LiteLLM 网关后面配置 MCP 服务器,使用 auth_type: oauth_delegatedcr_bridge: true,由网关充当 DCR(动态客户端注册)桥接,让 Claude Desktop / Claude Code / mcp-remote 走浏览器交互式登录,并把上游的 OAuth 保护资源(如 GitLab 内置 MCP)工具暴露给客户端。客户端在注册、授权、换取 token 后,用 llm_env_ 前缀的网关令牌发起 tools/list。此时若请求头里同时带上 x-litellm-api-key,工具列表变空,Claude Desktop 显示 “This server offered no tools”,服务器被判为不可用。

报错原文

[Bug]: MCP sending x-litellm-api-key to a dcr_bridge server returns an empty tool list

data: {"jsonrpc":"2.0","id":3,"result":{"_meta":{"litellm.ai/server_outcomes":{"gitlab":{"status":"auth_required","http_status":401}}},"tools":[]}}

this server issues a gateway-bound credential; complete the interactive sign-in, or send a litellm credential (x-litellm-api-key or Authorization) on the token request

SDK auth failed: Protected resource https://gitlab.example.com/api/v4/mcp does not match expected https://gateway.example.com (or origin)

原因分析

可能原因是:MCP 请求路径上的身份判定与 token 端点上的准入判定策略不一致。在 dcr_bridge: true 下,llm_env_ 令牌已经编码了准入身份(复现中可见 "subject_type":"key_hash",即准入绑定到虚拟 key),此时再附带冗余的 x-litellm-api-key 头会被当作额外的准入要求处理,导致上游凭据被扣留、上游返回 401,网关侧对客户端仍以 200 返回空 tools 数组(status: auth_required)。Issue 作者也指出,期望行为应当是冗余的 x-litellm-api-key 被忽略而不是让上游凭据被 withhold。

环境排查

  • LiteLLM 版本:v1.98.0 已确认存在,v1.101.0 仍存在;作者称撰写时 main 分支同样存在。
  • 部署方式:Docker 镜像 docker.litellm.ai/berriai/litellm-database:v1.98.0,并带有 DATABASE_URLSTORE_MODEL_IN_DB=True
  • MCP 配置:确认是否同时使用了 auth_type: oauth_delegatedcr_bridge: true
  • 上游授权服务器:是否只发布 authorization_coderefresh_token、没有 client_credentials(GitLab 19.3.1 CE 即属此类,故只能做每用户浏览器登录)。
  • 客户端:mcp-remote 0.2.1(Streamable HTTP)、Claude Code;mcp-remote 会把 --header 加到所有请求上,这一点需确认。
  • 请求路径:单服务器路由(如 /gitlab/mcp)而非聚合端点。
  • Issue 未提供操作系统、Python 版本、CUDA、显卡信息。

解决步骤

  1. 先用最小复现确认故障边界:使用同一个 MCP session,先只带 Authorization: Bearer <ENVELOPE>tools/list,观察是否返回全部工具(复现实测 28 个)。
  2. 保持同一 session、同一 token,仅额外加上 x-litellm-api-key 头再调一次 tools/list,观察是否变成空数组且 _meta 中出现 status: auth_required / http_status: 401。若两次结果不一致,即可定位到该头。
  3. 可优先尝试的临时绕行(Issue 作者所述):先带着 x-litellm-api-key 完成 POST /<server>/token 铸出 llm_env_ 凭据,然后停掉客户端,再在不带该头的情况下重启客户端。注意这只是临时手段。
  4. 不要尝试用 dcr_bridge: false 规避:关闭桥接后 LiteLLM 会原样转发上游的 protected-resource 元数据,客户端拿到 "resource": "https://gitlab.example.com/api/v4/mcp",与自身连接的 https://gateway.example.com 不匹配,会在 RFC 9728 资源校验处直接失败,没有客户端开关可绕过。
  5. 跟踪上游修复进展:#41390 看起来针对该故障,但当时为 draft,且与 #38326#38524 存在冲突的策略决定;#40923 不适用(它改的是 auth_type: oauth2 + delegate_auth_to_upstream 旧路径)。

验证方法

修复后应满足:在 Authorization: Bearer llm_env_…x-litellm-api-key 同时存在的情况下,POST /<server>/mcptools/list 返回 HTTP 200 且列出全部工具(复现中为 28 个),_metastatusok 而非 auth_required;Claude Desktop / Claude Code 中该服务器显示为已连接且可调用工具。另需确认约 2 小时后的 token 刷新路径同样获批,否则刷新后仍会复现空列表。

参考来源

BerriAI/litellm #38208

GamsGo AI

AI 工具推荐

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

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

了解 GamsGo AI

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

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 25101

发表回复

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