Skip to main content
Glama
README.md
# pyocd-debug-mcp

> **让 AI 全自动进行嵌入式单片机仿真调试的 MCP Server**

通过 [pyOCD](https://pyocd.io/) + CMSIS-DAP 探针,为 Claude / GitHub Copilot 等 AI 工具提供 **58 个调试工具**,涵盖从连接探针、烧录固件、打断点、读寄存器到 HardFault 故障分析的完整调试流程。

## ✨ 核心能力

| 能力 | 说明 |
|------|------|
| 🔌 探针管理 | 自动发现 CMSIS-DAP 探针,连接/断开 |
| ⚡ 烧录 | 支持 `.hex` / `.bin` / `.elf` / `.axf` 固件烧录,烧录 ELF 自动附加符号 |
| ✅ Flash 校验 | 烧录后逐段对比验证,检测 Flash 损坏或烧录异常 |
| 🎯 断点 & 监视点 | 硬件断点 / 软件断点 / 自动选择(地址或符号名),数据监视点(读/写/读写) |
| 🔄 断点恢复 | Reset 后自动恢复所有断点(软件断点 Reset 后丢失,自动重设) |
| ⏳ 等待机制 | `wait_halt` — AI 打断点 → 运行 → 等待命中 → 分析 |
| 📊 变量采样 | 周期性采样全局变量,返回统计数据 |
| 💥 故障分析 | HardFault/BusFault/UsageFault 全自动解析 |
| 📏 栈溢出检测 | 支持 RT-Thread / FreeRTOS TCB 栈边界检查 |
| 🔍 栈回溯 | DWARF CFI / EHABI / 启发式三级容错,覆盖 AC5/AC6/GCC |
| 🔧 寄存器 & 内存 | 读/写 CPU 寄存器、内存、外设寄存器(SVD),支持批量位域更新和枚举值 |
| 📋 符号解析 | 通过 ELF 文件将地址映射到函数名/变量名 |
| 📡 RTT 实时传输 | SEGGER RTT 通道读写,免 UART 打印调试 |
| 🆕 地址格式 | 所有地址参数同时接受整数和十六进制字符串(如 `"0x1FFE000E"`) |
| 🆕 组合工具 | `read_symbol` 一步读取变量值、`step_out` 执行到函数返回 |

## 📦 安装

### 前置条件

- Python ≥ 3.10
- [uv](https://docs.astral.sh/uv/) 包管理器(推荐)
- CMSIS-DAP 兼容调试探针(DAPLink / STLINK 等)

### 方式一:从 GitHub 安装(推荐)

```bash
# 使用 uv
uv pip install git+https://github.com/konbakuyomu/pyocd-debug-mcp.git

# 使用 pip
pip install git+https://github.com/konbakuyomu/pyocd-debug-mcp.git

# 如需 SVD 字段级解析(可选)
uv pip install "pyocd-debug-mcp[svd] @ git+https://github.com/konbakuyomu/pyocd-debug-mcp.git"
```

### 方式二:本地开发安装

```bash
git clone https://github.com/konbakuyomu/pyocd-debug-mcp.git
cd pyocd-debug-mcp
uv sync          # 创建虚拟环境并安装依赖
```

### HC32 系列芯片支持

HC32 芯片需要安装 CMSIS-Pack:

```bash
uv run pyocd pack install hc32f460
uv run pyocd pack install hc32f4a0
```

## 🔧 注册到 AI 工具

### Claude Desktop

在 `claude_desktop_config.json` 中添加:

```json
{
  "mcpServers": {
    "pyocd-debug": {
      "command": "uv",
      "args": [
        "--directory", "/path/to/pyocd-debug-mcp",
        "run", "pyocd-debug-mcp"
      ]
    }
  }
}
```

### Claude Code (CLI)

```bash
claude mcp add pyocd-debug -- uv --directory /path/to/pyocd-debug-mcp run pyocd-debug-mcp
```

### GitHub Copilot (VS Code)

在 `.vscode/mcp.json` 中添加:

```json
{
  "servers": {
    "pyocd-debug": {
      "command": "uv",
      "args": [
        "--directory", "/path/to/pyocd-debug-mcp",
        "run", "pyocd-debug-mcp"
      ]
    }
  }
}
```

> 💡 将 `/path/to/pyocd-debug-mcp` 替换为你的实际路径。Windows 下使用 `\\` 或 `/` 均可。

## 🛠️ 工具列表(58 个)

### 项目配置

| 工具名 | 说明 |
|--------|------|
| `pyocd_project_load` | 🆕 加载项目配置(`.pyocd-debug.json`),或自动发现固件/ELF/SVD 文件 |
| `pyocd_project_init` | 🆕 创建 `.pyocd-debug.json` 配置文件(路径自动转相对路径) |
| `pyocd_svd_attach_builtin` | 🆕 ⚠️ 从 pyocd 内置 SVD 临时回退(强烈建议改用厂商提供的完整 SVD) |

### 探针 & 会话

| 工具名 | 说明 |
|--------|------|
| `pyocd_probe_list` | 列出所有已连接的 CMSIS-DAP 调试探针 |
| `pyocd_probe_info` | 获取指定探针详细信息 |
| `pyocd_session_connect` | 连接探针并打开调试会话 |
| `pyocd_session_disconnect` | 断开调试会话,释放探针 |
| `pyocd_session_status` | 查看当前会话状态 |

### 烧录

| 工具名 | 说明 |
|--------|------|
| `pyocd_flash_program` | 烧录固件(.hex / .bin / .elf / .axf),烧录 ELF/AXF 自动附加符号 |
| `pyocd_flash_erase` | 擦除 Flash |
| `pyocd_flash_verify` | 🆕 校验 Flash 内容是否与固件文件一致(逐段对比) |

### 目标控制

| 工具名 | 说明 |
|--------|------|
| `pyocd_target_halt` | 暂停 CPU |
| `pyocd_target_resume` | 恢复运行 |
| `pyocd_target_step` | 单步执行 |
| `pyocd_target_reset` | 复位 MCU(自动恢复所有断点) |
| `pyocd_target_status` | 获取目标状态(运行/停止)及关键寄存器 |
| `pyocd_target_wait_halt` | ⏳ **等待目标停止**(断点命中/监视点触发),支持 `user_hint` 提示 |
| `pyocd_target_step_out` | 🆕 执行到当前函数返回(自动设临时断点在 LR) |
| `pyocd_target_list_supported` | 列出 pyOCD 支持的所有 MCU(206+) |

### 寄存器 & 内存

| 工具名 | 说明 |
|--------|------|
| `pyocd_register_read` | 读取 CPU 寄存器 |
| `pyocd_register_write` | 写入 CPU 寄存器 |
| `pyocd_register_read_all` | 读取全部寄存器(含 FPU) |
| `pyocd_memory_read` | 读内存 |
| `pyocd_memory_write` | 写内存(带 readback 验证) |
| `pyocd_memory_write_block` | 块写入 |
| `pyocd_memory_dump` | Hex dump 格式输出 |

### 断点 & 监视点

| 工具名 | 说明 |
|--------|------|
| `pyocd_breakpoint_set` | 设置断点(地址或符号名),支持 hw/sw/auto 三种类型 |
| `pyocd_breakpoint_clear` | 清除断点 |
| `pyocd_breakpoint_clear_all` | 清除所有断点 |
| `pyocd_breakpoint_list` | 列出当前断点 |
| `pyocd_watchpoint_set` | 设置数据监视点(读/写/读写触发) |
| `pyocd_watchpoint_clear` | 清除监视点 |
| `pyocd_watchpoint_clear_all` | 清除所有监视点 |
| `pyocd_watchpoint_list` | 列出当前监视点 |

### ELF 符号

| 工具名 | 说明 |
|--------|------|
| `pyocd_elf_attach` | 加载 ELF 文件用于符号解析 |
| `pyocd_elf_lookup` | 按名称查找符号地址 |
| `pyocd_read_symbol` | 🆕 **一步读取变量**:符号查找 + 内存读取组合工具 |
| `pyocd_elf_symbols` | 列出 ELF 中的符号(函数/变量) |
| `pyocd_elf_info` | 获取 ELF 文件信息 |
| `pyocd_elf_address_to_symbol` | 地址→符号反查(PC/LR→函数名+偏移) |

### SVD 外设寄存器

| 工具名 | 说明 |
|--------|------|
| `pyocd_svd_attach` | 加载 SVD 文件 |
| `pyocd_svd_list_peripherals` | 列出所有外设 |
| `pyocd_svd_list_registers` | 列出外设的寄存器 |
| `pyocd_svd_read` | 按名称读外设寄存器(含位域解析) |
| `pyocd_svd_write` | 按名称写外设寄存器 |
| `pyocd_svd_list_fields` | 列出寄存器的所有位域(名称、位范围、宽度) |
| `pyocd_svd_set_field` | 设置单个位域值(RMW,支持枚举名或整数) |
| `pyocd_svd_update_fields` | 🆕 批量设置多个位域(单次 RMW,原子操作) |
| `pyocd_svd_describe` | 🆕 查看外设/寄存器详细描述(含枚举值定义) |

### 高级调试

| 工具名 | 说明 |
|--------|------|
| `pyocd_debug_fault_analyze` | 💥 分析 HardFault 崩溃(SCB 寄存器 + 异常栈帧 + EXC_RETURN + backtrace) |
| `pyocd_debug_stack_overflow_check` | 📏 检查线程栈溢出(RT-Thread / FreeRTOS) |
| `pyocd_debug_sample_variable` | 📊 周期性采样变量(如每 0.5s 采样 200 次) |
| `pyocd_debug_backtrace` | 🔍 **精确栈回溯** — DWARF CFI / EHABI / 启发式三级容错,覆盖 AC5/AC6/GCC |

### RTT 实时传输

| 工具名 | 说明 |
|--------|------|
| `pyocd_rtt_start` | 🆕 启动 RTT 并发现通道(自动搜索 SEGGER RTT 控制块) |
| `pyocd_rtt_stop` | 🆕 停止 RTT 并释放资源 |
| `pyocd_rtt_read` | 🆕 从 RTT 上行通道读取数据(非阻塞) |
| `pyocd_rtt_write` | 🆕 向 RTT 下行通道写入数据 |
| `pyocd_rtt_status` | 🆕 查看 RTT 状态和通道信息 |

## 📋 项目配置(推荐)

在项目根目录创建 `.pyocd-debug.json`,AI 即可自动获取所有调试文件路径:

```json
{
  "target": "hc32f4a0xi",
  "firmware": "build/usart_uart_dma_Debug/usart_uart_dma.hex",
  "elf": "build/usart_uart_dma_Debug/usart_uart_dma.axf",
  "svd": "HC32F4A0PIHB.svd"
}
```

也可让 AI 自动创建:

```
AI: pyocd_project_load("/path/to/project")    → 自动扫描发现文件
AI: pyocd_project_init("/path/to/project",    → 创建配置
      target="hc32f4a0xi",
      firmware="build/xxx.hex",
      elf="build/xxx.axf",
      svd="HC32F4A0PIHB.svd")
```

> 💡 配置中的路径会自动转为项目根目录的相对路径,方便版本控制。

### SVD 文件查找策略

SVD 文件(外设寄存器描述)的查找遵循三级优先级:

1. **配置文件指定**(最佳):`.pyocd-debug.json` 中的 `svd` 字段 — 厂商提供的完整 SVD
2. **项目目录扫描**:自动在项目目录中递归查找 `.svd` / `.xml` 文件
3. **pyocd 内置回退**(最后手段):`pyocd_svd_attach_builtin` — 从 pyocd 内置的 105 个通用 SVD 中匹配

> ⚠️ **强烈建议** 从芯片厂商 SDK 获取与具体芯片型号匹配的 SVD 文件。内置 SVD 是通用简化版,可能缺少部分外设或引脚定义。

## 🚀 典型调试流程

以下是 AI 使用此 MCP Server 进行调试的典型对话流程:

### 1. 连接 → 烧录 → 运行到 main

```
AI: pyocd_probe_list                           → 发现探针
AI: pyocd_session_connect("hc32f460xe")        → 连接
AI: pyocd_flash_program("firmware.hex")        → 烧录
AI: pyocd_elf_attach("firmware.elf")           → 加载符号
AI: pyocd_breakpoint_set(symbol="main")        → 在 main 打断点
AI: pyocd_target_reset(halt=true)              → 复位并停止
AI: pyocd_target_wait_halt(timeout=10)         → 等待命中 main
```

### 2. 串口数据调试(等待断点)

```
AI: pyocd_breakpoint_set(symbol="UART_RxCallback")
AI: pyocd_target_wait_halt(timeout=60)         ← 等待数据到来
    ... 60s 内数据到达,断点命中 ...
AI: pyocd_memory_dump(rx_buffer_addr, 64)      → 查看接收缓冲区
AI: pyocd_register_read_all()                  → 查看寄存器现场
```

### 3. 周期性变量监控

```
AI: pyocd_debug_sample_variable(
      address=0x20001000,   # 全局变量地址
      interval=0.5,          # 每 0.5s
      count=200              # 共 200 次 = 100s
    )
→ 返回所有采样值 + min/max/变化统计
```

### 4. HardFault 崩溃分析

```
AI: pyocd_debug_fault_analyze()
→ 返回:
  - fault_type: "BusFault"
  - fault_address: "0x40012400"
  - active_faults: [PRECISERR, BFARVALID]
  - exception_frame: {PC_fault, LR_saved, R0-R3, ...}
  - exc_return: {stack_used: "PSP", fpu_context: ...}
```

### 5. 野指针/数组越界追踪

```
AI: pyocd_watchpoint_set(
      address=0x20002000,    # 数组末尾地址
      size=4,
      access_type="write"    # 监控越界写入
    )
AI: pyocd_target_wait_halt(timeout=30)
    ... 越界写入发生,DWT 触发停止 ...
AI: pyocd_target_status()                      → 查看 PC 定位到写入指令
AI: pyocd_debug_backtrace()                    → 查看完整调用链
```

### 6. 精确栈回溯(三级容错,全工具链覆盖)

```
AI: pyocd_debug_backtrace(max_frames=16)
→ 返回:
  frames:
    [0] USART_RxCallback+0x1A          (pc=0x0800135C)
    [1] DMA_IrqHandler+0x18            (unwound via DWARF CFI)
    [2] main+0x42                      (unwound via DWARF CFI)
  method: "dwarf_cfi"                   ← AC6/GCC: .debug_frame 精确展开
  method: "ehabi"                       ← AC5: .ARM.exidx 精确展开
  method: "heuristic"                   ← 无调试信息时: 栈扫描 + BL 验证

# wait_halt 断点命中时自动附带简短 backtrace:
AI: pyocd_target_wait_halt(timeout=30)
→ { ..., "backtrace": ["UART_RxCallback", "DMA_IrqHandler+0x18", "main+0x1A"] }

# fault_analyze 崩溃时自动附带 backtrace:
AI: pyocd_debug_fault_analyze()
→ { ..., "backtrace": ["HardFault_Handler", "memcpy+0x12", "cJSON_Parse+0x8A", ...] }
```

### 🆕 地址格式灵活性

所有接受地址参数的工具(共 11 个)同时支持整数和十六进制字符串:

```python
# 两种格式等价
AI: pyocd_memory_read(address=0x20000000, size=16)
AI: pyocd_memory_read(address="0x20000000", size=16)

# 断点也支持
AI: pyocd_breakpoint_set(address="0x0800135C")

# 监视点同理
AI: pyocd_watchpoint_set(address="0x20001000", access_type="write")
```

### 🆕 组合工具

```python
# read_symbol: 一步读取变量(自动查找地址 + 读取内存 + 类型推断)
AI: pyocd_read_symbol(name="g_rxBuffer")
→ { "name": "g_rxBuffer", "address": "0x20000100", "size": 64,
     "hex_dump": "48 65 6C 6C 6F ...", "as_string": "Hello..." }

# step_out: 执行到当前函数返回
AI: pyocd_target_step_out(timeout=5.0)
→ { "status": "returned", "from_function": "UART_RxCallback",
     "returned_to": "DMA_IrqHandler+0x18" }
```

## 🏗️ 项目结构

```
pyocd-debug-mcp/
├── pyproject.toml              # 项目配置和依赖
├── src/pyocd_debug_mcp/
│   ├── server.py               # MCP Server 入口,58 个工具注册
│   ├── session_manager.py      # 会话生命周期管理(单例)
│   └── tools/
│       ├── probe.py            # 探针发现
│       ├── target.py           # 目标控制
│       ├── flash.py            # Flash 烧录 + 校验
│       ├── register.py         # 寄存器读写
│       ├── memory.py           # 内存读写
│       ├── breakpoint.py       # 断点管理(HW/SW/AUTO + Reset 恢复)
│       ├── watchpoint.py       # 监视点管理
│       ├── elf.py              # ELF 符号解析
│       ├── svd.py              # SVD 外设寄存器(含批量更新、枚举、描述)
│       ├── rtt.py              # RTT 实时传输(SEGGER RTT 通道读写)
│       ├── debug.py            # 高级调试(故障分析、栈回溯、栈检查、采样)
│       └── project.py          # 项目配置(.pyocd-debug.json 管理)
└── tests/
```

## ⚙️ 支持的硬件

- **调试探针**: 所有 CMSIS-DAP 兼容探针(DAPLink、STLINK via pyOCD、J-Link via pyOCD)
- **MCU**: pyOCD 支持的 206+ 种芯片,包括:
  - **HDSC/XHSC**: HC32F460、HC32F4A0 等
  - **STMicroelectronics**: STM32F0/F1/F2/F3/F4/F7/H7/L0/L4/G0/G4 等
  - **Nordic**: nRF52832、nRF52840、nRF9160 等
  - **NXP**: LPC、Kinetis、i.MX RT 等
  - 更多: `pyocd_target_list_supported` 查看完整列表

## 📄 License

MIT

TDQS

A3.8/5.0

Scored across 58 tools

Disambiguation5/5

Each tool has a clearly distinct purpose within its category (breakpoints, debug analysis, ELF, flash, memory, probes, project, RTT, session, SVD, target, watchpoints). Descriptions are detailed and unique, preventing confusion.

Naming Consistency5/5

All tool names follow a consistent pyocd_<category>_<action> pattern in snake_case, e.g., pyocd_breakpoint_set, pyocd_debug_backtrace. The convention is uniform across all 58 tools.

Tool Count3/5

The server has 58 tools, which is high for an MCP server. While the domain (embedded debugging) is broad and each tool serves a specific function, this count is on the heavy side and may be overwhelming, slightly exceeding the ideal range.

Completeness5/5

The tool surface covers the complete debugging workflow: breakpoints, watchpoints, flash programming, memory/register access, SVD peripherals, RTT, project config, and target control. No obvious gaps for typical debug operations.

Maintenance

ActivityInactive
ResponsivenessNo issues