gdb-mcp
This MCP server gives an agent live control over GDB sessions for binary exploitation, crash triage, and pwntools workflows.
Session management — list/status sessions, launch gdb or pwntools scripts, kill/quit sessions, tail process output.
Execution control — run raw gdb commands, continue/step/next/finish, interrupt, wait for stops, get stop reasons.
Memory & registers — read/write memory, read/write registers.
Inspection — backtrace, disassemble, evaluate gdb expressions, list threads, select frames, get memory map, load programs/core dumps.
Breakpoints — set (sw/hw/watch/conditional/temporary), list, and manage breakpoints.
Crash triage — one-call
crash_reportwith signal, fault address, registers, backtrace, disassembly, and memory snapshots.
Launches and manages GDB debugging sessions inside ephemeral Docker containers, using a provided SYS_PTRACE image recipe with relaxed seccomp, and connects the in-container plugin back to the server.
Provides experimental kernel debugging integration with QEMU/gdbstub, enabling GDB-based inspection and control of kernel targets via QEMU.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@gdb-mcp checksec for ./vuln"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
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.
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 underbench/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 recommended3. 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 |
|
Execution |
|
Crash triage |
|
State |
|
Breakpoints |
|
Pwn workflow |
|
Static bridge (Ghidra) |
|
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
truncatedflags, 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_policyruns 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 |
| WSL2 distro | mirrored networking recommended |
| local Linux | plain |
| ephemeral container |
|
| 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.
--readonlydrops 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/soresolve 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-logto 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 withpython -m gdb_mcp.audit <log> [--token …].Journals, session state and results are written
0600; persisted state is re-validated on load (journals andsessions.jsoncarry 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 probesRoadmap
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 toolscontinue_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
Scored across 27 tools
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.
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.
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.
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
Related MCP Connectors
Self-hosted MCP server: 26 deterministic dev, security, and EVM tools.
Security scanner for MCP servers. Detect vulnerabilities, prompt injection, and tool poisoning.
MCP server for Pentest-Tools.com: run scans, manage findings and reports via your preffered LLM.
MCP server for progressive tool usage at any scale (see https://klavis.ai)
Related MCP Servers
- AlicenseCqualityDmaintenanceAn MCP server that exposes pwndbg commands running under LLDB as tools for AI assistants. This enables AI-driven binary analysis, exploit development, and reverse engineering through pwndbg's enhanced debugging capabilities.1001MIT
- AlicenseBqualityDmaintenanceEnables AI assistants to control GDB debugger via MCP protocol for local and remote debugging, supporting CTF Pwn, crash analysis, and ELF inspection.131MIT
- AlicenseBqualityCmaintenanceMCP server wrapping GDB and GEF for dynamic analysis, enabling interactive debugging and memory inspection via GDB/MI protocol.141MIT
- AlicenseBqualityDmaintenanceMCP server that wraps gdb to enable LLMs to drive live debugging sessions, including starting sessions on binaries, attaching to processes, and running commands.71,938 PyPI4MIT