REA Refuses to Guess

One MCP server wires Ghidra, IDA, Hopper, and dozens of other engines into a single agent workflow. Its most radical feature is what happens when one of them breaks.

9 min read • View on GitHub • More from morluto

A wide editorial illustration of a workshop where a small humanoid agent sits at a long wooden workbench, bent over a single binary file laid open like a book. Behind the bench, a tall pegboard holds dozens of specialized hand tools and sealed drawers, each with a small engraved label, and one drawer is open. A neat stack of index cards rests on the bench beside the agent. The scene shows a reverse-engineering workflow: one agent, many tools, and evidence as the tangible output.
REA puts one agent in front of a wall of specialist engines and asks it to bring back evidence, not answers.
Key Takeaways

The Tool That Refuses to Guess

Most tools that wrap a disassembler for an AI agent share a quiet assumption: if one engine fails, try another. REA does not. Its provider documentation states the rule as a hard contract: "runtime failure never selects another provider automatically." When a bound engine dies, REA returns an explicit failure and stops.

Why would a reverse-engineering tool deliberately break? Because the alternative is a hallucination vector. If Ghidra fails and REA silently retries in Hopper, the agent receives different decompilation, different function boundaries, and different naming, with no way to tell that the switch happened. The evidence from run one and the evidence from run two are no longer comparable, and the agent has no signal that anything changed.

A close-up editorial illustration of two heavy decompiler machines side by side, both with open inspection hatches. The left machine has a cracked, stopped gear and a small tag hanging from it. A hand hovers near the right machine's handle, but a second hand holds a small rectangular card reading STOP between the two machines. The hand does not reach for the working machine. The image makes REA's no-fallback rule physical: a working engine sits available, and the system still refuses to substitute it.
A working engine sits one step away. REA still will not reach for it, because a silent substitution would change the evidence without saying so.

The project started as a personal question. Morluto wanted to understand how a closed-source app they already used actually worked, and wiring analysis tools through MCP let an agent do the poking. The framing that stuck was evidence, not source: findings come back as records with stated limits, not as recovered code.

One MCP for reverse engineering across binaries, applications, and runtime behavior.

REA project, Project description in the official repository · morluto/rea

One MCP, Dozens of Engines

Once you accept the refusal, the breadth starts to make sense. An agent investigating a real application does not know in advance whether the interesting logic lives in a native binary, a JavaScript bundle, a managed assembly, or a network capture. REA's bet is that it should not have to care.

The server routes across a wide range of tools and target types. Native analysis runs through Hopper, Ghidra, and IDA (via the upstream ida-pro-mcp), plus rizin, objdump, GDB, and pwntools. JavaScript and Electron work covers ASAR reconstruction, source maps, the Chrome DevTools Protocol, and the V8 Inspector. Mobile and managed code spans JADX, Apktool, .NET, IL2CPP, and Flutter. Firmware routes into Binwalk and Unblob. Runtime work draws on tshark, Frida, and mitmproxy.

The packaging is part of the pitch. A single command, npx rea-agents setup, registers the MCP server with supported agents and installs matching workflow instructions. The installer shows the configuration changes it makes and backs up existing files. For a category where the usual advice is to assemble your own bridges, that is a real reduction in friction.

Evidence, Not Answers

REA's central data type is the Evidence record, documented in the MCP contracts. Every evidence-producing tool returns the complete record in both text and structured content. It carries a normalized result, an optional raw result from the upstream tool, an analysis profile, and an identity field called evidence_id.

The subtle rule is that the analysis profile participates in semantic identity. The same function analyzed under two different profiles produces two different IDs, because the settings are part of what the result means. Identity here is not incidental metadata. It is a claim about what was actually run.

The system also refuses to rewrite history. Saved records from an earlier identity scheme are recognized and rejected with a diagnostic rather than silently upgraded. The original ID and file are left untouched. That protects provenance at the cost of asking users to re-export, which is a deliberate trade.

Evidence is also composable. The compare_functions tool accepts complete analyze_function Evidence directly, and compare_artifacts takes a retained-evidence reference, a file path, or inline Evidence, with all three forms producing the same comparison record. The result is a data type that can be passed between tools without losing the context that makes it trustworthy.

334 MB In, 10 KB Out

Here is the part that keeps a senior engineer reading. analyze_function does not return its full dossier by default. Without a detail flag, it retains the complete analysis in the session and returns a tiny summary record whose parent_evidence_id names the dossier. The agent gets a pointer, not a payload.

The CLI documentation gives a concrete example: a 334 MB Obsidian application Evidence file produces a summary view of about 10 KB, with a page view of 32 modules available on request. The performance rules in AGENTS.md make the priority explicit, agent tokens and context come first, then analysis time, then CPU and memory.

The cost is complexity. Agents now track two identities, the summary and its parent, and the rules about which tool accepts which record are strict. Downstream tools that need the full dossier reject the summary. That strictness is the point: the type system keeps a cheap summary from being mistaken for the real thing.

The token economy in one picture: the dossier stays in the session, the agent gets a small summary that carries a pointer back, and the summary is deliberately not a valid input to tools that expect the full record.

The same honesty shows up at the edges. In the Ghidra bridge, string listings report a terminator state named present_or_not_required, because the API genuinely cannot tell a present terminator from a fixed or Pascal layout when none is missing. That name is an admission of what the engine can and cannot tell you, encoded in the schema.

How REA Compares

The specialist MCPs came first and do one thing tightly. REA's bet is that an agent investigating a real app needs many engines behind one contract, and one honest failure mode.

ProjectFocusEngines / formatsPackagingEvidence model
morluto/reaMulti-engine, multi-format MCP + CLINative, JS/Electron, .NET, Android, firmware, WASM/EVM, runtimeOne installer wires supported agents and adds workflow instructionsStructured Evidence records with semantic identity; explicit unknowns; no silent fallback
mrexodia/ida-pro-mcpIDA ProIDASingle bridgeTool output
LaurieWired/GhidraMCPGhidraGhidraSingle bridgeTool output
duty1g/x64dbg-mcp-serverx64dbg debuggerx64dbgSingle bridgeTool output
fosdickio/binary_ninja_mcpBinary NinjaBinary NinjaSingle bridgeTool output

Worth stating plainly: REA does not ship its own decompiler. It is a bridge and workflow layer. The core disassembly and decompilation still come from Ghidra, IDA, Hopper, and the rest, each with its own installation and licensing requirements. The value is orchestration and agent access, not a new engine.

What REA Can't Do

The honest framing cuts both ways, and the community has been quick to say so. Decompiled pseudocode is not the original source. Static inspection cannot prove every runtime behavior, and runtime capture executes the target, which can alter files, state, or data. A controlled environment and proper authorization still matter.

The most visible pushback came from a widely shared report of a user decompiling a purchased Unity game. Commenters pointed out that Mono builds ship managed IL that established .NET tools have decompiled for years, and that IL2CPP, which compiles to native code, would be the genuinely hard case. That criticism is correct. It does not weaken REA; it clarifies what REA is for.

What comes back is decompiled guesswork in C-like form, not the original source code. Rebuilding a feature still takes real engineering. The hard analysis is still Ghidra, IDA and Hopper doing what they've done for years.

@MrOcelot1976, X user criticizing claims about reverse-engineering output · Agent Breaking roundup

There is one more constraint REA cannot route around. What an agent is willing to do depends on the model, its policies, and the user's permissions. Community reports include cases where agents declined reverse-engineering requests regardless of the tooling on hand. REA supplies the plumbing. The judgment calls happen somewhere else.