MCP Error Codes Quick Reference
When an MCP request fails, the JSON-RPC layer returns a structured error object. The table below maps every standard error code to its failure layer and the first thing you should check. For Appwrite-specific failures, pair the code lookup with the Appwrite MCP troubleshooting guide.
Standard JSON-RPC Error Codes Used by MCP
| Error Code | Standard Meaning | Failure Layer | First Check |
|---|---|---|---|
| -32700 | Parse Error | Transport / Serialization | Malformed JSON in request or response |
| -32600 | Invalid Request | Protocol | Missing jsonrpc, method, or id fields |
| -32601 | Method Not Found | Protocol / Capability | Method name typo or capability not declared |
| -32602 | Invalid Params | Protocol / Schema | Check error.data for validation details |
| -32603 | Internal Error | Server-side | Server logs / stderr for stack trace |
| -32000 to -32099 | Server-Defined (implementation-specific) | Varies | Read error.message, error.data, and implementation docs |
Critical: Codes -32000 through -32099 have no universal MCP-defined meanings. The number alone tells you almost nothing. Always read the full error object and your implementation's documentation.
Common MCP Error Messages and What They Usually Indicate
| Error Message | What It Usually Indicates | First Diagnostic Step |
|---|---|---|
| Connection Closed | Transport dropped before response arrived | Check server process health and stderr |
| Request Timed Out | Response not received within client timeout | Check server startup time and tool execution duration |
| Method Not Found | Server doesn't recognize the called method | Verify capability negotiation in initialize response |
| Unsupported Protocol Version | Client and server disagree on MCP version | Check protocolVersion in initialize handshake |
| Initialization Failed | initialize / initialized handshake did not complete | Inspect both sides of the handshake in logs |
| Invalid Session ID | HTTP session token missing or expired | Check Mcp-Session-Id header and session lifecycle |
| Failed to Connect | Client cannot reach server process or endpoint | Verify command path, port, or URL |
| Server Process Exited | stdio server process terminated unexpectedly | Check exit code and stderr for crash reason |
| Tool Not Found | tools/call references a tool not in tools/list | Re-run tools/list; check server registration logic |
| Tool Execution Error | Tool ran but returned isError: true | Read tool result content array for the error detail |
| Unauthorized / 401 | Missing or invalid authentication credential | Check Bearer token, OAuth flow, or API key |
| Forbidden / 403 | Authenticated but lacks permission | Check scope, role, or resource-level authorization |
| Rate Limited / 429 | Too many requests to server or upstream API | Implement backoff; check upstream API quota |
How MCP Errors Are Structured
MCP uses JSON-RPC 2.0 as its wire protocol. Every error response follows this structure:
{
"jsonrpc": "2.0",
"id": "request-id-123",
"error": {
"code": -32603,
"message": "Internal error",
"data": {
"details": "TypeError: Cannot read properties of undefined (reading 'execute')",
"stack": "..."
}
}
}
Three fields matter:
code— an integer that classifies the error category. Use it to route your diagnosis, not to determine the exact cause.message— a short human-readable string. For server-defined codes (-32000 to -32099), this is often more diagnostic than the code itself.data— optional, implementation-defined. Can contain stack traces, validation details, upstream error bodies, or structured metadata. Always inspect this field — it is frequently the fastest path to a fix.
Want to analyze your API security?
Import your OpenAPI spec and generate a Security Report automatically.
MCP Error -32700: Parse Error
What it means: The server (or client) received a message it could not parse as valid JSON.
Why it happens:
- Truncated message due to a transport buffer or encoding issue
- Binary data injected into a stdio stream that expects newline-delimited JSON
- A server writing non-JSON to stdout before the MCP handshake (startup banners, debug prints)
How to fix it:
- Capture raw transport bytes. For stdio, redirect server stdout to a file and inspect it.
- Look for non-JSON content at the start of the stream — startup log lines are the most common culprit.
- Ensure your server only writes valid JSON-RPC objects to stdout. All diagnostic output must go to stderr.
- Check for encoding mismatches (UTF-16 vs UTF-8).
# Capture raw stdio output to inspect
my-mcp-server 2>/dev/null | head -c 500 | cat -v
MCP Error -32600: Invalid Request
What it means: The JSON parsed correctly, but the object does not conform to the JSON-RPC 2.0 request structure.
Common causes:
- Missing
jsonrpc: "2.0"field - Missing or null
methodfield - Sending a batch request to a server that doesn't support batching
- Client SDK bug producing malformed envelopes
How to fix it: Enable verbose logging in your client SDK to capture outgoing raw messages. Compare against the MCP specification. This error almost always points to a client-side or SDK-level issue.
MCP Error -32601: Method Not Found
What it means: The server received a valid request but does not recognize the method value.
Common causes in MCP:
- Calling
tools/callbefore the server declaredtoolscapability in itsinitializeresponse - Typo in a custom method name
- Client and server running incompatible MCP spec versions where method names changed
- Server failing to register handlers for standard methods
How to fix it:
- Check the server's
initializeresponse — specifically thecapabilitiesobject. Iftoolsis absent, the server does not support tool calls. - Confirm the method string exactly matches the MCP spec (
tools/list,tools/call,resources/read, etc.). - If you see this during protocol negotiation, cross-check the MCP spec version both sides declare.
MCP Error -32602: Invalid Params
What it means: The method was found, but the parameters failed validation.
Common causes in MCP:
- Missing required fields in a
tools/callrequest (e.g., missingname) - Tool input that doesn't match the tool's declared JSON Schema
- Sending the wrong data type for a parameter
- In some implementations: an
initializerequest declaring a protocol version the server doesn't support — you may see this surfaced as -32602 with a message like "Unsupported protocol version", though this is implementation-specific behavior, not a redefinition of the standard code
How to fix it:
- Check
error.data— most MCP servers include the specific validation failure there. - Retrieve the tool's input schema via
tools/listand validate your payload against it before calling. - If the error occurs during
initialize, compare theprotocolVersionstrings on both sides.
// Example tools/call with correct structure
{
"jsonrpc": "2.0",
"id": "1",
"method": "tools/call",
"params": {
"name": "get_weather",
"arguments": {
"city": "London"
}
}
}
MCP Error -32603: Internal Error
What it means: The server crashed or encountered an unhandled exception while processing the request.
This is always a server-side problem. The client sent a valid request; the server failed to handle it.
Common causes:
- Unhandled exception in tool handler code
- Missing environment variable causing a null reference
- Crashed database connection or external dependency
- Out-of-memory condition
- Bug in the MCP server SDK being used
How to fix it:
- Check server stderr immediately — most SDKs print the full stack trace there.
- Look at
error.datain the response for an embedded stack trace. - Reproduce the call in isolation using MCP Inspector to rule out client-side interference.
- Add try/catch around tool handler logic and return structured errors via
isError: truein the tool result rather than letting exceptions propagate to the JSON-RPC layer.
See the detailed -32603 troubleshooting guide for specific fixes by server framework.
MCP Error -32000 to -32099: Server-Defined Errors
The JSON-RPC 2.0 specification reserves codes -32000 through -32099 for implementation use. The MCP specification does not standardize specific meanings within this range. Different clients and servers assign their own codes.
This means diagnosing these errors requires:
- Reading the
error.messagestring (more diagnostic than the number) - Inspecting
error.datafor structured details - Checking your specific client's documentation or source code
- Reviewing server logs to find what triggered the error
MCP Error -32000: "Connection Closed" (Implementation-Specific)
In Claude Desktop, Cursor, and several other MCP clients, -32000 is commonly emitted with the message "Connection closed" when the underlying transport dropped before the response was delivered. This is not a universal MCP standard definition — it is a convention adopted by those implementations.
Typical causes when this message appears:
- The stdio server process exited prematurely
- The HTTP connection was reset or timed out at the network layer
- A client-side connection pool recycled the connection
- The server crashed during request processing
How to diagnose:
- Check whether the server process is still running after the error
- Review server stderr for crash output or unexpected exit
- For HTTP transport, check network infrastructure (load balancer timeouts, proxy resets)
For a step-by-step fix guide, see How to Fix MCP Error -32000: Connection Closed.
MCP Error -32001: "Request Timed Out" (Implementation-Specific)
Similarly, -32001 is commonly used to signal request timeout in some MCP clients. This is again implementation-specific — not a universally standardized MCP error code.
Typical causes when this message appears:
- Tool execution taking longer than the client's configured timeout
- Slow server startup causing initialization to exceed the timeout window
- Blocking I/O in a tool handler with no async handling
- Large data transfers over slow connections
How to diagnose:
- Measure actual tool execution time vs. client timeout setting
- Check if the issue is isolated to specific tools or all calls
- Review server-side performance for the slow path
For detailed fixes, see How to Fix MCP Error -32001: Request Timed Out.
Protocol Errors vs Tool Execution Errors
One of the most important conceptual distinctions in MCP debugging:
| Error Type | Returned As | Typical Cause | Visible to Model | Correct Fix |
|---|---|---|---|---|
| Protocol Error | JSON-RPC error object (with code) | Bad request, server crash, transport failure | No — client handles it | Fix the request, transport, or server |
| Tool Execution Error | Normal tools/call result with isError: true | Tool logic failed (API error, bad input, exception) | Yes — model sees the error content | Fix the tool logic; return structured error messages |
Why this matters in practice:
If your tool calls a downstream API that returns a 404, the correct behavior is to return a successful JSON-RPC response containing a tool result where isError: true and the content describes the failure. The model can then reason about it and potentially retry or inform the user.
If you instead throw an unhandled exception that becomes a -32603 Internal Error, the model sees nothing — the client receives a protocol-level failure and typically cannot inform the model of what went wrong.
// Correct: tool execution error returned to the model
{
"jsonrpc": "2.0",
"id": "1",
"result": {
"content": [
{
"type": "text",
"text": "Error: The requested resource was not found (404). Please verify the ID and try again."
}
],
"isError": true
}
}
MCP Errors by Failure Layer
Before diving into specific error codes, identify which layer failed. This dramatically narrows the search space.
| Failure Layer | Common Symptoms | What to Check | Recommended Test |
|---|---|---|---|
| Process Launch | "Server Process Exited", "Failed to Connect" | Command path, env vars, permissions, dependencies | Run the server command manually in a terminal |
| Transport | Parse errors, connection resets, -32000 | stdio vs HTTP config, port availability, proxy settings | curl for HTTP; raw pipe test for stdio |
| Initialization | "Initialization Failed", -32601 on first call | initialize / initialized handshake logs | MCP Inspector initialization test |
| Session | "Invalid Session ID", 404 on requests | Mcp-Session-Id header presence and validity | Replay request with correct session header |
| Authentication | 401 Unauthorized, 403 Forbidden | Token validity, OAuth configuration, scopes | curl -H "Authorization: Bearer <token>" |
| JSON-RPC Protocol | -32700, -32600, -32602 | Raw request/response payload structure | Enable SDK verbose logging |
| Tool Discovery | "Tool Not Found", empty tool list | tools/list response, server registration code | Call tools/list directly via MCP Inspector |
| Tool Execution | isError: true in result, -32603 | Tool handler logs, upstream API responses | Call the tool in isolation via MCP Inspector |
| Upstream API | Tool errors mentioning external services | API credentials, rate limits, endpoint availability | Call the upstream API directly with the same params |
| Server Infrastructure | Intermittent failures, slow responses | Memory, CPU, disk, network at server host | Server monitoring metrics |
How to Diagnose Any MCP Error
Follow this flow regardless of the error code. Each step narrows the failure layer.
Step 1 — Capture the complete error object
Get the full JSON including code, message, and data. Many developers only look at the message string and miss critical detail in data.
Step 2 — Verify the server process starts
# For stdio servers — run the command directly
node /path/to/my-mcp-server/index.js
# Should output the initialize response when you send the handshake
# Any crash here is a process launch failure
If the process exits immediately, the failure is at the launch layer. Fix dependencies, environment variables, or file paths before investigating anything else.
Step 3 — Identify the transport
- stdio: The client spawns the server as a child process. stderr is your primary log channel.
- Streamable HTTP: The server runs independently. Check the HTTP endpoint reachability and server logs separately.
Step 4 — Read logs from both sides
For Claude Desktop on macOS:
tail -f ~/Library/Logs/Claude/mcp*.log
For stdio servers, server stderr typically flows into the client's log. For HTTP servers, check your server process logs directly.
Step 5 — Verify initialization completes
The initialize → initialized handshake must complete before any other method call. If you see -32601 on the very first real request, the handshake likely failed silently. Look for the initialize response in logs and confirm the capabilities object is present.
Step 6 — Check authentication and session state
For HTTP-based MCP servers:
- Confirm Bearer token is present and not expired
- Confirm
Mcp-Session-Idheader is sent on every request after the session is established - Check OAuth token scopes match required permissions
Step 7 — Test tool discovery
# Using MCP Inspector (npx)
npx @modelcontextprotocol/inspector node /path/to/server.js
Call tools/list and confirm the tool you're trying to call appears in the response with the expected schema.
Step 8 — Reproduce the failing tool call in isolation
Using MCP Inspector, call the specific tool with the exact same arguments the client would send. This isolates whether the failure is in the client or the server.
Step 9 — Fix the failing layer and verify recovery
Don't move to the next layer until you've confirmed the current one is healthy. A process that crashes at startup will produce misleading transport errors if you skip layer 2.
MCP Error Troubleshooting Matrix
| Error or Symptom | Likely Cause | How to Verify | Fix | Detailed Guide |
|---|---|---|---|---|
| -32700 Parse Error | Non-JSON in transport stream | Capture raw stdout; look for startup logs before JSON | Move all non-JSON output to stderr | — |
| -32600 Invalid Request | Malformed JSON-RPC envelope | Log raw outgoing messages from client | Fix client SDK or request construction | — |
| -32601 Method Not Found | Capability not declared or wrong method name | Check initialize response capabilities | Declare capability in server; fix method name | — |
| -32602 Invalid Params | Schema validation failure | Inspect error.data field | Fix argument structure to match tool schema | — |
| -32603 Internal Error | Unhandled server exception | Check server stderr for stack trace | Add error handling in tool handlers | Fix Guide |
| -32000 / Connection Closed | Server process exited or transport reset | Check server process still running | Fix crash cause; restart server | Fix Guide |
| -32001 / Request Timed Out | Tool too slow or server overloaded | Measure tool execution time | Optimize tool; increase timeout if configurable | Fix Guide |
| Failed to Connect | Wrong path, port, or command | Run server command manually | Fix client config (command, args, URL) | Troubleshooting Guide |
| Server Process Exited | Missing dependency, bad env var | Run server manually; check exit code | Install deps; set env vars | Connection Guide |
| Initialization Failed | Handshake timeout or version mismatch | Check both sides of handshake in logs | Align protocol versions; fix server startup time | — |
| Invalid Session ID | Session expired or header missing | Inspect HTTP headers on failing request | Re-initialize session; fix header propagation | — |
| Unsupported Protocol Version | Version string mismatch in initialize | Compare protocolVersion in request and response | Update client or server to compatible version | — |
| Tool Not Found | Tool not registered or name mismatch | Call tools/list | Fix registration logic or correct tool name | — |
| isError: true in result | Tool logic failure (not protocol failure) | Read content array in tool result | Fix tool business logic or downstream API call | — |
| 401 Unauthorized | Missing or expired token | Replay request with valid token | Refresh token; fix OAuth configuration | — |
| 403 Forbidden | Insufficient scope or permissions | Check token scopes vs required permissions | Update OAuth scopes or fix authorization logic | — |
| 429 Rate Limited | Too many requests | Check retry-after header; review request rate | Implement exponential backoff; cache results | — |
Testing MCP Servers Independently
The most reliable way to isolate whether an error is client-caused or server-caused is to test the server directly, bypassing the client entirely.
MCP Inspector
MCP Inspector is the official interactive debugger for MCP servers:
# Test a stdio server
npx @modelcontextprotocol/inspector node ./my-server/index.js
# Test with environment variables
npx @modelcontextprotocol/inspector -e API_KEY=your_key node ./my-server/index.js
# Test an HTTP server
npx @modelcontextprotocol/inspector --url http://localhost:3000/mcp
Inspector shows raw JSON-RPC messages, server stderr output in real time, and lets you manually trigger initialize, tools/list, and individual tools/call requests. If the tool works in Inspector but fails in Claude Desktop, the problem is in the client configuration, not the server.
You can also use the MCPForge online server tester to validate HTTP-based MCP servers without installing anything locally.
Raw stdio Test
For quick verification without Inspector:
# Send a minimal initialize request via echo
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}' | node ./my-server/index.js
If you get a valid initialize response back, the server starts and the protocol layer works. If you get nothing or a crash, the problem is at the process or transport layer.
Authentication and Authorization Errors
For HTTP-based MCP deployments, authentication failures surface as HTTP status codes before any JSON-RPC error is even constructed. Don't confuse them:
| HTTP Status | What It Means in MCP | How to Fix |
|---|---|---|
| 401 Unauthorized | No valid credential provided | Add or refresh Bearer token; fix OAuth flow |
| 403 Forbidden | Credential valid but lacks permission | Add required scope; fix resource authorization |
| 429 Too Many Requests | Rate limit exceeded | Back off and retry; cache repeated calls |
| 503 Service Unavailable | Server overloaded or starting up | Retry with backoff; check server health |
These are HTTP-layer failures, not JSON-RPC errors. Your MCP client will typically surface them as connection failures or initialization failures rather than a numeric JSON-RPC error code.
For OAuth-based MCP servers, the most common mistake is requesting an access token with insufficient scopes during the OAuth authorization flow. Always verify the granted scopes match what the server requires.
Streamable HTTP-Specific Errors
The Streamable HTTP transport (the current recommended HTTP transport in MCP) introduces session management that stdio servers don't have. Additional failure modes:
Session establishment failures:
- The first
initializePOST must succeed and return anMcp-Session-Idheader - Subsequent requests must include this header — missing it causes session-not-found errors
- Sessions can expire; clients must re-initialize on expiry
SSE stream errors:
- For servers using SSE for server-to-client streaming, dropped connections cause partial responses
- Implement reconnection logic on the client side
- Verify the server sends proper SSE
data:prefixes and\n\nterminators
Proxy and infrastructure issues:
- Load balancers with short HTTP timeouts will kill long-running tool calls
- Ensure your infrastructure allows HTTP connections to remain open for the duration of your longest expected tool execution
- If using NGINX, set
proxy_read_timeoutappropriately
For production Streamable HTTP deployments, see Running MCP in Production for infrastructure configuration guidance.
Prevention Best Practices
Most MCP errors are preventable. Apply these at build time:
Server implementation:
- Always send all non-JSON diagnostic output to stderr, never stdout (for stdio servers)
- Wrap every tool handler in try/catch; return
isError: trueresults instead of letting exceptions propagate - Declare only capabilities your server actually implements in the
initializeresponse - Validate all tool input arguments at the start of each handler using your declared JSON Schema
- Set explicit timeouts on all upstream API calls inside tool handlers
Transport and infrastructure:
- For stdio: confirm environment variables and dependencies before deploying to a client
- For HTTP: configure infrastructure timeouts to exceed your maximum expected tool execution time
- Implement health check endpoints on HTTP servers so load balancers don't route to unhealthy instances
Development workflow:
- Test every server with MCP Inspector before connecting to Claude Desktop or Cursor
- Log the full JSON-RPC request and response at DEBUG level during development
- Use the MCPForge server tester for HTTP servers before production deployment
- Pin your MCP SDK version and test explicitly when upgrading
Client configuration:
- Double-check command paths, working directories, and environment variable names in client config files
- Use absolute paths for stdio server commands to avoid PATH resolution issues
- Test configuration changes in Claude Desktop by checking the MCP logs immediately after restart
Visual Architecture: Where MCP Errors Originate
┌─────────────────────────────────────────────────────────────┐
│ MCP Client │
│ (Claude Desktop, Cursor, custom client) │
│ │
│ Client config error ──► "Failed to Connect" │
│ Client timeout ──► "-32001" (implementation-specific)│
└──────────────────┬──────────────────────────────────────────┘
│ Transport
┌──────────┴──────────┐
│ stdio │ Streamable HTTP
│ │
Process launch HTTP layer
failure ──► -32000 401/403/429
Parse error ──► -32700│
│ │
└──────────┬──────────┘
│ JSON-RPC Layer
│
┌────┴────┐
│ MCP │
│ Server │
│ │
Protocol errors: Tool execution:
-32600 Invalid Req isError: true
-32601 No Method (model sees this)
-32602 Bad Params
-32603 Internal Err
-320xx Server-Defined
└────┬────┘
│
Upstream APIs
(429, 503, etc. wrapped
in tool results)
Key Takeaways
- Read the full error object —
codetells you the category;messageanddatatell you the cause - -32000 to -32099 are not standardized — meanings vary by implementation; always check the message string
- Protocol errors and tool execution errors are different — tool failures belong in
isError: trueresults, not JSON-RPC error responses - Identify the failure layer first — process, transport, protocol, auth, or tool — before investigating specific codes
- MCP Inspector is the fastest isolation tool — if it works in Inspector, the server is fine and the problem is client-side
- Most -32603 errors are fixable — add error handling in your tool handlers and stop letting exceptions surface as protocol failures