CodexSpot

MCP Troubleshooting Guide: Common Issues and Fixes

March 15, 2026 · 8 min read

TL;DR

  • Most MCP failures are config file syntax errors, wrong file paths, or missing environment variables
  • Check the MCP server log file first — it captures stderr from the server process and usually shows the root cause
  • Transport errors mean the server process started but the protocol handshake failed, often due to stdout pollution
  • Permission errors on the filesystem server are almost always path configuration issues, not OS-level permissions

MCP servers are generally reliable once configured correctly, but getting to that point can involve some debugging. This guide covers the failures developers encounter most often, explains why they happen, and gives concrete steps to fix them.

Where to Find Logs

Before diving into specific issues, know where to look for diagnostic information.

Claude Desktop logs

text
# macOS
~/Library/Logs/Claude/mcp-server-<server-name>.log

# Windows
%APPDATA%\Claude\logs\mcp-server-<server-name>.log

Claude Code logs

text
~/.claude/logs/mcp-server-<server-name>.log

Cursor logs

Open Cursor, press Cmd+Shift+P (macOS) or Ctrl+Shift+P (Windows/Linux), search for "Show MCP Logs", and select the relevant server.

These logs capture everything the server process writes to stderr, which is where well-behaved MCP servers write their diagnostic output. When something goes wrong, this is the first place to look.


Issue: Server Does Not Appear in the Tool List

The AI says it has no MCP tools, or the specific server's tools are missing.

Diagnosis

Check whether the server process started at all. Open the log file for that server. If the file does not exist, the server never started. If it exists but is empty, the server started and exited immediately.

Common causes and fixes

1. Config file has a JSON syntax error

The config file is read before any server starts. A single JSON error prevents all servers from loading.

Validate your config:

bash
# macOS / Linux
cat ~/.config/claude/claude_desktop_config.json | python3 -m json.tool

# Or for Claude Code
cat ~/.claude/mcp.json | python3 -m json.tool

Python will print the error location if the JSON is invalid. Common mistakes: trailing commas after the last item in an array or object, missing quotes around keys, single quotes instead of double quotes.

2. Wrong path to the server executable

If command is set to node and the server is a compiled JS file, make sure the path in args is absolute and the file exists:

bash
ls /absolute/path/to/dist/index.js

Relative paths do not work in MCP config files. Always use absolute paths.

3. npx cannot find the package

If you see npm error could not determine executable to run in the log, the package name is wrong or the version does not exist on npm.

Test the command manually in a terminal:

bash
npx -y @modelcontextprotocol/server-filesystem /tmp

If this fails in a terminal, it will fail in the MCP config too.

4. Node.js / Python not in PATH

Claude Desktop and Cursor launch server processes in a restricted environment where your shell's PATH may not be fully loaded.

Specify the full path to the executable:

json
{
  "command": "/usr/local/bin/node",
  "args": ["/path/to/server/dist/index.js"]
}

Find the full path with:

bash
which node
which python3
which uvx

Issue: Server Starts but Immediately Exits

The log file contains a startup message and then nothing (or an error and stack trace).

Common causes and fixes

1. Missing required environment variable

Most servers validate required env vars at startup and exit with an error if they are missing. The log should say something like GITHUB_PERSONAL_ACCESS_TOKEN environment variable is required.

Add the missing variable to the env block in your config:

json
{
  "mcpServers": {
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "your-token-here"
      }
    }
  }
}

Note that environment variables set in your shell profile (~/.zshrc, ~/.bashrc) are not automatically available to MCP server processes. You must include them explicitly in the env block.

2. Port conflict (HTTP transport only)

If your server uses HTTP transport and tries to bind to a port already in use, it exits immediately. Change the port in your server configuration or find and stop the conflicting process:

bash
lsof -i :8080 | grep LISTEN

3. Dependency not installed

For Python-based servers, the package may not be installed in the expected location. Use uvx for Python servers where possible — it handles dependency isolation automatically:

json
{
  "command": "uvx",
  "args": ["mcp-server-fetch"]
}

Issue: Connection Timeout

The server appears in the tool list but tool calls hang indefinitely or return a timeout error.

Common causes and fixes

1. Tool call is waiting for user input on stdin

Some server implementations incorrectly read from stdin for reasons other than the MCP protocol. This blocks the connection. Check the server's source or issues for stdin-related bugs.

2. External API not responding

If the tool makes an HTTP request to an external service, a slow or unresponsive API will cause the tool call to hang. Test the API directly:

bash
curl -I https://api.github.com

