Skip to content
Conduit

mcp server

ida-pilot

Headless IDA Pro analysis server that exposes the decompiler and disassembler as MCP tools for AI agents — tiered tool loading, multi-layer caching, batch ops, and compact payloads to cut token cost.

wklwkl115/ida-pilotcommunitylistedunreviewed

Set up

Runs on your computer. Pick your agent and operating system.

This project does not publish an install method we can turn into a config. Follow the README instead.

README

synced Oct 23, 2026

IDA Pilot

verify License: MIT Go Python MCP Platforms

Drive IDA Pro's decompiler and disassembler from an AI agent over the Model Context Protocol — headless, fast, and token-frugal.

Headless IDA Pro analysis server exposing MCP tools (28 with py_eval enabled, 27 without). Designed for AI agents — tiered tool loading, multi-layer caching, batch operations, and compact payloads minimize token cost per turn.

Go orchestrates sessions and caching. Python workers run IDA via idalib. Communication uses Connect RPC over TCP.

Why IDA Pilot?

  • Built for agents, not humans. Every response is compact — hex addresses, sparse fields, [address, type] xref tuples, "ok" instead of {"success": true} — to spend the fewest tokens per turn.
  • One call, not ten. Composite tools like survey_binary and analyze_function return decompilation + metadata + xrefs + comments in a single round-trip; analyze_functions batches up to 10 at once.
  • Stays responsive on huge binaries. Loading and auto-analysis run detached with a live progress heartbeat, so a 200 MB binary won't stall or time out your MCP client — you poll until ready=true and keep working.
  • Tiered tool surface. Agents boot with 3 tools; read/analysis and write tools promote in as the workflow advances, keeping the per-turn schema small.
  • Multi-binary. Open several databases and cross_reference / cross_search across them.
  • Safe by default. Loopback-only bind, py_eval off, Origin/Host guard, optional path allowlist (details below).

⚠️ Security model — read before exposing the port

IDA Pilot has no built-in authentication. The defaults are tuned for a single trusted MCP client on the same machine:

  • Bound to 127.0.0.1 by default. Only callers on the local host can reach it. Override with --bind 0.0.0.0 (or IDA_PILOT_BIND) only if you are putting an authenticated reverse proxy in front.
  • Origin / Host validation on every request when bound to loopback — blocks DNS-rebinding and browser cross-origin attacks.
  • py_eval is OFF by default. It runs arbitrary Python inside the IDA worker (full host filesystem + network access). Enable explicitly with --enable-py-eval (or IDA_PILOT_ENABLE_PY_EVAL=1) and treat the resulting endpoint as an RCE primitive — anyone who can reach the port can execute code.
  • Filesystem allowlist (opt-in). By default a client can open any file the server user can read (open_binary, import_metadata). Set --allowed-roots (or IDA_PILOT_ALLOWED_ROOTS) to confine those paths to specific directories — recommended whenever you expose the port. Paths are symlink-resolved before the check, so a link inside a root can't escape it.

The truncated-output cache (get_cached_output) is process-global with no per-session ACL — the server has no client identity to bind entries to — so access rests on unguessable 128-bit cache IDs plus the loopback/Origin guards above, not on session ownership.

In short: a fresh ./bin/ida-pilot run is safe to leave on; opening the port to the network or enabling py_eval is an explicit choice and your responsibility to protect.

Architecture

MCP Client (Claude, Cursor, etc.)
    │
    │  Streamable HTTP / SSE
    ▼
Go Server (:17300)
    │  session registry, tool tiers, caching, output pagination
    │
    │  Connect RPC (TCP)
    ▼
Python Worker (one per binary)
    │  idalib + Hex-Rays decompiler
    ▼
IDA database (.i64)

Quick Start

Prerequisites

  • IDA Pro 9.0+ with idalib activated (docs)
  • Go 1.25+
  • Python 3.10+ (the supported floor; CI and mise pin 3.12)

Build

git clone https://github.com/wklwkl115/ida-pilot.git
cd ida-pilot
pip install -r python/requirements.txt
go build -o bin/ida-pilot ./cmd/ida-pilot

