Skip to main content
Glama

SCPI MCP

An MCP server that puts benchtop test equipment within reach of an agentic coding harness. Point Claude Code, Codex or any other MCP client at it and ask it to go investigate a circuit.

It exposes four instruments as 76 typed tools, plus a raw SCPI passthrough for everything the wrappers do not cover:

Device key

Instrument

arb

Arbitrary waveform generator

dmm

Multimeter

osc

Oscilloscope

psu

Power supply

Anything that speaks SCPI over a socket should work. SCPI is a text protocol standardized in 1990, which turns out to suit this well: instruments that already take commands as strings do not need much of an adapter to take them from a model.

Why it is useful

The oscilloscope can hand back screenshots. That matters more than it sounds, because a lot of what a scope tells you is a shape rather than a number, and a model that can look at the trace reasons about it the way a person would instead of working from whichever measurements someone thought to request in advance.

The useful range runs from "set a rising edge trigger at 2.5 volts on channel 2", which just saves a menu dive, up to handing over a misbehaving circuit and letting the model drive all four instruments to work out why.

Related MCP server: rigol-oscilloscope-mcp

Requirements

  • Python 3.10 or newer

  • Instruments reachable over the network, listening for raw SCPI (port 5025 on nearly everything)

Install

git clone https://github.com/colingimenez/SCPI_MCP.git
cd SCPI_MCP
uv sync

Configuration

Instrument addresses come from the environment, so nothing needs editing in source. Set only the ones you have.

Variable

Default

SCPI_ARB_HOST

arb.local

SCPI_DMM_HOST

dmm.local

SCPI_OSC_HOST

osc.local

SCPI_PSU_HOST

psu.local

SCPI_<NAME>_PORT

5025

Use it from an MCP client

{
  "mcpServers": {
    "scpi": {
      "command": "uv",
      "args": ["--directory", "/path/to/SCPI_MCP", "run", "main.py"],
      "env": {
        "SCPI_OSC_HOST": "192.0.2.10",
        "SCPI_PSU_HOST": "192.0.2.11"
      }
    }
  }
}

A note on safety

Raw SCPI has no authentication of any kind. Anything that can reach port 5025 on an instrument can drive it, and this server does nothing to change that. Put your bench on a network you trust.

The tools will also happily turn a power supply on, change its voltage, and reset an instrument to factory defaults, because that is the point. Be aware that a model driving this is driving real hardware with real things wired to it.

Known specifics

Oscilloscope screenshot capture is written against the Siglent SDS1202X-E, which streams a raw image with no length header and no terminator. Other scopes implement this differently and may need their own path.

License

MIT.

Available Tools

76 tools
arb_disable_burstA

Disable burst mode on a waveform generator channel.

Args: channel: Channel number (1 or 2).

Inputs: channel (required). Returns: result

arb_disable_modulationB

Disable all modulation on a waveform generator channel.

Args: channel: Channel number (1 or 2).

Inputs: channel (required). Returns: result

arb_disable_sweepA

Disable frequency sweep on a waveform generator channel.

Args: channel: Channel number (1 or 2).

Inputs: channel (required). Returns: result

arb_get_basic_waveformB

Query the current basic waveform parameters of a waveform generator channel.

Args: channel: Channel number (1 or 2).

Inputs: channel (required). Returns: result

arb_get_outputA

Query whether a waveform generator channel output is on or off.

Args: channel: Channel number (1 or 2).

Inputs: channel (required). Returns: result

arb_set_amB

Enable AM modulation on the waveform generator.

Args: channel: Channel number (1 or 2). depth: Modulation depth in percent. frequency: Modulation frequency in Hz.

Inputs: depth (required), channel (required), frequency (required). Returns: result

arb_set_amplitudeA

Set the output amplitude in Vpp on the waveform generator.

Args: channel: Channel number (1 or 2). amplitude: Amplitude in Vpp.

Inputs: channel (required), amplitude (required). Returns: result

arb_set_burstB

Enable burst mode on the waveform generator.

Args: channel: Channel number (1 or 2). cycles: Number of burst cycles. period: Burst period in seconds.

Inputs: cycles (required), period (required), channel (required). Returns: result

arb_set_duty_cycleA

Set the duty cycle (%) for square/pulse waveforms on the waveform generator.

Args: channel: Channel number (1 or 2). duty: Duty cycle percentage.

Inputs: duty (required), channel (required). Returns: result

arb_set_fmA

Enable FM modulation on the waveform generator.

Args: channel: Channel number (1 or 2). deviation: Frequency deviation in Hz. frequency: Modulation frequency in Hz.

Inputs: channel (required), deviation (required), frequency (required). Returns: result

arb_set_frequencyA

