
MCP server for automated binary diffing.
Diaphora MCP is an MCP (Model Context Protocol) server for automated binary diffing. It connects Diaphora (the diffing engine) and IDA Pro (the disassembler) via the MCP protocol, allowing AI agents (such as Claude Code) to perform binary file comparison, find security patches, and analyze changes.
.i64 / .idb databases to the Diaphora SQLite format (via idat.exe headless mode)idat.exe)git clone https://github.com/xTeardx/diaphora-mcp.git
cd diaphora-mcp
pip install -e .
The package tries to automatically find IDA Pro and Diaphora in standard installation locations. If not found, you can set the following environment variables:
For Claude Code, you can specify them in ~/.claude.json (or the corresponding config file of your MCP client):
{
"mcpServers": {
"diaphora": {
"command": "python",
"args": ["path/to/repo/diaphora_mcp_server.py"],
"env": {
"IDAT_PATH": "C:\\Program Files\\IDA Pro 9.3\\idat.exe",
"DIAPHORA_DIR": "C:\\Program Files\\IDA Pro 9.3\\plugins\\diaphora-3.4.1"
},
"timeout": 7200
}
}
}
Note: For very large binaries (>100 MB), ensure
timeoutis at least 7200 (2 hours).
Codex typically uses two complementary MCP servers:
diaphora-mcp — this project: export, Diaphora diff, and result analysis;ida-pro-mcp — the upstream IDA inspection server for idb_open, decompilation, and address-level analysis.idalib-mcp is the headless backend of ida-pro-mcp, not a separate Diaphora server. After installing it, restart Codex:
uv run ida-pro-mcp --install codex --transport streamable-http --scope global --ida-rpc http://127.0.0.1:8745/mcp
For this project, a stdio configuration is sufficient:
[mcp_servers.diaphora-mcp]
command = "python"
args = ["D:\\path\\to\\diaphora-mcp\\diaphora_mcp_server.py"]
startup_timeout_sec = 120
IDA Pro must analyze the binaries first (creating .i64 or .idb files). After that:
┃ export_idb_to_diaphora(idb_path="old_version.i64")
┃ export_idb_to_diaphora(idb_path="new_version.i64")
Or run the full pipeline in one command:
┃ batch_export_and_diff(idb1="old.i64", idb2="new.i64")
Do not pass .i64 directly to results tools: it is an IDA database, not SQLite. Export it first.
┃ # 1. Full pipeline: export two .i64 → diff → summary report
┃ batch_export_and_diff(idb1="v1.0.i64", idb2="v1.1.i64")
┃ # 2. If databases are already exported
┃ diff_diaphora_dbs(db1="v1.0.sqlite", db2="v1.1.sqlite")
┃ # 3. Security analysis of diff results
┃ analyze_diff_results(results_path="v1.0_vs_v1.1.diaphora")
┃ # 4. Importance ranking of changes
┃ rank_changes(results_path="v1.0_vs_v1.1.diaphora", top_n=20)
┃ # 5. Find root-cause changes
┃ find_patch_root(results_path="v1.0_vs_v1.1.diaphora")
┃ # 6. Detect probable security patches
┃ detect_security_patches(results_path="v1.0_vs_v1.1.diaphora")
┃ # 7. Generate full report
┃ summarize_patch(results_path="v1.0_vs_v1.1.diaphora")
See examples/basic-session.md for a complete step-by-step transcript of a real Diaphora MCP session — from exporting two IDB databases to comparing individual functions. Also available in Russian.
Here's a sneak peek of what the server returns:
Input — compare two SQLite3 DLLs (2015 vs 2023):
{"idb1_path": "old.i64", "idb2_path": "new.i64", "use_decompiler": false}
Output — summary after export + diff:
{
"best_matches": 60,
"partial_matches": 993,
"multimatches": 52,
"unmatched_primary": 2647
}
The session walks through 6 MCP tool calls, showing the exact JSON in/out for each step, with the agent's reasoning alongside.
┃ # Get database export info
┃ get_export_info(db_path="app.sqlite")
┃ # Search for functions
┃ search_export_db(db_path="app.sqlite", name_pattern="%crypt%", min_instructions=50)
┃ # Retrieve pseudocode
┃ get_function_pseudocode(db_path="app.sqlite", address="401000")
diaphora-mcp/
├── diaphora_mcp_server.py # Main entrypoint
├── diaphora_mcp/
│ ├── diaphora_mcp_server.py # MCP tool registration
│ ├── config.py # Path configuration and auto-detection
│ ├── models.py # Constants and models
│ ├── core/
│ │ ├── export.py # Headless export, batch pipeline
│ │ ├── diff.py # Diffing and .diaphora results reader
│ │ ├── analysis.py # Function search, compare, explain
│ │ ├── security.py # Keyword matching, patch detection
│ │ ├── ranking.py # Importance ranking
│ │ ├── graph.py # Callgraph, BFS call trees, root cause
│ │ ├── metadata.py # Metadata preparation (names, comments)
│ │ └── report.py # Overall patch report generation
│ └── utils/
│ ├── sqlite.py # SQLite helpers
│ ├── format.py # Pseudocode diff, feature vector extraction
│ └── log.py # Export logging utilities
├── _diaphora_headless.py # idat.exe -S thin wrapper
└── logs/ # Automated export logs (created dynamically)
| Tool | Description |
|---|---|
export_idb_to_diaphora | Exports .i64/.idb database to SQLite format using IDA headless |
batch_export_and_diff | Full pipeline: export primary → export secondary → diff → summary |
| Tool | Description |
|---|---|
diff_diaphora_dbs | Diffs two exported Diaphora SQLite databases |
get_diff_results | Reads .diaphora diff file with filtering |
get_diff_summary | Returns match statistics |
| Tool | Description |
|---|---|
detect_security_patches | Detects probable security fixes (bounds checks, memory safety, anti-debug, etc.) |
| Tool | Description |
|---|---|
rank_changes | Ranks changed functions by importance (0-100 score) |
| Tool | Description |
|---|---|
get_changed_callgraph | Compares incoming and outgoing calls of a function |
compare_call_path | Walks callgraph from a function (BFS call path comparison, up to N levels) |
find_patch_root | Detects root-cause functions causing call cascades |
| Tool | Description |
|---|---|
performance_report | Returns aggregated memory, cache, and connection statistics |
| Tool | Description |
|---|---|
transfer_metadata | Prepares names, comments, and prototypes for bulk transfer |
The project includes built-in integration with running GUI IDA Pro sessions, enabling instant exports directly from active IDA windows without database locking conflicts.
plugins/ directory. It will start a background XML-RPC server on port 28652 whenever IDA starts.export_idb_to_diaphora, the MCP server checks port 28652. If a session is active, it runs the export directly in the GUI. Otherwise, it automatically falls back to headless background execution via idat.exe.For detailed instructions on configuring the bridge, see GUI_INSTRUCTIONS.md.
When processing extremely large projects, Diaphora MCP applies specific optimizations:
100000 (sys.setrecursionlimit) to prevent crashes during large callgraph traversals.diaphora_config.py, setting COMMIT_AFTER_EACH_GUI_UPDATE = False reduces disk writes, speeding up GUI export 2x to 3x.EXPORTING_USE_MICROCODE = False in Diaphora config) for a faster export when decompiler is not strictly required.Tools like analyze_diff_results, compare_functions, and find_function_match return an ida_pro_mcp block containing addresses and paths. This information can be passed directly to the ida-pro-mcp tools:
┃ # 1. Diaphora finds a suspicious function
┃ analyze_diff_results(results_path="diff.diaphora")
┃ → addr1="401000", db1="old.sqlite"
┃ # 2. IDA Pro MCP decompiles it
┃ decompile_function(address="401000")
To see Diaphora MCP in action, check out the following examples:
If you are an AI coding assistant (like Claude Code) using this protocol, keep the following compatibility rules in mind:
GUI vs. Headless Export Schemas:
ida_mcp.py plugin) produces a custom schema containing tables like calls, strings, structures, but no program table.idat.exe) produces the official Diaphora schema containing the program table.diff_diaphora_dbs) requires the official schema. Always export headlessly if you intend to compare/diff databases.Locked Databases in GUI:
Avoid Database Name Collisions:
<basename>.diaphora.sqlite.<basename>.sqlite for Diaphora exports, as this conflicts with the internal cache database created by the supervisor.The checked IDA Pro 9.3 fixtures pass the regression suite: 16 passed, 1 xpassed. A real staged export and Diaphora diff of two SQLite3 DLLs were also verified. Large or GUI-open IDBs still require a free IDA lock, a valid DIAPHORA_OUTPUT_ROOT, and a sufficiently large MCP client timeout.
MIT
| Variable | Description | Example |
|---|
IDAT_PATH | Full path to idat.exe | C:\Program Files\IDA Pro 9.3\idat.exe |
DIAPHORA_DIR | Folder containing diaphora.py | C:\Program Files\IDA Pro 9.3\plugins\diaphora-3.4.1 |
DIAPHORA_OUTPUT_ROOT | Root directory allowed for new export files | D:\\diaphora-outputs |
DIAPHORA_PYTHON | Python interpreter for diff | /usr/bin/python3 (defaults to sys.executable) |
| Tool | Description |
|---|
analyze_diff_results | Screens results using security keywords and filters |
compare_functions | Side-by-side comparison of a function in both databases |
find_function_match | Matches a function in the second binary with confidence metrics |
explain_similarity | Breaks down similarity factors (mnemonics, CFG, constants, prototype, hash) |
detect_behavior_change | Provides natural language summary of function logic changes |
summarize_patch | Produces comprehensive update report |
search_export_db | Queries exported functions by name/instructions/complexity |
get_function_pseudocode | Fetches pseudocode and metadata for a function |
get_export_info | Retrieves general database metadata |
ida-pro-mcp