ida-headless-mcp

mcp
Security Audit
Fail
Health Warn
  • License — License: Apache-2.0
  • Description — Repository has a description
  • Active repo — Last push 0 days ago
  • Low visibility — Only 5 GitHub stars
Code Fail
  • rm -rf — Recursive force deletion command in e2e/http_bootstrap.sh
  • rm -rf — Recursive force deletion command in e2e/http_close_recovery.sh
  • rm -rf — Recursive force deletion command in e2e/http_integration.sh
  • rm -rf — Recursive force deletion command in e2e/http_observability.sh
  • rm -rf — Recursive force deletion command in e2e/http_pool.sh
  • rm -rf — Recursive force deletion command in e2e/http_script_integration.sh
  • rm -rf — Recursive force deletion command in e2e/http_session_cancel.sh
Permissions Pass
  • Permissions — No dangerous permissions requested

No AI report is available for this listing yet.

SUMMARY

Rust-native, multi-session headless IDA Pro MCP server with isolated workers and stdio or Streamable HTTP transports.

README.md

ida-headless-mcp

English | 简体中文

Rust-native, multi-session headless IDA Pro MCP server.

This project is a derivative of blacktop/ida-mcp-rs, rewritten around an explicit supervisor/worker split and pinned to the mrexodia/ida-pro-mcp public contract. It is not a drop-in replacement for the upstream Homebrew/Scoop packages, and it is not an official Hex-Rays product.

License: Apache 2.0

What this project adds

  • One supervisor process owns MCP stdio or Streamable HTTP.
  • Each open database gets its own IDA worker process; a crash takes down one session, not the server.
  • Session lifecycle is explicit: idb_open, idb_list, idb_close, server_health, plus analysis tools that all require a database session ID.
  • 90 tools by default, 91 with --unsafe, in 12 categories.
  • Headless-only: debugger and GUI control stay out of the public surface.

See docs/ARCHITECTURE.md and docs/MIGRATION.md.

Prerequisites

  • IDA Pro 9.2, 9.3, or 9.4 with a valid license
  • Rust (source builds only) — rust-toolchain.toml pins the exact version and
    rustup installs it for you. Cargo.toml declares a 1.95 floor, inherited from
    vibrev-kit, but the pin is what every build and every CI run actually uses.
  • LLVM/Clang for the C++ bindings (source builds only)

Release builds never ship IDA, the SDK, or IDA runtime libraries. You must already have a licensed IDA install on the same platform and architecture.

Install

There is no package-manager distribution — no Homebrew tap, no Scoop bucket, no snap. Two paths:

  1. Prebuilt archive. Download from Releases, verify against checksums.txt, and put the executable on your PATH.
  2. Build from source (below) — the only option for any other platform or architecture.

Archives are named ida-headless-mcp_<version>_ida-<minor>_<OS>_<arch>, with .tar.gz on Unix and .zip on Windows. <OS> is Linux, macOS, or Windows. Each release publishes three IDA minors (9.2, 9.3, 9.4) for three platform pairs — Linux_x86_64, macOS_arm64, Windows_x86_64 — so nine archives in total. Each one carries the executable plus README.md, LICENSE, and NOTICE.

Pick the archive whose IDA minor matches your installed IDA. The binary checks the loaded IDA version before it opens a database: once either side is 9.4 the minor has to match exactly, because idalib reconstructs IDA-internal layouts by hand and 9.4 moved one of them. Below 9.4 only the major is compared (IDA 9.3 reports its product version as 9.0), but matching the minor is still the right habit.

Build

See docs/BUILDING.md. Each IDA minor has its own manifest; pick exactly one:

# IDA 9.4 (default)
IDADIR=/path/to/ida-9.4 cargo build --release

# IDA 9.3
IDADIR=/path/to/ida-9.3 cargo build --release \
  --manifest-path sdk/ida-93/Cargo.toml

# IDA 9.2
IDADIR=/path/to/ida-9.2 cargo build --release \
  --manifest-path sdk/ida-92/Cargo.toml

