Skip to main content
Glama

gdb-mcp

Give your coding agent hands on a real GDB — built for binary exploitation.

An MCP server that lets Claude Code, Codex, or any MCP client drive live Linux gdb sessions (pwndbg-aware) for vulnerability research, CTF pwn, and exploit development.

CI Python Platform License: MIT Tests

Quick Start · Tools · Architecture · Experimental · Roadmap · 中文文档


Why gdb-mcp?

Most "debugger MCP" projects parse GDB/MI output or scrape terminal screens. gdb-mcp takes a different route: a small Python plugin runs inside the gdb process and talks to the server over a JSON-lines control channel — so pwndbg contexts, pwntools-launched sessions, and reverse-execution all just work, with none of the prompt-scraping fragility.

  • Built for pwn, not just debugging — structured crash triage, glibc heap bins, checkpoint/restore, a cyclic-offset oracle, and a campaign state machine that remembers what your session has already proven.

  • Token-frugal by design — one call returns the whole stop picture (verdict + key registers + backtrace + disassembly); large outputs spill to disk instead of flooding the context window.

  • Delegated execution — bounded loops (trace, heap probes, fuzz_loop, minimize) run inside gdb at native speed and return constant-size summaries, so iterating 1,000 times costs one tool call.

  • pwntools stays in charge — gdb.debug() / gdb.attach() sessions register automatically; the server never fights your scripts for I/O.

  • Verified against reality — 902 unit tests (including seeded protocol-layer fuzzing against the JSON-lines control channel) plus end-to-end suites driving real gdb in WSL, and a versioned acceptance benchmark (bench/, 576 tasks across 8 families, reference-solved 576/576) that proves every task solvable before any model runs on it — the first model report is committed under bench/reports/.

Related MCP server: gdb-mcp

Quick Start

1. Install (Windows side, WSL2 backend — or natively on Linux):

pip install -e .

2. Prepare WSL (Kali/Ubuntu recommended):

sudo apt install gdb python3 python3-pip gcc   # pwndbg optional but recommended

3. Register with your MCP client:

Claude Code (.mcp.json in the project or user scope):

{
  "mcpServers": {
    "gdb-mcp": {
      "command": "gdb-mcp",
      "env": { "GDB_MCP_PORT": "3939" }
    }
  }
}

Cursor — same shape, in ~/.cursor/mcp.json. Codex CLI — add to ~/.codex/config.toml:

[mcp_servers.gdb-mcp]
command = "gdb-mcp"
env = { GDB_MCP_PORT = "3939" }

Any other MCP client: a stdio server launching gdb-mcp (or the hardened HTTP transport via --http + --mcp-port, with a bearer token).

4. Start a session — either let the server launch gdb:

launch_gdb(program="/tmp/cracker", run=True)

or keep your pwntools workflow untouched and just load the plugin:

from pwn import *
io = gdb.debug("./vuln", gdb_args=["-x", "src/gdb_mcp/plugin/gdb_mcp_plugin.py"])

The session registers itself. Then ask your agent:

Continue and tell me exactly why it crashed — then prove you control PC.

→ continue_execution(wait=True, with_context=True)
  {"stopped": true, "stop_info": {"signal": "SIGSEGV", "pc": "0x4011eb"},
   "context": {"registers": {...}, "backtrace": [...], "disassembly": [...]}}

One call. Full picture.

Tool Catalog

52 tools by default (12 under GDB_MCP_TOOL_PROFILE=core, 60 with --experimental), grouped by job — and by capability layer: core (sessions/execution/breakpoints/state — any debugging scenario), pwn (crash triage, heap, checkpoints, campaign, policies), static (the Ghidra bridge), and kernel (experimental QEMU/gdbstub tooling). The layers share one wire protocol; the core profile is the subset a non-exploitation backend would need.

Group

Tools

Sessions

list_sessions session_status launch_gdb launch_script get_process_output kill_session quit_gdb get_events export_session_script diff_sessions

Execution

