# CLAUDE.md Guidance for Claude Code when working in this repository. ## Purpose This repo provides a reproducible, Docker-managed reverse-engineering workstation on Linux, built around **Claude Desktop** with two MCP integrations: 1. **Reverse Engineer Anything MCP**: general-purpose RE tooling exposed to Claude over MCP. 2. **Ghidra + GhidraMCP**: Ghidra with the GhidraMCP plugin, so Claude can query and annotate an open program (functions, decompilation, xrefs, renames, comments). The goal is that `docker compose up` gives you a working setup where Claude Desktop can drive both toolsets against binaries in a shared workspace, without installing Ghidra, a JDK or RE tooling on the host. ## Status Early stage. What exists: a single image (`Dockerfile`, `launch-apps.sh`) with Claude Desktop, Ghidra and GhidraMCP, started by `run.sh`; Claude Desktop's MCP config is `claude-desktop/claude_desktop_config.json`; Ghidra config files are in `ghidra/`. No compose setup yet. The layout below is the **intended** structure. Update this file when the real structure differs. ## Intended layout ``` . ├── CLAUDE.md ├── README.md # user-facing setup and usage ├── docker-compose.yml # orchestrates all services ├── .env.example # versions, ports, UID/GID, display settings ├── claude-desktop/ │ ├── Dockerfile # Claude Desktop (Linux build) + GUI deps │ └── claude_desktop_config.json # MCP server definitions (template) ├── ghidra/ │ ├── Dockerfile # JDK + Ghidra + GhidraMCP plugin │ └── scripts/ # plugin install / headless helpers ├── re-mcp/ │ └── Dockerfile # Reverse Engineer Anything MCP server ├── scripts/ # host helpers (xhost setup, start/stop, health checks) └── workspace/ # shared, git-ignored: binaries + Ghidra projects ``` ## Architecture - **Claude Desktop and Ghidra share one container** (the root `Dockerfile`, started by `run.sh`), at the user's request. Ghidra is the official GitHub release (version, build date and SHA-256 are build args), is pinned to **12.1.4** because that's what the GhidraMCP release is built for (Ghidra only loads extensions built for its exact version), runs on Ubuntu's `openjdk-21-jdk`, lives in `/opt/ghidra` and starts together with Claude Desktop. The **Developer** plugin package is enabled in both the project window and the CodeBrowser. A bare `` only adds the package's RELEASED plugins, so the STABLE ones are listed with ``. CodeBrowser: the build inserts `ghidra/codebrowser-developer.xml` into `defaultTools/CodeBrowser.tool` inside `Public_Release.jar`. Project window: it has no default to patch, so `ghidra/FrontEndTool.xml` is copied into the user settings, along with `ghidra/preferences` (`USER_AGREEMENT=ACCEPT`, because a pre-created settings dir otherwise makes Ghidra ask for its user agreement). To check a config really loaded, close Ghidra cleanly and see whether the plugins survive in the file it rewrites; Ghidra drops what it didn't load. - **Shared workspace volume.** Every container mounts the workspace at `/workspace`, so a file path means the same thing to Claude, Ghidra and the RE MCP. `run.sh` asks for the host folder on each start in the desktop's folder picker (`zenity`, or `kdialog` on KDE; terminal prompt if neither exists), opening at the last folder used, else `./workspace`. Skip it with `--workspace DIR` or `WORKSPACE=DIR`. It refuses `/` and `$HOME`. The image symlinks `~/workspace` to `/workspace` for Claude Desktop's file picker. - **GUI forwarding.** Claude Desktop and Ghidra are GUI apps. Default to X11 forwarding (`/tmp/.X11-unix` + `DISPLAY`). Support Wayland through XWayland. Keep a noVNC/VNC fallback in mind for headless hosts. Never solve display access with a blanket `xhost +`. Scope it (`xhost +local:docker` or `+SI:localuser:...`). - **GhidraMCP wiring.** LaurieWired's GhidraMCP (https://github.com/LaurieWired/GhidraMCP), release 2.0, installed from the official release zip (SHA-256 checked). It has two parts: - a Ghidra extension, unpacked into `/opt/ghidra/Ghidra/Extensions/GhidraMCP`. Its `GhidraMCPPlugin` is a RELEASED plugin in the Developer package, so the CodeBrowser config loads it. While a CodeBrowser is open it serves an HTTP backend on `127.0.0.1:8080` (port: *Edit → Tool Options → GhidraMCP HTTP Server*). - the `ghidra-mcp` Python MCP server (2.0 replaced `bridge_mcp_ghidra.py`), installed from the release wheel into the venv `/opt/ghidra-mcp`. Its dependencies are pinned to GhidraMCP's `uv.lock` at the release commit via `ghidra/uvlock-to-constraints.py`. CLI: `ghidra-mcp --ghidra-server http://127.0.0.1:8080/` (stdio by default; also `--transport streamable-http`, `--headless`). A program must be open in the CodeBrowser for the tools to return data. Claude Desktop only starts MCP servers after sign-in. - **MCP transport.** Claude Desktop starts local MCP servers as stdio subprocesses. GhidraMCP runs in the same container, so `ghidra-mcp` is a plain stdio entry in `claude_desktop_config.json` that reaches Ghidra on `127.0.0.1`. For future servers in other containers, pick one approach and apply it consistently: - *Preferred:* run them with an HTTP/SSE transport in their own containers and bridge them into Claude Desktop's stdio config with a small proxy (e.g. `mcp-remote` or `mcp-proxy`) installed in the Claude Desktop image. - *Alternative:* install the client side inside the Claude Desktop image and point it at the other container over the network. - Avoid mounting the Docker socket into the Claude Desktop container just to `docker exec` MCP servers. ## Conventions - **Pin versions.** Ghidra version, GhidraMCP release, JDK version, Claude Desktop build and RE MCP commit go in `.env` / build args, not `latest`. The GhidraMCP release must match the Ghidra version it was built for. - **Run as non-root** inside containers. Map the host UID/GID (via `.env`) so files in `workspace/` stay owned by the user. - **Persist state in named volumes or `workspace/`**: Ghidra user settings and projects. Rebuilding an image must not lose analysis. - **Claude Desktop sign-in is not persisted.** No keyring is installed and `~/.config/Claude` is not mounted, so the user logs in on every start. Don't add a keyring or config volume back without being asked. - **No secrets in the repo.** Credentials, session data and `workspace/` contents are git-ignored. Ship `.env.example`, never `.env`. - **Untrusted binaries.** Samples under analysis may be malicious. Never execute them on the host or in the Claude Desktop container. Containers that might run samples (dynamic analysis) should have no host mounts beyond `workspace/` and should allow network isolation (`network_mode: none` or an internal-only network). - **Linux only.** Target recent Docker Engine + Compose v2 (`docker compose`, not `docker-compose`). Make the setup work under both Docker and rootless Podman where practical. On SELinux hosts such as Fedora, bind mounts need `:z`/`:Z`. ## Common commands These are expected once the compose setup exists. Keep this list in sync with reality. ```bash cp .env.example .env # then adjust UID/GID, versions, DISPLAY xhost +local:docker # allow containers to use the X server docker compose build docker compose up -d docker compose logs -f docker compose down ``` ## Things to verify, not assume - **Claude Desktop on Linux.** Check whether an official Linux build is available at the time of work. If not, use a maintained community repackaging and document which one and why. Confirm the config path, usually `~/.config/Claude/claude_desktop_config.json`. - **Reverse Engineer Anything MCP.** Confirm the upstream repository, install method, runtime (Python/Node), required external tools and supported transports before writing its Dockerfile. Record the source URL in the README. - **GhidraMCP.** Before bumping GhidraMCP or Ghidra, confirm the release's supported Ghidra version (`version=` in the extension's `extension.properties`; the build checks it), the `ghidra-mcp` CLI flags and its default ports from the upstream README. The Developer plugin lists in `ghidra/` were checked against 12.1.4 and 12.2; re-check them for other versions. ## When making changes - After changing a Dockerfile or compose file, run `docker compose config` to validate it, then build the affected service. - When adding an MCP server, update `claude-desktop/claude_desktop_config.json`, `docker-compose.yml`, `README.md` and the Architecture section above together.