Quick Answer
When an MCP server fails to connect, the fastest diagnostic path depends on whether the server is local stdio or remote HTTP.
For Shadcn-specific package/runtime failures, see Shadcn MCP failed to connect after you identify the general connection stage.
Local stdio server: Run the exact command from your client configuration manually in a plain shell. Check whether the process exits immediately and capture stderr. Verify the executable resolves from the client's PATH, not just your terminal's. Confirm no non-protocol output is written to stdout. Test initialization with MCP Inspector. If the Inspector UI itself cannot connect to its local proxy, fix the MCP Inspector proxy error before debugging the target server.
Remote HTTP server: Confirm the exact endpoint URL, verify DNS resolution, test TCP reachability, inspect the HTTP status code, then verify that authentication is configured correctly and that the MCP initialization handshake completes — not just that the HTTP endpoint responds.
Do not reinstall the server before completing these steps. Reinstalling destroys diagnostic evidence and rarely fixes the real cause.
MCP Server Failed to Connect: 60-Second Checklist
- Identify the exact server name that failed from your client's server list
- Determine whether it is a local stdio server or a remote HTTP server
- Open your client's configuration file and read the exact
command,args,env, andurlfields for that server — do not rely on memory - Local: Run the exact command manually in a plain shell (not your full terminal profile)
- Remote: Fetch the exact URL with
curl -iand inspect the HTTP status code - Capture the first real error message from stderr or the HTTP response body
- Verify the executable resolves from the environment the client uses, not just your terminal
- Confirm command and args are split correctly — shell syntax does not belong in
command - Confirm all required environment variables are explicitly set in the client config block
- Verify the server does not assume a specific working directory
- Local: Check that the process does not exit immediately after launch
- Local: Confirm the server writes no non-protocol output to stdout
- Remote: Verify URL, DNS, HTTP status, transport type, and authentication in sequence
- Test the server independently using MCP Inspector
- If multiple servers are configured, reduce to just the one failing server to eliminate interference
Jump to the Right Fix
Want to analyze your API security?
Import your OpenAPI spec and generate a Security Report automatically.
First: Identify Which MCP Server Failed
Most MCP clients support multiple servers configured simultaneously. When one reports a connection failure, the others keep working. Before touching anything, identify the exact server entry that failed.
How to find it:
- Open your client's server panel or settings. Each configured server is listed individually.
- The failing one is typically marked with a red indicator, disconnected status, or an error icon.
- Match that server name to its entry in your configuration file.
- That entry's
command,args,env, andurlare your entire diagnostic scope.
Four states to distinguish:
| State | What It Means |
|---|---|
| Server missing from UI entirely | Configuration was not parsed, or the entry has a syntax error |
| Server listed but disconnected | Client tried to connect and failed — this is the primary failure case |
| Server connected, tools missing | Connection succeeded, but tool registration or discovery failed |
| Server connected, tools appear but error on use | A different class of failure — not a connection problem |
Tools not appearing after a successful connection is not a connection failure. See the dedicated section below. If the failing implementation is Appwrite, use the Appwrite MCP troubleshooting guide for platform-specific checks.
Local stdio vs Remote HTTP: Pick the Right Fix Path
| Dimension | Local stdio server | Remote HTTP server |
|---|---|---|
| How client connects | Spawns a child process, communicates via stdin/stdout | Sends HTTP requests to an endpoint URL |
| Common failure causes | Executable not found, process exits immediately, stdout contamination, missing env vars | Wrong URL, DNS failure, HTTP error, auth failure, transport mismatch |
| Where logs appear | Server stderr, client log files | HTTP response body, server-side logs, client logs |
| What to test first | Run the command manually, check exit code and stderr | curl -i the exact URL |
| Most critical config | command, args, env | url, authentication headers |
| How MCP Inspector helps | Launches and initializes the server, shows tools | Connects to the endpoint, runs initialization |
| Common false assumption | "It works in my terminal" proves client can run it | HTTP 200 proves MCP compatibility |
MCP Server Connection Lifecycle
Understanding which stage fails tells you exactly where to look.
| Stage | Typical Symptom | How to Verify | What to Fix |
|---|---|---|---|
| 1. Client loads configuration | Server missing from UI | Check config file syntax | Fix JSON/YAML syntax error |
| 2. Client identifies server | Server present but never attempted | Check client logs for config parsing errors | Fix entry name or structure |
| 3. Process starts / URL reached | spawn ENOENT, ECONNREFUSED, DNS error | Run command manually or curl the URL | Fix executable path or URL |
| 4. Transport established | Timeout, protocol error, HTTP 405 | Test with curl, check transport type | Fix transport configuration |
| 5. Authentication | HTTP 401/403, OAuth error | Check auth headers, token validity | Fix credentials or OAuth flow |
| 6. MCP initialization handshake | Initialize request fails or times out | Run MCP Inspector | Fix server implementation or config |
| 7. Capability and tool discovery | Server connects but tools missing | Call tools/list via Inspector | Fix server tool registration |
| 8. Session maintained | Intermittent disconnects | Check server logs during session | Fix server stability or timeout config |
Fix a Local MCP Server That Failed to Connect
1. Inspect the Exact Configuration
Troubleshooting from memory causes wasted effort. Open the actual configuration file your client is reading — not what you think it contains.
For most clients this is a JSON file containing an mcpServers block. The structure looks like:
{
"mcpServers": {
"my-server": {
"command": "node",
"args": ["/absolute/path/to/server.js"],
"env": {
"MY_API_KEY": "sk-..."
}
}
}
}
Verify the path of the config file in your client's official documentation — config locations vary by client and OS. Do not guess.
2. Run the Exact Command Manually
Take the command and args from your configuration and run them in a plain shell — not your full interactive terminal session:
# Node.js server
node /absolute/path/to/server.js
# npx-based server
npx -y @modelcontextprotocol/server-filesystem /tmp
# Python server
python /absolute/path/to/server.py
# uvx-based server
uvx mcp-server-git
# Docker-based server
docker run --rm -i my-mcp-image
Interpreting what you see:
| Behavior | Meaning |
|---|---|
command not found | Executable not in PATH |
Cannot find module | Node.js dependency missing or wrong path |
ModuleNotFoundError | Python import failed |
Error: Cannot find module 'X' | npm install was not run or wrong working directory |
| Non-zero exit immediately | Startup error — check stderr |
| Process stays running silently | Server is waiting for stdin input — this is expected for stdio servers |
Critical: A stdio MCP server that stays running silently may simply be waiting for protocol input on stdin. Silence alone does not prove initialization will succeed — it only proves the process started. Use MCP Inspector to verify the full handshake.
3. Verify Executable Resolution
The MCP client process often runs in a different environment than your terminal. GUI applications on macOS and Windows typically do not inherit shell PATH modifications from .zshrc, .bashrc, or .profile.
macOS / Linux — check what your shell resolves:
command -v node
command -v python3
command -v uvx
command -v npx
Windows PowerShell — check what the system resolves:
Get-Command node
Get-Command python
Get-Command uvx
Get-Command npx
# Or use where.exe
where.exe node
If those commands succeed in your terminal but the client shows spawn ENOENT, use the absolute path of the executable in your client configuration:
{
"command": "/opt/homebrew/bin/node",
"args": ["/path/to/server.js"]
}
To find the absolute path:
# macOS/Linux
which node # /opt/homebrew/bin/node
which python3 # /usr/bin/python3
which uvx # /Users/you/.local/bin/uvx
# Windows PowerShell
(Get-Command node).Source
(Get-Command python).Source
4. Check Command and Arguments
The command field must contain only the executable name or path — no shell syntax, no flags joined with &&, no quoted compound expressions. Arguments belong in the args array as separate strings.
Wrong — shell syntax in command:
{
"command": "npx -y @modelcontextprotocol/server-filesystem /tmp",
"args": []
}
Correct — args split properly:
{
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
}
Windows paths in JSON require escaped backslashes:
{
"command": "node",
"args": ["C:\\Users\\alice\\projects\\mcp-server\\dist\\index.js"]
}
Paths with spaces require proper quoting as array elements:
{
"command": "C:\\Program Files\\nodejs\\node.exe",
"args": ["C:\\Users\\alice\\My Projects\\server\\index.js"]
}
If the command works in your terminal but not in the client, check whether your terminal is actually invoking a shell wrapper that expands variables or globs. Direct process spawning does not go through a shell.
5. Verify Environment Variables
Environment variables set in shell profiles (.zshrc, .bashrc, .profile, PowerShell $PROFILE) are not available to GUI-launched MCP clients unless they are explicitly passed in the env block of your configuration.
Safe way to check whether a variable exists without printing its value:
# macOS/Linux
[ -z "$MY_API_KEY" ] && echo "MISSING" || echo "SET"
# PowerShell
if ([string]::IsNullOrEmpty($env:MY_API_KEY)) { "MISSING" } else { "SET" }
Correct env block in MCP config:
{
"mcpServers": {
"my-server": {
"command": "node",
"args": ["/path/to/server.js"],
"env": {
"MY_API_KEY": "your-actual-key-here",
"NODE_ENV": "production"
}
}
}
}
Never put secrets in args. Process argument lists are visible to other processes on the same system. The env block is the correct place.
Check for these common mistakes:
- Variable name has a typo (
MY_API_KYEinstead ofMY_API_KEY) - Variable is set to an empty string
"" - Variable is set in the OS environment but not forwarded in the config's
envblock - Server validates the credential on startup and exits silently when invalid
6. Check Working Directory Assumptions
Some servers use relative paths to load configuration files, schemas, or assets. When the client launches the server, the working directory is determined by the client — not by your terminal's current directory.
Never assume the working directory. Use absolute paths in your server code and configuration wherever possible. If your client's documentation explicitly documents a cwd configuration field, use it. Do not add cwd fields speculatively — not all clients support it.
7. Check Immediate Process Exit
A server that exits immediately after launch is the most common local connection failure.
Capture stderr and exit code:
# macOS/Linux — run the exact command and capture stderr
node /path/to/server.js 2>/tmp/mcp-stderr.log
echo "Exit code: $?"
cat /tmp/mcp-stderr.log
# PowerShell
node C:\path\to\server.js 2> $env:TEMP\mcp-stderr.log
$LASTEXITCODE
Get-Content $env:TEMP\mcp-stderr.log
Common causes of immediate exit:
- Missing npm dependencies — run
npm installin the server directory - Missing Python dependencies — run
pip install -r requirements.txt - Invalid configuration read at startup — missing config file or env var
- Server validates credentials at startup and exits on failure
- Syntax error in server code
- Runtime version mismatch (Node.js version too old, Python version wrong)
The stderr output will almost always tell you exactly what failed.
8. Check stdout Contamination
This is the failure mode developers most commonly overlook. stdio MCP servers use stdout exclusively for JSON-RPC protocol messages. Any other text written to stdout — a startup banner, a console.log debug line, a progress indicator, output from a third-party library — will corrupt the message stream. The client will fail to parse the first message and report a connection or initialization failure, often with a cryptic JSON parse error.
In TypeScript/Node.js — always log to stderr:
// Wrong — writes to stdout, corrupts the protocol stream
console.log('Server started');
// Correct — writes to stderr, safe for stdio servers
console.error('Server started');
process.stderr.write('Server started\n');
In Python — always log to stderr:
import sys
import logging
# Wrong
print("Server started") # goes to stdout
# Correct
print("Server started", file=sys.stderr)
logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)
Also audit third-party libraries. Some Python and Node.js packages print startup messages, version banners, or warnings to stdout. Redirect or suppress them before the MCP server begins.
9. Verify MCP Initialization
A process that starts successfully can still fail during the MCP initialization handshake. The client sends an initialize request via JSON-RPC and expects a compliant response. Failures at this stage include:
- Server sends malformed JSON (e.g., because of stdout contamination)
- Server crashes when processing the
initializerequest - Server implementation does not conform to the protocol version
- Transport-level mismatch between client and server expectations
Use MCP Inspector to verify this stage independently:
npx @modelcontextprotocol/inspector node /path/to/server.js
If Inspector can initialize the server and list tools, the server itself is working. The issue is then in your client configuration. See the MCP Inspector section for detailed interpretation.
For a deeper guide on using the tool, the MCP Inspector complete guide covers every workflow in detail.
Fix a Remote MCP Server That Failed to Connect
1. Verify the Exact MCP Endpoint URL
Do not rely on the URL you remember typing. Copy it from the client configuration and verify each component:
- Protocol:
https://nothttp://for production servers - Hostname: exact domain with correct subdomain
- Path: the MCP endpoint path, not the service homepage
- Trailing slash: some servers are path-sensitive
Common mistakes:
- Using the service homepage URL (
https://api.example.com) instead of the MCP endpoint (https://api.example.com/mcp) - Using an outdated endpoint from old documentation
- HTTP when the server requires HTTPS
2. Check DNS and Network Reachability
macOS/Linux:
# DNS resolution
dig api.example.com
# TCP reachability on port 443
nc -zv api.example.com 443
# Full HTTP diagnostic
curl -iv https://api.example.com/mcp
Windows PowerShell:
# DNS resolution
Resolve-DnsName api.example.com
# TCP reachability
Test-NetConnection -ComputerName api.example.com -Port 443
# HTTP response
Invoke-WebRequest -Uri https://api.example.com/mcp -UseBasicParsing
If DNS fails, the hostname is wrong or your network cannot reach the domain. If TCP connects but HTTPS fails, check for a TLS/certificate issue.
3. Inspect HTTP Status Codes
| Status or Result | Likely Meaning | Next Check |
|---|---|---|
| No response / timeout | Network path blocked, server down, or serverless cold start | Check firewall, try again after delay |
ECONNREFUSED | Nothing listening on that port | Verify URL and port |
| DNS error | Hostname cannot be resolved | Verify hostname spelling |
| TLS/certificate error | Certificate invalid, expired, or hostname mismatch | Verify HTTPS URL and cert validity |
| 400 Bad Request | Request malformed | Check transport format and headers |
| 401 Unauthorized | Missing or invalid credentials | Check API key or bearer token |
| 403 Forbidden | Credentials valid but access denied | Check permissions or account tier |
| 404 Not Found | Wrong path | Verify exact endpoint URL |
| 405 Method Not Allowed | Wrong HTTP method for this transport | Verify transport type (POST vs GET) |
| 429 Too Many Requests | Rate limit hit | Reduce request frequency, check retry-after header |
| 5xx | Server-side error | Check server status page, server logs |
HTTP status codes indicate the transport layer result. A 200 response does not guarantee MCP protocol compatibility — it only means the HTTP request succeeded.
4. Verify Transport
The current MCP specification defines Streamable HTTP as the standard HTTP transport. It uses POST requests to the MCP endpoint for sending messages, with the server responding either with a complete JSON response or an SSE stream depending on the operation.
An older transport based on SSE-only connections (sometimes called SSE transport in earlier documentation) is still present in some deployments. If your client and server expect different transport behaviors, you may see HTTP 405 errors, protocol parse failures, or timeout-style disconnections even when the endpoint is reachable.
Verify:
- Which transport version your server advertises
- Which transport your client expects
- Whether your client version supports Streamable HTTP
5. Verify Authentication
API key / bearer token issues:
# Test with explicit bearer token
curl -i \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
https://api.example.com/mcp
Common auth failures:
- Token passed as a query parameter when the server expects a header (or vice versa)
- Token expired — regenerate it from the provider dashboard
- Bearer prefix missing or present when not expected
- Insufficient permissions on the token for the requested operations
OAuth issues:
Remote MCP servers using OAuth 2.0 implement a metadata discovery flow. The client fetches .well-known/oauth-authorization-server or the protected resource metadata to discover the authorization endpoint. If that discovery request fails (DNS error, 404, wrong Content-Type), the OAuth flow cannot begin and the server will appear to fail connection.
Verify:
- The authorization server URL is reachable
- The discovery document returns valid JSON
- The access token is being refreshed when it expires
- The token has the correct scopes for MCP operations
6. Check Timeouts, Cold Starts, and Server Availability
Some remote MCP servers run on serverless infrastructure and have cold start delays that exceed client timeout thresholds. Others are simply overloaded or temporarily down.
Diagnostic steps:
- Check the server's status page if one exists
- Retry the connection after 30–60 seconds
- Increase the client's connection timeout if configurable
- Check whether you have exceeded a rate limit (look for
Retry-Afterheader in 429 responses) - Test from a different network to rule out routing issues
7. Verify MCP Initialization (Remote)
A reachable HTTP endpoint that returns 200 does not confirm MCP compatibility. Verify that the server responds correctly to an MCP initialize request:
curl -i \
-X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_TOKEN" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}' \
https://api.example.com/mcp
A valid MCP server will respond with a JSON-RPC result containing protocolVersion and capabilities. Any other response indicates the endpoint is not a valid MCP server.
Use MCP Inspector to Test the Server Independently
MCP Inspector is the official testing tool maintained by the MCP team. It lets you connect to a server outside of any client, run the full initialization flow, and list tools and capabilities. This makes it the single most useful tool for isolating whether a problem is in the server or in the client configuration.
Launch for a local stdio server:
npx @modelcontextprotocol/inspector node /absolute/path/to/server.js
# With arguments
npx @modelcontextprotocol/inspector npx -y @modelcontextprotocol/server-filesystem /tmp
MCP Inspector opens a browser-based UI where you can:
- See whether the server starts
- See whether initialization completes
- Browse advertised capabilities
- List registered tools
- Call individual tools
Interpreting Inspector results:
| Inspector Result | What It Means | Next Step |
|---|---|---|
| Inspector cannot start the server | Executable not found or process crashes immediately | Fix command, path, or dependencies |
| Inspector starts but initialization fails | Server starts but protocol handshake fails | Check stdout contamination, server implementation |
| Inspector initializes but no tools listed | Server works but exposes no tools | Check server tool registration code |
| Inspector works, client still fails | Server is functional; client config is wrong | Compare Inspector command vs client config exactly |
| Inspector and client both fail | Server has a real bug or the config is consistently wrong | Debug the server implementation |
Inspector success confirms the server works under Inspector's configuration. It does not prove the client's configuration is correct — compare the exact command, args, and environment used by each.
For a comprehensive walkthrough of every Inspector feature, see the MCP Inspector complete guide.
MCP Server Failed to Connect in Claude Desktop, Claude Code, Cursor, and VS Code
Every MCP client manages configuration, environment, and logging differently. The diagnostic principles are identical, but the specifics vary.
Claude Desktop
Configuration is stored in a JSON file. The client spawns stdio servers as child processes with a limited environment — shell profile variables are not inherited. Use absolute executable paths and pass all environment variables explicitly in the env block. Logs are written to a client-specific log directory; check Claude Desktop's official documentation for the current log location on your OS.
Claude Code
Claude Code (the CLI tool) supports MCP configuration through project-level and global config files. It inherits more of the shell environment than a GUI app, but you should still use absolute paths for reliability. Run claude mcp list to see which servers are registered and their current status.
Cursor Cursor loads MCP configuration from its settings. Because it is an Electron app, it does not inherit shell profile environment variables. Use absolute paths. Cursor's developer tools (Help → Toggle Developer Tools) may provide additional error output from the MCP connection attempt.
VS Code VS Code supports MCP through extensions. Check the specific extension's documentation for its configuration format. The Output panel (View → Output) and the extension's dedicated output channel are the primary log sources. Extension-managed MCP servers may have their own environment handling that differs from direct process spawning.
For any client: if you are uncertain about the configuration format or log location, check the client's current official documentation rather than relying on outdated community posts.
MCP Server Works in Terminal but Fails in the Client
This is one of the most common reported issues. The server is not broken — the client is being launched in a different environment.
| Works Manually Because | Fails in Client Because | How to Verify | Fix |
|---|---|---|---|
| Your terminal PATH includes the executable location | GUI client PATH does not include that location | Run which node in terminal, check if same path exists in client env | Use absolute executable path in config |
| Shell profile exports the API key | GUI client does not load shell profiles | Check env block in client config | Add variable to env block |
| Terminal's working directory matches what server expects | Client launches server from a different directory | Add a debug log to print process.cwd() in the server | Use absolute paths in server, or configure cwd if client supports it |
You use npx and it resolves from your terminal's npm | Client npx resolves from a different npm installation | Run which npx in terminal | Use absolute path to npx or install the server globally |
| Relative path in args works from your project directory | Client launches from a different directory | Print cwd at startup | Use absolute paths in args |
Shell expands ~ or $HOME in your command | Client does not invoke a shell, no expansion | Use expanded absolute path in config | Expand the path explicitly in the config file |
| Server does not write to stdout in your quick test | Third-party library writes startup output to stdout in full load | Capture stdout when running node server.js | Redirect all output to stderr |
| Credentials work because you logged in interactively | Client cannot perform interactive auth prompts | Add credentials to config env block | Configure non-interactive auth in config |
MCP Server Connected but Tools Do Not Appear
If the server shows as connected but no tools appear in your client, this is not a connection failure — the TCP or stdio connection succeeded and the MCP handshake completed. Treat it as a separate problem class.
Possible causes:
- Server exposes no tools: The server implementation did not register any tools. Verify by calling
tools/listvia MCP Inspector. - Tool registration failed silently: A runtime error during tool setup prevented registration. Check server stderr logs.
- Permission or authorization filtering: The server registered tools but is filtering them based on the authenticated identity. Try with elevated permissions.
- Client has not refreshed: Some clients cache the tool list. Disconnect and reconnect the server, or restart the client.
- Capability negotiation: If the client did not advertise support for tools in its
initializerequest capabilities, a conformant server may not advertise tools in response. Check the client's MCP version and capabilities.
Do not conflate missing tools with a connection failure. They have different causes and different fixes.
MCP Server Failed to Connect After It Worked Before
Regressions are easier to diagnose once you identify what changed. Before modifying anything, ask: what changed between when it worked and now?
Common regression causes:
| What Changed | What to Check |
|---|---|
| npm update or pip upgrade | Check if the server package version changed; test the new version with Inspector |
| Client updated | Check if the client changed its config format or transport requirements |
| Server updated remotely | Check the server's changelog for breaking changes |
| Credentials expired | Regenerate API key or OAuth token |
| Environment variable removed | Check the env block in config; verify the variable still exists |
| Config file edited | Diff the config against a backup; check for JSON syntax errors |
| Remote endpoint changed | Verify the URL against current provider documentation |
| Transport protocol changed | Check whether the server now uses Streamable HTTP instead of legacy SSE |
| OS or Node/Python update | Verify runtime compatibility with the server version |
| Upstream service outage | Check the provider's status page |
The fastest approach: roll back one thing at a time and retest. Do not change multiple variables simultaneously.
For more on maintaining MCP servers reliably in production environments, see Running MCP in Production.
Windows-Specific Fixes
Locate executables:
# Find the absolute path of any executable
(Get-Command node).Source # e.g., C:\Program Files\nodejs\node.exe
(Get-Command python).Source
(Get-Command uvx).Source
(Get-Command npx).Source
# Alternative
where.exe node
where.exe npx
Check network reachability:
# DNS resolution
Resolve-DnsName api.example.com
# TCP port check
Test-NetConnection -ComputerName api.example.com -Port 443
Check environment variables safely:
# Does the variable exist?
if ([string]::IsNullOrEmpty($env:MY_API_KEY)) { 'MISSING' } else { 'SET (value hidden)' }
# List all env vars (names only, no values)
[System.Environment]::GetEnvironmentVariables().Keys | Sort-Object
JSON path escaping — use double backslashes:
{
"command": "C:\\Program Files\\nodejs\\node.exe",
"args": ["C:\\Users\\alice\\projects\\mcp-server\\dist\\index.js"]
}
WSL boundary: Executables installed inside WSL are not available to Windows processes without explicit cross-boundary calls. If your MCP server lives in WSL and your client is a native Windows app, you need to either install the server natively on Windows or configure the client to use wsl.exe as the command.
macOS and Linux Fixes
Locate executables:
which node # /opt/homebrew/bin/node
which python3 # /usr/bin/python3 or /opt/homebrew/bin/python3
which uvx # /Users/you/.local/bin/uvx
which npx # /opt/homebrew/bin/npx
# Check if file is executable
ls -la /path/to/server.py # should show -rwxr-xr-x
chmod +x /path/to/server.py # add execute permission if missing
Capture stderr and exit code:
node /path/to/server.js 2>/tmp/mcp-debug.log
echo "Exit: $?"
cat /tmp/mcp-debug.log
Check working directory:
# Add this temporarily at server startup to debug
pwd
echo "PWD: $(pwd)" >&2 # to stderr
DNS and network:
dig api.example.com
nc -zv api.example.com 443
curl -iv https://api.example.com/mcp
Environment variable check:
# Check existence without revealing value
[ -z "${MY_API_KEY}" ] && echo 'MISSING' || echo 'SET (value hidden)'
# List all env var names available to a process
env | cut -d= -f1 | sort
Shell profile note: Variables exported in ~/.zshrc, ~/.bashrc, or ~/.profile are not automatically available to processes launched by GUI applications like Claude Desktop or Cursor. Use the env block in your MCP configuration.
Minimal Reproduction Procedure
A minimal reproduction helps you isolate the actual cause and makes bug reports actionable.
For local stdio servers:
- Edit your config so only the failing server is active — disable all others
- Open the config file and read every field of that server entry
- Run the exact command and args from a clean shell (no terminal profile:
env -i PATH=/usr/bin:/usr/local/bin node /path/to/server.json macOS/Linux) - Capture stderr:
2>/tmp/mcp-test.log - Check the exit code:
echo $? - Read the log:
cat /tmp/mcp-test.log - Test with MCP Inspector using the same command
- Note what Inspector shows vs what the client shows
For remote HTTP servers:
- Confirm the exact URL from the config
Resolve-DnsNameordigthe hostnameTest-NetConnectionornc -zvthe portcurl -ithe endpoint and record the HTTP status and response body- Add the
Authorizationheader to the curl command and retest - Send a manual
initializeJSON-RPC request and inspect the response - Test with MCP Inspector if it supports your endpoint
- Compare behavior with the original client
What each result proves:
- Command fails in a clean shell → executable or dependency problem, not a client issue
- Command succeeds in clean shell but Inspector fails → stdout contamination or initialization bug
- Inspector succeeds but client fails → client configuration is wrong, not the server
- Everything fails → server or configuration has a fundamental problem
Prevention Best Practices
- Always use absolute paths for executables and server entry points
- Explicitly declare every environment variable your server needs in the client config
- In stdio servers, never write to stdout except via the MCP SDK's transport layer
- Set up stderr logging from the first line of your server
- Pin dependency versions to avoid silent breakage from updates
- Test with MCP Inspector after every server change before updating the client config
- Store your MCP configuration in version control (sanitized of secrets)
- Use a secrets manager or environment-specific
.envfiles rather than hardcoding keys
You can verify your MCP server configuration against known patterns and spot common mistakes using MCPForge Verify before deploying to a client.
What to Collect Before Reporting the Bug
If you have completed the diagnostic steps and cannot resolve the failure, file a report with the following. Remove all secrets and personal data before sharing.
☐ MCP client name and version
☐ MCP server name and version (or git commit hash)
☐ Operating system and version
☐ Local stdio or remote HTTP
☐ Transport type (Streamable HTTP, stdio, legacy SSE)
☐ Sanitized configuration (no API keys, tokens, or passwords)
☐ Exact command and args
☐ Environment variable names only (no values)
☐ First error message verbatim
☐ Full stderr output from a manual run
☐ Exit code from a manual run
☐ HTTP status code and response body (remote servers)
☐ Authentication method (Bearer token, OAuth, API key header — no actual credentials)
☐ MCP Inspector result (success/failure + what it showed)
☐ Minimal reproduction steps (step by step from a clean state)
☐ What changed before the failure started (for regressions)
☐ Expected behavior vs actual behavior
A reproducible case that a maintainer can run in under five minutes is far more useful than a detailed description of what you observed. Include the minimal config and the exact command.
Primary Sources
- Model Context Protocol Specification — official protocol specification
- MCP TypeScript SDK — official SDK and examples
- MCP Python SDK — official Python SDK
- MCP Inspector — official testing tool
- MCP Servers Repository — reference server implementations
- Anthropic Claude Desktop MCP documentation — Claude Desktop configuration