TCP/IP SCPI control for Copper Mountain Vector Network Analyzers via Model Context Protocol.
Disclaimer: This project is not affiliated with, endorsed by, or sponsored by Copper Mountain Technologies. "Copper Mountain" is a trademark of Copper Mountain Technologies. This is an independent open-source project.
| Family | Description | Example Models | S-Parameters |
|---|---|---|---|
| RVNA | 1-port reflectometers | R54, R60 | S11 |
| TRVNA | 2-port 1-path | TR1300 | S11, S21 |
| S2VNA | 2-port full reversing | M5090, Planar 804/1 | S11, S12, S21, S22 |
| S4VNA | 4-port full | S5048 | Full 4x4 matrix |
- Windows PC running Copper Mountain VNA software with socket server enabled
- Python 3.10+
- Network connectivity between MCP server host and VNA host (can be same machine)
pip install coppermountain-vna-mcpgit clone https://github.com/RFingAdam/copper-mountain-vna-mcp.git
cd copper-mountain-vna-mcp
pip install -e .mcp>=1.0.0pydantic>=2.0pydantic-settings>=2.0
Configure via environment variables or .env file:
# Connection defaults
VNA_DEFAULT_HOST=127.0.0.1 # VNA software host IP
VNA_DEFAULT_PORT=5025 # Socket server port
VNA_CONNECTION_TIMEOUT=5.0 # TCP connection timeout (seconds)
VNA_COMMAND_TIMEOUT=30.0 # SCPI command timeout (seconds)
# Safety limits
# These limits protect your equipment and DUT from damage.
# Adjust based on your VNA model and test requirements.
VNA_MAX_POWER_DBM=10 # Maximum output power (typical VNA max: +10 dBm)
VNA_MIN_POWER_DBM=-55 # Minimum output power
VNA_MAX_FREQUENCY_HZ=20000000000 # 20 GHz (adjust for your VNA model)
VNA_MIN_FREQUENCY_HZ=100000 # 100 kHz
VNA_MAX_POINTS=10001 # Maximum sweep points (memory/speed tradeoff)
# Software paths (Windows only - for auto-launch)
VNA_S2VNA_PATH=C:\Program Files\Copper Mountain Technologies\S2VNA\S2VNA.exe
VNA_RVNA_PATH=C:\Program Files\Copper Mountain Technologies\RVNA\RVNA.exe
VNA_TRVNA_PATH=C:\Program Files\Copper Mountain Technologies\TRVNA\TRVNA.exe
VNA_S4VNA_PATH=C:\Program Files\Copper Mountain Technologies\S4VNA\S4VNA.exe
# Logging
VNA_LOG_LEVEL=INFO| Setting | Purpose | When to Adjust |
|---|---|---|
VNA_MAX_POWER_DBM |
Prevents DUT damage from excessive power | Lower for sensitive devices (LNAs, detectors) |
VNA_MIN_POWER_DBM |
Ensures signal above noise floor | Rarely needs adjustment |
VNA_MAX_FREQUENCY_HZ |
Prevents out-of-band operation | Set to your VNA's max frequency |
VNA_MIN_FREQUENCY_HZ |
Prevents invalid frequency requests | Set to your VNA's min frequency |
VNA_MAX_POINTS |
Limits memory usage and sweep time | Increase for high-resolution sweeps |
The VNA software runs on Windows. Enable the socket server via command line:
S2VNA / S4VNA:
S2VNA.exe /SocketServer:on /SocketPort:5025 /visible:onRVNA / TRVNA:
RVNA.exe EnableSocket:5025Or enable via GUI: System > Socket Server > Enable
Add to claude_desktop_config.json:
{
"mcpServers": {
"copper-mountain-vna": {
"command": "python",
"args": ["-m", "coppermountain_vna_mcp"],
"env": {
"VNA_DEFAULT_HOST": "127.0.0.1",
"VNA_DEFAULT_PORT": "5025"
}
}
}
}Connect and perform a basic S11 measurement:
import asyncio
from coppermountain_vna_mcp.driver import CopperMountainVNADriver
from coppermountain_vna_mcp.models import SParameter, SweepConfig
async def main():
async with CopperMountainVNADriver("127.0.0.1", 5025) as vna:
# Get instrument info
info = await vna.identify()
print(f"Connected: {info.manufacturer} {info.model}")
# Configure sweep: 1-2 GHz, 201 points
config = SweepConfig(
start_freq_hz=1e9,
stop_freq_hz=2e9,
num_points=201,
if_bandwidth_hz=1000,
power_dbm=0,
)
await vna.configure_sweep(config)
# Perform sweep and get data
await vna.trigger_sweep()
data = await vna.get_s_parameter_data(SParameter.S11)
# Find minimum (best match)
marker = await vna.marker_search_min()
print(f"Best match: {marker.frequency_hz/1e9:.3f} GHz @ {marker.magnitude_db:.1f} dB")
# Export to Touchstone
await vna.save_touchstone("measurement.s1p")
asyncio.run(main())| Tool | Description |
|---|---|
vna_discover |
Scan ports 5025-5035 for running VNA instances |
vna_connect |
Connect to VNA at specified host:port |
vna_disconnect |
Disconnect from VNA |
vna_identify |
Get VNA identification (*IDN?) |
vna_get_status |
Get connection and configuration status |
| Tool | Description |
|---|---|
vna_configure_sweep |
Set frequency range, points, IF BW, power |
vna_set_center_span |
Configure via center frequency and span |
vna_set_averaging |
Configure sweep averaging |
vna_set_port_power |
Set power level per port |
vna_output_on |
Enable RF output |
vna_output_off |
Disable RF output |
| Tool | Description |
|---|---|
vna_trigger_sweep |
Trigger single sweep, wait for completion |
vna_get_s_parameter |
Get S-parameter data (frequency, magnitude, phase) |
vna_measure_return_loss |
Measure S11 at specific frequency |
vna_measure_vswr |
Measure VSWR at specific frequency |
vna_measure_insertion_loss |
Measure S21 at specific frequency |
| Tool | Description |
|---|---|
vna_set_marker |
Position marker at frequency |
vna_get_marker |
Get marker value |
vna_marker_search_min |
Find minimum in sweep |
vna_marker_search_max |
Find maximum in sweep |
vna_marker_bandwidth |
Find -3dB (or specified) bandwidth |
| Tool | Description |
|---|---|
vna_calibration_status |
Get calibration validity |
vna_calibration_start |
Start calibration (SOL, SOLT, SOLR, TRL) |
vna_calibration_measure_standard |
Measure OPEN/SHORT/LOAD/THRU |
vna_calibration_apply |
Apply calibration coefficients |
vna_correction_on |
Enable error correction |
vna_correction_off |
Disable error correction |
| Tool | Description |
|---|---|
vna_save_touchstone |
Export to .s1p/.s2p/.s4p file |
vna_save_screenshot |
Save display screenshot |
| Tool | Description |
|---|---|
vna_scpi_send |
Send raw SCPI command |
vna_scpi_query |
Send SCPI query, return response |
vna_reset |
Reset VNA (*RST) |
vna_preset |
Preset VNA (SYST:PRES) |
| Tool | Description |
|---|---|
vna_list_templates |
List all available measurement templates |
vna_load_template |
Load a measurement template by name |
vna_apply_template |
Apply loaded template to VNA |
vna_save_state |
Save VNA configuration to file |
vna_load_state |
Restore VNA configuration from file |
vna_get_full_state |
Get complete VNA configuration as JSON |
Pre-configured templates for common measurement scenarios. Each template sets up sweep parameters, markers, and display traces appropriately.
| Template | Frequency Range | Description |
|---|---|---|
antenna_wifi_24ghz |
2.4-2.5 GHz | WiFi 2.4 GHz band |
antenna_ble_24ghz |
2.402-2.480 GHz | Bluetooth Low Energy |
antenna_wifi_ble_24ghz |
2.4-2.5 GHz | Combined WiFi/BLE 2.4 GHz |
antenna_wifi_5ghz |
5.15-5.85 GHz | Full WiFi 5 GHz band |
antenna_wifi_5ghz_unii1 |
5.15-5.25 GHz | WiFi 5 GHz UNII-1 only |
antenna_wifi_5ghz_unii3 |
5.725-5.85 GHz | WiFi 5 GHz UNII-3 only |
antenna_wifi_6ghz |
5.925-7.125 GHz | WiFi 6E / 6 GHz band |
antenna_wifi_dual_band |
2.4 + 5 GHz | Dual-band WiFi |
antenna_wifi_tri_band |
2.4 + 5 + 6 GHz | Tri-band WiFi 6E |
antenna_mimo_wifi_24ghz |
2.4-2.5 GHz | MIMO 2.4 GHz (S11+S22+S21) |
antenna_mimo_wifi_5ghz |
5.15-5.85 GHz | MIMO 5 GHz (S11+S22+S21) |
antenna_mimo_wifi_dual_band |
2.4 + 5 GHz | MIMO dual-band (S11+S22+S21) |
antenna_ism_us915 |
902-928 MHz | US ISM band (LoRa, Zigbee) |
antenna_ism_eu868 |
863-870 MHz | EU ISM band (LoRa, Zigbee) |
antenna_ism_worldwide |
862-928 MHz | Worldwide ISM (EU + US) |
antenna_uwb_channel_5 |
6489.6 MHz | UWB Channel 5 |
antenna_uwb_channel_9 |
7987.2 MHz | UWB Channel 9 |
antenna_uwb_full_band |
3.1-8.5 GHz | Full UWB band |
antenna_cellular |
600 MHz-2.7 GHz | Cellular/LTE multiband |
antenna_mimo_cellular |
600 MHz-2.7 GHz | MIMO Cellular (S11+S22+S21) |
antenna_gps_l1 |
1575.42 MHz | GPS L1 band |
antenna_gnss_dual_band |
L1 + L5 | Dual-band GNSS |
antenna_nfc |
300 kHz-40 MHz | NFC with SRF detection |
| Template | Frequency Range | Description |
|---|---|---|
cable_dc_2_4ghz |
100 kHz-2.4 GHz | Cable/connector test |
cable_dc_8_5ghz |
100 kHz-8.5 GHz | Extended frequency cable test |
| Template | Description |
|---|---|
filter_wifi_24ghz |
2.4 GHz WiFi bandpass filter |
filter_wifi_5ghz |
5 GHz WiFi bandpass filter |
filter_ism_915mhz |
915 MHz ISM bandpass filter |
filter_gps_l1 |
GPS L1 bandpass filter |
filter_bandpass_custom |
Custom bandpass (provide center_freq_hz, bandwidth_hz) |
filter_lowpass_custom |
Custom lowpass (provide cutoff_freq_hz) |
# List available templates
templates = await vna.list_templates()
# Load and apply a WiFi 5GHz antenna template
await vna.load_template("antenna_wifi_5ghz")
await vna.apply_template()
# Or use custom template parameters
await vna.load_template("filter_bandpass_custom",
center_freq_hz=1.5e9,
bandwidth_hz=100e6)
await vna.apply_template()For reflection measurements (S11) on single-port VNAs or when only measuring one port:
- Start calibration:
vna_calibration_start(method="SOL") - Connect SHORT standard, measure:
vna_calibration_measure_standard(standard="SHORT", port_num=1) - Connect OPEN standard, measure:
vna_calibration_measure_standard(standard="OPEN", port_num=1) - Connect LOAD standard, measure:
vna_calibration_measure_standard(standard="LOAD", port_num=1) - Apply calibration:
vna_calibration_apply() - Enable correction:
vna_correction_on()
For full 2-port measurements including transmission (S21, S12):
- Start calibration:
vna_calibration_start(method="SOLT") - Measure standards on Port 1: SHORT, OPEN, LOAD
- Measure standards on Port 2: SHORT, OPEN, LOAD
- Connect THRU between ports:
vna_calibration_measure_standard(standard="THRU") - Apply calibration:
vna_calibration_apply() - Enable correction:
vna_correction_on()
- Calibration is frequency-specific; recalibrate when changing frequency range significantly
- Use quality calibration standards appropriate for your frequency range
- Store calibration files on the VNA for reuse
- Verify calibration by measuring a known standard (e.g., airline, attenuator)
The MCP server connects to VNA software via TCP/IP, enabling flexible deployment:
+-------------------+ TCP/IP +-------------------+
| Linux/macOS |<--------------->| Windows PC |
| | Port 5025 | |
| +-----------+ | | +-------------+ |
| | MCP Server| | | | VNA Software| |
| +-----------+ | | +-------------+ |
| | | | |
+-------------------+ | +----v----+ |
| | VNA | |
| | Hardware| |
| +---------+ |
+-------------------+
copper-mountain-vna-mcp/
├── src/coppermountain_vna_mcp/
│ ├── __init__.py
│ ├── __main__.py # Entry point
│ ├── server.py # MCP server (stdio transport)
│ ├── tools.py # Tool definitions and handlers
│ ├── config.py # Pydantic settings
│ │
│ ├── driver/
│ │ ├── scpi_socket.py # Async TCP/IP SCPI transport
│ │ ├── vna_driver.py # Unified VNA driver
│ │ └── exceptions.py # Custom exceptions
│ │
│ ├── models/
│ │ ├── vna_types.py # VNAFamily, SParameter enums
│ │ ├── sweep.py # SweepConfig dataclass
│ │ └── measurement.py # SParameterData, MarkerData
│ │
│ ├── safety/
│ │ └── validators.py # Power/frequency limit enforcement
│ │
│ └── software/
│ ├── launcher.py # VNA software lifecycle (Windows)
│ └── discovery.py # Port scanning
│
├── tests/
├── examples/
└── assets/
# Install with dev dependencies
pip install -e ".[dev]"
# Run tests
pytest
# Run tests with coverage
pytest --cov=coppermountain_vna_mcp
# Type checking
mypy src/
# Linting
ruff check src/Requires VNA hardware:
VNA_TEST_HOST=127.0.0.1 VNA_TEST_PORT=5025 pytest tests/test_integration.py -v- Verify VNA software is running with socket server enabled
- Check firewall settings allow connections on the configured port
- Confirm the IP address is correct (use
127.0.0.1for local, actual IP for remote)
- Increase
VNA_COMMAND_TIMEOUTfor long sweeps (many points, narrow IF bandwidth) - Check VNA is not in manual trigger mode
- Verify the requested S-parameter is supported by your VNA family
- RVNA: S11 only
- TRVNA: S11, S21
- S2VNA: S11, S12, S21, S22
- S4VNA: Full 4x4 matrix
- Ensure
vna_calibration_apply()was called after measuring all standards - Call
vna_correction_on()to enable error correction - Verify calibration covers current frequency range
Apache License 2.0 - see LICENSE for details.
Copyright 2025 Adam Engelbrecht (RFingAdam)