How-To

How to Debug MCP Server Connection Errors

Trace MCP connection failures from transport and process startup through initialization, capability negotiation, and tool discovery.

  • #MCP
  • #debugging
  • #AI agents
  • #developer tools

An MCP server connection error rarely identifies the failed layer. “Disconnected,” “server unavailable,” and an empty tool list can result from process startup, transport, initialization, or tool-discovery faults.

Debug the connection as a sequence rather than changing several settings at once:

  1. identify the transport;
  2. prove that the server starts;
  3. capture the initialization exchange;
  4. reproduce the launch environment;
  5. request the tool list directly;
  6. inspect sanitized logs;
  7. apply the smallest fix and rerun the same probe.

The protocol details in this article were checked against official Model Context Protocol documentation on 2026-07-24. The cited specification revision is 2025-11-25. Client interfaces and vendor-specific configuration formats can change, so confirm those against the documentation for your client before publication.

Confirm the transport before debugging the connection

First determine whether the client is using stdio or Streamable HTTP. They fail in different places.

With stdio, the client launches the server as a child process, writes JSON-RPC messages to its standard input, and reads JSON-RPC messages from its standard output. Messages are UTF-8 and newline-delimited. A server must not print banners, debug text, or any other non-MCP output to stdout; logs belong on stderr. These are protocol requirements, not style preferences (official MCP transport specification).

With Streamable HTTP, the server is already running independently. The client connects to one MCP endpoint that accepts HTTP POST and may also use GET for an SSE stream. Check the complete URL, scheme, port, path, proxy behavior, TLS certificate, authentication, and request headers. A healthy web homepage at the same domain does not prove that the MCP endpoint exists.

An HTTP 403 is not always an authorization-scope problem. The current transport specification also requires a Streamable HTTP server to reject an invalid Origin header with 403 Forbidden. Compare the received Origin with the server allowlist before changing OAuth scopes or tokens. This requirement was clarified in the 2025-11-25 specification revision (official MCP changelog).

Record the transport, absolute command or endpoint, sanitized arguments or authentication method, and client version before proceeding.

If the configuration still refers to the older HTTP+SSE transport, do not assume it is equivalent to Streamable HTTP. The current specification says Streamable HTTP replaced the HTTP+SSE transport from protocol version 2024-11-05 and defines a backward-compatibility sequence for clients. A transport mismatch can look like a dead server even when both programs work independently.

Use this transport-specific summary to choose the first probe:

CheckstdioStreamable HTTP
Server lifecycleClient starts a child processServer runs independently
MCP trafficUTF-8, newline-delimited JSON-RPC over stdin/stdoutHTTP POST; optional GET for SSE
First evidence to captureResolved command, exit code, sanitized stderrStatus code, response headers, sanitized server log
Frequent configuration faultWrong executable, arguments, or working directoryWrong scheme, host, port, or MCP path
Protocol-breaking outputNon-MCP text on stdoutNon-MCP response body or incorrect content type

Validate the server command outside the client

For a stdio server, copy the configured executable and arguments exactly. The MCP client may not load your shell profile, aliases, version manager, or user-specific PATH.

Check four facts:

  • the executable resolves to the expected file;
  • every script, package, configuration file, and working directory exists;
  • the client user can read or execute those paths;
  • the process stays alive long enough to receive an MCP request.

On macOS or Linux, use command -v <executable> to see what the shell resolves. On Windows PowerShell, use Get-Command <executable>. Prefer an absolute executable path while diagnosing.

Run the exact command from a minimal terminal environment. A clean exit may indicate that the program expects different arguments or starts a one-shot CLI instead of the MCP server mode. An immediate nonzero exit points toward process startup, imports, permissions, or configuration—not protocol negotiation. A process that waits silently may be correct for stdio because it is waiting for JSON-RPC on stdin.

Do not type arbitrary text into a stdio server and treat the parse error as a connection test. Use an MCP-aware client such as the official MCP Inspector, which can exercise stdio and Streamable HTTP servers (official MCP debugging guide).

The Inspector also has a CLI mode, so you can isolate discovery from the host client without clicking through a UI. Its official repository documents --method tools/list for stdio and --transport http --method tools/list for Streamable HTTP. Run it only in a trusted local environment: the Inspector proxy can launch local processes, and the project warns against exposing that proxy to untrusted networks (official MCP Inspector repository).

Inspect initialization before testing any tool

MCP initialization must be the first protocol interaction. The client sends initialize with its supported protocol version, capabilities, and implementation information. The server responds with its selected protocol version, server capabilities, and implementation information. The client then sends notifications/initialized. Normal operations begin only after that sequence.

Capture this exchange with Inspector, a protocol trace, or temporary structured logging. Ask:

  1. Did the client send initialize?
  2. Did the server parse it and return a response with the same JSON-RPC request ID?
  3. Did both sides settle on a compatible protocol version?
  4. Did the server advertise the feature the client later tried to use?
  5. Did the client send notifications/initialized?

The lifecycle specification explicitly identifies protocol-version mismatch, failure to negotiate required capabilities, and request timeout as errors implementations should handle. It also recommends timeouts for sent requests and cancellation when a request times out (official MCP lifecycle specification).

Classify a hang by its last confirmed event. “Process started, no initialize received” implicates the client launch or transport. “initialize received, no response” implicates server parsing or startup work. “Initialize response returned, client disconnects” suggests malformed response data, version negotiation, or capability assumptions. This event boundary is more useful than a generic stack trace.

Avoid database migrations, large network calls, or expensive index loading before returning the initialization response. If startup work is unavoidable, log its phases to stderr and enforce a timeout.

Check environment variables, paths, and working directory

