{
  "markdown": "# Debug Probe MCP Server\n\n<!-- mcp-name: io.github.es617/dbgprobe-mcp-server -->\n\n![MCP](https://img.shields.io/badge/MCP-compatible-blue)\n![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)\n![Python](https://img.shields.io/badge/python-3.11%2B-blue.svg)\n![Debug Probe](https://img.shields.io/badge/Debug_Probe-J--Link-green)\n<!-- TODO: add badges when backends are implemented -->\n<!-- ![Debug Probe](https://img.shields.io/badge/Debug_Probe-OpenOCD-green) -->\n<!-- ![Debug Probe](https://img.shields.io/badge/Debug_Probe-pyOCD-green) -->\n\nA stateful debug probe Model Context Protocol (MCP) server for developer tooling and AI agents.\nWorks 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.\n\n> **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.\n\n### Demo\n\n[Video walkthrough](https://youtu.be/nLt0Vj8TAHs) — connecting to a J-Link probe, flashing firmware, loading ELF and SVD for symbol-aware debugging, RTT logging, and breakpoints.\n\n---\n\n## Why this exists\n\nIf 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.\n\nYou 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.\n\nIt 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.\n\n**What agents can do with it:**\n\n- **Flash and iterate** — build firmware, flash it, reset, check behavior — all in one conversation\n- **Inspect memory** — read peripheral registers, check RAM contents, verify flash writes\n- **Debug interactively** — halt, step, set breakpoints, inspect state, resume\n- **Automate test flows** — flash → reset → read output → validate\n- **Multi-probe setups** — connect to multiple probes simultaneously, each with its own session\n\n---\n\n## Who is this for?\n\n- **Embedded engineers** — faster iteration: flash, debug, inspect memory conversationally\n- **Hobbyists and makers** — interact with microcontrollers without learning JLinkExe command syntax\n- **QA and test engineers** — automated flash-and-test sequences across multiple boards\n- **Researchers** — systematic exploration of embedded systems, register inspection\n\n---\n\n## Quickstart (Claude Code)\n\n```bash\npip install dbgprobe-mcp-server\n\n# Register the MCP server with Claude Code\nclaude mcp add dbgprobe -- dbgprobe_mcp\n\n# Or with explicit J-Link path\nclaude mcp add dbgprobe \\\n  -e DBGPROBE_JLINK_PATH=/Applications/SEGGER/JLink/JLinkExe \\\n  -- dbgprobe_mcp\n```\n\nThen in Claude Code, try:\n\n> \"List attached debug probes, connect to the J-Link, and read 16 bytes from address 0x20000000.\"\n\n<p align=\"center\"><img src=\"https://raw.githubusercontent.com/es617/dbgprobe-mcp-server/main/docs/assets/debug_probe_demo_list_connect.png\" alt=\"Listing probes and connecting\" width=\"600\"></p>\n\n<p align=\"center\"><img src=\"https://raw.githubusercontent.com/es617/dbgprobe-mcp-server/main/docs/assets/debug_probe_demo_erase_flash.png\" alt=\"Erasing and flashing firmware\" width=\"600\"></p>\n\n---\n\n## Supported backends\n\n| Backend | Status | Probe hardware |\n|---|---|---|\n| **J-Link** | Working (v0) | SEGGER J-Link (EDU, EDU Mini, PLUS, PRO, etc.) |\n| **OpenOCD** | Planned | ST-Link, CMSIS-DAP, and many others |\n| **pyOCD** | Planned | CMSIS-DAP, ST-Link, J-Link (via pyOCD) |\n\nThe server is backend-agnostic — tool names (`dbgprobe.*`) stay the same regardless of which probe you use.\n\n### J-Link requirements\n\nInstall the [SEGGER J-Link Software Pack](https://www.segger.com/downloads/jlink/). The server auto-detects `JLinkExe` on PATH or in common install locations:\n\n- **macOS:** `/Applications/SEGGER/JLink/`\n- **Linux:** `/opt/SEGGER/JLink/`, `/usr/bin/`\n- **Windows:** `C:\\Program Files\\SEGGER\\JLink\\`\n\nOr set `DBGPROBE_JLINK_PATH` to point to the executable directly.\n\n> *This project is not affiliated with or sponsored by SEGGER. J-Link is used because it's widely available and well-supported.*\n\n---\n\n## Tools\n\n| Category | Tools |\n|---|---|\n| **Probe** | `dbgprobe.probes.list`, `dbgprobe.connect`, `dbgprobe.erase`, `dbgprobe.disconnect`, `dbgprobe.reset`, `dbgprobe.halt`, `dbgprobe.go`, `dbgprobe.step`, `dbgprobe.status`, `dbgprobe.flash`, `dbgprobe.mem.read`, `dbgprobe.mem.write`, `dbgprobe.breakpoint.set`, `dbgprobe.breakpoint.clear`, `dbgprobe.breakpoint.list` |\n| **Introspection** | `dbgprobe.connections.list` |\n| **ELF** | `dbgprobe.elf.attach`, `dbgprobe.elf.info`, `dbgprobe.elf.lookup`, `dbgprobe.elf.symbols` |\n| **SVD** | `dbgprobe.svd.attach`, `dbgprobe.svd.info`, `dbgprobe.svd.read`, `dbgprobe.svd.write`, `dbgprobe.svd.set_field`, `dbgprobe.svd.update_fields`, `dbgprobe.svd.list_peripherals`, `dbgprobe.svd.list_registers`, `dbgprobe.svd.list_fields`, `dbgprobe.svd.describe` |\n| **RTT** | `dbgprobe.rtt.start`, `dbgprobe.rtt.stop`, `dbgprobe.rtt.read`, `dbgprobe.rtt.write`, `dbgprobe.rtt.status` |\n| **Plugins** | `dbgprobe.plugin.list`, `dbgprobe.plugin.template`, `dbgprobe.plugin.load`, `dbgprobe.plugin.reload` |\n| **Tracing** | `dbgprobe.trace.status`, `dbgprobe.trace.tail` |\n\nSee [docs/tools.md](https://github.com/es617/dbgprobe-mcp-server/blob/main/docs/tools.md) for full schemas and examples.\n\n---\n\n## Install (development)\n\n```bash\n# Editable install from repo root\npip install -e \".[test]\"\n\n# Or with uv\nuv pip install -e \".[test]\"\n```\n\n> MCP is a protocol — this server works with any MCP-compatible client. Below are setup instructions for the most common ones.\n\n## Add to Claude Code\n\n```bash\n# Standard setup\nclaude mcp add dbgprobe -- dbgprobe_mcp\n\n# With default target device\nclaude mcp add dbgprobe \\\n  -e DBGPROBE_JLINK_DEVICE=nRF52840_xxAA \\\n  -- dbgprobe_mcp\n\n# Debug logging\nclaude mcp add dbgprobe -e DBGPROBE_MCP_LOG_LEVEL=DEBUG -- dbgprobe_mcp\n```\n\n## Add to VS Code / Copilot\n\nAdd to your project's `.vscode/mcp.json` (or create it):\n\n```json\n{\n  \"servers\": {\n    \"dbgprobe\": {\n      \"type\": \"stdio\",\n      \"command\": \"dbgprobe_mcp\",\n      \"args\": [],\n      \"env\": {\n        \"DBGPROBE_JLINK_DEVICE\": \"nRF52840_xxAA\"\n      }\n    }\n  }\n}\n```\n\nAdjust `env` to match your target — set `DBGPROBE_JLINK_DEVICE` to your chip, or remove it to specify the device at connect time.\n\n## Add to Cursor\n\nAdd 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 `_`:\n\n```json\n{\n  \"mcpServers\": {\n    \"dbgprobe\": {\n      \"command\": \"dbgprobe_mcp\",\n      \"args\": [],\n      \"env\": {\n        \"DBGPROBE_JLINK_DEVICE\": \"nRF52840_xxAA\",\n        \"DBGPROBE_MCP_TOOL_SEPARATOR\": \"_\"\n      }\n    }\n  }\n}\n```\n\n## Environment variables\n\n### Server\n\n| Variable | Default | Description |\n|---|---|---|\n| `DBGPROBE_BACKEND` | `jlink` | Debug probe backend. Future: `openocd`, `pyocd`. |\n| `DBGPROBE_MCP_LOG_LEVEL` | `WARNING` | Python log level (`DEBUG`, `INFO`, `WARNING`, `ERROR`). Logs go to stderr. |\n| `DBGPROBE_MCP_TRACE` | enabled | JSONL tracing of every tool call. Set to `0`, `false`, or `no` to disable. |\n| `DBGPROBE_MCP_TRACE_PAYLOADS` | disabled | Include memory data payloads in traced args (stripped by default). |\n| `DBGPROBE_MCP_TRACE_MAX_BYTES` | `16384` | Max payload chars before truncation (only when `TRACE_PAYLOADS` is on). |\n| `DBGPROBE_MCP_TOOL_SEPARATOR` | `.` | Character used to separate tool name segments. Set to `_` for MCP clients that reject dots in tool names (e.g. Cursor). |\n| `DBGPROBE_MCP_PLUGINS` | disabled | Plugin policy: `all` or comma-separated plugin names (e.g. `nrf52,stm32`). |\n\n### J-Link backend\n\n| Variable | Default | Description |\n|---|---|---|\n| `DBGPROBE_JLINK_PATH` | auto-detect | Explicit path to `JLinkExe` (or `JLink.exe` on Windows). |\n| `DBGPROBE_JLINK_GDBSERVER_PATH` | auto-detect | Explicit path to `JLinkGDBServerCLExe`. |\n| `DBGPROBE_JLINK_DEVICE` | *(none)* | Default target device string (e.g. `nRF52840_xxAA`). Can be overridden per-session. |\n| `DBGPROBE_INTERFACE` | `SWD` | Debug interface: `SWD` or `JTAG`. |\n| `DBGPROBE_SPEED_KHZ` | `4000` | Interface clock speed in kHz. |\n| `DBGPROBE_GDB_TRACE` | disabled | Log all GDB RSP packets to file. Set to `1`, `true`, or `yes` to enable. |\n| `DBGPROBE_GDB_TRACE_FILE` | `/tmp/gdb_trace.log` | Path for GDB RSP trace log (only when `GDB_TRACE` is on). |\n\n---\n\n## ELF Support\n\nAttach an ELF file to a session to enable symbol-aware debugging:\n\n- **Symbol lookup** — resolve function names to addresses and vice versa\n- **Breakpoints by name** — `breakpoint.set(symbol=\"main\")` instead of raw addresses\n- **Auto-enriched responses** — `status`, `step`, and `halt` include `symbol` + `symbol_offset` when an ELF is attached\n- **Flash integration** — flashing an `.elf` auto-attaches it; flashing `.hex`/`.bin` auto-reloads a previously attached ELF; sibling `.elf` files are suggested via hints\n\n```\n> \"Attach the ELF, set a breakpoint on main, run, and show me where it halted.\"\n```\n\nThe agent calls `elf.attach`, `breakpoint.set(symbol=\"main\")`, `go`, then `status` — and gets back `\"halted at main+0\"` instead of a raw hex address.\n\n<p align=\"center\"><img src=\"https://raw.githubusercontent.com/es617/dbgprobe-mcp-server/main/docs/assets/debug_probe_demo_status_elf.png\" alt=\"ELF symbol resolution — PC resolved to arch_cpu_idle+18\" width=\"600\"></p>\n\n<p align=\"center\"><img src=\"https://raw.githubusercontent.com/es617/dbgprobe-mcp-server/main/docs/assets/debug_probe_demo_test_breakpoint.png\" alt=\"Breakpoint hit at main — symbol-aware debugging\" width=\"600\"></p>\n\n---\n\n## SVD Support\n\nAttach an SVD (System View Description) file to a session to enable register-level peripheral access:\n\n- **Named register reads** — `svd.read(\"GPIO.OUT\")` returns the raw value and all decoded fields with enum names\n- **Field-level reads** — `svd.read(\"GPIO.PIN_CNF[3].PULL\")` returns the field value and enum name (\"PullUp\")\n- **Safe field writes** — `svd.set_field(\"GPIO.PIN_CNF[3].PULL\", \"PullUp\")` does read-modify-write\n- **Batch field updates** — `svd.update_fields(\"GPIO.PIN_CNF[3]\", {\"DIR\": \"Output\", \"PULL\": \"PullUp\"})` — one read, one write\n- **Raw register writes** — `svd.write(\"GPIO.OUT\", 0x01)` — full register, no RMW\n- **Discovery** — list peripherals, registers, fields; describe with enums\n- **Auto-decode on mem.read** — when an SVD is attached and `mem.read` hits a known register address, the response includes decoded fields\n\n```\n> \"Attach the SVD, read GPIO.PIN_CNF[3], and set PULL to PullUp.\"\n```\n\nThe 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.\n\n<p align=\"center\"><img src=\"https://raw.githubusercontent.com/es617/dbgprobe-mcp-server/main/docs/assets/debug_probe_demo_svd.png\" alt=\"SVD attached — 84 peripherals, 2332 registers\" width=\"600\"></p>\n\n---\n\n## RTT (Real-Time Transfer)\n\nStart, 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.\n\n```\n> \"Start RTT and show me the output.\"\n```\n\n<p align=\"center\"><img src=\"https://raw.githubusercontent.com/es617/dbgprobe-mcp-server/main/docs/assets/debug_probe_demo_rtt.png\" alt=\"RTT streaming Zephyr boot log from target\" width=\"600\"></p>\n\nFor 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](https://github.com/es617/dbgprobe-mcp-server/blob/main/examples/nrf52840-dk/nrf52_info_plugin.py).\n\n---\n\n## Tracing\n\nEvery 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.\n\nUse `dbgprobe.trace.status` and `dbgprobe.trace.tail` to inspect the trace without reading the file directly.\n\n---\n\n## Try without an agent\n\nYou can test the server interactively using the [MCP Inspector](https://github.com/modelcontextprotocol/inspector):\n\n```bash\nnpx @modelcontextprotocol/inspector python -m dbgprobe_mcp_server\n```\n\n---\n\n## Roadmap / TODO\n\n- [ ] **OpenOCD backend** — support ST-Link, CMSIS-DAP, and other probes via OpenOCD subprocess\n- [ ] **pyOCD backend** — native Python probe access via pyOCD library\n- [ ] **Multi-core support** — target specific cores on multi-core SoCs\n- [ ] **Cortex-A/R support** — ARM-mode breakpoints (`kind=4`); currently Thumb-only (Cortex-M)\n---\n\n## Known limitations\n\n- **Single-client only.** The server handles one MCP session at a time (stdio transport).\n- **RTT channel 0 only.** RTT support is limited to channel 0 (terminal). Multi-channel RTT is a future enhancement.\n- **Flash clears breakpoints.** Flashing new firmware invalidates breakpoints (the code at those addresses may have changed). The session stays alive but breakpoints are cleared.\n- **Cortex-M only.** Breakpoints use Thumb-mode (`kind=2`). Cortex-A/R targets (ARM-mode, `kind=4`) are not yet supported.\n- **Instruction-level step only.** `dbgprobe.step` single-steps one CPU instruction. Source-level stepping (step into/over/out) is not supported.\n\n---\n\n## Safety\n\nThis server connects an AI agent to real debug hardware. That's the point — and it means the stakes are higher than pure-software tools.\n\n**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.\n\n**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.\n\n**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.\n\nThis software is provided as-is under the MIT License. You are responsible for what the agent does with your hardware.\n\n---\n\n## License\n\nThis project is licensed under the MIT License — see [LICENSE](https://github.com/es617/dbgprobe-mcp-server/blob/main/LICENSE) for details.\n",
  "bytes": 14712,
  "sha": "a6ea1d5f2a353b688ac0b58c7b534f1df9ac355aeaa5672de9e90678b83e58bb",
  "repo_slug": "es617/dbgprobe-mcp-server",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_es617_dbgprobe_mcp_server_a9968dcd/readme"
}