Skip to main content
ClaudeWave
getanirao avatar
getanirao

ghidra-retro-mcp

View on GitHub

A secure, headless Model Context Protocol (MCP) server for automated retro-reversing and bare-metal firmware triage. Utilizes PyGhidra for in-process P-code micro-emulation and multi-generation console ROM auto-triage (Nintendo, PlayStation, Sega) over secure stdio transport

MCP ServersOfficial Registry0 stars0 forksPythonApache-2.0Updated today
Install in Claude Code / Claude Desktop
Method: pip / Python · -e
Claude Code CLI
claude mcp add ghidra-retro-mcp -- python -m -e
claude_desktop_config.json (Claude Desktop)
{
  "mcpServers": {
    "ghidra-retro-mcp": {
      "command": "python",
      "args": ["-m", "-e"]
    }
  }
}
1. Run the command above in your terminal (Claude Code), or paste the JSON config into claude_desktop_config.json (Claude Desktop).
2. Replace any <placeholder> values with your API keys or paths.
3. Restart Claude. The MCP server and its tools appear automatically.
💡 Install first: pip install -e
Use cases

MCP Servers overview

# Ghidra Retro MCP

MCP (Model Context Protocol) server that exposes Ghidra's headless analysis capabilities to AI assistants via pyhidra.

