Skip to main content
Glama
bitpirate-mcp
by Indigaz

bitpirate-mcp

An MCP server for the ESP32-Bit-Pirate - an open-source, ESP32-S3-based clone of the Bus Pirate multibus tool. It exposes the bench's UART, SPI (incl. the on-device flash shell), I2C, 1-Wire and GPIO capabilities as MCP tools over stdio, so an AI agent can probe, dump and analyze firmware on a target board end-to-end: attach a device to the ESP32, let the agent drive the tools, and get extracted binaries and analysis out the other end.

A port of buspirate-mcp (Marc Plogas, MIT) from the BusPirate 6's BPIO2 binary protocol to the Bit-Pirate's text-console protocol. The tool/dispatch/session/safety layers are largely kept verbatim; the device layer was replaced and re-grounded in the Bit-Pirate v1.8 firmware source.

What makes this different from the upstream

buspirate-mcp (BP6)

bitpirate-mcp (ESP32-Bit-Pirate)

Transport

BPIO2 flatbuffers over a 2nd CDC port

Plain text console at 115200 baud (single CDC port)

Device layer

hardware.py (BPIO2 SDK, submodule)

bitpirate_hardware.py (prompt/marker-aware console driver, no vendor deps)

Flash work

Manual JEDEC sequences + host-side page program/erase

Native firmware flash shell: probe, on-device analysis, search, strings, read, raw dump, patch write, full erase

On-device analysis

None

BinaryAnalyzer in firmware: file signatures, secret patterns (keys/hashes/URLs), entropy summary

Raw transactions

spi_transfer byte arrays

BP6-style instruction syntax [0x9F r:3] dispatched by the firmware

Logic analyzer

FALA (5 tools, 75 MHz, 8 ch)

Removed - no FALA; verify_connection uses the DIO measure edge/frequency detector

Power supply

Hardware PSU (3 tools)

None on the bare devkit - tools report psu: unavailable gracefully

Signal timing

Fast binary protocol

~2 s per menu round-trip (firmware main-loop latency); raw dump is serial-bottlenecked (~11.5 KB/s)

Gains: the Bit-Pirate is stronger for RE than the BP6 in one key respect - the firmware does binary analysis on the device (39 secret patterns, file signature table, entropy), so spi_flash_analyze returns findings without pulling the whole image first. It is also cheaper (~$15 board + devkit vs $100+).

Related MCP server: agentic-hil

Architecture

MCP client (Claude Code, Hermes, any MCP host)
  |  stdio
  v
server.py            tool definitions + dispatch + safety tiers + session mgmt
  |
  v
tools.py             33 tool implementations (protocol-agnostic where possible)
  |
  v
bitpirate_hardware.py  THE device layer (the only firmware-specific module)
  |  pyserial, /dev/ttyACM0 @115200
  v
ESP32-S3 running ESP32-Bit-Pirate v1.8 text console

The console driver has two read modes, both grounded in the firmware's actual output:

  • Prompt-aware reads - command, then read until the trailing mode prompt (DIO> , SPI> , …) matches at the end of the transcript. Used for mode switches, DIO, and instruction-syntax transactions.

  • Marker-aware reads - shell flows (flash shell, config wizard) don't end at a mode prompt; the driver reads until a known completion marker (=== SPI Flash Shell ===, SPI Flash Dump: Done., SPI configured., …) and answers intermediate prompts in the exact order the firmware asks them.

A quadratic-echo line-length guard (250 chars) protects the firmware's getLine input path.

Every command string in the driver was taken from the v1.8 firmware source - SpiFlashShell.cpp, SpiController.cpp, DioController.cpp, UserInputManager.cpp, ActionDispatcher.cpp - not assumed.

Tools (33)

Tool

Tier

Notes

list_devices

read-only

USB CDC console ports

verify_connection

read-only

DIO measure edge/frequency detector on TX/RX

scan_baud

read-only

baud probing over a UART session

open_uart / read_output / send_command / close_uart

allowed / read

console interaction with targets

set_voltage / set_power

approval

report psu: unavailable (no PSU on this board)

enter_download_mode

allowed

boot/EN pin toggling (0-48 GPIO)

read_flash

allowed

esptool through the firmware UART bridge (Phase 4)

open_spi / close_spi

allowed

mode switch + engagement session; close exits the flash shell

spi_probe

read-only

firmware flash probe: JEDEC ID, manufacturer, model, capacity, capability notes

spi_read

read-only

region read as hexdump (flash shell menu 5)

spi_dump

read-only

raw full-chip dump to a file (menu 8) - the workhorse for RE

spi_write

approval

patch write from file/hex/ASCII (menu 6), auto-erase option

spi_flash_erase

approval

full-chip erase (menu 9) - destructive

spi_transfer

read-only

BP6-style instruction [0x9F r:3] (JEDEC, status, custom sequences)

spi_config

allowed

MOSI/MISO/SCLK/CS pins + 1-80 MHz + WP/HOLD (NVS-persisted)

spi_flash_analyze

read-only

on-device BinaryAnalyzer: file signatures, secrets, entropy

spi_flash_search

read-only

string search (1-32 bytes) with context

spi_flash_strings

read-only

printable-string extraction

open_i2c / i2c_scan / i2c_read / i2c_write / i2c_dump / close_i2c

