MCP Server Errors
MCP Server 错误
如何处理 foura-mcp server 返回的错误。
这四个工具 (foura_auto, foura_single, foura_proxy, foura_browser) 的每个错误响应都是结构化的。LLM agent 可以读取 code 字段来执行重试逻辑,而无需解析自然语言文本。
Envelope 结构
每个错误 (isError: true) 都包含一个 structuredContent 块。每个错误包含的最少字段:
{
"service": "auto | single | proxy | browser",
"code": "rate_limited",
"error": "Rate limit exceeded"
}
出现带 HTTP 状态的上游错误时,也会提供 status。对于速率限制和容量错误,封装中会添加 retryAfter、current.{concurrency, rpm} 和 limits.{maxConcurrency, maxRpm},结构与底层的 REST API 错误相同。
稳定的 code 值
| 代码 | HTTP | 含义 | 可安全重试? |
|---|---|---|---|
ssrf_blocked |
n/a | 目标 IP 位于私有或保留范围内(RFC 5735,RFC 6598,IPv6 保留) | 否,请更改 URL |
upstream_non_json |
不一 | 上游返回的正文不是有效的 JSON | 可能,需调查 |
output_validation_failed |
n/a | MCP 服务器的 outputSchema 拒绝了上游响应(服务器错误或非预期的上游结构) |
可能,请报告 |
bad_request |
400 | 输入结构被 FourA API 拒绝 | 否,请修复参数 |
auth_failed |
401 | FourA API 密钥缺失、无效或已停用;这与目标站点的凭据无关 | 否,请修复 FourA 密钥 |
forbidden |
403 | 目标拒绝了请求(反爬虫,地理封锁) | 否,或切换到 foura_proxy |
not_found |
404 | 目标 URL 或 endpoint 不存在 | 否 |
rate_limited |
429 | 达到单密钥 RPM 上限 | 是,等待 retryAfter 秒 |
at_capacity |
503 | 达到并发上限(current.concurrency > limits.maxConcurrency) |
是,等待 retryAfter 秒 |
service_disabled |
503 | 您的帐户的服务已禁用(计划或维护) | 联系支持 |
service_unavailable |
503 | 来自上游的通用 503 错误 | 是,短期退避 |
upstream_error |
500+ | 上游 5xx 错误 | 是,指数退避 |
upstream_client_error |
4xx | 未在上述涵盖的其他 4xx 错误 | 通常为否 |
upstream_unknown |
其他 | 防御性,在实践中不应发生 | 需调查 |
no_eligible_proxy |
n/a | 没有 proxy 匹配严格的 exitCountries 允许列表;details.exitCountries 包含标准化范围 |
稍后重试;仅可显式更改范围 |
来自 MCP 服务器的 HTTP 级别错误
某些故障发生在 MCP 传输层,在调用任何工具之前发生。这些会返回原始 JSON-RPC 错误(无 structuredContent):
| HTTP | 发生条件 | 现象 |
|---|---|---|
| 400 | 不受支持的 MCP-Protocol-Version header |
Unsupported MCP-Protocol-Version: <value>. Supported: 2025-11-25, 2025-06-18, 2025-03-26, 2024-11-05, 2024-10-07. |
| 401 | 缺失或格式错误的 Authorization header |
JSON-RPC 错误 + WWW-Authenticate: Bearer realm="foura-mcp", resource_metadata="https://foura.ai/docs/mcp/server#auth" |
| 403 | 不允许的 Origin 或 Host header(DNS 重新绑定防御,CVE-2025-66414) |
Origin <value> is not in the allowlist 或 Host <value> is not in the allowlist |
| 405 | 在 /mcp 上的 GET 或 DELETE(无状态模式) |
Method not allowed in stateless mode. Use POST /mcp. |
| 413 | Request body > 256 KB | Express 默认 413 |
自托管者可以通过 FOURA_MCP_ALLOWED_HOSTS 和 FOURA_MCP_ALLOWED_ORIGINS 对 403 的允许列表进行环境变量配置。
拒绝的浏览器配置文件
如果 catalogue 无法提供某个浏览器配置文件,或者发送配置文件的 unblocker 设置为 false,则会作为 upstream 故障返回,原因包含在 error 中,并且 request 永远不会离开 FourA。该消息会列出可用的选项,因此请使用列出的组合之一重试,而不是使用相同的组合。
这些是拒绝,而不是中断:重试完全相同的 request 无法成功,并且没有使用其他浏览器代替。
重试策略
分为四类:
- 等待并重试:
rate_limited,at_capacity,service_unavailable,upstream_error。存在时遵循retryAfter。不存在时使用带抖动的指数退避算法。 - 保留作用域并稍后重试:
no_eligible_proxy。不要静默移除exitCountries或替换为另一个国家。仅当用户明确更改要求时,才更改或放宽 allowlist。 - 在修复输入或凭据之前不要重试:
bad_request,auth_failed,not_found,ssrf_blocked。对于auth_failed,请验证 FourA API 密钥,而不是目标站点的凭据。 - 根据内容需求切换工具:
foura_single上的forbidden可以作为进行有界foura_proxy尝试的理由。当所需内容需要 JavaScript 时,请使用foura_browser。成功选择 proxy 后,将返回的proxyID 传递给foura_browser.proxy,而不是开始新的选择。
重试示例 (TypeScript, MCP 端)
async function callWithRetry(call: () => Promise<any>, maxAttempts = 3) {
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
const r = await call();
if (!r.isError) return r;
const code = r.structuredContent?.code;
const wait = r.structuredContent?.retryAfter ?? Math.min(2 ** attempt, 30);
if (["rate_limited", "at_capacity", "service_unavailable", "upstream_error"].includes(code)) {
await new Promise((res) => setTimeout(res, wait * 1000));
continue;
}
// Non-retryable, surface to caller
throw new Error(`${code}: ${r.structuredContent?.error}`);
}
throw new Error("max retries exceeded");
}
相关
- MCP Server,四个工具及其 schema
- MCP Recipes,随服务器提供的工作流提示词
- API Errors,底层 REST API 层的相同封装