GhidrAssistMCP: An MCP Server Inside Ghidra, and What Its Headless Mode Actually Requires
An native MCP server extension for Ghidra
At a glance
- What is it?
- GhidrAssistMCP is a Ghidra extension that exposes a Model Context Protocol server over HTTP, with 49 tools, 6 resources and 7 prompts. The interesting part is not the tool count but the headless launcher path, which changes what you have to install and how the JVM stays alive.
- Who is it for?
- Adopt GhidrAssistMCP if you already run Ghidra 11.4 or newer and want an MCP client, such as GhidrAssist, to query a loaded program over HTTP without writing your own bridge. Skip it if you cannot move to Java 25 for a source build, or if your workflow needs an MCP client that is not HTTP-based, since the README documents only SSE and Streamable HTTP endpoints.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 43 days ago.
- What is it written in?
- Mainly Java, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The gap GhidrAssistMCP fills between an LLM client and a loaded program
Ghidra has no built-in way for an external process to ask it questions. An AI assistant or an automation script that wants to know which functions call a given address, or what strings a binary contains, has to go through Ghidra's own scripting APIs or drive the UI. GhidrAssistMCP closes that gap by running a Model Context Protocol server inside the Ghidra process and exposing the analysis surface over HTTP. The audience is narrow and specific: reverse engineers who already use an MCP-capable client and want it pointed at a real Ghidra session rather than at a static export of the disassembly. The README names GhidrAssist as a client that supports the extension out of the box, which tells you the intended pairing. If you do not already have an MCP client, this extension gives you an endpoint and nothing to connect to it.
What the server exposes: tools, resources, prompts and the action-based tool API
The extension registers 49 tools, 6 resources and 7 prompts. The resources are static data sets: program info, functions, strings, imports, exports and segments. The prompts are pre-built for common reverse engineering tasks. The tools are the part worth reading carefully, because the README describes them as consolidated by action rather than one tool per operation. That is a deliberate API shape: fewer tool names, with the operation selected by a parameter. It keeps the tool list manageable for a model choosing between them, at the cost of a larger parameter surface per call. Two other mechanisms sit in front of the analysis work. Result caching serves repeated queries from a store instead of recomputing, and long-running operations run asynchronously with task management rather than blocking the request. The async path is the one to think about if you are writing a client: a tool call that returns a task handle is not the same as a tool call that returns an answer, and your client has to handle both.
Multi-program and multi-window behaviour, and why list_binaries matters
Ghidra users routinely have several binaries open at once, and the extension takes a position on that. A single MCP server is shared across all CodeBrowser windows, with focus tracking, and tool responses carry context hints about which binary window is active. To target a specific program you pass program_name. The README flags a real ambiguity here: two open programs can share a filename, so it directs you to use list_binaries Project Path values to disambiguate duplicates. This is the kind of detail that decides whether a tool is usable in practice. If your project has three builds of the same library open, program_name alone is not enough, and a client that guesses will silently analyse the wrong one. The focus-tracking default is convenient for interactive use and a hazard for unattended runs, where no window is in focus in any meaningful sense.
Installing from a release ZIP versus building with Java 25 and GHIDRA_INSTALL_DIR
There are two install paths and they have different requirements. The binary release is a ZIP downloaded from the releases page and added through File, Install Extensions, Add Extension, followed by a Ghidra restart and a check of the plugin under File, Configure, Configure Plugins. The source path is stricter: it needs Java 25 or newer, and the README says the included Gradle wrapper pins the supported Gradle release, so you should use the wrapper rather than a system Gradle. You point the build at your Ghidra install either by exporting GHIDRA_INSTALL_DIR or by passing -PGHIDRA_INSTALL_DIR=<path>. With Ghidra closed, ./gradlew installExtension copies the built ZIP into [GHIDRA_INSTALL_DIR]/Extensions/Ghidra and extracts it into your Ghidra user Extensions folder, replacing any existing extracted copy. That replacement behaviour is worth noting: reinstalling overwrites the extracted directory, and -PGHIDRA_USER_EXTENSIONS_DIR=<path> is the escape hatch if your user extensions live somewhere non-standard. Java 25 is a hard floor on this path, not a recommendation, and it is the single most likely reason a source build fails on a machine that otherwise runs Ghidra fine.
Running the MCP server under analyzeHeadless, and the wait flag that keeps it alive
The headless quickstart is the most operationally specific part of the README, and it changes the shape of the deployment. You still build and install the extension first, then export GHIDRA_INSTALL_DIR, GHIDRA_USER_EXTENSIONS_DIR and GHIDRASSISTMCP_EXT. On Linux the README places user extensions under ~/.config/ghidra/<ghidra_profile>/Extensions. The server is started as a Ghidra script rather than through the UI: analyzeHeadless is invoked with -scriptPath "$GHIDRASSISTMCP_EXT/ghidra_scripts" and -preScript GAMCPStartServerScript.java, passing host and port arguments. For an already-imported binary you swap -import for -process. The important flag is wait. Used as a -preScript, the server starts, analysis runs, and the process ends. Used as a -postScript with wait=true, analyzeHeadless stays open so an interactive MCP client can connect after analysis finishes. Clients connect to http://127.0.0.1:8080/sse for SSE, http://127.0.0.1:8080/message for SSE messages, or http://127.0.0.1:8080/mcp for Streamable HTTP. The README also states that the headless server holds a program consumer while running so that MCP requests do not race against program database closure, and that a harness can pass completion_file=/workspace/control/session.complete; creating that file shuts the server down cleanly and lets Ghidra save and exit. That completion-file contract is a harness integration point, not a user-facing feature, and it implies whoever runs this in CI owns the lifecycle of both the file and the JVM.
Where the extension stops: transport, client support and the caching blind spot
The documented transports are SSE and Streamable HTTP. A client that speaks stdio only, which is the common shape for locally launched MCP servers, has nothing to connect to here without an adapter. That is a design consequence of running inside Ghidra's JVM: the server cannot be spawned as a child process by the client, so HTTP is the transport that fits. The second limitation is caching. The README describes result caching as improving performance for repeated queries but does not state an invalidation rule. In a session where you rename a function, apply a data type, or run auto analysis, a cached answer and the current program can disagree. Treat the cache as an optimisation whose correctness conditions are undocumented, and verify behaviour after any operation that mutates the program rather than assuming the next query reflects it. The third constraint is version: Ghidra 11.4 or newer, tested against Ghidra 12.1 Public according to the README. Older Ghidra installs are out of scope.
GhidrAssistMCP versus writing your own Ghidra script or headless bridge
The alternative most teams reach for is a custom Ghidra script or a small headless harness that dumps functions, strings and imports to files an external tool reads. That approach has real advantages: no Java 25 requirement, no running server, no port to manage, and output you can diff and version. Its cost is that the data is a snapshot. Anything the analyst does in the Ghidra UI after the dump is invisible to the consumer, and every new question means a new script. GhidrAssistMCP inverts that: the program stays live, the consumer queries it over HTTP, and the tool surface is fixed at 49 tools instead of whatever you wrote. The trade is a persistent process with a port, a program consumer held open, and a client that must speak SSE or Streamable HTTP. If your questions are known in advance and the answers fit in a file, the script wins. If the questions arrive interactively and depend on what the previous answer showed, the live server is the point.
Maintenance cost, licence and what to check before you commit
The repository is MIT licensed, which is permissive and places few obligations on how you redistribute or modify the extension; that is a statement about the licence text, not legal advice, and you should read the LICENSE file for the terms that apply to you. Maintenance cost is dominated by two things the README makes explicit. First, the Ghidra version floor: 11.4 or newer, with the source build additionally requiring Java 25, so a Ghidra upgrade can force a JDK upgrade alongside it. Second, the install procedure replaces the extracted copy in your user extensions folder on every ./gradlew installExtension, so any local modification to that extracted directory is lost unless you keep it elsewhere. The release cadence visible in the supplied material is roughly monthly, with 2.9.0, 2.10.0 and 2.11.0 landing between late June and early August 2026, and the 2.11.0 notes title mentions hardened headless automation and reliable async results, which suggests the headless path is still being actively stabilised. Pin a release ZIP rather than tracking the branch if you depend on the headless contract.
Editorial conclusion
Adopt GhidrAssistMCP if you already run Ghidra 11.4 or newer and want an MCP client, such as GhidrAssist, to query a loaded program over HTTP without writing your own bridge. Skip it if you cannot move to Java 25 for a source build, or if your workflow needs an MCP client that is not HTTP-based, since the README documents only SSE and Streamable HTTP endpoints. Before committing, verify three things against your own setup: that the plugin appears under File, Configure, Configure Plugins after install; that your Ghidra user extensions directory matches the GHIDRA_USER_EXTENSIONS_DIR path you export; and that GAMCPStartServerScript.java starts and, with wait=true, stays up under your analyzeHeadless invocation.
Community notes