Skip to content

Configuration

mcpyvisa uses a TOML configuration file to define backends, instrument aliases, and server behavior. If no configuration file is found, the server starts with no backends configured.

The server looks for a configuration file in this order, using the first one found:

  1. $MCPYVISA_CONFIG — environment variable pointing to an explicit path
  2. ./mcpyvisa.toml — current working directory
  3. ~/.config/mcpyvisa/config.toml — XDG user config directory

If none of these paths exist, the server starts with an empty configuration (zero backends).

The [server] section controls global server behavior.

[server]
log_level = "INFO" # DEBUG, INFO, WARNING, ERROR
auto_discover = true # Discover instruments on connect (default: true)
auto_identify = true # Send *IDN? to discovered instruments (default: true)
KeyTypeDefaultDescription
log_levelstring"INFO"Python logging level. DEBUG logs every command sent to backends
auto_discoverbooleantrueAutomatically discover instruments when a backend connects. Individual backends can override this
auto_identifybooleantrueSend *IDN? to each discovered instrument. Individual backends can override this

Each [[backend]] section defines a single backend connection. You can define as many backends as needed — they are accessed independently and concurrently (one lock per backend, concurrent across backends).

mcpyvisa supports four backend types:

Connect to an AR488/Prologix adapter over USB serial.

[[backend]]
name = "bench-a" # Unique identifier
type = "ar488" # Backend type
transport = "serial" # Serial connection
port = "/dev/ttyUSB0" # Serial port path
baudrate = 115200 # Serial baud rate (default: 115200)
auto_discover = true # Discover instruments on connect (default: true)
auto_identify = true # Send *IDN? to discovered listeners (default: true)
read_timeout_ms = 3000 # GPIB read timeout for this backend (default: 3000)
inter_command_delay_ms = 10 # Delay between commands in ms (default: 10)

Connect to an AR488 adapter with WiFi enabled over TCP.

[[backend]]
name = "bench-b"
type = "ar488"
transport = "tcp"
host = "192.168.1.50" # IP address or hostname of ESP32
tcp_port = 23 # AR488 WiFi default port (default: 23)
auto_discover = false # Skip initial scan (useful for slow WiFi links)
read_timeout_ms = 5000 # Longer timeout for WiFi latency
inter_command_delay_ms = 20 # Larger delay for WiFi stability

Use the pure-Python pyvisa-py library for USB-TMC, LAN/VXI-11, and serial instruments. Does not require NI-VISA.

[[backend]]
name = "lan"
type = "pyvisa-py"

Use the system-installed VISA library (NI-VISA, Keysight IO Libraries, etc.). Provides access to all instrument types supported by the system VISA implementation.

[[backend]]
name = "ni"
type = "system"

Use the pyvisa-sim library to create virtual instruments from a YAML definition file. No hardware, drivers, or network access required.

[[backend]]
name = "sim-bench"
type = "sim"
sim_file = "./gpib-catalog/sim/all_instruments.yaml"
KeyTypeDefaultApplies toDescription
namestring(required)AllUnique backend identifier. Alphanumeric with hyphens and underscores only
typestring(required)AllBackend type: "ar488", "pyvisa-py", "system", or "sim"
transportstring"serial"AR488Transport type: "serial" or "tcp"
portstringnullAR488 serialSerial port path (required for serial transport)
baudrateinteger115200AR488 serialSerial baud rate
hoststringnullAR488 TCPTCP host address (required for TCP transport)
tcp_portinteger23AR488 TCPTCP port number
auto_discoverbooleantrueAllDiscover instruments on connect
auto_identifybooleantrueAllSend *IDN? to each discovered instrument
read_timeout_msinteger3000AR488GPIB read timeout in milliseconds (1—32000)
inter_command_delay_msinteger10AR488Delay between consecutive ++ commands (0—1000 ms)
sim_filestringnullSimPath to pyvisa-sim YAML definition file

The [instruments] section defines friendly aliases for VISA resource strings. Each key becomes an alias that can be used anywhere an instrument parameter is accepted.

[instruments.dmm]
resource = "GPIB0::22::INSTR"
backend = "bench-a"
[instruments.smu]
resource = "GPIB0::24::INSTR"
backend = "bench-a"
[instruments.psu]
resource = "GPIB0::5::INSTR"
backend = "bench-a"
[instruments.scope]
resource = "TCPIP::192.168.1.100::INSTR"
backend = "lan"
KeyTypeRequiredDescription
resourcestringYesVISA resource string for the instrument
backendstringYesName of the backend this instrument is connected to

With the above configuration, all of these are equivalent:

# Using the alias
await client.call_tool("instrument_query", {"instrument": "dmm", "command": "MEAS:VOLT:DC?"})
# Using the VISA resource string directly
await client.call_tool("instrument_query", {"instrument": "GPIB0::22::INSTR", "command": "MEAS:VOLT:DC?"})

Aliases provide shorter, memorable names and map instruments to specific backends, so mcpyvisa knows which backend to route commands through.

VariableDescription
MCPYVISA_CONFIGAbsolute path to TOML config file. Overrides the default search order

A complete configuration showing all backend types — AR488 serial, AR488 WiFi, pyvisa-py, system VISA, and sim:

mcpyvisa.toml
[server]
log_level = "INFO"
auto_discover = true
auto_identify = true
# USB-connected AR488 on the main bench
[[backend]]
name = "bench-a"
type = "ar488"
transport = "serial"
port = "/dev/ttyUSB0"
baudrate = 115200
auto_discover = true
auto_identify = true
read_timeout_ms = 3000
inter_command_delay_ms = 10
# WiFi-connected AR488 in the RF shielded room
[[backend]]
name = "rf-bench"
type = "ar488"
transport = "tcp"
host = "192.168.1.50"
tcp_port = 23
auto_discover = true
auto_identify = true
read_timeout_ms = 5000
inter_command_delay_ms = 20
# pyvisa-py for USB and LAN instruments
# [[backend]]
# name = "lan"
# type = "pyvisa-py"
# System VISA (NI-VISA, Keysight IO)
# [[backend]]
# name = "ni"
# type = "system"
# Simulated instruments (no hardware required)
# [[backend]]
# name = "sim-bench"
# type = "sim"
# sim_file = "./gpib-catalog/sim/all_instruments.yaml"
# Instrument aliases
[instruments.dmm]
resource = "GPIB0::22::INSTR"
backend = "bench-a"
[instruments.smu]
resource = "GPIB0::24::INSTR"
backend = "bench-a"
[instruments.psu]
resource = "GPIB0::5::INSTR"
backend = "bench-a"
# [instruments.scope]
# resource = "TCPIP::192.168.1.100::INSTR"
# backend = "lan"