If the API is slow, consider increasing the timeout in the server's configuration if it supports one, or add a timeout to your tool implementation.

3. Server is processing a very large response

Tools that return large amounts of data (full file trees, entire database dumps) can take much longer than expected. Scope your requests: ask the AI to look at specific directories or tables rather than everything at once.


Issue: Transport / Protocol Errors

You see errors like Unexpected token, Invalid JSON, Parse error, or MCP protocol violation in the logs.

Cause: stdout pollution

The MCP protocol uses stdout for communication. Any console.log() or print() statement in your server that writes to stdout will corrupt the protocol stream, causing parse errors on the client side.

Fix: Change all logging to stderr:

typescript
// Wrong — corrupts the protocol
console.log("Server started");

// Correct
console.error("Server started");

For Python:

python
import sys

# Correct
print("Server started", file=sys.stderr)

Cause: Server outputting non-JSON content before the handshake

Some servers print a startup banner or version string before the first JSON message. This breaks the protocol. If you see this in a third-party server, report it as a bug and temporarily work around it by piping output through a filter.


Issue: Filesystem Permission Errors

The filesystem server returns "Permission denied" or "Access denied" errors when trying to read or write files.

Common causes and fixes

1. Path not in the allowed list

The filesystem server only allows operations on directories you pass as arguments. If Claude tries to access a file outside those directories, it gets a permission error — even if the OS would allow it.

Check your configuration and make sure the paths you need are listed:

json
{
  "args": [
    "-y",
    "@modelcontextprotocol/server-filesystem",
    "/Users/yourname/projects",
    "/Users/yourname/Documents"
  ]
}

2. Symlinks pointing outside the allowed path

The filesystem server follows symlinks but checks whether the resolved path is within the allowed directories. A symlink inside an allowed directory that points to a file outside it will be rejected. Either move the target file into an allowed directory or add the symlink's target directory to the allowed list.

3. OS-level permission (less common)

If the MCP server process does not have read access to a file at the OS level, it returns a permission error. This is uncommon in local development but can happen with files owned by another user or with strict ACLs. Check with:

bash
ls -la /path/to/file

Issue: Environment Variable Not Found at Runtime

The server starts but fails when making API calls, reporting that an API key or credential is missing.

Cause: Shell profile variables are not inherited

When Claude Desktop or Claude Code starts an MCP server, the server process does not inherit your interactive shell environment. Variables set in .zshrc, .bashrc, .bash_profile, or similar files are not available.

Fix: Pass all required credentials explicitly in the env block of the server config:

json
{
  "env": {
    "GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_...",
    "NOTION_API_TOKEN": "secret_..."
  }
}

If you want to avoid storing secrets in the config file in plaintext, you can reference variables that Claude Code expands at config-read time:

json
{
  "env": {
    "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_TOKEN}"
  }
}

This reads GITHUB_TOKEN from the environment at the time Claude Code reads the config — which may or may not have the variable depending on how Claude Code was launched.

The most reliable approach is to store credentials directly in the config file and restrict file permissions:

bash
chmod 600 ~/.claude/mcp.json

Issue: Server Works Locally but Fails After Restart

The server worked in a previous session but is not responding now.

Common causes

1. npx package cache cleared or corrupted

npx -y downloads the package on first run and caches it. If the cache is cleared, it re-downloads. If npm's registry is temporarily unavailable, this fails.

Fix by pre-installing the package globally:

bash
npm install -g @modelcontextprotocol/server-filesystem

Then update your config to call node with the installed package path:

bash
# Find the installed path
npm root -g

2. Token expired or revoked

GitHub personal access tokens and similar credentials expire or get revoked. If a server was working and stopped, check that your credentials are still valid by testing the API directly:

bash
curl -H "Authorization: Bearer $GITHUB_PERSONAL_ACCESS_TOKEN" https://api.github.com/user

General Debugging Checklist

When you encounter an MCP issue, work through this list in order:

  1. Check the server log file — it contains the error in most cases
  2. Validate the config file JSON syntax
  3. Run the server command manually in a terminal to see its output
  4. Verify all required environment variables are in the env block
  5. Check that all file paths in args are absolute and exist
  6. Confirm that node, python3, or whichever runtime is used is accessible via its full path
  7. If the server makes external API calls, test those calls with curl to rule out network issues
  8. Check whether the issue reproduces with a simpler request — sometimes a specific tool input triggers a bug in the server

Most MCP issues resolve at steps 1-4. The protocol itself is simple and stable; the failures are almost always in configuration or credentials.

Referenced in this post