execute_command (raw gdb, pwndbg-compatible, paginated + spilled to disk) continue_execution (wait/with_context) interrupt wait_for_stop get_stop_reason read_result batch_commands

Crash triage

crash_report — signal, fault addr, registers, backtrace, disasm, memory at PC/SP/fault, structured memory map · triage_crash — replay a crashing payload from a checkpoint, collect the full report, optionally minimize, store evidence

State

read_memory write_memory read_registers write_register get_backtrace disassemble evaluate list_threads select_frame get_memory_map (structured) load_target

Breakpoints

set_breakpoint (sw/hw/watch/condition/temporary + commands/auto_continue probes) list_breakpoints manage_breakpoint

Pwn workflow

heap_bins (pwndbg bins → JSON) checkpoint (create/restore/diff) run_policy (trace / heap probes / fuzz_loop / minimize / crash_check / bp_stats — bounded loops at native speed) campaign (state machine + cyclic oracle)

Static bridge (Ghidra)

analyze_binary list_analyses get_analysis_status get_binary_overview list_sections list_symbols list_functions list_strings decompile_function get_static_disassembly get_xrefs get_call_graph search_decompiled_code annotate_code remove_code_annotation — SHA-256-keyed analysis cache; runtime stops map back to static function/line

8 experimental tools (behind --experimental): inferior stdio channel (io_setup / send_to_inferior / read_inferior_output / io_teardown), identify_libc, search_gadgets, kernel_launch / kernel_snapshot (crash delta-minimization rides run_policy(kind=...), not a tool).

15 static-analysis tools when a Ghidra headless install is available: analyze_binary, decompile_function, get_xrefs, get_call_graph, search_decompiled_code, annotations, and more.

export_session_script compiles everything your session did into a deterministic, replayable gdbscript — audit trail, reproducer, and the answer to "why not just write a gdbscript?" in one artifact.

Architecture

Claude Code / any MCP client ──stdio or HTTPS──► gdb-mcp server (52 tools)
        ▲  campaign state · journals · policies · static bridge
        │
        │ TCP JSON-lines (scoped session tokens, heartbeats)
        ▼
gdb process (WSL2 / native / Docker / SSH target)
  └─ gdb_mcp_plugin.py — in-process bridge
       ├─ all gdb API calls marshalled to gdb's main thread
       ├─ stop/running/exited events pushed as they happen
       └─ coexists with pwndbg & pwntools (never touches prompt or I/O)

Launchers: WSL2 · native Linux · Docker (SYS_PTRACE image recipe included) · SSH — pick with GDB_MCP_LAUNCHER. Transport: stdio by default, or hardened streamable HTTP (--http) with Host/Origin validation, bearer tokens, TLS and mutual-TLS options.

Concurrency semantics. Within one session, tool calls execute strictly one-at-a-time: the plugin marshals every gdb API call onto gdb's main thread, and the server serializes requests per session (composite tools like crash_report run atomically under the same lock). A second call on a busy session waits — bounded by GDB_MCP_REQUEST_TIMEOUT (30s default) — rather than interleaving. Execution verbs while the inferior runs fail fast with INFERIOR_RUNNING instead of queueing silently. Different sessions are fully independent.

Compatibility. The plugin's gdb API usage carries explicit per-version fallbacks (feature-probed at load, e.g. gdb.interrupt on gdb ≥ 15, qualified breakpoints on newer builds). Verified against:

gdb

Where

12.1

CI (ubuntu-22.04 apt)

15.x

CI (ubuntu-24.04 apt)

17.2 + pwndbg

WSL2, full end-to-end suites locally

Python 3.10+ on the server side; the plugin itself is stdlib-only so it can be source-deployed into any gdb with an embedded Python.

