Debugging MCP

Learn to debug MCP servers effectively. Tools, techniques and solutions for the most common problems.

Debugging Guide

Debugging MCP servers can be challenging due to the asynchronous nature of the protocol and JSON-RPC communication. This guide will help you identify and resolve common problems efficiently.

1. Identify

Use logs and inspection tools to identify where the problem occurs.

2. Isolate

Reduce the problem to its simplest component to understand the root cause.

3. Resolve

Apply the solution and verify that the problem is completely resolved.

Debugging Tools

Use these tools to inspect, test and debug your MCP servers.

MCP Inspector

Official interactive tool to inspect and test MCP servers. Allows viewing JSON-RPC messages in real time.

Features:

  • JSON-RPC message inspection
  • Resource and tool testing
  • Server capabilities visualization
  • Interactive debugging

Installation:

npm install -g @modelcontextprotocol/inspector

Usage:

mcp-inspector --server "python -m my_server"
View documentation

Verbose Logs

Enable detailed logging in your server to see all messages and operations.

Features:

  • Logging of all JSON-RPC messages
  • Detailed error traces
  • Timestamps and context
  • Filtering by log level

Usage:

# Python
import logging
logging.basicConfig(level=logging.DEBUG)

# TypeScript
import { setLogLevel } from "@modelcontextprotocol/sdk";
setLogLevel("debug");

Test Client

Create a simple test client to validate that your server responds correctly.

Features:

  • Testing specific methods
  • Response validation
  • Early error detection
  • Test automation

Usage:

# Basic example
from mcp.client import Client
client = Client("python -m my_server")
tools = await client.list_tools()
print(tools)

Debugging Techniques

Best practices and techniques to debug MCP servers effectively.

Strategic Logging

Add logs at key points in your code to track execution flow.

import logging
logger = logging.getLogger(__name__)

@app.call_tool()
async def call_tool(name: str, arguments: dict):
    logger.debug(f"Llamando herramienta: {name}")
    logger.debug(f"Argumentos: {arguments}")
    try:
        result = await execute_tool(name, arguments)
        logger.info(f"Herramienta ejecutada exitosamente")
        return result
    except Exception as e:
        logger.error(f"Error ejecutando herramienta: {e}", exc_info=True)
        raise

Input Validation

Validate and sanitize all parameters before processing them.

def validate_tool_args(arguments: dict, schema: dict):
    """Valida argumentos contra un esquema"""
    required = schema.get("required", [])
    for field in required:
        if field not in arguments:
            raise ValueError(f"Campo requerido faltante: {field}")
    
    # Validar tipos
    for field, value in arguments.items():
        expected_type = schema["properties"][field]["type"]
        if not isinstance(value, type_map[expected_type]):
            raise TypeError(f"{field} debe ser {expected_type}")

Error Handling

Implement robust error handling with clear messages.

from mcp.types import ErrorCode

@app.call_tool()
async def call_tool(name: str, arguments: dict):
    try:
        if name not in available_tools:
            raise ValueError(f"Herramienta desconocida: {name}")
        
        return await execute_tool(name, arguments)
    except ValueError as e:
        # Error de validación
        raise ValueError(f"Error de validación: {str(e)}")
    except Exception as e:
        # Error inesperado
        logger.exception(f"Error inesperado: {e}")
        raise RuntimeError(f"Error ejecutando herramienta: {str(e)}")

Incremental Testing

Test each component separately before integrating.

# Prueba unitaria de una herramienta
def test_read_file():
    result = read_file("/path/to/file.txt")
    assert result is not None
    assert isinstance(result, str)

# Prueba de integración
async def test_list_tools():
    tools = await list_tools()
    assert len(tools) > 0
    assert all(tool.name for tool in tools)

Common Troubleshooting

Frequent problems and their solutions. If you encounter a problem, check this section first.

Server does not start

Symptoms:

  • •Error executing server command
  • •Process terminates immediately
  • •No response from server

Solutions:

  • 1
    Verify that the server command is correct in the configuration
  • 2
    Make sure all dependencies are installed
  • 3
    Check operating system error logs
  • 4
    Try running the server manually from the terminal

Code example:

# Verificar que el servidor funciona
python -m my_server

# O con Node.js
node server.js

Tools do not appear in client

Symptoms:

  • •tools/list method returns empty list
  • •Tools are not available in Claude Desktop
  • •Error listing tools

Solutions:

  • 1
    Verify that list_tools() method is implemented correctly
  • 2
    Make sure the server has 'tools' capability enabled
  • 3
    Check that tool names are valid (no spaces, special characters)
  • 4
    Check server logs for serialization errors

Code example:

# Python - Verificar implementación
@app.list_tools()
async def list_tools() -> list[Tool]:
    return [
        Tool(
            name="my_tool",  # ✅ Nombre válido
            description="...",
            inputSchema={...}
        )
    ]

Parameter validation errors

Symptoms:

  • •Error 'Invalid params' when calling tools
  • •Parameters do not match schema
  • •Missing required values

Solutions:

  • 1
    Verify that inputSchema matches expected parameters
  • 2
    Make sure all 'required' fields are present
  • 3
    Validate data types (string, number, boolean, object, array)
  • 4
    Use valid JSON Schema for validation

Code example:

# Esquema correcto
inputSchema={
    "type": "object",
    "properties": {
        "name": {"type": "string"},
        "age": {"type": "number"}
    },
    "required": ["name"]  # ✅ Campos requeridos
}

Timeout or lost connection

Symptoms:

  • •Server stops responding
  • •Request timeouts
  • •Connection closed unexpectedly

Solutions:

  • 1
    Verify that asynchronous operations are handled correctly
  • 2
    Make sure there are no blocking operations
  • 3
    Implement appropriate timeouts for long operations
  • 4
    Check server memory and resource usage

Code example:

# Python - Operación asíncrona correcta
@app.call_tool()
async def call_tool(name: str, arguments: dict):
    # ✅ Usa async/await para operaciones I/O
    result = await some_async_operation()
    return result

JSON serialization errors

Symptoms:

  • •Error serializing responses
  • •Data types not compatible with JSON
  • •Encoding errors

Solutions:

  • 1
    Make sure all values are JSON serializable
  • 2
    Convert complex objects to dict/list before returning
  • 3
    Use TextContent for text responses
  • 4
    Handle special characters and UTF-8 encoding correctly

Code example:

# Python - Serialización correcta
from mcp.types import TextContent

return [TextContent(
    type="text",
    text=str(result)  # ✅ Convierte a string
)]

Debugging Checklist

Checklist for debugging problems in MCP servers

Basic Checks

  • Server runs without errors
  • Dependencies are installed correctly
  • Client configuration is correct
  • Logs show server activity
  • JSON-RPC protocol is working

Advanced Checks

  • Methods are implemented correctly
  • JSON Schema schemas are valid
  • Data types match the schema
  • Error handling is robust
  • Asynchronous operations are well handled

Need more help?

Explore more resources, tutorials and examples to master MCP.