MCP 서버 오류
MCP Server 에러
foura-mcp server에서 반환된 에러를 처리하는 방법입니다.
4개 도구(foura_auto, foura_single, foura_proxy, foura_browser)의 모든 에러 response는 정형화되어 있습니다. LLM 에이전트는 줄글을 파싱할 필요 없이 재시도 로직에 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 오류와 동일한 구조를 갖습니다.
플랜 자체의 한도로 인해 호출이 거부되는 경우 코드는 해당 한도 자체를 나타냅니다. plan_limit_ 뒤에 credits, bandwidth, rate, concurrency, browser_daily, premium 또는 feature가 붙습니다. 대기하여 해결될 수 있는 경우 retryAfter에 대기 시간이 포함되며, 플랜에 포함되지 않은 기능처럼 대기로 해결할 수 없는 한도에는 포함되지 않습니다. plan_limit_browser_daily 역시 retryAfter를 포함하지 않으며, 자정 UTC에 초기화됩니다.
foura_auto의 경우 사다리 내에서 플랜 한도에 도달하면 rate_limited 또는 forbidden로 반환되며, reason에 플랜 코드가 포함됩니다.
고정 code 값
| 코드 | HTTP | 의미 | 재시도 안전 여부 |
|---|---|---|---|
ssrf_blocked |
해당 없음 | 대상이 사설 또는 예약 주소(RFC 5735, RFC 6598, IPv6 예약)이거나, URL이 http(s)가 아니거나, 호스트 이름이 확인되지 않음 | 불가, URL을 확인하십시오. 일시적으로 실패한 조회의 경우 재시도 가능 |
upstream_non_json |
다양함 | 업스트림이 유효한 JSON이 아닌 본문을 반환함 | 가능성 있음, 원인 조사 필요 |
output_validation_failed |
해당 없음 | MCP 서버의 outputSchema이(가) 업스트림 응답을 거부했거나, 도구가 호출을 완료하지 못함(API 키 미설정, API 접근 불가) |
가능성 있음: 설정을 확인한 후 보고 |
bad_request |
400 | FourA API에서 입력 형식을 거부함 | 불가, 인수를 수정하십시오 |
auth_failed |
401 | FourA API 키가 누락되었거나 유효하지 않거나 비활성화됨. 대상 사이트의 인증 정보와는 무관함 | 불가, FourA 키를 수정하십시오 |
forbidden |
403 | 대상이 요청을 거부함(사이트 검사, 국가 제한) | 불가, 또는 foura_proxy(으)로 전환 |
not_found |
404 | 대상 URL 또는 엔드포인트가 존재하지 않음 | 불가 |
rate_limited |
429 | 플랫폼의 공유 분당 허용량이거나, validate이(가) 거부한 대상으로부터의 429 응답임. foura_auto의 경우 플랜의 크레딧, 트래픽 또는 rate limit일 수도 있음(reason 참조) |
가능, retryAfter이(가) 있으면 대기하고 그렇지 않으면 지연 후 재시도 |
at_capacity |
503 | 동시성 상한 도달(current.concurrency > limits.maxConcurrency) |
가능, retryAfter초 대기 |
service_disabled |
503 | 유지보수를 위해 서비스가 꺼져 있음. 플랜에 포함되지 않은 도구는 plan_limit_feature(으)로 반환됨 |
지원 팀에 문의 |
service_unavailable |
503 | 업스트림의 일반적인 503 오류 | 가능, 짧은 지연 후 재시도 |
upstream_error |
500+ 또는 0 | 대상이 서버 오류로 응답했거나, foura_proxy에서 foura_browser 및 foura_auto이(가) 응답하지 않음 |
가능, 지수 백오프 적용 |
upstream_client_error |
4xx | 위에 포함되지 않은 기타 4xx | 일반적으로 불가 |
upstream_unknown |
기타 | 요청이 실행되었으나 허용 가능한 응답을 생성하지 못함: foura_single에서 대상이 응답하지 않았거나(타임아웃, 연결 거부), 모든 도구에서 validate이(가) 2xx 또는 3xx 응답을 거부함. status 및 error 확인 필요 |
원인 조사 필요 |
no_eligible_proxy |
해당 없음 | 엄격한 exitCountries 허용 목록과 일치하는 프록시가 없음. details.exitCountries에 정규화된 범위가 포함됨 |
나중에 재시도. 범위는 명시적으로만 변경 |
plan_limit_credits |
429 | 플랜의 월간 크레딧이 모두 소진됨 | 가능, retryAfter 이후 또는 플랜 변경 |
plan_limit_bandwidth |
429 | 이번 청구 주기의 플랜 트래픽 허용량이 모두 소진됨 | 가능, retryAfter 이후 또는 플랜 변경 |
plan_limit_rate |
429 | 해당 엔드포인트에 대한 플랜의 분당 요청 수 초과 | 가능, retryAfter 이후 |
plan_limit_concurrency |
429 | 해당 엔드포인트에 대한 플랜의 동시 요청 수 초과 | 가능, retryAfter 이후 |
plan_limit_browser_daily |
429 | 플랜의 일일 Browser 허용량이 모두 소진됨 | 가능, 내일 재시도하거나 foura_single / foura_proxy 사용 |
plan_limit_premium |
403 | 프리미엄 출구가 포함되지 않은 플랜에서 exitClass: "premium"을(를) 전송함 |
불가, 매개변수를 제거하거나 플랜 변경 |
plan_limit_feature |
403 | 해당 엔드포인트나 기능이 플랜에 포함되어 있지 않음 | 불가, 플랜 변경 |
MCP 서버의 HTTP 수준 오류
일부 실패는 도구가 호출되기 전 MCP 전송 계층에서 발생합니다. 이러한 실패는 원시 JSON-RPC 오류를 반환합니다 (structuredContent 없음):
| HTTP | 발생 조건 | 표시 내용 |
|---|---|---|
| 400 | 지원되지 않는 MCP-Protocol-Version 헤더 |
Unsupported MCP-Protocol-Version: <value>. Supported: 2025-11-25, 2025-06-18, 2025-03-26, 2024-11-05, 2024-10-07. |
| 401 | API key 없이 도구 호출 또는 리소스 읽기 시도. 도구 및 프롬프트 목록 조회는 API key 없이도 작동함 | JSON-RPC 오류 + WWW-Authenticate: Bearer realm="foura-mcp" |
| 403 | 허용되지 않은 Origin 또는 Host 헤더 (DNS 리바인딩 방어, CVE-2025-66414) |
Origin <value> is not in the allowlist 또는 Host <value> is not in the allowlist |
| 405 | /mcp(stateless 모드)에서의 GET 또는 DELETE |
Method not allowed in stateless mode. Use POST /mcp. |
| 413 | 요청 본문 크기 > 256 KB | Express 기본 413 |
403 허용 목록은 자체 호스팅 사용자를 위해 FOURA_MCP_ALLOWED_HOSTS 및 FOURA_MCP_ALLOWED_ORIGINS 환경 변수로 구성할 수 있습니다.
거부된 브라우저 프로필
카탈로그에서 제공할 수 없는 브라우저 프로필이거나 unblocker이 false로 설정되어 전송된 프로필은 error에 이유가 포함된 업스트림 실패로 반환되며 요청은 FourA를 떠나지 않습니다. 메시지에 사용 가능한 항목이 명시되므로 동일한 조합 대신 나열된 조합 중 하나로 재시도하세요.
이는 장애가 아닌 거부입니다. 동일한 요청을 다시 시도해도 성공할 수 없으며 다른 브라우저가 대신 사용되지도 않았습니다.
재시도 전략
5가지 범주:
- 타깃이 아닌 사용자의 플랜에서 거부됨: 모든
plan_limit_*코드. 다른 도구를 통한 동일한 작업도 거부되므로 엔드포인트를 변경하는 것은 시간만 낭비하게 됩니다.retryAfter값이 있으면 대기하고, 그렇지 않으면 플랜을 변경해야 합니다.plan_limit_premium는exitClass를 제거하여 직접 해결할 수 있는 유일한 항목입니다. - 대기 후 재시도:
rate_limited,at_capacity,service_unavailable,upstream_error.retryAfter가 있으면 이를 준수하세요. 없는 경우 지터를 적용한 지수 백오프를 사용하세요. 대기 중인 모든 도구 호출을 한 번에 다시 실행하지 말고, 병렬 실행 수를 줄이세요. - 범위를 유지하고 나중에 재시도:
no_eligible_proxy.exitCountries를 제거하거나 다른 국가로 임의 대체하지 마세요. 사용자가 명시적으로 요구 사항을 변경할 때만 허용 목록을 변경하거나 확장하세요. - 입력 또는 인증 정보가 수정될 때까지 재시도 금지:
bad_request,auth_failed,not_found,ssrf_blocked.auth_failed의 경우 타깃 사이트 인증 정보가 아니라 FourA API key를 확인하세요. - 콘텐츠 요구 사항에 따라 도구 전환:
foura_single에서의forbidden는 제한적인foura_proxy시도를 정당화할 수 있습니다. 원하는 콘텐츠에 JavaScript가 필요한 경우foura_browser를 사용하세요. 프록시 선택이 성공한 후에는 새 선택을 시작하지 말고 반환된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, 4가지 도구 및 해당 스키마
- MCP Recipes, 서버와 함께 제공되는 워크플로 프롬프트
- API Errors, 기본 REST API 계층의 동일한 엔벨로프
- Rate Limits,
rate_limited및at_capacity기반의 계정 및 플랫폼 제한