[GH-ISSUE #2301] IDA provider rejects upstream ida-pro-mcp 2.0.0 in both attached and headless modes #763

Closed
opened 2026-10-15 18:28:06 +00:00 by bsakaguchi · 6 comments
Owner

Originally created by @vt0x78 on GitHub (Oct 12, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/2301

Summary

REA 6.4.0 cannot use mrexodia/ida-pro-mcp at its current main (version 2.0.0). Both compatibility profiles in IdaSessionClient fail the startup tool check, so no analysis ever runs.

This matters because installing from GitHub is the upstream project's documented method, so anyone following it today lands on 2.0.0. The last tagged upstream release is still 1.4.0, which is the only version the attached profile accepts.

What I observed

#initialize() compares the names from tools/list against legacyTools or modernTools and throws when any are missing.

Attached mode expects the 1.4 names (get_metadata, list_functions, get_function_by_name, decompile_function, disassemble_function, get_callers, get_callees, get_xrefs_to). The 2.0.0 GUI plugin exposes none of them. It ships a redesigned set instead, including server_health, lookup_funcs, list_funcs, decompile, disasm, callees, xrefs_to, find_regex.

Headless mode is much closer. Against idalib-mcp --stdio, ten of the eleven entries in modernTools are present. The only missing one is idb_close. Searching the installed 2.0.0 idalib_supervisor.py for that string returns nothing, and the supervisor declares only idb_open and idb_list as its session lifecycle tools.

So headless support is one tool away, but it is not a trivial rename. #closeDatabase() calls idb_close and then verifies the response reports owned: true, saved: false and backend: "worker". If upstream has no close tool at all, that release contract has no equivalent to map onto, and deciding what should replace it looks like a maintainer call rather than something to guess at in a patch.

Diagnosability

The failure is hard to trace back to its cause. AnalysisProtocolError names exactly which tools are missing, but running rea decompile against a 2.0.0 GUI instance prints only this:

code: unreadable_output
category: execution_failure
message: "Analysis returned an unreadable result. Retry once; if it continues, run `rea doctor`."

Nothing points at a version or profile mismatch. rea doctor does not help either, since it reports the IDA registration as healthy:

ida-registration  ok: true  classification: healthy
detail: "IDA MCP registration is valid. Upstream availability, compatibility, and target binding
are checked when analysis starts; no IDA process was launched."

That line is accurate, but combined with the generic runtime error it points away from the real problem. I only found the cause by logging the JSON-RPC traffic between REA and the proxy, where the exchange stops right after tools/list.

Surfacing the missing tool names in the CLI output would have turned a long debugging session into a quick fix, and that part seems worth addressing regardless of which versions end up supported.

Reproducing

  1. Install upstream from GitHub main, which currently builds 2.0.0.
  2. Start the MCP server in the IDA GUI, or run idalib-mcp --stdio for headless.
  3. Point REA_IDA_MCP_CONFIG at the registration and run any native analysis with REA_ANALYSIS_PROVIDER=ida.
  4. Analysis fails before any tool call. A stdio log shows initialize and tools/list succeeding, then nothing.

Tested with REA 6.4.0, IDA Professional 9.1 on Windows, upstream 2.0.0.

Workaround

For anyone hitting this before it is resolved, upstream 1.4.0 from PyPI still works with the attached profile. Its plugin file is self contained, so it can be dropped into the IDA plugins directory next to a 2.0.0 install rather than replacing it. Two things to watch for. The 1.4 plugin hardcodes its bind address and port, so a second instance needs those edited. The 1.4 proxy also needs mcp<2 pinned, since FastMCP was renamed in the 2.x Python SDK and server.py fails to import without it.

Suggestion

Three things that would each help on their own:

  1. Include the missing tool names in the error that reaches the CLI, so the mismatch is visible without packet logging.
  2. Have doctor probe the live tool list and report the detected profile, rather than validating the registration shape alone.
  3. Document which upstream versions each profile targets. The docs describe attached mode as requiring the legacy 1.4 profile, but nothing says that current main is unsupported, which is what most people will install.

Happy to help with a patch for the error reporting and docs if that would be useful. I left the lifecycle question alone since the right answer depends on what upstream intends to offer in place of idb_close.

Originally created by @vt0x78 on GitHub (Oct 12, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/2301 ## Summary REA 6.4.0 cannot use `mrexodia/ida-pro-mcp` at its current `main` (version 2.0.0). Both compatibility profiles in `IdaSessionClient` fail the startup tool check, so no analysis ever runs. This matters because installing from GitHub is the upstream project's documented method, so anyone following it today lands on 2.0.0. The last tagged upstream release is still 1.4.0, which is the only version the attached profile accepts. ## What I observed `#initialize()` compares the names from `tools/list` against `legacyTools` or `modernTools` and throws when any are missing. **Attached mode** expects the 1.4 names (`get_metadata`, `list_functions`, `get_function_by_name`, `decompile_function`, `disassemble_function`, `get_callers`, `get_callees`, `get_xrefs_to`). The 2.0.0 GUI plugin exposes none of them. It ships a redesigned set instead, including `server_health`, `lookup_funcs`, `list_funcs`, `decompile`, `disasm`, `callees`, `xrefs_to`, `find_regex`. **Headless mode** is much closer. Against `idalib-mcp --stdio`, ten of the eleven entries in `modernTools` are present. The only missing one is `idb_close`. Searching the installed 2.0.0 `idalib_supervisor.py` for that string returns nothing, and the supervisor declares only `idb_open` and `idb_list` as its session lifecycle tools. So headless support is one tool away, but it is not a trivial rename. `#closeDatabase()` calls `idb_close` and then verifies the response reports `owned: true`, `saved: false` and `backend: "worker"`. If upstream has no close tool at all, that release contract has no equivalent to map onto, and deciding what should replace it looks like a maintainer call rather than something to guess at in a patch. ## Diagnosability The failure is hard to trace back to its cause. `AnalysisProtocolError` names exactly which tools are missing, but running `rea decompile` against a 2.0.0 GUI instance prints only this: ``` code: unreadable_output category: execution_failure message: "Analysis returned an unreadable result. Retry once; if it continues, run `rea doctor`." ``` Nothing points at a version or profile mismatch. `rea doctor` does not help either, since it reports the IDA registration as healthy: ``` ida-registration ok: true classification: healthy detail: "IDA MCP registration is valid. Upstream availability, compatibility, and target binding are checked when analysis starts; no IDA process was launched." ``` That line is accurate, but combined with the generic runtime error it points away from the real problem. I only found the cause by logging the JSON-RPC traffic between REA and the proxy, where the exchange stops right after `tools/list`. Surfacing the missing tool names in the CLI output would have turned a long debugging session into a quick fix, and that part seems worth addressing regardless of which versions end up supported. ## Reproducing 1. Install upstream from GitHub `main`, which currently builds 2.0.0. 2. Start the MCP server in the IDA GUI, or run `idalib-mcp --stdio` for headless. 3. Point `REA_IDA_MCP_CONFIG` at the registration and run any native analysis with `REA_ANALYSIS_PROVIDER=ida`. 4. Analysis fails before any tool call. A stdio log shows `initialize` and `tools/list` succeeding, then nothing. Tested with REA 6.4.0, IDA Professional 9.1 on Windows, upstream 2.0.0. ## Workaround For anyone hitting this before it is resolved, upstream 1.4.0 from PyPI still works with the attached profile. Its plugin file is self contained, so it can be dropped into the IDA plugins directory next to a 2.0.0 install rather than replacing it. Two things to watch for. The 1.4 plugin hardcodes its bind address and port, so a second instance needs those edited. The 1.4 proxy also needs `mcp<2` pinned, since `FastMCP` was renamed in the 2.x Python SDK and `server.py` fails to import without it. ## Suggestion Three things that would each help on their own: 1. Include the missing tool names in the error that reaches the CLI, so the mismatch is visible without packet logging. 2. Have `doctor` probe the live tool list and report the detected profile, rather than validating the registration shape alone. 3. Document which upstream versions each profile targets. The docs describe attached mode as requiring the legacy 1.4 profile, but nothing says that current `main` is unsupported, which is what most people will install. Happy to help with a patch for the error reporting and docs if that would be useful. I left the lifecycle question alone since the right answer depends on what upstream intends to offer in place of `idb_close`.
bsakaguchi 2026-10-15 18:28:06 +00:00
Author
Owner

@nikolay-dementiev commented on GitHub (Oct 12, 2026):

The headless supervisor at upstream main (mrexodia/ida-pro-mcp c133c38, pyproject.toml version 2.0.0) does serve idb_close: src/ida_pro_mcp/idalib_supervisor.py defines idb_close(database, save=True), added by mrexodia/ida-pro-mcp#495. REA's headless profile works against that build on real IDA Professional 9.1 (macOS arm64): open, every read operation, idb_close with save: false and workspace cleanup. The version string did not change when idb_close was added, so a 2.0.0 install built before #495 lacks it. Reinstalling from current main provides it. The attached-mode findings above are unaffected.

<!-- gh-comment-id:6132835702 --> @nikolay-dementiev commented on GitHub (Oct 12, 2026): The headless supervisor at upstream `main` (mrexodia/ida-pro-mcp c133c38, `pyproject.toml` version 2.0.0) does serve `idb_close`: `src/ida_pro_mcp/idalib_supervisor.py` defines `idb_close(database, save=True)`, added by mrexodia/ida-pro-mcp#495. REA's headless profile works against that build on real IDA Professional 9.1 (macOS arm64): open, every read operation, `idb_close` with `save: false` and workspace cleanup. The version string did not change when `idb_close` was added, so a 2.0.0 install built before #495 lacks it. Reinstalling from current `main` provides it. The attached-mode findings above are unaffected.
Author
Owner

@matbrgz commented on GitHub (Oct 12, 2026):

Triage & Profile Evolution Notes

Upstream mrexodia/ida-pro-mcp v2.0.0 represents a significant tool renaming overhaul compared to v1.4.0 (get_functions -> list_funcs, decompile_function -> decompile, get_callers -> callers).

  • Multi-Profile Strategy: Per REA provider guidelines, support for ida-pro-mcp should be version-profiled rather than mutating the legacy contract in place:
    • Keep v1 attached profile for 1.4.x setups.
    • Introduce an explicit v2 profile in IdaSessionClient mapping the v2 tool names into REA's internal IDA adapter primitives.
    • Ensure headless mode handles the missing idalib tool omissions by falling back gracefully or declaring capability_unavailable for absent GUI-only tools.
<!-- gh-comment-id:6134273095 --> @matbrgz commented on GitHub (Oct 12, 2026): ### Triage & Profile Evolution Notes Upstream `mrexodia/ida-pro-mcp` v2.0.0 represents a significant tool renaming overhaul compared to v1.4.0 (`get_functions` -> `list_funcs`, `decompile_function` -> `decompile`, `get_callers` -> `callers`). - **Multi-Profile Strategy:** Per REA provider guidelines, support for `ida-pro-mcp` should be version-profiled rather than mutating the legacy contract in place: - Keep `v1` attached profile for 1.4.x setups. - Introduce an explicit `v2` profile in `IdaSessionClient` mapping the v2 tool names into REA's internal IDA adapter primitives. - Ensure headless mode handles the missing `idalib` tool omissions by falling back gracefully or declaring `capability_unavailable` for absent GUI-only tools.
Author
Owner

@akushonkamen commented on GitHub (Oct 14, 2026):

Confirmed against main@131b2d85f — I'll take this with a focused fix for the attached-mode half plus a diagnosable headless error.

Root cause (src/ida/IdaSessionClient.ts, verified at HEAD):

  • #initialize() picks the expected tool profile three-way (src/ida/IdaSessionClient.ts:519-524): attached → legacyTools (hardcoded 1.4 names at :53-64), headless → modernTools. There is no profile for upstream 2.x, so a 2.0.0 attached instance has zero intersection with legacyTools, missing.length > 0 (:525) throws ProviderAdapterError (:530) and startup dies before any tool call.
  • Headless only fails on idb_close (:68), which 2.0.0 builds predating mrexodia/ida-pro-mcp#495 lack.

Plan: add an explicit v2 attached profile selected by probing the served tools/list (legacy stays compatibility-first), route v2 attached metadata observation through server_health/the existing health schema path (:642-647) instead of get_metadata/legacyMetadataSchema (:620-631), and make the headless mismatch name the required build (post-#495) so it is diagnosable instead of guessable. Followed up with unit tests mocking a 2.0.0 tool list.

Assisted-by: AI (Claude Code); I verified the diagnosis and will run the tests myself.

<!-- gh-comment-id:6161801194 --> @akushonkamen commented on GitHub (Oct 14, 2026): Confirmed against `main`@`131b2d85f` — I'll take this with a focused fix for the attached-mode half plus a diagnosable headless error. **Root cause** (`src/ida/IdaSessionClient.ts`, verified at HEAD): - `#initialize()` picks the expected tool profile three-way (`src/ida/IdaSessionClient.ts:519-524`): attached → `legacyTools` (hardcoded 1.4 names at `:53-64`), headless → `modernTools`. There is no profile for upstream 2.x, so a 2.0.0 attached instance has zero intersection with `legacyTools`, `missing.length > 0` (`:525`) throws `ProviderAdapterError` (`:530`) and startup dies before any tool call. - Headless only fails on `idb_close` (`:68`), which 2.0.0 builds predating mrexodia/ida-pro-mcp#495 lack. **Plan**: add an explicit v2 attached profile selected by probing the served `tools/list` (legacy stays compatibility-first), route v2 attached metadata observation through `server_health`/the existing health schema path (`:642-647`) instead of `get_metadata`/`legacyMetadataSchema` (`:620-631`), and make the headless mismatch name the required build (post-#495) so it is diagnosable instead of guessable. Followed up with unit tests mocking a 2.0.0 tool list. Assisted-by: AI (Claude Code); I verified the diagnosis and will run the tests myself.
Author
Owner

@akushonkamen commented on GitHub (Oct 14, 2026):

Follow-up to my claim above, with a scope correction.

While preparing the patch I found that docs/ida-provider.md on current main (commit a688c7978, "docs(ida): describe catalog-based lifecycle compatibility") now documents the attached-mode refusal as deliberate: REA "has not established an equivalent attached-mode lifecycle and ownership contract for that catalog" and fails closed, with real attached 2.0.0 workflows required before support is claimed. So I am retracting the attached-mode half of my plan — a v2 profile PR from me would contradict a decision the maintainer documented hours ago, and I cannot run the real IDA verification that docs/ida-provider.md requires for it.

For the record, one upstream fact that may help if that contract is ever established: in the 2.0.0 GUI plugin (src/ida_pro_mcp/ida_mcp/api_core.py at upstream c133c385), server_health (_build_health_payload) already returns status, input_path, idb_path, module, imagebase, auto_analysis_ready — field-for-field the shape of REA's existing modernHealthSchema — so attached identity binding would not need a new upstream surface, only real-GUI verification of the lifecycle contract.

What I am contributing instead is the headless diagnosability slice from the issue's suggestion 1, aligned with the catalog-based documentation: when a headless supervisor is missing only idb_close, the startup error now names the upstream build that added it (mrexodia/ida-pro-mcp#495) in the summary, the recovery hint, and a new upstream_requirement diagnostic — turning "missing tools: idb_close" into "reinstall from a post-#495 build", which is the actual fix per @nikolay-dementiev's finding. Fail-closed behavior is unchanged. Patch is ready locally with tests; PR to follow.

Assisted-by: AI (Claude Code); diagnosis and tests verified by me.

<!-- gh-comment-id:6161966461 --> @akushonkamen commented on GitHub (Oct 14, 2026): Follow-up to my claim above, with a scope correction. While preparing the patch I found that `docs/ida-provider.md` on current `main` (commit a688c7978, "docs(ida): describe catalog-based lifecycle compatibility") now documents the attached-mode refusal as deliberate: REA "has not established an equivalent attached-mode lifecycle and ownership contract for that catalog" and fails closed, with real attached 2.0.0 workflows required before support is claimed. So I am retracting the attached-mode half of my plan — a v2 profile PR from me would contradict a decision the maintainer documented hours ago, and I cannot run the real IDA verification that docs/ida-provider.md requires for it. For the record, one upstream fact that may help if that contract is ever established: in the 2.0.0 GUI plugin (`src/ida_pro_mcp/ida_mcp/api_core.py` at upstream `c133c385`), `server_health` (`_build_health_payload`) already returns `status`, `input_path`, `idb_path`, `module`, `imagebase`, `auto_analysis_ready` — field-for-field the shape of REA's existing `modernHealthSchema` — so attached identity binding would not need a new upstream surface, only real-GUI verification of the lifecycle contract. What I am contributing instead is the headless diagnosability slice from the issue's suggestion 1, aligned with the catalog-based documentation: when a headless supervisor is missing only `idb_close`, the startup error now names the upstream build that added it (`mrexodia/ida-pro-mcp#495`) in the summary, the recovery hint, and a new `upstream_requirement` diagnostic — turning "missing tools: idb_close" into "reinstall from a post-#495 build", which is the actual fix per @nikolay-dementiev's finding. Fail-closed behavior is unchanged. Patch is ready locally with tests; PR to follow. Assisted-by: AI (Claude Code); diagnosis and tests verified by me.
Author
Owner

@akushonkamen commented on GitHub (Oct 14, 2026):

The fix is complete and re-verified against current main, but it has to be delivered via this comment instead of a PR: attempting to open one is currently rejected server-side for my account (CreatePullRequest → FORBIDDEN, REST returns 404), which looks like the repo's pull-request creation policy or a rate-control measure rather than anything branch-specific. I won't keep retrying against the repo's wishes.

Delivered: branch fix/2301-headless-idb-close-build-hint on my fork @ 14edd6b5a, rebased onto origin/main @ 7375ab6e3 (two files: src/ida/IdaSessionClient.ts, src/ida/IdaSessionClient.test.ts). It implements item 3 from my claim above: when the headless profile misses idb_close, the initialize error names mrexodia/ida-pro-mcp#495 in the summary, the recovery hint, and a new upstream_requirement diagnostic. Fail-closed behavior, the expected profile, and missing_tools are unchanged. The attached v2 profile (items 1–2) stays withdrawn per my follow-up.

Re-run on the rebased branch, as measured here:

  • npx vitest run src/ida/IdaSessionClient.test.ts --testTimeout=20000 -t "names every missing tool" against the pre-fix implementation — 1 failed | 59 skipped (60); with the fix applied, the full file passes 60/60.
  • npx vitest run tests/composition/idaProvider.test.ts src/ida/IdaBusyHealth.test.ts --testTimeout=20000 — 9/9 passed.
  • npm run verify:test-discovery — 1246 test files discovered exactly once; npm run verify:module-boundaries — 1861 source files (both counts grew from 1244/1859 because main added files; re-measured after the rebase).
  • npx oxfmt --check on the two changed files — clean; npx oxlint — 5 warnings / 0 errors, identical to the clean tree; npx tsc --noEmit — clean after npm ci synced the stale node_modules. The 4 pre-existing saxes/cborg errors reproduced identically on a clean origin/main worktree first, confirming they were environmental and unrelated to this change.

The branch stays available — happy to open the PR once policy allows, or maintainers can pull the branch directly. Investigated with AI assistance, as before.

<!-- gh-comment-id:6162387310 --> @akushonkamen commented on GitHub (Oct 14, 2026): The fix is complete and re-verified against current `main`, but it has to be delivered via this comment instead of a PR: attempting to open one is currently rejected server-side for my account (`CreatePullRequest` → FORBIDDEN, REST returns 404), which looks like the repo's pull-request creation policy or a rate-control measure rather than anything branch-specific. I won't keep retrying against the repo's wishes. **Delivered:** branch [`fix/2301-headless-idb-close-build-hint`](https://github.com/akushonkamen/rea/tree/fix/2301-headless-idb-close-build-hint) on my fork @ `14edd6b5a`, rebased onto `origin/main` @ `7375ab6e3` (two files: `src/ida/IdaSessionClient.ts`, `src/ida/IdaSessionClient.test.ts`). It implements item 3 from [my claim above](https://github.com/morluto/rea/issues/2301#issuecomment-6161801194): when the headless profile misses `idb_close`, the initialize error names `mrexodia/ida-pro-mcp#495` in the summary, the recovery hint, and a new `upstream_requirement` diagnostic. Fail-closed behavior, the expected profile, and `missing_tools` are unchanged. The attached v2 profile (items 1–2) stays withdrawn per [my follow-up](https://github.com/morluto/rea/issues/2301#issuecomment-6161966461). Re-run on the rebased branch, as measured here: - `npx vitest run src/ida/IdaSessionClient.test.ts --testTimeout=20000 -t "names every missing tool"` against the pre-fix implementation — 1 failed | 59 skipped (60); with the fix applied, the full file passes 60/60. - `npx vitest run tests/composition/idaProvider.test.ts src/ida/IdaBusyHealth.test.ts --testTimeout=20000` — 9/9 passed. - `npm run verify:test-discovery` — 1246 test files discovered exactly once; `npm run verify:module-boundaries` — 1861 source files (both counts grew from 1244/1859 because `main` added files; re-measured after the rebase). - `npx oxfmt --check` on the two changed files — clean; `npx oxlint` — 5 warnings / 0 errors, identical to the clean tree; `npx tsc --noEmit` — clean after `npm ci` synced the stale `node_modules`. The 4 pre-existing `saxes`/`cborg` errors reproduced identically on a clean `origin/main` worktree first, confirming they were environmental and unrelated to this change. The branch stays available — happy to open the PR once policy allows, or maintainers can pull the branch directly. Investigated with AI assistance, as before.
Author
Owner

@morluto commented on GitHub (Oct 14, 2026):

Thanks for the report and the follow-up verification. The original “2.0.0 is rejected in both modes” description no longer matches the supported boundary: current headless supervisor builds that serve idb_open, idb_list, and idb_close are supported, while older builds with the same 2.0.0 version string but no idb_close are rejected with the missing tool and expected profile reported. The current requirements and recovery are documented in docs/ida-provider.md.

Attached-mode 2.0.0 remains intentionally unsupported because REA has not verified an equivalent attached GUI lifecycle and ownership contract; the adapter fails closed rather than inferring support from renamed tools. Supporting that catalog would need a separate scope decision and real attached-mode verification. Since neither failure is an undisclosed compatibility bug on the current supported boundary, Closing this report as clarified supported-build requirements. This does not claim attached v2 support or compatibility with older headless builds missing idb_close.

<!-- gh-comment-id:6179626221 --> @morluto commented on GitHub (Oct 14, 2026): Thanks for the report and the follow-up verification. The original “2.0.0 is rejected in both modes” description no longer matches the supported boundary: current headless supervisor builds that serve `idb_open`, `idb_list`, and `idb_close` are supported, while older builds with the same `2.0.0` version string but no `idb_close` are rejected with the missing tool and expected profile reported. The current requirements and recovery are documented in [docs/ida-provider.md](https://github.com/morluto/rea/blob/main/docs/ida-provider.md#supported-upstream-versions). Attached-mode 2.0.0 remains intentionally unsupported because REA has not verified an equivalent attached GUI lifecycle and ownership contract; the adapter fails closed rather than inferring support from renamed tools. Supporting that catalog would need a separate scope decision and real attached-mode verification. Since neither failure is an undisclosed compatibility bug on the current supported boundary, Closing this report as clarified supported-build requirements. This does not claim attached v2 support or compatibility with older headless builds missing `idb_close`.
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#763
No description provided.