Python MIT

IDA-instances-MCP

Custom build of ida-pro-mcp - stability-hardened MCP server for hosting headless IDA Pro instances

C

Claude-Reverser

Dernière activité 23 août 2026
Claude-Reverser/IDA-instances-MCP

460

étoiles

31

forks

0

issues ouvertes

Ce README est souvent en anglais.

IDA-instances-MCP

Custom build of ida-pro-mcp: an MCP Server that lets MCP clients drive IDA Pro — reworked with a stability pass aimed at hosting multiple headless idalib instances (the Ida-Instances setup).

This is a fork of mrexodia's ida-pro-mcp (MIT). All upstream credit goes to Duncan Ogilvie and contributors; the custom changes below are maintained in this repository.

What's custom

Stability hardening on top of upstream v2.0.0:

Area Change
Data safety Partial-database cleanup is ownership-aware: it never deletes .id0/.id1/.id2/.nam/.til files claimed by another live instance, and fails safe when discovery is unavailable
Save reliability idb_save runs with a 600s budget (was 60s); idb_close refuses to kill a worker after a failed save instead of silently discarding changes
Concurrency Supervisor lock no longer spans worker spawn (~120s), health probes (~2.5s/session) or stale-worker termination — one slow open can't freeze every session
Robustness Malformed JSON-RPC over stdio returns -32700/-32600 instead of crashing the proxy
Timeouts Proxy timeout raised 30s → 900s and made configurable (IDA_MCP_PROXY_TIMEOUT) so long decompiles don't "fail" client-side while still running server-side
Networking Worker port TOCTOU now retries; SSE writes and teardown are lock-guarded; CORS policy reads are cached off the IDA main thread
Resource limits IDB trace log capped at 64 MB (IDA_MCP_TRACE_MAX_MB) with oversized arguments/results clipped; flush-failure queue bounded
Authentication Every HTTP request requires an instance API key; issued exactly once via GET /key, then burned. The key persists on disk so it survives restarts and reboots
Hosting endpoints GET /health (unauthenticated readiness probe), GET /sessions (open databases + last-accessed), POST /upload (direct binary upload with size cap)
Idle reaping Sessions untouched for IDA_MCP_IDLE_TIMEOUT minutes are auto-closed (saved first)
Graceful shutdown On SIGTERM/SIGINT every open database is saved before exit — no more lost work on pct stop
Self-update Startup checks GitHub releases; interactive sessions are offered a one-keypress auto-update
Hosting defaults Headless supervisor listens on 0.0.0.0:9999; the GUI plugin also binds 0.0.0.0 and now requires the same API key

Requirements

  • Linux, macOS or Windows
  • Python 3.11+ (use idapyswitch inside IDA to match)
  • IDA Pro 8.3+ (9.x recommended). IDA Free is not supported
  • uv
  • An MCP client (Claude Code, Cursor, Codex, Opencode, VS Code, ...)

Setup

Activate idalib for your uv environment:

# linux (server deployment)
uv run "/opt/idapro-9.x/idalib/python/py-activate-idalib.py"
# macos
uv run "/Applications/IDA Professional 9.x.app/Contents/MacOS/idalib/python/py-activate-idalib.py"
# windows
uv run "C:\Program Files\IDA Professional 9.x\idalib\python\py-activate-idalib.py"

Headless runs additionally need the IDA install directory in IDADIR.

Run the headless supervisor (hosting mode)

uv run idalib-mcp                # serves http://0.0.0.0:9999/mcp (new default)

On startup an API key is generated (or loaded from disk) and every request without it gets 401 Unauthorized — no exceptions.

Fetch the key once, from the machine/network that owns the instance:

curl http://your-host:9999/key
# {"key": "3f2b..."}   <- save it; this endpoint is now burned until restart
  • The key persists at ~/.idapro/mcp/api_key (mode 0600) and survives reboots; GET /key re-issues it once per server start
  • Override with IDA_MCP_API_KEY (or relocate via IDA_MCP_API_KEY_FILE)
  • All other endpoints require it on every call:
Authorization: Bearer <key>
# or equivalently
X-API-Key: <key>

The key is never logged.

Hosting endpoints