Run

./bin/ida-pilot --debug

The server listens on http://localhost:17300/ (Streamable HTTP) and http://localhost:17300/sse (SSE fallback).

Connect an MCP Client

Add to your MCP client configuration:

{
  "mcpServers": {
    "ida-pilot": {
      "type": "http",
      "url": "http://127.0.0.1:17300/"
    }
  }
}

Claude Desktop: ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows)

Claude Code: .mcp.json in project root or ~/.claude/settings.json

Cursor: .cursor/mcp.json in project root

Agent-Optimized Design

IDA Pilot is built for agents, not humans. Every design decision targets lower token cost and fewer round-trips.

Tiered Tool Loading

Agents start with 3 tools. More appear as needed — the schema payload per turn stays small.

TierTriggerToolsPurpose
0Server boot3open_binary, list_sessions, get_cached_output
1Binary opened+19 = 22Read, query, composite, analysis, context & cross-session tools
2First analysis+5 = 27Write, annotate, and import tools

When the last session closes, tools demote back to Tier 0. Adding --enable-py-eval registers one more Tier-1 tool, taking the full surface to 28.

Composite Tools

One call replaces many. These are the primary entry points for analysis:

  • survey_binary — segments, function/import/export/string counts with top entries, entry point, decompiler status. One call to orient.
  • analyze_function — pseudocode + metadata + xrefs + comments for a single function. All cached.
  • analyze_functions — batch-analyze up to 10 functions in parallel.
  • annotate_function — batch rename, retype, and comment in a single call per function.

Multi-Layer Caching

CacheScopeCapacityInvalidation
List (functions, imports, exports, strings)SessionUnboundedrename / make_function
Decompilation (pseudocode)Per-function200 entriestargeted: function renames invalidate only that function; data-label renames search and evict only entries containing the old name; lvar/comments invalidate that function
Xrefs (to + from)Per-addressUnboundedmake_function
SegmentsSessionStaticNever
Output (truncated responses)Global200 entries, 1h TTLFIFO eviction
Analysis context (visited + notes)SessionUnboundedNever

Background cache warming starts automatically when a binary is opened — survey_binary returns instantly on its first call.

Compact Payloads

  • Addresses are hex (0x...) on both input and output, so the agent pastes back exactly what it sees in disassembly/listings (decimal is also accepted on input)
  • Sparse fields: zero/false/empty values omitted
  • Xrefs as [address, type] tuples instead of objects
  • Write operations return "ok" instead of {"success": true}
  • Responses over 8KB auto-truncated with pagination via get_cached_output
  • Session ID auto-detected when only one session is active

Analysis Context

Agents lose context on long conversations. IDA Pilot tracks it server-side:

  • set_analysis_note — attach notes to addresses during analysis
  • get_analysis_context — retrieve all visited functions and notes to recover state

Tools Reference

The surface is intentionally small: related operations are consolidated behind a few dispatcher tools that take a discriminator field (category, mode, action, target, format). 28 tools across three tiers.

Session & lifecycle (Tier 0–1)

ToolDescription
open_binaryOpen a binary. Returns immediately; loads + auto-analyzes in the background
close_binaryClose session and save database
save_databaseSave without closing
list_sessionsList active sessions
get_session_progressLoad/analysis progress and readiness — poll until ready=true
get_cached_outputPaginate a truncated response via its _cache_id

open_binary does not block: loading and auto-analysis run in a background worker thread so the call returns at once (large binaries take minutes to analyze). Poll get_session_progress until ready=true before issuing analysis tools — they are gated and return a not ready error until then. Status RPCs stay responsive throughout because the worker serializes IDA access on a single thread while answering progress queries from cached state.

Composite (Tier 1)

ToolDescription
survey_binaryFull binary overview in one call
analyze_functionDecompile + metadata + xrefs + comments for one function
analyze_functionsBatch-analyze up to 10 functions; per-item errors so one bad address won't fail the batch

Read & query (Tier 1)

