return_all=True on large binaries (1800+ functions) produced 72K char responses that exceeded the MCP tool result limit. Instead of truncating, oversized responses now return a structured summary with sample data, available fields, and actionable instructions for narrowing the query. Three layers of filtering: - Server-side grep: Jython HTTP handlers filter during Ghidra iteration - Field projection: jq-style key selection strips unneeded fields - Token budget guard: responses exceeding 8k tokens return a summary New files: core/filtering.py (project_fields, apply_grep, estimate_and_guard) Modified: config, pagination, base mixin, all 5 domain mixins, headless server
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:
- Ghidra 11.4.2 - Full headless installation
- GhydraMCP Extension - The Java plugin (installed in Extensions/)
- 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
PluginToolframework ProgramManagerservice 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
currentProgramfrom 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