Designed for Agents

  • Stop = full context. continue_execution(wait=True, with_context=True) returns verdict, key registers, backtrace and disassembly in one response.

  • Bounded everything. Pagination, result spilling with SHA-256 handles, explicit truncated flags, ring-buffered events — no silent truncation, no unbounded dumps.

  • Campaign state machine. Cyclic-offset oracle, libc leak bookkeeping, and pc-control detection are injected into every stop — the agent never re-derives what the session already proved.

  • Delegated policies. run_policy runs tracing, heap timelines, snapshot fuzzing and delta-minimization inside gdb at native speed; the model only sees constant-size summaries.

  • Session = asset. Journals persist across restarts; sessions re-attach with their identity intact; everything exports to replayable gdbscript.

Launchers

Backend

Target

Notes

wsl (default)

WSL2 distro

mirrored networking recommended

native

local Linux

plain bash -lc

docker

ephemeral container

SYS_PTRACE + relaxed seccomp; per-session containers. Build the image first (docker build -f docker/Dockerfile -t gdb-mcp:latest .); run the server with --host-bind 0.0.0.0 --token ... (a non-loopback bind requires a token) and the plugin dials back over host.docker.internal

ssh

remote host

key-based auth; great for IoT/router targets

Experimental Features

Enable with the --experimental launch flag (deliberately no environment variable — a stray shell variable must never destabilize your server):

  • Inferior stdio channel — drive menu-style targets without pwntools.

  • Crash minimizer — delta-debugging over checkpoint restore.

  • identify_libc / search_gadgets — libc.rip API and ROPgadget CLI integrations with honest-degradation errors.

  • kernel_launch / kernel_snapshot — boot a Linux kernel VM under QEMU with a gdbstub and attach gdb to it; savevm/loadvm is the kernel-pwn revert primitive. Requires QEMU inside the launcher backend.

Security Model

  • TCP listener is loopback-only by default; non-loopback binds require a token. Launched gdb sessions use session-scoped tokens (HMAC-derived) — the master never reaches child processes.

  • HTTP transport adds Host/Origin validation, bearer tokens (controller + read-only observer roles), TLS and mutual TLS.

  • --readonly drops mutating tools; debugger-escaping commands (shell/python/source/dump/restore/set exec-wrapper/…) are blocked at two layers unless --allow-unsafe. The gate is abbreviation-aware (she/py/so resolve to shell/python/source in real gdb) and checks every line of a multi-command string; the command-resolution premises it relies on are verified against real gdb in CI (tests/integration/run_unsafe_gate_probe.sh).

  • A chained audit log (<log-dir>/audit.log, on by default, --no-audit-log to disable) records security decisions — handshakes and rejections, HTTP 403s, observer denials, unsafe-command blocks — as a tamper-evident chain where every record commits to its predecessor: HMAC-SHA256 when a master token is configured (a full rewrite without the token fails verification), plain SHA-256 otherwise; chain heads are anchored to the server log periodically so tail truncation is detectable. Verify offline with python -m gdb_mcp.audit <log> [--token …].

  • Journals, session state and results are written 0600; persisted state is re-validated on load (journals and sessions.json carry explicit schema versions; unknown newer versions are refused, not guessed at). GDB can execute arbitrary code on its target — run it on targets you own. Full notes: ROADMAP_V2.md, CIA audit in the commit history.

On token lifetimes: session tokens are stateless HMAC-SHA256 derivations of the master token, which is what lets a plugin re-verify after a server restart without state — so they cannot expire individually. The compensating design: the master token never leaves the server process, per-session tokens are useless for any other session, and HTTP exposure should use TLS/mTLS (client certificates are revocable). If you need a shorter leak window, restart the server with a new master token — plugins re-derive automatically.

Testing

# unit (no gdb required)
python -m pytest tests/ -q                        # 902 tests, ~12s

# real-gdb suites (WSL2 or native Linux; each prints its own verdict)
wsl bash tests/integration/run_wsl_integration.sh # plugin <-> server protocol
python tests/integration/run_mcp_tools_e2e.py --distro kali-linux
                                                  # every registered tool, end to end