Set the output frequency in Hz on the waveform generator.

Args: channel: Channel number (1 or 2). frequency: Frequency in Hz.

Inputs: channel (required), frequency (required). Returns: result

arb_set_offsetC

Set the DC offset in volts on the waveform generator.

Args: channel: Channel number (1 or 2). offset: Offset in volts.

Inputs: offset (required), channel (required). Returns: result

arb_set_outputA

Enable or disable the output of a waveform generator channel.

Args: channel: Channel number (1 or 2). state: True to enable, False to disable.

Inputs: state (required), channel (required). Returns: result

arb_set_output_loadA

Set the output load impedance on the waveform generator.

Args: channel: Channel number (1 or 2). load: 'HZ' for high-impedance or a numeric value in ohms (e.g. '50').

Inputs: load (required), channel (required). Returns: result

arb_set_phaseA

Set the phase in degrees on the waveform generator.

Args: channel: Channel number (1 or 2). phase: Phase in degrees.

Inputs: phase (required), channel (required). Returns: result

arb_set_pmA

Enable PM (phase) modulation on the waveform generator.

Args: channel: Channel number (1 or 2). deviation: Phase deviation in degrees. frequency: Modulation frequency in Hz.

Inputs: channel (required), deviation (required), frequency (required). Returns: result

arb_set_polarityA

Set the output polarity on the waveform generator.

Args: channel: Channel number (1 or 2). polarity: 'NOR' for normal, 'INVT' for inverted.

Inputs: channel (required), polarity (required). Returns: result

arb_set_sweepA

Enable frequency sweep on the waveform generator.

Args: channel: Channel number (1 or 2). start_freq: Start frequency in Hz. stop_freq: Stop frequency in Hz. time: Sweep time in seconds.

Inputs: time (required), channel (required), stop_freq (required), start_freq (required). Returns: result

arb_set_waveformA

Set the basic waveform type on the waveform generator.

Args: channel: Channel number (1 or 2). waveform: Waveform type – SINE, SQUARE, RAMP, PULSE, NOISE, ARB, or DC.

Inputs: channel (required), waveform (required). Returns: result

dmm_clear_statisticsA

Clear accumulated statistics on the multimeter.

Inputs: no named parameters. Returns: result

dmm_disable_statisticsA

Disable statistics calculation on the multimeter.

Inputs: no named parameters. Returns: result

dmm_enable_statisticsA

Enable statistics calculation on the multimeter.

Inputs: no named parameters. Returns: result

dmm_fetchA

Fetch the last measurement from the multimeter without triggering a new one.

Inputs: no named parameters. Returns: result

dmm_get_functionA

Query the current measurement function on the multimeter.

Inputs: no named parameters. Returns: result

dmm_get_rangeA

Query the current measurement range on the multimeter.

Inputs: no named parameters. Returns: result

dmm_get_statisticsA

Query statistics (average, min, max, stddev) from the multimeter.

Inputs: no named parameters. Returns: result

dmm_measureB

Configure and take a single measurement on the multimeter.

Args: function: One of VOLT:DC, VOLT:AC, CURR:DC, CURR:AC, RES, FRES, FREQ, PER.

Inputs: function (required). Returns: result

dmm_readA

Take a new measurement reading from the multimeter (triggers and reads).

Inputs: no named parameters. Returns: result

dmm_set_auto_rangeA

Enable or disable auto-range on the multimeter.

Args: enable: True to enable, False to disable.

Inputs: enable (required). Returns: result

dmm_set_functionA

Set the measurement function on the multimeter.

Args: function: One of VOLT:DC, VOLT:AC, CURR:DC, CURR:AC, RES, FRES, FREQ, PER, CONT, DIOD, CAP.

Inputs: function (required). Returns: result

dmm_set_nplcA

Set the integration time in number of power line cycles on the multimeter.

Args: nplc: NPLC value (e.g. 0.02, 0.2, 1, 10, 100).

Inputs: nplc (required). Returns: result

dmm_set_rangeA

Set the measurement range on the multimeter.

Args: value: Range value (e.g. 10 for 10V range).

Inputs: value (required). Returns: result

dmm_set_resolutionC

Set the measurement resolution on the multimeter.

Args: resolution: Resolution value.

Inputs: resolution (required). Returns: result

dmm_set_trigger_sourceA

Set the trigger source on the multimeter.

Args: source: One of IMM, BUS, EXT.

Inputs: source (required). Returns: result

dmm_triggerB

Send a software trigger to the multimeter.

Inputs: no named parameters. Returns: result

get_errorA

Read the latest error from the device error queue.

Args: device: Device key – one of 'arb', 'dmm', 'osc', 'psu'.

Inputs: device (required). Returns: result

