Add docs site for mcghidra.warehack.ing
Some checks are pending
Build Ghidra Plugin / build (push) Waiting to run

Starlight/Astro docs site following the warehack.ing cookie-cutter
pattern. Landing page with architecture overview, getting-started
guide with install and firmware import examples, Docker reference
with env vars and port pool docs, and MCP tools reference.

Warm amber/rust color scheme. Caddy prod + Node dev Docker stages.
This commit is contained in:
Ryan Malloy 2026-03-06 22:35:27 -07:00
parent 0250c2df01
commit 1db36464ed
18 changed files with 4997 additions and 0 deletions

6
docs-site/.dockerignore Normal file
View File

@ -0,0 +1,6 @@
node_modules
dist
.astro
.env
.env.*
!.env.example

6
docs-site/.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
node_modules/
dist/
.astro/
.env
.env.local
.env.production

61
docs-site/Dockerfile Normal file
View File

@ -0,0 +1,61 @@
# syntax=docker/dockerfile:1
# -- Build stage --
FROM node:22-alpine AS builder
RUN corepack enable && corepack prepare pnpm@latest --activate
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN --mount=type=cache,target=/root/.local/share/pnpm/store \
pnpm install --frozen-lockfile
COPY . .
ENV ASTRO_TELEMETRY_DISABLED=1
RUN pnpm build
# -- Production stage --
FROM caddy:2-alpine AS production
COPY --from=builder /app/dist /srv
COPY <<EOF /etc/caddy/Caddyfile
:80 {
root * /srv
encode gzip
try_files {path} {path}/
file_server
header Cache-Control "public, max-age=3600"
@immutable path /_astro/*
header @immutable Cache-Control "public, max-age=31536000, immutable"
handle_errors {
rewrite * /404.html
file_server
}
}
EOF
EXPOSE 80
CMD ["caddy", "run", "--config", "/etc/caddy/Caddyfile"]
# -- Dev stage --
FROM node:22-alpine AS dev
RUN corepack enable && corepack prepare pnpm@latest --activate
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN --mount=type=cache,target=/root/.local/share/pnpm/store \
pnpm install --frozen-lockfile
COPY . .
ENV ASTRO_TELEMETRY_DISABLED=1
EXPOSE 4321
CMD ["pnpm", "dev"]

13
docs-site/Makefile Normal file
View File

@ -0,0 +1,13 @@
.PHONY: prod dev down logs
prod:
docker compose up -d --build
dev:
docker compose --profile dev up --build
down:
docker compose down
logs:
docker compose logs -f

View File

@ -0,0 +1,49 @@
// @ts-check
import { defineConfig } from 'astro/config';
import starlight from '@astrojs/starlight';
export default defineConfig({
site: 'https://mcghidra.warehack.ing',
devToolbar: { enabled: false },
integrations: [
starlight({
title: 'MCGhidra',
tagline: 'Reverse engineering bridge between Ghidra and MCP',
description: 'Multi-instance Ghidra plugin with HATEOAS REST API and MCP server for decompilation, analysis, and binary manipulation.',
social: [
{ icon: 'external', label: 'Gitea', href: 'https://git.supported.systems/MCP/mcghidra' },
{ icon: 'external', label: 'PyPI', href: 'https://pypi.org/project/mcghidra/' },
],
customCss: ['./src/styles/custom.css'],
editLink: {
baseUrl: 'https://git.supported.systems/MCP/mcghidra/_edit/main/docs-site/',
},
head: [
{
tag: 'meta',
attrs: {
name: 'theme-color',
content: '#c85533',
},
},
],
sidebar: [
{
label: 'Getting Started',
items: [
{ label: 'Overview', slug: 'getting-started/overview' },
{ label: 'Installation', slug: 'getting-started/installation' },
],
},
{
label: 'Reference',
collapsed: true,
items: [
{ label: 'Docker Usage', slug: 'reference/docker' },
{ label: 'MCP Tools', slug: 'reference/mcp-tools' },
],
},
],
}),
],
});

View File

@ -0,0 +1,38 @@
services:
docs:
build:
context: .
dockerfile: Dockerfile
target: production
restart: unless-stopped
networks:
- caddy
labels:
caddy: ${DOMAIN:-mcghidra.l.warehack.ing}
caddy.reverse_proxy: "{{upstreams 80}}"
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:80/"]
interval: 30s
timeout: 5s
retries: 3
start_period: 10s
docs-dev:
build:
context: .
dockerfile: Dockerfile
target: dev
profiles: ["dev"]
volumes:
- ./src:/app/src
- ./public:/app/public
- ./astro.config.mjs:/app/astro.config.mjs
networks:
- caddy
labels:
caddy: ${DOMAIN:-mcghidra.l.warehack.ing}
caddy.reverse_proxy: "{{upstreams 4321}}"
networks:
caddy:
external: true

24
docs-site/package.json Normal file
View File

@ -0,0 +1,24 @@
{
"name": "mcghidra-docs",
"type": "module",
"version": "0.0.1",
"scripts": {
"dev": "astro dev --host",
"start": "astro dev --host",
"build": "astro build",
"preview": "astro preview",
"astro": "astro"
},
"dependencies": {
"@astrojs/mdx": "^4.3.13",
"@astrojs/starlight": "^0.37.4",
"astro": "^5.6.1",
"sharp": "^0.34.2"
},
"pnpm": {
"onlyBuiltDependencies": [
"esbuild",
"sharp"
]
}
}

4355
docs-site/pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,2 @@
User-agent: *
Allow: /

View File

@ -0,0 +1,7 @@
import { defineCollection } from 'astro:content';
import { docsLoader } from '@astrojs/starlight/loaders';
import { docsSchema } from '@astrojs/starlight/schema';
export const collections = {
docs: defineCollection({ loader: docsLoader(), schema: docsSchema() }),
};

View File

@ -0,0 +1,81 @@
---
title: Installation
description: Installing MCGhidra from PyPI and configuring your MCP client
---
## Install from PyPI
```bash
pip install mcghidra
```
Or with [uv](https://docs.astral.sh/uv/) for isolated execution:
```bash
uvx mcghidra
```
This installs the MCP server and bundles the Ghidra plugin JAR. No separate plugin installation is needed — the server deploys the JAR automatically when starting Docker containers.
## MCP Client Configuration
Add MCGhidra to your MCP client configuration. For Claude Code:
```json
{
"mcpServers": {
"mcghidra": {
"command": "uvx",
"args": ["mcghidra"]
}
}
}
```
## Docker Setup (Optional)
If you want automatic container provisioning:
1. Clone the repository:
```bash
git clone https://git.supported.systems/MCP/mcghidra.git
cd mcghidra
```
2. Build the Docker image:
```bash
cd docker && docker build -t mcghidra:latest -f Dockerfile ..
```
Or use the MCP tool:
```
docker_build()
```
3. The `docker_auto_start` tool handles everything else — port allocation, container naming, health polling.
## Analyzing Raw Firmware
For raw binary blobs (firmware dumps, bootloaders), specify the processor architecture:
```
docker_auto_start(
binary_path="/path/to/firmware.bin",
language="ARM:LE:32:v4t",
base_address="0x00000000"
)
```
Common language IDs:
| Target | Language ID |
|--------|------------|
| ARM7TDMI (Thumb) | `ARM:LE:32:v4t` |
| ARM Cortex-M | `ARM:LE:32:Cortex` |
| ARMv7 | `ARM:LE:32:v7` |
| MIPS32 LE | `MIPS:LE:32:default` |
| MIPS32 BE | `MIPS:BE:32:default` |
| x86 32-bit | `x86:LE:32:default` |
| x86-64 | `x86:LE:64:default` |
When `language` is specified, the loader is automatically set to `BinaryLoader` (raw binary import). Override with `loader="AutoImporter"` if your file has a recognized header format.

View File

@ -0,0 +1,42 @@
---
title: Overview
description: What MCGhidra does and how the pieces fit together
---
MCGhidra is a two-part system that bridges NSA's [Ghidra](https://ghidra-sre.org/) reverse engineering framework with [Model Context Protocol](https://modelcontextprotocol.io/) (MCP) clients.
## Components
### Ghidra Plugin (Java)
A headless-compatible Ghidra script that starts an HTTP server inside the JVM. The server exposes a HATEOAS REST API — every response includes hypermedia links to related resources, so clients discover the API by following links rather than memorizing paths.
The plugin supports:
- Function listing, decompilation, and disassembly
- Memory reads and data type inspection
- Symbol renaming and annotation
- Cross-reference navigation
- Program metadata and analysis status
- Health checks for container orchestration
### MCP Server (Python)
A [FastMCP](https://github.com/jlowin/fastmcp) server that wraps the REST API as MCP tools. It adds:
- **Multi-instance management** — connect to multiple Ghidra sessions, switch between them
- **Docker provisioning** — automatic container lifecycle with port pooling
- **Raw firmware support** — specify processor language, base address, and loader for binary blobs
- **Session isolation** — each MCP client gets its own session ID, preventing cross-talk
## Typical Workflow
1. **Start Ghidra** — either via Docker (`docker_auto_start`) or by running the plugin in an existing Ghidra instance
2. **Connect** — the MCP server discovers the Ghidra instance via health checks
3. **Analyze** — use MCP tools to decompile functions, read memory, navigate references
4. **Iterate** — rename symbols, annotate findings, re-decompile to see updated output
## Requirements
- Python 3.11+
- Ghidra 11.0+ (for the plugin)
- Docker (optional, for container management)

View File

@ -0,0 +1,67 @@
---
title: MCGhidra
description: Reverse engineering bridge between Ghidra and MCP
template: splash
hero:
tagline: Multi-instance Ghidra with a REST API and MCP server for decompilation, analysis, and binary manipulation.
actions:
- text: Getting Started
link: /getting-started/overview/
icon: right-arrow
- text: View on PyPI
link: https://pypi.org/project/mcghidra/
icon: external
variant: minimal
---
import { Card, CardGrid } from '@astrojs/starlight/components';
## What is MCGhidra?
MCGhidra connects [Ghidra](https://ghidra-sre.org/) to the [Model Context Protocol](https://modelcontextprotocol.io/) (MCP), turning Ghidra's analysis engine into a set of tools that any MCP client can use. It consists of two parts: a **Ghidra plugin** that exposes a HATEOAS REST API from within Ghidra's JVM, and a **Python MCP server** that translates those endpoints into MCP tools.
The result is that an MCP client can decompile functions, read memory, rename symbols, navigate cross-references, and manage Docker-based Ghidra instances — all through standard tool calls.
<CardGrid>
<Card title="HATEOAS REST API" icon="puzzle">
The Ghidra plugin serves a discoverable API with hypermedia links. Clients navigate resources by following links rather than hardcoding endpoint paths.
</Card>
<Card title="Multi-Instance" icon="list-format">
Run multiple Ghidra sessions in parallel, each analyzing a different binary. The MCP server tracks instances and routes requests to the right one.
</Card>
<Card title="Docker Support" icon="rocket">
Automatic container provisioning with port pooling. Pass a binary path and MCGhidra handles image building, container startup, and health polling.
</Card>
<Card title="Raw Firmware" icon="setting">
Specify processor architecture, base address, and loader type for raw firmware binaries. Supports targets like ARM7TDMI, MIPS, x86, and anything Ghidra recognizes.
</Card>
</CardGrid>
## Quick Install
```bash
# Install the MCP server
pip install mcghidra
# Or use uvx for isolated execution
uvx mcghidra
```
The Ghidra plugin JAR ships inside the Python package and is automatically deployed to running Ghidra instances or Docker containers.
## Architecture
```
MCP Client (Claude, etc.)
MCGhidra MCP Server (Python, FastMCP)
Ghidra Plugin REST API (Java, runs inside Ghidra's JVM)
Ghidra Analysis Engine
```
Each layer is independently useful. The REST API works without MCP. The MCP server works without Docker. Docker support is optional for automated container management.

View File

@ -0,0 +1,87 @@
---
title: Docker Usage
description: Container management, port pooling, and firmware import options
---
MCGhidra can automatically provision Docker containers running Ghidra in headless mode. Each container gets a dedicated port from a configurable pool, and containers are tracked by session to prevent cross-talk between concurrent MCP clients.
## Quick Start
```
docker_auto_start(binary_path="/path/to/binary")
```
This checks for an existing instance analyzing the same binary, and if none is found, starts a new container with an auto-allocated port.
## Environment Variables
The Docker entrypoint accepts these environment variables:
| Variable | Default | Description |
|----------|---------|-------------|
| `MCGHIDRA_PORT` | `8192` | HTTP API port inside the container |
| `MCGHIDRA_MAXMEM` | `2G` | Max JVM heap size |
| `PROJECT_NAME` | `MCGhidra` | Ghidra project name |
| `PROJECT_DIR` | `/projects` | Project directory inside container |
| `GHIDRA_LANGUAGE` | *(auto-detect)* | Processor language ID (e.g., `ARM:LE:32:v4t`) |
| `GHIDRA_BASE_ADDRESS` | *(auto-detect)* | Base address for raw binaries (e.g., `0x00000000`) |
| `GHIDRA_LOADER` | *(auto-detect)* | Loader type (e.g., `BinaryLoader`) |
## Port Pool
Ports are allocated from a pool to prevent conflicts:
| Variable | Default | Description |
|----------|---------|-------------|
| `MCGHIDRA_PORT_START` | `8192` | First port in the pool |
| `MCGHIDRA_PORT_END` | `8319` | Last port in the pool (128 ports) |
| `MCGHIDRA_PORT_LOCK_DIR` | `/tmp/mcghidra-ports` | Lock file directory |
Port allocation uses `flock`-based locking for cross-process safety.
## Raw Firmware Import
For binaries without recognized headers (raw firmware dumps, bootloader images):
```
docker_start(
binary_path="/path/to/firmware.bin",
language="ARM:LE:32:v4t",
base_address="0x00000000"
)
```
When `language` is specified, `loader` is automatically set to `BinaryLoader`. This tells Ghidra to treat the file as raw bytes mapped at the given base address, rather than trying to parse it as an ELF, PE, or Mach-O.
To override the auto-loader (e.g., if you have an ELF but need a specific language):
```
docker_start(
binary_path="/path/to/firmware.elf",
language="ARM:LE:32:v7",
loader="AutoImporter"
)
```
## Container Lifecycle
| Tool | Description |
|------|-------------|
| `docker_auto_start` | Find existing or start new container |
| `docker_start` | Start a container explicitly |
| `docker_stop` | Stop and remove a container |
| `docker_health` | Check if API is responding |
| `docker_logs` | View container output |
| `docker_status` | List all containers and images |
| `docker_cleanup` | Remove orphaned containers and stale locks |
| `docker_session_info` | Show this session's containers |
## Input Validation
All firmware import parameters are validated before reaching the container:
- **Language**: Must match `ARCH:ENDIAN:SIZE:VARIANT` pattern (e.g., `ARM:LE:32:v4t`)
- **Base address**: Must be a valid hex string (e.g., `0x00000000` or `00000000`), max 64-bit
- **Loader**: Must be alphanumeric with underscores (e.g., `BinaryLoader`)
Invalid values are rejected with a descriptive error before any Docker operations occur.

View File

@ -0,0 +1,93 @@
---
title: MCP Tools
description: Complete reference for MCGhidra's MCP tool interface
---
MCGhidra exposes Ghidra's capabilities as MCP tools. These are grouped by function.
## Analysis Tools
### `functions_list`
List all functions in the current program. Returns function names, addresses, and sizes.
### `functions_decompile`
Decompile a function by name or address. Returns C-like pseudocode from Ghidra's decompiler.
### `functions_disassemble`
Get assembly-level disassembly for a function or address range.
### `functions_create`
Define a new function at a given address.
## Memory & Data
### `memory_read`
Read bytes from a memory address. Returns hex-encoded data.
### `data_types`
List available data types in the program's data type manager.
### `data_create`
Apply a data type at an address (e.g., mark bytes as a struct).
## Navigation
### `xrefs_to`
Find all cross-references *to* an address — who calls this function or references this data.
### `xrefs_from`
Find all cross-references *from* an address — what does this function call or reference.
### `symbols_search`
Search for symbols by name pattern (supports wildcards).
## Annotation
### `symbols_rename`
Rename a symbol (function, label, variable) at a given address.
### `comments_set`
Set a comment at an address (EOL, pre, post, plate, or repeatable).
## Instance Management
### `instances_list`
List all known Ghidra instances (both local and Docker).
### `instances_use`
Switch the active instance by port number.
## Docker Management
### `docker_auto_start`
The primary entry point. Finds an existing container for the binary or starts a new one.
**Parameters:**
- `binary_path` (required) — Path to the binary file
- `language` — Ghidra language ID (e.g., `ARM:LE:32:v4t`)
- `base_address` — Memory base address (e.g., `0x00000000`)
- `loader` — Loader type (e.g., `BinaryLoader`)
### `docker_start`
Start a container with explicit control over all parameters.
### `docker_stop`
Stop a container (session-scoped — can only stop your own).
### `docker_health`
Poll a container's HTTP API to check readiness.
### `docker_logs`
Retrieve container stdout/stderr.
### `docker_build`
Build the MCGhidra Docker image from source.
### `docker_status`
Overview of all containers, images, and port allocations.
### `docker_cleanup`
Remove orphaned containers and stale port locks.
### `docker_session_info`
Show containers and ports for the current MCP session.

1
docs-site/src/env.d.ts vendored Normal file
View File

@ -0,0 +1 @@
/// <reference path="../.astro/types.d.ts" />

View File

@ -0,0 +1,62 @@
/* MCGhidra reverse engineering tooling aesthetic
* Warm amber/rust accent (#c85533), dark grays
*/
/* Light mode */
:root {
--sl-color-accent-low: #f8e4db;
--sl-color-accent: #b5452a;
--sl-color-accent-high: #6e2915;
--sl-color-white: #1a1614;
--sl-color-gray-1: #3a3230;
--sl-color-gray-2: #5c524e;
--sl-color-gray-3: #8a7e78;
--sl-color-gray-4: #b0a49e;
--sl-color-gray-5: #d0c8c4;
--sl-color-gray-6: #eae4e0;
--sl-color-gray-7: #f6f2f0;
--sl-color-black: #faf8f6;
--sl-font: 'Segoe UI', system-ui, -apple-system, sans-serif;
--sl-font-mono: 'Cascadia Code', 'Fira Code', 'JetBrains Mono', ui-monospace, monospace;
}
/* Dark mode */
:root[data-theme='dark'] {
--sl-color-accent-low: #3a1a0c;
--sl-color-accent: #e07040;
--sl-color-accent-high: #f5c4aa;
--sl-color-white: #f6f2f0;
--sl-color-gray-1: #d0c8c4;
--sl-color-gray-2: #b0a49e;
--sl-color-gray-3: #8a7e78;
--sl-color-gray-4: #5c524e;
--sl-color-gray-5: #3a3230;
--sl-color-gray-6: #261e1a;
--sl-color-gray-7: #1a1614;
--sl-color-black: #100c0a;
}
/* Inline code background */
:root {
--sl-color-bg-inline-code: #eae4e0;
}
:root[data-theme='dark'] {
--sl-color-bg-inline-code: #261e1a;
}
/* Tighter sidebar spacing */
nav.sidebar .top-level > li + li {
margin-top: 0.25rem;
}
/* Code blocks and disassembly tables */
table {
font-size: 0.9rem;
}
th {
background: var(--sl-color-gray-6);
font-weight: 600;
}

3
docs-site/tsconfig.json Normal file
View File

@ -0,0 +1,3 @@
{
"extends": "astro/tsconfigs/strict"
}