wsl bash tests/integration/run_policy_smoke.sh   # policy loops (trace/bp_stats)
wsl bash tests/integration/run_io_smoke.sh        # inferior stdio over a pty
bash tests/integration/run_tls_smoke.sh           # HTTP / TLS / mTLS / bearer tokens
python tests/integration/run_observer_smoke.py    # observer role over live HTTP

# acceptance benchmark (576 versioned tasks; bench/SPEC.md is the outline)
python -m bench.framework.cli selfcheck --distro kali-linux  # reference-solve + grade
python -m bench.framework.cli stress --distro kali-linux     # call volume + churn
python -m bench.framework.cli faults --distro kali-linux     # fault injection + recovery
python -m bench.framework.cli perf --distro kali-linux       # overhead / startup / concurrency
python -m bench.framework.cli pwndbg --distro kali-linux     # pwndbg compatibility probes

Roadmap

Development status, benchmark results, and the long-term vision live in ROADMAP.md and ROADMAP_V2.md. 中文文档见 README.zh-CN.md。

Contributing

Issues and PRs welcome — the test suite (902 tests, no gdb required for unit runs) is the contract: please add tests for behavior changes and keep ruff check clean.

License

MIT © gdb-mcp contributors

Available Tools

27 tools
continue_executionA

Resume the inferior: continue / step / next / stepi / nexti / finish / until. Returns immediately; use wait_for_stop to wait for the next stop event, or rely on the async stop notification.

Inputs: mode, session_id, until_addr.

crash_reportA

One-call crash triage: signal, fault address, PC, registers, backtrace, disassembly around PC, memory at PC/SP/fault address and the head of the memory map. Use after wait_for_stop (or after a stop notification). Best-effort: unreadable pieces are reported in warnings instead of failing the whole call.

Inputs: max_frames, session_id.

disassembleA

Disassemble count instructions at start (address, gdb expression, function name — or the current PC when omitted).

Inputs: count, start, session_id.

evaluateA

Evaluate a gdb expression against the live inferior (PIE-aware): 'main', '&puts@got', '$rax+8', '*(char**)0x404000'.

Inputs: expression (required), session_id.

execute_commandA

Execute a raw gdb command and return its output. Use for pwndbg-specific commands (vmmap, heap, got, checksec, ropgadget, search, ...) or any other gdb CLI command. Works while the inferior is running (queued until the next stop).

Inputs: command (required), keep_ansi, session_id.

get_backtraceC

Stack backtrace: pc, function name, source file/line per frame.

Inputs: max_frames, session_id.

get_memory_mapA

Memory mappings of the inferior (info proc mappings — works without pwndbg). For richer output use execute_command('vmmap').

Inputs: session_id.

get_process_outputA

Tail the stdout/stderr log of a launched session (gdb or script). Requires the session to have been started by launch_gdb / launch_script.

Inputs: session_id, tail_lines.

get_stop_reasonB

The reason the inferior last stopped (signal, fault address, breakpoint info).

Inputs: session_id.

interruptA

Interrupt the running inferior (equivalent to Ctrl-C in gdb). The inferior stops and a stop notification is emitted.

Inputs: session_id.

kill_sessionA

End a session. For gdb, the default detaches the plugin and leaves gdb running; force=True also terminates gdb. Script sessions are terminated gracefully by default or killed with force=True.

Inputs: force, session_id.

launch_gdbA

Launch gdb with the MCP plugin loaded inside WSL2 (background process, log captured to a file). program may be a Windows or WSL path; the session registers itself when the plugin connects. With run=True, the inferior is started immediately (equivalent to gdb -ex run).

Inputs: cwd, env, run, args, +4 more.

launch_scriptA

Launch a Python (typically pwntools) script inside WSL2. script must be an absolute Windows or WSL file path; inline code is not supported. If the script starts gdb with the MCP plugin loaded (via gdb_args/gdbscript), the new gdb session id is returned once it registers. A script that exits without gdb returns immediately with its state, return code, and log tail.

Inputs: script (required), cwd, env, args, +3 more.

list_breakpointsB

List all breakpoints/watchpoints.

