Skip to main content
本页是实用参考:收到一个负载后,你可以查阅它,从而知道下一步该怎么做。服务器在三个独立层面发出失败信号 —— HTTP 状态码JSON-RPC error.code,以及 result.content[0].text 中的软行为信封 —— 一次失败可能触及其中一个、两个或全部三个层面。请由外向内排查:HTTP 状态码 → JSON-RPC 代码 → 软信封。 关于投影语法本身,请参阅 JMESPath 指南。关于各工具的参数与新鲜度预算,请参阅 工具参考

快速指引

  • HTTP 状态码是传输层的回答。大多数 JSON-RPC 回复 —— 无论成功还是错误 —— 按 JSON-RPC 2.0 惯例都会以 HTTP 200 返回。只有当失败属于通用 HTTP 客户端必须响应的情况(鉴权、每日上限、服务不可用)且受益于 Retry-After / WWW-Authenticate 头时,handler 才会升级状态码。
  • JSON-RPC error.code 是应用层的回答。共使用九个代码:-32001-32002-32003-32004-32029-32600-32601-32602-32603。handler 不会发出其他代码 —— 如果你看到了其他代码,请将其视为协议 bug 并提交 issue。
  • 软行为信封是高频失败模式。tools/call 在 JSON-RPC 层成功(HTTP 200,无 error 字段),但位于 result.content[0].text 中的 JSON 携带了一个 _budget_exceeded_jmespath_error 判别字段。只检查 JSON-RPC 信封的客户端会默默地把这些当作成功 —— 请解析 result.content[0].text,并在将该负载作为数据消费前检查是否存在前导下划线 _ 键。
  • 已执行的调用仍计费。 _budget_exceeded_jmespath_error 和工具执行错误(-32603)都发生在工具已运行之后,因此它们会消耗 Pro 每日配额槽位。只有预分发失败(如每日上限拒绝或配额预留服务失败)才不消耗槽位。
  • 两条 401 路径都设置了 WWW-Authenticate,包含 realm="worldmonitor" 以及指向 /.well-known/oauth-protected-resourceresource_metadata 指针。支持 RFC 9728 的客户端(Claude Desktop、MCP Inspector)会凭此头自动跳转 OAuth 流程,无需进一步干预。

JSON-RPC 错误代码

下面的小节给出每个代码的字面负载、触发站点以及应对方式。

-32001 —— 未鉴权 / 凭证无效

api/mcp/auth.ts 的鉴权解析路径触发,总是配对 HTTP 401WWW-Authenticate 头。用户可见的触发点按客户端命中顺序如下:
  1. 既无 Authorization bearer 也无 X-WorldMonitor-Key —— 客户端在调用 /mcp 时未携带任何凭证。
  2. Authorization: Bearer <token><token> 无效或已过期 —— 令牌无法解析到上下文(被撤销 / TTL 过期 / 从未由 /api/oauth/token 签发)。
  3. X-WorldMonitor-Key: <key><key> 不在有效集合中 —— API key 错误。
  4. OAuth 令牌可解析但 Pro MCP 令牌行缺失或跨绑定 —— mcpTokenId 不再映射到该 userId。通常是 Settings → Connected MCP clients 中的撤销操作所致。
订阅不活跃故意不属于此列表。已确认的免费账户(配置正确但无权益行,或内部一致的 tier-0 行)使用免费账户额度。服务方已确认失效的订阅也遵循同一路径:共享权益门禁将已结束的覆盖期视为已确认的免费状态。不带该失效标记的付费权益过期或停用才会返回终止性 -32002 / HTTP 403;无法确定或可重试的校验故障使用 -32603 / HTTP 503。 示例线上负载(情况 1):
如何处理。 重新走一遍 OAuth 流程(/api/oauth/token 使用新的授权码,或用有效 refresh token 做刷新授权)。对于 API key 客户端,复核 X-WorldMonitor-Key 头 —— 用户签发的 wm_ key 与运维签发的企业 key 必须放在该头中,而不是作为 Authorization: BearerWWW-Authenticate 头中的 resource_metadata 指针是从零开始发起发现流程的权威入口。

