LMN516 / 运维事件记录
微信 MCP 接口调用异常故障记录
发生日期:2026 年 11 月 10 日(北京时间) 事件状态:状态查询已恢复,实际发送未验收
故障现象与影响
11 月 10 日,ChatGPT 调用 LMN516 的微信状态工具 wechat_takeover_status,反复得到 The tool failed internally.,同一时期部分远程桌面 MCP 读取也无法正常返回。用户最直接感受到的是:已经配置了 M4 上的微信控制器,却仍无法通过 ChatGPT 正常使用对应的 MCP 接口。
现场没有直接重启微信或修改发送脚本。M4 本地运行 lmn-wechat-mode status 返回 ok: true;Mac mini 通过 SSH 访问 M4,以及用 Node.js 的 spawnSync 执行相同命令,都返回退出码 0。也就是说,微信控制器至少在“读取状态”这个动作上是正常的,继续围绕它重装和改权限缺少依据。
为什么端口都正常,工具却调用失败
Mac mini 的 3101、3200、3210 三个端口访问 /api/mcp 均得到 HTTP 401。这个结果容易令人误以为 MCP 全链路已通。实际上,401 只表明某个 HTTP 服务收到了请求并要求认证;它不能说明请求被转发到预期的应用,更不能证明经过认证后某个 MCP 工具能执行。
M4 的独立 MCP Router 此时报告活跃运行槽为 green:3212。但检查 Mac mini 的生产路由响应头,得到 x-lmn-router: blue-green-v1,说明当时请求仍进入 Next.js 主站,而非 M4 的独立运行时。后端存在、端口可达与用户请求实际抵达该后端,是三件不同的事。
定位到的两个配置问题
第一处是反向 SSH 隧道。M4 的 LaunchAgent 仍将隧道连向 lmn516-mini-lan,其旧局域网地址已经不可达;换用经过验证的 Tailscale 别名 lmn516-mini 后,Mac mini 才重新出现由 sshd-sess 占用的本地 3210 监听端口。
第二处更直接决定 MCP 请求的去向:Mac mini 的 public-cutover.json 显示 enabled=false。路由源码中的判断如下(节选):
function resolveUpstream(rawUrl, active, miniBridge = false) {
if (isCanonicalMcpRoute(rawUrl) &&
(miniBridge || mcpSplitEnabled()))
return { host: mcpRouterHost, port: mcpRouterPort, kind: "mcp-runtime" };
return { host: upstreamHost(active.activePort),
port: active.activePort, kind: "web-runtime" };
}
这段代码说明:对普通 MCP 请求,独立路由未启用时会退回主站运行时。失效隧道与关闭的路由开关属于两处不同的问题。旧路由尚未使用隧道,因此不能把最初的全部工具错误简单归因于 SSH;但切换至 M4 前,必须先恢复这条依赖链。
技术故障记录 · 续 / 02
故障处理与恢复结果
修复没有重新构建 Next.js,也没有调整微信发送逻辑。首先备份 M4 的 LaunchAgent 配置,将 SSH 目标由 lmn516-mini-lan 改为 lmn516-mini,重载隧道后检查服务进程与 Mac mini 的 3210 端口。终端显示隧道 running、端口监听正常,并给出 TUNNEL_VERIFIED。
随后备份 Mac mini 的路由配置,只将 public-cutover.json 中的 enabled 从 false 改为 true,让 /api/mcp 转向已恢复的 M4 独立运行时。现场采用的核心修改如下;实际脚本还包含备份、状态校验和失败回滚:
const config = JSON.parse(fs.readFileSync(p, "utf8"));
if (config.enabled !== false) throw Error("配置状态不符");
config.enabled = true;
fs.writeFileSync(p, JSON.stringify(config, null, 2) + "\n");
用户确认切换完成后,重新通过 ChatGPT 调用真实工具,wechat_takeover_status 返回 ok: true、code: WECHAT_STATUS_READ、transport: LOCAL,这次响应的 elapsedMs 为 124。远程桌面 MCP 状态读取也报告 connected: true。这些是业务接口恢复的直接证据,可靠性高于仅检查一个 HTTP 状态码。由于没有保留切换后的完整响应头,不能用这次记录替代所有公网入口的独立路由验收。
从这次排查中应该保留什么
首先,故障定位需要沿真实调用路径逐层缩小范围。状态接口返回 401,只排除了端口完全不可达的情况;路由响应头 x-lmn-router 才回答“请求去了哪里”;控制器的 exit=0 证明命令自身能够运行;最后一次经过 ChatGPT 的 MCP 工具调用,才验证了用户实际使用的入口。以后遇到相似故障,应当按“入口路由—目标服务—命令执行—业务结果”核对,而不是看到一个健康状态就停止。
其次,恢复动作应尽量局部且可回滚。这里先修复已经证实失效的 SSH 目标,再改动一个路由开关,而不是一开始就重启整套应用或重新部署。配置备份与失败回滚尤其重要:当路由指向的新后端尚未真正可达时,错误的切换可能把原本局部的故障扩大成整个 MCP 入口不可用。
第三,检查脚本本身也必须可靠。前期有一次 heredoc 中的 SSH 调用没有使用 -n,导致 SSH 消耗了脚本剩余的标准输入,后续修复步骤实际上没有执行。这不是生产故障的根因,却提醒我们:自动诊断脚本不能把“输出了第一步成功”当成“全部步骤完成”。每一步都应有明确退出码和最终验收标记。
结论及尚未完成的部分
可以确认,MCP 状态读取与远程桌面状态接口已恢复,反向隧道也已验证有效;但并没有进行真实微信发送。控制器仍显示 enabled=false、shadow=true,监听历史错误中还有 wechat-window-not-found,应单独处理。旧 Next.js 路径究竟在哪一行抛出内部错误,现有记录没有对应异常堆栈,不能进一步定论;同时出现的 Prisma 事务超时日志也没有足够证据证明与本事故有关。
记录依据:11 月 10 日的终端输出、MCP 工具返回结果及 LMN516 生产路由源码。
结论边界:MCP 状态接口恢复已验证;微信实际发送与监听仍待独立验收。