Guides

Local Ghidra

Drive your own Ghidra instance (GhidraMCP plugin) with GINE instead of the bundled headless one.

By default GINE ships a headless Ghidra container (ghidra-mcp) and talks to it through a sidecar bridge. If you already run Ghidra on your machine with the ghidra-mcp extension installed, you can point GINE at that instance instead: same stack, your project, your annotations, live in your CodeBrowser.

This is a Linux-only workflow.

1. Install the plugin (once)

Follow the upstream Quickstart through installing and enabling the extension (ghidra-mcp v7.0.0, matching your Ghidra — e.g. 12.1.4). Then, in Ghidra:

  1. Open the project window (not a CodeBrowser) and enable the plugin from Tools > GhidraMCP > Server Status. The plugin runs while the project window is open.
  2. Leave the HTTP server on its defaults (loopback). GINE does not need it exposed.

You don't install the GINE bridge yourself — GINE runs it for you (step 3).

2. Lock the socket location

The plugin always also serves a Unix domain socket at:

$XDG_RUNTIME_DIR/ghidra-mcp/ghidra-<pid>.sock

GINE reaches the plugin through this socket (the plugin's TCP port is bound to 127.0.0.1 only, so containers can't use it). Launch Ghidra from a session where XDG_RUNTIME_DIR is set (on a desktop it is, e.g. /run/user/1000); otherwise the plugin falls back to /tmp/ghidra-mcp-<user>, which the GINE overlay does not mount. You can check the socket exists:

ls "${XDG_RUNTIME_DIR:-/run/user/$(id -u)}/ghidra-mcp"/*.sock

3. Start GINE against your Ghidra

make local-ghidra

This runs the normal stack with the compose.local-ghidra.yml overlay. It defaults the socket directory to ${XDG_RUNTIME_DIR:-/run/user/$(id -u)}/ghidra-mcp; override it with GHIDRA_SOCKET_DIR if yours is elsewhere:

GHIDRA_SOCKET_DIR=/run/user/1000/ghidra-mcp make local-ghidra

What the overlay changes:

  • the bundled ghidra-mcp does not run a headless Ghidra (an idle container is kept only because the bridge shares its network namespace);
  • ghidra-bridge ignores TCP and auto-discovers the plugin over the Unix socket, mounting the host socket directory read-only;
  • the orchestrator's REST client (GhidraClient) also uses the socket (GHIDRA_SOCKET_DIR).

4. Verify

docker compose exec orchestrator python -c "
import asyncio
from app.ghidra_client import GhidraClient
print(asyncio.run(GhidraClient().check_connection()))
"

Expect {'status': 'ok', 'server_kind': 'gui', 'version': '7.0.0'}. The bridge log should show Auto-connecting via UDS to <your project>.

Notes and limitations

  • One instance, one user. The agent drives your live Ghidra: renames and decompilation appear in your CodeBrowser, and the plugin's "current program" is global. Don't point a shared/multi-user GINE deployment at a single analyst's Ghidra.
  • Host PID namespace. The bridge liveness-checks the PID embedded in the socket name, so compose.local-ghidra.yml runs it with pid: host.
  • Sandbox and binary downloads are limited. GINE has no local copy of the binary (it lives on your machine), so sandbox_run_script and the .gzf/.gar download flows are not available for programs opened this way.
  • Version mismatch. Opening a program whose language/compiler spec was built by a different Ghidra version can open it read-only.
Copyright © 2026