Expand description
The agent-agnostic half of the Ghidra MCP stack.
Everything here is shared by every agent’s plugin: the MCP server and its 19
tools, the worker lifecycle glue, the config contract, and the embedded
GhidraMcpWorker.java and driver skill. An agent plugin contributes only a
binary that calls cli::dispatch, plus its own manifest and skills.
Modules§
- cli
- The argv-level entry point every agent’s plugin binary dispatches into.
- config
- Server configuration + static validation (spec §7). Precedence: CLI flag > env var > config file >
built-in default. Validation happens BEFORE any worker boot so a misconfig surfaces as a clean
onboarding error, not a boot crash-loop.
bootstrap_programis required (the worker cannot boot without a valid -process program — M0 spike D1). - execute
- The request engine (spec §4.3/§4.4/§4.7/§5): the ordered pipeline every tool call runs through.
Returns either a worker
resultValue (plus a snapshot of the active canonicalizer for the caller to canonicalize addresses) or a structuredErrorEnvelope. - logging
- Server logging: a per-instance, size-bounded, owner-only file log — never stdout (spec §5). stdout is the MCP JSON-RPC channel; any byte there corrupts the protocol. The 128-bit connection token is NEVER passed to a log macro anywhere in the server (enforced by review, not code).
- paths
- Filesystem locations for the server: the ghidra-mcp data dir, the per-version worker-script dir, and the per-instance log path (spec §5). Base dir = $GHIDRA_MCP_HOME, else %USERPROFILE%/$HOME + “.ghidra-mcp”, else the system temp dir. No external dir crate (keeps the deny gate small).
- poison
- Bounded poison-set (spec §4.3): remembers (tool, selector) pairs that reproducibly crashed the worker, so an identical later request is rejected up-front without a third/fourth respawn. Bounded LRU (evicts oldest) so a stubborn agent spamming distinct payloads can’t grow it without limit.
- server
- MCP stdio server (lands across Tasks 12-15 of the M1a “Crucible” plan).
- skill_
asset - Embed the driver skill (
skill/SKILL.md) in the binary so an agent plugin can regenerate its committed copy from the shipped binary (single source of truth — no skill drift). The ship-guard test below fails the build if the embedded content is stubbed, emptied, or truncated rather than the authored driver skill. - state
- Server state: the single worker held behind an async mutex, its active attachment + address
canonicalizer, the poison set, and a permit semaphore. Lazy single-flight boot (spec §5); strict
inner<outer timeouts (spec §4.7); transparent crash respawn (spec §4.3) lives in
execute.rs. - tools
- MCP tool handlers (spec §3). Each maps a worker
resultValue into the client-facing shape, then canonicalizes every address string through the attached program’sAddressCanonicalizer(spec §6). Domain errors becomeCallToolResult{isError:true}with theErrorEnvelopeas text (spec §4.2). - worker_
asset - Embed the worker
.javain the binary and extract it to a per-user script dir at boot, keyed by content hash so the extracted copy always matches the compiled binary (spec §12). Only the thin-slice extraction primitive; the §6 extraction-integrity hardening (0700/0600, ownership, symlink guards) is layered in a later milestone.
Functions§
- worker_
asset_ extract - Extract the embedded worker script into
dir. Returns the script path; IO failures (full disk, read-only temp dir) are returned, never panicked — the shippedboot-smokepath calls this on a real filesystem.