Blog/

Guide

8 min read

Debugging MCP Connections — Every Error I've Hit and How I Fixed Them

A field guide to the MCP connection failures that waste the most time, with fixes grouped by how quickly you can usually resolve them.

LL

Lee Li

Independent Developer · MCP Enthusiast

·

A field guide to the MCP connection failures that waste the most time, with fixes grouped by how quickly you can usually resolve them.

Test context

Primary environment: macOS on Apple Silicon
Common hosts tested: Claude Desktop and local dev runners
Common server types: filesystem, browser, custom Python/Node servers
Main transports tested: stdio, a smaller amount of HTTP/SSE
Time window: recurring errors logged over several months while indexing and testing MCP tools for mcp-find.org

Start here: the fastest diagnosis path

Before reading the full list, do these five checks in order:

  • Run the server outside the host
  • Verify the exact runtime path the host uses
  • Check stdout for accidental log noise
  • Confirm the config uses absolute paths
  • Fully restart the host app
  • That checklist solves a surprising percentage of failures.

    Tier 1: quick fixes (5–10 minutes)

    1. Wrong executable or interpreter path

    Recommendation: verify the actual binary path, not the one you assume the host uses.

    Symptoms:
    Server never appears, or generic launch failure, or works in your terminal but fails in the app.

    Common cause:
    Your shell is using one runtime, the host config points at another.

    Fix:
    Use absolute paths like this:

    {
    "command": "/opt/homebrew/bin/python3",
    "args": ["/Users/lee/projects/mcp/server.py"]
    }

    2. Relative paths and tilde

    Recommendation: Replace them with full absolute paths immediately.

    Many hosts do not resolve tilde or relative paths the way your interactive shell does.

    Fix:
    Bad example: "args": ["~/projects/server.py"]
    Good example: "args": ["/Users/lee/projects/server.py"]

    3. Missing dependency

    Symptoms:
    Process launches, then exits; host shows a vague internal failure; manual run reveals a module import error.

    Fix:
    Run the exact command manually in the exact environment. For example:

    /opt/homebrew/bin/python3 /Users/lee/projects/mcp/server.py

    Tier 2: medium pain (15–40 minutes)

    4. stdout pollution

    Recommendation: Keep protocol output clean. Send logs to stderr.

    This one is nasty because the server might be "working" while startup logs break the protocol handshake.

    Common pattern: print("Starting server..."). That line can break things if it goes to stdout before the protocol stream is established.

    Fix: Log to stderr instead.

    5. Invalid JSON in config

    Symptoms:
    Host ignores server entry; no useful error. Works after random edits because the real issue was formatting.

    Fix:
    Validate the config separately. Especially watch for trailing commas, invalid escaping, and wrong quoting on Windows paths.

    6. Timeout on first launch

    Recommendation: treat cold start separately from steady-state performance.

    A server that initialises slowly may appear broken when the host expects a faster handshake.

    Fix: reduce startup work, cache expensive initialisation, test warm vs cold launch separately.

    Tier 3: serious time sink (40 minutes to half a day)

    7. Tool registered in code, not visible in host

    Recommendation: Verify registration is completed at runtime.

    Possible causes:
    exception before tool registration finishes; invalid schema rejected silently; host caching stale capability state; startup path branching differently than expected.

    What helped: compare against a known-good minimal server and diff the capability declaration.

    8. Expired auth or bad secret handling

    Symptoms:
    The server starts, the connection appears fine, and the real tool call fails silently or inconsistently.

    Fix:
    Check token freshness, env var injection, and whether the host actually passes the variables you think it does.

    9. Crash with no visible log

    Recommendation: wrap startup aggressively during debugging.

    If your host swallows useful logs, add temporary diagnostics around environment load, tool registration, config parse, and external dependency init.

    Error patterns that look complicated but usually aren't

    Symptom: "Internal error" – Often the real cause is bad config, bad path, or startup exception.

    Symptom: Tool not showing up – Often, the real cause is a schema issue, a failed registration path, or stdout noise.

    Symptom: Works in the terminal, not in the host – Often the real cause is an environment mismatch.

    Symptom: Random first-call failure – Often the real cause is cold startup latency or auth/init timing.

    One caveat the docs don't emphasise enough

    A server can fail in a way that still appears to be "the connection sort of exists." That's the most annoying class of bug. The process starts, the host doesn't crash, but the capability surface is wrong or incomplete. Those cases are where comparing with a tiny known-good server saves the most time.

    My take

    The protocol itself is rarely the first thing that's broken. Most MCP debugging is still focused on environment, config, startup behaviour, and host expectations.

    If you want one tool-page link while you're in this mode, start with the simplest local server you can find, like the filesystem one, and use that as your baseline for every comparison.

    python server.py 2>debug.log

    LL

    Lee Li

    Independent Developer · MCP Enthusiast

    Building and breaking things with AI tools since 2023. MCP Find started as a personal project to track the rapidly evolving MCP ecosystem. Based in Hong Kong.

    info@mcp-find.org📍 Sai Kung, Kowloon, Hong Kong

    Sponsored