mcghidra/docker/README.md
Ryan Malloy 4c112a2421 feat(headless): Expand Python server to full API parity
Rewrite GhydraMCPServer.py from 348 to 2138 lines, implementing all 45
routes that the MCP client expects. Previously, most endpoints returned
{"error": "Not found"}, breaking tools like data_list, xrefs_list, and
memory_read.

Key changes:
- Regex-based routing table with method-aware dispatch
- Thread-safe Ghidra transactions via threading.Lock()
- Full read endpoints: functions, data, strings, memory, xrefs, structs
- Full write endpoints: rename, comment, signature, create function/data
- Analysis endpoints: callgraph traversal, dataflow, run analysis
- Jython/Python 2 compatible (no f-strings, type hints, or walrus ops)

Tested with Docker build and curl against all major endpoint groups.
MCP client integration verified working.
2026-01-27 16:23:27 -07:00

198 lines
5.1 KiB
Markdown

# GhydraMCP Docker Setup
This directory contains Docker configuration for running GhydraMCP in headless mode.
## Quick Start
```bash
# Build the image
docker build -t ghydramcp:latest -f docker/Dockerfile .
# Analyze a binary
docker run -p 8192:8192 -v /path/to/binaries:/binaries ghydramcp /binaries/sample.exe
# Check API health
curl http://localhost:8192/
```
## Architecture
The Docker container includes:
1. **Ghidra 11.4.2** - Full headless installation
2. **GhydraMCP Extension** - The Java plugin (installed in Extensions/)
3. **GhydraMCPServer.py** - Headless HTTP server (Jython, full API parity)
### Why Two HTTP Servers?
The GhydraMCP plugin (`GhydraMCPPlugin.java`) is a full Ghidra GUI plugin that requires:
- Ghidra's `PluginTool` framework
- `ProgramManager` service for program access
- GUI event handling
These GUI services don't exist in headless mode. Instead, the container uses `GhydraMCPServer.py`, a Jython script that:
- Runs via `analyzeHeadless -postScript`
- Has direct access to `currentProgram` from the script context
- Provides **full API parity** with the GUI plugin (45 routes)
- Supports all read and write operations
### Available Endpoints (Headless Mode)
The headless server implements the complete GhydraMCP HTTP API:
| Category | Endpoints | Description |
|----------|-----------|-------------|
| **Info** | `GET /`, `/info`, `/program` | API info, program metadata |
| **Functions** | `GET /functions`, `/functions/{addr}`, `/functions/by-name/{name}` | List and detail |
| **Decompile** | `GET /functions/{addr}/decompile`, `/functions/by-name/{name}/decompile` | C pseudocode |
| **Disassembly** | `GET /functions/{addr}/disassembly`, `/functions/by-name/{name}/disassembly` | Assembly listing |
| **Data** | `GET /data`, `/strings` | Defined data and strings |
| **Memory** | `GET /memory`, `/memory/blocks` | Read bytes, list segments |
| **Xrefs** | `GET /xrefs` | Cross-references (to/from) |
| **Structs** | `GET /structs` | Data type structures |
| **Symbols** | `GET /symbols`, `/imports`, `/exports` | Symbol tables |
| **Analysis** | `GET /analysis/callgraph`, `/analysis/dataflow` | Static analysis |
| **Write Ops** | `PATCH /functions/*`, `POST /data`, `POST /structs/*` | Rename, annotate, create |
See [GHIDRA_HTTP_API.md](../GHIDRA_HTTP_API.md) for the complete API specification.
## Container Modes
### Headless Mode (Default)
Imports a binary, analyzes it, and starts the HTTP API server:
```bash
docker run -p 8192:8192 \
-v ./samples:/binaries \
ghydramcp /binaries/sample.exe
```
### Server Mode
Opens an existing project and program:
```bash
docker run -p 8192:8192 \
-e GHYDRA_MODE=server \
-v ./projects:/projects \
ghydramcp program_name
```
### Analyze Mode
Imports and analyzes without starting HTTP server:
```bash
docker run \
-e GHYDRA_MODE=analyze \
-v ./samples:/binaries \
-v ./projects:/projects \
ghydramcp /binaries/sample.exe
```
### Shell Mode
Interactive debugging:
```bash
docker run -it \
-e GHYDRA_MODE=shell \
ghydramcp
```
## Environment Variables
| Variable | Default | Description |
|----------|---------|-------------|
| `GHYDRA_MODE` | `headless` | Container mode (headless, server, analyze, shell) |
| `GHYDRA_PORT` | `8192` | HTTP API port |
| `GHYDRA_MAXMEM` | `2G` | JVM heap memory |
| `PROJECT_DIR` | `/projects` | Ghidra project directory |
| `PROJECT_NAME` | `GhydraMCP` | Ghidra project name |
## Docker Compose
Use docker-compose for easier management:
```bash
# Development mode (hot-reload scripts)
docker compose --profile dev up ghydramcp-dev
# Production mode
docker compose --profile prod up ghydramcp
# Interactive shell
docker compose --profile debug run --rm ghydramcp-shell
```
## MCP Integration
The GhydraMCP Python server includes Docker management tools:
```python
# Check Docker status
await docker_status()
# Start container for a binary
await docker_start(binary_path="/path/to/binary.exe", port=8192)
# Wait for container to be ready
await docker_wait(port=8192, timeout=300)
# Automatic mode - starts container if no Ghidra available
await docker_auto_start(binary_path="/path/to/binary.exe")
# Get container logs
await docker_logs("ghydramcp-server")
# Stop container
await docker_stop("ghydramcp-server")
```
## Building
```bash
# Using Make
make build
# Using Docker directly
docker build -t ghydramcp:latest -f docker/Dockerfile .
# Build with specific Ghidra version
docker build -t ghydramcp:latest \
--build-arg GHIDRA_VERSION=11.4.2 \
--build-arg GHIDRA_DATE=20250826 \
-f docker/Dockerfile .
```
## Troubleshooting
### Container starts but API doesn't respond
Analysis takes time. Monitor progress with:
```bash
docker logs -f ghydramcp-server
```
### Port already in use
Stop existing containers:
```bash
docker stop $(docker ps -q --filter "name=ghydramcp")
```
### Memory issues with large binaries
Increase JVM heap:
```bash
docker run -e GHYDRA_MAXMEM=4G -p 8192:8192 ghydramcp /binaries/large.exe
```
### Permission denied on volumes
The container runs as user `ghidra` (UID 1001). Ensure volume permissions:
```bash
sudo chown -R 1001:1001 /path/to/binaries
```