Inputs: session_id.

list_sessionsA

List all known sessions (gdb plugin connections and launched processes) with their state.

Inputs: no named parameters.

list_threadsA

List inferior threads and which one is selected.

Inputs: session_id.

load_targetA

Load a program (file <path>) or core dump (core-file <path>) into the gdb session. For gdb sessions started without an inferior.

Inputs: path (required), core, session_id.

manage_breakpointA

Delete / enable / disable a breakpoint by number.

Inputs: action (required), number (required), session_id.

quit_gdbA

Detach the MCP plugin from gdb. With kill_gdb=True, also quit gdb itself (and with it the debugged process). Default leaves the externally launched gdb running.

Inputs: kill_gdb, session_id.

read_memoryB

Read raw memory from the inferior. address may be an int, a hex string ('0x401000'), or a gdb expression ('main+0x10', '&puts@got'). Returns hex, printable-ascii, and unreadable ranges.

Inputs: address (required), length, session_id.

read_registersA

Read register values (all general-purpose registers by default, or the named subset).

Inputs: names, session_id.

select_frameA

Select a stack frame by level (0 = innermost) for subsequent register/memory/local inspection.

Inputs: level (required), session_id.

session_statusC

Detailed status of one gdb session: state, inferior info, last stop reason.

Inputs: session_id.

set_breakpointC

Set a breakpoint at an address/symbol/expression ('main', '*main+0x20', '0x401000'). Types: breakpoint (software), hw (hardware), watch, hw_watch.

Inputs: location (required), type, thread, pending, +3 more.

wait_for_stopA

Wait until the inferior stops (signal, breakpoint, exit) or the timeout elapses. Returns immediately when the inferior is already stopped.

Inputs: session_id, timeout_ms.

write_memoryB

Write raw bytes (given as a hex string, e.g. '9090c3' or '90 90 c3') to the inferior's memory.

Inputs: hex (required), address (required), session_id.

write_registerC

Write a register. value is a gdb expression (e.g. '0x401000', '$rax+8', 'main').

Inputs: name (required), value (required), session_id.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    B3.4/5.0

    Scored across 27 tools

    Disambiguation4/5

    Most tools target distinct gdb actions such as memory, registers, breakpoints, and execution control. The main ambiguity is between quit_gdb and kill_session, which overlap in detaching/terminating sessions, but descriptions are detailed enough to guide selection in most cases.

    Naming Consistency4/5

    The set mostly follows verb_noun conventions: list_*, get_*, read_*, write_*, set_breakpoint, launch_*. Minor inconsistencies exist, such as session_status and crash_report using noun phrases instead of get_* and interrupt/continue_execution/wait_for_stop using different patterns, but the overall style remains readable and predictable.

    Tool Count3/5

    At 27 tools, the set is above the typical well-scoped range and feels heavy, though gdb is a broad debugging domain and most tools cover a concrete operation. The count could be reduced by merging quit_gdb into kill_session and avoiding the catch-all nature of execute_command.

    Completeness4/5

    The core debugging lifecycle is well covered: launching/loading targets, breakpoints, execution control, memory and register inspection, threads/frames, and crash triage. Minor gaps such as setting breakpoint conditions or modifying variables directly can be worked around using execute_command or evaluate.

    Maintenance

    ActivitySlowing
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      B
      quality
      D
      maintenance
      Enables AI assistants to control GDB debugger via MCP protocol for local and remote debugging, supporting CTF Pwn, crash analysis, and ELF inspection.
      13
      1
      MIT
    • A
      license
      B
      quality
      C
      maintenance
      MCP server wrapping GDB and GEF for dynamic analysis, enabling interactive debugging and memory inspection via GDB/MI protocol.
      14
      1
      MIT
    • A
      license
      B
      quality
      D
      maintenance
      MCP server that wraps gdb to enable LLMs to drive live debugging sessions, including starting sessions on binaries, attaching to processes, and running commands.
      7
      1,938 PyPI
      4
      MIT