Tools
mcjtag exposes 17 tools organized across 9 mixin categories. Each tool is a callable MCP function that an LLM client (or any MCP-compatible client) invokes over JSON-RPC.
All tools that interact with the target require an active OpenOCD connection. If you haven’t connected yet, start with connect() or start_openocd().
Connection Tools
Section titled “Connection Tools”Manage the lifecycle of the OpenOCD connection.
connect
Section titled “connect”Connect to a running OpenOCD instance over its TCL RPC interface.
| Parameter | Type | Default | Description |
|---|---|---|---|
host | str | "localhost" | OpenOCD TCL RPC hostname |
port | int | 6666 | OpenOCD TCL RPC port |
Returns: ConnectionStatus — connected, host, port, message
Use this when OpenOCD is already running (started manually or by another process). For auto-starting OpenOCD, use start_openocd instead.
If already connected, returns immediately with a message to disconnect first.
# Connect to OpenOCD on the default portconnect()
# Connect to a remote OpenOCD instanceconnect(host="192.168.1.50", port=6666)start_openocd
Section titled “start_openocd”Spawn an OpenOCD subprocess with the given config file, then connect to it.
| Parameter | Type | Default | Description |
|---|---|---|---|
config | str | (required) | Path to OpenOCD .cfg file |
tcl_port | int | 6666 | TCL RPC port for the new OpenOCD process |
extra_args | str | "" | Additional CLI arguments (space-separated) |
Returns: ConnectionStatus — connected, host, port, process_pid, message
The spawned process is tracked internally. When you call disconnect(), the process is stopped automatically.
# Start OpenOCD with SWD configstart_openocd(config="/path/to/openocd-daplink-swd.cfg")
# Start on a non-default port with extra flagsstart_openocd( config="/path/to/openocd-daplink-swd.cfg", tcl_port=6667, extra_args="-d2")See OpenOCD Configurations for the shipped config files.
disconnect
Section titled “disconnect”Close the OpenOCD connection and stop the managed process if one was started via start_openocd.
| Parameter | Type | Default | Description |
|---|---|---|---|
| (none) |
Returns: ConnectionStatus — connected=false, message
Safe to call even when not connected.
disconnect()Diagnostics
Section titled “Diagnostics”probe_diagnostics
Section titled “probe_diagnostics”Run a comprehensive health check on the probe, target, and server capabilities. Call this first after connecting to understand what is working and what is not.
| Parameter | Type | Default | Description |
|---|---|---|---|
| (none) |
Returns: DiagnosticsResult — connected, checks (list of DiagnosticCheck), summary
Runs 9 diagnostic checks in sequence:
| Check | What it tests |
|---|---|
connection | Whether the OpenOCD session is active |
openocd_version | OpenOCD version string |
adapter_speed | Debug adapter clock speed |
transport | Active transport (SWD or JTAG) |
target | Whether any targets are defined |
target_state | Whether the target state can be read |
memory_access | Read the CPUID register at 0xE000ED00 |
flash | Flash bank enumeration |
svd | Whether an SVD file is loaded |
Each check returns a name, pass/fail boolean, and a detail string with guidance on what to try if it failed.
probe_diagnostics()# Returns something like:# {# "connected": true,# "checks": [# {"name": "connection", "ok": true, "detail": "Connected to OpenOCD"},# {"name": "openocd_version", "ok": true, "detail": "Open On-Chip Debugger 0.12.0"},# ...# ],# "summary": "connected, target found, 8/9 checks passed"# }Target Control
Section titled “Target Control”target_state
Section titled “target_state”Query the current execution state of the target.
| Parameter | Type | Default | Description |
|---|---|---|---|
| (none) |
Returns: TargetStateResult — state, pc (hex string or null), halted (bool), name
The state field can be one of: halted, running, reset, debug-running.
The pc (program counter) is only available when the target is halted.
target_state()# {"state": "halted", "pc": "0x08001234", "halted": true, "name": "stm32f1x.cpu"}target_control
Section titled “target_control”Control target execution: halt, resume, single-step, or reset.
| Parameter | Type | Default | Description |
|---|---|---|---|
action | str | (required) | One of: "halt", "resume", "step", "reset_halt", "reset_run" |
address | str | None | None | Hex address for resume/step (e.g. "0x08001000") |
Returns: TargetControlResult — action, state, pc, halted
Actions:
| Action | Effect |
|---|---|
halt | Stop the CPU at its current instruction |
resume | Continue execution (optionally from a specific address) |
step | Execute one instruction, then halt again |
reset_halt | Reset the chip and halt at the reset vector |
reset_run | Reset the chip and let it run freely |
The address parameter is only used with resume and step. If provided, it must be 2-byte aligned (ARM Thumb requirement). Odd addresses are rejected.
# Stop the CPUtarget_control(action="halt")
# Single-step one instructiontarget_control(action="step")
# Resume execution from a specific addresstarget_control(action="resume", address="0x08001000")
# Reset and halt at the reset vectortarget_control(action="reset_halt")Memory
Section titled “Memory”read_memory
Section titled “read_memory”Read memory from the target at a given address.
| Parameter | Type | Default | Description |
|---|---|---|---|
address | str | (required) | Start address in hex (e.g. "0x08000000") |
count | int | 1 | Number of elements to read (1—4096) |
width | int | 32 | Element width in bits: 8, 16, 32, or 64 |
Returns: MemoryDump — address, width, count, values (list of hex strings), hexdump (formatted text)
The hexdump field provides a formatted view with hex bytes and ASCII representation, similar to xxd:
08000000: 00 50 00 20 A1 01 00 08 AB 01 00 08 AD 01 00 08 |.P. ............|Unaligned reads produce a warning (they can cause bus faults on Cortex-M0 targets).
# Read 16 words from flashread_memory(address="0x08000000", count=16, width=32)
# Read a byte array from SRAMread_memory(address="0x20000100", count=64, width=8)
# Read a single 32-bit word (the default)read_memory(address="0xE000ED00")write_memory
Section titled “write_memory”Write values to target memory. By default, writes are restricted to SRAM regions.
| Parameter | Type | Default | Description |
|---|---|---|---|
address | str | (required) | Start address in hex (e.g. "0x20000000") |
values | list[str] | (required) | Hex values to write (e.g. ["0xDEADBEEF", "0x12345678"]) |
width | int | 32 | Element width in bits: 8, 16, or 32 |
Returns: MemoryWriteResult — address, width, count, written
Safety checks:
- Address must fall within configured safe write ranges (default:
0x20000000—0x20100000) - Writes must be aligned to the element width (e.g., 32-bit writes to 4-byte aligned addresses)
- Each value must fit within the specified width
See Environment Variables to configure MCJTAG_SAFE_WRITE_RANGES, and Memory Layout for why SRAM is the default safe zone.
# Write two 32-bit words to SRAMwrite_memory(address="0x20000000", values=["0xDEADBEEF", "0x12345678"])
# Write byteswrite_memory(address="0x20000100", values=["0x41", "0x42", "0x43"], width=8)search_memory
Section titled “search_memory”Search for a byte pattern within a memory range.
| Parameter | Type | Default | Description |
|---|---|---|---|
pattern | str | (required) | Hex byte pattern (e.g. "DEADBEEF") |
start | str | (required) | Start address, inclusive (hex) |
end | str | (required) | End address, exclusive (hex) |
Returns: MemorySearchResult — pattern, start, end, matches (list of hex addresses), count
The search reads memory in 4 KB chunks and reports progress via MCP progress notifications. The maximum search range is 1 MB by default, configurable via the MCJTAG_MAX_SEARCH_RANGE environment variable.
# Search for 0xDEADBEEF in SRAMsearch_memory(pattern="DEADBEEF", start="0x20000000", end="0x20010000")
# Search for an ASCII string ("Hello")search_memory(pattern="48656C6C6F", start="0x20000000", end="0x20008000")Registers
Section titled “Registers”read_registers
Section titled “read_registers”Read CPU registers from the halted target.
| Parameter | Type | Default | Description |
|---|---|---|---|
names | list[str] | None | None | Register names to read, or None for all |
Returns: RegisterSet — registers (dict of name to hex value), count
The target must be halted for register access. Common ARM Cortex-M registers:
| Register | Purpose |
|---|---|
r0—r12 | General-purpose registers |
sp (r13) | Stack pointer |
lr (r14) | Link register (return address) |
pc (r15) | Program counter |
xPSR | Program status register |
msp | Main stack pointer |
psp | Process stack pointer |
# Read all registersread_registers()
# Read specific registersread_registers(names=["pc", "sp", "lr", "xPSR"])write_register
Section titled “write_register”Write a value to a single CPU register. The target must be halted.
| Parameter | Type | Default | Description |
|---|---|---|---|
name | str | (required) | Register name (e.g. "pc", "r0", "sp") |
value | str | (required) | Hex value to write (e.g. "0x08001000") |
Returns: RegisterWriteResult — name, value, written
# Set the program counterwrite_register(name="pc", value="0x08001000")
# Set r0 to zerowrite_register(name="r0", value="0x00000000")flash_info
Section titled “flash_info”List all flash banks on the target with metadata.
| Parameter | Type | Default | Description |
|---|---|---|---|
| (none) |
Returns: FlashBanksResult — banks (list of FlashBankInfo), count
Each FlashBankInfo contains:
| Field | Type | Description |
|---|---|---|
index | int | Bank index (0-based) |
name | str | Flash driver name |
base | str | Base address (hex) |
size | int | Total size in bytes |
sectors | int | Number of sectors (-1 if unavailable) |
target | str | Associated target name |
flash_info()# {# "banks": [{# "index": 0,# "name": "stm32f1x",# "base": "0x08000000",# "size": 65536,# "sectors": 64,# "target": "stm32f1x.cpu"# }],# "count": 1# }flash_program
Section titled “flash_program”Program a firmware image into flash memory.
| Parameter | Type | Default | Description |
|---|---|---|---|
path | str | (required) | Path to the firmware image file |
erase | bool | True | Erase affected sectors before writing |
verify | bool | True | Verify flash contents after writing |
Returns: FlashProgramResult — path, erased, verified, success, message
This is a destructive operation — it overwrites flash contents.
Validation checks before programming:
- File must exist
- Extension must be one of:
.bin,.hex,.elf,.ihex,.srec,.s19 - File must not be empty
- File must not exceed 16 MB
Progress is reported in phases: erase, write, verify.
# Program with default erase + verifyflash_program(path="/home/user/firmware.bin")
# Program without erasing (overwrite in-place)flash_program(path="/home/user/firmware.hex", erase=False)jtag_scan
Section titled “jtag_scan”Enumerate all TAPs (Test Access Ports) on the JTAG scan chain.
| Parameter | Type | Default | Description |
|---|---|---|---|
| (none) |
Returns: JTAGChain — taps (list of TAPResult), count
Each TAPResult contains:
| Field | Type | Description |
|---|---|---|
name | str | TAP name (e.g. "stm32f1x.cpu") |
idcode | str | JTAG IDCODE (hex, e.g. "0x1ba01477") |
ir_length | int | Instruction register length in bits |
enabled | bool | Whether the TAP is enabled |
The IDCODE uniquely identifies the silicon. Bits 1—11 contain the manufacturer ID (JEDEC), and bits 12—27 contain the part number.
jtag_scan()# {# "taps": [{# "name": "stm32f1x.cpu",# "idcode": "0x1ba01477",# "ir_length": 4,# "enabled": true# }],# "count": 1# }jtag_shift
Section titled “jtag_shift”Perform a raw JTAG IR scan or DR scan operation.
| Parameter | Type | Default | Description |
|---|---|---|---|
tap | str | (required) | TAP name (e.g. "stm32f1x.cpu") |
operation | str | (required) | "irscan" or "drscan" |
value | str | (required) | Value to shift in (hex, e.g. "0x0E") |
bits | int | None | None | Number of bits (required for drscan) |
Returns: JTAGShiftResult — operation, tap, value_in, value_out, bits
This is a low-level tool for protocols not covered by the higher-level tools. Most users should use the target, memory, and register tools instead.
# Read the IDCODE register (IR = 0x0E on ARM DAP)jtag_shift(tap="stm32f1x.cpu", operation="irscan", value="0x0E")
# Scan a 32-bit data registerjtag_shift(tap="stm32f1x.cpu", operation="drscan", value="0x00000000", bits=32)svd_inspect
Section titled “svd_inspect”Load an SVD file and/or inspect peripherals and registers with decoded bitfields.
| Parameter | Type | Default | Description |
|---|---|---|---|
svd_path | str | None | None | Path to .svd file (loads it if provided) |
peripheral | str | None | None | Peripheral name to inspect (e.g. "GPIOA") |
register | str | None | None | Specific register (e.g. "CR1"). Requires peripheral. |
Returns: varies by arguments:
| Arguments | Return Type | Content |
|---|---|---|
svd_path only | SVDListResult | List of all peripherals |
| neither (SVD already loaded) | SVDListResult | List of all peripherals |
peripheral | SVDPeripheralResult | All registers for that peripheral, decoded |
peripheral + register | SVDPeripheralResult | Single register, decoded |
SVD (System View Description) files describe a chip’s memory-mapped peripheral registers and their bitfields. They are provided by silicon vendors and available from the CMSIS-SVD repository.
Validation checks:
- SVD file must exist, have a
.svdextension, and be under 50 MB
Progress reporting: When decoding a full peripheral, progress is reported per register.
# Load an SVD file and list peripheralssvd_inspect(svd_path="/path/to/STM32F103.svd")
# List peripherals (SVD already loaded)svd_inspect()
# Decode all GPIOA registerssvd_inspect(peripheral="GPIOA")
# Decode a single registersvd_inspect(peripheral="USART1", register="CR1")Example decoded register output:
{ "peripheral": "GPIOA", "registers": { "CRL": { "name": "CRL", "address": "0x40010800", "raw_value": "0x44444444", "fields": [ {"name": "MODE0", "value": 0, "width": 2, "offset": 0, "description": "Port mode bits"}, {"name": "CNF0", "value": 1, "width": 2, "offset": 2, "description": "Port configuration bits"} ] } }}Raw Command
Section titled “Raw Command”raw_command
Section titled “raw_command”Send a raw OpenOCD TCL command and return the response.
| Parameter | Type | Default | Description |
|---|---|---|---|
command | str | (required) | OpenOCD TCL command string |
Returns: RawCommandResult — command, response
This is an escape hatch for OpenOCD functionality not covered by the typed tools. A deny-list blocks destructive commands by default:
| Blocked Pattern | Use Instead |
|---|---|
flash erase, flash write, flash protect, flash fill | flash_program() |
mww, mwh, mwb, write_memory | write_memory() |
reset | target_control(action="reset_halt") or target_control(action="reset_run") |
shutdown, exit | disconnect() |
reg | read_registers() / write_register() |
eval, subst, uplevel | Blocked to prevent deny-list bypass via TCL metaprogramming |
Set MCJTAG_ALLOW_RAW=true to disable the deny-list entirely. See Environment Variables for details.
# Query OpenOCD versionraw_command(command="version")
# Check adapter speedraw_command(command="adapter speed")
# List configured targetsraw_command(command="targets")
# Read a chip-specific register via OpenOCD commandsraw_command(command="flash banks")