The 9.4 binary is under target/release; 9.2 and 9.3 use their manifest-local
sdk/ida-*/target/release directories. Windows adds the .exe suffix. The 9.2
and 9.3 builds need one extra linker flag — see docs/BUILDING.md.

just --list shows the repo's build and test recipes; docs/TESTING.md explains which ones need a licensed IDA.

Platform setup

The process links against IDA at runtime. Point it at your install if it is not in a default location:

Platform Typical path Runtime hint
Linux ~/ida-pro-9.4 or /opt/ida-pro-9.4 IDADIR or LD_LIBRARY_PATH
macOS /Applications/IDA Professional 9.4.app/Contents/MacOS IDADIR or DYLD_LIBRARY_PATH
Windows C:\Program Files\IDA Professional 9.4 Put the exe next to ida.dll, or set IDADIR and add that directory to PATH
# Linux / macOS
export IDADIR=/path/to/ida
./target/release/ida-headless-mcp
# Windows
$env:IDADIR = "C:\Program Files\IDA Professional 9.4"
.\target\release\ida-headless-mcp.exe

That starts the default HTTP listener on 127.0.0.1:8765 and prints a security
banner — enough to confirm the binary found IDA. Ctrl-C to stop it.

IDADIR must name the same installation the binary was built for. The two
halves of IDA are resolved separately — the core library by the dynamic linker,
the plugins and processor modules by IDA out of IDADIR — so pointing IDADIR
at a different release on a machine that has both leaves you running one
version's core with another version's plugins. That used to start, and then fail
as "Hex-Rays decompiler is not available", a segfault inside a processor module,
or a dyld_shared_cache that would not open. It now refuses at startup and names
both directories. Pass --allow-ida-mismatch (or IDA_MCP_ALLOW_IDA_MISMATCH=1)
if you have a reason to run it anyway.

Configure an MCP client

MCP clients spawn the binary and talk over the pipe, so they need the stdio transport by name: serve --mode stdio. (A bare invocation serves HTTP — see Streamable HTTP.) After the binary is on PATH (or use the absolute path):

Claude Code

claude mcp add ida -- ida-headless-mcp serve --mode stdio

Codex CLI

codex mcp add ida -- ida-headless-mcp serve --mode stdio

Cursor

Add to .cursor/mcp.json:

{
  "mcpServers": {
    "ida": {
      "command": "ida-headless-mcp",
      "args": ["serve", "--mode", "stdio"],
      "env": {
        "IDADIR": "/path/to/ida"
      }
    }
  }
}

Usage

The supervisor returns an opaque session ID from idb_open. Pass that ID as database to every analysis tool, then close the session when finished.

idb_open(input_path: "~/samples/malware")
idb_list()
list_funcs(database: "<session_id>", offset: 0, limit: 20)
find_string(database: "<session_id>", query: "libc")
disasm(database: "<session_id>", address: "0x100000f00")
xrefs_to(database: "<session_id>", address: "0x100000f00")
decompile(database: "<session_id>", address: "0x100000f00")
idb_close(database: "<session_id>")

Notes that save a round trip:

  • input_path may be a raw binary (Mach-O/ELF/PE) or an existing .i64/.idb. Opening the same canonical path twice returns the session that already exists instead of a second worker.
  • Sessions are reaped after idle_ttl_sec seconds idle (default 600); pass 0 to disable.
  • idb_open takes a mode: prefer_headless (default), force_headless, and prefer_gui all yield a headless worker; force_gui returns a stable unsupported-mode error, because this build is headless-only.
  • --max-workers (default 4) caps how many worker processes the supervisor keeps alive at once, on either transport — one per open database. IDA_MCP_MAX_WORKERS is the env spelling.
  • server_health reports on the supervisor without touching a database.

Coming from the previous ida-pro-mcp-compatible tool names? See the mapping table in docs/MIGRATION.md.

Streamable HTTP

./target/release/ida-headless-mcp serve --bind 127.0.0.1:8765

Unlike stdio, this opens a listener, so every request needs a bearer token — there is no flag that turns it off. The token lives in $VIBREV_HOME/token, or ~/.vibrev/token when that is unset (mode 0600, generated on first use and reused afterwards); --token-file moves it. On startup the server prints a security banner and a paste-able client-config snippet:

