Ryuumonbuchi
Health Warn
- License — License: GPL-2.0
- Description — Repository has a description
- Active repo — Last push 0 days ago
- Low visibility — Only 5 GitHub stars
Code Fail
- eval() — Dynamic code execution via eval() in src/ryuumonbuchi/backend/program.py
- exec() — Shell command execution in src/ryuumonbuchi/backend/program.py
Permissions Pass
- Permissions — No dangerous permissions requested
No AI report is available for this listing yet.
Maybe the headless Ghidra MCP you are looking for.
Ryuumonbuchi
Maybe the headless Ghidra MCP you are looking for.
A 216-tool Model Context Protocol server that exposes a Ghidra reverse-engineering surface to LLM agents. Runs on Linux and Python 3.13, speaks MCP over stdio, and drives one persistent PyGhidra/JVM backend per connection.
Overview · Architecture · Prerequisites · Install · Configuration · Tool surface · Usage · Development
Overview
Ryuumonbuchi turns Ghidra into an MCP tool server. An agent connects over stdio, opens a binary, and drives analysis through typed tool calls: decompilation, disassembly, type reconstruction, patching, symbol and memory edits, and project export. No GUI automation, no hand-written analyzeHeadless scripts.
The server uses the low-level MCP SDK (mcp.server.lowlevel) with a registry generated from one authoritative catalog. The catalog declares 216 dotted tool names. 212 of them map one-to-one onto methods of a persistent backend; health.ping and mcp.response_format are server-native, headless.run is the native launcher path, and operation.batch is the batching dispatcher. The catalog does not promise coverage of every Ghidra API; it covers the surface those 212 methods implement.
Behind the stdio front end, one persistent worker child holds a live PyGhidra/JVM session for the whole MCP lifespan. Repeated calls reuse the warmed backend instead of paying JVM startup per request.
Architecture
MCP client ── stdio (JSON-RPC) ──► Ryuumonbuchi server
(low-level SDK, schema/policy dispatch)
│
│ protocol-v2, 8-byte length-prefixed socket IPC
▼
persistent worker child
(lazy PyGhidra/JVM, multiple program sessions)
│
┌──────────────────┴───────────────────┐
▼ ▼
backend (PyGhidra) headless.run ── analyzeHeadless
program sessions, (separate process group)
decompiler, analysis
Three dispatch paths:
- Worker tools (212): validated against the catalog schema, sent to the persistent child over protocol-v2 IPC, run against a live program session.
headless.run: spawnssupport/analyzeHeadlessdirectly with the caller's argv in its own process group. No shell, no rewriting of arguments.operation.batch: 1 to 32 worker tools in one call; read-only batches run without a transaction, mutating batches wrap in one undo transaction with rollback on error.
The private mode-0700 workspace owns every managed Ghidra project, worker log file, and native capture file. Oversized worker results spill to mode-0600 files under the workspace and are reloaded internally; they are not surfaced to the MCP client as a path contract.
Prerequisites
- Linux host.
- Python
>=3.13,<3.14. - Ghidra 12.0 or newer, with metadata declaring a Java minimum of 21 (
application.java.min) and Python 3.13 support (application.python.supported). Ghidra bundles its own JDK, so no separate Java install is required when it is present. - uv for the documented workflow.
Startup validates the installation before entering the MCP loop. It checks Ghidra/application.properties, Ghidra/Features/PyGhidra/lib/PyGhidra.jar, and support/analyzeHeadless, then exits with code 2 on any configuration failure.
Install
Run the published package from PyPI:
uvx ryuumonbuchi
uvx builds an isolated environment on first run and reuses it after.
To run the current main branch instead:
uvx --from git+https://github.com/elliottophellia/Ryuumonbuchi@main ryuumonbuchi
For a local checkout:
git clone https://github.com/elliottophellia/Ryuumonbuchi.git
cd ryuumonbuchi
uv sync --locked --all-groups
uv run ryuumonbuchi
Configuration
Precedence is CLI flag over environment variable over built-in default. Classpath, class-file, and VM-argument values from CLI and environment are combined rather than overridden.
| CLI flag | Environment variable | Default | Description |
|---|---|---|---|
--ghidra-install-dir PATH |
GHIDRA_INSTALL_DIR |
/usr/share/ghidra |
Ghidra installation root |
--max-heap-mb MIB |
RYUUMONBUCHI_MAX_HEAP_MB |
1024 |
Worker JVM max heap, 256 to 8192 |
--max-cpu COUNT |
RYUUMONBUCHI_MAX_CPU |
2 |
Worker CPU affinity count, 1 to os.cpu_count() |
--operation-timeout-seconds SECONDS |
RYUUMONBUCHI_OPERATION_TIMEOUT_SECONDS |
900 |
Per-operation wall-clock deadline, 30 to 86400 |
--max-import-bytes BYTES |
RYUUMONBUCHI_MAX_IMPORT_BYTES |
67108864 |
Cap on program.open_bytes payloads |
--max-response-bytes BYTES |
RYUUMONBUCHI_MAX_RESPONSE_BYTES |
4194304 |
Inline response cap before spill-to-file |
--max-log-tail-bytes BYTES |
RYUUMONBUCHI_MAX_LOG_TAIL_BYTES |
65536 |
Worker log tail returned on failure |
--classpath PATH (repeatable) |
RYUUMONBUCHI_CLASSPATH (path-separated) |
empty | Extra Java classpath entries |
--class-file PATH (repeatable) |
RYUUMONBUCHI_CLASS_FILES (path-separated) |
empty | Extra Java class files to load |
--vmarg ARG (repeatable) |
RYUUMONBUCHI_VMARGS (shlex) |
empty | Extra JVM arguments |
--allow-export |
RYUUMONBUCHI_ALLOW_EXPORT |
disabled | Enable export and save tools |
--allow-import-bytes |
RYUUMONBUCHI_ALLOW_IMPORT_BYTES |
disabled | Enable program.open_bytes |
[!IMPORTANT]
program.export_binary,program.export_packed,program.save,program.save_as, andproject.exportrequireRYUUMONBUCHI_ALLOW_EXPORT=1or--allow-export.program.open_bytesrequiresRYUUMONBUCHI_ALLOW_IMPORT_BYTES=1or--allow-import-bytes, and obeys the byte cap. Both gates default to deny.
Tool surface
All 216 tools use dotted names and take a JSON object. Backend tools generally accept a session_id (returned by program.open or program.open_bytes) and are batch-eligible. A representative slice, drawn from the catalog:
| Category | Example tools |
|---|---|
| Program & session | program.open, program.open_bytes, program.close, program.summary, program.report, program.mode.get/set, program.image_base.set, program.save, program.save_as, program.export_binary, program.export_packed |
| Analysis & tasks | analysis.update, analysis.update_and_wait, analysis.status, analysis.options.*, analysis.analyzers.*, analysis.clear_cache, task.analysis_update, task.status, task.result, task.cancel |
| Listing, decompilation, p-code | listing.disassemble.*, listing.code_units.list, listing.data.*, listing.clear, decomp.function, decomp.tokens, decomp.ast, decomp.writeback.*, pcode.function, pcode.block, pcode.op.at |
| Functions, symbols, types, layouts | function.*, symbol.*, namespace.create, class.create, type.*, layout.struct.*, layout.enum.*, layout.union.*, variable.*, parameter.* |
| References, search, graphs | reference.*, search.*, graph.basic_blocks, graph.cfg.edges, graph.call_paths |
| Memory | memory.blocks.list, memory.read, memory.write, memory.block.* |
| Comments, bookmarks, tags | comment.*, bookmark.*, tag.* |
| Transactions & patches | transaction.*, patch.assemble, patch.nop, patch.branch_invert |
| Projects & metadata | project.*, metadata.query, metadata.store |
| External, source, relocations | external.*, source.file.*, source.map.*, relocation.*, equate.* |
| Open world | ghidra.call, ghidra.eval, ghidra.script |
| Server-native | health.ping, mcp.response_format, headless.run, operation.batch |
Usage
A first-analysis sequence:
health.ping: confirm the server responds; this never starts the JVM.program.openwithpath,read_only: true,update_analysis: false. Bothread_onlyandupdate_analysisdefault totruewhen omitted, so setupdate_analysis: falsewhen analysis options must be changed first.analysis.update_and_waitto run auto-analysis to completion.function.listto enumerate recovered functions.decomp.functionon a function start address.program.close.
Function addresses and decompiler views
Function tools accept exact function entries and addresses contained within a function. An unresolved address remains an error rather than selecting a nearby function; the error reports the normalized address plus the nearest previous and next function entries.
decomp.function defaults to view: "raw", the complete Ghidra C output. Use view: "compact" only for initial triage of declaration-heavy functions:
{
"session_id": "<session_id>",
"function_start": 1053104,
"view": "compact"
}
Compact output conservatively elides Ghidra-generated local declarations, is not compilable, and reports the omission count. Return to raw C, decomp.tokens, decomp.ast, or p-code when exact structure matters.
Typed tools come first. Sessions open read-only by default; switch program.mode.set to read_only: false only before intended mutations. Use operation.batch for 1 to 32 atomic program-bound calls. Treat ghidra.call, ghidra.eval, ghidra.script, and headless.run as open-world execution. Inspect the second TextContent block for the full JSON result; the first is a compact summary. Close sessions with program.close when done.
Claude Code
Add the server under mcpServers in .mcp.json or ~/.claude.json:
{
"mcpServers": {
"ryuumonbuchi": {
"type": "stdio",
"command": "uvx",
"args": [
"ryuumonbuchi",
"--ghidra-install-dir",
"/usr/share/ghidra"
],
"env": {
"RYUUMONBUCHI_MAX_CPU": "4",
"RYUUMONBUCHI_MAX_HEAP_MB": "2048"
}
}
}
}
Codex
Add the server to ~/.codex/config.toml:
[mcp_servers.ryuumonbuchi]
command = "uvx"
args = ["ryuumonbuchi", "--ghidra-install-dir", "/usr/share/ghidra"]
[mcp_servers.ryuumonbuchi.env]
RYUUMONBUCHI_MAX_CPU = "4"
RYUUMONBUCHI_MAX_HEAP_MB = "2048"
Development
uv sync --locked --all-groups # install runtime and dev dependencies
uv run ryuumonbuchi --version # print version and exit
uv run ryuumonbuchi --help # list every CLI flag
Test tiers:
uv run pytest tests/test_mcp_client_smoke.py tests/test_worker_lifecycle.py -q
uv run pytest -m "not live and not live_server" --cov=ryuumonbuchi --cov-branch --cov-report=term-missing --cov-fail-under=100
The live matrix requires a real Ghidra install plus Java 21 and a C compiler, and is skipped by default:
RYUUMONBUCHI_REQUIRE_LIVE=1 GHIDRA_INSTALL_DIR=/usr/share/ghidra uv run pytest -m live tests/test_live_workflow.py -q
Static checks run with ruff check, ruff format --check, and strict pyright.
Reviews (0)
Sign in to leave a review.
Leave a reviewNo results found