MCP server and skill for AI-controlled oscilloscopes.
Project description
scopebench-mcp
MCP server + skill for AI-controlled oscilloscopes.
scopebench-mcp is a focused framework that lets AI agents connect to an oscilloscope, configure it, acquire waveform data, save visual captures, and return structured evidence through MCP tools. The first target is the RIGOL DHO800 series, starting from the DHO804D we have already tested.
中文简介:scopebench-mcp 是一个让 AI agent 安全、稳定地使用示波器的 MCP server + Agent Skill 项目。它负责连接示波器、配置通道/时基/触发、采集波形和屏幕证据,并把结果以结构化 JSON 和文件路径返回给 AI。第一版聚焦 RIGOL DHO800 系列,已用 DHO804D 做过验证。
Language: English first, with Chinese notes for users and project context. See docs/project_brief_zh.md for the Chinese project brief.
语言说明:README 以英文为主,同时保留中文摘要和中文文档入口;完整中文项目总纲见 docs/project_brief_zh.md。
Current Focus
- Vendor: RIGOL
- Initial family: DHO800 / DHO900 style SCPI scopes
- Verified device: RIGOL DHO804D
- First transports:
- USB VISA / USBTMC
- LAN TCP SCPI, verified on DHO804D for direct static Ethernet after USB-assisted LAN apply
- Agent interface:
- MCP server for real hardware access
- Skill instructions for safe and effective AI usage
This project is intentionally scoped to oscilloscopes. Power supplies, meters, logic analyzers, and full circuit-debugging workflows are out of scope for the first version.
Why MCP + Skill
MCP is the execution layer. It owns hardware access, SCPI transport, settings, waveform acquisition, and file outputs.
The skill is the operating guide for the AI. It explains when to use screen waveform versus memory waveform, how to choose conservative defaults, how to avoid reading huge captures into chat, and how to summarize waveform evidence.
The intended flow is:
AI agent
-> scopebench-mcp skill: how to use the tools well
-> scopebench-mcp MCP server: actual tool calls
-> oscilloscope over USB or LAN
Repository Layout
docs/ Public project notes, roadmap, hardware notes, and vendor reference links
src/scopebench_mcp/ Driver, transport, capture, and MCP server code
skill/scopebench-mcp/ Codex/AI skill draft
examples/ Example command flows and capture reports
captures/ Local waveform data, metadata, and screen/preview images, ignored by git
scripts/ Temporary dev/test helper scripts
Client And Platform Compatibility
The stdio MCP server can be configured in Codex, Cursor, Claude Code, Qoder,
and CodeBuddy. The canonical SKILL.md content is also portable to clients
that support Agent Skills, but each client uses its own discovery directory.
The currently verified USB transport is Windows-only because it uses
visa64.dll. LAN TCP SCPI is the intended macOS/Linux path, but macOS hardware
validation has not yet been completed. See
docs/client_platform_compatibility.md for the client matrix and exact
boundaries.
Quickstart
中文快速说明:
- 安装包名是
scopebench-mcp,不要安装 PyPI 上无关的scope-mcp。 - Python import 包名是
scopebench_mcp。 - CLI 命令是
scopebench-mcp。 - Skill 名称和 MCP server 名称也是
scopebench-mcp。 - 使用硬件前,用户仍然负责探头接地、电压范围、隔离和上电安全确认;AI 只负责仪器控制、数据读取和分析。
Install
The public Python distribution name is scopebench-mcp. The earlier working
name scope-mcp is used by an unrelated project on PyPI, so do not run
pip install scope-mcp for this project.
Install the wheel from the matching GitHub Release bundle into a dedicated virtual environment:
py -m venv .venv
.venv\Scripts\python -m pip install ".\scopebench_mcp-0.3.1-py3-none-any.whl[mcp]"
For optional LAN WebControl panel capture, install the WebControl extra and a browser:
.venv\Scripts\python -m pip install ".\scopebench_mcp-0.3.1-py3-none-any.whl[mcp,webcontrol]"
.venv\Scripts\playwright install chromium
The wheel contains the same canonical Agent Skill as the repository. Export it to the exact Skill directory recognized by your client; the destination must not already exist:
.venv\Scripts\scopebench-mcp-skill "C:\path\to\client-skills\scopebench-mcp"
Restart the client or open a fresh conversation after registering the MCP
server and Skill. See docs/client_platform_compatibility.md for the supported
client directories and INSTALL.md for the complete end-user flow.
A complete release bundle contains:
scopebench-mcp-v0.3.1/
scopebench_mcp-0.3.1-py3-none-any.whl
skill/scopebench-mcp/SKILL.md
INSTALL.md
SHA256SUMS
For source development, install the project in editable mode:
python -m pip install -e ".[mcp]"
Include the WebControl extra when browser-rendered panel capture is needed:
python -m pip install -e ".[mcp,webcontrol]"
playwright install chromium
Playwright-managed browser revisions are version-specific. Run the install
command from the same Python environment that launches scopebench-mcp; a Chromium
download made by another virtual environment may not match. Alternatively use
an installed supported browser by passing browser_channel="msedge" or
browser_channel="chrome".
Windows users may instead use an installed Microsoft Edge browser by passing
browser_channel="msedge".
Run the no-hardware tests:
python -m unittest discover -s tests
Start The MCP Server
Run the MCP server:
scopebench-mcp
On Windows, editable installs usually place scopebench-mcp.exe in a Python Scripts directory. If your MCP client cannot find scopebench-mcp, add that Scripts directory to PATH or use the full path in the MCP client config.
Minimal MCP client config:
{
"mcpServers": {
"scopebench-mcp": {
"command": "scopebench-mcp",
"args": []
}
}
}
See examples/mcp_client_config.json for a Windows note and a full-path variant.
USB/VISA Smoke Test
For the verified DHO804D path, connect the PC to the rear USB DEVICE port and confirm your VISA runtime can see the instrument:
python src\scopebench_mcp\drivers\rigol_dho804d_visa.py list
python src\scopebench_mcp\drivers\rigol_dho804d_visa.py idn
Expected verified identity:
RIGOL TECHNOLOGIES,DHO804D,YOUR_SCOPE_SERIAL,00.01.05
The compatibility CLI keeps the same default behavior and also accepts an optional serial check:
python src\scopebench_mcp\drivers\rigol_dho804d_visa.py --serial YOUR_SCOPE_SERIAL idn
Common MCP Tool Flow
The initial MCP tools are:
scope_listscope_webcontrol_statusscope_webcontrol_capturescope_webcontrol_inputscope_identifyscope_statusscope_network_statusscope_configure_channelscope_configure_timebasescope_configure_triggerscope_configure_pulse_triggerscope_configure_acquisitionscope_measurescope_measure_statisticsscope_measure_timingscope_cursor_measurescope_configure_lan_staticscope_autoscalescope_controlscope_capture_singlescope_capture_pulsescope_acquire_screenscope_acquire_memoryscope_screenshot
For USB/VISA targets, scope_list returns parsed resource metadata when
available, including vendor ID, product ID, and USB serial. The MCP tools accept
an optional serial argument. When serial is provided, the resource string is
used only as the address and *IDN? is used as the final identity check.
If multiple matching USB scopes are connected and neither resource nor
serial is provided, the MCP layer asks for an explicit target instead of
silently selecting one.
For LAN targets, scope_webcontrol_status(host="<scope_ip>") performs a
read-only, bounded HTTP GET / probe of the oscilloscope-provided WebControl
page. It reports HTTP reachability separately from RIGOL/WebControl page
detection. It does not open control WebSockets or send pointer/touch input.
scope_webcontrol_capture(host="<scope_ip>") opens the discovered
control.html page in a headless browser, waits for a decoded H.264 keyframe,
captures only the 1024 x 600 remote-panel canvas, and saves
remote_panel.png plus metadata.json. It does not run autoset or change
trigger/acquisition state; the image reflects the scope's current display.
scope_webcontrol_input(...) sends exactly one click, touch tap, or
drag to panel pixel coordinates. It requires confirm_input=True and a
non-empty expected_effect, rejects coordinates outside the detected canvas,
and saves before_panel.png, after_panel.png, and metadata.json. Raw
coordinates are model-, firmware-, and layout-dependent. Prefer SCPI for
normal control and use SCPI readback after UI input whenever practical.
Typical workflow:
scope_listscope_identify(serial="...")scope_network_status(serial="...", verify_lan=True)when Ethernet is connected but its address is unknown; switch to LAN only when the returned identity matches.scope_status(channel=1, serial="...")- For a safe low-voltage bench signal covered by the current session authorization,
scope_autoscale(confirm_physical_setup=True, serial="..."), then inspect its returned status. Otherwise configure deliberately with the next three tools. scope_configure_channel(channel=1, probe_ratio=10, scale_v_per_div=0.1, coupling="DC", offset_v=-0.2, serial="...")scope_configure_timebase(scale_s_per_div=0.001, offset_s=0.002, serial="...")scope_configure_trigger(source_channel=1, level_v=0.14, slope="positive", serial="...")scope_configure_pulse_trigger(condition="greater_than", source_channel=1, polarity="positive", width_s=3e-6, level_v=0.14, serial="...")when an abnormal pulse width is the event of interest. Uselower_width_sandupper_width_sonly withcondition="between".scope_measure(channels=[1, 2], measurements=["frequency", "vpp", "rms"], serial="...")for concise independent values from multiple channels; keepchannel=1for the original single-channel response.scope_measure_statistics(action="start", channel=1, measurement="vpp", sample_count=1000, serial="..."), followed later byaction="read", for a bounded instrument-side min/max/average/stddev/count snapshot. Useresetandstopexplicitly.scope_measure_timing(source_channel_a=1, source_channel_b=2, measurements=["rr_delay", "rr_phase"], serial="...")for instrument-side edge delay and phase.scope_cursor_measure(mode="manual", axis="time", source_channel=1, cursor_a=-0.0005, cursor_b=0.0005, settle_s=0.5, serial="...")for explicit cursor positions and structured deltas after the display calculation settles.scope_autoscale(confirm_physical_setup=True, serial="...")may also be used later to reset the display starting point when the current session authorization covers it.scope_control(action="run" | "stop" | "single", wait_s=0.5, serial="...")when acquisition state needs to be explicit.scope_capture_single(channel=1, points=1000, trigger_timeout_s=10, run_after_capture=True, serial="...")when one event from the currently configured trigger must be captured with bounded waiting and evidence. Passchannels=[1, 2]instead when multiple displayed channels must come from that same frozen event.scope_capture_pulse(condition="greater_than", source_channel=1, width_s=3e-6, level_v=0.14, points=1000, trigger_timeout_s=10, serial="...")to configure pulse-width trigger and arm the same bounded SINGLE state machine in one connection. Add explicitmemory_points,memory_max_points, and chunk/duration/disk limits only when the same stopped event needs deeper RAW evidence. The pulse trigger remains configured afterward.scope_screenshot(serial="...", screenshot_method="display_png")for a quick visual check.scope_acquire_screen(channel=1, points=1000, serial="...", screenshot_method="display_png")for waveform evidence.scope_acquire_memory(channel=1, points=250000, chunk_points=100000, max_points=250000, stop_before_capture=True, serial="...")only when stopped memory detail is needed and stopping acquisition is acceptable.
The callable scope_measure schema enumerates its canonical measurement names:
frequency, freq, period, vpp, vmax, max, vmin, min, mean,
average, rms, duty, positive_duty, negative_duty, rise_time, and
fall_time. Use these names rather than guessing longer aliases such as
minimum or maximum.
For scope_acquire_screen and the screen-waveform portion of SINGLE capture,
points is a requested upper bound. DHO800 NORMAL waveform reads support at
most 1000 points, so the driver bounds the SCPI read window to 1000 without
discarding the original request. Compare requested_points with the returned
points or multi-channel alignment.points; saved CSV files always contain
the actual device payload without padding.
scope_measure_statistics never waits for sample_count acquisitions inside
one MCP call. start configures one measurement, enables statistics, and
resets history globally; read immediately returns current, minimum, maximum,
average, standard deviation, and accumulated count; reset also clears all
active statistics; stop disables the statistics display. The state is global
to the instrument, so coordinate with other front-panel or remote users.
Capture tools save large evidence to files and return paths plus concise JSON.
When an offset is supplied, the channel and timebase configuration tools return
structured requested and actual position readback. Treat the device readback as
authoritative because valid ranges depend on scale and acquisition state.
scope_capture_single leaves the instrument stopped after a successful event by
default. Set run_after_capture=True only when acquisition should be restored;
the tool polls and reports the resulting non-STOP readback. A trigger timeout
sends :STOP, saves no waveform, and leaves the instrument stopped.
When channels is supplied, it must contain at least two unique displayed
analog channels. The tool arms only once, reads each channel while the scope
remains stopped, and verifies common point count and horizontal sampling. The
shared evidence directory contains metadata.json, an optional screen.png,
and per-channel chN/waveform.csv plus chN/preview.png files.
A normal screen waveform report contains:
metadata.jsonwaveform.csvpreview.pngscreen.pngwhen direct oscilloscope screenshot capture succeeds
scope_screenshot is screen-only and does not write waveform CSV data.
scope_acquire_memory queries the available record depth, reads RAW stopped
memory through contiguous bounded chunks, and incrementally writes CSV plus a
small min/max-envelope preview. It returns only summary metadata and paths.
The operation has independent point, wall-clock, and disk-use limits. A failed
later chunk leaves progress metadata and the completed CSV prefix on disk. It
defaults to a 100k point soft limit and refuses larger captures unless the
caller explicitly raises max_points, with a current hard cap of 1M points.
USB/LAN multi-chunk parity is the gate before that public cap is raised.
LAN Status
LAN TCP SCPI is implemented as a manual host/port transport. On the
verified DHO804D, direct static Ethernet works with raw TCP SCPI on port 5555
after LAN settings are written and :LAN:APPLy is sent. Port 5025 refused
connections on the tested instrument.
The recommended DHO804D bring-up path is:
- Use USB/VISA as the known-good control channel.
- Call
scope_network_status(serial="...", verify_lan=True)to read the existing IP, mask, gateway, mode, and MAC without changing settings. - If its LAN verification is reachable and the serial matches, use the returned
hostwithtransport="lan"and port5555. - Only when a network change is actually required, call
scope_configure_lan_static(..., confirm_network_change=True)with the intended static IP, mask, gateway, and optional DNS, then repeat the read-only status/identity check. - For troubleshooting, validate the intended host interface with bound ping or ARP/neighbor evidence; do not treat an open port alone as instrument identity.
After LAN reachability is established, optionally call:
scope_webcontrol_status(host="<scope_ip>", web_port=80)
scope_webcontrol_capture(host="<scope_ip>", web_port=80)
scope_webcontrol_input(host="<scope_ip>", action="tap", x=772, y=105,
expected_effect="Close the visible menu",
confirm_input=True)
The status tool only discovers the instrument-provided HTTP interface. The capture tool receives the browser video canvas but sends no pointer/touch input. The input tool is a separately gated operation that records visual evidence but does not treat image differences as proof of semantic success.
On Windows, unbound socket-connect results can be misleading when VPN, proxy, or tunnel adapters are active. Bind probes to the Ethernet source address or check ARP/MAC reachability before treating a LAN result as real.
Existing Assets Imported
-
src/scopebench_mcp/drivers/rigol_dho804d_visa.pyExisting Windows VISA helper that can list instruments, query*IDN?, read status, apply a basic CH1 setup, and capture screen waveform data. -
docs/rigol_dho804d_scope_notes.mdField notes from the initial DHO804D validation, including USB/VISA behavior, Ultra Sigma notes, tested resource string, and practical reading strategy.
MVP Definition
The first public version should make these operations easy for an AI agent:
- Discover a connected RIGOL scope.
- Identify model, serial, firmware, and transport.
- Read status for channel, timebase, trigger, acquisition, and waveform settings.
- Configure channel scale, offset, coupling, probe ratio, and display.
- Configure timebase and trigger.
- Read concise instrument-side measurements such as frequency, Vpp, mean, RMS, and duty cycle.
- Run autoscale as an explicitly confirmed starting point, then read back the resulting settings.
- Explicitly run, stop, or single-shot acquisition and read back status.
- Acquire a small screen waveform and return summary statistics plus saved data, local preview, and real screen image files when supported.
- Optionally acquire bounded stopped memory waveform evidence without returning raw arrays in chat/tool output.
- Return all results as structured JSON suitable for an AI agent.
Non-Goals For v0
- Full multi-vendor abstraction.
- GUI application.
- Automatic circuit diagnosis.
- Controlling power supplies, meters, or logic analyzers.
- Solving physical wiring or electrical safety automatically.
Safety Position
The AI can control the oscilloscope and analyze data, but the user remains responsible for physical probing, grounding, voltage range, isolation, and powering hardware. At the first hardware access in each agent/MCP session, the workflow should give one concise safety reminder and confirm the physical setup and authorized test scope. That authorization remains valid for the approved workflow; prompt again only after a session restart or a material change in wiring, probes, voltage/isolation risk, network configuration, or intended remote-panel action. High-voltage and non-isolated work always requires explicit scope-specific confirmation.
Status
This is an early standalone project seed created from the initial DHO804D validation work. USB/VISA is verified on one DHO804D for identity, status, configuration tools, screen waveform capture, and direct screen image capture. LAN TCP support is verified on that DHO804D for direct static Ethernet with raw SCPI on port 5555 after USB-assisted LAN configuration and :LAN:APPLy.
This project is not affiliated with RIGOL. RIGOL is a trademark of its owner.
Project Memory
The current project intent, planning, verified assets, and future direction are captured in:
docs/README.mdfor the documentation index.docs/project_brief_zh.mdfor the Chinese project brief.docs/roadmap.mdfor implementation order.docs/development_plan.mdfor technical decisions and implementation tasks.docs/mcp_tool_design.mdfor the MCP tool draft.docs/client_platform_compatibility.mdfor MCP client, skill, and host-platform support.docs/open_source_release_strategy.mdfor the private-development/public-release policy and Apache-2.0 decision.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file scopebench_mcp-0.3.1.tar.gz.
File metadata
- Download URL: scopebench_mcp-0.3.1.tar.gz
- Upload date:
- Size: 151.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
29ca9a977cc6f46d60c10fca38aa1c6d40e7abd380eb3dc38541b6baa22ba869
|
|
| MD5 |
6cca11879372acee6750feec4c680d46
|
|
| BLAKE2b-256 |
e7bb1c726a2cdc828ac5bcf280c0f5a37636fdc0a4b9d93045a007cb25b1cf90
|
File details
Details for the file scopebench_mcp-0.3.1-py3-none-any.whl.
File metadata
- Download URL: scopebench_mcp-0.3.1-py3-none-any.whl
- Upload date:
- Size: 68.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
535c264906357349134e6968bc3ab5c597919ed94237493c30b1b30dc6719422
|
|
| MD5 |
a0d5d73b093fa43b4857a48ac85cba93
|
|
| BLAKE2b-256 |
99dadb635399a54cbdd43c65cc1aa5534f4d0d0a92f1b6249d4a2ed246b60c28
|