MCP JSON-RPC Errors: Complete Fix Guide (2026)
Getting JSON-RPC errors in your MCP server or client? This guide covers every MCP error code, what causes them, and how to fix them — with working code examples.
Have broken JSON right now? Fix it free in under 1 second — no signup.
Fix My JSON →MCP JSON-RPC Errors: Complete Fix Guide (2026)
The Model Context Protocol (MCP) runs on JSON-RPC 2.0. Every message — tool call, resource fetch, prompt request — is a JSON object sent over stdio or SSE. When the JSON is malformed, the schema is wrong, or the protocol handshake fails, MCP throws a JSON-RPC error that stops your tool cold.
This guide covers the specific error codes MCP uses, what causes each one, and how to fix them — with working Python and TypeScript examples for both server and client implementations.
MCP JSON-RPC Error Architecture
MCP inherits the JSON-RPC 2.0 error structure:
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32600,
"message": "Invalid Request",
"data": {
"details": "missing required field: method"
}
}
}
Every error has three parts:
code— numeric identifier (negative integers by convention)message— short human-readable descriptiondata— optional additional context (MCP implementations vary on whether this is populated)
MCP defines a mix of standard JSON-RPC codes and MCP-specific extensions.
Standard JSON-RPC Error Codes in MCP
-32700: Parse Error
Meaning: The server received a message that is not valid JSON. Common causes:- Malformed JSON from an LLM tool call (markdown fences, trailing commas, single quotes)
- Truncated message from a network error or buffer overflow
- Encoding issues (BOM characters, mixed line endings on Windows)
MCP Error -32700: Parse error
Failed to parse JSON-RPC message: SyntaxError: Unexpected token '`' in JSON at position 0
Fix — Python server:
import json
from json_repair import repair_json
def safe_parse_rpc(raw_message: str) -> dict:
"""Parse incoming MCP message with repair fallback."""
try:
return json.loads(raw_message)
except json.JSONDecodeError:
# Attempt repair for LLM-generated tool arguments
repaired = repair_json(raw_message)
if repaired:
return json.loads(repaired)
raise
# In your MCP server's message handler:
try:
message = safe_parse_rpc(raw_input)
except (json.JSONDecodeError, ValueError):
send_error(-32700, "Parse error", {"raw": raw_input[:200]})
Fix — TypeScript server:
import { jsonrepair } from 'jsonrepair';
function parseRpcMessage(raw: string): unknown {
try {
return JSON.parse(raw);
} catch {
// Try repair for LLM-generated arguments
try {
return JSON.parse(jsonrepair(raw));
} catch {
throw { code: -32700, message: 'Parse error' };
}
}
}
-32600: Invalid Request
Meaning: The JSON parsed successfully, but the JSON-RPC request object is malformed — missing required fields or wrong types. MCP-specific causes:- Missing
jsonrpc: "2.0"field - Missing
methodfield idis not a string, number, or null (e.g., an object was passed)paramsis not an object or array when required
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32600,
"message": "Invalid Request",
"data": "missing required field: method"
}
}
Fix:
All MCP requests must conform to the base JSON-RPC 2.0 structure:
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "get_weather",
"arguments": {
"location": "Karachi"
}
}
}
Check:
jsonrpcis exactly the string"2.0"(not2.0the number, not"2")methodis a non-empty stringidis a string, number, ornull— not an object or arrayparamsis an object (for MCP tool calls) — not a string
-32601: Method Not Found
Meaning: Themethod field references a method the server doesn't implement.
Common causes in MCP:
- Calling
tools/callbefore completing initialization (the server's tool list isn't registered yet) - Typo in method name (
tool/callinstead oftools/call) - Using a method from a newer MCP protocol version that the server doesn't support
initialize
initialized (notification)
ping
tools/list
tools/call
resources/list
resources/read
resources/subscribe
resources/unsubscribe
prompts/list
prompts/get
logging/setLevel
sampling/createMessage
roots/list
Fix: Ensure your method name matches the MCP spec exactly. Method names are case-sensitive and plural (tools/list, not tool/list).
If you're getting this error on tools/call, check that initialization completed first:
# Correct initialization sequence:
# 1. Client sends: initialize
# 2. Server responds: capabilities
# 3. Client sends: initialized (notification)
# 4. ONLY THEN: tools/list, tools/call, etc.
# Wrong: calling tools/call before initialized notification
-32602: Invalid Params
Meaning: The method exists, but the parameters are wrong — wrong type, missing required field, or extra field not allowed.This is the most common MCP error in practice. It almost always involves the arguments object passed to a tool.
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "get_user",
"arguments": {
"user_id": "usr_123"
}
}
}
Common causes:
argumentscontains keys not declared in the tool's input schema- Required argument is missing
- Wrong type for an argument (e.g., passing
"42"where the schema requires42) argumentsis a JSON string instead of a JSON object (common when LLM serializes twice)
import json
def fix_mcp_arguments(raw_args) -> dict:
"""Handle arguments that may be double-serialized JSON."""
if isinstance(raw_args, str):
# LLM passed JSON string instead of object
return json.loads(raw_args)
if isinstance(raw_args, dict):
return raw_args
raise ValueError(f"Invalid arguments type: {type(raw_args)}")
Fix — validate arguments before sending (Python):
import jsonschema
def call_tool(tool_name: str, arguments: dict, tool_schema: dict):
"""Validate arguments against tool's input schema before sending."""
try:
jsonschema.validate(instance=arguments, schema=tool_schema)
except jsonschema.ValidationError as e:
raise ValueError(f"Invalid tool arguments: {e.message}")
return send_rpc("tools/call", {"name": tool_name, "arguments": arguments})
-32603: Internal Error
Meaning: The server received a valid request but encountered an unexpected error processing it. Common causes in MCP servers:- Unhandled exception in tool implementation
- Database connection failure
- External API timeout
- Missing environment variable the tool depends on
from mcp.server import Server
from mcp.types import TextContent, Tool
app = Server("my-server")
@app.call_tool()
async def call_tool(name: str, arguments: dict):
try:
if name == "get_data":
result = await fetch_data(arguments["query"])
return [TextContent(type="text", text=json.dumps(result))]
else:
raise ValueError(f"Unknown tool: {name}")
except KeyError as e:
# Missing required argument — should have been caught by schema validation
return error_response(-32602, f"Missing required argument: {e}")
except TimeoutError:
return error_response(-32603, "Tool execution timed out")
except Exception as e:
# Log the full error server-side, return generic message to client
logger.exception(f"Tool {name} failed: {e}")
return error_response(-32603, "Internal error")
MCP-Specific Error Codes
MCP extends JSON-RPC 2.0 with its own error codes in the -32000 to -32099 range:
| Code | Name | When It Occurs |
|---|---|---|
-32001 | Resource not found | resources/read for a URI that doesn't exist |
-32002 | Resource unavailable | Resource exists but can't be read (permissions, offline) |
-32003 | Tool not found | tools/call for a tool not in the server's tool list |
-32004 | Tool execution failed | Tool ran but returned a failure state |
-32005 | Prompt not found | prompts/get for an unknown prompt name |
-32003: Tool Not Found
Different from -32601 (method not found). The tools/call method exists, but the specific tool named in params.name isn't registered.
async function callToolWithRefresh(
name: string,
args: Record<string, unknown>
): Promise<unknown> {
try {
return await mcpClient.callTool(name, args);
} catch (err: any) {
if (err.code === -32003) {
// Tool not found — refresh tool list and retry once
await mcpClient.listTools();
return await mcpClient.callTool(name, args);
}
throw err;
}
}
Schema Validation Errors in MCP Tool Definitions
A common source of -32602 errors is a tool's input schema itself being invalid JSON Schema. The MCP TypeScript SDK added stricter schema validation in v2, and the 2026 migration from zod-to-json-schema to Zod's native .toJSONSchema() broke schemas that relied on specific Zod version behavior.
See the MCP TypeScript SDK v2 migration guide for details on the specific breaking changes.
Common schema mistakes:
// ❌ Wrong: $dynamicRef in tool schema (causes parse failure)
const brokenSchema = z.object({
items: z.array(z.lazy(() => itemSchema)) // generates $dynamicRef
});
// ✅ Fix: avoid recursive schemas in tool inputs
const fixedSchema = z.object({
items: z.array(z.object({
id: z.string(),
label: z.string()
}))
});
// ❌ Wrong: anyOf with incompatible types
const brokenSchema = z.union([z.string(), z.number()]);
// Generates: {"anyOf": [{"type": "string"}, {"type": "number"}]}
// Some MCP clients reject this
// ✅ Fix: use discriminated unions with an explicit type field
const fixedSchema = z.discriminatedUnion("kind", [
z.object({ kind: z.literal("text"), content: z.string() }),
z.object({ kind: z.literal("count"), value: z.number() })
]);
Debugging MCP JSON-RPC Errors
Enable MCP Inspector
The MCP Inspector is the fastest way to debug server/client message exchange:
npx @modelcontextprotocol/inspector your-server-command
It shows the raw JSON-RPC messages in both directions — you can see exactly what the client sent and what the server responded.
Log Raw Messages
Add raw message logging to your server:
import logging
import json
logger = logging.getLogger(__name__)
async def handle_message(raw: str):
logger.debug(f"RECV: {raw[:500]}") # Log incoming
try:
message = json.loads(raw)
response = await process(message)
response_str = json.dumps(response)
logger.debug(f"SEND: {response_str[:500]}") # Log outgoing
return response_str
except Exception as e:
logger.error(f"Error processing: {e}", exc_info=True)
return json.dumps({"jsonrpc": "2.0", "id": None, "error": {"code": -32603, "message": str(e)}})
Validate Against MCP Schema
Use AI JSONMedic's JSON repair tool to clean malformed tool arguments before they reach your server, and the schema validator to test your tool's input schema against sample inputs.
Quick Reference: Error → Likely Cause → Fix
| Error | Most Likely Cause | Quick Fix |
|---|---|---|
| -32700 Parse Error | LLM output has markdown fences or syntax errors | Strip fences, use json-repair before forwarding |
| -32600 Invalid Request | Missing jsonrpc: "2.0" or method field | Check request structure against JSON-RPC 2.0 spec |
| -32601 Method Not Found | Calling before initialization, typo in method name | Complete init handshake first; check method spelling |
| -32602 Invalid Params | Missing required arg, wrong type, double-serialized JSON | Validate against tool schema before sending |
| -32603 Internal Error | Unhandled exception in tool implementation | Add try/catch, log full error, return generic message |
| -32003 Tool Not Found | Stale tool list, tool not registered | Refresh tool list, retry |
Frequently Asked Questions
What version of JSON-RPC does MCP use?
MCP uses JSON-RPC 2.0. This means: requests must include "jsonrpc": "2.0", requests have an id, responses always echo the id, and notifications (fire-and-forget) have no id. JSON-RPC 1.0 messages (with positional params arrays) are not compatible.
Can I use JSON5 or JSONC in MCP messages?
No. MCP requires standard JSON (RFC 8259). Comments and trailing commas are not allowed. If your tool arguments come from a JSON5 or JSONC source, convert them to standard JSON before sending via MCP.
Why does my LLM keep sending malformed tool arguments?
LLMs generate tool arguments as text tokens — they don't have a native understanding of JSON validity. Common issues: markdown fences wrapping the JSON, Python boolean literals (True/False), trailing commas. The fix is to use your LLM provider's native tool use / function calling API, which constrains the output to valid JSON. If you're working with a provider that doesn't enforce structure, add a repair step before forwarding to your MCP server.
How do I handle the MCP -32602 error when arguments look correct?
Check for double-serialization: the LLM may have passed a JSON string where an object was expected. arguments: "{\"key\": \"value\"}" instead of arguments: {"key": "value"}. Parse the string if it's a string. Also check that the tool's input schema uses additionalProperties: false — some MCP clients reject arguments with extra keys even if the server would have ignored them.
What's the difference between -32601 and -32003?
-32601 Method Not Found means the JSON-RPC method itself doesn't exist on the server (e.g., tools/call isn't implemented). -32003 Tool Not Found means the JSON-RPC method tools/call exists, but the specific tool named in the params (e.g., "name": "send_email") isn't registered.
Do MCP errors always include a data field?
No. The data field in the error object is optional per JSON-RPC 2.0. Different MCP implementations (Python SDK, TypeScript SDK, community servers) populate it differently. Don't depend on error.data being present — always check error.code and error.message.
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