"ida-headless-mcp": {
  "type": "http",
  "url": "http://127.0.0.1:8765/mcp",
  "headers": { "Authorization": "Bearer vbr_…" }
}

The token is elided from that snippet when stderr is not a terminal, so redirected logs and CI output do not leak it; read it back with head -n1 ~/.vibrev/token.

HTTP is what serve does unless you pass --mode stdio, so the command above needs no mode. See docs/TRANSPORTS.md for authentication, Origin/Host checks, session keep-alive, and the pool flags.

Bundled skills

The binary carries an IDAPython reference skill (105 files, compressed into the
executable) that teaches a model the ida_* API the tool surface sits on top of.
It is packed at build time from skills/ and written back out byte for byte:

ida-headless-mcp skills list
ida-headless-mcp skills export --dir ~/.claude/skills

Neither command opens a database or needs an IDA license — the answer is baked
into the binary. vibrev install ida calls them for you and puts the result
where Claude Code reads it; see vibrev skill --help. Only Claude Code has a
skill mechanism, so other clients get the MCP server without this part.

Tool filtering

The default catalog advertises every available tool except run_script, which executes arbitrary IDAPython inside the worker. --unsafe (or IDA_MCP_UNSAFE=true) enables it — that is the only tool the flag gates.

To narrow the surface instead:

  • --toolsets keeps only the named categories: core, functions, disassembly, decompile, xrefs, control_flow, memory, search, metadata, types, editing, scripting.
  • --tools adds individual tools back on top of --toolsets.
  • --exclude-tools removes tools; exclusion always wins.
  • --read-only keeps only tools that declare readOnlyHint, so it tracks the catalog rather than a hand-kept list.

Each has an environment mirror (IDA_MCP_TOOLSETS, IDA_MCP_TOOLS, IDA_MCP_EXCLUDE_TOOLS, IDA_MCP_READ_ONLY).

Lumina

Automatic Lumina lookup is disabled unless you opt in:

ida-headless-mcp --allow-lumina

The equivalent environment setting is IDA_MCP_ALLOW_LUMINA=true. The isolated IDA user profile used by this server does not change the normal IDA GUI profile.

Limitations

  • You bring your own IDA. No archive here contains IDA, its SDK, or its runtime libraries, and none of them will run without a licensed install.
  • The decompiler-backed tools need Hex-Rays. Without a decompiler the worker reports "Hex-Rays decompiler is not available" at warm-up — followed by what it observed: the processor, the module that processor needs, the modules actually installed, and whether the installation is internally consistent. decompile, pseudocode_at, diff_before_after and the pseudocode part of analyze_function cannot answer. Everything built on disassembly still works.
  • Prebuilt binaries cover three platform pairs only — Linux x86_64, macOS arm64, Windows x86_64. Anything else means building from source.
  • A binary is tied to one IDA installation. Mixing a 9.4 build with a non-9.4 runtime, or the reverse, is rejected before any database opens. Pointing IDADIR at an installation other than the one the core library was loaded from is rejected at startup, before IDA is initialized at all.
  • Headless-only. There is no debugger surface and no GUI control; force_gui is an error, not a fallback.
  • HTTP is authenticated, always. There is no anonymous mode, so a client that cannot send an Authorization header cannot use this transport.

Docs

Attribution

Substantial portions of the IDA worker, MCP tool implementations, and build glue come from ida-mcp-rs by blacktop, MIT License.

The multi-database session model (idb_open / idb_list / idb_close plus a database argument on every analysis tool) follows ida-pro-mcp by Duncan Ogilvie and contributors, MIT License. This project no longer implements that project's tool contract; see docs/MIGRATION.md.

IDA bindings come from idalib (MIT OR Apache-2.0).

Full notices are in NOTICE.

License

Apache-2.0. Copyright (c) 2026 VibRev Developers.

The upstream portions listed above arrived under the MIT License and stay available under it; their notices are preserved in NOTICE as MIT requires.

See LICENSE and NOTICE.

Reviews (0)

No results found