Błędy serwera MCP
Błędy serwera MCP
Jak obsługiwać błędy zwracane przez serwer foura-mcp.
Każda odpowiedź błędu z dowolnego z czterech narzędzi (foura_auto, foura_single, foura_proxy, foura_browser) ma ustrukturyzowaną postać. Agenci LLM mogą odczytywać pole code na potrzeby logiki ponawiania prób bez konieczności parsowania tekstu.
Kształt koperty
Każdy błąd (isError: true) zawiera blok structuredContent. Minimalne pola każdego błędu:
{
"service": "auto | single | proxy | browser",
"code": "rate_limited",
"error": "Rate limit exceeded"
}
W przypadku błędów upstream ze statusem HTTP obecne jest również status. Gdy współdzielony limit platformy odrzuca wywołanie, koperta dodaje retryAfter, current.{concurrency, rpm} oraz limits.{maxConcurrency, maxRpm}, o takiej samej strukturze jak bazowe błędy REST API.
Gdy wywołanie zostanie odrzucone przez jeden z limitów Twojego planu, kodem JEST ten limit: plan_limit_, a po nim credits, bandwidth, rate, concurrency, browser_daily, premium lub feature. retryAfter zawiera czas oczekiwania, jeśli odczekanie rozwiązuje problem, i nie występuje w przypadku limitu, którego oczekiwanie nie może zresetować, takiego jak funkcja niedostępna w danym planie. plan_limit_browser_daily również nie zawiera retryAfter: resetuje się o północy UTC.
W foura_auto limit planu osiągnięty w ramach drabinki zwracany jest jako rate_limited lub forbidden, z kodem planu w reason.
Stabilne wartości code
| Kod | HTTP | Znaczenie | Bezpieczne ponowienie? |
|---|---|---|---|
ssrf_blocked |
nd. | Cel jest adresem prywatnym lub zastrzeżonym (RFC 5735, RFC 6598, IPv6 reserved), URL nie używa http(s) lub jego nazwa hosta nie została rozwiązana | Nie, sprawdź URL. Krótkotrwały błąd rozpoznawania nazwy można ponowić |
upstream_non_json |
różne | Upstream zwrócił treść, która nie jest poprawnym JSON-em | Być może, zbadaj problem |
output_validation_failed |
nd. | Komponent outputSchema serwera MCP odrzucił odpowiedź upstreamu lub narzędzie nie mogło ukończyć wywołania (brak skonfigurowanego klucza API, API nieosiągalne) |
Być może: sprawdź konfigurację, a następnie zgłoś |
bad_request |
400 | Format danych wejściowych odrzucony przez API FourA | Nie, popraw argumenty |
auth_failed |
401 | Klucz API FourA jest nieobecny, nieprawidłowy lub dezaktywowany; nie dotyczy to danych uwierzytelniających witryny docelowej | Nie, popraw klucz FourA |
forbidden |
403 | Cel odrzucił żądanie (weryfikacja witryny, blokada regionalna) | Nie, lub przełącz na foura_proxy |
not_found |
404 | Docelowy URL lub endpoint nie istnieje | Nie |
rate_limited |
429 | Współdzielony limit na minutę platformy lub kod 429 z celu odrzucony przez regułę validate. W foura_auto może to być również limit kredytów, transferu lub rate limit Twojego planu (zobacz reason) |
Tak, poczekaj retryAfter jeśli podano, w przeciwnym razie wycofaj się (backoff) |
at_capacity |
503 | Osiągnięto limit współbieżności (current.concurrency > limits.maxConcurrency) |
Tak, odczekaj retryAfter s |
service_disabled |
503 | Usługa jest wyłączona z powodu prac konserwacyjnych. Narzędzie niedostępne w Twoim planie zwraca plan_limit_feature |
Skontaktuj się ze wsparciem |
service_unavailable |
503 | Ogólny błąd 503 z upstreamu | Tak, krótki backoff |
upstream_error |
500+ lub 0 | Cel zwrócił błąd serwera albo w foura_proxy, foura_browser i foura_auto nie udzielił odpowiedzi |
Tak, wykładniczy backoff |
upstream_client_error |
4xx | Inny kod 4xx nieujęty powyżej | Zazwyczaj nie |
upstream_unknown |
inne | Żądanie zostało wykonane, ale nie przyniosło zaakceptowanej odpowiedzi: w foura_single cel nie odpowiedział (timeout, odrzucone połączenie), a w dowolnym narzędziu Twoja reguła validate odrzuciła odpowiedź 2xx lub 3xx. Sprawdź status oraz error |
Zbadaj problem |
no_eligible_proxy |
nd. | Żadne proxy nie spełnia ścisłej białej listy exitCountries; details.exitCountries zawiera znormalizowany zakres |
Ponów później; zmieniaj zakres wyłącznie jawnie |
plan_limit_credits |
429 | Miesięczne kredyty w Twoim planie zostały wyczerpane | Tak, po retryAfter, lub zmień plan |
plan_limit_bandwidth |
429 | Limit transferu w Twoim planie został wyczerpany w tym okresie rozliczeniowym | Tak, po retryAfter, lub zmień plan |
plan_limit_rate |
429 | Przekroczono limit żądań na minutę dla tego endpointu w Twoim planie | Tak, po retryAfter |
plan_limit_concurrency |
429 | Przekroczono limit jednoczesnych żądań dla tego endpointu w Twoim planie | Tak, po retryAfter |
plan_limit_browser_daily |
429 | Dzienny limit Browser w Twoim planie został wyczerpany | Tak, jutro, lub użyj foura_single / foura_proxy |
plan_limit_premium |
403 | Wysłano exitClass: "premium" w planie, który nie obejmuje wyjść premium |
Nie, usuń parametr lub zmień plan |
plan_limit_feature |
403 | Plan nie obejmuje tego endpointu ani tej funkcji | Nie, zmień plan |
Błędy na poziomie HTTP z serwera MCP
Niektóre błędy występują na warstwie transportowej MCP, zanim jakiekolwiek narzędzie zostanie wywołane. Zwracają one surowe błędy JSON-RPC (brak structuredContent):
| HTTP | Kiedy | Co widzisz |
|---|---|---|
| 400 | Nieobsługiwany nagłówek 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 | Wywołanie narzędzia lub odczyt zasobu bez klucza API. Listowanie narzędzi i promptów działa bez niego | Błąd JSON-RPC + WWW-Authenticate: Bearer realm="foura-mcp" |
| 403 | Niedozwolony nagłówek Origin lub Host (ochrona przed DNS-rebinding, CVE-2025-66414) |
Origin <value> is not in the allowlist lub Host <value> is not in the allowlist |
| 405 | GET lub DELETE na /mcp (tryb bezstanowy) |
Method not allowed in stateless mode. Use POST /mcp. |
| 413 | Ciało żądania > 256 KB | Domyślny błąd Express 413 |
Listy dozwolonych dla 403 są konfigurowalne przez zmienne środowiskowe dla instalacji self-hosted za pomocą FOURA_MCP_ALLOWED_HOSTS oraz FOURA_MCP_ALLOWED_ORIGINS.
Odrzucone profile przeglądarek
Profil przeglądarki, którego katalog nie może udostępnić, lub profil wysłany z unblocker ustawionym na false, wraca jako błąd upstreamu z przyczyną w error, a żądanie nigdy nie opuszcza FourA. Komunikat wskazuje dostępne opcje, więc ponów próbę z jedną z wymienionych kombinacji zamiast tej samej.
Są to odrzucenia, a nie awarie: ponowienie identycznego żądania nie może się udać, a żadna inna przeglądarka nie została użyta w zamian.
Strategia ponawiania (retry)
Pięć kategorii:
- Twój własny plan odrzucił żądanie, nie cel: dowolny kod
plan_limit_*. To samo zadanie wykonane przez inne narzędzie również zostanie odrzucone, więc zmiana endpointu marnuje tylko czas. OdczekajretryAfter, jeśli jest podany; w przeciwnym razie plan musi ulec zmianie.plan_limit_premiummożesz rozwiązać samodzielnie, usuwającexitClass. - Odczekaj i ponów:
rate_limited,at_capacity,service_unavailable,upstream_error. PrzestrzegajretryAfter, gdy jest obecny. Stosuj wykładnicze wycofywanie (exponential backoff) z szumem (jitter), gdy go brakuje. Nie reaguj ponownym wysyłaniem wszystkich zakolejkowanych wywołań narzędzi naraz: zamiast tego zmniejsz liczbę zadań wykonywanych równolegle. - Zachowaj zakres i spróbuj ponownie później:
no_eligible_proxy. Nie usuwajexitCountriesani nie zastępuj po cichu innym krajem. Zmień lub rozszerz listę dozwolonych tylko wtedy, gdy użytkownik wyraźnie zmieni wymaganie. - Nie ponawiaj, dopóki dane wejściowe lub poświadczenia nie zostaną poprawione:
bad_request,auth_failed,not_found,ssrf_blocked. W przypadkuauth_failedzweryfikuj klucz API FourA, a nie dane uwierzytelniające witryny docelowej. - Zmień narzędzie, gdy wymaga tego zawartość:
forbiddenwfoura_singlemoże uzasadniać ograniczoną próbęfoura_proxy. Użyjfoura_browser, gdy żądana zawartość wymaga JavaScriptu. Po pomyślnym wyborze proxy przekaż zwrócony identyfikatorproxydofoura_browser.proxyzamiast rozpoczynać nowy wybór.
Przykład ponawiania (TypeScript, strona 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");
}
Powiązane
- MCP Server, cztery narzędzia i ich schematy
- MCP Recipes, prompty workflow dostarczane z serwerem
- API Errors, ta sama koperta na poziomie bazowego REST API
- Rate Limits, limity konta i platformy stojące za
rate_limitedorazat_capacity