Endpoint Auth Purpose
GET /health none Readiness probe: {"status":"ok","uptime":N,"sessions":N} — poll instead of sleeping
GET /sessions key Open databases incl. last-accessed timestamps
POST /upload?filename=NAME key Raw-body binary upload, streamed to IDA_MCP_UPLOAD_DIR; returns the path to feed idb_open
# provisioning flow
while ! curl -sf http://10.0.0.4:9999/health >/dev/null; do sleep 1; done
KEY=$(curl -s http://10.0.0.4:9999/key | jq -r .key)
curl -H "Authorization: Bearer $KEY" --data-binary @sample.elf \
     "http://10.0.0.4:9999/upload?filename=sample.elf"

Useful flags:

uv run idalib-mcp --host 127.0.0.1 --port 9999   # override bind address
uv run idalib-mcp --max-workers 8                # concurrent databases (default 4, 0 = unlimited)
uv run idalib-mcp --unsafe                       # enable destructive/debugger tools (DANGEROUS)
uv run idalib-mcp --profile tools.txt            # restrict worker tools to a profile file
uv run idalib-mcp --stdio                        # stdio transport instead of HTTP
uv run idalib-mcp path/to/binary                 # open a binary at startup

Session lifecycle tools: idb_open, idb_list, idb_close — open one database per session; each session gets its own isolated worker process.

Run the GUI proxy (interactive IDA)

Start the plugin inside IDA (Edit -> Plugins -> MCP, or Ctrl+Alt+M), then:

uv run ida-pro-mcp                                   # stdio proxy, auto-discovers IDA
uv run ida-pro-mcp --transport http://127.0.0.1:9999 # serve HTTP instead

Connect an MCP client

Generic JSON config (HTTP transport):

{
  "mcpServers": {
    "ida-instances": {
      "url": "http://your-host:9999/mcp",
      "headers": {
        "Authorization": "Bearer <key-from-/key>"
      }
    }
  }
}

Claude Code:

claude mcp add --transport http ida-instances http://your-host:9999/mcp \
  --header "Authorization: Bearer <key-from-/key>"

For the GUI proxy over stdio, run uv run ida-pro-mcp --config and paste the JSON into your client.

Configuration (environment variables)

Variable Default Meaning
IDA_MCP_OPEN_TIMEOUT 1800 Max seconds for open + auto-analysis before reap (0 = unlimited)
IDA_MCP_WORKER_CALL_TIMEOUT 900 Backstop per forwarded tool call
IDA_MCP_PROXY_TIMEOUT 900 GUI-proxy → IDA upstream timeout (0 = unlimited)
IDA_MCP_TRACE_MAX_MB 64 Trace log cap stored inside the IDB
IDA_MCP_MAX_WORKERS 4 Default --max-workers
IDA_MCP_HEALTH_TCP_TIMEOUT / IDA_MCP_HEALTH_RPC_TIMEOUT 2.0 / 10.0 Health probe budgets
IDA_MCP_IDLE_TIMEOUT 60 Minutes before an untouched session is auto-closed (0 disables)
IDA_MCP_MAX_UPLOAD_MB 100 Cap for POST /upload bodies
IDA_MCP_UPLOAD_DIR ~/.idapro/mcp/uploads Where uploads are stored
IDA_MCP_API_KEY / IDA_MCP_API_KEY_FILE – / ~/.idapro/mcp/api_key Inject or relocate the instance key
IDA_MCP_SHUTDOWN_SAVE_TIMEOUT / IDA_MCP_SHUTDOWN_SAVE_BUDGET 30 / 120 Per-database / total save budget on SIGTERM
IDA_MCP_NO_UPDATE_CHECK unset Set 1 to disable the GitHub release check

Security notes: the API key gates every HTTP endpoint on both the supervisor and the GUI plugin (the plugin can execute arbitrary code via py_eval, so it is keyed even on loopback). It is a bearer token — anyone who obtains it owns the instance; add a TLS reverse proxy if it leaves your trusted network. Browsers can pass the key as ?key=<key> (handy for /config.html).

Testing

IDADIR=/path/to/ida uv run ida-mcp-test tests/crackme03.elf -q
IDADIR=/path/to/ida uv run ida-mcp-test tests/typed_fixture.elf -q
IDADIR=/path/to/ida uv run ida-mcp-test tests/crackme03.elf -c api_analysis   # one category
IDADIR=/path/to/ida uv run coverage run -m ida_pro_mcp.test tests/crackme03.elf -q

License

MIT — inherited from upstream ida-pro-mcp. Upstream product names (IDA Pro, Hex-Rays) are trademarks of Hex-Rays SA; this project requires your own valid IDA Pro license.

Projets similaires

AI-powered reverse engineering assistant that bridges IDA Pro with language models through MCP.

Pythonaiaiagentbinary-analysis
Mmrexodia
12,4 k étoiles1,5 k

Official Hex-Rays IDA MCP Server.

Python
HHexRaysSA
399 étoiles16

Say goodbye to the complex, verbose, and laggy interaction mode of IDA Pro MCP

Python
PP4nda0s
2 k étoiles262