Errors, limits & retries

In short: every error has the same shape, only 429, 503 and 504 are worth retrying, and failed requests are never billed. Every response carries an x-request-id; quote it when you contact support.

402 error bodyjson
{
  "error": {
    "code": "insufficient_credits",
    "message": "Your 1,000 free requests are used; add credits or subscribe at https://mcp-guard.ai/dashboard/billing. This request needs 5 checks (1 credit = 1 check); the workspace has 3.",
    "balance": 3,
    "needed": 5,
    "free_runs_remaining": 0,
    "free_runs_total": 1000,
    "unit": "check"
  }
}

Status codes

StatusMeaning
200Checked. x-credits-charged says what was billed (1 per check; 0 on a free request), x-free-runs-remaining how many free requests are left.
400invalid_json: the body is not valid JSON. invalid_request: the check is invalid (missing action, trigger not one of user_request / tool_result / correction / user_override, constraints or conversation of the wrong shape or too long). In a batch the message names the item, e.g. checks[3].trigger. too_many_checks: more than 64 checks in a batch.
401missing_api_key or invalid_api_key: no key, a malformed key, or a revoked one. Send Authorization: Bearer mcpg_live_… (x-api-key also works).
402insufficient_credits: the workspace's 1,000 free requests are used and its balance cannot cover this request (1 credit per check). The body carries balance and needed. Add credits or subscribe in the dashboard.
413payload_too_large: the body is over 512 KB, or one field (action, intent, context, …) is over 20,000 characters.
422invalid_request from the model server: an input passed the edge checks but could not be read (for example an action that is only whitespace). Fix the request.
429rate_limited: too many requests for this key. Honour Retry-After (seconds).
503inference_unavailable: capacity is busy or restarting (Retry-After: 2). Also auth_unavailable or usage_unavailable when a dependency is briefly down. Nothing was charged; retry with backoff.
504Gateway timeout. Rare; treat it like 503.

Limits

LimitMeaning
Checks per batch64 (POST /v1/guard/batch and the guard_batch MCP tool)
Characters per field20,000 (action text or JSON, intent, user_message, context)
Constraints per check32
Conversation turns50. Send the most recent ones: the model reads about 384 tokens per check.
Body size512 KB
Rate limit3,000 requests per 10 s per key (write to support@mcp-guard.ai to raise it)

What is billed

A successful check costs 1 credit; a batch of N checks costs N credits. While the workspace has free requests left, a request (a single check or a whole batch) uses one of them instead. Any request that fails, for whatever reason, costs nothing. See pricing.

Retry policy with exponential backoff

Retry 429, 503 and 504 (and network errors) with jittered exponential backoff; never retry other 4xx errors. The small random jitter stops many clients from retrying at the same instant. If the guard stays unreachable, decide on a fallback in advance: most agents should treat the action as ask.

Capacity is saturated for a moment: two 503s, then success.

  1. t=0.00s attempt 1 → 503 · wait 0.37s (0.25·2^0 = 0.25s + 0.12s jitter)
  2. t=0.49s attempt 2 → 503 · wait 0.57s (0.25·2^1 = 0.5s + 0.07s jitter)
  3. t=1.18s attempt 3 → 200

Running…

Pythonpython
import random, time, requests

def guard(check, key, attempts=5):
    for i in range(attempts):
        r = requests.post("https://api.mcp-guard.ai/v1/guard", json=check,
                          headers={"Authorization": f"Bearer {key}"}, timeout=10)
        if r.status_code not in (429, 503, 504):
            r.raise_for_status()   # other 4xx: fix the request, don't retry
            return r.json()
        wait = float(r.headers.get("retry-after", 0)) or min(8, 0.25 * 2 ** i)
        time.sleep(wait + random.random() * 0.25)
    r.raise_for_status()

Errors over MCP

The MCP server reports authentication and rate-limit failures as HTTP errors with a JSON-RPC error body, and tool problems (invalid arguments, not enough credits, inference busy) as a normal tool result with isError: true and a plain-English message. See MCP server.