Skip to main content
Glama
wolog1

siglent-sds-mcp

by wolog1

siglent-sds-mcp

MCP server for controlling a SIGLENT SDS824X HD oscilloscope via SCPI over raw TCP.

Project status: SDS824X HD hardware-tested alpha. Core measurement-driven auto setup is functional on real hardware.

Quick start

# Install
python -m venv .venv && source .venv/bin/activate
pip install -e '.[dev]'

# Test
pytest -q

# Run MCP server (stdio, for AI client config)
python -m siglent_sds_mcp.server

# Quick connectivity probe
python examples/tcp_idn_test.py <scope-ip>

Related MCP server: siglent-sds-mcp

Auto setup — one-command screen setup

The main feature: point at an unknown signal and let the scope measurement engine find usable VDIV / OFST / TDIV settings. The command also saves a screenshot artifact from the final setup path.

# Backwards-compatible CLI name; internally uses measurement-driven auto setup
python examples/auto_find_waveform_tcp.py <scope-ip> --channels C1 C2 C3 C4

# With signal-type hint for better trigger slope policy
python examples/auto_find_waveform_tcp.py <scope-ip> --signal-hint uart

# Direct TTL wiring / 1X probe
python examples/auto_find_waveform_tcp.py <scope-ip> \
    --channels C1 \
    --signal-hint clock \
    --probe 1

# Weak periodic signal policy
python examples/auto_find_waveform_tcp.py <scope-ip> \
    --channels C1 \
    --signal-hint clock \
    --noise-floor 0.05 \
    --min-signal-vpp 0.005

# Restart acquisition after capture only when explicitly requested
python examples/auto_find_waveform_tcp.py <scope-ip> --restart-after-capture

Default behavior: leave_stopped=true. The tool intentionally leaves the scope stopped on the final visible frame. The return object includes screen_hold, final_panel_state, measurements, final_settings, probe_steps, screenshot, and compatibility_parameters.

Compatibility note: coarse_timebase, initial_vdiv, max_points, and refine_attempts are accepted by the historical auto_find_waveform API so older MCP/CLI callers do not break. The current measurement-driven adapter path owns the actual scanning and refinement logic, so those compatibility fields are reported in JSON but are not directly used by the measurement path.

Waveform capture modes

get_waveform_tcp defaults to capture_mode="immediate".

STOP -> WF? DAT2

This intentionally skips WFSU. SDS824X HD field debugging showed that sending WFSU SP,1,NP,0,FP,0 after STOP can refresh/replace the stopped frame before WF? DAT2, which loses intermittent UART/RS485 bursts and often returns an IDLE frame instead.

For stable/repetitive signals only, callers may request the legacy configured path:

STOP -> WFSU SP,1,NP,0,FP,0 -> WF? DAT2

Use it through MCP by setting:

{
  "capture_mode": "configured"
}

The metadata records capture.mode, capture.wfsu_sent, decode.dt_source, parsed.trdl_s, parsed.effective_start_s, parsed.effective_end_s, and warnings when fallback timing is used.

UART decoding

analyze_uart_csv_file now performs real UART 8N1 byte decoding instead of only reporting edge timing. It detects falling-edge start bits, samples 8 data bits LSB-first, validates the stop bit, and returns decoded bytes:

{
  "decoded_hex": "48 69",
  "decoded_ascii": "Hi",
  "frames": [
    {"byte_hex": "0x48", "stop_ok": true, "framing_ok": true}
  ]
}

Thresholding is histogram-based when two voltage levels are visible, with min/max midpoint fallback. This is more robust for small-amplitude UART such as high=5.2 V and low=4.95 V, where simple min/max Vpp rules are too brittle.

Architecture

MCP client (AI)
  │ MCP tool calls (stdio)
  ▼
server.py — FastMCP tools, auto-reconnect
  │
  ▼
sds_tcp_adapter.py — SDS800X HD command adapter
  │  channel / acquisition / trigger / measure / screenshot /
  │  waveform capture (WAVEDESC adaptive decode + envelope decimation) /
  │  measurement-driven auto_setup
  ▼
waveform_capture.py — immediate/configured WF? DAT2 capture modes
  │  immediate mode preserves stopped frames by skipping WFSU
  ▼
tcp_transport.py — RawTcpTransport
  │  socket-level SCPI, IEEE 488.2 binary block parser,
  │  thread-safe (RLock), pre-query socket flush
  ▼
auto_setup.py — compatibility wrapper for historical auto_find_waveform API

SIGLENT SDS824X HD oscilloscope (LAN port 5025)

Command verification pipeline

candidate → official-doc → tested → implemented → safe-tool

Tracked in docs/sds824x-hd-command-matrix.md. Do NOT expose an untested command as a default MCP tool.

Key design decisions

Measurement-driven auto setup

SDS800XHDTcpAdapter.auto_setup() uses scope measurements (PKPK, MEAN, FREQ, PER, MAX, MIN) to select display settings. This avoids relying on a separate offline CSV analyzer for first-pass screen setup.

Weak periodic signal policy

noise_floor_v is treated as the strong-signal threshold. A lower-amplitude signal can still be accepted when the scope reports a valid FREQ or PER and PKPK >= min_signal_vpp. This handles real field observations such as a stable 7.89 kHz signal with only about 22.5 mV peak-to-peak.

WAVEDESC adaptive decode

WF? DAT2 returns 8-bit signed bytes. Voltage decode queries WF? DESC for the WAVEDESC descriptor and uses the descriptor-derived codes_per_div with current panel VDIV? / OFST? for decoding.

Timebase and dt policy

DAT2 timing should use WAVEDESC HORIZ_INTERVAL whenever available. SARA? is recorded as metadata and only used as a fallback. Metadata warnings are emitted when dt_source falls back to SARA or TDIV because UART/protocol decoding can be wrong if the fallback does not match the DAT2 memory interval.

Min/max envelope decimation

When max_points < raw sample count, each bucket outputs min + max voltages instead of naive stride-sampling. Preserves glitches/spikes stride would miss.

ARM/STOP behaviour

get_waveform_tcp immediate mode freezes the current frame with STOP and reads DAT2 directly. This is the default for intermittent signals. The older WFSU path is available only through capture_mode="configured".

Trigger level policy

C?:TRLV <level> is a known issue on SDS824X HD firmware 4.8.12.1.1.6.5. Display-oriented auto setup does not depend on this command by default. set_trigger_level=true must be requested explicitly.

Project structure

src/siglent_sds_mcp/
  server.py              — MCP tools, auto-reconnect, FastMCP
  sds_tcp_adapter.py     — Command adapter, WAVEDESC decode, envelope, auto_setup
  waveform_capture.py    — WF? DAT2 capture modes, immediate skips WFSU
  tcp_transport.py       — Raw TCP socket, lock, binary block parser
  auto_setup.py          — Compatibility wrapper for auto_find_waveform API
  uart_analyzer.py       — Offline UART CSV analyzer and 8N1 byte decoder
  rs485_analyzer.py      — RS485 differential pair analyzer
  modbus_timing.py       — Modbus RTU timing calculator
  report.py              — Markdown field report generator
  artifacts.py           — Timestamped artifact paths, JSON writer
  transport.py           — PyVISA fallback (legacy, not wired into MCP)
  scope_driver.py        — SiglentSDSDriver with safety gate (legacy)

docs/
  architecture.md                  — Layered design, UART capture reference
  sds824x-hd-command-matrix.md     — Per-command verification status
  sds824x-hd-knowledge-base.md     — Instrument-specific knowledge
  verification-workflow.md         — Hardware verification procedure

tests/   — pytest, parser tests, TCP transport tests, auto setup helper tests
examples/ — auto_find_waveform_tcp, TCP IDN probe, waveform/RS485 capture

Safety model

Allowed

Blocked

*IDN?, run/stop/single

*RST, factory reset

Channel/timebase/trigger setup

Firmware update

Measurement query

Network config changes

Screenshot/waveform fetch

File deletion/formatting

Offline waveform analysis

Arbitrary SCPI writes

Raw SCPI writes are NOT exposed as MCP tools. safe_scpi_query_tcp only accepts ?-suffixed commands.

Test coverage

pytest -q

Key test areas:

  • test_unit_parsing.py_parse_voltage, _parse_time, _parse_sample_rate

  • test_wavedesc.py / test_wavedesc_parser.py — synthetic WAVEDESC decode, ASCII prefix handling

  • test_tcp_binary_prefix.pyquery_binary IEEE 488.2 / BMP prefix skipping

  • test_auto_setup.py_pick_vdiv, _pick_tdiv, measurement parser and SCPI number formatting

  • test_auto_find_compat.py — weak periodic detection, screen hold, screenshot artifact, compatibility parameters

  • test_waveform_capture_modes.py — immediate mode skips WFSU; configured mode sends WFSU with warning

  • test_uart_decoder.py — UART 8N1 byte decoding, hex/ascii output, low-Vpp thresholding

  • test_tcp_transport_parser.py — socketpair binary block parsing

Target device

  • SIGLENT SDS824X HD / SDS800X HD family

  • SCPI over raw TCP, port 5025

  • Firmware verified: 4.8.12.1.1.6.5

Reference

A
license - permissive license
-
quality - not tested
C
maintenance

Maintenance

Maintainers
<1hResponse time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/wolog1/siglent-sds-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server