identifyA

Query the identification string of a device.

Args: device: Device key – one of 'arb', 'dmm', 'osc', 'psu'.

Inputs: device (required). Returns: result

osc_auto_setupB

Run auto-setup on the oscilloscope.

Inputs: no named parameters. Returns: result

osc_force_triggerB

Force a trigger event on the oscilloscope.

Inputs: no named parameters. Returns: result

osc_get_channel_infoA

Query full channel setup info from the oscilloscope.

Args: channel: Channel number (1 or 2).

Inputs: channel (required). Returns: result

osc_get_timebaseA

Query the current timebase setting on the oscilloscope.

Inputs: no named parameters. Returns: result

osc_measureA

Measure a waveform parameter on the oscilloscope.

Args: channel: Channel number (1 or 2). parameter: One of PKPK, MAX, MIN, AMPL, TOP, BASE, MEAN, RMS, FREQ, PER, RISE, FALL, DUTY, WID, NWID, DELAY, OVSP, OVSH.

Inputs: channel (required), parameter (required). Returns: result

osc_runA

Start acquisition (set trigger mode to AUTO) on the oscilloscope.

Inputs: no named parameters. Returns: result

osc_screenshotA

Capture a screenshot from the oscilloscope. Returns base64-encoded PNG data.

Inputs: no named parameters. Returns: result

osc_set_acquire_modeB

Set the acquisition mode on the oscilloscope.

Args: mode: One of SAMPLING, PEAK_DETECT, AVERAGE.

Inputs: mode (required). Returns: result

osc_set_average_countA

Set the number of averages when in average acquisition mode.

Args: count: Number of averages (power of 2, e.g. 4, 16, 64, 256).

Inputs: count (required). Returns: result

osc_set_channel_couplingA

Set the coupling mode of an oscilloscope channel.

Args: channel: Channel number (1 or 2). coupling: One of AC, DC, GND.

Inputs: channel (required), coupling (required). Returns: result

osc_set_channel_offsetA

Set the vertical offset of an oscilloscope channel.

Args: channel: Channel number (1 or 2). offset: Offset in volts.

Inputs: offset (required), channel (required). Returns: result

osc_set_channel_scaleA

Set the vertical scale (V/div) of an oscilloscope channel.

Args: channel: Channel number (1 or 2). scale: Volts per division.

Inputs: scale (required), channel (required). Returns: result

osc_set_channel_stateA

Enable or disable a channel trace on the oscilloscope.

Args: channel: Channel number (1 or 2). state: True to enable, False to disable.

Inputs: state (required), channel (required). Returns: result

osc_set_memory_sizeA

Set the acquisition memory depth on the oscilloscope.

Args: size: Memory size, e.g. '7K', '70K', '700K', '7M', '14M'.

Inputs: size (required). Returns: result

osc_set_probe_attenuationA

Set the probe attenuation factor on an oscilloscope channel.

Args: channel: Channel number (1 or 2). attenuation: Attenuation factor (e.g. 1, 10, 100).

Inputs: channel (required), attenuation (required). Returns: result

osc_set_timebaseA

Set the horizontal timebase (s/div) on the oscilloscope.

Args: scale: Time per division in seconds.

Inputs: scale (required). Returns: result

osc_set_trigger_levelA

Set the trigger level in volts on the oscilloscope.

Args: level: Trigger level in volts.

Inputs: level (required). Returns: result

osc_set_trigger_modeC

Set the trigger mode on the oscilloscope.

Args: mode: One of AUTO, NORM, SINGLE, STOP.

Inputs: mode (required). Returns: result

osc_set_trigger_slopeA

Set the trigger slope on the oscilloscope.

Args: slope: 'POS' for rising edge, 'NEG' for falling edge.

Inputs: slope (required). Returns: result

osc_set_trigger_sourceA

Set the trigger source channel on the oscilloscope.

Args: channel: Channel number (1 or 2).

Inputs: channel (required). Returns: result

osc_singleA

Set the oscilloscope to single-trigger mode.

Inputs: no named parameters. Returns: result

osc_stopB

Stop acquisition on the oscilloscope.

Inputs: no named parameters. Returns: result

psu_get_currentA

Query the set current limit on a power supply channel.

Args: channel: Channel number (1, 2, or 3).

Inputs: channel (required). Returns: result

psu_get_outputA

Query whether a power supply channel output is on or off.

Args: channel: Channel number (1, 2, or 3).

Inputs: channel (required). Returns: result

psu_get_statusB

Query the system status register of the power supply (channel modes, output states).

Inputs: no named parameters. Returns: result

psu_get_voltageA

Query the set voltage on a power supply channel.

Args: channel: Channel number (1, 2, or 3).

