Skip to content
← All articles
Your MCP Server Is Not Connecting: A Debugging Checklist

Your MCP Server Is Not Connecting: A Debugging Checklist

An MCP server that will not connect looks the same from the outside no matter where the fault sits: the tools never appear, the client offers no useful explanation, and you start editing config at random. The search phrase mcp server not connecting covers at least five different faults, and each one lives in a different layer: the config file, the transport, the environment the server launches in, the credentials it uses, and the logs that name the fault. Work the layers in order and you find the break in minutes. Start at the wrong end and you lose an afternoon to a syntax error. What follows is a ladder that works on any MCP server, with PostSider as the running example, plus one isolation command that settles whether the key or the client is broken.

MCP connection failures live in five layers: config, transport, environment, credentials, logs

A broken MCP connection is five possible bugs wearing one symptom. The layers, in the order worth testing, are the config file, the transport, the environment the server launches in, the credentials it uses, and the logs that record what happened. Each layer fails quietly in the same way, with no tools and no error in the chat window, so a fixed order beats intuition.

Most people begin at the wrong end, reinstalling the server package or rotating a key that was never the problem, while the real break is one line in a JSON file the client silently refused to load.

If server, transport, and tool are still doing heavy lifting in that sentence, start with what an MCP server is.

Layer 1: the config file, its exact location and syntax per client

An MCP server exists in your client only if a config file names the command that starts it. Claude Desktop reads claude_desktop_config.json, Claude Code writes its configuration through the claude mcp add command, Cursor reads a project or global mcp.json, and Codex stores TOML in ~/.codex/config.toml. A wrong path, a relative command, or invalid JSON leaves the client with nothing to launch.

Claude Desktop: the file and the shape

The config lives at ~/Library/Application Support/Claude/claude_desktop_config.json on macOS and %APPDATA%\Claude\claude_desktop_config.json on Windows. The stdio shape is a top-level mcpServers object with one entry per server, each carrying command, args, and an optional env block. The official example uses npx as the command with -y, a package name, and an absolute path. For PostSider the same shape looks like this:

{
  "mcpServers": {
    "postsider": {
      "command": "npx",
      "args": ["-y", "@postsider/mcp"],
      "env": {
        "POSTSIDER_API_KEY": "your_api_key"
      }
    }
  }
}

Two mistakes account for most Layer 1 failures. The first is a relative path: the working directory of a server launched from the config may be undefined, on macOS it can be /, so an absolute path is the only form that resolves. The second is editing the config without a restart, where the official instruction is to fully quit and reopen Claude Desktop, since closing the window is not enough. The official troubleshooting list is worth running in order: restart completely, check the JSON syntax, use absolute paths, check the logs, run the server manually.

Claude Code: add, scopes, and a flag-order gotcha

The CLI generates the config for you: claude mcp add [options] <name> -- <command> [args...], and everything after the double dash goes to the server untouched. The two scopes worth knowing are --scope project for the repo and --scope user for your account. The PostSider README command reads:

claude mcp add postsider -e POSTSIDER_API_KEY=your_api_key -- npx -y @postsider/mcp

One documented trap sits in the flag order. The docs warn that “if the server name comes directly after —env, the CLI reads the name as another pair and rejects it, so place at least one other option, such as —transport stdio, between —env and the server name.”

Check the state before writing anything else. claude mcp list reports each server as Connected, Needs authentication, or Failed to connect. claude mcp get <name> adds an Issue line with the status code. The docs carry a second warning: “the claude mcp add command saves the configuration without validating credentials, so a placeholder value is accepted here but the server fails to connect later.” A clean add is not a working server.

Cursor and Codex

Cursor reads a project-level .cursor/mcp.json or a global ~/.cursor/mcp.json. Codex has a CLI add plus a TOML file:

codex mcp add postsider --env POSTSIDER_API_KEY=your_api_key -- npx -y @postsider/mcp

In ~/.codex/config.toml the server lands in a [mcp_servers.postsider] table with command, args, and env. The Codex walkthrough runs that path end to end, authentication included.

Layer 2: the transport, before you blame the server

Transport is how the client and the server exchange messages, and a mismatch there fails before any of your code runs. A local server speaks stdio over stdin and stdout; a remote server speaks HTTP. Point a stdio client at a URL and the server never starts, so your server logs stay empty.

If the config is clean, the next suspect is the channel: a URL pasted into a stdio entry launches nothing, and a local package handed to an HTTP entry connects to nothing.

On stdio the contract is strict and short. The spec says the server MUST NOT write anything to its stdout that is not a valid MCP message, and that the server MAY write UTF-8 strings to stderr for any logging purposes. Messages travel as newline-delimited JSON-RPC and must not contain embedded newlines, which is why a hand-written server dies on its first run: one print line lands in the middle of the protocol stream and the client drops the connection without explaining why. If you maintain a server, put every log line on stderr.

