# mcjtag

JTAG/SWD MCP Server for hardware debugging via OpenOCD.

Gives LLMs the ability to interact with JTAG/SWD debug probes — read/write memory, inspect registers, flash firmware, scan JTAG chains, and decode SVD peripheral registers.

**[Documentation](https://mcjtag.warehack.ing)** | **[PyPI](https://pypi.org/project/mcjtag/)**

## Install

```bash
uvx mcjtag
```

Or install permanently:

```bash
uv pip install mcjtag
```

**Requirements:** Python 3.11+, OpenOCD installed on your system.

## Quick Start

```bash
# Auto-spawn OpenOCD with a config file
OPENOCD_CONFIG=openocd-daplink-swd.cfg uvx mcjtag

# Connect to an already-running OpenOCD
OPENOCD_HOST=localhost OPENOCD_PORT=6666 uvx mcjtag

# Add to Claude Code
claude mcp add mcjtag -- uvx mcjtag

# Add to Claude Code with auto-spawn
claude mcp add mcjtag -- env OPENOCD_CONFIG=/path/to/config.cfg uvx mcjtag
```

A typical first session:

1. `probe_diagnostics()` — verify probe, target, and connection health
2. `jtag_scan()` — enumerate the JTAG chain, read IDCODEs
3. `target_state()` — check if the target is halted or running
4. `read_memory("0x08000000", count=4)` — read the vector table
5. `read_registers()` — inspect all CPU registers

## Tools

17 tools across 9 categories:

| Category | Tools | Purpose |
|----------|-------|---------|
| Connection | `connect`, `start_openocd`, `disconnect` | Session lifecycle |
| Diagnostics | `probe_diagnostics` | 9-point health check |
| Target | `target_state`, `target_control` | Halt, resume, step, reset |
| Memory | `read_memory`, `write_memory`, `search_memory` | Read, write (SRAM-safe), search |
| Registers | `read_registers`, `write_register` | CPU register access |
| Flash | `flash_info`, `flash_program` | Bank info, program firmware |
| JTAG | `jtag_scan`, `jtag_shift` | Scan chain, IR/DR shift |
| SVD | `svd_inspect` | Peripheral register decoding |
| Raw | `raw_command` | Direct OpenOCD TCL access |

## Resources

7 MCP resources for polling target state without tool calls:

| URI | Description |
|-----|-------------|
| `jtag://target/state` | Execution state and program counter |
| `jtag://registers/all` | All CPU register values |
| `jtag://flash/banks` | Flash bank topology |
| `jtag://jtag/chain` | JTAG scan chain with TAPs |
| `jtag://svd/peripherals` | Loaded SVD peripheral list |
| `jtag://svd/{peripheral}` | Decoded register values for a peripheral |
| `jtag://transport/info` | Active transport and adapter info |

## Prompts

5 pre-built prompt templates for common workflows:

| Prompt | Purpose |
|--------|---------|
| `identify_chip()` | JTAG scan and chip identification |
| `debug_crash()` | HardFault diagnosis via registers and stack |
| `reverse_engineer_peripheral(peripheral)` | SVD-based register decoding |
| `flash_and_verify(image_path)` | Complete flash programming workflow |
| `memory_map()` | Build memory map from vector table |

## Environment Variables

| Variable | Default | Description |
|----------|---------|-------------|
| `OPENOCD_HOST` | `localhost` | OpenOCD TCL server hostname |
| `OPENOCD_PORT` | `6666` | OpenOCD TCL server port |
| `OPENOCD_CONFIG` | — | Path to .cfg file; auto-spawns OpenOCD if set |
| `OPENOCD_SVD` | — | SVD file path; auto-loaded on connection |
| `MCJTAG_SAFE_WRITE_RANGES` | `0x20000000-0x20100000` | Allowed write ranges (comma-separated hex). Set to `none` for unrestricted |
| `MCJTAG_MAX_SEARCH_RANGE` | `1048576` | Maximum search_memory range in bytes |
| `MCJTAG_ALLOW_RAW` | `false` | Set `true` to disable raw_command deny-list |

## Safety

mcjtag ships with conservative defaults for use alongside safety-critical firmware:

- **Write restrictions** — `write_memory` only allows SRAM by default (0x20000000-0x20100000). Flash, peripheral, and system writes are blocked unless you expand the ranges.
- **Raw command deny-list** — `raw_command` blocks destructive OpenOCD commands (flash erase, memory writes, reset, shutdown). Use dedicated tools instead, or set `MCJTAG_ALLOW_RAW=true`.
- **Flash validation** — `flash_program` checks file existence, extension, and size before writing.
- **Input validation** — Hex parsing rejects negatives, alignment is enforced for writes, values are range-checked against width.

## Hardware

Tested with:

- **Probe**: [Treedix DAP-Link V1](https://www.amazon.com/dp/B0D93ZFVPY) (CMSIS-DAP)
- **Target**: STM32F103C8T6 (Blue Pill)
- **Transport**: SWD and JTAG

Shipped OpenOCD configs:

- `openocd-daplink-swd.cfg` — DAP-Link over SWD (2-wire, recommended)
- `openocd-daplink-jtag.cfg` — DAP-Link over JTAG (4-wire, chain scanning)

## License

MIT
