关于 J-Link MCP
J-Link MCP 是面向固件开发者的 MCP 服务,用于通过硬件探针调试 ARM Cortex-M 设备。它提供设备控制、崩溃诊断、RTT 日志和 GDB 工作流,并支持 J-Link、OpenOCD 和 Black Magic Probe 后端。
主要功能
- 01读写内存和寄存器
- 02烧录固件并控制执行
- 03解码 Cortex-M 故障
- 04读取和筛选 RTT 日志
- 05GDB 调试与服务控制
- 06CMSIS-SVD 外设解码
适用场景
- 01诊断目标硬件上的固件崩溃
- 02按名称检查外设寄存器
- 03烧录固件并逐步执行
- 04按级别或模式搜索设备日志
MCP 相关
该服务向 MCP 客户端提供嵌入式设备调试工具,包括探针配置、设备访问、崩溃诊断、RTT 和 GDB 操作。它还附带四个 MCP 提示词。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
npx -y jlink-mcpJLINK_DEVICETarget device name, exactly as J-Link spells it (e.g. nRF52840_XXAA, STM32F407VG). Use the search_devices tool to find it.JLINK_SERIALSerial number of a specific probe, when more than one is attached.SVD_PATHCMSIS-SVD file for the target. Without it, peripheral reads are undecoded hex.JLINK_RTT_ADDRAddress of the firmware's _SEGGER_RTT symbol. Lets RTT survive a reset or flash.本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
工具
43收录的工具列表 · 更新于 2 天前
此工具无需参数。
详细介绍
jlink-mcp
让 AI 拥有触碰芯片的双手。
一个 MCP 服务,让大模型通过 SEGGER J-Link 探针调试嵌入式设备。
看看它如何工作
针对真实 nRF52840-DK 的 MCP 工具调用。亲自复现:npm run demo
你的固件刚刚崩溃。只需一次工具调用:
> diagnose_crash
## Crash Diagnosis
### CPU State
Core: PC=0x000000B8 SP=0x2003FFA8 R0=0x0000000A R1=0x000007FF R2=0x00000001 ...
Status: XPSR=0x21000003 CONTROL=0x00000000 PRIMASK=0x00000000 ...
Stack: MSP=0x2003FFA8 PSP=0x00000000
⚠ CPU is in exception handler (IPSR=0x00000003)
### Fault Registers
CFSR=0x01000000 HFSR=0x40000000 DFSR=0x00000000 MMFAR=0xe000edf8 BFAR=0xe000edf8
### Decoded Faults
## UsageFault (UFSR):
- UNALIGNED: Unaligned memory access
## HardFault (HFSR):
- FORCED: Forced HardFault (escalated from configurable fault)
### Exception Stack Frame
R0 = 0x0000000A R1 = 0x000007FF
R12 = 0x00000000 LR = 0x000001F5
PC = 0x00000254 xPSR = 0x21000000
→ Faulting instruction at PC=0x00000254
### Recent Errors/Warnings from RTT
[WRN] sensor_drv: sample out of range, clamping seq=2
故障已解码,异常帧已展开,触发故障的指令已指出,并与设备自身的日志关联——只需一次调用,无需人工查阅数据手册来弄清 CFSR 的第 24 位代表什么。
它还了解芯片本身
将目标的 CMSIS-SVD 文件交给它,外设寄存器就不再只是十六进制数:
> read_peripheral FICR
FICR @ 0x10000000
INFO.PART @ 0x10000100 = 0x00052840 (read-only)
[31:0] PART 0x52840 → N52840
INFO.RAM @ 0x1000010C = 0x00000100 (read-only)
[31:0] RAM 0x100 → K256
INFO.FLASH @ 0x10000110 = 0x00000400 (read-only)
[31:0] FLASH 0x400 → K1024
0x400 表示 1024 KB 的闪存——但前提是你知道这一点;而让大模型猜测位布局,正是这个工具要避免的问题。地址取自厂商自己的描述,含义则来自其中的枚举值。
两段记录均为本项目硬件测试套件中 nRF52840-DK 的原样输出。
这是什么?
jlink-mcp 使用 Model Context Protocol,通过 SEGGER J-Link 调试探针,将 AI 助手(Claude、Copilot 等)连接到嵌入式硬件。
无需手动输入 J-Link 命令,AI 助手即可:
- 读取寄存器和内存,了解设备状态
- 烧录固件并重置设备
- 流式传输 RTT 日志,并按级别/模块/正则表达式搜索
- 诊断崩溃,自动解码 ARM Cortex-M 故障寄存器
- 控制执行——暂停、单步执行、恢复、设置断点
- 启动 GDB 服务,进行完整的调试会话
也支持 OpenOCD(ST-Link、CMSIS-DAP、FTDI)和 Black Magic Probe 后端。
安装
你需要安装 SEGGER J-Link 软件
——该服务会调用它——并准备一个连接到 ARM Cortex-M
目标设备的探针,以及 Node 18+。使用其他后端时,则需要 OpenOCD 或 arm-none-eabi-gdb。
Claude Code——从插件市场安装。它会连同服务一起安装
embedded-debugging 技能,让助手不再对你的硬件进行猜测:
/plugin marketplace add Klievan/jlink-mcp
/plugin install jlink-mcp
其他 Agent——将此代码库交给它,并让它自行完成设置:
所需信息都在这里。如果你更愿意手动操作,该服务已发布到 npm,无需构建步骤:npx -y jlink-mcp,并将 JLINK_DEVICE 设置为你的目标设备。mcp-config.json 是一份可直接粘贴使用的配置。
VS Code——安装 扩展。 它会为 Copilot Chat、Claude 和任何支持 MCP 的客户端注册该服务,因此无需进行任何配置。
Nix / NixOS——直接通过 flake 运行,无需安装:
# Run standalone MCP server
nix run github:Klievan/jlink-mcp
# Or in an MCP client configuration (e.g. Claude Desktop / Claude Code)
# "command": "nix", "args": ["run", "github:Klievan/jlink-mcp", "--"]
或者将 jlink-mcp 和 jlink-mcp-skills 添加到系统配置或 flake 中:
# flake.nix inputs
inputs.jlink-mcp.url = "github:Klievan/jlink-mcp";
# In your packages:
inputs.jlink-mcp.packages.''${system}.jlink-mcp
inputs.jlink-mcp.packages.''${system}.jlink-mcp-skills
NixOS 用户注意: 将你偏好的探针工具(
segger-jlink/segger-jlink-headless、openocd或gdb)添加到environment.systemPackages或devShell中。segger-jlink需要设置nixpkgs.config.allowUnfree = true;,并添加services.udev.packages = [ pkgs.segger-jlink ];以授予探针 USB 权限。
然后检查设置
调用 check_setup。只需调用一次,它就会说明缺少什么以及该怎么做:
Not ready to debug yet.
OK probe software — J-Link software found at /Applications/SEGGER/JLink
BLOCK probe — none detected (Connecting to J-Link via USB...FAILED). Check the USB cable.
BLOCK target device — not set. Find the exact name with search_devices, then set_device.
note SVD — not loaded, so peripheral reads stay raw hex. Set SVD_PATH to a CMSIS-SVD file.
你无需事先知道设备的确切型号。search_devices
可按型号、制造商或内核搜索 J-Link 支持的全部 9800 种设备。
工具(48)
工作流工具(从这里开始)
| 工具 | 描述 |
|---|---|
start_debug_session | **一次调用即可完成设置。**启动 GDB 服务 + 连接 RTT + 返回启动日志。 |
snapshot | 捕获完整设备状态:寄存器、故障状态、堆栈转储、RTT 输出。 |
diagnose_crash | 自动读取并解码 ARM Cortex-M 故障寄存器(CFSR、HFSR、MMFAR、BFAR)以及异常堆栈帧。 |
设备设置
| 工具 | 描述 |
|---|---|
list_devices | 扫描已连接的探针并显示已配置的目标设备 |
set_device | 在运行时更改目标设备——无需重启 |
set_serial_number | 在运行时更改探针序列号(用于多探针配置) |
get_config | 当前探针、目标设备和 GDB 服务状态 |
设备控制
| 工具 | 描述 |
|---|---|
device_info | 探针类型、目标 CPU、简要寄存器摘要 |
halt | 暂停 CPU |
resume | 恢复 CPU |
reset | 重置设备。halt 会将其停在复位向量处;strategy 用于选择 J-Link 复位类型,也可以省略,由 J-Link 自行选择 |
step | 单步执行一条指令 |
外设(CMSIS-SVD)
将 jlinkMcp.svdPath 设置为目标设备的 SVD 文件 — 与 Cortex-Debug 用作
svdFile 的文件相同。厂商会为每个器件发布一个 SVD 文件。
| 工具 | 描述 |
|---|---|
list_peripherals | 芯片上的所有外设及其基地址 |
read_peripheral | 读取外设寄存器,并按名称解码每个寄存器的位字段 |
decode_register | 解码单个寄存器 — 从设备读取,或解读已有的值 |
内存与寄存器
| 工具 | 描述 |
|---|---|
read_memory | 读取指定地址的内存(输出为清晰的十六进制转储) |
write_memory | 向指定地址写入 32 位值 |
read_registers | 以紧凑格式读取所有 CPU 寄存器 |
read_register | 读取指定寄存器(PC、SP、R0-R12 等) |
闪存
| 工具 | 描述 |
|---|---|
flash | 将 .hex/.bin/.elf 固件烧录到设备 |
erase | 擦除整个闪存 |
断点
| 工具 | 描述 |
|---|---|
set_breakpoint | 在指定地址设置硬件断点 |
clear_breakpoints | 清除所有断点 |
GDB 服务
| 工具 | 描述 |
|---|---|
gdb_server_start | 启动探针的 GDB 服务 |
gdb_server_stop | 停止 GDB 服务并断开 RTT |
gdb_server_status | 查看 GDB 服务、RTT 和代理的状态 |
源代码级调试
连接真正的 GDB 客户端,以便进行符号感知的操作 — 回溯调用栈、检查变量, 以及按源代码行而非指令进行单步执行。
| 工具 | 描述 |
|---|---|
gdb_connect | 连接 GDB 客户端(自动启动服务;可选提供用于符号的 ELF 文件) |
gdb_load | 加载 ELF 文件以获取调试符号,也可选择同时烧录 |
gdb_backtrace | 查看调用栈,也可选择显示每个栈帧中的局部变量 |
gdb_command | 运行任意 GDB 命令 — print sensor_state、info threads、break main |
gdb_wait | 等待目标停止(在继续运行或触发断点后) |
gdb_disconnect | 分离客户端,并清除断点和调试硬件 |
RTT(实时传输)
| 工具 | 描述 |
|---|---|
rtt_connect | 连接 RTT telnet 端口 |
rtt_disconnect | 断开 RTT |
rtt_read | 读取最近的日志行(移除 ANSI 转义序列,并解析 Zephyr 格式) |
rtt_search | 按级别(err/wrn/inf/dbg)、模块或正则表达式筛选日志 |
rtt_send | 通过 RTT 下行通道向设备发送数据 |
rtt_clear | 清空 RTT 缓冲区 |
Telnet 代理(Trice / Pigweed)
| 工具 | 描述 |
|---|---|
telnet_proxy_start | 启动 TCP 代理,将 RTT 数据分流给外部反令牌化工具 |
telnet_proxy_stop | 停止代理 |
telnet_proxy_status | 查看代理连接状态 |
telnet_proxy_read | 读取代理原始缓冲区 |
高级功能
| 工具 | 描述 |
|---|---|
probe_command | 执行原始探针命令 |
get_config | 查看当前探针和服务配置 |
状态栏知道谁占用了探针
J-Link 一次只能服务一个客户端,因此,GDB 服务一旦一直运行,就会阻塞其他所有操作——而这种情况通常是助手通过 MCP 启动了服务,却没人注意到。扩展无法通过记住自己做过什么来检测这种情况:MCP 服务运行在单独的进程中,因此它看不到由 LLM 启动的服务。
所以它会监视 GDB 端口,这种方式无论是谁负责都有效。当有程序正在监听时,状态栏会变为琥珀色,并显示 J-Link · MCP · 47m——由谁启动,以及启动了多久。这两项信息能让“有东西占着探针”变成“助手从午餐前就一直占着探针”。点击即可停止服务。
工具提示会显示其他信息:设备、端口、RTT 是否已启动,以及它为何重要。而且它绝不会声称自己监测到并未监测到的运行时长——如果窗口打开时服务已经在运行,它会显示服务已运行这么久是已知的,而不是声称服务已运行这么久。
它不会终止无法确认是 J-Link GDB 服务的进程。端口正在监听只能证明那里有东西,不能证明那是我们的进程。
技能
工具会告诉模型它能做什么。但它们不会告诉模型什么值得做;如果没有这方面的指引,两件事总会出问题:模型从不会想到要加载 ELF,因此每个回溯都只有裸地址;它们还会推理硬件应该在做什么,而不是花一次调用去询问硬件。
skills/embedded-debugging/SKILL.md 是一个 Claude Code 技能,涵盖了这两方面——两个能改变一切的文件(ELF 提供名称,SVD 提供含义)、暂停/读取/恢复规则、针对崩溃、挂起、外设和无响应设备的工作流,以及一张将各种认知与实际验证它们的工具调用配对的表格。
如果你将此仓库安装为插件(.claude-plugin/plugin.json),Claude Code 就会加载它;你也可以将该目录复制到固件项目中的 .claude/skills/。MCP 本身没有技能的概念——与之对应的可移植形式是提示词,而此服务提供了四个提示词。
其中的说法都经过了测试。test/hil/s04-symbols.test.ts 在真实芯片上证明:没有符号的回溯不包含函数名称;加载 ELF 后就会有函数名称;而仅加载符号不会重新编程设备。
多探针支持
jlink-mcp 通过通用的 ProbeBackend 抽象支持多个调试探针后端:
| 后端 | 探针硬件 | 状态 | RTT 支持 |
|---|---|---|---|
| J-Link | SEGGER J-Link、J-Link OB、J-Link EDU | 生产可用 | 是 |
| OpenOCD | ST-Link、CMSIS-DAP、FTDI、J-Link(通过 OpenOCD) | Beta | 否 |
| Black Magic Probe | BMP(串行接口上的内置 GDB 服务) | Beta | 否 |
| probe-rs | probe-rs 支持的所有探针 | 计划中 | 计划中 |
选择后端
# 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
架构
┌─────────────────────────────────────────────────────┐
│ 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)│
└─────────────────────────┘
源码布局
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 (45 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
设计决策(针对 LLM 优化)
这个服务是通过让 AI 在真实硬件上使用它,然后修复每个阻碍点构建而成的。
read_registers 会给你什么
JLinkExe 执行 halt; regs 的原始输出——77 行,其中大约只有六行包含有效信息。这里的每个词都会占用上下文,而寄存器值则埋在输出中间:
SEGGER J-Link Commander V9.70 (Compiled Aug 19 2026 12:16:13)
DLL version V9.70, compiled Aug 19 2026 12:15:25
Connecting to J-Link ...O.K.
Firmware: J-Link OB-nRF5340-NordicSemi compiled Jun 11 2026 13:12:28
Hardware version: V1.00
J-Link uptime (since boot): 0d 00h 34m 29s
S/N: 1050298247
License(s): RDI, FlashBP, FlashDL, JFlash, GDB
...30 more lines of connect banner...
PC = 00000044, CycleCnt = 00EB67E5
R0 = 20000000, R1 = 9D56C547, R2 = 00000000, R3 = 00000000
...
FPS0 = 00000000, FPS1 = 00000000, FPS2 = 00000000, FPS3 = 00000000
...28 more lines of zeroed FP registers...
它实际能提供什么
三行。 信息相同,只是按你可能提出的问题归类:
Core: PC=0x00000046 SP=0x20010000 R0=0x20000000 R1=0x01D43416 R2=0x00000000 ...
Status: XPSR=0x01000000 CONTROL=0x00000000 PRIMASK=0x00000000 BASEPRI=0x00000000
Stack: MSP=0x20010000 PSP=0x00000000
两者都从同一块开发板采集。设计的其余部分遵循同一原则 ——返回所请求的内容,不多不少:
- 输出解析会去除连接横幅。只返回数据。
- 寄存器采用紧凑格式,并按组归类(核心/状态/堆栈)。
- FP 寄存器仅在非零时显示(它们通常全为零)。
- RTT 输出会去除 ANSI 转义码,并将 Zephyr 日志格式解析为结构化字段。
- 组合工具(
start_debug_session、snapshot、diagnose_crash)可通过单次调用取代多步骤工作流。 - 故障解码为自动进行——读取 CFSR/HFSR/MMFAR/BFAR,并解释每个位。
- **
rtt_search**让你无需通读整个日志即可查找错误。 - 外设寄存器使用供应商自己的 CMSIS-SVD 进行解码,因此模型会读取
RAM = K256,而不是猜测该寄存器该字段中的0x100是什么意思。 - 失败时会说明该怎么做。“目标正在运行;请使用 halt”比“无法读取内存”更有用;读取故障寄存器失败时也会明确报告,而不是把零值解码成“未检测到故障”。
在真实硬件上验证
LLM 与调试探针之间可能出现的大多数问题都会悄无声息地失败:工具返回成功,却没有任何内容;解析器丢掉半行;会话中断后,下一个命令却报告一个看似合理的结果。光看代码看不出这些问题,而只断言“调用没有报错”的测试套件也会让它们全都通过。
因此,本项目设有硬件测试层:在自托管运行器上,使用真实的 nRF52840-DK 执行 58 项测试,通过 stdio 驱动实际的 MCP 服务,方式与客户端完全相同。测试涵盖探针发现、烧录与验证、实时 GDB 会话中的暂停/单步/恢复、内存与外设读取、RTT 流式传输与筛选,以及按需注入故障后的崩溃诊断。
它发现了那些一直通过测试、实际上却存在的问题,包括:
diagnose_crash在真实崩溃期间报告**“未检测到故障”**——内存转储解析器丢掉了每行的半段内容- 所有经由 GDB 路由的工具都返回空输出,而服务却报告自身运行正常
- 会话结束后目标变得无法启动,且断点比较器仍处于启用状态,任何重置都无法清除
reset报告成功,却什么都没做——GDB 服务是同步远程服务,目标运行时会拒绝命令,因此重置序列中的每条命令都被依次拒绝,而失败结果也被丢弃- 因相同原因,负责停用调试硬件的会话清理操作被全部拒绝,却仍报告“调试硬件已停用”——上文的修复让这个问题得以显现
- GDB 服务在已经退出后仍被报告为正在运行,因为启动流程在进程生成后就返回了,没有等待确认探针是否连接成功
- 重置或烧录后 RTT 变得无声——目标仍在记录日志,但探针已停止采集,表现出来与设备安静无异。通过从两端读取控制块发现了问题:固件写入 490 字节,却没有任何内容被采集
- 一个赋值操作被悄悄丢弃,导致 RTT 在会话剩余时间内无法使用——控制该操作的标志检查的是状态枚举是否为
GDB_RUNNING,而实际要检查的问题是 GDB 服务是否正在运行
这些情况无一例外都报告成功。这正是设置硬件测试层的意义所在,也是测试套件要断言解析后的内容,而不是只检查调用是否无错误返回的原因——只检查错误的测试套件会让它们全都通过。
这些测试运行时捕获的原始探针输出会作为黄金记录提交,因此快速单元测试层可以在任何机器上于数秒内重放真实设备数据,无需探针也能发现格式回归。
npm test # ~257 tests, seconds, no hardware
npm run test:hil # hardware tier; needs HIL=1 and a probe
环境变量
J-Link
| 变量 | 默认值 | 描述 |
|---|---|---|
PROBE_TYPE | jlink | 探针后端:jlink、openocd、blackmagic |
JLINK_DEVICE | Unspecified | 目标设备(例如,nRF52840_XXAA、STM32F407VG) |
JLINK_INSTALL_DIR | 自动检测 | SEGGER J-Link 安装路径 |
JLINK_INTERFACE | SWD | 调试接口:SWD 或 JTAG |
JLINK_SPEED | 4000 | 连接速度,单位为 kHz |
JLINK_SERIAL | J-Link 序列号(多探针) | |
JLINK_GDB_PORT | 2331 | GDB 服务端口 |
JLINK_RTT_PORT | 19021 | RTT telnet 端口 |
JLINK_RTT_ADDR | 自动 | RTT 控制块的地址(你的 _SEGGER_RTT 符号)。J-Link 会通过扫描 RAM 查找该地址,但不会将其报告回来——提供此地址才能让 RTT 在目标设备重置后继续工作 |
OpenOCD
| 变量 | 默认值 | 描述 |
|---|---|---|
OPENOCD_BINARY | openocd | openocd 二进制文件路径 |
OPENOCD_INTERFACE | interface/stlink.cfg | 接口配置文件 |
OPENOCD_TARGET | target/stm32f4x.cfg | 目标配置文件 |
OPENOCD_GDB_PORT | 3333 | GDB 服务端口 |
OPENOCD_TELNET_PORT | 4444 | Telnet 命令端口 |
Black Magic Probe
| 变量 | 默认值 | 描述 |
|---|---|---|
BMP_GDB_PATH | arm-none-eabi-gdb | GDB 二进制文件路径 |
BMP_SERIAL_PORT | /dev/ttyACM0 | BMP 串口 |
BMP_TARGET_INDEX | 1 | 扫描后的目标索引 |
参与贡献
添加新的探针后端:
- 创建
src/probe/yourprobe.ts,实现ProbeBackend - 在
src/probe/factory.ts中添加一个分支 - 就这么简单——全部 31 个 MCP 工具都会自动生效
许可证
MIT - 详见 LICENSE
由 The Sprk Factory 构建
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。