Protocol version mismatches surface here too. The client probes with server/discover, and an unsupported version comes back as an UnsupportedProtocolVersionError, code -32022, listing the versions the server does support.

Test the server standalone before touching the client again. The official description: “MCP Inspector is the reference developer tool for testing and debugging MCP servers.” It requires Node 22.19 or newer and ships web, --cli, and --tui clients behind one binary:

npx @modelcontextprotocol/inspector node path/to/server.js
npx -y @modelcontextprotocol/inspector npx -y @postsider/mcp

The first form runs a local script, the second a published package. --cli mode lists the tools and exits: the fastest yes or no on whether the server answers.

Layer 3: environment variables, the silent killer

A server spawned by a desktop client does not inherit your shell. The documentation states that MCP servers launched over stdio inherit only a limited subset of environment variables automatically, and the exact set is platform-dependent. The env key in the client config is how you supply the rest.

This layer produces the ladder’s most misleading symptom: a server that runs fine by hand and fails inside the client. For PostSider, POSTSIDER_API_KEY is required, while POSTSIDER_API_URL is optional, defaults to https://api.postsider.com, and must be HTTPS.

Three failures recur in community reports rather than official documentation. The first is spawn npx ENOENT while npx works in your terminal, because GUI applications launch their children with a minimal PATH. The second is Windows, where npx resolves through npx.cmd and some clients need a cmd /c wrapper to launch it. The third is a version manager: Node installed through nvm or fnm is not the Node the client finds, because the client never reads your shell profile.

The fixes are boring and effective: absolute paths, an explicit env block, a full client restart afterward.

Layer 4: test the key without MCP

One curl call tells you whether the credentials are the problem. Send the same key to the PostSider API directly: a successful response means the key is valid and the fault is in the client configuration, and a 401 means the key itself is wrong.

curl https://api.postsider.com/public/v1/integrations \
  -H 'Authorization: <your-api-key>'

The Authorization header carries the raw key with no Bearer prefix. The status codes are unambiguous: 401 for a missing or invalid key, 402 for a plan limit, 429 for the rate limit of 60 requests per minute per organization, where the correct move is to honor the Retry-After header.

The decision rule is the point of this layer. If the same key works in curl and the MCP server still fails, the fault sits in the config, the environment, or the transport, and you walk back up the ladder. If curl fails too, you are holding an auth problem, and no amount of config editing will fix it.

Key hygiene belongs here too, because the API has no scoped or read-only keys. Keys are created in the dashboard under Settings then API, displayed once, and never narrowed afterward. Create a dedicated key per agent and revoke it when the work is done.

Layer 5: read the logs, then let the Inspector referee

The client logs name the fault that the interface only gestures at. Claude Desktop writes logs to ~/Library/Logs/Claude on macOS and to %APPDATA%\Claude\logs on Windows, where the mcp log files capture connection events, configuration issues, and runtime errors.

tail -n 20 -F ~/Library/Logs/Claude/mcp*.log

In Claude Code the equivalent is the /mcp panel: each server shows as connected or failed with the HTTP status attached, so a bad key shows 401 right there. claude mcp get repeats it on the Issue line, and claude --debug-file /tmp/claude-debug.log writes debug output to a file.

Once the pipe is live, make the first request harmless. Ask the agent to list your channels and say explicitly: do not create or modify anything. A read-only first call proves the connection without touching a live account. The setup page with copy-paste blocks for every client above is at the PostSider MCP setup page. If you are still weighing whether your own product should expose MCP at all, the MCP vs function calling decision is the sibling piece.

Lukasz Blania is the solo founder of PostSider, where agents schedule and publish social posts over MCP, REST, and the SDK.

Frequently asked questions

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

Almost always PATH or environment. Desktop clients launch the server with a minimal environment, so npx or node may not be found, and your shell variables are not inherited. Absolute paths plus an explicit env block fix most of these.

How do I tell whether the API key or the client config is broken?

Test the key without MCP. One curl request to the API with the same Authorization header separates auth from everything else. If curl succeeds, the key is fine and the fault is in the client configuration.

Where are the MCP logs in Claude Desktop?

macOS: ~/Library/Logs/Claude. Windows: %APPDATA%\Claude\logs. The mcp log files capture connection events and runtime errors, and the official flow is: read the logs, then test the server standalone before touching the config again.

What does the stdout rule for stdio servers actually mean?

On stdio, standard output is the protocol channel. Any stray print or log line is not a valid MCP message, corrupts the stream and the connection dies. Send your own logging to stderr, which clients may capture.

Run your social media
on autopilot.

Start free in minutes. Publish it yourself, or let your AI agent take the wheel.

30+ networks · MCP, REST and SDK · No credit card