-32002 —— 终止性权益拒绝

权益拒绝通常为 HTTP 403,带 Cache-Control: no-store,且不带 WWW-Authenticate:凭证仍有效,但当前权益不允许该调用,重新鉴权无法改变结果。error.data.reason 区分两种情况:
  • lapsed-subscription:这是一个罕见的执行中竞态:订阅在权益预检查通过之后、Pro 工具的下游抓取之前失效。如果权益预检查时已有服务方确认的失效结果,账户会被重新分类到受限免费账户路径,不会在预检查中发出此拒绝。较晚出现的下游 BillingDenialError 会由 api/mcp/dispatch.ts 重新发出,并带 X-Billing-Verification: subscription_lapsed,因为该次执行中的 Pro 操作已无法完成。
  • upgrade-required:免费额度账户调用了 subscription 工具,或经确认的非免费权益不足(例如已过期或停用的付费权益行)。这类拒绝发生在额度预留之前,不消耗调用槽位。
一个例外是:使用非用户绑定凭证读取 worldmonitor://account/mcp-allowance 时,-32002 位于 HTTP 200 的普通 JSON-RPC 错误中,不带 data 负载。 如何处理。 对于已发出的 -32002,不要重试,也不要重新运行 OAuth,两者都会重现同一拒绝。向用户显示权益状态:执行中失效的操作需要恢复订阅后再发起,upgrade-required 需要改用 free-account 工具或订阅 Pro。后续预检查若已确认覆盖期结束,会改走受限免费账户路径,客户端可继续使用 free-account 工具。如果订阅仍在服务方复核中,服务器会改为返回可重试的 -32603 / HTTP 503,并附带 Retry-After

-32003 —— 必需数据输入不可用

工具已开始运行,但无法读取所需的上游种子数据(例如 Redis 瞬时故障,或 seeder 尚未发布)。响应位于 HTTP 200 中,并通过结构化 data 负载列出问题输入:
如何处理。 按退避策略重试;retryable: true 就是此契约。如果某个工具持续返回 -32003,请检查 data 中列出的输入及 status.worldmonitor.app

-32004 —— 找不到 SSE 重放光标

Last-Event-IDGET /mcp 尝试恢复一个当前 edge 实例不再保留的流:有界内存重放缓冲可能已过期,或重连落到了另一个实例。返回 HTTP 404 如何处理。 重新发出原始 POST,不要继续恢复;将 SSE 重放视为容许丢失的传输层恢复,而非持久化存储。若重放 GET 缺少 Accept: text/event-stream,会返回 HTTP 406;若缺少有效 Mcp-Session-Id,则会在到达此检查前以 -32600 / HTTP 400 失败。

-32029 —— 被限流(每分钟或每日)