mixed

I2C bus (host-driven; firmware session work pending)

open_1wire / onewire_search / onewire_read / close_1wire

mixed

1-Wire bus

Approval-tier tools require an explicit _confirmed: true and the firmware's own confirmation prompts are driven - double-gated for destructive operations.

Install

# any Python 3.10+ (tested on 3.11)
git clone https://github.com/Indigaz/bitpirate-mcp
cd bitpirate-mcp
python3 -m venv .venv          # or: uv venv --python 3.11 .venv
.venv/bin/pip install -e .

Register with an MCP host (.mcp.json):

{
  "mcpServers": {
    "bitpirate": {
      "command": "/absolute/path/to/bitpirate-mcp/.venv/bin/python",
      "args": ["-m", "buspirate_mcp"]
    }
  }
}

Board requirements: an ESP32-S3 devkit running ESP32-Bit-Pirate v1.x, exposing a USB CDC console (/dev/ttyACM0 on Linux). No pin configuration needed for first use - the firmware keeps its SPI pin map in NVS (defaults on a typical Bit-Pirate build: MOSI 40, MISO 39, SCLK 41, CS 4, 20 MHz, WP 7); spi_config re-points any free GPIO.

Typical RE workflow

  1. Attach a target to the bench (SPI flash via clip, or I2C bus).

  2. spi_probe - identify the chip (ID, manufacturer, capacity).

  3. spi_dump → ~/re-lab/<target>/flash.bin - raw image off the bus.

  4. spi_flash_analyze / spi_flash_strings / spi_flash_search - on-device findings (what firmware, embedded keys, embedded binaries).

  5. Hand the image to your static-analysis tooling (Ghidra, REA, etc.).

Testing & verification

  • 221 tests, all passing. The device layer is tested with a transcript-driven protocol mock (FakeSerial): scripted firmware transcripts are released only after the triggering command is written, simulating real round-trip latency so command/response pairing cannot bleed across commands. The mock is a FIFO of (line → response) so repeated prompts (e.g. y/y) resolve in firmware order, and it accepts raw bytes for the dump path.

  • Live-verified on hardware (ESP32-S3 devkit + Bit-Pirate v1.8, no target attached - no-chip paths):

    • DIO: read, edge counter, and electrical drive-HIGH/LOW self-test

    • instruction syntax: [0x9F r:3] → 00 00 00 (floating bus, correct)

    • flash shell: probe (no-chip detection), analyze short-circuit, clean shell exit

  • Reproduce the live smoke tests: scripts/smoke_live.py, scripts/smoke_live_spi.py (read-only by design).

Roadmap

  • Phase 3 - I2C/1-Wire sessions rewritten against the firmware's native controllers (scan/read/write/dump + I2C monitor/glitch when grounded); SPI EEPROM shell (24cxx/25xxx - matches common bench EEPROMs).

  • Phase 4 - read_flash via the firmware UART bridge + esptool (transparent bridge is persistent; requires a button/USB-replug to exit).

  • Phase 5 - packaging: rename the buspirate_mcp package to bitpirate_mcp, PyPI publish, CI.

Credits

  • Upstream: buspirate-mcp by Marc Plogas (MIT) - the tool/dispatch/session/ safety architecture it builds on.

  • Hardware & firmware: ESP32-Bit-Pirate by geo-tp (the console protocol, flash shell and analyzer this port drives).

  • Port to the ESP32-Bit-Pirate: designed and implemented by Hermes Agent (Nous Research)

    • the LLM agent driving this bench - under direction by Christian Brooks (Indigaz), who owns the hardware, set the goals, and reviews the work.

  • Method: every firmware-facing string is grounded in v1.8 source; the whole port is test-first (221 tests) and smoke-tested against the real board before each phase ships.

License

MIT - see LICENSE. Upstream copyright (c) Marc Plogas; port copyright (c) 2026 Hermes Agent (Nous Research) / Christian Brooks.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      D
      maintenance
      MCP server for BusPirate 6 hardware security testing. Exposes UART, SPI, I2C, 1-Wire, power supply, GPIO, and logic analyzer operations as tools.
      2
      MIT
    • A
      license
      A
      quality
      B
      maintenance
      Agentic Hardware-in-the-Loop (Agentic HIL) lets coding agents develop firmware on real embedded boards: flash, reset, read UART and exchange CAN traffic, diagnose and fix. Local, policy-gated MCP tools support OpenOCD, pyOCD and STM32CubeProgrammer, with pytest for CI.
      44
      972 PyPI
      26
      Apache 2.0
    • A
      license
      A
      quality
      B
      maintenance
      Enables AI agents to interact with physical embedded target boards over a dual-CDC USB bridge using MCP tools. It exposes console reading, pattern waiting, command sending, reboot/login state machines, and in-RAM MicroPython execution while a single-owner daemon safely arbitrates access to the serial devices.
      6
      4
      Apache 2.0
    • A
      license
      Not graded
      quality
      B
      maintenance
      Exposes 238 schema-typed tools over streamable-HTTP MCP that let a client drive a Flipper Zero, an AWOK Biscuit (ESP32-C5) and an ESP32 Marauder — scanning, screen mirroring, storage, and other device operations — from natural-language or direct tool calls. Transmit/attack tools stay behind an explicit human confirmation gate.
      MIT