# REA: Multi-Tool Reverse Engineering Through MCP Orchestration

> Source: <https://dev.to/mech_app_ai/rea-multi-tool-reverse-engineering-through-mcp-orchestration-oe5>
> Published: 2026-10-07 20:07:46+00:00

Reverse engineering typically requires juggling multiple specialized tools: Ghidra for decompilation, Hopper for disassembly, dynamic tracers for runtime behavior. Each tool has its own CLI, API surface, and session management. REA (Reverse Engineer Anything) exposes all of them through a single Model Context Protocol (MCP) server, letting agents coordinate static analysis, dynamic tracing, and binary inspection without managing tool-specific state.

The project sits at 14,029 stars and ranks #1 in trending TypeScript repos. It targets Claude Code, Codex, Cursor, Gemini, and Grok through a skills framework that abstracts vendor differences. The interesting part is not the agent frontend but the MCP server that maintains investigation state across tool boundaries.

REA treats reverse engineering as a multi-phase investigation. An agent might:

The MCP server holds the investigation context. When an agent calls `analyze_binary`, the server decides whether to invoke Ghidra, Hopper, or both based on the query. When the agent requests runtime behavior, the server spawns a tracer and merges its output with prior static analysis.

This is not a simple tool wrapper. The server maintains a shared investigation graph: functions discovered in static analysis become targets for dynamic tracing. Symbols resolved at runtime feed back into the decompiler's type inference. The agent sees a unified API; the server handles tool coordination.

The MCP server runs on Node.js 22+ and exposes a catalog of tools:

Each tool runs in a subprocess. The server manages lifecycle (spawn, attach, teardown) and serializes results into a common schema. Agents call MCP methods like `decompile_function` or `trace_syscalls`; the server routes to the appropriate backend and caches results in the investigation context.

The server maintains three state layers:

| Layer | Scope | Persistence | 
|---|---|---|
| **Investigation context** | Cross-tool results, symbol maps, call graphs | In-memory, serialized to JSON on request | 
| **Tool sessions** | Ghidra project files, Hopper database handles | Ephemeral, cleaned up on investigation close | 
| **Agent checkpoints** | Intermediate findings, hypotheses, next steps | Stored in MCP resource URIs for resume | 

When an agent requests `analyze_binary`, the server:

If the agent later calls `trace_function` with a function ID, the server:

The agent never manages Ghidra project files or frida script lifecycles. It sees a stateful investigation that spans tools.

The server uses heuristics to decide which tool to invoke:

`file` and `objdump` for basic metadata
These rules live in the server's investigation planner. The agent can override by calling specific tools directly, but the default flow minimizes redundant analysis. For example, if Ghidra already decompiled a function, the server skips Hopper disassembly unless the agent explicitly requests a second opinion.

REA includes wrappers for vendor CLIs like `stripe` and `gh`. These tools often require OAuth tokens or API keys. The MCP server handles credential injection server-side:

Agents call `invoke_cli` with a tool name and arguments. The server injects credentials, runs the command, and returns stdout. The agent never sees raw tokens. This keeps the MCP interface tool-agnostic while supporting authenticated workflows.

REA ships with 33 Parseltongue techniques for testing agent robustness. These are input perturbations across three intensity tiers:

The MCP server can apply Parseltongue transforms to any tool input before passing it to the backend. This lets agents test how decompilers, disassemblers, and tracers handle malformed or malicious inputs. For example, an agent might:

This is useful for evaluating tool brittleness and finding edge cases in binary parsers.

The MCP server logs every tool invocation with:

Logs are structured JSON, queryable with `jq` or ingested into observability platforms. When a tool crashes, the server:

Common failure modes:

| Failure | Cause | Mitigation | 
|---|---|---|
| **Ghidra timeout** | Large binary, complex control flow | Server kills subprocess after 5 minutes, returns partial results | 
| **Frida attach failure** | Target process protected by SIP or ptrace restrictions | Server falls back to passive tracing (dtrace, strace) | 
| **Hopper license error** | Commercial license expired or not found | Server skips Hopper, uses Ghidra only | 
| **Memory exhaustion** | Decompiler allocates too much RAM | Server enforces per-tool memory limits via cgroups (Linux) or `ulimit` | 

The agent sees a unified error interface. It can retry with different tools or adjust the investigation scope.

REA runs as a single MCP server process. Typical deployment:

``` js
// server.ts
import { MCPServer } from 'rea-agents/mcp';
import { GhidraBackend, HopperBackend, FridaBackend } from 'rea-agents/tools';

const server = new MCPServer({
  tools: [
    new GhidraBackend({ headless: true, timeout: 300000 }),
    new HopperBackend({ license: process.env.HOPPER_LICENSE }),
    new FridaBackend({ spawn: true, attach: true }),
  ],
  investigation: {
    persistTo: './investigations',
    maxConcurrent: 4,
  },
  observability: {
    logLevel: 'debug',
    metricsPort: 9090,
  },
});

server.listen(3000);
```

The server exposes:

Agents connect via MCP clients (Claude Desktop, Cursor, custom scripts). Multiple agents can share the same server, but each investigation is isolated. The server enforces concurrency limits to prevent resource exhaustion.

The MCP server runs tool subprocesses with restricted privileges:

`ulimit` (macOS)
Agents cannot execute arbitrary code on the server. They can only invoke predefined MCP tools. The server validates all inputs against a schema before passing them to backends. This prevents command injection and path traversal attacks.

Credential storage uses OS-level keychains. Tokens are encrypted at rest and never logged. The server rotates tokens on a schedule and revokes them when an investigation closes.

``` js
// agent.ts
import { MCPClient } from 'rea-agents/client';

const client = new MCPClient({ serverUrl: 'http://localhost:3000' });

// Start investigation
const investigation = await client.createInvestigation({
  target: './suspicious-binary',
  goals: ['identify obfuscation', 'find network calls'],
});

// Static analysis
const functions = await client.call('analyze_binary', {
  investigationId: investigation.id,
  binary: './suspicious-binary',
  tools: ['ghidra', 'hopper'],
});

// Filter for network-related functions
const networkFuncs = functions.filter(f => 
  f.name.includes('socket') || f.calls.some(c => c.includes('connect'))
);

// Dynamic tracing
for (const func of networkFuncs) {
  const trace = await client.call('trace_function', {
    investigationId: investigation.id,
    functionId: func.id,
    duration: 10000, // 10 seconds
  });

  console.log(`${func.name} called with:`, trace.arguments);
  console.log(`Returned:`, trace.returnValue);
}

// Export investigation
const report = await client.call('export_investigation', {
  investigationId: investigation.id,
  format: 'markdown',
});

console.log(report);
```

The agent sees a high-level API. The MCP server coordinates Ghidra, Hopper, and frida under the hood.

**Use REA when:**

**Avoid REA when:**

The MCP server architecture works well for agent-driven workflows where the agent decides what to investigate and the server handles tool coordination. It does not replace manual reverse engineering but automates the plumbing between tools.
