gdbmcp is an MCP server that exposes structured GDB controls to an LLM over GDB/MI.
- Session lifecycle: start/stop/list sessions
- Target modes: local binary, PID attach, remote gdbserver, corefile
- Execution control: run/continue/step/next/finish/interrupt
- Debug state: backtrace, registers, threads, expression eval
- Memory: read memory by address
- Breakpoints/watchpoints: add/list/remove
- Runtime config: follow-fork mode, detach-on-fork, disassembly flavor
- CLI bridge: restricted read-only
interpreter-exec consolefor pwndbg/gef helpers - LLM helper tools:
snapshot_state,explain_stop_reason - Pwntools helpers:
find_processes_by_name,wait_for_process,attach_by_process_namepwntools_attach_and_break(wait + attach + bootstrap in one call)pwntools_bootstrap,resolve_module_bases,leak_snapshotgenerate_pwntools_gdbscript
- Audit logging to JSONL (
gdbmcp.audit.jsonlby default)
python -m venv .venv
source .venv/bin/activate
pip install -e .gdbmcpThe server uses stdio transport (default FastMCP behavior), which is what most MCP clients expect.
Use this in clients that accept an mcpServers JSON block (for example Claude Desktop/Cursor):
{
"mcpServers": {
"gdbmcp": {
"command": "/home/kali/mcp/gdbmcp/.venv/bin/python",
"args": ["-m","gdbmcp.server"],
"env": {
"GDBMCP_ENABLE_ATTACH": "1",
"GDBMCP_ENABLE_WRITE": "0"
}
}
}
}If you installed globally, replace command with gdbmcp.
- GDB runs as a subprocess in MI mode:
gdb --interpreter=mi2. - One command at a time per session (serialized by an async lock).
- Async GDB events (
*stopped,=thread-created, etc.) are captured and exposed.
write_memoryis disabled by default.- Enable it explicitly with:
export GDBMCP_ENABLE_WRITE=1- PID attach is enabled by default; disable if needed:
export GDBMCP_ENABLE_ATTACH=0- Restrict debugged paths to approved prefixes:
export GDBMCP_ALLOWED_PATH_PREFIXES=/home/kali/ctf:/tmp/lab- Audit log path can be configured:
export GDBMCP_AUDIT_LOG=/tmp/gdbmcp.audit.jsonlstart_session(binary="./chall", disable_aslr=true)set_runtime_options(follow_fork_mode="child", detach_on_fork=false)set_breakpoint(location="main")run()snapshot_state()
pwntools_attach_and_break(name="chall", breakpoints=["main", "*0x40123a"], binary="./chall", timeout_sec=15)continue_exec()leak_snapshot(session_id=...)
resolve_module_bases(session_id=...)leak_snapshot(session_id=..., stack_qwords=32)generate_pwntools_gdbscript(breakpoints=["main"], commands=["x/20gx $rsp"])
connect_gdbserver(target="127.0.0.1:1234", binary="./chall")list_threads()read_memory(address="0x7fffffffe000", count=128)
load_corefile(binary="./chall", corefile="./core.1337")backtrace()snapshot_state()