The full upstream README, mirrored here for reference. Install config, tool schemas, adoption signals, and an original overview live on the Pyghidra Lite listing page.
Token-efficient MCP server for Ghidra-based reverse engineering. Analyze ELF, Mach-O, and PE binaries with Swift, Objective-C, and Hermes support.
Bottom line: a lean, security-first Ghidra MCP. It is read-only by default — analysis tools never mutate your binaries or the server's configuration (which is frozen for the life of the process). The one tool that writes, annotate (rename / comment / prototype), is opt-in (--allow-write) and human-confirmed: every change is approved by you through an MCP elicitation prompt before it's committed, and it fails closed if your client can't ask. You get an analyst-agent that can persist its findings — under supervision — without giving up the read-only safety story.
1. Prerequisites
JDK 21+ and Ghidra 11.x are required.
Ghidra installed via Homebrew (brew install ghidra) or to /opt/ghidra or ~/ghidra is found automatically. Set GHIDRA_INSTALL_DIR only for non-standard paths.
2. Install pyghidra-lite
3. Add to Claude Code
Create .mcp.json in your project (or ~/.claude.json for global):
4. Use it
Add to ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):
uvx auto-installs pyghidra-lite from PyPI on first run. Ghidra is auto-detected; set GHIDRA_INSTALL_DIR in env if needed:
Create .mcp.json in your project (or ~/.claude.json for global):
For single-session use or debugging, run the server directly:
By default, pyghidra-lite can load binaries from any path (the MCP client handles permissions). Use --restrict-path to lock down access:
The HTTP/SSE transports are shared and apply DNS-rebinding protection (Host/Origin
validation). Binding to a non-loopback address additionally requires both
--restrict-path and a bearer token:
Clients then send Authorization: Bearer <token> on every request. Terminate TLS
at a reverse proxy for remote access.
pyghidra-lite provides 8 read-only analysis tools plus 1 opt-in write tool, all auto-detecting format (ELF/Mach-O/PE) and language (Swift/ObjC/Hermes):
| Tool | Purpose | Key Parameters |
|---|---|---|
load | Import and analyze binary | path, profile?, fresh?, bootstrap?, bootstrap_mode? |
delete | Remove binary and cancel jobs | name |
binaries | List binaries + job status | jobs?, rank_sources? |
info | Binary overview | binary, detail? (summary/full/format/sections/entropy) |
functions | List/search functions | binary, query?, type? (all/swift/objc/imports/exports) |
code | Decompile or disassemble | binary, target, what? (decompile/asm), cfg? |
xrefs | References and call graphs | binary, target, direction?, depth?, diff? |
search | Find strings, bytes, symbols | binary, query, type?, mode?, bg? |
annotate 🔒 | Rename / comment / set prototype | binary, target, action, name?/comment?/prototype? |
🔒 annotate is the only tool that writes. It is disabled unless the server is
started with --allow-write, and every change requires interactive
confirmation (MCP elicitation) before it is committed — clients that can't
confirm get a preview only. See Writing back.
All tools automatically detect:
Use the type and detail parameters to access format/language-specific features.
bootstrap_mode="named": transfer only meaningful source names (default).bootstrap_mode="all": also assign stable synthetic labels to source FUN_* functions during transfer, which is useful for large version-to-version bootstrap workflows where uniqueness matters more than semantics.By default pyghidra-lite is read-only — no tool mutates your binaries. To let
an agent persist findings (rename a function, attach a comment, fix a prototype),
start the server with --allow-write:
Then the annotate tool becomes usable:
Every call is human-confirmed: the server sends an MCP elicitation prompt
showing the exact old -> new change, and only commits if you accept. If the
server was started without --allow-write, the tool refuses; if your MCP client
doesn't support elicitation, the tool returns a preview with applied: false
and writes nothing (fail closed). Confirmed changes are written in a single
Ghidra transaction and saved to the on-disk project.
Audit journal. Because MCP elicitation ultimately trusts the client (an
autonomous "auto-approve" client can self-confirm), every write is recorded in
annotate_audit.jsonl next to the projects — and every declined or failed
attempt is logged too. Each line records old -> new, so the journal is both an
accountability trail and an undo log; a flood of entries is your signal that an
auto-agent is churning, and the server also nudges (ctx.warning) as write
volume climbs. The journal is fail-closed and hardened: a write is recorded
before it's applied (if it can't be journaled, it isn't committed), the file
is created 0o600 and opened with O_NOFOLLOW (a symlinked journal is
refused), and it rotates by size so it can't grow without bound.
| Profile | Use Case |
|---|---|
fast | Quick triage, disables 20 slow analyzers (default) |
default | Balanced, full Ghidra analysis |
deep | Thorough analysis for obfuscated code |
The server defaults to fast to stay within MCP timeout limits. Use load(fresh=True) to run deeper analysis when needed:
pyghidra-lite is designed for minimal token usage:
functions(binary, type="all") returns minimal {name, addr} pairsinfo(detail="full"), code(cfg=True), or richer type/what modes only when neededBy default, pyghidra-lite runs as a lightweight stdio proxy (~10MB) that forwards to a persistent shared HTTP backend (~500MB JVM). Multiple sessions share a single JVM instead of each spawning their own.
The proxy auto-starts the backend on first use and the backend auto-exits after 30 minutes of idle. A file lock prevents concurrent proxy starts from spawning duplicate backends.
| Command | What it does |
|---|---|
pyghidra-lite | Stdio proxy (default) -- auto-starts backend |
pyghidra-lite serve | Direct stdio server (1 JVM per session) |
pyghidra-lite serve -t streamable-http | Start persistent HTTP backend manually |
pyghidra-lite stop | Stop the shared backend |
Set PYGHIDRA_LITE_NO_AUTOSTART=1 to disable auto-start (useful with systemd).
Each binary gets its own Ghidra project, enabling:
Projects stored in ~/.local/share/pyghidra-lite/projects/.
MIT