Skip to main content

Debugging Your MCP Server

This guide helps you identify and fix common issues when building an MCP server for Dedalus.

Common Issues and Solutions

1. Server Not Responding

Symptom: Error: connect ECONNREFUSED or Connection refusedSolutions:
  • Verify your server is running on the correct port
  • Check firewall settings aren’t blocking the port
  • Ensure you’re using the correct URL (http://localhost:8000/mcp)
# Check if port is in use
lsof -i :8000  # Mac/Linux
netstat -an | findstr :8000  # Windows
Symptom: Getting 404 errors when calling the endpointSolutions:
  • Verify the endpoint path is exactly /mcp (case-sensitive)
  • Check your server routing configuration
  • Ensure POST method is allowed
# Correct
@app.post("/mcp")  

# Wrong
@app.post("/MCP")  # Case matters!
@app.get("/mcp")   # Must be POST!
Symptom: Access-Control-Allow-Origin errors in browser consoleSolutions:
# Python/FastAPI
from fastapi.middleware.cors import CORSMiddleware

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # Configure for your domain in production
    allow_methods=["POST", "GET"],
    allow_headers=["*"],
)
// Node.js/Express
const cors = require('cors');
app.use(cors());

2. Protocol Handshake Failures

Symptom: Error about unsupported protocol versionSolution: Use a supported protocol version:
{
  "protocolVersion": "2024-11-05"  // Currently supported
}
Symptom: Initialization fails with missing serverInfo errorSolution: Always include serverInfo in initialize response:
{
  "jsonrpc": "2.0",
  "result": {
    "protocolVersion": "2024-11-05",
    "capabilities": {},
    "serverInfo": {
      "name": "your-server-name",  // Required!
      "version": "1.0.0"            // Required!
    }
  },
  "id": 1
}
Symptom: Tools not appearing or not workingSolution: Declare capabilities correctly:
{
  "capabilities": {
    "tools": {
      "listTools": true,
      "callTool": true
    }
  }
}

3. Tool Execution Problems

Symptom: tools/list returns empty array or errorDebug Steps:
  1. Check method name is exactly tools/list
  2. Verify tools array format:
{
  "jsonrpc": "2.0",
  "result": {
    "tools": [  // Must be an array
      {
        "name": "tool_name",
        "description": "Tool description",
        "inputSchema": {
          "type": "object",
          "properties": {}
        }
      }
    ]
  },
  "id": 2
}
Symptom: Tool execution returns error or wrong formatCommon Issues:
  • Wrong parameter extraction:
# Wrong
tool_name = message["params"]["tool"]  

# Correct
tool_name = message["params"]["name"]
arguments = message["params"]["arguments"]
  • Invalid response format:
# Wrong
return {"result": "Hello"}

# Correct
return {
  "jsonrpc": "2.0",
  "result": {
    "content": [
      {"type": "text", "text": "Hello"}
    ]
  },
  "id": message.get("id")
}
Symptom: Tool gets undefined or missing parametersSolution: Check parameter schema matches what you expect:
// Tool definition
{
  "name": "search",
  "inputSchema": {
    "type": "object",
    "properties": {
      "query": {"type": "string"}  // Parameter name is 'query'
    },
    "required": ["query"]
  }
}

// Tool handler
const query = message.params.arguments.query;  // Must match schema

Testing Tools

MCP Test Client

Create a simple test client to debug your server:
# test_client.py
import requests
import json

