Skip to main content
Glama
andy-qingcai

MHO98 MCP Server

by andy-qingcai
README.md
# MHO98 MCP Server

Rigol **MHO98** 示波器的 Model Context Protocol (MCP) 服务器。
基于官方《MHO98 Programming Guide》(PGA45102-1110) 做全量参数化封装,
通过 **PyVISA (raw TCP socket 5555 / USBTMC)** 控制仪器。

- 手册摘要:`docs/NOTES.md`;功能规划:`docs/PLAN.md`;手册原文:`docs/MHO98_ProgrammingGuide_EN.pdf`
- **142 个 MCP 工具**,手册全部 28 个命令子系统逐命令核对覆盖(采集/触发 20 种/测量 44 项/波形/9 种协议解码/内置 AWG/LAN 配置/仪器端 U 盘与 SMB 存储/IEEE488.2/逻辑分析……)
- **波形数据只落盘**(CSV/NPY),绝不在 MCP 返回值中内联采样数组,防止撑爆大模型上下文;返回值为统计摘要 + 文件路径,供后续脚本按协议解析

## 快速开始

```bash
cd /Users/andylos/mcp_gen/rigol/mho98
python3 -m venv .venv
.venv/bin/pip install -e .          # 或 pip install mcp'>=1.2,<2' pyvisa pyvisa-py numpy
.venv/bin/python -m pytest tests/   # 离线单元测试(mock 仪器)
.venv/bin/python scripts/probe_device.py   # 真机全功能自检
```

## 配置(环境变量)

| 变量 | 默认 | 说明 |
|---|---|---|
| `MHO98_RESOURCE` | `TCPIP0::169.254.112.67::5555::SOCKET` | VISA 资源串;USB 形如 `USB0::0x1AB3::0x****::***::INSTR` |
| `MHO98_SOURCE_IP` | 自动检测 | macOS 直连 link-local 网段时绑定本机源地址(en 口 169.254.*) |
| `MHO98_DATA_DIR` | `./data` | 波形 CSV/NPZ、截图、设置文件的保存目录 |

> **macOS 直连网线注意**:仪器使用 link-local 地址(169.254.x.x)时,系统默认把流量
> 路由到主网卡导致连不上。本服务会自动发现本机 169.254.* 地址并绑定;若仍有问题,
> 可 `sudo route -host add 169.254.112.67 -interface en7` 持久修复。

## 接入 MCP 客户端

ZCode(`.zcode/settings.json`)或 Claude Desktop(`claude_desktop_config.json`):

```json
{
  "mcpServers": {
    "mho98": {
      "command": "/Users/andylos/mcp_gen/rigol/mho98/.venv/bin/python",
      "args": ["-m", "mho98_mcp.server"],
      "cwd": "/Users/andylos/mcp_gen/rigol/mho98",
      "env": {
        "MHO98_RESOURCE": "TCPIP0::169.254.112.67::5555::SOCKET",
        "MHO98_DATA_DIR": "/Users/andylos/mcp_gen/rigol/mho98/data"
      }
    }
  }
}
```

## 工具总览(142 个)

| 分组 | 工具 |
|---|---|
| 系统/IEEE488.2/连接 (23) | `connect` `disconnect` `list_resources` `get_idn` `get_status` `get_errors` `reset` `clear_status` `self_test` `set_system` `get_system_config` `get_system_info` `get_keyboard_check` `get_ieee488_status` `set_ieee488_enable` `get_option_status`(挂死守卫) `reboot_system` `get_datetime` `set_datetime` `save_setup` `load_setup` `wait_complete` `scpi`(任意 SCPI 逃生舱) |
| LAN (2) | `get_lan_config` `set_lan`(IP/掩码/网关/DNS/DHCP/mDNS/主机名 + `APPLy`) |
| 仪器端存储 (16) | `save_image_on_instrument` `save_waveform_on_instrument` `save_memory_waveform_on_instrument` `save_setup_on_instrument` `save_mask_on_instrument` `load_setup_on_instrument` `load_mask_on_instrument` `get_save_status` `configure_save` `get_save_config` `get_screenshot_data` + SMB 五件套(`configure_smb` `smb_connect` `smb_disconnect` `get_smb_status` `get_smb_config`) |
| 运行/采集 (12) | `set_run_state`(RUN/STOP/SINGLE/FORCE/CLEAR) `autoscale` `set_autoset_options` `get_autoset_options` `set_channel`(15 参数) `get_channel` `get_channel_full` `set_timebase`(含 XY/延迟/水平参考) `get_timebase` `get_timebase_full` `set_acquire` `get_acquire` |
| 触发 (18) | `set_trigger_common` `get_trigger_common` `get_trigger_status` `get_trigger_position` `get_trigger_config`(20 种类型全读回) + edge/pulse_width/slope/runt/window/duration/timeout/pattern/delay/**setup_hold**/nth_edge/video/serial(RS232/IIC/SPI/CAN/LIN/FLEXray/IIS/M1553,协议参数全类型化) |
| 测量/光标/计数/DVM (20) | `measure_item`(44 项) `measure_batch` `measure_quick` `set_measure_statistics` `measure_statistics_item` `set_measure_thresholds` `set_measure_sources_ab` `configure_measure_setup` `configure_measure_region` `configure_measure_amplitude` `set_measure_histogram` `set_measure_counter` `set_cursor` `get_cursor_values` `get_cursor_xy_values` `read_counter` `set_counter` `read_dvm` `set_dvm` `configure_quick` |
| 波形/数学/参考 (11) | `get_waveform`(落盘+统计) `get_waveform_preamble` `export_waveform_csv` `get_waveform_setup` `get_math_waveform`(落盘) `configure_math`(40+ 参数) `get_math_config` `get_math_config_full` `get_math_fft_peaks` `configure_reference` `get_reference_config` |
| 协议解码 (13) | `configure_bus` `get_bus_config` + 九种协议专用:`configure_bus_parallel/rs232/iic/spi/can/lin/flexray/iis/m1553`;`read_bus_data`(落盘 CSV) `export_bus_on_instrument` |
| AWG/Bode (8) | `configure_awg` `get_awg_config` `get_awg_full_config` `set_awg_output` `sync_awg_phase` `configure_awg_modulation`(AM/FM/PM 全参数) `configure_bode` `get_bode_config` |
| 显示 (3) | `get_screenshot`(PNG/BMP/JPG 落盘) `set_display` `get_display` |
| 分析 (16) | `set_histogram` `read_histogram_stats` `get_histogram_config` `configure_mask` `get_mask_result` `get_mask_config` `configure_search` `get_search_config` `get_search_event_time` `navigate_to_event` `configure_navigate` `get_navigate_config` `configure_record` `get_record_status` `configure_la` `get_la_config` |

