Content
Tool List
This project securely reads and controls the following USBTMC + NI-VISA/PyVISA:
- SIGLENT SDS2000X Plus series oscilloscopes model: SDS2502X Plus.
- SIGLENT0X/SDG6000X-E series signal generators; verified model: SDG6032X-E.
The project provides both MCP Server and `econtest-signal-bench` Agent Skill, suitable for low-voltage waveform generation, oscilloscope configuration, amplitude and frequency measurement, sweep, and evidence reporting in electrical competitions.
## Current Capabilities
- Only supports USB + VISA, not LAN, wireless, Telnet, or WebControl.
- Signal sources support SINE, SQUARE, RAMP, PULSE, and sweep.
- Server output soft upper limit is 3 Vpp; current complete loop verified at 1 Vpp.
- Supports SDS channels, timebase, edge trigger, RUN/STOP/SINGLE, oscilloscope native measurements, and bounded BYTE waveform reading.
- Amplitude, Vpp, and frequency verification prioritize using `scope_measure_simple` returned oscilloscope native measurements; waveform export is only for evidence and diagnosis.
- All write operations perform identity verification, `*OPC setting readback, and evidence recording.
- Complete loop tools source output and confirm oscilloscope STOP upon failure or normal### TODO: PNG Screenshot
`PRIN? BMP/PNG` on SDS2502X Plus firmware `5.0.1.3.7R5` does not return data and times out via USB-VISA; thus, the screenshot tool is not exposed in the current version.
Future verification is needed to confirm the USB screenshot protocol, alternative commands, or secure instrument file reading methods. Do not claim support for PNG screenshots until verification is complete.
## Installation
First, install NI-VISA and confirm both instruments appear as USB INSTR resources in NI MAX. Then, run:
```powershell
python -m pip install -e ".[mcp]"
python -m unittest discover -s tests -v
```
`econtest-bench-mcp` is a **stdio MCP Server** and should be launched by the MCP client, not an interactive terminal program. Directly running it in PowerShell and pressing Enter will input an empty line to the Server, resulting in JSON: EOF while parsing`; this indicates the input is not a JSON-RPC message, not an instrument communication failure.
Add the to the MCP client configuration to launch:
```powershell
econtest-bench-mcp
```
command-line entry is not installed, the client can also run:
```powershell
python -m econtest_bench_mcp
```
## MCP Client Configuration
After installing as a command-line program, use the following stdio configuration:
```json
{
"mcpServers": {
"econtest-bench": {
"command": "econtest-bench-mcp"
}
}
}
```
If the command-line entry is not installed, specify Python and the project directory:
```json
{
"mcpServers": {
"econtest-bench": {
"command": "python",
"args": ["-m", "econtest_bench_mcp"],
"cwd": "D:/CodeStudy/econtest-bench-mcp/eench-mcp"
}
}
}
```
Specific configuration on the MCP client used. The Server communicates using standard input and do not write regular logs to standard output.
## Agent Skill Installation
The canonical Skill is located in:
```text
skill/econtest-signal-bench/
```
The installation package provides an export command that refuses to overwrite:
```powershell
econtest-bench-mcp-skill C:\target\directory\econtest-signal-bench
```
Place the exported directory into the client's supported Skill directory and use `$econtest-signal` to call it.
## MCP Tools
### Discovery and Status
| Tool | Purpose |
| --- | --- |
| `bench_list_devices` | Enumerate USBTMC devices and identify roles |
| `bench_identify` | Verify specified resource, role, and serial number |
| `scope_status` oscilloscope channel, and trigger status |
| `generator_status` | Read output and basic waveform status `bench_status` | Generate read-only baseline evidence for dual### Signal Generator
| Tool | Purpose |
| --- || `generator_configure_basic` | Configure four basic waveforms is OFF |
| `_load` | Set High-Z50 Ω display load when output is OFF |
| `_output` | Enable or; ON requires confirmation, target, and load `generator_configure_sweep Configure or disable sweep when output is OFF |
After sweep is disabled, the device may stay at the carrier frequency in the sweep process. To continue using a fixed frequency, call `generator_configure_basic` to restore the basic waveform.
### Oscilloscope
| Tool | Purpose |
| --- | --- |
| `scope_configure_channel` | Set channel switch, coupling, probe ratio, gear, and offset |
| `scope_configure_timebase` | Set main timebase |
| `scope_configure_edge_trigger` | Set edge trigger |
| `scope_control` | Control RUN, STOP, or SINGLE; SINGLE can wait boundedly and return freshness status |
| `scope_measure_simple` | Read-only obtain oscilloscope native PKPK/FREQ/RMS and other readings, units, invalid values, statistics, and complete configuration context |
| `scope_capture_waveform` | Read bounded BYTE waveform evidence after confirming STOP; cannot be used as precise Vpp acceptance value |
### Complete Loop
| Tool | Purpose |
| --- | --- |
| `bench_capture_response` | Automatically execute OFF configuration, output ON, measurement, waveform acquisition, output OFF, and oscilloscope STOP |
| `artifacts_remove_runs` | Delete specified failed or expired evidence runs only after explicit confirmation |
## Minimal Read-Only Tutorial
1. Call `bench_list_devices`.
2. Record the VISA resource, model, and serial number of the scope and generator.
3. Call `bench_status` with both resources and serial numbers.
4. Check the returned `evidence.manifest` and device readback.
Any subsequent operations should continue to pass the serial number to avoid selecting the wrong device after the USB resource order changes.
## Complete Loop Tutorial
Recommended safe entry loop:
```text
SDG CH1 OUTPUT ── 50 Ω BNC coaxial cable ── SDS CH1 INPUT
```
Connection conditions: no DUT, both instruments normally protect the ground, SDS CH1 is 1 MΩ, SDG display load is High-Z, and both signal source outputs are OFF.
After confirming physical conditions, prioritize calling `bench_capture_response`:
```json
{
"scope_resource": "USB0::...SDS...::INSTR",
"generator_resource": "USB0::G...::INSTR",
"scope_serial": "oscilloscope serial number",
"generator_serial": "signal generator serial number",
"waveform": "SINE",
"frequency_hz": 1000,
"amplitude_vpp": 1,
"expected_destination": "SDS CH1 directly connected BNC, 1 MΩ, no DUT",
"confirm_output_enable": true,
"load_mode": "HZ",
"scope_channel": 1,
"generator_channel": 1,
"points": 4000,
"settle_time_s": 0.5
}
```
Successful results should include:
- Signal generator configuration and output enable readback;
- Oscilloscope PKPK, FREQ, RMS, DUTY measurements;
- Waveform Vpp, mean, time span, and other summaries;
- `output_final_state: confirmed_off`;
- `scope_final_state: Stop`;
- Evidence manifest path.
If the tool fails, check the returned error for cleanup and partial evidence paths. When the output state is unknown, manually check the signal generator front panel immediately.
## Step-by-Step Control Tutorial
When manual arrangement is needed, strictly follow this order:
1. `bench_status`: Confirm identity and baseline; target SDG channel must be OFF.
2. `generator_set_load`: Set the load consistent with actual wiring, `HZ` or `50`.
3. `generator_configure_basic`: Configure waveform; amplitude must not exceed 3 Vpp.
4. Configure oscilloscope channel, timebase, and trigger.
5. `scope_control(RUN)`.
6. `generator_set_output(ON)`: Provide `confirm_output_enable=true`, target description, and load.
7. Amplitude/frequency verification uses `scope_measure_simple`; waveform shape diagnosis or evidence uses `scope_capture_waveform`.
8. `generator_set_output(OFF)` and check `confirmed_off`.
9. `scope_control(STOP)`.
Do not call basic waveform, load, or sweep configuration tools when output is ON.
## Evidence Directory
All products are written to:
```text
artifacts/runs/<UTC time>_<run_id>/
```
Common files include `manifest.json`, `events.jsonl`, device identity, configuration readback, raw waveform code, waveform metadata, and numerical summaries. The `calibration_eligible` in `manifest.json` defaults to `false`; only when the complete loop of native measurement, configuration readback, external DUT echo, and fresh acquisition is available can it be marked as `true`. MCP only returns summaries and paths, not large arrays in the conversation.
Verification evidence:
```powershell
python skill\econtest-signal-bench\scripts\validate_evidence.py artifacts\runs\某次运行\manifest.json
```
To clean up products, only call `artifacts_remove_runs`, pass directory names (e.g., `20260722T...Z_<run_id>`), failed or expired reasons, and set `confirm_cleanup=true`. It does not accept arbitrary paths, wildcards, or parent directories; deleting with the `failed` reason also verifies that the manifest is indeed in a failed state.
## External DUT (e.g., serial port control MCU) Tutorial
`bench_capture_response` only applies to the complete loop of `SDG → DUT → SDS`. If DUT is driven by a serial port, debugger, or other controllers, the controller should complete DUT operations first, then use MCP's read-only native measurement tools:
1 DUT commands and confirm parseable echo. For example, record `RX r4 1000 2.0` and `OUT R4 1000 2.0`.
2. From the **echo completion moment**, set a stable time based on DUT characteristics; do not apply a fixed short wait for low-frequency, high Q, or long time constant circuits.
3. If a fresh frame is needed, call `scope_control(action="SINGLE", confirm_state_change=true, single_wait_timeout_s=...)`. Only when `single.completed can the frame be considered complete; `Ready`, timeout, or invalid measurement is `inconclusive`.
4.scope_measure_simple`, for example:
```json
{
"resource": "USB0::...SDS...::INSTR",
"serial": "oscilloscope serial number "channel": 1,
"items": ["PKPK", "FREQ", "RMS"],
"require_scope_state": "STOP",
"samples": 3,
"measurement_point_id": "round1.r4.1000hz.2vpp",
"dut_context": {
"command": "r4 1000 2.0",
"echo": "OUT R4 1000 2.0",
"command_sent_at_utc": "recorded by DUT controller",
"echo_received_at_utc": "recorded by DUT controller"
}
}
```
5. Check `scope_measure_simple.measurement_validity`. If any native item is invalid is `inconclusive` and the calibration table should not be updated. Then, call `scope_capture_waveform` with the same `measurement_point_id` and `dut_context` to save reproducible waveform evidence. Its `waveform.vpp_v` is the exported BYTE waveform summary and must not cover native `PKPK`.
6. Finally, call `scope_control(STOP)` and confirm readback. The final output state of the external DUT can only be recorded by its controller; MCP does not claim to have shut it down.
When the native value and waveform summary Vpp difference exceed the predetermined threshold, stop automatic calibration and manually judge. Do not use a single software fitting value to claim to meet the 1% index; before batch calibration, verify the consistency of the two types of values with 1 to 3 representative points.
##
- Software cannot verify grounding, isolation, probe and ratings; these are the operator's responsibility.
- Do not connect the BNC ground to a non-isolated high-side node.
- Arbitrary SCPI, `*RST`, firmware, network, or instrument file system operations are not supported.
- Output ON must explicitly confirm the target and load; shutting down output does not require confirmation.
- When communication is lost, do not claim the output has been shut down.
- USB software operation is not hardware synchronous triggering.
## Development Verification
```powershell
python -m unittest discover -sv
python -m compileall -q src```
Verified hardware and known differences are in [Hardware Validation Record/hardware-validation.md), and the support matrix is in [Compatibility Matrix](docs/compatibility-matrix.md).
MCP Config
Below is the configuration for this MCP Server. You can copy it directly to Cursor or other MCP clients.
mcp.json
Connection Info
You Might Also Like
No recommendations available