| name | ida-mcp-headless-reverse-engineering |
| description | Headless IDA Pro MCP server for AI-powered binary analysis and reverse engineering |
| triggers | ["analyze this binary with IDA Pro","disassemble and decompile this executable","find cross-references in this binary","open this file in headless IDA","run IDA analysis on this malware sample","decompile this function with Hex-Rays","extract strings from this binary","analyze dyld_shared_cache module"] |
ida-mcp Headless Reverse Engineering
Skill by ara.so — MCP Skills collection.
Overview
ida-mcp-rs is a headless IDA Pro MCP server that enables AI agents to perform binary analysis, disassembly, decompilation, and reverse engineering tasks programmatically. It exposes IDA Pro's powerful analysis engine through 71 MCP tools without requiring the GUI.
Key capabilities:
- Open and analyze binaries (ELF, Mach-O, PE, etc.)
- Disassemble functions and code regions
- Decompile with Hex-Rays (if licensed)
- Cross-reference analysis (xrefs)
- String extraction and searching
- IDAPython script execution
- Apple dyld_shared_cache analysis
- Background task management for long-running operations
Requirements:
- IDA Pro 9.2+ with valid license (9.3sp1 recommended)
- Hex-Rays decompiler license (for decompilation features)
Installation
macOS
brew install blacktop/tap/ida-mcp
brew install blacktop/tap/ida-mcp@9.2
claude mcp add ida -- ida-mcp
claude mcp add ida -e DYLD_LIBRARY_PATH='/Applications/IDA Professional 9.3.app/Contents/MacOS' -- ida-mcp
Linux
brew install blacktop/tap/ida-mcp
sudo snap install ida-mcp
sudo snap connect ida-mcp:dot-idapro
claude mcp add ida -- ida-mcp
claude mcp add ida -e IDADIR='/opt/ida-pro-9.3' -- ida-mcp
Windows
# Via Scoop (recommended)
scoop bucket add blacktop https://github.com/blacktop/scoop-bucket
scoop install blacktop/ida-mcp
claude mcp add ida -- ida-mcp
# OR copy binary to IDA directory
copy ida-mcp.exe "C:\Program Files\IDA Professional 9.3\"
claude mcp add ida -- "C:\Program Files\IDA Professional 9.3\ida-mcp.exe"
# OR set IDADIR manually
setx IDADIR "C:\Program Files\IDA Professional 9.3"
claude mcp add ida -- ida-mcp
Version Matching
ida-mcp versions mirror IDA Pro versions:
v9.3.x → IDA Pro 9.3/9.3sp1
v9.2.x → IDA Pro 9.2
Version mismatches are detected at startup with clear error messages.
Configuration
Context Optimization
By default, ida-mcp exposes all 71 tools (~10k tokens). Filter the surface for smaller models or Gemini's 512-function limit:
ida-mcp --toolsets=core,functions,disassembly,decompile,xrefs
{
"mcpServers": {
"ida-mcp": {
"command": "ida-mcp",
"env": {
"IDA_MCP_TOOLSETS": "core,functions,disassembly,decompile,xrefs",
"IDA_MCP_READ_ONLY": "true"
}
}
}
}
Available toolsets: core, functions, disassembly, decompile, xrefs, control_flow, memory, search, metadata, types, editing, scripting
Flags:
--toolsets=cat1,cat2 — Enable specific categories
--tools=t1,t2 — Add individual tools
--exclude-tools=t1,t2 — Remove specific tools
--read-only — Strip all mutating tools (run_script, patch*, rename, etc.)
HTTP/SSE Worker Pool
For multi-client HTTP/SSE usage:
ida-mcp serve-http --bind 127.0.0.1:8765 --max-workers 4 --min-workers 1
Each HTTP session leases one child worker until close_idb or timeout. Configure:
--worker-idle-timeout-secs — How long idle workers stay alive
--worker-disconnect-grace-secs — Grace period for SSE reconnects
--session-keep-alive-secs — POST-only session timeout (default 1800s)
Core Workflows
Opening and Analyzing a Binary
result = open_idb(path="/path/to/malware.exe")
status = analysis_status()
analyze = analyze_funcs(background=true)
progress = task_status(task_id="analyze-1")
while task_status(task_id="analyze-1")["status"] != "complete":
time.sleep(5)
Function Discovery and Disassembly
funcs = list_functions(limit=20)
asm = disasm_by_name(name="main", count=20)
asm = disasm(address="0x100000f00", count=50)
info = func_info(address="0x100000f00")
Decompilation (Hex-Rays Required)
code = decompile(address="0x100000f00")
code = decompile_by_name(name="main")
status = analysis_status()
if status["status"] == "pending":
analyze_funcs(background=true)
Cross-Reference Analysis
callers = callers(address="0x100000f00")
callees = callees(address="0x100000f00")
data_xrefs = data_xrefs(address="0x100002000")
code_xrefs = code_xrefs_to(address="0x100000f00")
String Extraction
strings = strings(limit=100)
results = search_text(pattern="password")
results = search_binary(pattern="4883EC20")
Symbol and Import/Export Analysis
imports = list_imports()
exports = list_exports()
symbols = list_symbols(limit=100)
Memory and Segments
segments = list_segments()
bytes_data = read_bytes(address="0x100000f00", size=64)
info = idb_info()
IDAPython Scripting
result = run_script(code="""
import idautils
import idc
for func_ea in idautils.Functions():
func_name = idc.get_func_name(func_ea)
if 'crypto' in func_name.lower():
print(f"{hex(func_ea)}: {func_name}")
""")
result = run_script(file="/path/to/analysis_script.py")
result = run_script(
code="import ida_bytes; print(ida_bytes.get_bytes(0x1000, 16).hex())",
timeout_secs=30
)
Apple dyld_shared_cache Analysis
result = open_dsc(
path="/System/Library/dyld/dyld_shared_cache_arm64e",
arch="arm64e",
module="/usr/lib/libobjc.A.dylib"
)
while task_status(task_id="dsc-1")["status"] != "complete":
time.sleep(10)
result = open_dsc(
path="/System/Library/dyld/dyld_shared_cache_arm64e",
arch="arm64e",
module="/usr/lib/libobjc.A.dylib",
frameworks=["/System/Library/Frameworks/Foundation.framework/Foundation"]
)
dsc_add_dylib(module="/usr/lib/libSystem.B.dylib")
dsc_add_region(address="0x180116000")
status = analysis_status()
Task Management
tasks = list_tasks()
status = task_status(task_id="analyze-1")
cancel_task(task_id="analyze-1")
Database Lifecycle
open_idb(path="/path/to/binary")
info = idb_info()
close_idb()
analyze_funcs(background=true)
Common Patterns
Complete Binary Analysis Pipeline
open_idb(path="/path/to/malware.exe")
task = analyze_funcs(background=true)
task_id = task["task_id"]
import time
while task_status(task_id=task_id)["status"] != "complete":
progress = task_status(task_id=task_id)
print(f"Analysis progress: {progress.get('progress', 0)}%")
time.sleep(5)
funcs = list_functions(limit=50)
strings = strings(limit=100)
imports = list_imports()
main_code = decompile_by_name(name="main")
crypto_funcs = []
for func in funcs:
if 'crypt' in func['name'].lower() or 'aes' in func['name'].lower():
crypto_funcs.append(func)
code = decompile(address=func['address'])
print(f"Found crypto function: {func['name']}\n{code}\n")
close_idb()
Finding and Analyzing Suspicious Functions
open_idb(path="/path/to/suspicious.exe")
analyze_funcs(background=true)
suspicious = search_text(pattern="cmd.exe|powershell|/bin/sh")
for hit in suspicious:
print(f"Found suspicious string at {hit['address']}: {hit['match']}")
xrefs = code_xrefs_to(address=hit['address'])
for xref in xrefs:
func = func_info(address=xref['from'])
print(f" Referenced by {func['name']} at {xref['from']}")
code = decompile(address=func['start'])
print(f" Decompiled:\n{code}\n")
Control Flow Analysis
cfg = func_cfg(address="0x100000f00")
for block in cfg['blocks']:
print(f"Block {block['start']} -> {block['end']}")
asm = disasm(address=block['start'], count=10)
print(asm)
Custom IDAPython Analysis
result = run_script(code="""
import idautils
import idc
malloc_ea = idc.get_name_ea_simple('malloc')
free_ea = idc.get_name_ea_simple('free')
memory_funcs = set()
for xref in idautils.XrefsTo(malloc_ea):
func = idaapi.get_func(xref.frm)
if func:
memory_funcs.add(func.start_ea)
for xref in idautils.XrefsTo(free_ea):
func = idaapi.get_func(xref.frm)
if func:
memory_funcs.add(func.start_ea)
for func_ea in memory_funcs:
print(f"{hex(func_ea)}: {idc.get_func_name(func_ea)}")
""")
print(result['stdout'])
Tool Discovery
tools = tool_catalog(query="find callers")
tools = tool_catalog(category="xrefs")
Troubleshooting
Library Loading Errors
macOS: Library not loaded: @rpath/libida.dylib
claude mcp add ida -e DYLD_LIBRARY_PATH='/Applications/IDA Professional 9.3.app/Contents/MacOS' -- ida-mcp
Linux: error while loading shared libraries: libida.so
claude mcp add ida -e IDADIR='/opt/ida-pro-9.3' -- ida-mcp
Windows: The program can't start because ida.dll is missing
# Copy exe to IDA directory or set IDADIR
copy ida-mcp.exe "C:\Program Files\IDA Professional 9.3\"
# OR
setx IDADIR "C:\Program Files\IDA Professional 9.3"
Version Mismatch
Error: IDA version mismatch: expected 9.3, found 9.2
Solution: Install matching version:
brew install blacktop/tap/ida-mcp@9.2
Analysis Not Complete
If decompilation or xrefs fail with "analysis pending":
status = analysis_status()
if status["status"] == "pending":
task = analyze_funcs(background=true)
while task_status(task_id=task["task_id"])["status"] != "complete":
time.sleep(5)
Decompilation Fails
Error: Decompilation failed: Hex-Rays decompiler not available
Solution: Requires Hex-Rays license. Check:
info = idb_info()
print(info.get("decompiler_available"))
Worker Pool Exhausted
Error: Worker pool exhausted
Solution: Close unused databases or increase worker count:
ida-mcp serve-http --max-workers 8
dyld_shared_cache First-Time Delay
First open_dsc call can take 5-15 minutes to create .i64:
result = open_dsc(path="/path/to/dyld_shared_cache_arm64e",
arch="arm64e",
module="/usr/lib/libobjc.A.dylib")
task_id = result["task_id"]
while task_status(task_id=task_id)["status"] != "complete":
time.sleep(30)
Subsequent opens of the same module are instant (reuses .i64).
Performance Tips
- Use background analysis for large binaries (>10MB)
- Filter tool surface if using small models or hitting Gemini's 512-function limit
- Close databases when done to free resources
- Poll task_status instead of blocking on long operations
- Use worker pool (
--max-workers) for concurrent HTTP sessions
Reference
Lifecycle: open_idb, close_idb, idb_info, analysis_status, analyze_funcs
Functions: list_functions, func_info, func_cfg, disasm_by_name, disasm, decompile, decompile_by_name
XRefs: callers, callees, code_xrefs_to, data_xrefs, xrefs_from
Search: search_text, search_binary, strings, find_pattern
Symbols: list_imports, list_exports, list_symbols, resolve_name
Memory: read_bytes, list_segments, segment_info
Tasks: task_status, list_tasks, cancel_task
DSC: open_dsc, dsc_add_dylib, dsc_add_region
Scripting: run_script
Discovery: tool_catalog
For complete tool list and parameters, use tool_catalog() or check the GitHub repository.