---
title: "rea-ida-adapter: REA with IDA Free"
url: "https://reamcp.dev/ja/cases/rea-ida-adapter-rea-with-ida-free-305b75"
source: "https://github.com/akbar-npj/rea-ida-adapter"
source_type: "github"
repo: "https://github.com/akbar-npj/rea-ida-adapter"
author: "akbar-npj"
author_handle: "akbar-npj"
stars: 0
category: "ツール・連携"
categories: ["tools-integrations"]
tags: []
added: "2026-10-12T22:38:05.215Z"
updated: "2026-10-11T11:27:44Z"
locale: "ja"
content_locale: "en"
---

# rea-ida-adapter: REA with IDA Free

An adapter MCP server that connects REA's legacy IDA tool profile to IDA Free 9.x on aarch64.

## Description

Why it is listed: Tooling for using a legitimately licensed disassembler.

## Original README

# rea-ida-adapter

A small, stdlib-only Python 3 MCP adapter that bridges **REA's "IDA provider"** to a
running **`ida-free-mcp`** IDA plugin.

REA's *attached* mode expects the upstream MCP server to speak the **ida-pro-mcp
v1.4 "legacy attached" tool profile** — a fixed set of 10 tools with specific JSON
result shapes that REA validates with zod (a shape mismatch hard-fails the request).
`ida-free-mcp` exposes a *different* (modern) tool set over **Streamable HTTP MCP**.
This adapter sits in between:

```
REA  --stdio JSON-RPC-->  adapter.py  --HTTP MCP-->  ida-free-mcp (IDA plugin)
       (legacy 1.4 profile)              (modern profile)
```

It advertises exactly the 10 legacy tool names, translates each call into one or more
`ida-free-mcp` tool calls, and reshapes the results into the exact legacy schemas.

## Files

| File | Purpose |
| --- | --- |
| `adapter.py` | The adapter (executable, `#!/usr/bin/env python3`). |
| `README.md` | This document. |
| `.gitignore` | Ignore local scratch files. |

No third-party packages are required. Run it with `python3 adapter.py`; it reads/writes
newline-delimited JSON-RPC 2.0 on stdin/stdout and logs to **stderr only**.

## Registering with REA

Point `REA_IDA_MCP_CONFIG` at a JSON file shaped like:

```json
{
  "mcpServers": {
    "ida-pro-mcp": {
      "type": "stdio",
      "command": "python3",
      "args": ["/home/shaanair/Projects/ida-mcp/rea-ida-adapter/adapter.py"],
      "mode": "attached"
    }
  }
}
```

REA spawns the adapter over stdio, calls `initialize` / `tools/list`, checks that the
legacy tool set is present, and then drives the tools below.

### Upstream discovery

On the first tool call the adapter connects to `ida-free-mcp` at `POST /mcp`:

1. `IDA_MCP_URL` (env) — full URL or base; `/mcp` is appended if missing.
2. `IDA_MCP_PORT` (env) — `http://127.0.0.1:<port>/mcp`.
3. `~/.ida-mcp/instances/*.json` — each file records `{port, pid, idb_path}`; ports are
   tried newest-file-first (handles the plugin's auto-increment when 13337 is busy).
4. `http://127.0.0.1:13337/mcp` — the default.

It performs an MCP `initialize` + `notifications/initialized` handshake against the
first reachable candidate and pins it. Responses are accepted as either plain JSON or
SSE-framed (`text/event-stream` with `data: {...}` lines).

## Tool mapping

| REA tool (legacy 1.4) | args | `ida-free-mcp` source | result translation |
| --- | --- | --- | --- |
| `get_metadata` | `{}` | resource `ida://idb/metadata` | passthrough `{path, module, sha256, base, ...}`; `base` normalized to `0x…` |
| `list_functions` | `{offset, count}` | `list_funcs` `{queries:{offset,count}}` | `[{data,next_offset}]` → `{data:[{address,name,size}], next_offset}` |
| `get_function_by_name` | `{name}` | `lookup_funcs` `{queries:[name]}` | `[{query,fn,error}]` → `{address,name,size}` |
| `get_function_by_address` | `{address}` | `lookup_funcs` `{queries:[addr]}` | `[{query,fn,error}]` → `{address,name,size}` |
| `list_strings` | `{offset, count}` | `find_regex` `{pattern:"(?s).*", limit, offset}` | `{matches:[{addr,string}]}` → `{data:[{address,string,length}], next_offset}`; `length` synthesized |
| `disassemble_function` | `{start_address}` | `disasm` `{addr, max_instructions:50000}` | `asm.lines` **string** → parsed into `[{address,instruction}]`; `name`/`start_ea`/`return_type`/`arguments` passed through |
| `decompile_function` | `{address}` | `decompile` `{addr}` | `{ok,pseudocode}` → pseudocode **string**, or `null` when `ok=false` |
| `get_xrefs_to` | `{address}` | `xrefs_to` `{addrs:[addr], limit:1000}` | `[{xrefs:[{addr,type,fn}]}]` → `[{address,type,function}]` |
| `get_callers` | `{function_address}` | `xrefs_to` (derived) | keep `type=="code"` xrefs, dedupe by containing function, drop self-references → `[{address,name,size}]` |
| `get_callees` | `{function_address}` | `callees` `{addrs:[addr], limit:500}` | `[{callees:[{addr,name,type}]}]` → `[{address,name,type}]` |

All addresses are normalized to lowercase `0x…`; `size` is always a string.

## Known limitations

- **`list_strings`** — `ida-free-mcp` has no string-list tool. This adapter enumerates
  string literals via `find_regex` with `(?s).*`, falling back to `[\s\S]*` if the
  C++ `std::regex` ECMAScript engine rejects the inline `(?s)` flag. Only items IDA has
  flagged as string literals (`is_strlit`) are returned; `length` is the Python
  character count of the decoded string (not the on-disk byte length). Empty strings
  are not returned by the upstream tool.
- **`get_callers`** — `ida-free-mcp` has no callers tool. Callers are *derived* from
  `xrefs_to`: only `code` cross-references whose containing function differs from the
  target are reported. This can miss callers reached through data/indirect references
  and can, in principle, include non-call code references (e.g. a tail jump) that IDA
  classifies as `code`. It is a best-effort approximation, not a proven call-edge set.
- **`get_metadata.sha256`** — passed straight through from IDA. If IDA cannot produce
  the input SHA-256 (e.g. the `.i64` has no input hash), the upstream returns
  `"unavailable"`, which REA rejects (it requires 64 hex chars). Open the original
  input binary in IDA so the hash is recorded.
- **`disassemble_function`** — the upstream caps a single call at 50 000 instructions;
  larger functions are silently truncated. Basic-block/CFG data is not requested.
- **`decompile_function`** — on IDA Free the upstream uses GUI-based decompilation
  (F5 + widget scraping); it returns `null` (never an error) when no pseudocode widget
  can be found for the function.
- **Startup** — the adapter starts even when `ida-free-mcp` is down; the first tool
  call returns a clear MCP tool error, which REA surfaces rather than crashing.

## Verifying without IDA

```sh
python3 -c "import ast; ast.parse(open('adapter.py').read())"

printf '%s\n' \
  '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"t","version":"1"}}}' \
  '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}' \
  | python3 adapter.py
```

`tools/list` does not touch `ida-free-mcp` and returns all 10 legacy tool names.