def test_mcp_server(base_url="http://localhost:8000"):
    """Test MCP server endpoints"""
    
    print("Testing MCP Server...")
    
    # Test 1: Initialize
    print("\n1. Testing initialize...")
    response = requests.post(
        f"{base_url}/mcp",
        json={
            "jsonrpc": "2.0",
            "method": "initialize",
            "params": {
                "protocolVersion": "2024-11-05",
                "capabilities": {}
            },
            "id": 1
        }
    )
    print(f"Status: {response.status_code}")
    print(f"Response: {json.dumps(response.json(), indent=2)}")
    
    # Test 2: Initialized notification
    print("\n2. Testing initialized notification...")
    response = requests.post(
        f"{base_url}/mcp",
        json={
            "jsonrpc": "2.0",
            "method": "initialized",
            "params": {}
        }
    )
    print(f"Status: {response.status_code}")
    
    # Test 3: List tools
    print("\n3. Testing tools/list...")
    response = requests.post(
        f"{base_url}/mcp",
        json={
            "jsonrpc": "2.0",
            "method": "tools/list",
            "params": {},
            "id": 2
        }
    )
    print(f"Status: {response.status_code}")
    tools = response.json()
    print(f"Available tools: {json.dumps(tools, indent=2)}")
    
    # Test 4: Call a tool
    if tools.get("result", {}).get("tools"):
        tool_name = tools["result"]["tools"][0]["name"]
        print(f"\n4. Testing tools/call with '{tool_name}'...")
        response = requests.post(
            f"{base_url}/mcp",
            json={
                "jsonrpc": "2.0",
                "method": "tools/call",
                "params": {
                    "name": tool_name,
                    "arguments": {}
                },
                "id": 3
            }
        )
        print(f"Status: {response.status_code}")
        print(f"Response: {json.dumps(response.json(), indent=2)}")

if __name__ == "__main__":
    test_mcp_server()

Debug Logging

Add comprehensive logging to understand what’s happening:
# Add to your server
import logging

logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)

@app.post("/mcp")
async def mcp_endpoint(request: Request):
    message = await request.json()
    
    # Log incoming request
    logger.debug(f"Received message: {json.dumps(message, indent=2)}")
    
    method = message.get("method")
    logger.info(f"Processing method: {method}")
    
    # Process message...
    response = process_message(message)
    
    # Log outgoing response
    logger.debug(f"Sending response: {json.dumps(response, indent=2)}")
    
    return JSONResponse(response)

Validation Checklist

Use this checklist to validate your MCP server:
1

Basic Connectivity

curl -X POST http://localhost:8000/mcp \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"initialize","params":{},"id":1}'
✅ Should return 200 status with valid JSON
2

Protocol Compliance

Check response includes:
  • jsonrpc: "2.0"
  • result or error field
  • Same id as request (if provided)
3

Tool Discovery

curl -X POST http://localhost:8000/mcp \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"tools/list","params":{},"id":2}'
✅ Returns array of tool definitions
4

Tool Execution

curl -X POST http://localhost:8000/mcp \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"your_tool","arguments":{}},"id":3}'
✅ Returns content array with results
5

Error Handling

curl -X POST http://localhost:8000/mcp \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"invalid_method","params":{},"id":4}'
✅ Returns proper error response

Performance Issues

Slow Response Times

If your tools take longer than 30 seconds, consider implementing SSE streaming to prevent timeouts.
Quick fixes:
  • Add async/await for I/O operations
  • Implement caching for expensive operations
  • Use connection pooling for database/API calls
  • Return partial results with streaming

Memory Leaks

Common causes:
  • Not closing database connections
  • Accumulating data in global variables
  • Not cleaning up async tasks
Solution:
# Use context managers
async with httpx.AsyncClient() as client:
    response = await client.get(url)
    
# Clean up resources
@app.on_event("shutdown")
async def shutdown():
    # Close database connections
    # Cancel pending tasks
    # Clear caches

Getting Help

Quick Debug Commands

# Test endpoint is accessible
curl -I http://localhost:8000/mcp

# Test with minimal message
echo '{"jsonrpc":"2.0","method":"initialize","id":1}' | \
  curl -X POST http://localhost:8000/mcp \
    -H "Content-Type: application/json" \
    -d @-

# Monitor server logs
tail -f server.log | grep -E "(ERROR|WARNING)"

# Check process is running
ps aux | grep "your_server"

# Test with timeout
curl -m 5 -X POST http://localhost:8000/mcp \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"tools/list","id":1}'
Remember: Most issues come from incorrect JSON-RPC formatting or missing required fields. Always validate your responses match the expected format.