A command that works in your terminal can fail when launched by a desktop client, service, container, or IDE. The official debugging guide warns that the working directory may be undefined or unexpected and that stdio servers may inherit only a limited, platform-dependent subset of environment variables.

Compare the launch contexts without printing secrets:

ItemSafe comparison
Working directoryLog the absolute directory
ExecutableLog the resolved absolute path and runtime version
Required variablesLog names and whether each is set, not values
File inputsLog normalized paths and existence checks
Network dependencyLog host category and status, not credentials or payloads
PermissionsLog the attempted operation and error class

Use absolute paths for the executable, local data directories, and .env files during diagnosis. Treat relative paths inside the server separately from relative paths in the client configuration: they may be resolved by different processes.

If credentials are required, pass them through the client’s documented environment configuration or a secret manager. Do not paste tokens into logs, command histories, screenshots, or issue reports. For stdio, the MCP specification says credentials should come from the environment rather than the HTTP authorization framework.

Diagnose tool discovery separately from connection health

A connected server with no visible tools is not necessarily a transport failure. Tool discovery depends on initialization capabilities and a successful tools/list request.

Servers that expose tools must declare the tools capability. Clients then send tools/list; the response contains tool definitions and may contain a pagination cursor. A server can also declare listChanged support and send notifications/tools/list_changed when its available tools change (official MCP tools specification).

Inspect the protocol in this order:

initialize response -> capabilities.tools exists
tools/list request -> response or JSON-RPC error
response.tools -> array with valid tool definitions
nextCursor -> fetch remaining pages when present

If capabilities.tools is absent, fix server registration or feature configuration. If tools/list never leaves the client, revisit capability negotiation. If the server returns an empty array, inspect conditional registration, permissions, and feature flags. If the response contains tools but the UI shows none, suspect client-side validation, filtering, or caching.

Validate every tool’s name, description, and inputSchema. One malformed entry can cause a strict client to reject more of the list than expected. Also distinguish discovery from invocation: a tool can appear correctly and still fail later because its arguments, authorization, or downstream service are invalid.

Read logs without breaking the protocol or leaking secrets

For stdio, write application logs to stderr, never stdout. The transport specification allows UTF-8 logging on stderr and cautions clients not to assume that every stderr line represents an error. For all transports, servers may also use MCP logging notifications. For Streamable HTTP, ordinary server logs and HTTP diagnostics are usually required because client capture of server stderr does not apply.

Make each diagnostic event structured enough to correlate:

timestamp level event request_id phase duration_ms error_class

Useful events include process start, resolved configuration, initialization received, initialization returned, capability set, tools/list received, tool count, shutdown, and timeout. Record payload sizes rather than raw prompts, tool arguments, resource contents, authorization headers, cookies, or environment values.

Before sharing logs, redact tokens, personal data, file contents, tenant identifiers, internal hostnames, and query parameters. Preserve event order, error class, request ID, and sanitized path shape. The site’s MCP security checklist covers the broader permission and secret boundary.

Fix common failure patterns and retest one layer at a time

Use the last successful event to choose the fix:

SymptomLikely layerFocused fix
Executable not foundProcess launchUse the resolved absolute executable and verify permissions
Process exits immediatelyRuntime or argumentsRun the exact configured command and inspect sanitized stderr
JSON parse error on first messagestdio framingRemove every banner and debug print from stdout
HTTP 404 or 405Endpoint or transportVerify the MCP path and whether the client expects Streamable HTTP or legacy HTTP+SSE
Initialization times outStartup or protocolTrace initialize; defer expensive startup work; verify response framing
Unsupported protocol versionNegotiationUse versions supported by both client and server; do not hard-code an invented version
Connected, no toolsCapabilities or discoveryConfirm capabilities.tools, then inspect tools/list and pagination
Works in terminal onlyLaunch environmentReproduce the client’s working directory, runtime, paths, and variable presence
Reconnect loopCrash or stale client stateFind the first disconnect cause, fix it, then fully restart the client if required

After each change, rerun the same smallest probe. First prove process startup, then initialization, then tools/list, then one read-only or otherwise safe tool call. Do not use a destructive tool invocation as a health check.

A useful evidence bundle contains the sanitized configuration, client and server versions, transport, reproduction steps, last successful protocol event, and shortest relevant log excerpt. It must not contain credentials or complete user payloads.

The connection is fixed when a clean restart produces repeatable initialization, the expected capabilities, a valid tool list, and a controlled test call from the actual client launch path.

Frequently asked questions

Why does an MCP server work in a terminal but not in my client?

The two processes probably have different working directories, executable paths, runtime versions, or environment variables. Log the resolved path, runtime version, working directory, and presence—not values—of required variables from the client-launched process.

Why does the client connect but show no tools?

Check that the initialization response declares capabilities.tools, then capture the tools/list request and response. An empty response can come from conditional registration or permissions; a populated response that disappears in the UI points more toward client validation, filtering, pagination, or caching.

What causes an MCP initialization timeout?

Common causes are a server that never receives initialize, malformed JSON-RPC framing, expensive startup work before the response, or a protocol-version mismatch. Identify the last confirmed initialization event before increasing a timeout, because a longer wait does not fix a message that was never delivered or parsed.

What is the difference between HTTP 401 and 403 during an MCP connection?

For an authenticated HTTP server, 401 Unauthorized normally starts or challenges the authorization flow and should include WWW-Authenticate. A 403 Forbidden may mean insufficient permission, but Streamable HTTP also requires 403 for an invalid Origin header. Inspect the response headers and sanitized server logs before replacing credentials (official MCP authorization specification).

Can I write debug logs to stdout for a stdio MCP server?

No. stdout is reserved for valid MCP messages, so ordinary log text can corrupt the transport. Send logs to stderr and keep secrets and complete payloads out of both streams.

Additional official sources

Checked on 2026-07-24: