Skip to content
Conduit

mcp server

binscout

Headless, agent-first binary analysis: functions, CFGs, xrefs, strings, and IR over a JSON CLI or MCP server

mimi1vx/binscoutcommunitylistedunreviewed

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 26, 2026

binscout

CI License

Headless, agent-first binary analysis. Open a binary (ELF/PE/Mach-O/COFF/LE/raw), get functions, CFGs, xrefs, strings, symbols, and IR — over a JSON CLI or an MCP server over stdio. Annotations (renames, comments) live in a redb sidecar; the binary is never written.

Full docs live in the book.

Install

From crates.io:

cargo install binscout

Or from git (latest master):

cargo install --git https://github.com/mimi1vx/binscout

Or from source:

git clone https://github.com/mimi1vx/binscout
cd binscout
cargo install --path .

This installs both binscout (JSON CLI) and binscout-mcp (MCP server).

Quickstart

binscout load fw.elf                    # open the binary, cache the analysis snapshot
binscout functions fw.elf --limit 10    # first 10 functions
binscout disasm fw.elf 0x400000 32      # decode 32 bytes at the entry point
binscout annotate fw.elf 0x400000 --rename main   # rename a known function

CLI

Every command prints exactly one JSON value to stdout. Runtime failures print {"error": "..."} with exit 1, so stdout is always valid JSON. (Clap usage errors for unknown flags/subcommands still go to stderr with exit 2.)

binscout [--db PATH] [--raw --arch ARCH --base ADDR [--entry ADDR]] [--fat-arch ARCH] [--pdb PATH] [--debug-file PATH] <command> <binary> [args]

--db overrides the sidecar DB (default <binary>.rsdbg.redb, appended to the full file name so foo.exe and foo.dll never share one). --raw selects explicit raw mapping for firmware/blob workflows (arch is one of x86_64, x86_32, aarch64, arm32, thumb, riscv32, riscv64, mips32, ppc32, ppc64); without it, container auto-detection applies. --fat-arch selects a slice of a fat Mach-O container (x86_64, x86_32, aarch64, arm32, plus lipo aliases like arm64, case-insensitive); it is required for fat inputs and exclusive with --raw.

