Skip to main content
Glama
README.md
# firehose-mcp

A native Python **MCP (Model Context Protocol)** server for the **Qualcomm Firehose** protocol.

## WHAT THIS IS

After a Qualcomm EDL device has been brought up with a Firehose programmer
(e.g. `prog_firehose_ddr.elf`) via the sibling `sahara-mcp` project, the
device speaks the **Firehose** protocol: an XML command/response stream over
USB bulk endpoints. `firehose-mcp` implements that client side and exposes it
to LLM agents through MCP tools: configure, read/write/erase partitions,
query storage info, send raw XML, and reset.

## ⚠️ ALPHA — NOT TESTED ON REAL HARDWARE

This code is derived from public protocol documentation and the
`linux-msm/qdl` (BSD-3-Clause) reference. It has **not** been validated
against a real Firehose programmer. **Do not flash production devices with
it** without careful review and testing on disposable hardware. Use of this
tool to alter device storage is entirely at your own risk.

## Feature list

- `firehose_configure` — send `<configure>` with `MemoryName`,
  `MaxPayloadSizeToTargetInBytes=1048576`, `ZlpAwareHost=1`, etc.
- `firehose_get_storage_info` — issue `<getstorageinfo>` and decode the JSON
  geometry (LUNs, block sizes, total blocks) returned in the log stream.
- `firehose_program_from_file` / `firehose_read_partition` /
  `firehose_erase_partition` — the `<program>` / `<read>` / `<erase>` XML
  commands with raw binary data streaming.
- `firehose_raw_xml` — dump an arbitrary XML string with the packet framing
  and return the device's `<response>` XML.
- `firehose_reset` — issue the `<power value="reset">` XML.
- `firehose_list_devices` — enumerate visible Qualcomm EDL devices.

Responses are decoded by regex; `ACK` is surfaced as a success, `NAK` is
surfaced with its `rawdata` payload.

## Windows driver note (Zadig / WinUSB)

On Windows the Qualcomm EDL device must be bound to a **WinUSB**-capable
driver so that libusb/pyusb can claim it:

1. Put the device into EDL mode (it enumerates as `Qualcomm HS-USB QDLoader 9008`).
2. Open **Zadig**, select the device, and replace the driver with **WinUSB / libusb-win32**.
3. Load the Firehose programmer first (see `sahara-mcp`), then connect with this server.

On Linux, ensure `modemmanager`/ModemManager is not grabbing the device.

## pip install

```bash
pip install "mcp" "pyusb>=1.2"
# or, from this directory:
pip install -e .
```

`pyusb` also needs a libusb backend (bundled by `libusb` packages; see the
driver note above for Windows).

## Example usage (as an MCP server)

Run the server:

```bash
python firehose_mcp_server.py
```

Then connect an MCP client and call tools, e.g.:

```
firehose_configure(memory_name="emmc")
firehose_get_storage_info(lun=0)
firehose_read_partition(partition=0, file_path="dump.bin", num_sectors=16)
firehose_raw_xml(xml="<?xml version=\"1.0\" ?><data><response value=\"ACK\"/></data>")
firehose_reset()
```

## Protocol reference

The wire format and XML command layouts are derived from the authoritative
BSD-3-Clause reference implementation:

- https://github.com/linux-msm/qdl — `src/firehose.c`, `src/usb.c`
  (Linaro Ltd / Qualcomm).

Key facts taken from that reference:

- The host sends commands **raw as XML** over the USB bulk endpoints; no
  host-side packet framing is added (src/usb.c `usb_write`, src/firehose.c
  `firehose_write`).
- Responses come back as one or more `<?xml ...?><data>` documents
  (`<log value="...">`, `<response value="ACK"/>`, `<response value="NAK"
  rawdata="..."/>`, `rawmode="true"` for binary transfers).
- Configure XML, storage-info JSON-in-log decoding, and the program/read/
  erase/reset XML shapes mirror `src/firehose.c`.

The "fastboot-like" magic/command words and the `NOP;NOP;NOP;` preamble are
produced by the programmer firmware itself and are **not** in the BSD host
reference; the inferred framing constants in the source are explicitly marked
**inferred + untested**.

## License

GPL-3.0 — see [LICENSE](LICENSE). Copyright (c) 2026 libertyrights.
Protocol facts reference `linux-msm/qdl` (BSD-3-Clause). No GPL code is
imported or linked beyond our own.