Skip to main content

Conduit

MIT license Node.js 20+ MCP protocol Debugger engines

Conduit is an MCP debugger. One server connects Cursor, Claude, Cline, and any other MCP client to radare2, x64dbg, cdb, and Frida for disassembly, control-flow graphs, cross-references, strings, and live debugging.

Debugger coverage rises from 4 percent before Conduit to 100 percent with Conduit, a gain of 96 points

The bars score 12 debugger jobs. Before means a coding agent with a shell and no debugger tool: it can scrape strings or a hex dump, and it can narrate assembly only if someone pastes it. With Conduit means the same job returns from an MCP tool (disassemble, get_cfg, xrefs, debug_*, explain). Average coverage moves from 4% to 100% (+96 points). That is tool coverage, not a model-IQ benchmark. Strings, hex dump, and assembly reading stay above zero before Conduit because a shell or a pasted listing can still produce a partial answer.

Static analysis and live debugging share one tool surface. session_open picks the engine. Nothing is stubbed: a tool the engine does not implement returns capability_unsupported.

Protocol MCP 2026-07-28, plus 2025-era clients
Transports stdio, Streamable HTTP (POST /mcp, GET /health)
Static engine radare2 — disassembly, CFG, xrefs, strings, hexdump
Debug engines x64dbg, cdb (WinDbg), Frida
Clients Cursor, Claude Desktop, Cline, OpenCode

Install

Node.js 20 or newer must already be on PATH. Then:

pip install conduit-debugger

That puts the conduit command on PATH. The first launch installs the Node dependencies into your home directory. conduit, conduit-mcp, and conduit-cli are already taken on PyPI, so the package name is conduit-debugger.

From a checkout, the same package installs with pip install .

Prerequisites

Clean-machine install, in order:

  1. Node.js ≥ 20 — node --version
  2. radare2 — a prebuilt release, no compilation. Any 6.x works (goldens were captured with 6.2.2; the comparator tolerates formatting drift between r2 versions). Must be on PATH as radare2 or r2: r2 -v. Override the path with DBG_BRIDGE_R2.
  3. Graphviz — dot on PATH: dot -V.
  4. Python 3 — only to regenerate or verify the example fixture: python --version.

prerequisites reports these programs plus x64dbg, cdb, Frida, and ScyllaHide. A missing program includes indir (a URL) and nereye (where to put it). Conduit does not download it. The same hint is appended to engine_unavailable when a session tries to start a missing engine.

explain reads an assembly window: what the region does, where it jumps, and which calls are notifications (MessageBox, printf, and the like). Pass instructions already read, or a session_id. Reading a live debug session still needs confirm:true.

Run

node dist/server.js                                     # stdio (default)
node dist/server.js --transport http --port 3847        # Streamable HTTP

HTTP prints conduit streamable-http 2026-07-28 http://127.0.0.1:3847/mcp and serves POST /mcp plus GET /health. --host, --port, and --transport flags exist; DBG_BRIDGE_HOST, DBG_BRIDGE_PORT, and DBG_BRIDGE_TRANSPORT do the same.

Optional token: set DBG_BRIDGE_TOKEN and every HTTP route (including /health) requires Authorization: Bearer <token> (anything else gets 401 {error:"unauthorized"}). When unset, localhost stays open. The token is env-only (a flag would leak via the process list) and is compared in constant time. stdio needs no token: spawning the process locally is the authentication there.

Connect a client

Ready-made configs live in configs/ (stdio and HTTP variants for Cursor, Claude Desktop, Cline, and OpenCode). Replace <DBG_BRIDGE_DIR> with the absolute path of this folder and follow configs/README.md, then restart the client.

Quick check inside the client: call health. Expect status: ok and name: conduit.

Client compatibility: the server speaks 2026-07-28 and also accepts 2025-era clients (for example opencode 1.x negotiating 2025-11-25) through the SDK's legacy fallback. Verified end-to-end with real opencode and cursor-agent runs (health → session_open → open_target → disassemble).

End-to-end check

Fixture: examples/target/mini_branch.elf — a hand-packed 64-bit ELF (1536 bytes, no compiler needed) whose entry 0x400200 runs a branching function (lea + cmp/je if/else). .rodata holds HELLO-FIXTURE and mini-branch. Sources: mini_branch.c, mini_branch.asm, gen_mini_branch.py.

  1. session_open {"engine": "radare2"} → session_id
  2. open_target {"session_id", "path": "<abs path>/mini_branch.elf", "mode": "static"}
  3. disassemble {"session_id"} → 10 ops at entry0
  4. get_cfg {"session_id", "format": "both"} → 4-block CFG, JSON + DOT
  5. strings {"session_id"} → HELLO-FIXTURE @ 0x400300, mini-branch @ 0x40030e
  6. dump {"session_id", "address": "0x400200", "length": 34, "format": "json"}
  7. xrefs {"session_id", "address": "0x400300"} → DATA xref from 0x400200
  8. events_pull {"session_id"} → contains target.opened
  9. close_target {"session_id"} / session_close {"session_id"}

Raw-protocol note (only if you drive the server without an MCP client): every request on protocol 2026-07-28 carries the envelope _meta: {"io.modelcontextprotocol/protocolVersion": "2026-07-28", "io.modelcontextprotocol/clientCapabilities": {}}, starting with server/discover. Over HTTP, POST /mcp also requires the Mcp-Method header (and Mcp-Name for tools/call). The golden runner (tests/run_golden.mjs) shows the exact wire format. The stdio transport pins its dialect on the first request, so a bare request or a legacy initialize locks that process into legacy mode and later server/discover calls fail with Method not found.

