# CLAUDE.md
Guidance for working in this repository.
## What this project is
IDA Pro MCP Server: exposes IDA Pro / idalib functionality to MCP clients.
Main pieces:
- `src/ida_pro_mcp/server.py`: MCP server entrypoint
- `src/ida_pro_mcp/idalib_server.py`: headless idalib server
- `src/ida_pro_mcp/ida_mcp/`: IDA/plugin-side APIs
Important API modules:
- `api_core.py`: IDB metadata, functions, strings, imports
- `api_analysis.py`: decompilation, disassembly, xrefs, paths, pattern search
- `api_memory.py`: bytes/ints/strings, patching
- `api_types.py`: structs, type inference, type application
- `api_modify.py`: comments, renaming, asm patching
- `api_stack.py`: stack frame operations
- `api_sigmaker.py`: signature creation, scanning, xref signatures (uses sigmaker.py)
- `api_debug.py`: debugger control, unsafe / low priority for tests
- `api_python.py`: execute Python in IDA context
- `api_resources.py`: `ida://` MCP resources
## Core implementation rules
### IDA thread safety
All IDA SDK calls must run on the main thread.
Use:
```python
from .rpc import tool
from .sync import idasync
@tool
@idasync
def my_tool(...):
...
```
### API conventions
- Prefer batch-first APIs.
- Many functions accept either a comma-separated string or a list.
- Use full type hints and `Annotated[...]` descriptions.
- The function docstring becomes the MCP tool description.
Example:
```python
def my_api(addrs: Annotated[str, "Addresses (0x401000, main) or list"]) -> list[dict]:
...
```
### Common helpers
- Parse addresses with `parse_address()`
- Normalize batch input with `normalize_list_input()` / `normalize_dict_list()`
- Use shared pagination / filtering helpers from `utils.py`
### Unsafe operations
Debugger or destructive operations should be marked unsafe:
```python
from .rpc import tool, unsafe
@unsafe
@tool
@idasync
def dangerous_op(...):
...
```
## Development commands
### Run
```bash
uv run ida-pro-mcp
uv run ida-pro-mcp --transport http://127.0.0.1:8744/sse
uv run idalib-mcp --stdio path/to/binary
uv run idalib-mcp --host 127.0.0.1 --port 8745 path/to/binary
uv run ida-pro-mcp --unsafe
```
### MCP inspector
```bash
uv run mcp dev src/ida_pro_mcp/server.py
```
### Install / uninstall
```bash
uv run ida-pro-mcp --install
uv run ida-pro-mcp --uninstall
```
## Testing and coverage
### Run tests
Use the headless test runner:
```bash
uv run ida-mcp-test tests/crackme03.elf -q
uv run ida-mcp-test tests/typed_fixture.elf -q
uv run ida-mcp-test tests/crackme03.elf -c api_analysis
uv run ida-mcp-test tests/typed_fixture.elf -p "*stack*"
```
Notes:
- Use `uv run ...`
- Non-interactive output should show failures only plus a summary
- Binary-specific tests should use `@test(binary="...")` with the executable basename
### Coverage
Measure coverage across both maintained fixtures:
```bash
uv run coverage erase
uv run coverage run -m ida_pro_mcp.test tests/crackme03.elf -q
uv run coverage run --append -m ida_pro_mcp.test tests/typed_fixture.elf -q
uv run coverage report --show-missing
```
Current fixture intent:
- `tests/crackme03.elf`: compact general regression fixture
- `tests/typed_fixture.elf`: typed globals / structs / locals / stack coverage fixture
### Test expectations
- Prefer semantic assertions, not weak "field exists" checks
- Prefer round-trip tests for mutating APIs
- If tests expose clearly wrong API behavior, fix the API instead of weakening the test
- Focus on IDA-facing modules, not server/config plumbing
- Expect some IDA / Hex-Rays variance; guarded assertions or runtime skips are acceptable when justified
### Generic-test sanity check
When adding generic tests, also try a non-fixture binary to avoid ELF-specific assumptions:
```bash
uv run ida-mcp-test "C:\CodeBlocks\x64dbg\bin\x64\x64dbg.dll" -q
```
## Scope priorities
High priority:
- `api_analysis.py`
- `api_types.py`
- `api_modify.py`
- `api_stack.py`
- `api_memory.py`
- `api_core.py`
- `api_resources.py`
- `utils.py`
- `framework.py`
Lower priority:
- `api_debug.py`
- MCP transport / hosting details
- install / config mutation logic
## Practical notes
- Server/plugin Python: 3.11+
- IDA Pro 8.3+; 9.0 recommended
- IDA Free is not supported
- If IDA uses the wrong Python, use `idapyswitch`
# ida_loader
Loader and file operations - loading binaries, database management, file I/O, and plugin loading.
## Key Functions
### Database Operations
- `save_database(outfile=None, flags=-1, root=None, attr=None)` - Save database with optional new filename
- `flush_buffers()` - Flush buffers to disk
- `is_trusted_idb()` - Check if database is trusted
- `get_path(pt)` / `set_path(pt, path)` - Get/set file paths (PATH_TYPE_CMD, PATH_TYPE_IDB, PATH_TYPE_ID0)
### File Loading
- `load_binary_file(filename, li, neflags, fileoff, basepara, binoff, nbytes)` - Load binary into database
- `file2base(li, pos, ea1, ea2, patchable)` - Load file portion into address range
- `mem2base(mem, ea, fpos)` - Load from memory buffer
- `reload_file(file, is_remote)` - Reload input file bytes without losing analysis
- `base2file(fp, pos, ea1, ea2)` - Unload database to binary file
### File Type Detection
- `get_basic_file_type(li)` - Recognize file type (libraries, zip, etc.)
- `get_file_type_name()` - Get current file type name (from idainfo.filetype)
### Output Generation
- `gen_file(otype, fp, ea1, ea2, flags)` - Generate output files (MAP, EXE, IDC, LST, ASM, DIF)
- `gen_exe_file(fp)` - Generate executable file from database
### File/Memory Mapping
- `get_fileregion_offset(ea)` - Get file offset for linear address (returns -1 if unmapped)
- `get_fileregion_ea(offset)` - Get linear address for file offset (returns BADADDR if not found)
### Plugin Management
- `load_plugin(name)` - Load plugin by name or path
- `run_plugin(plg, arg)` - Run loaded plugin with argument
- `load_and_run_plugin(name, arg)` - Load and run plugin in one call
- `find_plugin(name, load_if_needed=False)` - Find plugin, optionally loading it
- `get_plugin_options(plugin)` - Get -Oplugin:options from command line
### Import/IDS
- `set_import_ordinal(modnode, ea, ord)` - Set ordinal import entry info
- `set_import_name(modnode, ea, name)` - Set named import entry info
- `load_ids_module(fname)` - Load and apply IDS file
### Archives
- `process_archive(temp_file, li, module_name, neflags, defmember, loader)` - Process archive file
- `extract_module_from_archive(fname, is_remote=False)` - Extract module from archive interactively
### Snapshots
- `build_snapshot_tree(root)` - Build snapshot tree structure
## Key Classes
### snapshot_t
Database snapshot representation.
- `id` - Snapshot ID (qtime64_t timestamp)
- `flags` - Snapshot flags (SSF_AUTOMATIC, etc.)
- `desc` - Description string (max 128 chars)
- `filename` - Snapshot filename
- `children` - Child snapshots
### plugin_info_t
Plugin metadata.
- `path` - Full plugin path
- `name` - Short name (appears in menu)
- `hotkey` - Current hotkey
- `flags` - Plugin flags
- `comment` - Plugin comment
### loader_t
Loader module interface (low-priority: advanced loader development only).
### idp_desc_t / idp_name_t
Processor module metadata (low-priority: processor module development).
## Key Flags
### Load Flags (NEF_*)
- `NEF_FIRST` - First file loaded into database
- `NEF_SEGS` - Create segments
- `NEF_CODE` - Load as code segment
- `NEF_RELOAD` - Reload at same place (don't recreate segments/fixups)
- `NEF_FLAT` - Autocreate FLAT group (PE)
### Database Flags (DBFL_*)
- `DBFL_KILL` - Delete unpacked database
- `DBFL_COMP` - Collect garbage
- `DBFL_BAK` - Create backup file
- `DBFL_TEMP` - Temporary database
### Output File Types (OFILE_*)
- `OFILE_MAP` - MAP file
- `OFILE_EXE` - Executable
- `OFILE_IDC` - IDC script
- `OFILE_LST` - Disassembly listing
- `OFILE_ASM` - Assembly
- `OFILE_DIF` - Difference
## See Also
Full docs: skill/docs/ida_loader.rst
# ida_merge
IDA Teams merge functionality - 3-way merging of IDB files (not available in IDA Pro).
## Overview
Low-priority module for IDA Teams only. Handles merging of base_idb, local_idb, and remote_idb databases with conflict resolution.
## Key Concepts
- **base_idb**: Common ancestor database (middle pane in UI)
- **local_idb**: Local database receiving merge result (left pane)
- **remote_idb**: Remote database merging into local (right pane)
## Merge Phases
Merges occur in phases: global settings, segmentation, bytes, names, functions, types, debugger settings, etc.
## Key Functions
- `is_diff_merge_mode()` - Check if in merge/diff mode
- `create_nodeval_merge_handler()` / `create_nodeval_merge_handlers()` - Create merge handlers for custom data
- `destroy_moddata_merge_handlers()` - Destroy module data merge handlers
- `get_ea_diffpos_name()` - Get name of EA difference position
## Key Classes
### merge_data_t
Merge operation data container.
### merge_handler_params_t
Parameters for creating merge handlers.
### merge_node_helper_t / merge_node_info_t
Helpers for merging netnode data.
## Merge Kinds (MERGE_KIND_*)
Extensive list including: NETNODE, INF, SEGMENTS, FUNC, FRAME, EXPORTS, IMPORTS, ENUMS, STRUCTS, TILS, TINFO, BYTEVAL, FLAGS, CREFS, DREFS, BPTS, DEBUGGER, etc.
## See Also
Full docs: skill/docs/ida_merge.rst