MCP-PDB: Python Debugger Interface for Claude/LLMs

April 14, 2026 · View on GitHub

Python License

MCP-PDB provides tools for using Python's debugger (pdb) with Claude and other LLMs through the Model Context Protocol (MCP). This was inspired by debug-gym by Microsoft, which showed gains in various coding benchmarks by providing a coding agent access to a python debugger.

⚠️ Security Warning

This tool executes Python code through the debugger. Use in trusted environments only.

Installation

Works best with uv

Claude Code

# Install the MCP server
claude mcp add mcp-pdb -- uv run --with mcp-pdb mcp-pdb

# Alternative: Install with specific Python version
claude mcp add mcp-pdb -- uv run --python 3.13 --with mcp-pdb mcp-pdb

# Note: The -- separator is required for Claude Code CLI

Windsurf

{
  "mcpServers": {
    "mcp-pdb": {
      "command": "uv",
      "args": [
        "run",
        "--with",
        "mcp-pdb",
        "mcp-pdb"
      ]
    }
  }
}

Available Tools

ToolDescription
start_debug(file_path, use_pytest, args)Start a local debugging session for a Python file
connect_remote_debug(host, port, timeout)Connect to a remote PDB session over TCP
send_pdb_command(command)Send a command to the running PDB instance (local or remote)
set_breakpoint(file_path, line_number)Set a breakpoint at a specific line
clear_breakpoint(file_path, line_number)Clear a breakpoint at a specific line
list_breakpoints()List all current breakpoints
restart_debug()Restart/reconnect the current debugging session
examine_variable(variable_name)Get detailed information about a variable
get_debug_status()Show the current state of the debugging session
end_debug()End the current debugging session (closes socket for remote)

Remote Debugging

Connect to a Python process that exposes PDB over a TCP socket. All existing tools (send_pdb_command, set_breakpoint, examine_variable, etc.) work identically once connected.

rpdb is installed alongside mcp-pdb and is the easiest way to debug with both a local terminal and the MCP agent simultaneously.

Terminal ──→ stdin ──→ PDB ──→ stdout ──→ Terminal
                            └──→ socket ──→ mcp-pdb
mcp-pdb  ──→ socket ──┘  (local stdin takes priority)

Start a script under rpdb:

REMOTE_PDB_PORT=4444 rpdb script.py [args]
REMOTE_PDB_PORT=4444 rpdb -m mymodule [args]

rpdb prints waiting for mcp connection on 127.0.0.1:4444 ... and blocks until the MCP agent connects. All normal pdb flags (-c, --help, etc.) are supported.

Then connect from Claude / the MCP agent:

connect_remote_debug(host="127.0.0.1", port=4444)

All PDB output is now mirrored to both the terminal and the agent. Commands typed in the terminal take priority; the agent's commands are echoed to the terminal so you can follow along.

Environment variables:

VariableDefaultDescription
REMOTE_PDB_HOST127.0.0.1Interface to listen on (0.0.0.0 for remote machines)
REMOTE_PDB_PORT4444TCP port

In-source one-liner (correct frame, all locals visible):

# Add at the line you want to break at:
from mcp_pdb.rpdb import set_trace; set_trace()

The process blocks here until the MCP agent (or any TCP client) connects.

Zero-code-change with breakpoint():

PYTHONBREAKPOINT=mcp_pdb.rpdb.set_trace python script.py

Python ≥ 3.11 with --pdbcls (remote only, no local terminal):

python -m pdb --pdbcls=mcp_pdb.rpdb:Debugger script.py
pytest --pdb --pdbcls=mcp_pdb.rpdb:Debugger

Manual remote-pdb setup

If you need to attach to an already-running process without using rpdb:

Option A – remote-pdb package

from remote_pdb import RemotePdb
RemotePdb("0.0.0.0", 4444).set_trace()

Option B – stdlib only

import io, socket, pdb

srv = socket.socket()
srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
srv.bind(("0.0.0.0", 4444))
srv.listen(1)
conn, _ = srv.accept()   # blocks until MCP connects
f = conn.makefile("rwb", buffering=0)
pdb.Pdb(stdin=io.TextIOWrapper(f), stdout=io.TextIOWrapper(f)).set_trace()

Connect from Claude / the LLM:

connect_remote_debug(host="192.168.1.10", port=4444)

timeout (default 30 s) controls how long to retry on ConnectionRefused— useful when the remote process has not yet reached set_trace().

restart_debug() reconnects to the same host/port. end_debug() closes the socket gracefully (sends q first).

Common PDB Commands

CommandDescription
nNext line (step over)
sStep into function
cContinue execution
rReturn from current function
p variablePrint variable value
pp variablePretty print variable
b file:lineSet breakpoint
cl numClear breakpoint
lList source code
qQuit debugging

Features

  • Project-aware debugging with automatic virtual environment detection
  • Support for both direct Python debugging and pytest-based debugging
  • Automatic breakpoint tracking and restoration between sessions
  • Works with UV package manager
  • Variable inspection with type information and attribute listing

Troubleshooting

Claude Code Installation Issues

If you encounter an error like:

MCP server "mcp-pdb" Connection failed: spawn /Users/xxx/.local/bin/uv run --python 3.13 --with mcp-pdb mcp-pdb ENOENT

Make sure to include the -- separator when using claude mcp add:

# ✅ Correct
claude mcp add mcp-pdb -- uv run --with mcp-pdb mcp-pdb

# ❌ Incorrect (missing --)
claude mcp add mcp-pdb uv run --with mcp-pdb mcp-pdb

To verify your installation:

# Check if mcp-pdb is listed
claude mcp list | grep mcp-pdb

# Check server status in Claude Code
# Type /mcp in Claude Code to see connection status

License

MIT License - See LICENSE file for details.