{
  "markdown": "# pyghidra-lite\n\n[![PyPI](https://img.shields.io/pypi/v/pyghidra-lite)](https://pypi.org/project/pyghidra-lite/)\n[![Python](https://img.shields.io/pypi/pyversions/pyghidra-lite)](https://pypi.org/project/pyghidra-lite/)\n[![License](https://img.shields.io/github/license/johnzfitch/pyghidra-lite)](LICENSE)\n[![MCP](https://img.shields.io/badge/MCP-2025--11--25-blue)](https://modelcontextprotocol.io)\n\n<!-- mcp-name: io.github.johnzfitch/pyghidra-lite -->\n\nToken-efficient MCP server for Ghidra-based reverse engineering. Analyze ELF, Mach-O, and PE binaries with Swift, Objective-C, and Hermes support.\n\n**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.\n\n## Quick Start\n\n**1. Prerequisites**\n\nJDK 21+ and Ghidra 11.x are required.\n\n```bash\n# macOS\nbrew install openjdk@21\nbrew install ghidra\n\n# Ubuntu/Debian\nsudo apt install openjdk-21-jdk\n# Download Ghidra from https://ghidra-sre.org\n\n# Arch Linux\nsudo pacman -S jdk21-openjdk\nyay -S ghidra\n```\n\nGhidra installed via Homebrew (`brew install ghidra`) or to `/opt/ghidra` or `~/ghidra` is found automatically. Set `GHIDRA_INSTALL_DIR` only for non-standard paths.\n\n**2. Install pyghidra-lite**\n\n```bash\npip install pyghidra-lite\n```\n\n**3. Add to Claude Code**\n\nCreate `.mcp.json` in your project (or `~/.claude.json` for global):\n\n```json\n{\n  \"mcpServers\": {\n    \"pyghidra-lite\": {\n      \"command\": \"pyghidra-lite\"\n    }\n  }\n}\n```\n\n**4. Use it**\n\n```\nYou: Analyze the binary at /path/to/binaries/app\n\nClaude: [calls load, info, code...]\n```\n\n## Installation\n\n### PyPI (recommended)\n\n```bash\npip install pyghidra-lite\n```\n\n### Arch Linux (AUR)\n\n```bash\nyay -S python-pyghidra-lite\n```\n\n### From source\n\n```bash\ngit clone https://github.com/johnzfitch/pyghidra-lite\ncd pyghidra-lite\npip install -e .\n```\n\n## MCP Configuration\n\n### Claude Desktop\n\nAdd to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\\Claude\\claude_desktop_config.json` (Windows):\n\n```json\n{\n  \"mcpServers\": {\n    \"pyghidra-lite\": {\n      \"command\": \"uvx\",\n      \"args\": [\"pyghidra-lite\"]\n    }\n  }\n}\n```\n\n`uvx` auto-installs pyghidra-lite from PyPI on first run. Ghidra is auto-detected; set `GHIDRA_INSTALL_DIR` in `env` if needed:\n\n```json\n{\n  \"mcpServers\": {\n    \"pyghidra-lite\": {\n      \"command\": \"uvx\",\n      \"args\": [\"pyghidra-lite\"],\n      \"env\": {\n        \"GHIDRA_INSTALL_DIR\": \"/path/to/ghidra\"\n      }\n    }\n  }\n}\n```\n\n### Claude Code\n\nCreate `.mcp.json` in your project (or `~/.claude.json` for global):\n\n```json\n{\n  \"mcpServers\": {\n    \"pyghidra-lite\": {\n      \"command\": \"pyghidra-lite\"\n    }\n  }\n}\n```\n\n#### Direct mode (skip proxy)\n\nFor single-session use or debugging, run the server directly:\n\n```json\n{\n  \"mcpServers\": {\n    \"pyghidra-lite\": {\n      \"command\": \"pyghidra-lite\",\n      \"args\": [\"serve\"]\n    }\n  }\n}\n```\n\n#### With explicit Ghidra path\n\n```json\n{\n  \"mcpServers\": {\n    \"pyghidra-lite\": {\n      \"command\": \"pyghidra-lite\",\n      \"args\": [\n        \"serve\",\n        \"--ghidra-dir\", \"/path/to/ghidra\"\n      ]\n    }\n  }\n}\n```\n\n#### Restrict to specific paths\n\nBy default, pyghidra-lite can load binaries from any path (the MCP client handles permissions). Use `--restrict-path` to lock down access:\n\n```json\n{\n  \"mcpServers\": {\n    \"pyghidra-lite\": {\n      \"command\": \"pyghidra-lite\",\n      \"args\": [\n        \"serve\",\n        \"--restrict-path\", \"/home/user/binaries\",\n        \"--restrict-path\", \"/opt/targets\"\n      ]\n    }\n  }\n}\n```\n\n#### Shared HTTP transport (network access)\n\nThe HTTP/SSE transports are shared and apply DNS-rebinding protection (Host/Origin\nvalidation). Binding to a non-loopback address additionally **requires** both\n`--restrict-path` and a bearer token:\n\n```bash\npyghidra-lite serve -t streamable-http --host 0.0.0.0 \\\n  --restrict-path /opt/targets \\\n  --auth-token \"$PYGHIDRA_LITE_AUTH_TOKEN\" \\\n  --allowed-host re.example.com:8000   # if fronted under another hostname\n```\n\nClients then send `Authorization: Bearer <token>` on every request. Terminate TLS\nat a reverse proxy for remote access.\n\n## Tools (9)\n\npyghidra-lite provides 8 read-only analysis tools plus 1 opt-in write tool, all\nauto-detecting format (ELF/Mach-O/PE) and language (Swift/ObjC/Hermes):\n\n| Tool | Purpose | Key Parameters |\n|------|---------|----------------|\n| `load` | Import and analyze binary | `path`, `profile?`, `fresh?`, `bootstrap?`, `bootstrap_mode?` |\n| `delete` | Remove binary and cancel jobs | `name` |\n| `binaries` | List binaries + job status | `jobs?`, `rank_sources?` |\n| `info` | Binary overview | `binary`, `detail?` (summary/full/format/sections/entropy) |\n| `functions` | List/search functions | `binary`, `query?`, `type?` (all/swift/objc/imports/exports) |\n| `code` | Decompile or disassemble | `binary`, `target`, `what?` (decompile/asm), `cfg?` |\n| `xrefs` | References and call graphs | `binary`, `target`, `direction?`, `depth?`, `diff?` |\n| `search` | Find strings, bytes, symbols | `binary`, `query`, `type?`, `mode?`, `bg?` |\n| `annotate` 🔒 | Rename / comment / set prototype | `binary`, `target`, `action`, `name?`/`comment?`/`prototype?` |\n\n🔒 `annotate` is the only tool that writes. It is disabled unless the server is\nstarted with `--allow-write`, and every change requires interactive\nconfirmation (MCP elicitation) before it is committed — clients that can't\nconfirm get a preview only. See [Writing back](#writing-back).\n\n### Examples\n\n```python\n# Import and analyze\nload(\"/path/to/binary\", profile=\"fast\")\n\n# Version-track from a prior build, including synthetic IDs for unnamed code\nload(\"/path/to/new.bin\", profile=\"deep\", bootstrap=\"old.bin\", bootstrap_mode=\"all\")\n\n# Get overview with full triage\ninfo(\"mybinary\", detail=\"full\")\n\n# List Swift functions\nfunctions(\"mybinary\", type=\"swift\")\n\n# Decompile with CFG\ncode(\"mybinary\", \"main\", cfg=True)\n\n# Search strings in background\nsearch(\"mybinary\", [\"password\", \"api_key\"], bg=True)\n\n# Get cross-references\nxrefs(\"mybinary\", \"malloc\", depth=2)\n```\n\n### Auto-Detection\n\nAll tools automatically detect:\n- **Format**: ELF, Mach-O, PE\n- **Language**: Swift, Objective-C, Hermes/React Native\n- **Runtime**: Bun, Node.js, Electron, PyInstaller\n\nUse the `type` and `detail` parameters to access format/language-specific features.\n\n### Bootstrap Modes\n\n- `bootstrap_mode=\"named\"`: transfer only meaningful source names (default).\n- `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.\n\n## Writing back\n\nBy default pyghidra-lite is **read-only** — no tool mutates your binaries. To let\nan agent persist findings (rename a function, attach a comment, fix a prototype),\nstart the server with `--allow-write`:\n\n```bash\npyghidra-lite serve --allow-write          # or PYGHIDRA_LITE_ALLOW_WRITE=1\n```\n\nThen the `annotate` tool becomes usable:\n\n```python\nannotate(\"mybinary\", target=\"FUN_00401000\", action=\"rename\", name=\"parse_header\")\nannotate(\"mybinary\", target=\"parse_header\", action=\"comment\", comment=\"validates the v2 header\")\nannotate(\"mybinary\", target=\"parse_header\", action=\"prototype\", prototype=\"int parse_header(char *buf, int len)\")\n```\n\nEvery call is **human-confirmed**: the server sends an MCP elicitation prompt\nshowing the exact `old -> new` change, and only commits if you accept. If the\nserver was started without `--allow-write`, the tool refuses; if your MCP client\ndoesn't support elicitation, the tool returns a preview with `applied: false`\nand writes nothing (fail closed). Confirmed changes are written in a single\nGhidra transaction and saved to the on-disk project.\n\n**Audit journal.** Because MCP elicitation ultimately trusts the client (an\nautonomous \"auto-approve\" client *can* self-confirm), every write is recorded in\n`annotate_audit.jsonl` next to the projects — and every declined or failed\nattempt is logged too. Each line records `old -> new`, so the journal is both an\naccountability trail and an undo log; a flood of entries is your signal that an\nauto-agent is churning, and the server also nudges (`ctx.warning`) as write\nvolume climbs. The journal is **fail-closed and hardened**: a write is recorded\n*before* it's applied (if it can't be journaled, it isn't committed), the file\nis created `0o600` and opened with `O_NOFOLLOW` (a symlinked journal is\nrefused), and it rotates by size so it can't grow without bound.\n\n## Analysis Profiles\n\n| Profile | Use Case |\n|---------|----------|\n| `fast` | Quick triage, disables 20 slow analyzers (default) |\n| `default` | Balanced, full Ghidra analysis |\n| `deep` | Thorough analysis for obfuscated code |\n\nThe server defaults to `fast` to stay within MCP timeout limits. Use `load(fresh=True)` to run deeper analysis when needed:\n\n```python\n# Default import uses fast profile\nload(\"/path/to/binary\")\n\n# Re-analyze with deep profile\nload(\"/path/to/binary\", profile=\"deep\", fresh=True)\n```\n\n## Token Efficiency\n\npyghidra-lite is designed for minimal token usage:\n\n- **Compact output by default** - `functions(binary, type=\"all\")` returns minimal `{name, addr}` pairs\n- **Opt-in detail** - use `info(detail=\"full\")`, `code(cfg=True)`, or richer `type`/`what` modes only when needed\n- **Progress reporting** - large imports report progress every 10% or 60s\n- **Truncated strings** - long strings capped at 500 chars\n\n## Architecture\n\nBy 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.\n\n```\nClaude Code session 1 ──stdio──> proxy ──┐\nClaude Code session 2 ──stdio──> proxy ──┼──HTTP──> shared backend (1 JVM)\nClaude Code session 3 ──stdio──> proxy ──┘        localhost:19101\n```\n\nThe 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.\n\n| Command | What it does |\n|---------|-------------|\n| `pyghidra-lite` | Stdio proxy (default) -- auto-starts backend |\n| `pyghidra-lite serve` | Direct stdio server (1 JVM per session) |\n| `pyghidra-lite serve -t streamable-http` | Start persistent HTTP backend manually |\n| `pyghidra-lite stop` | Stop the shared backend |\n\nSet `PYGHIDRA_LITE_NO_AUTOSTART=1` to disable auto-start (useful with systemd).\n\n## Multi-Agent Support\n\nEach binary gets its own Ghidra project, enabling:\n\n- Parallel analysis of different binaries\n- Shared results across agents\n- Persistent analysis (survives restarts)\n- Content-addressed storage (same binary = same analysis)\n\nProjects stored in `~/.local/share/pyghidra-lite/projects/`.\n\n## Links\n\n- [PyPI Package](https://pypi.org/project/pyghidra-lite/)\n- [AUR Package](https://aur.archlinux.org/packages/python-pyghidra-lite)\n- [MCP Registry](https://registry.modelcontextprotocol.io)\n- [Issue Tracker](https://github.com/johnzfitch/pyghidra-lite/issues)\n- [Contributing](CONTRIBUTING.md)\n- [Security Policy](SECURITY.md)\n- [Changelog](CHANGELOG.md)\n\n## License\n\nMIT\n",
  "bytes": 11567,
  "sha": "17bf2ebe9112ab3b9307acc28aeca3ad13e3f2fe623d8ddb1da0f705d42c4f67",
  "repo_slug": "johnzfitch/pyghidra-lite",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_johnzfitch_pyghidra_lite_0cdbf955/readme"
}