长尾/组合参数通过各工具的 `extra={"KEYWORD": value}` 白名单透传到
`:子系统:KEYWORD value`(白名单按手册逐命令核对,非法关键字报 ValueError)。

## 已验证固件特性(00.01.00,实机 MHO9A274501356)

- `:SYSTem:OPTion:STATus?` / `:OPTion:VALid?` 会挂死(不响应),`get_system_info` 已跳过;`get_option_status` 默认跳过,仅 `opt_in=True` 才真正查询
- `:DVM:CURRent?` 在 DVM 关闭时挂死,`read_dvm` 已做使能守卫
- `:CURSor:MANual:TYPE` 合法值为 `TIME|AMPLitude`(非 X/Y)
- `:TRIGger:PATTern:PATTern` 需要 `H,H,L,L` 逗号分隔(工具自动转换 `HHLL`)
- `:DISPlay:GRADing:TIME` 只接受 `MIN|数值秒|INFinite`(不接受 `1S`/`1.0`)
- `:NAVigate:MODE` 需要 STOP 状态(`configure_navigate(stop_first=True)`)
- SCPI 错误入队有延迟,写后错误检查带 50 ms 稳定期防止误归属

## 手册逐条核对带来的修正(v0.1 → v0.2)

- `:CHANnel<n>:POSition` 是偏置电压(V)而非垂直格数
- 测量阈值命令为 `:MEASure:SETup:MAX/MID/MIN`(非 `:MEASure:THReshold:*`);统计查询必带类型参数 `:MEASure:STATistic:ITEM? <type>,<item>`
- PATTern/DURation 触发的 `LEVel` 需 `<源>,<电平>` 二元形式;`holdoff` 下限 8 ns
- 此型号无 `:MATH<n>:DATA?`,数学波形经 `:WAVeform:SOURce MATH<n>` 读取;REF 插槽为 1–10;FFT 窗函数集为 {RECTangle|BLACkman|HANNing|HAMMing|FLATtop|TRIangle}
- AWG 调制仅支持 AM/FM/PM(无 SWP/Burst);AM 深度 0–120%;频率 2 mHz–100 MHz
- Bode:`sweep_type` 合法值 `LOG|LINE`;`:BODeplot:VOLTage` 需 `<量程>,<幅值>` 双参数
- LA 阈值按 POD 组设置(POD1=D0–D7,POD2=D8–D15),非逐通道
- 录制帧间隔命令为 `:RECord:WRECord:FINTerval`(非 INTerval);搜索类型仅 EDGE|PULSe
- `power_on` 合法值 `LATest`;语言设置用 13 种长格式
- `:SAVE:IMAGe:DATA?` 截图与 `:SAVE:*`/`:LOAD:*` U 盘路径、SMB 共享均已封装

## 数据文件格式

- 波形 CSV:两行 `#` 注释头(含 preamble 换算参数)+ `t_s,v_V` 两列
- 波形 NPY:`np.load(f)["t_s"]` / `["v_V"]`(npz,RAW 大采集推荐)
- 电压换算:`v = (code - yorigin - yreference) × yincrement`

TDQS

C2.7/5.0

Scored across 142 tools

Disambiguation2/5

There are many overlapping families: get_channel vs get_channel_full, get_timebase vs get_timebase_full, get_math_config vs get_math_config_full, configure_bus vs configure_bus_rs232/iic/spi/etc., set_counter vs set_measure_counter, and multiple screenshot/save-image tools. Descriptions often clarify differences, but the set has several tool pairs whose boundaries an agent could easily misselect among.

Naming Consistency4/5

Mostly consistent snake_case verb_noun naming (get_, set_, configure_, measure_, save_, load_, read_) is used throughout. Minor deviations exist, such as bare verbs reset/autoscale, noun-like scpi, and get_screenshot vs get_screenshot_data, but the overall convention is readable and predictable.

Tool Count1/5

142 tools is an extreme mismatch for an MCP server, far beyond the typical 3-15 range. The surface is effectively a full SCPI wrapper, creating excessive cognitive load and making tool selection impractical for an agent despite the exhaustive coverage.

Completeness5/5

The server covers nearly every major oscilloscope subsystem: system, LAN, save/load, triggers, channels, timebase, acquisition, measurements, cursors, counter/DVM, waveform, math, reference, bus decode, AWG, Bode, display, histogram, mask, search, record, logic analyzer, and connection management. The scpi escape hatch also prevents dead ends for undocumented or unexposed operations.

Maintenance

ActivityMaintained
ResponsivenessNo issues