[GH-ISSUE #1416] [Feature] Support the official Hex-Rays IDA MCP server as an analysis provider #485

Open
opened 2026-10-15 18:25:29 +00:00 by bsakaguchi · 3 comments
Owner

Originally created by @ljcyt on GitHub (Oct 10, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/1416

Before submitting

  • I searched the open and closed issues and pull requests for a related proposal.
  • I removed credentials, tokens, private paths, and sensitive target data.

Area

Provider or capability discovery; native analysis; CLI and MCP integration.

Current limitation

REA's IDA provider is contract-bound to mrexodia/ida-pro-mcp. The official Hex-Rays server (HexRaysSA/ida-mcp, announced 2026-09-25, latest release v20261008.0.1) cannot drive it: the two expose disjoint tool surfaces — not a single name overlaps.

docs/ida-provider.md scopes the adapter explicitly:

REA adapts an existing mrexodia/ida-pro-mcp server into its native analysis tools. […] REA does not install, upgrade, activate, or license them, and does not bundle another IDA server.

Upstream tools REA calls (src/ida/IdaSessionClient.ts, src/ida/IdaOperationRunner.ts):

get_metadata, list_functions, list_funcs, decompile_function, disassemble_function,
get_function_by_address, get_function_by_name, get_xrefs_to, xrefs_to,
get_callers, get_callees, list_strings, idb_open, idb_list, idb_close

Tools the official server exposes (ida_mcp/mcp.py — module docstring and @tool registrations, v20261008.0.1):

open_database, execute_python, reference, list_databases, save_database, close_database

Intersection: empty. Setting REA_IDA_MCP_CONFIG to the official registration does connect, but every REA operation resolves to an unknown upstream tool.

The two differ by design, not only by naming:

mrexodia/ida-pro-mcp (currently supported) Hex-Rays official ida-mcp
surface typed semantic tools (decompile_function, list_functions, …) attach a database, run IDAPython, query an API reference
who picks the operation REA the agent, writing IDAPython against reference
base library upstream's own IDA bridge ida-nexus>=0.13.4

Use cases

  1. Avoid running two IDA MCP servers. Hex-Rays' own install instructions say: "We recommend disabling other IDA MCP servers to reduce agent confusion." A user on IDA 9.4+ who installed the official server via uvx ida-hcli mcp install currently has to keep mrexodia/ida-pro-mcp alongside it just to satisfy REA — directly against vendor guidance.
  2. Vendor-maintained tooling. The official server ships through the IDA install path (hcli mcp install, or uvx ida-mcp stdio --agent=<agent>), so setup and updates follow Hex-Rays rather than a third-party repo.
  3. Headless parity. The official server works headlessly without the GUI plugin, which maps onto REA's existing headless IDA profile intent.
  4. Same analyst workflow. Attach an already-open GUI database, or hand REA a local binary, and keep REA's provider-neutral operations and evidence contract — without changing which IDA MCP the user has installed.

Desired outcome and success criteria

  • A second IDA provider profile (e.g. ida-official / ida-nexus) selectable through REA_ANALYSIS_PROVIDER, the CLI's --provider, or MCP's open_binary.provider_id, leaving the existing mrexodia profile untouched.
  • REA's provider-neutral operations map onto the official surface. Since there is no decompile_function upstream, this most likely means implementing the semantic operations on top of execute_python + reference rather than forwarding tools 1:1 — that trade-off is the main thing to decide.
  • The same guarantees as the current profile: target-identity match against the recorded input hash, image-base checks around each request, live (non-replayed) results, and never saving or closing the user's database.
  • Actionable failure when a configured server matches no known contract: report the detected tool set and the contract REA expected, instead of a generic unknown-tool error.

Authority boundaries and non-goals

  • REA should not install, upgrade, activate, or license the official server; that stays with hcli mcp install / the user, consistent with the current bring-your-own stance.
  • Prerequisites worth documenting: IDA 9.4+ with idalib, Python 3.11+, and uv + Git on PATH.
  • execute_python executes arbitrary code inside IDA's process. That is a materially wider authority than the current typed-tool adapter, and it deserves an explicit decision rather than being folded into implementation. A read-only or allowlisted posture would be worth stating if that is the intent.
  • Not a non-goal, but adjacent: the official server also exposes save_database, which the current adapter's "never mutate the user's database" stance deliberately avoids.

Alternatives considered

  • Status quo (mrexodia only). Works, and is what #747 scoped deliberately. It leaves official-server users running two IDA MCP servers, against vendor guidance.
  • Drive execute_python outside REA's provider layer, letting the agent run IDAPython directly. Cheapest, but drops REA's target-identity checks and evidence provenance, which is the reason the adapter exists.
  • Ask Hex-Rays for a compatibility shim exposing the mrexodia tool names. Out of REA's control and unlikely.

Additional context

  • Verified against official ida-mcp v20261008.0.1 (released 2026-10-08). Tool names extracted from ida_mcp/mcp.py at main; REA's expected upstream names read from src/ida/* and docs/ida-provider.md at main.
  • Prior art: #747 established the IDA provider and explicitly scoped it to mrexodia/ida-pro-mcp. This request does not reopen that decision — it asks for the official server as an additional profile.
  • Related: #1389 (rsleigh as a headless provider candidate) suggests new provider candidates are evaluated on their own merits, which is the model this request follows.
Originally created by @ljcyt on GitHub (Oct 10, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/1416 ### Before submitting - [x] I searched the open and closed issues and pull requests for a related proposal. - [x] I removed credentials, tokens, private paths, and sensitive target data. ### Area Provider or capability discovery; native analysis; CLI and MCP integration. ### Current limitation REA's IDA provider is contract-bound to [`mrexodia/ida-pro-mcp`](https://github.com/mrexodia/ida-pro-mcp). The **official Hex-Rays server** ([`HexRaysSA/ida-mcp`](https://github.com/HexRaysSA/ida-mcp), announced 2026-09-25, latest release `v20261008.0.1`) cannot drive it: the two expose **disjoint tool surfaces — not a single name overlaps**. `docs/ida-provider.md` scopes the adapter explicitly: > REA adapts an existing mrexodia/ida-pro-mcp server into its native analysis tools. […] REA does not install, upgrade, activate, or license them, and does not bundle another IDA server. **Upstream tools REA calls** (`src/ida/IdaSessionClient.ts`, `src/ida/IdaOperationRunner.ts`): ``` get_metadata, list_functions, list_funcs, decompile_function, disassemble_function, get_function_by_address, get_function_by_name, get_xrefs_to, xrefs_to, get_callers, get_callees, list_strings, idb_open, idb_list, idb_close ``` **Tools the official server exposes** (`ida_mcp/mcp.py` — module docstring and `@tool` registrations, `v20261008.0.1`): ``` open_database, execute_python, reference, list_databases, save_database, close_database ``` **Intersection: empty.** Setting `REA_IDA_MCP_CONFIG` to the official registration does connect, but every REA operation resolves to an unknown upstream tool. The two differ by design, not only by naming: | | mrexodia/ida-pro-mcp (currently supported) | Hex-Rays official `ida-mcp` | | --- | --- | --- | | surface | typed semantic tools (`decompile_function`, `list_functions`, …) | attach a database, run IDAPython, query an API reference | | who picks the operation | REA | the agent, writing IDAPython against `reference` | | base library | upstream's own IDA bridge | `ida-nexus>=0.13.4` | ### Use cases 1. **Avoid running two IDA MCP servers.** Hex-Rays' own install instructions say: *"We recommend disabling other IDA MCP servers to reduce agent confusion."* A user on IDA 9.4+ who installed the official server via `uvx ida-hcli mcp install` currently has to keep `mrexodia/ida-pro-mcp` alongside it just to satisfy REA — directly against vendor guidance. 2. **Vendor-maintained tooling.** The official server ships through the IDA install path (`hcli mcp install`, or `uvx ida-mcp stdio --agent=<agent>`), so setup and updates follow Hex-Rays rather than a third-party repo. 3. **Headless parity.** The official server works headlessly without the GUI plugin, which maps onto REA's existing headless IDA profile intent. 4. **Same analyst workflow.** Attach an already-open GUI database, or hand REA a local binary, and keep REA's provider-neutral operations and evidence contract — without changing which IDA MCP the user has installed. ### Desired outcome and success criteria - A **second IDA provider profile** (e.g. `ida-official` / `ida-nexus`) selectable through `REA_ANALYSIS_PROVIDER`, the CLI's `--provider`, or MCP's `open_binary.provider_id`, leaving the existing mrexodia profile untouched. - REA's provider-neutral operations map onto the official surface. Since there is no `decompile_function` upstream, this most likely means implementing the semantic operations on top of `execute_python` + `reference` rather than forwarding tools 1:1 — that trade-off is the main thing to decide. - The same guarantees as the current profile: target-identity match against the recorded input hash, image-base checks around each request, live (non-replayed) results, and **never saving or closing the user's database**. - Actionable failure when a configured server matches no known contract: report the detected tool set and the contract REA expected, instead of a generic unknown-tool error. ### Authority boundaries and non-goals - REA should not install, upgrade, activate, or license the official server; that stays with `hcli mcp install` / the user, consistent with the current bring-your-own stance. - Prerequisites worth documenting: IDA **9.4+ with idalib**, Python **3.11+**, and `uv` + Git on `PATH`. - **`execute_python` executes arbitrary code inside IDA's process.** That is a materially wider authority than the current typed-tool adapter, and it deserves an explicit decision rather than being folded into implementation. A read-only or allowlisted posture would be worth stating if that is the intent. - Not a non-goal, but adjacent: the official server also exposes `save_database`, which the current adapter's "never mutate the user's database" stance deliberately avoids. ### Alternatives considered - **Status quo (mrexodia only).** Works, and is what `#747` scoped deliberately. It leaves official-server users running two IDA MCP servers, against vendor guidance. - **Drive `execute_python` outside REA's provider layer**, letting the agent run IDAPython directly. Cheapest, but drops REA's target-identity checks and evidence provenance, which is the reason the adapter exists. - **Ask Hex-Rays for a compatibility shim** exposing the mrexodia tool names. Out of REA's control and unlikely. ### Additional context - Verified against official `ida-mcp` **`v20261008.0.1`** (released 2026-10-08). Tool names extracted from `ida_mcp/mcp.py` at `main`; REA's expected upstream names read from `src/ida/*` and `docs/ida-provider.md` at `main`. - Prior art: `#747` established the IDA provider and explicitly scoped it to mrexodia/ida-pro-mcp. This request does not reopen that decision — it asks for the official server as an **additional** profile. - Related: `#1389` (rsleigh as a headless provider candidate) suggests new provider candidates are evaluated on their own merits, which is the model this request follows.
Author
Owner

@elkahtersidi commented on GitHub (Oct 11, 2026):

Cv

<!-- gh-comment-id:6105056897 --> @elkahtersidi commented on GitHub (Oct 11, 2026): Cv
Author
Owner

@NaiJii commented on GitHub (Oct 17, 2026):

I've implemented this as an additional profile of the existing IDA provider in #4813. Since it runs code through execute_python, it needs a scope decision here before integration, per CONTRIBUTING's fail-closed rule.

Approach

  • A registration with "mode": "headless" and "protocol": "hexrays" (stdio only) selects the profile. The provider id stays ida, so REA_ANALYSIS_PROVIDER, --provider ida and open_binary.provider_id work unchanged, and the mrexodia profiles are untouched.
  • REA copies the target into its private workspace and calls open_database(path, set_current=false) on that copy. It binds the session only when the reply reports an idalib backend and list_databases shows that lease for the copy. A GUI backend is refused.
  • Every read goes through execute_python, but REA only ever sends one fixed, packaged module, bridge/ida/hexrays_queries.py, followed by _rea_query("<name>", "<json>"). Caller input reaches it only as JSON data; the generated line is round-trip tested with adversarial names.
    • The module only reads: functions, lookup, strings, paged pseudocode and assembly, callees, a depth-zero call graph, xrefs, and segments. It never renames, retypes, patches, saves or navigates.
    • Its replies use the database-supervisor shapes REA already validates, so the existing runner, coverage and limitations are reused.
    • Each observation records execute_python, the query name and arguments, and the module's SHA-256.
  • Close calls close_database, then requires list_databases to show neither the lease nor the copy. A rejected close is retried, and a late lease after a lost open reply is adopted and released. REA never calls save_database.

Against the success criteria above

Criterion Status
Second profile, mrexodia profile untouched Yes. It's selected by protocol: "hexrays" in the registration, like the native profile, rather than by a new provider id.
Semantic operations built on execute_python instead of 1:1 forwarding Yes, through the fixed module.
Read-only or allowlisted posture Yes. Only the packaged module runs, and no caller Python is forwarded, consistent with #747's non-goal.
Target identity and image-base checks; live results; never save or close the user's database Yes. These are the headless profile's checks on the private copy.
Attach an already-open GUI database (use case 4) No. REA can't prove it owns a GUI lease, so this is left for a follow-up decision.
Actionable failure on a contract mismatch Yes. Errors report advertised_tools; a protocol-less registration that reaches the Hex-Rays server is told to set "protocol": "hexrays".
Documented prerequisites Yes: IDA 9.4+ with idalib, Python 3.11+, uv and Git.

Effects

  • Reads the target and REA's private copy.
  • Launches the registered ida-mcp stdio server and its idalib worker. The target is never executed.
  • Runs REA's fixed module inside IDA.
  • Writes only inside REA's private workspace: the copy, plus the .i64 that Hex-Rays packs on release. REA deletes the workspace afterwards.
  • Upstream also writes its own session traces under ~/.idapro/mcp/sessions/.
  • REA makes no network calls. Upstream may: uvx package resolution, and IDA licensing depending on the license type.

Verification

  • Unit tests:
    • lifecycle, failure and cleanup paths against a stateful Hex-Rays fixture
    • stdlib tests for the module, run against IDA module stand-ins
  • npm run verify:ida passed on Linux x64 with Hex-Rays IDA MCP 20261008.0.1, on three ELF fixtures:
    • x86-64, with an --expected-xref oracle
    • x86-64 plus a string literal, with an --expected-string oracle
    • AArch64, which exercises the call-graph callee path
  • Each run also checked that no file appears next to the original target.
  • Not yet verified: PE and Mach-O targets, macOS and Windows hosts, and very large binaries.

Questions for a scope decision

  1. Is a fixed, packaged, read-only module executed through execute_python within scope, given that REA never forwards caller Python?
  2. Is stdio-only the right boundary? Hex-Rays leases belong to the server process, so ownership is only provable when REA launches its own server.
  3. Hex-Rays has no "close without saving". Is it acceptable that it packs the private copy's database before REA deletes the workspace?
  4. Should attaching to a GUI database (use case 4) stay out of scope for now?
<!-- gh-comment-id:6235254300 --> @NaiJii commented on GitHub (Oct 17, 2026): I've implemented this as an additional profile of the existing IDA provider in #4813. Since it runs code through `execute_python`, it needs a scope decision here before integration, per CONTRIBUTING's fail-closed rule. ### Approach - A registration with `"mode": "headless"` and `"protocol": "hexrays"` (stdio only) selects the profile. The provider id stays `ida`, so `REA_ANALYSIS_PROVIDER`, `--provider ida` and `open_binary.provider_id` work unchanged, and the mrexodia profiles are untouched. - REA copies the target into its private workspace and calls `open_database(path, set_current=false)` on that copy. It binds the session only when the reply reports an `idalib` backend and `list_databases` shows that lease for the copy. A GUI backend is refused. - Every read goes through `execute_python`, but REA only ever sends one fixed, packaged module, `bridge/ida/hexrays_queries.py`, followed by `_rea_query("<name>", "<json>")`. Caller input reaches it only as JSON data; the generated line is round-trip tested with adversarial names. - The module only reads: functions, lookup, strings, paged pseudocode and assembly, callees, a depth-zero call graph, xrefs, and segments. It never renames, retypes, patches, saves or navigates. - Its replies use the database-supervisor shapes REA already validates, so the existing runner, coverage and limitations are reused. - Each observation records `execute_python`, the query name and arguments, and the module's SHA-256. - Close calls `close_database`, then requires `list_databases` to show neither the lease nor the copy. A rejected close is retried, and a late lease after a lost open reply is adopted and released. REA never calls `save_database`. ### Against the success criteria above | Criterion | Status | | --- | --- | | Second profile, mrexodia profile untouched | Yes. It's selected by `protocol: "hexrays"` in the registration, like the native profile, rather than by a new provider id. | | Semantic operations built on `execute_python` instead of 1:1 forwarding | Yes, through the fixed module. | | Read-only or allowlisted posture | Yes. Only the packaged module runs, and no caller Python is forwarded, consistent with #747's non-goal. | | Target identity and image-base checks; live results; never save or close the user's database | Yes. These are the headless profile's checks on the private copy. | | Attach an already-open GUI database (use case 4) | No. REA can't prove it owns a GUI lease, so this is left for a follow-up decision. | | Actionable failure on a contract mismatch | Yes. Errors report `advertised_tools`; a protocol-less registration that reaches the Hex-Rays server is told to set `"protocol": "hexrays"`. | | Documented prerequisites | Yes: IDA 9.4+ with idalib, Python 3.11+, `uv` and Git. | ### Effects - Reads the target and REA's private copy. - Launches the registered `ida-mcp` stdio server and its idalib worker. The target is never executed. - Runs REA's fixed module inside IDA. - Writes only inside REA's private workspace: the copy, plus the `.i64` that Hex-Rays packs on release. REA deletes the workspace afterwards. - Upstream also writes its own session traces under `~/.idapro/mcp/sessions/`. - REA makes no network calls. Upstream may: `uvx` package resolution, and IDA licensing depending on the license type. ### Verification - Unit tests: - lifecycle, failure and cleanup paths against a stateful Hex-Rays fixture - stdlib tests for the module, run against IDA module stand-ins - `npm run verify:ida` passed on Linux x64 with Hex-Rays IDA MCP 20261008.0.1, on three ELF fixtures: - x86-64, with an `--expected-xref` oracle - x86-64 plus a string literal, with an `--expected-string` oracle - AArch64, which exercises the call-graph callee path - Each run also checked that no file appears next to the original target. - Not yet verified: PE and Mach-O targets, macOS and Windows hosts, and very large binaries. ### Questions for a scope decision 1. Is a fixed, packaged, read-only module executed through `execute_python` within scope, given that REA never forwards caller Python? 2. Is stdio-only the right boundary? Hex-Rays leases belong to the server process, so ownership is only provable when REA launches its own server. 3. Hex-Rays has no "close without saving". Is it acceptable that it packs the private copy's database before REA deletes the workspace? 4. Should attaching to a GUI database (use case 4) stay out of scope for now?
Author
Owner

@MarkDDi commented on GitHub (Oct 27, 2026):

When can we enter the main branch?

<!-- gh-comment-id:6440621228 --> @MarkDDi commented on GitHub (Oct 27, 2026): When can we enter the main branch?
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#485
No description provided.