Inputs: channel (required). Returns: result

psu_measure_currentA

Measure the actual output current on a power supply channel.

Args: channel: Channel number (1, 2, or 3).

Inputs: channel (required). Returns: result

psu_measure_powerA

Measure the actual output power on a power supply channel.

Args: channel: Channel number (1, 2, or 3).

Inputs: channel (required). Returns: result

psu_measure_voltageA

Measure the actual output voltage on a power supply channel.

Args: channel: Channel number (1, 2, or 3).

Inputs: channel (required). Returns: result

psu_recallB

Recall a saved preset on the power supply.

Args: preset: Preset number (1–5).

Inputs: preset (required). Returns: result

psu_saveA

Save the current settings to a preset on the power supply.

Args: preset: Preset number (1–5).

Inputs: preset (required). Returns: result

psu_set_currentA

Set the output current limit on a power supply channel.

Args: channel: Channel number (1, 2, or 3). current: Current in amps.

Inputs: channel (required), current (required). Returns: result

psu_set_modeA

Set the channel tracking mode on the power supply.

Args: mode: One of INDEPENDENT, SERIES, PARALLEL.

Inputs: mode (required). Returns: result

psu_set_ocpA

Set the over-current protection threshold on a power supply channel.

Args: channel: Channel number (1 or 2). current: OCP threshold in amps.

Inputs: channel (required), current (required). Returns: result

psu_set_outputA

Enable or disable the output of a power supply channel.

Args: channel: Channel number (1, 2, or 3). state: True to enable, False to disable.

Inputs: state (required), channel (required). Returns: result

psu_set_ovpA

Set the over-voltage protection threshold on a power supply channel.

Args: channel: Channel number (1 or 2). voltage: OVP threshold in volts.

Inputs: channel (required), voltage (required). Returns: result

psu_set_voltageB

Set the output voltage on a power supply channel.

Args: channel: Channel number (1, 2, or 3). voltage: Voltage in volts.

Inputs: channel (required), voltage (required). Returns: result

resetA

Reset a device to factory defaults.

Args: device: Device key – one of 'arb', 'dmm', 'osc', 'psu'.

Inputs: device (required). Returns: result

send_raw_scpiB

Send an arbitrary SCPI command to a device. If the command ends with '?', the response is returned.

Args: device: Device key – one of 'arb', 'dmm', 'osc', 'psu'. command: The raw SCPI command string.

Inputs: device (required), command (required). Returns: result

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    B3.4/5.0

    Scored across 76 tools

    Disambiguation4/5

    Device-specific prefixes (arb_, dmm_, osc_, psu_) cleanly separate tools by instrument, and most tools target a unique parameter. A few pairs like dmm_read vs dmm_measure and psu_get_voltage vs psu_measure_voltage have overlapping semantics, though descriptions clarify the distinction.

    Naming Consistency4/5

    Most tools follow a consistent device_verb_noun pattern (e.g., arb_set_frequency, psu_measure_current), making the set highly predictable. Minor deviations such as osc_screenshot, psu_recall, and arb_get_basic_waveform break the strict pattern but are still understandable.

    Tool Count3/5

    76 tools is a high number, but the server covers four independent instruments with 15-22 tools each, matching the device-specific scope. The count feels heavy for an agent to sort through, though naming conventions and prefix grouping mitigate the burden.

    Completeness4/5

    The surface covers the vast majority of operations needed for the four instruments: waveform generation, DMM measurement and statistics, oscilloscope triggering/measurement, and PSU output/protection. The most notable gap is lack of oscilloscope waveform data acquisition (raw trace points), which agents may need for signal analysis.

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      C
      quality
      B
      maintenance
      Enables natural language control of test instruments like spectrum analyzers and power supplies via SCPI commands, with auto-discovery and multi-instrument session support.
      100
      1
      MIT
    • A
      license
      A
      quality
      B
      maintenance
      Enables LLMs to control RIGOL oscilloscopes over SCPI via LAN or USB, including configuring channels/timebase/trigger, taking measurements, capturing waveforms and screenshots, decoding serial protocols, running FFT analysis, and controlling the built-in AFG.
      38
      MIT
    • A
      license
      Not graded
      quality
      C
      maintenance
      Enables MCP clients to connect to and control Siglent oscilloscopes and power supplies over SCPI/TCP using typed tool calls with input validation, safety controls, and built-in observability.
      1
      Apache 2.0
    • F
      license
      Not graded
      quality
      B
      maintenance
      Enables unified discovery, query, and control of laboratory instruments (power supplies, oscilloscopes, signal generators, multimeters) via VISA/SCPI, with device-specific libraries and an MCP server exposing 19 tools for natural language interaction.
      -