Debug engines

The same debug_* tool names work on every engine. Config files under configs/ do not name an engine. session_open does.

x64dbg cdb frida
Launch hidden debugger, break on entry hidden cdb.exe, stops at the loader breakpoint and plants an entry breakpoint spawn stays suspended until continue
Attach / close detach leaves the target running qd on attach, q on launch detach on attach, kill on launch. Pid attach is impossible for an embedded Gadget or a phone package: debug_attach takes gadget (host:port) or usb + package
Software breakpoint yes yes capability_unsupported
Hardware execute yes yes (after the initial breakpoint) yes, slots 0–3; a fifth is no_breakpoint_slot
Hardware read/write, memory breakpoints yes hardware read/write yes; memory no capability_unsupported
Continue until the next stop or exit until the next stop or exit until the next hit or exit; the hit slot is disarmed
Pause / step yes yes capability_unsupported
Registers / call stack live live last hardware-breakpoint hit only
Live memory read / search / dump debug_memory with confirm:true same same
Disassemble / run to address debug_code with confirm:true same same; run-to arms one hardware slot and disarms it on the hit
Assemble XEDParse, no GUI capability_unsupported capability_unsupported
Thread list / context debug_thread with confirm:true same; id is the cdb index same; id is the OS thread id
Thread select / freeze yes yes capability_unsupported
Scylla / ScyllaHide debug_plugin reports files and does not open a window capability_unsupported capability_unsupported
Snapshot / rewind checkpoint of registers, threads, and one memory window same memory window restores; register commit is capability_unsupported when Frida cannot write thread context
Where X64DBG_DIR or %USERPROFILE%\Tools\x64dbg CDB_DIR or Windows Kits Debugging Tools npm dependency frida

Debug fixtures live at plugin/x64dbg/test/mini_pe_x64.exe and mini_pe_x86.exe.

Test

npm test                  # node tests/run_golden.mjs
npm run test:debug        # x64dbg launch + attach (Windows)
npm run test:cdb          # cdb launch + attach (Windows)
npm run test:frida        # Frida hardware-breakpoint loop (Windows)
npm run test:dynamic      # confirm gate, live memory/code/thread/checkpoint
npm run test:explain      # assembly reading + download hints
npm run test:concurrency  # multi-client isolation over HTTP
npm run test:auth         # optional DBG_BRIDGE_TOKEN gate over HTTP

Expected: 38 passed, 0 failed. The suite checks prerequisites, fixture determinism, golden output, Graphviz rendering, and full MCP sessions over stdio and HTTP.

To re-capture goldens after an intentional behavior change:

node tests/run_golden.mjs --update

Troubleshooting

Symptom Cause / fix
engine_unavailable r2 is not on PATH. Install a prebuilt radare2 release or set DBG_BRIDGE_R2
npm test fails at prereqs run npm run build first; install the missing tool from Prerequisites
golden mismatch after an r2 upgrade formatting drift: run --update, inspect the diff, commit if only prose changed
HTTP client cannot connect the server must be running (--transport http); the URL port must match --port
capability_unsupported on open_target only mode: "static" is supported on radare2
capability_unsupported on disassemble / get_cfg the session is not radare2
capability_unsupported on debug_step / debug_pause Frida has no single-step or thread-suspend API
confirmation_required repeat the dynamic tool call with confirm:true
no_breakpoint_slot Frida already holds four hardware execute breakpoints
engine_unavailable on debug_open with cdb set CDB_DIR to the Debugging Tools Debuggers directory
Method not found on server/discover (stdio) the dialect was pinned by the first request; restart and send the _meta envelope from request 1
401 {error:"unauthorized"} DBG_BRIDGE_TOKEN is set: send Authorization: Bearer <token>
Host rejected over HTTP set DBG_BRIDGE_EXTRA_HOSTS to the public hostname(s), comma-separated

Layout

conduit/
├── src/                 engines and MCP tools
├── dist/                build output (git-ignored)
├── examples/target/     mini_branch.elf fixture
├── plugin/x64dbg/       x64dbg bridge and debug fixtures
├── tests/               golden runner and engine acceptance
├── configs/             Cursor, Claude Desktop, Cline, OpenCode
└── README.md

License

MIT. See LICENSE. The x64dbg plugin sources are vendored from ouonet/x64dbg-mcp; see plugin/x64dbg/THIRD_PARTY_NOTICES.md.

Release files for conduit-debugger 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for conduit-debugger 0.1.0
File Size Uploaded
conduit_debugger-0.1.0.tar.gz 155.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for conduit-debugger 0.1.0
File Interpreter ABI Platform
conduit_debugger-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 322.7 kB

Release files / conduit_debugger-0.1.0.tar.gz

Download URL conduit_debugger-0.1.0.tar.gz
Size 155.9 kB
Tags Source
SHA-256 checksum
How to use checksums
4230f23b04bb4389da839418621fbb49d4812840f19133d44287aba82f67f9a5
BLAKE2b-256 checksum
How to use checksums
21443d51dfeca503eef08f460ca70b523499b8b02c1fceed59a39856c8f40056
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.10

Release files / conduit_debugger-0.1.0-py3-none-any.whl

Download URL conduit_debugger-0.1.0-py3-none-any.whl
Size 166.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c4fbb17e0528124a266c196c8ac8d294976df6821a00f433a69655fddf127454
BLAKE2b-256 checksum
How to use checksums
9478bda5aaed1569759e9c314f5defb7a30b9f37d50cb5e7d9c49db56fe7bc66
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.10

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page