Metadata-Version: 2.4
Name: scopebench-mcp
Version: 0.3.1
Summary: MCP server and skill for AI-controlled oscilloscopes.
Author: scopebench-mcp contributors
License: Apache-2.0
License-File: LICENSE
Requires-Python: >=3.11
Provides-Extra: mcp
Requires-Dist: mcp[cli]<2,>=1.27; extra == 'mcp'
Provides-Extra: webcontrol
Requires-Dist: playwright<2,>=1.52; extra == 'webcontrol'
Description-Content-Type: text/markdown

# 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:

```text
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

```text
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:

```powershell
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:

```powershell
.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:

```powershell
.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:

```text
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:

```powershell
python -m pip install -e ".[mcp]"
```

Include the WebControl extra when browser-rendered panel capture is needed:

```powershell
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:

```powershell
python -m unittest discover -s tests
```

### Start The MCP Server

Run the MCP server:

```powershell
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:

```json
{
  "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:

```powershell
python src\scopebench_mcp\drivers\rigol_dho804d_visa.py list
python src\scopebench_mcp\drivers\rigol_dho804d_visa.py idn
```

Expected verified identity:

```text
RIGOL TECHNOLOGIES,DHO804D,YOUR_SCOPE_SERIAL,00.01.05
```

The compatibility CLI keeps the same default behavior and also accepts an
optional serial check:

```powershell
python src\scopebench_mcp\drivers\rigol_dho804d_visa.py --serial YOUR_SCOPE_SERIAL idn
```

### Common MCP Tool Flow

The initial MCP tools are:

- `scope_list`
- `scope_webcontrol_status`
- `scope_webcontrol_capture`
- `scope_webcontrol_input`
- `scope_identify`
- `scope_status`
- `scope_network_status`
- `scope_configure_channel`
- `scope_configure_timebase`
- `scope_configure_trigger`
- `scope_configure_pulse_trigger`
- `scope_configure_acquisition`
- `scope_measure`
- `scope_measure_statistics`
- `scope_measure_timing`
- `scope_cursor_measure`
- `scope_configure_lan_static`
- `scope_autoscale`
- `scope_control`
- `scope_capture_single`
- `scope_capture_pulse`
- `scope_acquire_screen`
- `scope_acquire_memory`
- `scope_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:

1. `scope_list`
2. `scope_identify(serial="...")`
3. `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.
4. `scope_status(channel=1, serial="...")`
5. 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.
6. `scope_configure_channel(channel=1, probe_ratio=10, scale_v_per_div=0.1, coupling="DC", offset_v=-0.2, serial="...")`
7. `scope_configure_timebase(scale_s_per_div=0.001, offset_s=0.002, serial="...")`
8. `scope_configure_trigger(source_channel=1, level_v=0.14, slope="positive", serial="...")`
9. `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. Use `lower_width_s` and `upper_width_s` only with `condition="between"`.
10. `scope_measure(channels=[1, 2], measurements=["frequency", "vpp", "rms"], serial="...")` for concise independent values from multiple channels; keep `channel=1` for the original single-channel response.
11. `scope_measure_statistics(action="start", channel=1, measurement="vpp", sample_count=1000, serial="...")`, followed later by `action="read"`, for a bounded instrument-side min/max/average/stddev/count snapshot. Use `reset` and `stop` explicitly.
12. `scope_measure_timing(source_channel_a=1, source_channel_b=2, measurements=["rr_delay", "rr_phase"], serial="...")` for instrument-side edge delay and phase.
13. `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.
14. `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.
15. `scope_control(action="run" | "stop" | "single", wait_s=0.5, serial="...")` when acquisition state needs to be explicit.
16. `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. Pass `channels=[1, 2]` instead when multiple displayed channels must come from that same frozen event.
17. `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 explicit `memory_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.
18. `scope_screenshot(serial="...", screenshot_method="display_png")` for a quick visual check.
19. `scope_acquire_screen(channel=1, points=1000, serial="...", screenshot_method="display_png")` for waveform evidence.
20. `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.json`
- `waveform.csv`
- `preview.png`
- `screen.png` when 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:

1. Use USB/VISA as the known-good control channel.
2. Call `scope_network_status(serial="...", verify_lan=True)` to read the existing IP, mask, gateway, mode, and MAC without changing settings.
3. If its LAN verification is reachable and the serial matches, use the returned `host` with `transport="lan"` and port `5555`.
4. 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.
5. 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:

```text
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.py`
  Existing 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.md`
  Field 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.md` for the documentation index.
- `docs/project_brief_zh.md` for the Chinese project brief.
- `docs/roadmap.md` for implementation order.
- `docs/development_plan.md` for technical decisions and implementation tasks.
- `docs/mcp_tool_design.md` for the MCP tool draft.
- `docs/client_platform_compatibility.md` for MCP client, skill, and host-platform support.
- `docs/open_source_release_strategy.md` for the private-development/public-release policy and Apache-2.0 decision.
