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.
198 lines
5.1 KiB
Markdown
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
|
|
```
|