MCP JSON-RPC 2.0 Errors: Complete Debug Guide for Model Context Protocol (2026)
MCP uses JSON-RPC 2.0 as its wire format. Here's every error code, what triggers it, how the MCP spec extends it, and how to fix malformed JSON-RPC payloads from Claude, tool servers, and host apps.
Have broken JSON right now? Fix it free in under 1 second — no signup.
Fix My JSON →Model Context Protocol (MCP) is JSON all the way down. Every tool call, every resource fetch, every sampling request, and every error response travels as a JSON-RPC 2.0 message. When something goes wrong — a malformed tool argument, a missing id field, a tool server that returns broken JSON — you see a JSON-RPC error code, and you need to know what it means.
This guide covers every JSON-RPC error code that appears in MCP, the MCP-specific extensions on top of the base spec, common causes, and how to diagnose and fix each one.
JSON-RPC 2.0 Quick Refresher
MCP's wire protocol is JSON-RPC 2.0. Every message is either:
A request (client → server):{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "read_file",
"arguments": {"path": "/data/config.json"}
}
}
A notification (no id — fire and forget):
{
"jsonrpc": "2.0",
"method": "notifications/tools/list_changed"
}
A response (success):
{
"jsonrpc": "2.0",
"id": 1,
"result": { "content": [{"type": "text", "text": "file contents"}] }
}
A response (error):
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32602,
"message": "Invalid params",
"data": "Missing required argument: path"
}
}
The jsonrpc field must always be exactly "2.0". The id must be present in requests and must be echoed in responses. Notifications have no id and get no response.
Standard JSON-RPC Error Codes in MCP Context
-32700 Parse Error
What it means: The server received a message it couldn't parse as JSON. Triggers in MCP:- A tool server response contains broken JSON (truncated by a proxy, encoding error, binary garbage mixed in)
- A host application sends a request where the JSON wasn't serialized correctly
- A transport layer (stdio, HTTP) introduced encoding corruption
{
"jsonrpc": "2.0",
"id": null,
"error": {
"code": -32700,
"message": "Parse error",
"data": "Unexpected token at position 42"
}
}
Note: When a parse error occurs, the server may not know the request id (since it couldn't parse the message), so id in the error response is null.
- Log the raw bytes at the transport layer — don't let your client silently discard the raw response before you can inspect it
- Paste the raw response into AI JSONMedic to identify the exact syntax error
- Check if your transport is introducing line endings or encoding issues — MCP over stdio is particularly sensitive to mixed line endings
- If the broken JSON came from a tool server, file an issue — it's a bug in the server
# macOS/Linux — tail the MCP debug log while reproducing the error
tail -f ~/Library/Logs/Claude/mcp*.log 2>/dev/null || \
tail -f ~/.config/Claude/logs/mcp*.log 2>/dev/null
-32600 Invalid Request
What it means: The message was valid JSON but didn't conform to the JSON-RPC 2.0 structure. Triggers in MCP:- Missing required field (
jsonrpc,method, oridfor requests) jsonrpcversion field is not exactly"2.0"(e.g.,2,"2","2.0.0")idfield is an object or array (must be string, number, or null)- The message structure has
resultanderrorboth present (mutually exclusive)
"jsonrpc": "2.0" or send id: undefined which serializes to omitting the field entirely.
How to fix:
// Wrong — missing jsonrpc field
const request = {
id: 1,
method: "tools/call",
params: { name: "my_tool" }
};
// Correct
const request = {
jsonrpc: "2.0",
id: 1,
method: "tools/call",
params: { name: "my_tool" }
};
# Wrong — id is undefined/None handled incorrectly
request = {
"jsonrpc": "2.0",
"method": "tools/call",
# id missing entirely — this is a notification, not a request
}
# Correct for a request (expects a response)
request = {
"jsonrpc": "2.0",
"id": str(uuid.uuid4()), # or an integer
"method": "tools/call",
"params": {"name": "my_tool", "arguments": {}}
}
-32601 Method Not Found
What it means: The server received a valid JSON-RPC request for a method it doesn't implement. Triggers in MCP:- Calling a capability the server hasn't declared (e.g.,
resources/liston a server that only declaredtools) - Typo in the method name (
tools/Calinstead oftools/call) - Calling a method that was added in a newer MCP spec version than the server implements
- The server's capability negotiation during initialization declared fewer capabilities than you assumed
# During MCP handshake, the server declares its capabilities
# Store and check them before calling methods
capabilities = await client.initialize()
if "resources" not in capabilities.get("capabilities", {}):
print("This server doesn't support resources — skip resources/list")
Common MCP method names (2026 spec):
initialize
ping
tools/list
tools/call
resources/list
resources/read
resources/subscribe
resources/unsubscribe
prompts/list
prompts/get
logging/setLevel
sampling/createMessage
roots/list
completion/complete
How to fix: Always check the server's declared capabilities during the initialize handshake before calling methods. Don't assume a server supports all MCP features.
-32602 Invalid Params
What it means: The method was found, but the parameters were structurally wrong. Triggers in MCP:- Tool arguments don't match the tool's declared JSON Schema
- A required argument is missing from
arguments - An argument value has the wrong type (string where number expected, etc.)
- The
namefield in atools/callrequest doesn't match any registered tool
{
"name": "query_database",
"inputSchema": {
"type": "object",
"properties": {
"query": {"type": "string"},
"limit": {"type": "integer", "minimum": 1, "maximum": 100}
},
"required": ["query"]
}
}
These would trigger -32602:
// Missing required argument
{"name": "query_database", "arguments": {"limit": 10}}
// Wrong type for limit
{"name": "query_database", "arguments": {"query": "SELECT *", "limit": "10"}}
// limit out of range
{"name": "query_database", "arguments": {"query": "SELECT *", "limit": 0}}
How to fix:
- Validate arguments against the tool's
inputSchemabefore calling — useajv(JS) orjsonschema(Python) - Always provide all
requiredfields - Check type coercions — JavaScript may send
"10"where the schema expects10
import jsonschema
def validate_tool_args(tool_schema: dict, args: dict) -> bool:
try:
jsonschema.validate(instance=args, schema=tool_schema["inputSchema"])
return True
except jsonschema.ValidationError as e:
print(f"Argument validation failed: {e.message}")
return False
Also see our guide on MCP JSON Schema validation errors for the full set of schema-related failures.
-32603 Internal Error
What it means: The server encountered an error processing the request. Something went wrong on the server side, not because of a problem with the request format. Triggers in MCP:- A tool's underlying function threw an exception
- Database connection failed inside a resource handler
- A tool server crashed mid-response
- The server ran out of memory processing a large argument
data field in the error response should contain diagnostic information if the server implements it correctly.
What to do:
- Check the
datafield for a stack trace or error message - Check the tool server's own logs (not the MCP transport logs)
- Reproduce with the exact parameters — it may be a specific input value that triggers the failure
- If the tool is yours, wrap your handler in a try/catch and return a proper error response rather than crashing
MCP-Specific Error Codes
MCP extends JSON-RPC with its own error code range: -32000 to -32099.
-32001 — Request Timeout
The MCP server or client waited longer than the configured timeout for a response. Affects long-running tool calls (code execution, large file reads, network requests inside tools).
Fix: Increase the timeout in your client configuration, or make the tool return faster (pagination, streaming, async patterns).-32002 — Resource Not Found
A resources/read or resources/subscribe call referenced a URI that doesn't exist on the server.
{
"jsonrpc": "2.0",
"id": 3,
"error": {
"code": -32002,
"message": "Resource not found",
"data": "URI 'file:///tmp/missing.json' not found"
}
}
Fix: Check that the URI matches exactly what was returned by resources/list. Resource URIs are case-sensitive and scheme-sensitive.
-32003 — Tool Execution Error
The tool was called with valid parameters but the tool's execution failed (the function ran but returned an error, as opposed to -32603 which is the server crashing).
This is distinct from -32603: a -32003 means the tool handled its own error and returned it cleanly. A -32603 means something unexpected happened before or during error handling.
Tool Response JSON Errors (Content-Level Errors)
JSON-RPC error codes cover transport and protocol failures. But tools can also return broken JSON inside a successful JSON-RPC response. This is subtler:
{
"jsonrpc": "2.0",
"id": 5,
"result": {
"content": [
{
"type": "text",
"text": "{'status': 'ok', 'data': [1, 2, 3]}"
}
],
"isError": false
}
}
The JSON-RPC frame is valid. But the tool returned a Python dict repr (single quotes) inside the text content field. If your application tries to parse content[0].text as JSON, it will fail.
import json
from json_repair import repair_json
def parse_tool_content(result: dict) -> dict:
for item in result.get("content", []):
if item.get("type") == "text":
text = item["text"]
try:
return json.loads(text)
except json.JSONDecodeError:
# Try repair
repaired = repair_json(text)
return json.loads(repaired)
raise ValueError("No parseable text content in tool result")
You can also validate the tool output at AI JSONMedic before consuming it in your pipeline.
Diagnosing MCP JSON-RPC Errors: Checklist
When you hit a JSON-RPC error in MCP, work through this order:
- Check the error code — is it in the standard range (-326xx) or MCP range (-320xx)?
- Read the
datafield — most well-implemented servers include diagnostic details there - Inspect the raw request — log the exact JSON-RPC payload you sent, not the high-level parameters
- Check capability negotiation — for -32601, verify the server declared the capability during
initialize - Validate params against schema — for -32602, run the arguments through the tool's declared
inputSchema - Check transport encoding — for -32700, inspect raw bytes at the transport layer
For Claude Desktop specifically, MCP logs are at:
- macOS:
~/Library/Logs/Claude/mcp-server-[name].log - Windows:
%APPDATA%\Claude\logs\mcp-server-[name].log
Frequently Asked Questions
Q: What's the difference between a JSON-RPC -32603 Internal Error and a -32003 Tool Execution Error in MCP?A: -32603 means the server's JSON-RPC layer encountered an unexpected error — the server itself crashed or hit an unhandled exception. -32003 is MCP-specific and means the tool ran and handled its own failure — it caught the error and returned it as an MCP tool execution error. -32003 is the expected way for tools to report controlled failures; -32603 indicates something unexpected happened.
Q: I'm getting -32602 Invalid Params but my arguments look right. What should I check?A: The most common cause is type mismatch — the schema expects integer and you're sending a string "10". Also check for extra keys: if the schema has additionalProperties: false, any argument not in the schema triggers -32602. Validate your arguments against the tool's inputSchema using a JSON Schema validator before sending.
"id": null? Is that valid?
A: "id": null is technically valid in JSON-RPC 2.0 but it's discouraged. Null IDs make it impossible to correlate responses to requests in a pipelined transport. Use a string (UUID) or incrementing integer for request IDs. The only time you legitimately see "id": null is in a server's error response when a parse error (-32700) prevented the server from reading the original request ID.
A: Check for a BOM (byte order mark) at the start of the response stream, or a trailing newline after the JSON that the client's parser doesn't expect. MCP over stdio is sensitive to framing — some transports use newline-delimited framing and a stray extra newline inside a JSON string value can throw off the frame parser.
Q: How do I handle -32602 errors in production without crashing the MCP host?A: Catch the error at the tool call site, log the request ID and the data field from the error response, and return a degraded or fallback response to the LLM context. Do not propagate the raw JSON-RPC error to the user. Implement retry logic only for -32001 (timeout) and -32603 (transient internal errors) — retrying a -32602 will always fail because the parameters are structurally wrong.
Still dealing with broken JSON?
Paste it in and get it fixed in under 1 second — free, no signup, no install. Works with ChatGPT, Claude, n8n, and any AI output.
Fix My JSON Free →Related Articles