MCP errors
The HTTP statuses and JSON-RPC codes the server returns, and what to do about each.
Protocol errors
A malformed or refused request is an HTTP error with a JSON-RPC error object. The code is a JSON-RPC code (negative) or, for authentication and limits, the HTTP status.
| HTTP | Code | Name | When | What to do |
|---|---|---|---|---|
| 400 | -32700 | Parse error | The body is not UTF-8 JSON. | Send one JSON object with Content-Type: application/json. |
| 400 | -32600 | Invalid request | A batch (a JSON list), a message with no method, a method that is not text, or an id that is not a string or a whole number. | Send one JSON-RPC 2.0 object per POST, with "jsonrpc": "2.0". |
| 400 | -32602 | Invalid params | params is not an object; the 2026-07-28 _meta fields are missing; the tool or prompt is unknown; arguments are not an object; a prompt argument is wrong. | Read the message: it names the problem. List the names with tools/list and prompts/list. |
| 400 | -32022 | Unsupported protocol version | The version in the request is not one the server speaks. data.supported lists the ones it does. | Use one of the supported versions (see the changelog). |
| 400 | -32020 | Header mismatch | MCP-Protocol-Version, Mcp-Method or Mcp-Name disagrees with the body. | Make the headers match the body, or leave the optional headers out. |
| 401 | 401 | Unauthorized | No Authorization header, a key that is not valid, a revoked key, or an expired key. The reply carries WWW-Authenticate: Bearer realm="harnesslab". | Send Authorization: Bearer <key>. Use Test my key in the app to see which it is. |
| 403 | 403 | Account not approved | The account that owns the key is not approved. | Ask the owner of the service to approve the account. |
| 403 | -32600 | Origin not allowed | The request has an Origin header that is not the server's own address (a web page calling the server). | Call from a server, a CLI or an IDE, not from a web page. |
| 404 | -32601 | Method not found | A method the server does not answer. It answers initialize, ping, server/discover, tools/list, tools/call, prompts/list and prompts/get. | Check the method name. |
| 405 | -32600 | Method not allowed | GET, DELETE or another verb. The server has no event stream and no sessions. | Use POST. |
| 413 | -32600 | Request too large | The body is over 64 KB. | Send a smaller request. Shorten the context you pass to ask. |
| 429 | 429 | Too many requests | More calls a minute than the key allows; the key's monthly calls or daily output tokens are used up; or too many failed key checks from your address. Every 429 carries Retry-After in seconds. | Wait Retry-After seconds. The message says which limit and when it resets. |
| 503 | 503 | Switched off | The owner of the service has switched the MCP server off. | Try again later. |
A protocol error
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": 401,
"message": "This API key is not valid. Create a key in the app: https://app.harnesslab.co/#/account (Account, Connect your agent)."
}
}
Notifications and stray responses get 202 with no body. Everything else that worked is 200.
Tool errors
A tool that was called correctly but cannot answer replies with HTTP 200 and isError: true. The text says what is wrong and how to fix it, so an agent can retry by itself.
A tool error
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"content": [
{
"type": "text",
"text": "Unknown topic 'compact'. Valid topics: compaction, ... List them with list_catalog(kind=\"topics\")."
}
],
"isError": true
}
}
| The text starts | What to do |
|---|---|
| Invalid arguments for search_knowledge: 'query' is required. Example: {...} | Fix the arguments. The example is a valid call. |
| Unknown topic 'x'. Valid topics: ... Use list_catalog. | Call list_catalog(kind="topics") and use one of those ids. |
| This key may only use the free tools. Make a key with scope free+ask ... | Make a free+ask key in the app and use that one for ask. |
| No claim 'x'. Use the id from the Evidence footer ... | Pass a claim id exactly as the Evidence footer of another reply shows it. |
| This key has used its daily ask budget ... | Wait for 00:00 UTC, or ask the owner to raise the cap. |
| Something went wrong on the server. Try again later. | Retry. If it keeps happening the owner has the details in the server log. |
Retrying
- Retry a
429after the seconds inRetry-After, not before. - Do not retry a
401,403or400unchanged: they will fail again. - For
ask, pass the samerequest_idon a retry: it returns the same job and never pays twice.