<p align="center"> <img src="logo.png" alt="jlink-mcp logo" width="200"> </p>
<h1 align="center">jlink-mcp</h1>
<p align="center"> <strong>Give AI hands to touch silicon.</strong><br> An MCP server that lets LLMs debug embedded devices through SEGGER J-Link probes. </p>
<p align="center"> <img src="https://img.shields.io/badge/MCP-Server-blue?style=for-the-badge" alt="MCP Server"> <img src="https://img.shields.io/badge/TypeScript-007ACC?style=for-the-badge&logo=typescript&logoColor=white" alt="TypeScript"> <img src="https://img.shields.io/badge/J--Link-SEGGER-00979D?style=for-the-badge" alt="J-Link"> <img src="https://img.shields.io/badge/ARM-Cortex--M-0091BD?style=for-the-badge" alt="ARM Cortex-M"> </p>
<p align="center"> <a href="https://github.com/Klievan/jlink-mcp/stargazers"><img src="https://img.shields.io/github/stars/Klievan/jlink-mcp?style=flat-square" alt="GitHub Stars"></a> <a href="https://github.com/Klievan/jlink-mcp/blob/main/LICENSE"><img src="https://img.shields.io/github/license/Klievan/jlink-mcp?style=flat-square" alt="License"></a> <a href="https://www.npmjs.com/package/jlink-mcp"><img src="https://img.shields.io/npm/v/jlink-mcp?style=flat-square&color=cb0000" alt="npm"></a> <a href="https://www.npmjs.com/package/jlink-mcp"><img src="https://img.shields.io/npm/dt/jlink-mcp?style=flat-square&color=cb0000" alt="npm downloads"></a> <a href="https://marketplace.visualstudio.com/items?itemName=Klievan.jlink-mcp"><img src="https://img.shields.io/visual-studio-marketplace/v/Klievan.jlink-mcp?style=flat-square&label=VSCode" alt="VSCode Marketplace"></a> <a href="https://smithery.ai/server/@Klievan/jlink-mcp"><img src="https://smithery.ai/badge/@Klievan/jlink-mcp" alt="Smithery"></a> <a href="https://modelcontextprotocol.io"><img src="https://img.shields.io/badge/MCP-Compatible-green?style=flat-square" alt="MCP Compatible"></a> </p>
---
What is this?
jlink-mcp connects AI assistants (Claude, Copilot, etc.) to your embedded hardware via SEGGER J-Link debug probes using the Model Context Protocol.
Instead of manually typing J-Link commands, your AI assistant can:
- Read registers and memory to understand device state
- Flash firmware and reset devices
- Stream RTT logs and search them by level/module/regex
- Diagnose crashes by auto-decoding ARM Cortex-M fault registers
- Control execution — halt, step, resume, breakpoints
- Start GDB servers for full debugging sessions
Also supports OpenOCD (ST-Link, CMSIS-DAP, FTDI) and Black Magic Probe backends.
Quick Start
Claude Desktop
Add to your Claude Desktop config (~/Library/Application Support/Claude/claude_desktop_config.json):
{
"mcpServers": {
"jlink": {
"command": "node",
"args": ["/path/to/jlink-mcp/out/mcp/standalone.js"],
"env": {
"JLINK_DEVICE": "nRF52840_XXAA"
}
}
}
}
Claude Code
Add .mcp.json to your project root:
{
"mcpServers": {
"jlink": {
"command": "node",
"args": ["out/mcp/standalone.js"],
"cwd": "/path/to/jlink-mcp",
"env": {
"JLINK_DEVICE": "nRF52840_XXAA"
}
}
}
}
VSCode Extension
Install the extension (requires VSCode 1.99+). It auto-registers the MCP server via the native vscode.lm API. Configure the device in settings:
jlinkMcp.jlink.device = "nRF52840_XXAA"
Copilot Chat and Claude in VSCode will automatically discover all 31 tools.
From Source
git clone https://github.com/Klievan/jlink-mcp.git
cd jlink-mcp
npm install
npm run compile
JLINK_DEVICE=nRF52840_XXAA node out/mcp/standalone.js
Tools (31)
Workflow Tools (start here)
| Tool | Description | |------|-------------| | start_debug_session | One-call setup. Starts GDB server + connects RTT + returns boot log. | | snapshot | Captures full device state: registers, fault status, stack dump, RTT output. | | diagnose_crash | Auto-reads and decodes ARM Cortex-M fault registers (CFSR, HFSR, MMFAR, BFAR) with exception stack frame. |
Device Control
| Tool | Description | |------|-------------| | device_info | Probe type, target CPU, compact register summary | | halt | Halt CPU | | resume | Resume CPU | | reset | Reset device (optionally halt after reset) | | step | Single-step one instruction |
Memory & Registers
| Tool | Description | |------|-------------| | read_memory | Read memory at address (clean hex dump output) | | write_memory | Write 32-bit value to address | | read_registers | All CPU registers in compact format | | read_register | Read specific register (PC, SP, R0-R12, etc.) |
Flash
| Tool | Description | |------|-------------| | flash | Flash .hex/.bin/.elf firmware to device | | erase | Erase entire flash |
Breakpoints
| Tool | Description | |------|-------------| | set_breakpoint | Set hardware breakpoint at address | | clear_breakpoints | Clear all breakpoints |
GDB Server
| Tool | Description | |------|-------------| | gdb_server_start | Start probe's GDB server | | gdb_server_stop | Stop GDB server + disconnect RTT | | gdb_server_status | GDB server, RTT, and proxy status |
RTT (Real-Time Transfer)
| Tool | Description | |------|-------------| | rtt_connect | Connect to RTT telnet port | | rtt_disconnect | Disconnect from RTT | | rtt_read | Read recent log lines (ANSI stripped, Zephyr format parsed) | | rtt_search | Filter logs by level (err/wrn/inf/dbg), module, or regex | | rtt_send | Send data to device via RTT down-channel | | rtt_clear | Clear RTT buffer |
Telnet Proxy (Trice / Pigweed)
| Tool | Description | |------|-------------| | telnet_proxy_start | Start TCP proxy that tees RTT for external detokenizers | | telnet_proxy_stop | Stop proxy | | telnet_proxy_status | Proxy connection status | | telnet_proxy_read | Read raw proxy buffer |
Advanced
| Tool | Description | |------|-------------| | probe_command | Execute raw probe commands | | get_config | Current probe and server configuration |
Multi-Probe Support
jlink-mcp supports multiple debug probe backends through a common ProbeBackend abstraction:
| Backend | Probe Hardware | Status | RTT Support | |---------|---------------|--------|-------------| | J-Link | SEGGER J-Link, J-Link OB, J-Link EDU | Production | Yes | | OpenOCD | ST-Link, CMSIS-DAP, FTDI, J-Link (via OpenOCD) | Beta | No | | Black Magic Probe | BMP (built-in GDB server on serial) | Beta | No | | probe-rs | All probe-rs supported probes | Planned | Planned |
Selecting a Backend
# J-Link (default)
PROBE_TYPE=jlink JLINK_DEVICE=nRF52840_XXAA node out/mcp/standalone.js
# OpenOCD with ST-Link
PROBE_TYPE=openocd \
OPENOCD_INTERFACE=interface/stlink.cfg \
OPENOCD_TARGET=target/stm32f4x.cfg \
node out/mcp/standalone.js
# Black Magic Probe
PROBE_TYPE=blackmagic \
BMP_SERIAL_PORT=/dev/ttyACM0 \
node out/mcp/standalone.js
Architecture
┌─────────────────────────────────────────────────────┐
│ MCP Client │
│ (Claude, Copilot, any MCP client) │
└──────────────────────┬──────────────────────────────┘
│ JSON-RPC over stdio
┌──────────────────────▼──────────────────────────────┐
│ jlink-mcp │
│ │
│ ┌──────────┐ ┌──────────┐ ┌───────────────────┐ │
│ │ 31 Tools │ │4 Resources│ │ 4 Prompts │ │
│ └────┬─────┘ └────┬─────┘ └───────┬───────────┘ │
│ │ │ │ │
│ ┌────▼──────────────▼────────────────▼───────────┐ │
│ │ ProbeBackend │ │
│ │ ┌─────────┐ ┌─────────┐ ┌──────────────────┐ │ │
│ │ │ J-Link │ │ OpenOCD │ │ Black Magic Probe│ │ │
│ │ └────┬────┘ └────┬────┘ └────────┬─────────┘ │ │
│ └───────┼───────────┼───────────────┼─────────────┘ │
│ │ │ │ │
│ ┌───────▼───┐ ┌─────▼────┐ ┌───────▼──────────┐ │
│ │ RTTClient │ │TelnetProxy│ │ ProcessManager │ │
│ └───────────┘ └──────────┘ └──────────────────┘ │
└─────────────────────────────────────────────────────┘
│
┌────────────▼────────────┐
│ Debug Probe (USB) │
│ → Target MCU (SWD/JTAG)│
└─────────────────────────┘
Source Layout
src/
├── probe/
│ ├── backend.ts # ProbeBackend abstract class + shared utilities
│ ├── jlink.ts # SEGGER J-Link implementation
│ ├── openocd.ts # OpenOCD implementation
│ ├── blackmagic.ts # Black Magic Probe implementation
│ └── factory.ts # Probe creation from config
├── mcp/
│ ├── server.ts # MCP server (31 tools, 4 resources, 4 prompts)
│ └── standalone.ts # Standalone entry (stdio transport)
├── rtt/
│ └── rtt-client.ts # RTT client with ANSI stripping + Zephyr log parsing
├── telnet/
│ └── telnet-proxy.ts # TCP proxy for Trice/Pigweed detokenizer
├── utils/
│ ├── config.ts # VSCode settings / env var config
│ ├── logger.ts # Logging
│ └── process-manager.ts # Child process lifecycle
└── extension.ts # VSCode extension + MCP provider registration
Design Decisions (LLM-Optimized)
This server was built by having an AI use it against real hardware, then fixing every friction point:
- Output parsing strips 40+ lines of J-Link connection banners. Only data comes back.
- Registers are compact:
Core: PC=0xBF54 SP=0x20062880 ...instead of 65 raw lines. - FP registers only shown if non-zero (they're usually all zeros).
- RTT output has ANSI escape codes stripped and Zephyr log format parsed into structured fields.
- Composite tools (
start_debug_session,snapshot,diagnose_crash) replace multi-step workflows with single calls. - Fault decoding is automatic — reads CFSR/HFSR/MMFAR/BFAR and explains each bit.
rtt_searchlets you find errors without reading the entire log.
Environment Variables
J-Link
| Variable | Default | Description | |----------|---------|-------------| | PROBE_TYPE | jlink | Probe backend: jlink, openocd, blackmagic | | JLINK_DEVICE | Unspecified | Target device (e.g., nRF52840_XXAA, STM32F407VG) | | JLINK_INSTALL_DIR | Auto-detect | Path to SEGGER J-Link installation | | JLINK_INTERFACE | SWD | Debug interface: SWD or JTAG | | JLINK_SPEED | 4000 | Connection speed in kHz | | JLINK_SERIAL | | J-Link serial number (multi-probe) | | JLINK_GDB_PORT | 2331 | GDB server port | | JLINK_RTT_PORT | 19021 | RTT telnet port |
OpenOCD
| Variable | Default | Description | |----------|---------|-------------| | OPENOCD_BINARY | openocd | Path to openocd binary | | OPENOCD_INTERFACE | interface/stlink.cfg | Interface config file | | OPENOCD_TARGET | target/stm32f4x.cfg | Target config file | | OPENOCD_GDB_PORT | 3333 | GDB server port | | OPENOCD_TELNET_PORT | 4444 | Telnet command port |
Black Magic Probe
| Variable | Default | Description | |----------|---------|-------------| | BMP_GDB_PATH | arm-none-eabi-gdb | Path to GDB binary | | BMP_SERIAL_PORT | /dev/ttyACM0 | BMP serial port | | BMP_TARGET_INDEX | 1 | Target index after scan |
Prerequisites
- SEGGER J-Link Software installed (JLinkExe, JLinkGDBServer)
- A J-Link debug probe connected to an ARM Cortex-M target
- Node.js 18+
For other backends: OpenOCD or arm-none-eabi-gdb as appropriate.
Contributing
Adding a new probe backend:
- Create
src/probe/yourprobe.tsimplementingProbeBackend - Add a case to
src/probe/factory.ts - That's it — all 31 MCP tools work automatically
License
MIT - see LICENSE
---
<p align="center"> Built by <a href="https://github.com/thesprkfactory">The Sprk Factory</a> </p>






