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
# macOS
~/Library/Logs/Claude/mcp-server-<server-name>.log
# Windows
%APPDATA%\Claude\logs\mcp-server-<server-name>.logClaude Code logs
~/.claude/logs/mcp-server-<server-name>.logCursor 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:
# macOS / Linux
cat ~/.config/claude/claude_desktop_config.json | python3 -m json.tool
# Or for Claude Code
cat ~/.claude/mcp.json | python3 -m json.toolPython 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:
ls /absolute/path/to/dist/index.jsRelative 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:
npx -y @modelcontextprotocol/server-filesystem /tmpIf 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:
{
"command": "/usr/local/bin/node",
"args": ["/path/to/server/dist/index.js"]
}Find the full path with:
which node
which python3
which uvxIssue: 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:
{
"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:
lsof -i :8080 | grep LISTEN3. 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:
{
"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:
curl -I https://api.github.comIf 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:
// Wrong — corrupts the protocol
console.log("Server started");
// Correct
console.error("Server started");For 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:
{
"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:
ls -la /path/to/fileIssue: 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:
{
"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:
{
"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:
chmod 600 ~/.claude/mcp.jsonIssue: 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:
npm install -g @modelcontextprotocol/server-filesystemThen update your config to call node with the installed package path:
# Find the installed path
npm root -g2. 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:
curl -H "Authorization: Bearer $GITHUB_PERSONAL_ACCESS_TOKEN" https://api.github.com/userGeneral Debugging Checklist
When you encounter an MCP issue, work through this list in order:
- Check the server log file — it contains the error in most cases
- Validate the config file JSON syntax
- Run the server command manually in a terminal to see its output
- Verify all required environment variables are in the
envblock - Check that all file paths in
argsare absolute and exist - Confirm that
node,python3, or whichever runtime is used is accessible via its full path - If the server makes external API calls, test those calls with
curlto rule out network issues - 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.