dbgprobe-mcp-server
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@dbgprobe-mcp-server List attached debug probes, connect to the J-Link, and read 16 bytes from address 0x20000000."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Debug Probe MCP Server
A stateful debug probe Model Context Protocol (MCP) server for developer tooling and AI agents. Works out of the box with Claude Code, VS Code with Copilot, and any MCP-compatible runtime. Communicates over stdio and drives on-chip debug probes (J-Link first, OpenOCD and pyOCD planned) to flash, debug, and inspect embedded targets.
Example: Let Claude Code list attached J-Link probes, connect to your nRF52840, flash a new firmware, read memory, and reset the target — all conversationally.
Demo
Video walkthrough — connecting to a J-Link probe, flashing firmware, loading ELF and SVD for symbol-aware debugging, RTT logging, and breakpoints.
Why this exists
If you've ever typed J-Link Commander commands by hand, copy-pasted memory addresses between a datasheet and a terminal, re-flashed the same firmware 20 times during a debug session, and juggled multiple tool windows — this is for you.
You have a microcontroller on a debug probe. You want an AI agent to interact with it — connect, flash firmware, read/write memory, reset, halt, resume. This server makes that possible.
It gives any MCP-compatible agent a full set of debug probe tools. The agent calls these tools, gets structured JSON back, and reasons about what to do next — without you manually driving JLinkExe for every operation.
What agents can do with it:
Flash and iterate — build firmware, flash it, reset, check behavior — all in one conversation
Inspect memory — read peripheral registers, check RAM contents, verify flash writes
Debug interactively — halt, step, set breakpoints, inspect state, resume
Automate test flows — flash → reset → read output → validate
Multi-probe setups — connect to multiple probes simultaneously, each with its own session
Related MCP server: io.github.microhenrio/openocd-mcp
Who is this for?
Embedded engineers — faster iteration: flash, debug, inspect memory conversationally
Hobbyists and makers — interact with microcontrollers without learning JLinkExe command syntax
QA and test engineers — automated flash-and-test sequences across multiple boards
Researchers — systematic exploration of embedded systems, register inspection
Quickstart (Claude Code)
pip install dbgprobe-mcp-server
# Register the MCP server with Claude Code
claude mcp add dbgprobe -- dbgprobe_mcp
# Or with explicit J-Link path
claude mcp add dbgprobe \
-e DBGPROBE_JLINK_PATH=/Applications/SEGGER/JLink/JLinkExe \
-- dbgprobe_mcpThen in Claude Code, try:
"List attached debug probes, connect to the J-Link, and read 16 bytes from address 0x20000000."
Supported backends
Backend | Status | Probe hardware |
J-Link | Working (v0) | SEGGER J-Link (EDU, EDU Mini, PLUS, PRO, etc.) |
OpenOCD | Planned | ST-Link, CMSIS-DAP, and many others |
pyOCD | Planned | CMSIS-DAP, ST-Link, J-Link (via pyOCD) |
The server is backend-agnostic — tool names (dbgprobe.*) stay the same regardless of which probe you use.
J-Link requirements
Install the SEGGER J-Link Software Pack. The server auto-detects JLinkExe on PATH or in common install locations:
macOS:
/Applications/SEGGER/JLink/Linux:
/opt/SEGGER/JLink/,/usr/bin/Windows:
C:\Program Files\SEGGER\JLink\
Or set DBGPROBE_JLINK_PATH to point to the executable directly.
This project is not affiliated with or sponsored by SEGGER. J-Link is used because it's widely available and well-supported.
Tools
Category | Tools |
Probe |
|
Introspection |
|
ELF |
|
SVD |
|
RTT |
|
Plugins |
|
Tracing |
|
See docs/tools.md for full schemas and examples.
Install (development)
# Editable install from repo root
pip install -e ".[test]"
# Or with uv
uv pip install -e ".[test]"MCP is a protocol — this server works with any MCP-compatible client. Below are setup instructions for the most common ones.
Add to Claude Code
# Standard setup
claude mcp add dbgprobe -- dbgprobe_mcp
# With default target device
claude mcp add dbgprobe \
-e DBGPROBE_JLINK_DEVICE=nRF52840_xxAA \
-- dbgprobe_mcp
# Debug logging
claude mcp add dbgprobe -e DBGPROBE_MCP_LOG_LEVEL=DEBUG -- dbgprobe_mcpAdd to VS Code / Copilot
Add to your project's .vscode/mcp.json (or create it):
{
"servers": {
"dbgprobe": {
"type": "stdio",
"command": "dbgprobe_mcp",
"args": [],
"env": {
"DBGPROBE_JLINK_DEVICE": "nRF52840_xxAA"
}
}
}
}Adjust env to match your target — set DBGPROBE_JLINK_DEVICE to your chip, or remove it to specify the device at connect time.
Add to Cursor
Add to your project's .cursor/mcp.json (or create it). Cursor does not support dots in tool names, so DBGPROBE_MCP_TOOL_SEPARATOR must be set to _:
{
"mcpServers": {
"dbgprobe": {
"command": "dbgprobe_mcp",
"args": [],
"env": {
"DBGPROBE_JLINK_DEVICE": "nRF52840_xxAA",
"DBGPROBE_MCP_TOOL_SEPARATOR": "_"
}
}
}
}Environment variables
Server
Variable | Default | Description |
|
| Debug probe backend. Future: |
|
| Python log level ( |
| enabled | JSONL tracing of every tool call. Set to |
| disabled | Include memory data payloads in traced args (stripped by default). |
|
| Max payload chars before truncation (only when |
|
| Character used to separate tool name segments. Set to |
| disabled | Plugin policy: |
J-Link backend
Variable | Default | Description |
| auto-detect | Explicit path to |
| auto-detect | Explicit path to |
| (none) | Default target device string (e.g. |
|
| Debug interface: |
|
| Interface clock speed in kHz. |
| disabled | Log all GDB RSP packets to file. Set to |
|
| Path for GDB RSP trace log (only when |
ELF Support
Attach an ELF file to a session to enable symbol-aware debugging:
Symbol lookup — resolve function names to addresses and vice versa
Breakpoints by name —
breakpoint.set(symbol="main")instead of raw addressesAuto-enriched responses —
status,step, andhaltincludesymbol+symbol_offsetwhen an ELF is attachedFlash integration — flashing an
.elfauto-attaches it; flashing.hex/.binauto-reloads a previously attached ELF; sibling.elffiles are suggested via hints
> "Attach the ELF, set a breakpoint on main, run, and show me where it halted."The agent calls elf.attach, breakpoint.set(symbol="main"), go, then status — and gets back "halted at main+0" instead of a raw hex address.
SVD Support
Attach an SVD (System View Description) file to a session to enable register-level peripheral access:
Named register reads —
svd.read("GPIO.OUT")returns the raw value and all decoded fields with enum namesField-level reads —
svd.read("GPIO.PIN_CNF[3].PULL")returns the field value and enum name ("PullUp")Safe field writes —
svd.set_field("GPIO.PIN_CNF[3].PULL", "PullUp")does read-modify-writeBatch field updates —
svd.update_fields("GPIO.PIN_CNF[3]", {"DIR": "Output", "PULL": "PullUp"})— one read, one writeRaw register writes —
svd.write("GPIO.OUT", 0x01)— full register, no RMWDiscovery — list peripherals, registers, fields; describe with enums
Auto-decode on mem.read — when an SVD is attached and
mem.readhits a known register address, the response includes decoded fields
> "Attach the SVD, read GPIO.PIN_CNF[3], and set PULL to PullUp."The agent calls svd.attach, svd.read("GPIO.PIN_CNF[3]"), then svd.set_field("GPIO.PIN_CNF[3].PULL", "PullUp") — and gets back decoded field values instead of raw hex.
RTT (Real-Time Transfer)
Start, stop, read, and write to SEGGER RTT channels. The agent can stream target log output and send data to the device — useful for debugging firmware that prints over RTT instead of UART.
> "Start RTT and show me the output."For repetitive flows — read device ID, run a self-test sequence, validate calibration — you can package them as plugins: Python modules that expose custom tools the agent can call directly. Enable with DBGPROBE_MCP_PLUGINS=all. See the nrf52_info example.
Tracing
Every tool call is traced to .dbgprobe_mcp/traces/trace.jsonl and an in-memory ring buffer (last 2000 events). Tracing is on by default — set DBGPROBE_MCP_TRACE=0 to disable.
Use dbgprobe.trace.status and dbgprobe.trace.tail to inspect the trace without reading the file directly.
Try without an agent
You can test the server interactively using the MCP Inspector:
npx @modelcontextprotocol/inspector python -m dbgprobe_mcp_serverRoadmap / TODO
OpenOCD backend — support ST-Link, CMSIS-DAP, and other probes via OpenOCD subprocess
pyOCD backend — native Python probe access via pyOCD library
Multi-core support — target specific cores on multi-core SoCs
Cortex-A/R support — ARM-mode breakpoints (
kind=4); currently Thumb-only (Cortex-M)
Known limitations
Single-client only. The server handles one MCP session at a time (stdio transport).
RTT channel 0 only. RTT support is limited to channel 0 (terminal). Multi-channel RTT is a future enhancement.
Flash clears breakpoints. Flashing new firmware invalidates breakpoints (the code at those addresses may have changed). The session stays alive but breakpoints are cleared.
Cortex-M only. Breakpoints use Thumb-mode (
kind=2). Cortex-A/R targets (ARM-mode,kind=4) are not yet supported.Instruction-level step only.
dbgprobe.stepsingle-steps one CPU instruction. Source-level stepping (step into/over/out) is not supported.
Safety
This server connects an AI agent to real debug hardware. That's the point — and it means the stakes are higher than pure-software tools.
Plugins execute arbitrary code. When plugins are enabled, the agent can create and run Python code on your machine with full server privileges. Review agent-generated plugins before loading them.
Writes affect real hardware. A bad memory write or flash operation can brick a device, wipe calibration data, or trigger unintended behavior. Consider what the agent can reach.
Use tool approval deliberately. When your MCP client prompts you to approve a tool call, consider whether you want to allow it once or always.
This software is provided as-is under the MIT License. You are responsible for what the agent does with your hardware.
License
This project is licensed under the MIT License — see LICENSE for details.
Available Tools
41 toolsdbgprobe.breakpoint.clearC
Clear a breakpoint at a target address.
Inputs: address (required), session_id (required).
dbgprobe.breakpoint.listB
List all active breakpoints for a session.
Inputs: session_id (required).
dbgprobe.breakpoint.setA
Set a breakpoint at a target address or symbol name. Software breakpoints (default) are handled by the debug probe and work on both flash and RAM. Hardware breakpoints use the CPU's FPB and are limited in number (typically 4-6). If 'symbol' is provided and an ELF is attached, resolves the symbol to an address.
Inputs: session_id (required), symbol, address, bp_type.
dbgprobe.connectA
Establish a debug probe session. Returns a session_id and the resolved configuration (backend, executable paths, defaults applied). The target is halted after connecting — this is inherent to the debug probe connection. Use dbgprobe.go to resume execution if needed. For symbol-aware debugging, attach an ELF file with dbgprobe.elf.attach after connecting — this enables breakpoints by function name and address-to-symbol resolution in status/step/halt responses. For register-level peripheral access, attach an SVD file with dbgprobe.svd.attach.
Inputs: device, backend, probe_id, interface, +1 more.
dbgprobe.connections.listA
List all open probe sessions with their status, backend, device, and config. Useful for recovering session IDs after context loss.
Inputs: no named parameters.
dbgprobe.disconnectC
Close a debug probe session and release resources.
Inputs: session_id (required).
dbgprobe.elf.attachA
Parse an ELF file and attach it to a session. Enables symbol-based breakpoints (by function name), address-to-symbol resolution in status/step/halt responses, and symbol search. Re-attaching replaces the previous ELF.
Inputs: path (required), session_id (required).
dbgprobe.elf.infoA
Get ELF metadata for a session: file path, symbol count, entry point, sections. Returns null if no ELF is attached.
Inputs: session_id (required).
dbgprobe.elf.lookupA
Bidirectional symbol lookup. Provide 'symbol' for name-to-address, or 'address' for address-to-name+offset. Exactly one is required.
Inputs: session_id (required), symbol, address.
dbgprobe.elf.symbolsB
Search or list ELF symbols. Optional substring filter, optional type filter (FUNC, OBJECT, NOTYPE, etc.), default limit 50.
Inputs: session_id (required), type, limit, filter.
dbgprobe.eraseA
Erase target flash. With no address params: full chip erase (unlocks secured/read-protected devices like Nordic APPROTECT). With start_addr and end_addr: erase only that range. If session_id is provided, erases through the active GDB session (preferred — no USB contention). Without session_id, uses JLinkExe directly (for session-less erase, e.g. unlocking a secured device before connect).
Inputs: device, backend, end_addr, probe_id, +4 more.
dbgprobe.flashA
Program a firmware image to the target. Supports .hex, .elf (address auto-detected) and raw .bin (requires explicit addr). Optionally verify and reset after flashing. If session_id is provided, tears down GDB, flashes, and restarts (preferred). Without session_id, uses JLinkExe directly (session-less, no debug session needed).
Inputs: path (required), addr, device, verify, +6 more.
dbgprobe.goC
Resume target execution (run/go).
Inputs: session_id (required).
dbgprobe.haltC
Halt the target CPU.
Inputs: session_id (required).
dbgprobe.mem.readA
Read memory from the target. Returns data in the requested format: 'hex' (hex string), 'base64', or 'u32' (array of 32-bit words, little-endian). If an SVD file is attached and the read is exactly one register wide, the response includes decoded SVD field names and values.
Inputs: length (required), address (required), session_id (required), format.
dbgprobe.mem.writeB
Write data to target memory. Provide data in one of: 'hex' (hex string), 'base64', or 'u32' (array of 32-bit words, little-endian).
Inputs: address (required), session_id (required), data, format, +1 more.
dbgprobe.plugin.listA
List loaded plugins with their tool names and metadata. Each plugin may include a 'meta' dict with matching hints like device_name_contains or description — use these to determine which plugin fits the connected device. Also returns whether plugins are enabled and the current policy. Plugins require DBGPROBE_MCP_PLUGINS env var — set to 'all' for all or 'name1,name2' to allow specific plugins. If disabled, tell the user to set this variable when adding the MCP server.
Inputs: no named parameters.
dbgprobe.plugin.loadB
Load a new plugin from a file or directory path. Requires DBGPROBE_MCP_PLUGINS env var to be set.
Inputs: path (required).
dbgprobe.plugin.reloadA
Hot-reload a plugin by name. Re-imports the module and refreshes tools. Requires DBGPROBE_MCP_PLUGINS env var to be set.
Inputs: name (required).
dbgprobe.plugin.templateA
Return a Python plugin template. Use this when creating a new plugin. Optionally pre-fill with a device name. Save the result to .dbgprobe_mcp/plugins/.py, fill in the tools and handlers, then load with dbgprobe.plugin.load.
Inputs: device_name.
dbgprobe.probes.listA
List attached debug probes. Returns vendor/backend-specific info (serial number, description). For J-Link, enumerates via JLinkExe.
Inputs: backend.
dbgprobe.resetA
Reset the target. Modes: 'soft' (default) — software reset and resume, 'hard' — hardware reset, 'halt' — reset and halt at first instruction.
Inputs: session_id (required), mode.
dbgprobe.rtt.readA
Read buffered RTT data from the target. Returns data as text (UTF-8 by default) or hex. Non-blocking — returns whatever is buffered, waiting up to timeout seconds for initial data.
Inputs: session_id (required), timeout, encoding.
dbgprobe.rtt.startA
Start RTT (Real-Time Transfer) on a connected session. Connects to the JLinkGDBServer RTT telnet port and begins buffering target output (channel 0). Optional address hint for the RTT control block in target RAM.
Inputs: session_id (required), address.
dbgprobe.rtt.statusA
Return RTT status: active, bytes buffered, total read/written.
Inputs: session_id (required).
dbgprobe.rtt.stopC
Stop RTT and disconnect from the telnet port.
Inputs: session_id (required).
dbgprobe.rtt.writeA
Write data to the target via RTT channel 0. Input is text (UTF-8 by default) or hex-encoded bytes.
Inputs: data (required), session_id (required), newline, encoding.
dbgprobe.statusA
Query target state. Returns whether the target is running or halted, and if halted, the current PC and stop reason (e.g. breakpoint hit).
Inputs: session_id (required).
dbgprobe.stepA
Single-step one instruction. Target must be halted first. Returns the new PC and stop reason.
Inputs: session_id (required).
dbgprobe.svd.attachA
Parse an SVD file and attach it to a session. Enables named register reads/writes, field-level access, and auto-decode on mem.read. Re-attaching replaces the previous SVD.
Inputs: path (required), session_id (required).
dbgprobe.svd.describeB
Detailed description of a peripheral, register, or field. Includes description, access type, reset value, and enum values as appropriate.
Inputs: target (required), session_id (required).
dbgprobe.svd.infoB
Get SVD metadata for a session: device name, peripheral count. Returns null if no SVD is attached.
Inputs: session_id (required).
dbgprobe.svd.list_fieldsB
List all fields for a register.
Inputs: register (required), peripheral (required), session_id (required).
dbgprobe.svd.list_peripheralsC
List all peripherals defined in the attached SVD.
Inputs: session_id (required).
dbgprobe.svd.list_registersB
List all registers for a peripheral.
Inputs: peripheral (required), session_id (required).
dbgprobe.svd.readB
Read a register or field by name. For registers (e.g. 'GPIO.OUT'), returns the raw value and all decoded fields. For fields (e.g. 'GPIO.PIN_CNF[3].PULL'), returns just the field value and enum name.
Inputs: target (required), session_id (required).
dbgprobe.svd.set_fieldA
Read-modify-write a single register field. Reads the current register value, modifies the specified field, and writes back. Accepts enum names (e.g. 'PullUp') or integer values.
Inputs: field (required), value (required), session_id (required).
dbgprobe.svd.update_fieldsA
Batch read-modify-write: update multiple fields in one register with a single read and write. Accepts a dict of field names to values (enum names or integers).
Inputs: fields (required), register (required), session_id (required).
dbgprobe.svd.writeA
Write a raw value to a full register. No read-modify-write — the entire register is overwritten. For field-level writes, use svd.set_field.
Inputs: value (required), register (required), session_id (required).
dbgprobe.trace.statusB
Return tracing config and event count.
Inputs: no named parameters.
dbgprobe.trace.tailB
Return last N trace events (default 50).
Inputs: n.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 41 tools
Each tool targets a distinct operation (e.g., breakpoint.set vs breakpoint.clear, mem.read vs mem.write) with no overlap. Even within categories like SVD, separate tools for reading, writing, describing, and listing ensure clear boundaries.
All tools follow a consistent hierarchical pattern: 'dbgprobe.<category>.<action>' (e.g., dbgprobe.breakpoint.set, dbgprobe.elf.attach). The naming is uniform and predictable across all 41 tools.
With 41 tools, the set is large but justified by the diverse domain (breakpoints, memory, ELF, SVD, RTT, tracing, plugins). Each tool serves a specific purpose, though a few categories (e.g., SVD with 8 tools) might be slightly over-partitioned.
The tool surface covers the full lifecycle of debug probe interaction: connection management, breakpoints, memory access, flash operations, ELF/SVD integration, RTT, tracing, and plugin extensibility. No obvious gaps hinder typical debugging workflows.
Maintenance
Related MCP Connectors
A comprehensive Model Context Protocol (MCP) server that enables AI assistants to interact with yo…
Shared memory MCP server for Claude Code, Codex, Gemini CLI and Cursor. Cited, editable.
MCP server for your apps' tools and custom tools, plus hosted AI agents and approval-gated workflows
MCP server for Sentry - error monitoring, issue tracking, and debugging for AI assistants
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceAn MCP server that provides comprehensive debugging capabilities for J-Link debuggers, enabling memory, flash, register, and RTT operations through AI assistants.24 PyPI40MIT
- AlicenseAqualityDmaintenanceDebug microcontrollers directly from Claude. This is an MCP server that drives OpenOCD, letting Claude flash firmware, control execution, and inspect a running target — and read your variables and peripheral registers by name instead of raw addresses.3940 PyPI5MIT
- AlicenseAqualityBmaintenanceAgentic 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.44972 PyPI25Apache 2.0
- AlicenseCqualityCmaintenanceMCP server for AI-assisted MCU and embedded firmware debugging. It connects to real hardware via debug probes, inspects CPU/memory/peripherals, manages Keil builds, and provides structured evidence for fault diagnosis.1957 PyPI9MIT