ToolDescription
queryBrowse by category: functions, imports, exports, strings, globals, segments, structs, enums, entry_point. Regex, pagination, and category filters (named_only, module, name)
get_referencesCross-references. mode=code (direction=to/from/both), data, or string
searchmode=text (needle) or binary (IDA pattern), over a start/end range
inspectName + type + comment + function bounds + instruction length at an address
get_disasmDisassembly at an address, or the whole function
read_memoryRaw memory: format=bytes/dword/qword/byte/string

Cross-session (Tier 1)

ToolDescription
cross_referenceLook up a symbol from one binary (source_session_id + address) and find where it appears in another (target_session_id) — searches imports, exports, function names, and strings
cross_searchSearch across multiple sessions at once. mode=functions/imports/exports/strings, regex or exact needle. Omit session_ids to search all active sessions

Analysis control & context (Tier 1)

ToolDescription
run_auto_analysisTrigger IDA auto-analysis (for binaries opened with skip_analysis). Returns once analysis finishes, or — for a long analysis that outlasts the call — promptly with status:"analyzing" while it continues in the background; poll get_session_progress until ready=true
watch_auto_analysisObserve auto-analysis progress (does not drive or cancel it)
set_analysis_note / get_analysis_contextServer-side context tracking for state recovery
prune_contextClear cached outputs + noted-function caches to free memory
py_eval (opt-in)Execute Python in IDA — registered only with --enable-py-eval. Invalidates caches after each call (read_only=true to keep them warm). See Security model.

Write & import (Tier 2)

ToolDescription
annotate_functionBatch rename + retype + comment for a function → returns updated pseudocode
set_metadataaction=set_name, delete_name, or set_comment (scope=address/function/decompiler)
set_typetarget=function (prototype), global (C type), or lvar (C type + function_address + lvar_name)
make_functionCreate a function at an address
import_metadataformat=il2cpp (script.json + il2cpp.h) or flutter (flutter_meta.json)

Configuration

CLI Flags

--bind              Bind interface (default 127.0.0.1; use 0.0.0.0 only behind an auth proxy)
--port              HTTP port (default: from config.json)
--config            Config file path (default: config.json)
--worker            Python worker script path
--max-sessions      Max concurrent sessions
--session-timeout   Session idle timeout (e.g. 4h)
--debug             Verbose logging
--enable-py-eval    Register the py_eval tool (arbitrary Python in the IDA worker — RCE primitive)
--allowed-roots     Restrict agent-supplied paths to these dirs (OS-path-list separated; empty = unrestricted)

Environment Variables

IDA_PILOT_BIND=127.0.0.1
IDA_PILOT_PORT=17300
IDA_PILOT_SESSION_TIMEOUT_MIN=240
IDA_PILOT_MAX_SESSIONS=10
IDA_PILOT_WORKER=/path/to/worker.py
IDA_PILOT_DEBUG=1
IDA_PILOT_ENABLE_PY_EVAL=0
IDA_PILOT_ALLOWED_ROOTS=/srv/samples:/data/binaries   # OS-path-list separated; empty = unrestricted

config.json

{
  "bind": "127.0.0.1",
  "port": 17300,
  "session_timeout_minutes": 240,
  "max_concurrent_sessions": 4,
  "database_directory": "./databases",
  "python_worker_path": "python/worker/server.py",
  "debug": false,
  "enable_py_eval": false,
  "allowed_roots": []
}

Development

make build          # Build server
make test           # Run tests
make proto          # Regenerate protobuf (requires protoc)
make clean          # Clean artifacts
make inspector      # Launch MCP Inspector at localhost:5173

Project Structure

ida-pilot/
├── cmd/ida-pilot/        # Server entry point
├── internal/
│   ├── server/           # MCP tool handlers, caching, tiers
│   ├── session/          # Session registry + persistence
│   └── worker/           # Python worker process manager
├── proto/                # Protobuf service definitions
└── python/worker/        # idalib wrapper + Connect RPC server

Contributing

Contributions are welcome — see CONTRIBUTING.md for setup, the local test gates, and conventions. To report a security issue privately, see SECURITY.md.

License

MIT

↑↓ navigate openesc close