每分钟与每日上限触发条件共用此代码;由 HTTP 状态码区分。 每分钟节流 —— HTTP 200。 滑动窗口限流器为 60 次请求 / 分钟,按 API key(Starter 及以上)、按 Pro 用户(该用户所有令牌合计)或按 IP(用于匿名公开发现)键控。已鉴权请求在鉴权之后受限。无凭证的公开发现方法(initializenotifications/initializedtools/listresources/listresources/templates/list)与匿名公开资源读取无需鉴权即可服务,但仍会经过匿名发现限流器。无凭证的数据 / 配额方法,或该公开集合之外的元数据方法,使用匿名发现 —— 它们以 -32001 / HTTP 401 故障关闭。以 HTTP 200 内的 JSON-RPC 错误返回,因为限流器位于任何按 id 关联的上游。在 Upstash 瞬时错误时故障开放 —— 限流器后端的偶发延迟尖峰不会拖垮整个 API。 当每分钟限流器拒绝时,handler 会发出一条持久的 mcp.rate_limit_hit 遥测事件,其身份形态经过允许列表过滤。套餐限制扫描器用该事件做持续突发通知;它不会从原始 Upstash 限流器内部推断面向客户的 MCP 突发通知。 message 文本标识了是哪个限流器触发。有三种不同字符串: 示例负载(Pro 变体 —— env_key 客户端得到相同信封形状,但使用 API-key 的 message 字符串):
每日上限 —— HTTP 429 + Retry-After 硬性每日上限(默认 50 次配额消耗调用 / UTC 日)由工具运行之前的原子 Redis 预留执行,因此恰好跨越边界的那次调用会被拒绝。只有 tools/call 和对数据承载 URI 模板实例化resources/read(鉴权对称的 resources 路径)计数。控制面板签发的 wm_… API-key 调用者使用每日 50 次默认值。OAuth 额度按套餐解析;API Starter 和 API Business 当前使用相同默认值,企业 OAuth 可以不设上限。只有部署许可名单中的旧版运营方密钥不进入每日预留路径。豁免每日上限: describe_toolget_sourcestools/listprompts/listprompts/getresources/listresources/templates/listlogging/setLevelinitializenotifications/initializedping,以及对公开(具体、仅元数据)资源的 resources/read,例如 worldmonitor://seed-meta/freshness。(这些方法仍计入已认证调用的每分钟限制;匿名 get_sources 改用独立的每 IP 每分钟 10 次失败关闭限额。)
如何处理。 对于 HTTP 200 / 每分钟:退避约 1 秒后重试。限流器是滑动窗口而非令牌桶 —— 持续 60 rpm 没问题;任意 60 秒窗口内超过 60 的突发会被拒绝。对于 HTTP 429 / 每日:遵循 Retry-After(该值为 距 UTC 午夜的秒数)。若 MCP 每日上限是批量工作的瓶颈约束,请使用 REST/API 路径,或联系 Enterprise 获取自定义 MCP 限制。 付费套餐客户还会在持续用量越过套餐阈值时收到账户通知与有界节奏的邮件。这些通知绝不意味着自动升级、自动超额收费或自动迁入 API Business;支持或结账动作是显式的。

-32600 —— 请求信封无效

