Debugging Tips
Learn to diagnose and fix common issues with Claude Desktop integration.
Common Issues Overview
When things go wrong, systematic debugging helps. Here are the most common issues and how to solve them.
Issue 1: Server Not Appearing
Symptom: Your server doesn't show in Claude Desktop settings, or Claude says it doesn't have access to your tools.
Checklist:
1. Verify configuration file location
□ macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
□ Windows: %APPDATA%\Claude\claude_desktop_config.json
□ Linux: ~/.config/claude/claude_desktop_config.json
2. Verify JSON syntax
□ Run: python -m json.tool < claude_desktop_config.json
□ Should print formatted JSON without errors
3. Verify paths are absolute
□ "/Users/you/project/server.py" (correct)
□ "./server.py" or "~/project/server.py" (incorrect)
4. Verify file exists
□ ls -la /path/to/your/server.py
□ Should show the file with appropriate permissions
5. Restart Claude Desktop completely
□ Quit (not just close window)
□ Reopen
Issue 2: Server Fails to Start
Symptom: Server shows in settings but with an error status, or Claude can't use your tools despite the server being configured.
# Test server manually with exact command from config
/path/to/python /path/to/server.py
# Common errors:
# - ModuleNotFoundError: Wrong Python or missing dependencies
# - FileNotFoundError: Wrong path to server script
# - PermissionError: Script not executable
# - SyntaxError: Bug in server code
If using a virtual environment, make sure the config points to the
venv's Python: /path/to/project/.venv/bin/python
Issue 3: Handshake Fails
Symptom: Server starts but tools don't appear. The handshake isn't completing successfully.
# Add debugging to your server's initialize handler
def handle_initialize(params: dict) -> dict:
import sys
print(f"Received initialize: {params}", file=sys.stderr)
response = {
"protocolVersion": "2024-11-05",
"capabilities": {
"tools": {}
},
"serverInfo": {
"name": "my-server",
"version": "1.0.0"
}
}
print(f"Sending response: {response}", file=sys.stderr)
return response
Common handshake issues:
- Wrong
protocolVersion(must be "2024-11-05" or compatible) - Missing required fields in response
- Server outputting extra text to stdout (breaks JSON-RPC)
- Server not sending
notifications/initializedacknowledgment
Issue 4: Tools Not Working
Symptom: Tools appear but calls fail or return errors.
# Add comprehensive error handling
def handle_tool_call(name: str, arguments: dict) -> dict:
import sys
import traceback
print(f"Tool call: {name}({arguments})", file=sys.stderr)
try:
result = execute_tool(name, arguments)
print(f"Success: {result}", file=sys.stderr)
return {
"content": [{"type": "text", "text": str(result)}]
}
except Exception as e:
error_msg = f"Error in {name}: {e}\n{traceback.format_exc()}"
print(error_msg, file=sys.stderr)
return {
"content": [{"type": "text", "text": f"Error: {e}"}],
"isError": True
}
Issue 5: Stdout Corruption
Symptom: Intermittent failures, garbled responses, or "invalid JSON" errors.
Never print to stdout except for JSON-RPC messages! All debug output, logs, and print statements must go to stderr.
import sys
# BAD - corrupts STDIO protocol
print("Starting server...")
print(f"Processing: {data}")
# GOOD - use stderr for all non-protocol output
print("Starting server...", file=sys.stderr)
print(f"Processing: {data}", file=sys.stderr)
# Or use logging configured for stderr
import logging
logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)
logger = logging.getLogger(__name__)
logger.info("Starting server...")
logger.debug(f"Processing: {data}")
Viewing Claude Desktop Logs
Claude Desktop writes logs that can help diagnose issues:
# macOS - View Claude Desktop logs
tail -f ~/Library/Logs/Claude/mcp*.log
# Or find all log files
ls -la ~/Library/Logs/Claude/
# Windows - Logs location
# %LOCALAPPDATA%\Claude\Logs\
# Linux - Logs location
# ~/.local/share/Claude/logs/
Creating a Debug Wrapper
Create a wrapper script that logs all communication:
#!/usr/bin/env python3
"""
debug_wrapper.py - Wraps your server and logs all I/O.
Usage: Configure Claude Desktop to run this instead of your server.
"""
import subprocess
import sys
import threading
from datetime import datetime
LOG_FILE = "/tmp/mcp_debug.log"
def log(direction: str, data: str):
with open(LOG_FILE, "a") as f:
timestamp = datetime.now().isoformat()
f.write(f"[{timestamp}] {direction}: {data}\n")
def forward_stderr(process):
"""Forward server stderr to our stderr and log."""
for line in process.stderr:
log("STDERR", line)
sys.stderr.write(line)
sys.stderr.flush()
def main():
# Start the actual server
server_cmd = ["/path/to/python", "/path/to/server.py"]
process = subprocess.Popen(
server_cmd,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True
)
# Forward stderr in background
stderr_thread = threading.Thread(
target=forward_stderr,
args=(process,),
daemon=True
)
stderr_thread.start()
# Forward stdin to server
def forward_stdin():
for line in sys.stdin:
log("IN", line.strip())
process.stdin.write(line)
process.stdin.flush()
stdin_thread = threading.Thread(target=forward_stdin, daemon=True)
stdin_thread.start()
# Forward stdout from server
for line in process.stdout:
log("OUT", line.strip())
sys.stdout.write(line)
sys.stdout.flush()
if __name__ == "__main__":
main()
Testing with MCP Inspector
The MCP Inspector tool can help debug your server independently of Claude Desktop:
# Install MCP Inspector (if available)
npm install -g @modelcontextprotocol/inspector
# Run your server with the inspector
mcp-inspector python /path/to/server.py
# This provides a web UI to:
# - Send requests manually
# - View responses
# - Test tools interactively
# - Debug protocol issues
Quick Reference: Debugging Checklist
When things don't work:
1. Configuration
□ JSON syntax valid?
□ Paths absolute?
□ File permissions OK?
□ Claude Desktop restarted?
2. Server Basics
□ Server runs standalone?
□ All dependencies installed?
□ Correct Python version?
□ Virtual env activated (in config)?
3. Protocol
□ Initialize response correct?
□ Tool definitions valid?
□ No stdout pollution?
□ Proper JSON-RPC format?
4. Runtime
□ Error handling in place?
□ Logging to stderr?
□ No infinite loops?
□ Graceful shutdown?
5. Environment
□ Required env vars set?
□ API keys valid?
□ Network accessible (if needed)?
□ File paths accessible?
Lesson Complete!
You've learned how to integrate your MCP server with Claude Desktop. This is a major milestone - your custom tools are now available to a production AI assistant!
Configuration: Use absolute paths, valid JSON, and
specify the correct Python interpreter.
Debugging: Always log to stderr, never stdout. Use
debug wrappers and log files to trace issues.
Testing: Test your server standalone before
integrating with Claude Desktop.
What's Next?
In the final lesson, you'll build a capstone project that combines everything you've learned into a complete, production-ready MCP server.