Skip to main content
The Closient MCP server exposes the same business operations as the REST API (GTIN validation, resolution, product lookup, QR-URL generation, more to come) but speaks JSON-RPC 2.0 instead of HTTP. This page documents how MCP tools surface failures so agents can react predictably — distinguishing “GTIN not found” from “rate limited” from “internal error” without parsing free-form strings.

Envelope shape

When a tool fails, the result it returns to the client has an error field matching the JSON-RPC 2.0 error-object shape:
{
  "error": {
    "code": -32200,
    "message": "Not Found",
    "data": {
      "type": "https://closient.com/docs/errors/not_found",
      "title": "Not Found",
      "status": 404,
      "detail": "No product found for GTIN 00614141123452",
      "error_code": "not_found",
      "retryable": false,
      "timestamp": "2026-04-26T02:34:56+00:00"
    }
  }
}
The data payload is an RFC 9457 Problem Details document — the same structure the REST API returns under Content-Type: application/problem+json. Agents that already understand Closient’s REST error shape do not need a second mapping. Successful tool calls do not include an error key — the tool’s normal payload is returned directly.

Code table

JSON-RPC error codes are stable and grouped by failure class:
CodeClassMeaningRetryable?
-32001Transport / authenticationMissing or invalid token (unauthorized).After auth
-32002Transport / authenticationToken lacks required scope (forbidden).No
-32003Transport / authenticationRate limit exceeded (rate_limited). See retry_after.Yes
-32100Request validationMalformed request (bad_request).No
-32101Request validationField-level validation error (validation_error).No
-32102Request validationSemantically invalid (unprocessable_entity).No
-32200Business ruleResource does not exist (not_found).No
-32201Business ruleState conflict, e.g. already claimed (conflict).No
-32300Upstream / internalUnexpected server error (internal_error).Backoff
Adding new codes within these ranges is non-breaking. Renumbering existing codes is a breaking change.

Common errors per tool

ToolLikely codes
pingnone — health check has no failure modes.
validate_gtinnone — invalid GTINs return valid: false in payload.
resolve_gtin-32101 (invalid GTIN), -32200 (no rule).
lookup_product-32101 (invalid GTIN). Missing GTINs return found: false rather than an error.
generate_qr_url-32101 (invalid GTIN), -32002 (missing qr:generate scope, when auth wires up).

Handling errors in an agent

result = client.call_tool("resolve_gtin", {"gtin": "00614141123452"})

if "error" in result:
    err = result["error"]
    code = err["code"]
    problem = err["data"]

    if problem.get("retryable"):
        # Optional: respect retry_after on rate-limit responses.
        time.sleep(problem.get("retry_after", 5))
        ...
    elif code == -32200:
        # Resource not found — surface to the user, do not retry.
        ...
    else:
        # 4xx-class user error or 5xx-class server error.
        ...
else:
    # Success path — use the tool's normal payload.
    ...

Reference

  • Tracking ticket: C-2491.
  • Implementation: backend/closient/mcp_errors.py.
  • REST counterpart: see Errors.