MCP 서버 에러
How to handle errors returned by the foura-mcp server.
Every error response from any of the three tools (foura_single, foura_proxy, foura_browser) is structured. LLM agents can read the code field for retry logic without parsing prose.
Envelope 구조
모든 에러(isError: true)에는 structuredContent 블록이 포함됩니다. 모든 에러의 최소 필드는 다음과 같습니다.
{
"service": "single | proxy | browser",
"code": "rate_limited",
"error": "Rate limit exceeded"
}
HTTP status가 있는 업스트림 에러의 경우 status도 함께 제공됩니다. rate-limit 및 용량 에러의 경우, envelope에 retryAfter, current.{concurrency, rpm}, limits.{maxConcurrency, maxRpm}이 추가되며, 이는 기본 REST API errors와 동일한 구조입니다.
안정적인 code 값
| Code | HTTP | 의미 | 재시도 가능 여부 |
|---|---|---|---|
ssrf_blocked |
n/a | 대상 IP가 사설 또는 예약된 대역에 있음 (RFC 5735, RFC 6598, IPv6 reserved) | 불가, URL을 변경하세요 |
upstream_non_json |
가변 | 업스트림이 유효하지 않은 JSON body를 반환함 | 가능성 있음, 확인 필요 |
output_validation_failed |
n/a | MCP 서버의 outputSchema가 업스트림 response를 거부함 (서버 버그 또는 예상치 못한 업스트림 구조) |
가능성 있음, 보고 필요 |
bad_request |
400 | 입력 구조가 FourA API에 의해 거부됨 | 불가, 인자 수정 필요 |
auth_failed |
401 | 키가 누락되었거나, 유효하지 않거나, 비활성화됨 | 불가, 키 수정 필요 |
forbidden |
403 | 대상이 request를 거부함 (안티봇, 지역 차단) | 불가, 또는 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 |
other | 방어적 코드, 실제로 발생해서는 안 됨 | 확인 필요 |
MCP 서버의 HTTP 레벨 에러
일부 실패는 도구가 호출되기 전, MCP 전송 레이어에서 발생합니다. 이 경우 raw 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 호출 (stateless 모드) |
Method not allowed in stateless mode. Use POST /mcp. |
| 413 | Request body > 256 KB | Express 기본 413 |
403 에러에 대한 허용 목록은 셀프 호스팅 사용자를 위해 FOURA_MCP_ALLOWED_HOSTS 및 FOURA_MCP_ALLOWED_ORIGINS 환경 변수로 설정할 수 있습니다.
재시도 전략
세 가지 범주:
- 대기 후 재시도:
rate_limited,at_capacity,service_unavailable,upstream_error.retryAfter값이 제공되면 이를 준수하세요 (서버 힌트, 초 단위). 제공되지 않는 경우 지터(jitter)를 포함한 지수 백오프를 사용하세요. - 재시도 불가, 입력 수정:
bad_request,auth_failed,not_found,ssrf_blocked. - 도구 전환:
foura_single에서forbidden발생 시 →foura_proxy로 에스컬레이션합니다. 페이지에 JavaScript도 필요한 경우foura_browser를 사용합니다.foura_browser가forbidden을 보고하는 경우, 먼저foura_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, 세 가지 도구 및 해당 스키마
- MCP Recipes, 서버와 함께 제공되는 워크플로우 프롬프트
- API Errors, 기본 REST API 레이어의 동일한 envelope 구조