Ryan Malloy c93abaf86c feat: Complete Sprint 3+4 — CRUD operations, bookmarks, enums, typedefs
Sprint 3 (Symbol & Variable CRUD):
- Add symbols_create, symbols_rename, symbols_delete MCP tools
- Add variables_rename MCP tool with optional type change
- Implement corresponding Jython HTTP handlers in headless server

Sprint 4 (Bookmarks & Data Types):
- Add BookmarksMixin (bookmarks_list, bookmarks_create, bookmarks_delete)
- Add DataTypesMixin (enums_list, enums_create, typedefs_list, typedefs_create)
- Register both mixins in server.py, add resource caps in config.py

Fixes:
- Use resolve_data_type() for typedef creation and variable retyping
  (was missing builtin types like int, char, void)
- Fix docker_auto_start reusing containers with wrong binary loaded
  (now compares requested binary name against running instance)

Headless server (GhydraMCPServer.py): +14 routes, 58 total
MCP tools: 75 registered
Tested: 24/24 endpoint tests passing
2026-01-31 15:16:39 -07:00
..

GhydraMCP Docker Setup

This directory contains Docker configuration for running GhydraMCP in headless mode.

Quick Start

# 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 for the complete API specification.

Container Modes

Headless Mode (Default)

Imports a binary, analyzes it, and starts the HTTP API server:

docker run -p 8192:8192 \
  -v ./samples:/binaries \
  ghydramcp /binaries/sample.exe

Server Mode

Opens an existing project and program:

docker run -p 8192:8192 \
  -e GHYDRA_MODE=server \
  -v ./projects:/projects \
  ghydramcp program_name

Analyze Mode

Imports and analyzes without starting HTTP server:

docker run \
  -e GHYDRA_MODE=analyze \
  -v ./samples:/binaries \
  -v ./projects:/projects \
  ghydramcp /binaries/sample.exe

Shell Mode

Interactive debugging:

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:

# 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:

# 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

# 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:

docker logs -f ghydramcp-server

Port already in use

Stop existing containers:

docker stop $(docker ps -q --filter "name=ghydramcp")

Memory issues with large binaries

Increase JVM heap:

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:

sudo chown -R 1001:1001 /path/to/binaries