故障排查与升级
tool-bridge 的错误通常落在五层之一:目标/网络、身份、路径授权、节点契约、provider/宿主。按层排查能避免把 404 当宕机、把上游 401 当本地 SK 错误,或为临时问题扩大权限。
先收集最小安全证据
Section titled “先收集最小安全证据”在不泄露 Secret 的前提下记录:
- BaseURL 的 host(不含 query/token);
- 宿主类型和对应版本;
- 当前 profile 名、SK id/owner(不含明文);
- 请求 method/path、HTTP status、TBError code、retryable;
- 节点 kind、工具名、schema digest/版本线索;
- 时间、trace id、设备/plugin/remote 的公开标识;
- 能否由最小只读请求复现。
不要粘贴 Authorization、Cookie、OAuth code/state、SecretStore 值、完整敏感 arguments、环境文件或 Cloudflare 资源凭证。
tb whoamitb status --jsontb help --jsontb tree --depth 2 --jsonTARGET_PATH=tools/docstb help "$TARGET_PATH" --json如果 CLI 自身不可用,先用 HTTP:
curl -i https://tb.example.com/healthz
curl -i \ -H "Authorization: Bearer $TB_SK" \ -H "Accept: application/json" \ https://tb.example.com/~helphealthz 200 但 ~help 失败,说明进程存活但认证、bootstrap 或数据面仍有问题。
按状态码判断第一落点
Section titled “按状态码判断第一落点”401 permission_denied
Section titled “401 permission_denied”含义:Bearer 缺失、未知、disabled、deleted 或 expired。
检查:是否选错 profile/BaseURL;代理是否保留 Authorization;SK 是否被旋转;Workers KV 吊销/签发是否仍在传播窗口。不要改成 query token,也不要立即换 Admin SK 掩盖问题。
404 not_found
Section titled “404 not_found”含义:路径确实不存在,或当前身份没有 read 而被可见性隐藏。
从最近可见父路径执行 tb help/tb tree;用管理员身份只做对照,不要让业务客户端依赖管理员结果。tb search 404 还可能仅表示宿主没有 Search capability。
403 permission_denied
Section titled “403 permission_denied”身份有效且资源可见,但缺 call、write、register 或 admin。检查节点 ~help 声明的 scope、SK 的 allow/deny,以及 registerPaths。不要只添加一个宽泛 ** scope;修正最小动作和路径。
400 invalid_argument
Section titled “400 invalid_argument”重新读取工具级 ~help --json 和当前 CLI --help。检查直连/信封形状、JSON object、路径占位、Context capability、Plugin export、remote host 写法。不要保留旧字段 fallback。
409 conflict
Section titled “409 conflict”常见于 Context ifVersion 过期、注册路径被另一 key 占用或并发更新。重新读取权威状态,合并后重试;不要直接删除他人节点或覆盖版本。
429 rate_limited
Section titled “429 rate_limited”读取 retryable,指数退避并限制总时长。Feedback 每 owner/path 也有防刷限制。不要并发洪泛或无上限重试。
503/501 unavailable
Section titled “503/501 unavailable”区分消息来源:设备 offline、Secret 无法解析、上游网络、Plugin disabled、对象存储未装配、remote 环/跳数、未实现 capability。retryable 为 false 时先修配置;为 true 时仍要有退避和截止时间。
500 internal
Section titled “500 internal”使用最小无敏感请求复现,保留时间/trace/版本,检查服务日志中的结构化错误。不要把完整 payload 或 headers 打开到 debug 日志。
发现与 Search
Section titled “发现与 Search”正常发现流程与 Feedback/Search 的分工见发现、反馈与协作。
症状:Search 404,但树正常。
根级 POST /~search 是可选宿主能力。使用 tb tree、父路径 tb help;Cloudflare Deploy Button 模板与完整源码部署的 bindings 可能不同,以实际 ~help/宿主配置为准。
症状:Search 找到旧工具或找不到新工具。
Search 是派生索引。直接读取节点/工具 ~help 判断权威工具表;确认节点仍存在且当前 SK 有 read+call。必要时按对应版本管理入口重建/刷新,不要直接修改 D1/SQLite 索引表。
SecretStore 与认证上游
Section titled “SecretStore 与认证上游”先复核密钥、出站身份与安全边界,不要用扩大本地 SK 或匿名降级掩盖上游凭证错误。
症状:错误提到 authRef/skRef 无法解析。
tb secret ls确认引用名存在,但不要尝试读取明文。检查部署是否正确注入 32 字节 base64url 加密主密钥;主密钥错误会使已有密文不可解。声明引用后必须 fail closed,不能删掉 authRef 让请求匿名出去。
症状:挂载时 permission_denied。
绑定任何 authRef/skRef 除目标路径 register 外,还要求 system/secret:admin。这是防止受限注册者借用平台已有 Secret 的安全门。
症状:上游 401/403。
区分本地 HTTP status 与归一后的上游错误。检查 auth header/scheme、凭证过期和上游 scope;本地调用者 SK 永远不应透传上游。
内置集成与 Plugin
Section titled “内置集成与 Plugin”任务步骤分别见使用内置集成目录和注册外部 Plugin。
catalog 找不到 provider:当前宿主没有打包它,改用其他接入方式,不复制别的实例 catalog。
Plugin health 正常但注册失败:~describe 的 protocolVersion、exports、auth、methods/capabilities 或重复 id 不合法。healthz 只检查生命周期端点,不证明 descriptor 合法。
Plugin 注册成功但调用 unavailable:检查 enabled、transport token、endpoint TLS、binding 是否由宿主装配,以及挂载业务 authRef。transport token 与上游 token 不得混用。
多 export 选错:用 tb plugin get <id> 或 tb integration catalog --json 查看逐 export profile;tools/v1 用 tool 节点,context/v1 用 Context 节点。
回滚时先卸载引用节点,再注销 Plugin,最后确认无引用后删除 Secret。
先确认当前是在排查上游挂载还是入站投影;两个方向的完整流程见挂载 MCP 与 MCP 客户端投影。
先确定故障方向:
- 上游挂载:
tb help <mcp-node>是否能 discovery,OAuth/authRef 是否有效; - 入站投影:MCP client 是否连接
/<base>/~mcp,每次请求是否带 scoped SK。
MCP 客户端里的工具名可能是编码后的名称,以 tools/list 为准。tb_search 缺失只表示宿主未启用 Search。上游返回 isError:true 可以是 HTTP 200 的业务错误,不等同于传输失败。
OAuth 问题检查 canonical origin、redirect allowlist 和实际访问域名;上游只接受 loopback 时按当前 tb tool auth --help 判断 --local 是否适用。
声明式 HTTP
Section titled “声明式 HTTP”工具表、凭证与验证步骤见把 HTTP API 声明为工具。
路径参数缺失时比较 pathTemplate 的 {name} 与 arguments/schema。GET/DELETE 剩余参数进 query,POST/PUT 进 JSON body。复杂签名、响应转换或供应商错误语义无法由简单工具表表达时,迁移为 Plugin,不要继续堆静态 header 或隐藏约定。
公网 endpoint 被拒时改用 HTTPS。TB_ALLOW_INSECURE_HTTP 只用于本地测试,不作为生产修复。
Context
Section titled “Context”Provider capability、乐观并发和 $ref 边界见挂载与使用 Context。
unknown cmd:该 provider 没有相应 handler/capability;重新读 namespace ~help。
写入 403:缺 write 或节点 readOnly。不要因为 CLI 有 ctx put 就假设所有 Context 可写。
conflict:重新 Get 最新 version,再合并重试。
$ref 404/过期:重新 Get 获取新短期 URL;检查节点是否仍存在、TTL 是否过期、对象是否被删除。
R2 provider unavailable:宿主没有注入 ObjectStore 或加密 key 无法生成中转 token。修宿主装配,不改业务 schema。
Device
Section titled “Device”tb device lsDEVICE_ID=build-01tb tree "device/$DEVICE_ID" --depth 3设备 SK、Shell/文件白名单与容器模式见Device 反向连接。
连接拒绝时检查 register scope、registerPaths、mountPath、URL/hello deviceId 一致。反复重连检查反向代理 WebSocket upgrade、Authorization 和网络 idle timeout。
Shell 默认 allowlist 为空;所有命令拒绝是安全默认。Sidecar 看不到文件时确认双方挂同一个 volume。调用 503 retryable 表示 offline,可以退避等待重连;不要高频轮询或自动改成 --allow '*'。
紧急处置先 disable Device SK,再停止进程,最后通过 registry 管理面处理遗留 offline 节点。
Federation
Section titled “Federation”双层身份、host allowlist、skRef 与 Via 保护见Federation 连接多棵树。
remote baseUrl 不在白名单 时先检查:
tb federation ls --jsonallowlist 需要裸 host suffix;env 基线不可通过 API 删除。skRef 失败按 SecretStore 排查。本地 403/404 与远端权限是两层问题,分别用本地 SK 和远端专用 SK 验证。
环/跳数错误表示拓扑有问题,不要先无限提高 maxHops。远端路径、tree/help 响应被当作不可信数据;路径不规范也会得到不可用错误。
Dashboard
Section titled “Dashboard”浏览器身份、本地存储和同源代理要求见使用 Dashboard。
/ui/ 404 通常是 assets 未部署或代理路径错误。页面能加载但 API 401 是浏览器会话/SK 问题。深链刷新失败时只为 /ui/* 配 SPA fallback,不能吞根 ~help、~mcp、POST 数据面或 system/*。
共享电脑使用后清理该 origin 的站点数据;怀疑泄露时立即 disable/rotate SK。
Cloudflare 与 Node/Docker
Section titled “Cloudflare 与 Node/Docker”Cloudflare
Section titled “Cloudflare”先确认实际采用的是一键部署还是完整源码部署,两者的 D1/Search 资源不同。
- KV 的认证/注册读可能有最终一致窗口;
- 检查 KV/R2/D1/DO/Assets bindings 是否与部署方式一致;
- 自定义域与 canonical origin 必须一致;
- 部署仓库配置不应包含账户 ID、资源 ID 或 secret;
- 不要把官网 Pages 部署和网关 Worker 部署混淆。
Node/Docker
Section titled “Node/Docker”持久卷、反向代理、备份与恢复步骤见部署 Node / Docker。
/data必须可写且持久;- 首次启动缺
TB_BOOTSTRAP_ADMIN_SK会 fail closed; TB_ALLOW_INSECURE_BOOTSTRAP=true只用于一次性本地开发;- 反向代理保留 WebSocket、Authorization、host/proto;
- SQLite/文件备份应在升级前完成并验证恢复。
安全回滚模板
Section titled “安全回滚模板”- 停止新流量或切回旧路径;
- 禁用新节点/Plugin/Device 身份,而不是立刻删全部状态;
- 用
~help和最小 read-only 调用验证旧路径; - 卸载新节点;
- 确认没有引用后再删除 Plugin、allowlist、Secret;
- 对远端/OAuth 凭证在上游侧完成撤销;
- 保存不含 Secret 的证据和对应版本。
项目处于 pre-launch,升级前阅读发布说明并备份状态。不要依赖隐藏旧 flag、旧 wire fallback 或临时共享部署的状态。
升级不是“换一个 tag 后看 /healthz”。每次升级都应重新证明身份、权限、真实 Provider 与恢复路径仍然成立。
通用升级顺序
Section titled “通用升级顺序”- 记录当前宿主、版本或 commit、BaseURL 与不含 Secret 的资源清单;
- 阅读目标版本 release notes,识别用户可感知和存储变化;
- 限制写入,并备份权威状态、对象数据与 SecretStore 加密根;
- 保留旧镜像、旧 commit 或上一 Worker version,明确回滚目标;
- 在隔离或预览环境部署目标版本;
- 用 Admin SK 验证根
~help、status 和实际 capability; - 用受限 SK 验证 allow/deny/404,并完成一个无破坏性的真实 Provider 调用;
- 验证 Dashboard,以及启用时的 Search、MCP、Device 和 Federation;
- 切换正式流量,并观察结构化错误与上游健康;
- 失败时停止新流量,恢复权威状态和旧版本,再重复最小 smoke。
- Node / Docker:按部署 Node / Docker停止写入、备份整个
/data、固定旧/新镜像并演练卷恢复; - Cloudflare:按源码部署核对 KV/R2/D1/DO/Assets 与构建产物;一键模板按其生成仓库和一键部署说明升级,不要混用资源表;
- 嵌入式 SDK:按嵌入现有应用随宿主应用升级,重点验证自定义 StateStore/ObjectStore、Plugin catalog/bindings 与
fetch/connect; - 所有宿主:切流前重新执行生产上线检查清单。
如果目标版本无法读取旧状态、原加密根不可用或真实 Provider smoke 失败,不要用重新 bootstrap、删除索引或扩大 Admin 权限绕过。先回滚并保存脱敏证据,再根据对应版本发布说明处理迁移。
仍无法定位时
Section titled “仍无法定位时”准备一份最小报告:宿主/版本、无敏感的复现命令、status/code/retryable、期望与实际、相同 SK 的父路径 ~help 结果、是否可在本地/另一宿主复现。源码问题可提交到 tool-bridge GitHub,提交前再次清除 token、URL query 和业务数据。
- 恢复后重新执行生产上线检查清单;
- 权限或 404 不符合预期:回到权限、SK 与可见性;
- 动态 schema 或调用形状不明确:回到从
~help到调用; - CLI 和 HTTP 结果不一致:对照
tbCLI与运行时 HTTP 参考。