当请求体不是合法 JSON,或是合法 JSON 但缺少字符串类型的 method 字段时触发。位于 api/mcp/handler.ts 的两个站点。严格来说是客户端编码器 bug —— 格式良好的 JSON-RPC 客户端在生产中永远不会看到它。
如何处理。 审查请求编码器。请求体必须是 JSON 对象,含字符串类型的 method,以及(除 notifications/* 外的任何方法都需要的)id 字段。如果你从已知良好的客户端库看到 -32600,请针对本服务器提交 issue —— 它不应到达你这一侧。

-32601 —— 方法未找到

method 字段是字符串但未匹配到任何 handler。本服务器支持的方法:initializenotifications/initializedpingtools/listtools/callprompts/listprompts/getresources/listresources/templates/listresources/readlogging/setLevel
如何处理。 使用你的 initialize 响应中 capabilities 块里存在的方法。注意 resources/subscribe 实现(initialize 握手明确宣告 resources.subscribe: false)—— 尝试调用它的客户端会得到 -32601

-32602 —— 参数无效

最常见的错误代码,跨 tools/callprompts/getresources/readlogging/setLevel 共用。六种具体触发条件:
如何处理。 阅读 message —— 它总是告诉你缺少或错误了什么。对于工具,名称在 tools/list 中。对于提示,名称 + 参数 schema 在 prompts/list 中。对于资源,具体 URI 在 resources/list 中,参数化 URI 模板在 resources/templates/list 中。对于 logging/setLevel,有效级别是上面列出的 RFC 5424 子集

-32603 —— 内部错误

四类不同条件共用此代码;HTTP 状态码以及计费校验场景下的 X-Billing-Verification 响应头用于区分重试方式。 HTTP 200 —— 工具执行失败。 工具分发器抛出异常。最常见情形:工具读取的每个 Redis key 都返回 null(cache_all_null —— 瞬时 Redis 抖动或仍在预热的种子程序),或一个同侪内部抓取在调用中途失败。Pro 配额不会回滚:工具已执行,因此重试会再消耗一个槽位。
HTTP 503 —— 服务不可用。 OAuth/权益解析服务抛出、匿名免费层限流后端故障关闭、部署中缺少 MCP_INTERNAL_HMAC_SECRET,或 Pro/免费账户额度预留 Redis 失败时使用固定 Retry-After: 5。续订校验进行中或失败时也返回 503,但携带 X-Billing-Verification 与动态 Retry-After;权益后端不可达使用固定 5 秒。
message 文本标识触发条件: 非计费校验基础设施故障遵循固定 Retry-After: 5。计费校验行会携带 X-Billing-Verification,其 data.code 与该响应头一致;renewal_verification_pending / renewal_verification_failed 使用与实际提供方复查相匹配的动态 Retry-After(1–60 秒),客户端必须遵循响应头而不是假定 5 秒。entitlement_verification_unavailable 表示权益后端没有给出结论,固定使用 Retry-After: 5。续订校验状态表示本地订阅刚到期、服务器正在向计费提供方复核;已续订账户通常会在一到两次重试内恢复。 HTTP 200 —— resources/read 负载为空或不可解析。 resources/read 内部的防御性检查,针对内部 tools/call 分发器返回的 content[0].text 为空或非 JSON 文本的不应发生情形。 如何处理。 对于 HTTP 200 工具错误:约 1 秒后重试一次;若某个工具持续返回 -32603,请在 status.worldmonitor.app 查看相关种子程序。对于 HTTP 503:遵循 Retry-After。对于 resources/read 防御性情形:提交 issue —— 它表明你调用上游存在分发器契约违规。

HTTP 状态码

MCP handler 可能返回的每个状态码。大多数 JSON-RPC 回复 —— 包括大多数错误 —— 按惯例是 HTTP 200;下表标出 handler 升级状态码的情况。 有一个 HTTP 状态码不属于 JSON-RPC 错误:
  • 405 携带空主体来自 JSON-RPC 之前的方法校验。handler 接受 POST(JSON-RPC 路径)、GETLast-Event-ID SSE 重放;无 SSE Accept 时也可返回 200 markdown 指南)、HEAD(与 GET 相同的路由:重放确认、指南响应头,或非 /mcp 路径上的 JSON 200 探针确认)和 OPTIONS(CORS 预检)。只有带 SSE Accept 但缺少 Last-Event-IDGET/HEAD 才以 405 表示“不提供独立流”;其他不支持的方法也返回 405 + Allow: POST, GET, HEAD, OPTIONS。该端点不强制 Origin 允许列表:它通告通配 CORS,并通过显式 Authorization / X-WorldMonitor-Key 头鉴权,因此浏览器来源客户端(任意来源)均被接受。

软行为信封

软信封是高频失败模式,也是只检查 JSON-RPC 层的客户端最常遇到的解析 bug。tools/call 返回 HTTP 200没有 error 字段result.content[0].text 可解析为 JSON,所得对象带有一个前导下划线判别键。务必:
  1. result.content[0].text 解析为 JSON。
  2. 检查解析后的对象顶层是否含有 _budget_exceeded_jmespath_error 键。若有,视为错误,不要将同侪字段当作数据消费。
  3. 否则,将解析后的对象视为该工具的正常响应(缓存工具会将其包成 { cached_at, stale, data };RPC 工具返回其声明的形状)。

_budget_exceeded —— 响应超出每工具预算

每个工具声明一个每工具输出预算(_outputBudgetBytes),其大小设定为使响应能容纳在典型 agent 上下文窗口内。当序列化响应在所有每工具过滤器、summary 和 JMESPath 都已应用之后仍超出该预算时,分发器会用此信封替换超限负载 —— 仍在正常 MCP result 中,仍为 HTTP 200,仍无 isError
解码后的 text 负载:
字段:
  • _budget_exceeded: true —— 判别字段。始终字面为 true;绝不会出现在成功响应中。
  • budget_bytes: number —— 响应所对照检查的每工具预算。
  • actual_bytes: number —— 所有收窄后序列化响应的 UTF-8 字节长度。
  • hint: string —— 恢复建议。文本因调用者是否已传入 jmespath 参数而异;两种措辞都要求你收窄结果。
配额。 Pro 每日配额槽位不会回滚。工具在服务端度量序列化输出大小之前已执行,因此即便响应是错误信封,槽位仍计费。 恢复。 让投影更具选择性,叠加一个工具级过滤器(countrysincelimit),或两者并用。JMESPath 指南 有投影的示例。summary: true 标志(每个缓存工具都接受)返回一个服务端构建的计数与样本摘要,始终在预算以内。

_jmespath_error —— 投影失败

三种失败类型,都以相同信封形状返回。_jmespath_error 的值是一个字符串(不是对象);其内容为 <kind>: <details>。判别依据是第一个 : 之前的开头 kind 词元
original_keys 是未投影响应的顶层键(上限 50 项,截断时带有 ...<N more> 哨兵)。其存在正是为了让 LLM 能在下一次 tools/call 时自我纠正而无需重新抓取 —— 投影失败了,但工具抓取本身是成功的。 配额。 Pro 每日配额槽位回滚。工具抓取已成功;失败的是用户提供的投影。一个错误表达式每次尝试消耗一个配额槽位,这正是 original_keys 存在的原因 —— 让重试在额外一次调用内自我纠正,而非在 N 次调用上盲目猜测。 三种类型:

expression_too_long

JMESPath 表达式本身超过 1024 个 UTF-8 字节JMESPATH_MAX_EXPR_BYTES)。此上限有意设得宽松 —— 真实表达式通常为 50–200 字节 —— 而一个 1024+ 字节的表达式几乎总是意味着误把整个负载复制粘贴进了参数。
恢复。 缩短表达式。如果你确实需要 >1KB 的投影,将工作拆分到多次调用中。

invalid_expression

JMESPath 引擎解析表达式时抛出 —— 语法错误、未闭合的方括号、未知函数。kind 词元之后的 details 是解析器错误信息的逐字内容。
恢复。 修正表达式。两种最常见的 bug 是:(a) 在字符串字面量两端用了双引号([?country == "Iraq"]),而 JMESPath 要求单引号([?country == 'Iraq']);(b) 用了裸数字字面量([?deathsBest > 0]),而 JMESPath 要求反引号([?deathsBest > \0`]`)。JMESPath 指南 涵盖了这两个坑。

projection_too_large

表达式解析并运行成功,但投影输出在字符串化后超过 256 KBJMESPATH_MAX_OUTPUT_BYTES)。几乎总是表明一个失控的 multiselect-hash 或 multiselect-list 在大型数组上重复复制字段。
恢复。 使用更精简的 multiselect-hash(丢弃字段),先过滤输入数组([?...]),或对结果切片([0:N])。管道组合子(见 JMESPath 指南 示例 12)在此组合良好。

其他工具专属信封

少数工具在 content[0].text 内返回自己的应用层错误信封,而非通过 JSON-RPC -32602。这些在 工具参考 中按工具记录 —— 本目录列出它们以便客户端识别该模式:
  • describe_tool 返回 { "error": "missing_tool_name", "hint": "..." }{ "error": "unknown_tool", "requested": "...", "available": [...] }。配额豁免 —— 错误输入不消耗配额槽位。见 工具参考 → describe_tool
若你要构建通用信封检测器,对目录类信封以前导下划线(_budget_exceeded_jmespath_error)为键,对每工具信封以顶层 error: string 为键。

路线图

  • 预算超限时自动摘要。 未来的协议修订可能让 _budget_exceeded 响应在信封之外内联附带一个服务端构建的摘要(一个带注解的内容块),适用于摘要定义良好的那部分工具。推迟到生产遥测数据能证明每工具权衡合理之时。

另请参阅