MHO98 MCP Server
# 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
Scored across 142 tools
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.
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.
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.
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.