Reverse-engineer several binaries at once — dropper, payload, C2 — through a single MCP endpoint.
Each plugin-equipped IDA Pro database auto-registers when opened · headless idalib sessions · local, stripping-resistant function similarity across binaries.
Install · In action · Why · Upstream · Architecture · Tools · Docs
--- ## Install in one prompt **Ask your AI agent to install it.** Copy-paste one of these — it matches IDA's Python version, drops the plugin in place, and registers the MCP server with your client. **Claude Code / Codex:** > Install and configure ida-multi-mcp by following the instructions here: https://raw.githubusercontent.com/MeroZemory/ida-multi-mcp/main/docs/installation.md **Cursor:** > @Web fetch https://raw.githubusercontent.com/MeroZemory/ida-multi-mcp/main/docs/installation.md and follow the installation steps. Then open your binaries in IDA Pro — instances register themselves — and talk to your agent. Prefer doing it by hand? See [Manual installation](#manual-installation). Removing it again is in [Troubleshooting](docs/troubleshooting.md#uninstallation). --- ## See it in action Two binaries open in two IDA windows. One MCP endpoint. No client config per binary. > *"Which function in dropper.dll is the same as `sub_140001000` in malware.exe?"* ```text → list_instances() k7m2 malware.exe x86_64 port 49152 px3a dropper.dll x86_64 port 49153 → analysis_wait(instance_id="px3a", timeout_sec=200) { "finished": true, "functions_added": 12884 } # 12,884 functions that did not exist a minute ago → index_functions(instance_id="k7m2") · index_functions(instance_id="px3a") { "indexed": 61044 } { "indexed": 73929 } → similar_functions(instance_id="k7m2", func="sub_140001000", scope="instances") 0.94 px3a sub_18000C120 high minhash 0.91 · anchors 0.97 · cfg 0.88 0.71 px3a sub_18000E440 medium minhash 0.68 · anchors 0.80 · cfg 0.64 → decompile(instance_id="px3a", addr="sub_18000C120") ... ``` Core instruction, anchor and CFG signals do not use function names, so stripping does not remove them. When both functions have meaningful symbols, pseudocode identifier tokens can also contribute. Scoring and inference run locally; no binary or IDB is uploaded. --- ## Why ida-multi-mcp| **Built for multi-binary work** - **Zero-configuration discovery** — every IDA Pro instance running the installed plugin registers into `~/.ida-mcp/instances.json` when a database opens; no per-binary client configuration - **Genuinely parallel across instances** — requests run on a worker pool. A call to instance B while instance A was busy: **3.41 s → 0.01 s** ([#27](https://github.com/MeroZemory/ida-multi-mcp/pull/27)) - **Headless idalib sessions** — `idalib_open` analyses a binary with no GUI, one isolated subprocess per session - **Cross-binary similarity (BCSD)** — patch diffing, library-function ID and variant hunting, with local scoring and indexes - **Short, stable instance IDs** — `k7m2`, `px3a`, with automatic binary-change detection | **Built so the agent does not lie to you** - **Analysis gating** — `analysis_status` / `analysis_wait` tell an agent whether IDA has actually settled, and the router warns on results from analysis-dependent tools while it has not ([why this matters](#the-one-rule-wait-for-auto-analysis)) - **Deadlines that reach into C** — a slow SDK call used to hold IDA's main thread past the tool timeout. The deadline now fires IDA's own `set_cancelled()`, and partial pages are labelled `cursor.cancelled` ([#28](https://github.com/MeroZemory/ida-multi-mcp/pull/28)) - **Actionable failure** — binary changes, stale instances and crashes come back as errors an agent can act on, not silence - **Localhost only** — loopback-bound with Host/Origin validation; no remote surface - **IDA 8.5–9.3** — `compat.py` shims APIs that moved between releases and warns on the builds that shipped without them |
finished is a snapshot, not a latch