Errors
Two distinct kinds, and conflating them is why some integrations retry when they should not.
Protocol errors
The request never reached a tool. JSON-RPC error, non-200 HTTP status.
| Code | HTTP | Meaning | Cause |
|---|---|---|---|
-32602 | 400 | Invalid _meta envelope | A required _meta key is missing |
-32020 | 400 | Header mismatch | Mcp-Name/Mcp-Method disagrees with the body |
-32022 | 400 | Unsupported protocol version | With data.supported listing what is served |
-32601 | 404 | Method not found | Unknown JSON-RPC method |
-32600 | 405 | Invalid request | GET or DELETE on the endpoint |
| none | 403 | Forbidden | Origin or Host not allowlisted |
| none | 415 | Unsupported media type | Content type is not JSON |
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32022,
"message": "Unsupported protocol version: 1900-01-01",
"data": { "supported": ["2026-07-28"], "requested": "1900-01-01" }
}
}
Tool errors
The tool ran and could not answer. HTTP 200, a normal result with
isError: true. That is the MCP contract: a tool failure is data, not a
transport fault.
{
"content": [{ "type": "text", "text": "Not found in the Vulnetix VDB: ..." }],
"isError": true,
"_meta": { "vulnetix/plan": "community" }
}
| Situation | What comes back |
|---|---|
| No credential | Which header to set, or to run vulnetix_auth_start |
| Rejected credential (401) | The same, plus that both halves are required |
| Access denied (403) | The organisation may be inactive |
| Unknown advisory (404) | Not found, with the identifier echoed |
| Rate limit (429) | Reset time, and an explicit instruction not to retry |
| Maintenance | Reads may still work; retry after the window |
| Plan-locked feature | What it needs and how to get it |
| Response too large | Which argument to narrow |
| Invalid arguments | The failing field and why |
Why a rate limit is not an HTTP 429
A transport-level 429 makes clients retry the whole JSON-RPC exchange, and many do so automatically. Since a quota reset is hours away, that turns one failure into a retry storm that cannot possibly succeed.
So it is returned in band, with text aimed at the agent:
Vulnetix daily rate limit exhausted for this organisation. The quota resets at 2026-08-11T00:00:00Z. Do NOT retry this call. Retrying cannot succeed until the quota resets and only burns further budget. Either wait, or authenticate a higher-tier organisation.
The server itself never retries a 429 upstream either.
Degraded results
Composing tools return partial results instead of failing whole:
"_meta": { "vulnetix/degraded": ["vendor-trends"] }
The successful sections are present and usable. The listed ones failed. This is
not an error result, and isError is absent, because four of five sections is a
useful answer.
AI analysis skipped
Not an error either. The database result is complete; only the optional analysis is absent:
{
"analysis": null,
"analysisSkipped": "AI analysis requires a Pro plan or above; this organisation is on 'community'. The deterministic result above is unaffected.",
"_meta": { "vulnetix/ai": { "skipped": "gated", "reason": "..." } }
}
skipped is one of gated, unconfigured or disabled.
Retry guidance
| Kind | Retry? |
|---|---|
-32602, -32020 | No, fix the request |
-32022 | Yes, once, with a supported version |
403, 415 | No |
| Tool 401/403 | No, fix the credential |
| Tool 404 | No, try a GHSA alias |
| Tool 429 | No, wait for the reset |
| Timeout | Yes, once |
| Degraded section | Optionally, that section alone |