CommandExampleOutput
loadbinscout load fw.elfproject info (protocol, mode, arch, base, diagnostic totals, analysis_revision); caches the analysis snapshot
functionsbinscout functions fw.elf --query main --limit 50function rows, renames resolved; filter with --query (case-insensitive name substring), --caller/--callee (addresses resolving to call-graph neighbors), --range LO HI (inclusive); page with --offset/--limit under the page envelope; rows carry calls_count instead of the calls target array
funcbinscout func fw.elf 0x400000compact metadata: entry, name, block/insn/call counts, discovery reasons
blocksbinscout blocks fw.elf 0x400000 --limit 50block summaries of the containing function, paged under the page envelope
block-insnsbinscout block-insns fw.elf 0x400000 0x400000one block's instructions in address order, paged
diagnosticsbinscout diagnostics fw.elf --kind decode-failureprovenance records (unresolved indirect sites, decode failures) filtered by --kind/--func, paged; never writes a sidecar
disasmbinscout disasm fw.elf 0x400000 32decoded instructions (addr = hex or decimal, then byte count); trailing bad bytes report in error_at, ranges cap at 1 MiB
cfgbinscout cfg fw.elf 0x400000block nodes plus (from, to) edges; inferred_edges holds provenance-marked indirect-jump resolutions (single-slot absolutes and guarded scaled-index tables; raw-only, same-function)
structurebinscout structure fw.elf 0x400000approximate control-flow structure: syntactic loops and ifs over the CFG plus the IR lift, with an approximation warning
pseudobinscout pseudo fw.elf 0x400000approximate pseudo-C of one function: one lossy C-like line per IR row plus assembled text, with an approximation warning
calleesbinscout callees fw.elf 0x400000 --depth 5transitive callees out to --depth hops (direct are depth 1), ordered by entry with shortest distance, paged under the page envelope
callersbinscout callers fw.elf 0x400000 --depth 5transitive callers out to --depth hops, ordered by entry with shortest distance, paged under the page envelope
slicebinscout slice fw.elf 0x400000 --depth 5backward slice of an address: every instruction that can reach it via xref edges (any kind) and intra-function CFG predecessors out to --depth hops (direct are depth 1, default 8), ordered by address with shortest distance, paged under the page envelope; unmapped roots are a NotFound error
xrefsbinscout xrefs fw.elf --to 0x400000 --kind codecross-references filtered by --to/--from/--kind (code, data, string, import, inferred-code), paged with --offset/--limit under the protocol-1 page envelope (items) with an exact total
stringsbinscout strings fw.elf --pattern SAVE --min-len 6 --limit 20extracted strings by address; --pattern (substring or regex: expression), --min-len, --section, --include-code (executable-memory hits hidden by default), --decode (xor:<byte>, add:<byte>, or rot:<0-7>, read-only in-memory transform with original offsets); paged by --start/--limit under the page envelope
stack-stringsbinscout stack-strings fw.elf --limit 20recovered stack-constructed strings with function and address, paged under the page envelope
go-funcsbinscout go-funcs fw.elf --limit 20Go functions from the pclntab table, paged under the page envelope; empty table reads as an empty page
bytesbinscout bytes fw.elf 0x400000 --len 32 --as u16raw bytes with VA/file provenance plus bytes_hex and typed values (u8/u16/u32/u64/ptr/cstr/utf16); integer views carry the exact 0x-hex twin values_hex
symbolsbinscout symbols fw.elfimports and exports; Mach-O imports carry the address of their __stubs entry (null when unmapped), and each mapped stub seeds its own import-named function
sectionsbinscout sections fw.elfsection table: name, vaddr (flat VA = IMAGE_BASE + RVA on PE), in-memory/file sizes, permissions
irbinscout ir fw.elf 0x400000 32P-code-inspired lift of the range (error_at on trailing bad bytes, ranges cap at 1 MiB)
ir-coveragebinscout ir-coverage x86_64machine-readable lift coverage for one arch; with BINARY ADDR LEN adds decoded/lifted/unlifted counts from actual lifts
flirt-hintsbinscout flirt-hints fw.elf --addr 0x400000FLIRT-like library hints (read-only): corpus signature matches over each function's leading bytes, paged under the page envelope; suggested names stay hints, querying never writes a sidecar
statsbinscout stats fw.elfstorage stats: binary size, sidecar DB size, analysis counts
annotatebinscout annotate fw.elf 0x400000 --rename main --comment "entry"read/write annotation at an address
search-bytesbinscout search-bytes fw.elf "48 8B ??" --range 0x400000 0x401000paged ??-wildcard byte-pattern matches with --section/--range filters
annotations-exportbinscout annotations-export fw.elfportable annotation document (revision, SHA-256, size, mapping, sorted rows); read-only
annotations-importbinscout annotations-import fw.elf --input doc.json [--overwrite]atomically merge a document; returns rows/changed, default fails on conflicts
diffbinscout diff old.elf new.elf [--db-a A.redb --db-b B.redb]function-level diff between two binaries (matched/added/removed/changed with match reason); both projects open read-only, never creating or modifying a sidecar; the global --raw mapping or --fat-arch selection (if any) applies to both, with per-side --db-a/--db-b instead of the global --db
patchbinscout patch fw.elf 0x400000 --asm "jmp 0x401020"assemble replacement bytes at one x86 address (nop, ret, int3, jmp ADDR, call ADDR) or aarch64 address (nop, ret, brk #IMM, b ADDR, bl ADDR; 4-aligned, byte count a multiple of 4) and export the patch (va, old_hex, new_hex, size_ok); never writes the binary or the sidecar

Paged lists cap at 1024 rows. Addresses accept 0x-hex or decimal strings.

Annotate without flags reads; --rename "" / --comment "" clears, omitting the flag leaves that field alone. rename only accepts known function entries; comment accepts any address.

MCP server

binscout-mcp serves 43 tools over stdio (newline-delimited JSON-RPC): project_info, load, functions, func, blocks, block_insns, diagnostics, disasm, bytes, cfg, structure, pseudo, callees, callers, slice, xrefs, strings, stack_strings, symbols, stats, sections, ir, ir_coverage, flirt_hints, sig_gen, go_funcs, headers, rename, annotation, comment, set_type_hint, get_type_hint, define_func, undefine_func, search_bytes, crypto_scan, scan_yara, annotations_export, annotations_import, diff, diff_func, patch, batch. Each takes binary plus optional db (and an optional raw mapping object or fat_arch slice selection plus optional pdb/debug_file debug inputs on binary-taking tools) and returns one JSON document as text; failures are tool errors.

{
  "mcpServers": {
    "binscout": { "command": "/path/to/binscout-mcp" }
  }
}

Develop

cargo test          # full suite (unit + CLI/MCP e2e over fixtures)
cargo clippy --all-targets -- -D warnings
cargo fmt --check
cargo doc --no-deps # warning-free; `#![warn(missing_docs)]` is on

Project database

Analysis snapshots live in a redb sidecar next to the binary: <binary>.rsdbg.redb by default, overridden per-invocation with --db PATH (CLI) or the db parameter (MCP). load writes the snapshot; rename/comment persist immediately; every other command only reads. binscout stats <binary> reports the binary size, the sidecar size (db_size, 0 before the first load), and the analysis counts, so the storage cost of a snapshot stays visible.

The sidecar is a cache: delete it to drop analysis and annotations, and it is rebuilt on the next load. Snapshots are keyed by binary content, loader mapping (auto versus explicit raw arch/base/entry), and analysis revision: the same bytes opened under a different mapping re-analyze rather than reuse layouts, and opening a sidecar holding annotations under an incompatible mapping fails with a separate-DB error instead of remapping them. Sidecars from older schema versions rebuild the same way. Never commit sidecars — keep them out of version control:

*.rsdbg.redb

License

Dual-licensed under either of:

at your option.

↑↓ navigate openesc close