> **GBA ROMs**: If analyzing Game Boy Advance ROMs, install [pudii/gba-ghidra-loader](https://github.com/pudii/gba-ghidra-loader) in your Ghidra installation for proper ROM header parsing, mirrored memory regions, and I/O register maps. The loader repository has pre-built `.gpa` files for Ghidra 11.x.

## Security Model

This server communicates **exclusively over standard process stdio** — there is no HTTP socket, no TCP listener, and no network interface exposed. It is inherently immune to LAN/WAN exposure, SSRF, and unauthenticated API attacks. The only way to interact with it is for an MCP client to launch it as a subprocess and communicate via stdin/stdout.

## Hardware & Retro Ecosystem Integration

`ghidra-retro-mcp` includes native out-of-the-box support for retro-reversing automation pipelines. The server container bundles pre-compiled execution dependencies for:

- **Nintendo Entertainment System (NES)** via `GhidraNes`
- **Super Nintendo Entertainment System (SNES)** via native 65816 memory maps
- **Game Boy Advance (GBA)** via `gba-ghidra-loader`
- **Nintendo DS (NDS)** via `NTRGhidra`
- **Nintendo Switch** via `ghidra-switch-loader`
- **PlayStation 1 (PSX)** via `ghidra_psx_ldr`
- **Sega Genesis / Mega Drive** via native 68000 memory maps
- **Sega Master System / Game Gear** via `Ghidra-SegaMasterSystem-Loader`
- **Sega Dreamcast** via native SuperH4 memory maps

### Zero-Input Triage — Worked Example (GBA)

The primary entry point is `triage_and_load_retro_rom`. Call it with any ROM path and the server handles the rest:

```python
# Auto-detect platform, map language, provision session
triage_and_load_retro_rom(rom_path="/data/game.gba")
# → platform: "Game Boy Advance (GBA)"
# → loader:   "GBA ROM Loader"
# → arch:     "ARM:LE:32:v4t"

# Decompile the main entry point on the same session
decompile_function(address="0x00001c2c")
# → decompiled C code for the GBA ROM entry routine

# Search for a known pattern (e.g. 32-bit ARM store-multiple)
search_bytes(pattern="09 08 00 01")
# → matching addresses labelled "gba_ram_start"
```

### Execution Chaining Flow

Instead of forcing your AI agent to spend cycles manually identifying architecture maps, register layouts, or memory segments, chain the automated ingestion pipeline:

1. Invoke `triage_and_load_retro_rom` with a target file path.
2. The server headlessly parses the binary file structure (`NES\x1a`, `NTR`, `NSO0`, `GBA`, SNES title vectors, `PS-X EXE`, `SEGA`, `TMR SEGA`, `SEGA ENTERPRISES`), binds the matching Ghidra language module (`6502:LE:16`, `ARM:LE:32:v4t`, `AARCH64:LE:64`, `65816:LE:24`, `MIPS:LE:32`, `68000:BE:32`, `Z80:16`, `SuperH4:LE:32`), loads standard address memory blocks, and links automated signature cache arrays.
3. Use the integrated `emulate_slice` or `emulate_slice_with_taint` tools to analyze localized console loops — no physical console hardware or open GDB networking ports needed.

### Triage Tool

| Tool | Description |
|---|---|
| `triage_and_load_retro_rom` | Reads raw file magic bytes to detect NES, SNES, GBA, NDS, Switch, PSX, Genesis, SMS, or Dreamcast ROMs. Provisions a correctly-language-mapped Ghidra session and auto-restores cached function signatures. Returns platform, loader, architecture tag, and mapped memory blocks. |

## Quick Start

### Local

```bash
pip install -e .
set GHIDRA_INSTALL_DIR=C:\path\to\ghidra   # Windows
ghidra-retro-mcp
```

### Docker

```bash
docker build -t ghidra-retro-mcp .
docker run -i --rm -v /path/to/binaries:/data ghidra-retro-mcp
```

The container bundles JDK 17, Ghidra 11.2, and the server — no host dependencies beyond Docker.

## Claude Desktop config

```json
{
  "mcpServers": {
    "ghidra-headless": {
      "command": "ghidra-retro-mcp",
      "args": ["--ghidra-dir", "C:\\path\\to\\ghidra"],
      "env": {}
    }
  }
}
```

## Tools

### Session management

| Tool | Description |
|---|---|
| `analyze_binary` | Import + analyze a binary, returns a `session_id`. Reuses the ID if provided, otherwise auto-generates. |
| `list_sessions` | List all active workspaces with their session IDs, binary paths, and load times. |
| `close_session` | Close a session and free its Ghidra project resources. |

Most tools accept an optional `session_id` parameter — omit it to use the most recently loaded session.

### Read / Analysis

| Tool | Description |
|---|---|
| `decompile_function` | Decompile a function by name or address. |
| `decompile_function_paginated` | Decompile with `line_start`, `line_end`, `max_tokens` (token-budget truncation), and `summarize` (strips boilerplate locals + collapsing blank lines). Prevents context-window exhaustion. |
| `get_data_types` | List all data types defined in the program. |
| `get_cross_references` | Cross-references to/from an address. |
| `get_call_graph` | Recursive call graph + callers for a function. |
| `analyze_and_decompile_entrypoints` | Composite — bulk decompile all entry points (program entry, exports, `main`, `_start`, etc.) in one call. |
| `generate_workspace_report` | Produce a Markdown summary of the active workspace — entry points, function count, custom symbols, recovered structures, renamed functions, comments. Replaces a GUI CodeBrowser window. |

### Write / Mutation

| Tool | Description |
|---|---|
| `rename_symbol` | Rename a function or label. Stored in the Ghidra project DB. |
| `add_comment` | Attach a comment (`plate`, `pre`, `post`, `eol`, `repeatable`). |
| `create_struct` | Create a custom structured data type from a JSON member layout `[{offset, name, type}, ...]`. Offsets are optional. |
| `retype_variable` | Re-type a local variable or function parameter (e.g. `undefined4*` → `MyStruct*`). |

### Assembly-level

| Tool | Description |
|---|---|
| `disassemble_range` | Disassemble N raw instructions at an address — returns mnemonic, operands, hex bytes, and length for precise lower-level inspection. |
| `get_listing_range` | Raw hex + ASCII dump for a byte range, equivalent to Ghidra's Listing panel. Complements `disassemble_range` for data regions. |

### Byte-sequence search

| Tool | Description |
|---|---|
| `search_bytes` | Search the entire binary for a hex byte pattern (e.g. `09 08 00 01` or `F86D0003`). Returns matching addresses with context bytes and any string label at the hit. |

### Binary diffing

| Tool | Description |
|---|---|
| `diff_binaries` | Compare two loaded sessions by function name and body size. Returns functions unique to each side and changed functions. |

## Workspace Sessions

Each `analyze_binary` call creates a named session. Sessions keep their Ghidra project open independently, so multiple binaries can be loaded concurrently:

```python
# Load two binaries into separate sessions
s1 = analyze_binary(binary_path="/bin/a.out")        # auto session_id
s2 = analyze_binary(binary_path="/bin/b.out", session_id="my_session")

# Operate on a specific session
decompile_function(function_name="main", session_id=s1.session_id)

# Diff them
diff_binaries(session_a=s1.session_id, session_b="my_session")
```

## Deployment

### Docker (multi-user / CI)

```bash
docker build -t ghidra-retro-mcp .

# Run as an MCP subprocess
docker run -i --rm \
  -v /data/binaries:/data \
  ghidra-retro-mcp \
  --ghidra-dir /opt/ghidra
```

The `Dockerfile` bundles Ghidra 11.2 and JDK 17 in a slim Python 3.11 image. Bind-mount your binaries directory at runtime.

### P-code micro-emulation

| Tool | Description |
|---|---|
| `emulate_slice` | Headlessly execute N instructions. Seed register state and get a step-by-step trace of register mutations. |
| `emulate_slice_with_taint` | Same as `emulate_slice` but with automated taint tracking — specify a taint register (e.g. `r0`) and the tool flags exactly when its value is modified or propagates to other registers. |
| `emulate_slice_with_breakpoints` | Execute until a condition is met or the count expires. Condition syntax: `R0==0`, `R1>0xFF`, `R2!=R3`, `PC==0x1234`. Stops before or after the matching instruction. |

All run inside the pyhidra process via Ghidra's `EmulatorHelper` — no GDB/LLDB, no network ports, no debugger stubs. Works on ARM, x86, MIPS, and any Ghidra-supported architecture.

#### Worked example — breaking on a register condition

Suppose you're reversing a GBA ROM and want to find the first time `r0` becomes zero inside a loop at `0x08000100`:

```python
# Step until r0 == 0, stop before the matching instruction
result = emulate_slice_with_breakpoints(
    session_id="gba_v1",
    start_address="0x08000100",
    max_instructions=5000,
    stop_condition="R0==0",
    stop_mode="before"
)
# result.exit_reason → "R0==0"
# result.instructions_executed → 312
# result.trace → [step 311: r0 goes 4→2, step 312: r0 goes 2→0]

# Check if a specific address was reached after a branch
result = emulate_slice_with_breakpoints(
    session_id="gba_v1",
    start_address="0x08000100",
    max_instructions=5000,
    stop_condition="PC==0x08001234"
)
# result.exit_reason → "PC==0x08001234"

# Use inequalities to catch bounds checks
result = emulate_slice_with_breakpoints(
    session_id="gba_v1",
    start_address="0x08000100",
    max_instructions=5000,
    stop_condition="R1>0xFF"
)
# result.exit_reason → "R1>0xFF"
# result.last_step["r1"] → 0x100
```

This is especially powerful for identifying copy-loop bounds (`R3 >= R4`), null-pointer paths (`R0==0`), or switch-table targets (`PC==0x`).

### Function fingerprinting / signature transfer

| Tool | Description |
|---|---|
| `calculate_function_fingerprint` | Generate a structural hash for a function (vars, params, body size, branches, called funcs, embedded strings, numeric constants). Survives compiler reordering. |
| `export_signature_map` | Build a complete `{hash → name}` map for every function in the current binary. Save this JSON to reuse across versions. |
armgbaghidramcpreverse-engineering

What people ask about ghidra-retro-mcp

What is getanirao/ghidra-retro-mcp?

+

getanirao/ghidra-retro-mcp is mcp servers for the Claude AI ecosystem. A secure, headless Model Context Protocol (MCP) server for automated retro-reversing and bare-metal firmware triage. Utilizes PyGhidra for in-process P-code micro-emulation and multi-generation console ROM auto-triage (Nintendo, PlayStation, Sega) over secure stdio transport It has 0 GitHub stars and was last updated today.

How do I install ghidra-retro-mcp?

+

You can install ghidra-retro-mcp by cloning the repository (https://github.com/getanirao/ghidra-retro-mcp) or following the README instructions on GitHub. ClaudeWave also provides quick install blocks on this page.

Is getanirao/ghidra-retro-mcp safe to use?

+

getanirao/ghidra-retro-mcp has not been audited yet by our security agent. Review the original repository on GitHub before using it in production.

Who maintains getanirao/ghidra-retro-mcp?

+

getanirao/ghidra-retro-mcp is maintained by getanirao. The last recorded GitHub activity is from today, with 0 open issues.

Are there alternatives to ghidra-retro-mcp?

+

Yes. On ClaudeWave you can browse similar mcp servers at /categories/mcp, sorted by popularity or recent activity.

Deploy ghidra-retro-mcp to your cloud

Ship this repo to production in minutes. Each platform spins up its own environment with editable env vars.

Maintain this repo? Add a badge to your README

Drop the badge into your GitHub README to show it's tracked on ClaudeWave. Each badge links back to this page and reflects the live Trust Score.

Featured on ClaudeWave: getanirao/ghidra-retro-mcp
[![Featured on ClaudeWave](https://claudewave.com/api/badge/getanirao-ghidra-retro-mcp)](https://claudewave.com/repo/getanirao-ghidra-retro-mcp)
<a href="https://claudewave.com/repo/getanirao-ghidra-retro-mcp"><img src="https://claudewave.com/api/badge/getanirao-ghidra-retro-mcp" alt="Featured on ClaudeWave: getanirao/ghidra-retro-mcp" width="320" height="64" /></a>

More MCP Servers

ghidra-retro-mcp alternatives