MCP 错误码与排查
个人 MCP 服务(/mcp)走 JSON-RPC 2.0 协议,错误分两层:认证与协议层返回 JSON-RPC error 对象,工具执行层返回 isError=true 的工具结果。两者的判断方式完全不同,请勿混用。
与 REST 的区别:REST 接口用
HTTP 状态码 + statusCode 表达错误(见「错误码」章节);MCP 服务的 HTTP 状态码只用于认证层,工具执行失败时 HTTP 仍为 200,必须读取响应体中的 isError。
一、认证与协议层错误(HTTP 非 200)
该层由鉴权中间件直接拦截,返回 JSON-RPC 错误结构,error.code 固定为 -32001,error.message 为可直接展示的中文原因。
{
"jsonrpc": "2.0",
"id": null,
"error": {
"code": -32001,
"message": "令牌身份与个人 Key 所有者不一致"
}
}| HTTP 状态 | error.code | error.message | 排查方向 |
|---|---|---|---|
| 400 | -32001 | 企业集成 API Key 不能访问个人 MCP 服务,请使用个人 API Key | 请求头误用了 X-API-Key/X-API-Secret。MCP 只用个人凭据。 |
| 400 | -32001 | 个人 MCP 凭据操作人固定为密钥所有者,不接受身份指定请求头 | 请求误带了 X-Employee-Virtual-Id。MCP 操作人由密钥所有者确定,不可指定。 |
| 401 | -32001 | 缺少个人 API Key 凭据 | 未携带 Authorization: Bearer。同时会返回 WWW-Authenticate 资源元数据挑战。 |
| 401 | -32001 | 个人 API Key 格式无效 | 个人密钥必须以 公开标识.秘密 的形式提供,且前缀须为 hqxzmcp_;请核对复制是否完整。 |
| 401 | -32001 | 个人 API Key 无效 | 密钥不存在、已删除,或秘密部分校验不通过。请到工作台重新生成。 |
| 401 | -32001 | 个人 API Key 配置无效 | 密钥记录缺少所有者或秘密摘要等必要信息,属异常数据,请联系管理员。 |
| 401 | -32001 | Bearer 令牌无效或已过期 | OAuth 令牌校验不通过,或令牌对应的客户端/密钥已不存在。需重新授权。 |
| 401 | -32001 | 密钥已到期,请到所属企业工作台续期 | 个人 API Key 超过有效期。 |
| 401 | -32001 | 令牌已随密钥重置失效,请重新授权 | 密钥被重置后旧令牌凭据版本不匹配,需重新授权。 |
| 403 | -32001 | 请求来源不在 MCP 允许列表中 | 请求 Origin 不在允许域名内,检查客户端来源。 |
| 403 | -32001 | 个人 MCP 访问令牌必须绑定密钥所有者身份,请重新授权 | 令牌没有员工身份声明,需重新走授权流程。 |
| 403 | -32001 | OAuth 客户端已停用 / 已过期 | 授权客户端状态异常,请到工作台检查客户端配置。 |
| 403 | -32001 | 个人 API Key 已停用 | 密钥状态非启用,请到工作台启用。 |
| 403 | -32001 | 令牌身份与个人 Key 所有者不一致 | 授权令牌所属员工与密钥所有者不是同一人,属于越权拦截。 |
| 403 | -32001 | 令牌 scope 与个人 Key 权限无交集 | 令牌授权范围与密钥权限没有重叠,任何工具都无法调用,需重新授权或补权限。 |
二、工具执行层错误(HTTP 200,isError=true)
通过认证后,工具执行失败不再使用 JSON-RPC error,而是在正常响应中返回 isError=true,并在 structuredContent.callResultStatus 给出机器可判定的失败类别。请以该字段分支处理,不要依赖文本内容匹配。
| callResultStatus | 含义 | 典型原因与处理方式 |
|---|---|---|
| 0 | Success 成功 | 正常结果,读取 structuredContent。 |
| 1 | ArgumentError 参数错误 | 必填缺失、guid 格式无效、传入未声明字段、virtualId 不属于当前企业等。修正参数后重试,不要原样重试。 |
| 2 | PermissionDenied 权限拒绝 | API Key 未授权该工具所需 scope,或员工无对应业务权限。不要重试,需补授权。 |
| 3 | DownstreamFailed 下游业务失败 | 内部业务服务拒绝,例如任务状态不允许该动作。structuredContent 会附带任务当前 status 与可用动作 nextActions,按提示换路而非重试。 |
| 4 | SystemError 系统异常 | 服务端内部异常,或权限校验服务暂时不可用(不会降级放行)。可稍后重试;持续失败请联系管理员并提供时间点。 |
| 5 | RateLimited 额度耗尽 | 企业或成员当日 MCP 调用额度用完,或调用被暂停。当日重试无效,额度按天重置。 |
| 6 | Running 执行中 | 写操作已受理但尚未结束,计量状态中间态。请以最终工具结果为准。 |
| 7 | Aborted 中断 | 进程中断导致执行结果未知,服务统计归入失败,不伪装成功也不自动重放。请按 X-Client-Request-Id 核对业务数据后再决定是否重提。 |
系统异常不返回内部细节:
callResultStatus=4 时文本提示固定为「系统异常」,不会返回异常消息、堆栈或内网信息。这是防止内部信息外泄的刻意设计,不是信息缺失。需要定位时请提供服务端日志中的时间点与工具名。
三、协议层错误 -32603
error.code = -32603(Internal error)表示请求没有进入业务处理逻辑,通常与客户端实现有关,而不是业务规则拒绝。
| 现象 | 原因 | 处理方式 |
|---|---|---|
返回 -32603,且服务端日志显示 tools/list 正常 | 请求体 JSON 结构或序列化不符合协议,服务端在反序列化阶段即失败 | 检查客户端的 JSON 序列化实现与连接复用,确认每个请求体是独立的完整 JSON-RPC 对象 |
服务端日志报 Path: $.arguments,BytePositionInLine 逐次递增 | 多条 JSON-RPC 消息被拼接进同一个请求体发送 | 检查客户端是否复用了未读取完的响应流,或并发写入同一连接 |
| 工具名拼写错误 | 未知工具 | 会返回 InvalidParams;请以 tools/list 返回的工具名为准 |
无状态服务说明:MCP 服务为无状态模式,不返回也不校验
Mcp-Session-Id,每次请求相互独立。客户端发送 notifications/initialized 时,服务端日志会出现 no handler is available 提示 —— 这是无状态服务未注册该通知处理器导致的正常现象,不影响调用,可忽略。
排查建议
- 先看 HTTP 状态码:非
200属认证层,直接读error.message。 - HTTP
200时再看isError:为true则读structuredContent.callResultStatus分支处理。 callResultStatus=3时优先读structuredContent中的任务状态与nextActions,按提示换路。- 写操作超时或中断时,使用原
X-Client-Request-Id重试;不要用新标识重复提交,避免重复写入。 - 额度类失败(
callResultStatus=5)当日重试无效,额度按天重置。 - 确认客户端具备读取 SSE(
text/event-stream)响应体的能力,否则可能拿到空结果。