Skip to content

fix(mcp): OAuth token 缺失 fail-closed,鉴权 401 归 auth 类——不再静默裸连 - #440

Closed
Lin-Dongg wants to merge 1 commit into
huiliyi37:mainfrom
Lin-Dongg:fix/mcp-oauth-fail-closed
Closed

Lin-Dongg wants to merge 1 commit into
huiliyi37:mainfrom
Lin-Dongg:fix/mcp-oauth-fail-closed

Conversation

@Lin-Dongg

Copy link
Copy Markdown
Collaborator

Problem

auth.oauth 声明的 MCP server 在 token 缺失/过期时静默裸连:_connectServer 拿到
loadMcpOAuthToken() 的 null 后只是跳过鉴权注入,照样把没有 Authorization 头的请求发
出去。用户看到的报错来自服务端,例如 GitHub MCP:

Streamable HTTP error: Error POSTing to endpoint: bad request: missing required Authorization header

排查方向因此被带偏到命令/网络(UI 的通用提示是「本地服务先确认命令可执行/已安装,远程
服务确认 URL 与网络可达」),而真正该做的是重新授权。

同时 classifyMcpError 对 remote 鉴权 401 的两种实测形态都不命中 auth 正则,全部掉进
默认 tool_error:

  • bad request: missing required Authorization header(GitHub MCP,无 Authorization 头)
  • {"error": "invalid_token", "error_description": "Authentication required"}(liblib MCP,Bearer 失效)

——后者 UI 上直接显示 [tool_error] 前缀,同样是误导。

修复

  1. fail-closed(manager.ts):声明了 auth.oauth 就必须拿到凭据才发起连接。
    • token 缺失/过期(含 refresh 失败回落)→ 发请求之前抛出:
      OAuth token for MCP server "<id>" is missing or expired — re-authorize this server (run \/mcp auth `, or reconnect from settings)`
    • auth.provider 未注册 → 同理不裸连,明确指向 auth.provider 配置。
    • 语义对齐既有 fail-closed 先例(见 buildStdioChildEnv / systemPathFallback 注释):
      声明过的凭据来源失效就大声失败,不静默降级。
  2. 鉴权分类(failure-classifier.ts):auth 特征正则补
    authorization|invalid[_ -]?token|authentication required|bearer(两条实测文本均由此
    命中),suggestion 落到「re-authorize the server」。

未声明 auth、只用静态 headers 的 server 行为不变(生态中立,不越权拦截)。

验证

  • 新增 4 个用例(RED→GREEN):
    • missing required Authorization header 归 auth 类(修复前实际为 tool_error)
    • invalid_token / Authentication required 归 auth 类(同上)
    • token 缺失时 fail-closed、不发裸请求(修复前实测裸连 127.0.0.1:9 得 connection refused,
      7.5s 后归入 network 类——静默裸连行为在测试中当场复现)
    • provider 未注册同理 fail-closed
  • src/mcp/__tests__/ 全套件 151/151 通过(node --import tsx --test,exit 0)
  • tsc --noEmit 全绿;oxlint 0 errors(2 个既有 warning:unused lower,非本改动引入)

备注

auth.oauth 声明的 server 在 token 缺失/过期时静默跳过鉴权注入、把裸请求
发出去——用户看到的是服务端的 "missing required Authorization header",
排查方向被带偏到命令/网络,真正该做的是重新授权。改为发起请求前直接失败,
错误信息给出重新授权指引;provider 未注册同理。

failure-classifier 对 remote 鉴权 401 实测形态(missing required
Authorization header / invalid_token / Authentication required)不命中
auth 正则,全部掉进默认 tool_error,UI 只能给通用提示。补三条特征,并把
auth suggestion 落到「重新授权」。
huiliyi37 added a commit that referenced this pull request Oct 10, 2026
…uth 类——不再静默裸连

内容已经 sync 流程合入(dev 收编记录:未检索到),本提交为作者署名落账(提交页归属)。

Co-authored-by: Lin-Dongg <322679856+Lin-Dongg@users.noreply.github.com>
huiliyi37 pushed a commit that referenced this pull request Oct 10, 2026
@huiliyi37

Copy link
Copy Markdown
Owner

已通过 sync 流程合入 dev,感谢 @Lin-Dongg 的贡献 🎉

本 PR 的改动(fix(mcp): OAuth token 缺失 fail-closed,鉴权 401 归 auth 类——不再静默裸连)已经 sync 流程合入主仓(本次 sync),并已收录进 CONTRIBUTORS.md。

按仓库的双仓流程,公开仓 PR 不经 merge 按钮合入(保持 dev 主仓唯一事实源),现以 sync-merged 标记关闭。欢迎继续贡献!

@huiliyi37 huiliyi37 added the sync-merged 内容已通过 sync 流程合入 dev 主仓(PR 形态留痕,作者计入 CONTRIBUTORS) label Oct 10, 2026
@huiliyi37 huiliyi37 closed this Oct 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

sync-merged 内容已通过 sync 流程合入 dev 主仓(PR 形态留痕,作者计入 CONTRIBUTORS)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants