JDS2800 MCP
Summary: This MCP server (and its JSON scripting CLI) controls a JUNTEK JDS2800 signal generator over USB serial — reading device state, configuring both channels, and setting calibrated 50-ohm power — with automatic port discovery and no hardware connection needed for docs/calibration data.
Read-only info:
get_manual(bundled specs, limits, protocol notes),get_calibration(measured power tables/ranges),list_ports,list_waveforms(built-ins + 60 arbitrary slots),get_device_info(model, serial, port, frequency limit),get_state(mode, phase, channel settings).Configure channels:
configure_channelsets frequency, waveform, amplitude (Vpp), offset, duty and enable, with validation and verified readback (preserving unspecified settings).Outputs & phase:
set_outputsenables/disables each channel independently;set_phasesets inter-channel phase, normalized to 0–359.9°.Modes & sweep:
set_modestops actions and selects a mode (WAVE_CH1/2, MEASURE, COUNTER, SWEEP_CH1/2, PULSE, BURST, SYSTEM);configure_sweepsets start/end frequency, time, scale, direction and optionally starts the sweep.Safety stop:
stop_outputsstops sweep/counter/pulse/burst actions and disables both outputs.Arbitrary waveforms:
read_arbitraryreads all 2048 samples from slots 1–60;upload_arbitraryoverwrites a slot with 2048 samples (0–4095) and verifies all samples.Calibrated power:
preview_powerchecks identity and predicts voltage/dBm without writing;set_powerconfigures SINE, zero offset, 50% duty and calibrated amplitude into a physical 50-ohm load (≈-29 to +11 dBm over 1–15 MHz), preserving enable state unless specified.Diagnostics:
read_registerreads protocol registers 0–89, including counter/measurement data.Also via CLI: every tool is callable as
./jds2800 <subcommand>orcall, andbatchruns multiple operations under one serial lease.Note: the schema exposes no
waveformargument onpreview_power/set_power, although the README documents SQUARE calibration support for those tools.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@JDS2800 MCP set channel 1 to a 1 kHz sine at 2 Vpp and turn output on"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
JDS2800 MCP
MCP server and JSON scripting CLI for a JUNTEK JDS2800 over USB serial.
Uses the existing Kristoff Bonne Python driver with per-operation serial ownership, line framing, parameter checks and verified readback. The legacy source and MIT license are vendored, so the server does not require another checkout or computer. Built with the official MCP Python SDK, pinned to version 1.30.0. Supports macOS and Linux with Python 3.11 or newer.
Install and run
git clone https://github.com/ikatkov/jds2800-mcp.git
cd jds2800-mcp
uv sync --locked
./jds2800 info
./jds2800 stateRun these commands from the checkout. The jds2800 and run-mcp launchers
use the virtual environment created by uv sync. An installed package
also provides jds2800 and jds2800-mcp console commands.
No port setting is required. The driver tries available USB serial ports, prioritizing JDS descriptions and CH340 adapters. It identifies a compatible generator by reading its model, serial number and channel states, without changing output settings. Probes have short timeouts and use the same serial lock as normal operations. Bluetooth/headset and debug-console ports are excluded.
If no generator answers, the CLI exits with status 2 and an error listing the
ports it tried. If multiple generators answer, it asks you to select one explicitly
using --port or JDS2800_PORT. An explicit port always overrides discovery.
Related MCP server: dwf-mcp-server
Manual reference for agents
Read JDS2800-reference.md before controlling the instrument. It summarizes the supplied manufacturer's 18-page English manual (Rev 1.0, June 2018), with page references, specifications, operating procedures, documented ambiguities, 50-ohm power calculations, and separately labeled protocol details and measured hardware findings.
The same Markdown is bundled in the Python package and available without a
generator connection through the MCP get_manual tool or the jds2800://manual
resource (text/markdown). Server instructions direct agents to it. The CLI
./jds2800 manual returns it as a JSON string; ./jds2800 call get_manual also works.
MCP connection
Install the console commands so an MCP client can launch the server from any directory:
uv tool install .Copy .mcp.example.json into the client's MCP settings:
{
"mcpServers": {
"jds2800": {
"command": "jds2800-mcp"
}
}
}Ensure the installed console command is on the client's PATH. For development,
./run-mcp launches the checkout's environment; configure the client with the
path to your own checkout rather than a path from someone else's machine.
Server startup and tool discovery do not open the generator or enable outputs. The server implements 17 tools:
Tool | Purpose |
| Bundled specifications, operating notes and verified limitations |
| Separate measured 50-ohm SINE/SQUARE power tables and valid ranges |
| Check device identity and calculate voltage for requested dBm |
| Configure calibrated SINE/SQUARE AC RMS power into a physical 50-ohm load |
| Find USB serial ports without opening them |
| Built-in names/IDs and arbitrary slots |
| Model code, serial, port and frequency limit |
| Read both channels or one channel, mode and phase |
| Frequency, waveform, amplitude, offset, duty and enable |
| Independently enable/disable either output |
| Inter-channel phase; negative values normalized modulo 360 |
| Explicitly select mode and stop active actions |
| Sweep parameters, readback, optional start |
| Stop actions and disable both outputs |
| Read protocol registers, including counter/measurement data |
| Read 2048 samples from a stored waveform |
| Overwrite a stored waveform and verify all samples |
Scripting CLI
Successful commands print one JSON value to stdout. Failures print JSON to stderr
and exit with status 2. Help/argument parsing uses the standard argparse interface.
The port is discovered automatically. To override it, supply --port before
the subcommand or set JDS2800_PORT.
# 1 kHz triangle, 2 Vpp, +1 V offset on channel 1.
./jds2800 configure 1 --waveform TRIANGLE --frequency-hz 1000 \
--amplitude-vpp 2 --offset-v 1 --enabled on
# 2 kHz, 1 Vpp, 30% duty on channel 2.
./jds2800 configure 2 --waveform PULSE --frequency-hz 2000 \
--amplitude-vpp 1 --offset-v 0 --duty-percent 30 --enabled on
./jds2800 outputs --ch1 off
./jds2800 phase -90
./jds2800 stop
# Every MCP tool is also available through `call`.
./jds2800 call get_state --args '{"channel":2}'
./jds2800 call configure_sweep --args \
'{"channel":1,"start_hz":1000,"end_hz":2000,"time_s":1,"start":false}'
./jds2800 mode WAVE_CH1
# Multiple operations, one serial lease. This example enables both outputs.
./jds2800 batch examples/dual-channel.json
./jds2800 stopbatch also accepts - to read a JSON array from stdin. Entries contain an
operation (the MCP tool name) and an optional arguments object. Operations run
sequentially and stop on the first failure. Earlier operations are not rolled
back; the error includes their results and the failing entry's zero-based index.
Device behavior and units
Frequency is in Hz, amplitude in V peak-to-peak, offset in V, duty in percent, and phase in degrees. Frequency readback uses the actual quantized device value.
The connected unit reports model code 15, serial 1816400000. Its sine limit is 15 MHz. The driver detects the limit instead of assuming the original JDS6600 library's 60 MHz maximum.
Pulse/CMOS/arbitrary frequency is limited to 6 MHz. Other non-sine waveforms are limited to the smaller of the model limit and 25 MHz.
Amplitude and offset limits are checked together. Maximum amplitude decreases above 10 MHz and 30 MHz; non-sine amplitude is conservatively capped at 5 Vpp above 10 MHz. The allowed offset range also depends on amplitude. The actual load affects physical voltage. The tested wiring used direct coax into the scope's high-impedance inputs, with probe attenuation 1×.
Device synchronization can make selected CH2 parameters follow CH1 (manual p. 18). This server does not read or change synchronization settings; check the front-panel SYS menu before relying on independent channel parameters.
SQUARE is physically 50% duty on this unit. The duty register can say 30% while the square wave stays at 50%. Use PULSE for adjustable duty. Requests to set a non-50% SQUARE duty are rejected before writing.
Channel configuration requires
WAVE_CH1orWAVE_CH2mode. It validates the complete target configuration, temporarily disables the target channel, writes and reads back all its parameters, then restores its previous enable state unlessenabledwas supplied. It preserves the other channel's enable state.A failed configuration requests the target channel off and reports an error. Unplugging can prevent that request from reaching the device. There are no automatic write retries or claims of rollback; read state before continuing.
Each operation releases the serial connection after completion. CLI commands can coexist with a running MCP server. A shared file lock serializes operations across processes, including a complete batch. External legacy programs do not participate in this lock and should not run against the same port concurrently.
configure_sweepselects sweep mode and stops prior actions. It preserves output enable state;start=truestarts the action. Return explicitly to wave mode before ordinary configuration. Arbitrary uploads overwrite device storage; they do not select the slot or enable output.
Calibrated sine output in dBm
Calibrated square output
get_calibration, preview_power, and set_power also accept waveform="SQUARE".
The default remains SINE. Square output uses its own measured per-channel profile,
never the sine table or a theoretical +3 dB conversion. For example, an MCP call is:
{"channel":1,"frequency_hz":10000000,"power_dbm":7,"waveform":"SQUARE","enabled":true}Square power means AC RMS power including harmonics within the scope's bandwidth,
with the measured DC component removed. It is not fundamental-only RF power.
The output is configured for 50% duty and zero requested DC offset. Physical 50-ohm
termination and the measured cable setup are required. get_calibration(waveform="SQUARE")
reports the supported range and verification results; out-of-range requests fail before writes.
CMOS/PULSE and other duty cycles do not have calibrated dBm controls.
./jds2800 calibration --waveform SQUARE
./jds2800 preview-power 1 --frequency-hz 10000000 --dbm 7 --waveform SQUARE
./jds2800 power 1 --frequency-hz 10000000 --dbm 7 --waveform SQUARE --enabled onThe square profile is bundled separately as data/square-calibration.json and
exposed at jds2800://calibration/square. A measured override uses
JDS2800_SQUARE_CALIBRATION; JDS2800_CALIBRATION continues to select the sine profile.
See the square measurement guide.
Existing MCP clients must reconnect to discover the new waveform argument.
Existing sine profile
The bundled power calibration is for this 15 MHz generator, serial 1816400000, with separate tables for CH1 and CH2. It uses external 50-ohm terminations at Rigol CH1/CH3 through the existing direct coax cables. These loads must be present at the receiving end when using dBm settings. Scope-referenced power includes the measured cable loss.
./jds2800 calibration
./jds2800 preview-power 1 --frequency-hz 5500000 --dbm 0
./jds2800 power 1 --frequency-hz 5500000 --dbm 0 --enabled on
./jds2800 power 2 --frequency-hz 14500000 --dbm -10 --enabled on
./jds2800 stopset_power / power explicitly sets SINE, zero DC offset, 50% duty, frequency,
and calibrated amplitude. It preserves output enable state unless enabled is
supplied. It requires wave mode, verifies the generator serial and register
readback, and refuses requests outside the measured frequency/level ranges.
It does not remeasure power on every call. The returned predicted_power_dbm
accounts for the generator's 1 mV amplitude increments.
Calibration covers 1–15 MHz, at every integer MHz plus 10.01 MHz, with ten
amplitude settings per frequency on each channel: 320 points, each measured
three times. The table supports approximately -29 to +11 dBm across the full
frequency range, with precise per-frequency bounds reported by get_calibration.
The ordinary voltage controls retain the manufacturer's larger amplitude range;
the power controls require measured coverage. No frequency or level extrapolation
is performed. Interpolation is linear in dBm versus log amplitude and log frequency.
MCP get_calibration(include_points=true) returns the full measured table.
The resource jds2800://calibration returns metadata and supported ranges.
An alternate calibration file can be selected using JDS2800_CALIBRATION;
it must match the actual device and use the same sine/zero-offset/50-ohm convention.
The table is bundled in the installed package. Published evidence omits private
paths and connection addresses while preserving numeric readings and provenance.
The bundled profile applies only to serial 1816400000; other units require
their own measured profile, selected with JDS2800_CALIBRATION. Calibration
collection currently targets 15 MHz units.
To repeat calibration, attach both external 50-ohm loads, supply the scope server and address as described below, and run:
uv run jds2800-calibrate --scope-host "$RIGOL_HOST" --rigol-server "$RIGOL_SERVER" \
--out artifacts/new-power-calibration.json --confirm-50ohmThis procedure changes channel settings, uses the Rigol MCP server, saves partial
measurements as it runs, and disables both outputs on completion or a handled
failure. --resume continues an incomplete run with the same measurement grid.
The checked-in data are validated against independent frequency/level requests
by scripts/verify_power.py. This is a scope-referenced correction; absolute
accuracy still depends on the scope, terminations, cables, and operating conditions.
The RMS measurement includes harmonics and noise rather than isolating the RF
fundamental. Sine power calibration does not apply to square/pulse/noise outputs;
square output has the separate measured profile described above.
Scope readings come from numeric measurement queries. The collector clears previous measurements before each reading, retains Vpp, and derives AC power from RMS with the measured DC component removed. The display scale only keeps signals in range. The original 256 points used 16-acquisition averaging; 64 refinement points and the independent checks use normal acquisition. See the guide for the raw evidence.
Independent verification passed 72 checks from -25 to +10 dBm, including intermediate frequencies, the 10 MHz boundary, and both outputs together. The largest difference from requested power was 0.195 dB relative to this scope. See the results. Both outputs were left off.
What was tested
On October 3, 2026, both connected channels were verified through the actual stdio JDS2800 MCP server and the existing Rigol scope MCP server. Wiring: generator CH1 → scope CH1; generator CH2 → scope CH3. Scope: DS1104Z, serial DS1ZA225013504. See the measured values and screenshot in artifacts/hardware-verification.json and artifacts/scope-triangle-pulse.png.
The hardware test covers both sine outputs, the original triangle/offset setup, 30% pulse duty, independent output switching, negative-phase register readback, model-limit rejection without mutation, and CLI access while MCP is alive. The scope readings verify control behavior; this is not a calibration of absolute amplitude. Both generator outputs are off at the end of the test.
Sweep parameter/mode readback and reading all 2048 samples from arbitrary slot 1 were also checked on the device. Sweep progression, physical inter-channel phase, arbitrary uploads, and external counter/measurement inputs have not been verified on the scope. The tests do not overwrite stored arbitrary waveforms.
uv run pytest -q
uv run ruff check src tests scripts
uv run ruff format --check src tests scripts
# Handshake and discovery without hardware.
uv run python scripts/check_mcp.py
# Read the device through MCP without changing its settings.
uv run python scripts/check_mcp.py --hardware
# Changes both channels for testing, captures scope data, then disables outputs.
uv run python scripts/verify_hardware.py --rigol-server "$RIGOL_SERVER" \
--scope-host "$RIGOL_HOST"Supply RIGOL_SERVER as the path to a compatible Rigol stdio MCP server script
and RIGOL_HOST as the scope hostname or IP address. The hardware checks use
the active Python environment and USB discovery unless --port is supplied.
The scope server must be able to run in that environment. Scope setup writes
are followed by *OPC? through its scpi MCP tool to wait for completion.
Library comparison
Two drivers were exercised against the same 15 MHz instrument:
Driver | Observed result | Assessment for this server |
Python | Read both channels and changed frequency, waveform, amplitude, offset and enables | Compact API, same language as MCP, and compatible with the reproduced automation sequence |
Rust | Read identity, frequency/amplitude, and changed settings in individual commands | Partly compatible, but combined reads failed with exit status 19 |
The Rust reproduction --gg --gn successfully read CH1's offset, then failed on
CH2 with a missing-equals error. Its fixed-size read() calls do not consume a
complete variable-length CRLF reply or check the number of bytes returned. A
leftover byte is parsed as the next response. See
artifacts/rust-offset-read.txt and
artifacts/rust-frequency-write.txt.
The Python library is the better starting point, but its original class-level serial handle and loose validation also needed improvement. This server bypasses that constructor, replaces the transport, verifies readback, prevents negative waveform indexes, and fixes the original negative-phase conversion. The vendored Python driver makes ordinary operation independent of the comparison drivers.
Configuration
Setting | Default |
| Probe USB serial ports and select a single matching JDS generator |
| 1 second per serial reply/write |
| 5 seconds waiting for another operation |
Protocol reference: upstream register map. Hardware ranges follow the supplied manufacturer's manual, summarized in the bundled reference, which records the document edition, page references, and checksum. MIT license; the vendored library retains its original copyright and license.
Available Tools
17 toolsconfigure_channelADestructive
Set channel parameters in wave mode and verify them. Unspecified settings are preserved. Output is gated during changes; its previous enable state is restored unless enabled is supplied. Limits follow the detected model. On communication/readback failure the target output is requested off. SQUARE is physically 50% duty; use PULSE for adjustable duty.
Inputs: channel (required), enabled, offset_v, waveform, +3 more.
configure_sweepBDestructive
Switch to sweep mode, configure and read back limits. start=true starts the sweep. Output enable state is preserved; use set_outputs separately.
Inputs: end_hz (required), time_s (required), channel (required), start_hz (required), +3 more.
get_calibrationARead-onlyIdempotent
Read measured power calibration metadata/ranges without opening a port. include_points=true also returns the full amplitude/frequency measurement table. Applies to zero-offset SINE into a physical 50-ohm load through measured cables.
Inputs: channel, include_points.
get_device_infoARead-onlyIdempotent
Read the model code, serial number, port and detected sine frequency limit.
Inputs: no named parameters.
get_manualARead-onlyIdempotent
Read the bundled manual reference: model/frequency/voltage limits, 50-ohm power estimates, modes, synchronization, protocol notes, and tested behavior. Includes source page numbers and discrepancies. No serial port is opened.
Inputs: no named parameters. Returns: result
get_stateARead-onlyIdempotent
Read mode, phase and channel settings. Omit channel to read both.
Inputs: channel.
list_portsARead-onlyIdempotent
List USB serial ports without opening the generator.
Inputs: no named parameters. Returns: result
list_waveformsARead-onlyIdempotent
List built-in waveform names/IDs and the 60 arbitrary waveform slots.
Inputs: no named parameters. Returns: result
preview_powerARead-onlyIdempotent
Check generator identity and calculate calibrated voltage for sine power into 50 ohms. Interpolates measured levels/frequencies; no extrapolation or writes. Returns predicted power after 1 mV amplitude quantization, not a live measurement.
Inputs: channel (required), power_dbm (required), frequency_hz (required).
read_arbitraryARead-onlyIdempotent
Read all 2048 samples from an arbitrary waveform slot, numbered 1..60.
Inputs: slot (required).
read_registerARead-onlyIdempotent
Read a protocol register 0..89 for diagnostics or measurement/counter data. Unsupported registers may time out; this does not select a mode.
Inputs: register (required).
set_modeADestructive
Stop current actions, select the operating mode and verify it.
Inputs: mode (required).
set_outputsADestructive
Enable or disable outputs independently, preserving unspecified output state.
Inputs: ch1, ch2.
set_phaseADestructive
Set inter-channel phase, normalized to 0..359.9 degrees, with readback.
Inputs: phase_deg (required).
set_powerADestructive
Set calibrated sine power into a physical 50-ohm load using the measured table. Sets waveform=SINE, DC offset=0, duty=50, and frequency/amplitude. Requires wave mode and matching serial number. Preserves enabled state unless supplied. Predicted dBm includes measured cable loss; other loads/waveforms are unsupported. Uses register readback; it does not remeasure the signal with the scope.
Inputs: channel (required), power_dbm (required), frequency_hz (required), enabled.
stop_outputsADestructive
Stop sweep/counter/pulse/burst actions and disable both output channels.
Inputs: no named parameters.
upload_arbitraryADestructive
Overwrite slot 1..60 with 2048 integer samples (0..4095) and verify readback. This changes device waveform storage; it does not select the slot or enable output.
Inputs: slot (required), samples (required).
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 17 tools
Most tools have a clear primary purpose, but there are overlapping boundaries around output control (stop_outputs vs set_outputs), power/amplitude setting (set_power vs configure_channel vs preview_power), and sweep/mode selection (configure_sweep vs set_mode). The detailed descriptions mostly resolve these, so misselection is possible but not severe.
All tools use snake_case verb_noun names (get_/set_/list_/read_/configure_/stop_/upload_/preview_) with no mixed conventions. The pattern is predictable throughout.
17 tools is slightly above the typical 3-15 range, but the complex signal-generator domain (calibration, power, modes, arbitrary waveforms, diagnostics) justifies most tools. It is not excessive but feels a bit heavy.
Core signal generation workflows are covered: ports/info/state, channel config, outputs, phase, mode/sweep, calibrated sine power, arbitrary waveform read/upload, and manual/diagnostics. Minor gaps exist for configuring pulse/burst/counter modes despite stop_outputs referencing them, but agents can handle the main use cases.
Maintenance
Related MCP Connectors
32 agent utilities and 51 premium analyzers. API key required; automated checkout not active.
Agent utility belt: memory, locks, webhook inboxes, timers, DNS, email, URL, timezone, cron
Protocol-native energy infrastructure orchestration for AI data centers. Provides 46 MCP tools across 8 grid protocols (IEC-61850, DNP3, Modbus, OCPP, OpenADR, IEEE 2030.5, IEC 60870-5-104, ICCP) with 5 core API primitives: connect, dispatch, settle, comply, and intel. Enables AI agents to programmatically interact with substations, grid interfaces, and energy assets for real-time workload-grid coordination.
Build, run, inspect, and continue AgentScript workflows on connected Super Chrome and Mac clients.
Related MCP Servers
- AlicenseAqualityBmaintenanceEnables control of MHS-5200A series signal generators via serial connection, including frequency, amplitude, waveform, and sweep settings.16MIT
- AlicenseNot gradedqualityDmaintenanceEnables control of Digilent WaveForms instruments (oscilloscope, AWG, logic analyzer) over USB, supporting devices like Analog Discovery 2/3 and Digital Discovery.3MIT
- FlicenseNot gradedqualityDmaintenanceEnables remote control of Siglent SDG series function/arbitrary waveform generators via SCPI over TCP/IP. Provides tools for configuring waveforms, modulation, sweep, burst, and other instrument functions.1-
- AlicenseNot gradedqualityDmaintenanceEnables AI agents to control Siglent SDG-series signal generators, configure waveforms, and switch outputs via natural language.3MIT