copper-mountain-vna-mcp
<div align="center">
<img src="assets/logo-banner.svg" alt="copper-mountain-vna-mcp: Copper Mountain VNA control over SCPI" width="100%"/>
<br/>
[](https://github.com/RFingAdam/copper-mountain-vna-mcp/actions/workflows/ci.yml)
[](LICENSE)
[](https://www.python.org/downloads/)
[](https://modelcontextprotocol.io)
[](https://github.com/RFingAdam/eng-mcp-suite)
**Drive Copper Mountain Vector Network Analyzers from any MCP-compatible AI client.**
**TCP/IP SCPI over the wire: 45 tools spanning sweep, calibration, measurement, and export.**
[Quick start](#quick-start) ยท
[Tools](#tools) ยท
[Workflows](#workflows) ยท
[Documentation](#documentation)
</div>
---
## What is copper-mountain-vna-mcp?
`copper-mountain-vna-mcp` is a [Model Context Protocol](https://modelcontextprotocol.io)
server that exposes a Copper Mountain VNA: RVNA, TRVNA, S2VNA, or S4VNA family
to any MCP-capable AI assistant. The server speaks raw TCP/IP SCPI to the
Copper Mountain software socket server (default port `5025`), then surfaces
sweep configuration, calibration, S-parameter capture, marker math, and
Touchstone export as plain MCP tools.
Drive it from Claude Desktop, Claude Code, VS Code Copilot, or any other MCP
client. SCPI is generated server-side, so the AI agent never needs to know the
underlying command set. It just calls `vna_configure_sweep`, `vna_trigger_sweep`,
`vna_get_s_parameter` and gets back structured data.
**What `copper-mountain-vna-mcp` does well:**
- ๐ค **AI-native via MCP.** First-class [Model Context Protocol](https://modelcontextprotocol.io)
server with 45 tools. Any Claude / LLM agent can drive it.
- ๐ **Python + MCP surfaces.** Import `coppermountain_vna_mcp` for direct driver access,
or run as an MCP server for AI-agent automation.
- โก **Direct TCP/IP SCPI.** No VISA dependency, no proprietary middleware: just
asyncio sockets straight to the Copper Mountain software socket server.
- โ
**Validated against 4 VNA families.** RVNA (S11), TRVNA (S11/S21),
S2VNA (full 2-port), S4VNA (full 4ร4).
- ๐ **AGPL-3.0-or-later.** Network-copyleft open-source. Independent of
Copper Mountain Technologies (trademark disclaimer below).
> **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.
---
## Quick start
### Install
```bash
pip install coppermountain-vna-mcp
```
Or from source:
```bash
git clone https://github.com/RFingAdam/copper-mountain-vna-mcp.git
cd copper-mountain-vna-mcp
pip install -e ".[dev]"
```
### Supported instruments
| Family | Description | Example models | S-parameters |
| ------ | ----------- | -------------- | ------------ |
| RVNA | 1-port reflectometer | 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 4ร4 matrix |
### Two surfaces, same answer
<table>
<tr>
<td valign="top" width="50%">
**Python**
```python
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:
await vna.configure_sweep(SweepConfig(
start_freq_hz=1e9, stop_freq_hz=2e9,
num_points=201, if_bandwidth_hz=1000, power_dbm=0,
))
await vna.trigger_sweep()
data = await vna.get_s_parameter_data(SParameter.S11)
marker = await vna.marker_search_min()
print(f"Best match: {marker.frequency_hz/1e9:.3f} GHz @ {marker.magnitude_db:.1f} dB")
asyncio.run(main())
```
</td>
<td valign="top" width="50%">
**MCP (Claude Desktop, Claude Code, any MCP client)**
```json
{
"mcpServers": {
"copper-mountain-vna": {
"command": "python",
"args": ["-m", "coppermountain_vna_mcp"],
"env": {
"VNA_DEFAULT_HOST": "127.0.0.1",
"VNA_DEFAULT_PORT": "5025"
}
}
}
}
```
Then ask your assistant in plain English:
> *"Connect to the VNA on 127.0.0.1, sweep 1โ2 GHz at 201 points, and tell me where S11 is best matched."*
The agent will call `vna_connect`, `vna_configure_sweep`, `vna_trigger_sweep`,
and `vna_marker_search_min` in sequence and report the result.
</td>
</tr>
</table>
### Start the VNA software socket server
The VNA software runs on Windows. Enable the socket server via command line:
```cmd
:: S2VNA / S4VNA
S2VNA.exe /SocketServer:on /SocketPort:5025 /visible:on
:: RVNA / TRVNA
RVNA.exe EnableSocket:5025
```
Or in the GUI: `System > Socket Server > Enable`.
### Configuration
Configure via environment variables or `.env` file:
| Variable | Default | Description |
| -------- | ------- | ----------- |
| `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 (s) |
| `VNA_COMMAND_TIMEOUT` | `30.0` | SCPI command timeout (s) |
| `VNA_MAX_POWER_DBM` | `10` | Max output power |
| `VNA_MIN_POWER_DBM` | `-55` | Min output power |
| `VNA_MAX_FREQUENCY_HZ` | `20e9` | Upper sweep bound |
| `VNA_MAX_POINTS` | `10001` | Maximum sweep points |
---
## Tools
45 MCP tools, grouped:
| Group | Tools |
| ----- | ----- |
| **Connection** | `vna_discover`, `vna_connect`, `vna_disconnect`, `vna_identify`, `vna_get_status` |
| **Configuration** | `vna_configure_sweep`, `vna_set_center_span`, `vna_set_averaging`, `vna_set_port_power`, `vna_output_on`, `vna_output_off` |
| **Measurement** | `vna_trigger_sweep`, `vna_get_s_parameter`, `vna_measure_return_loss`, `vna_measure_vswr`, `vna_measure_insertion_loss` |
| **Markers** | `vna_set_marker`, `vna_get_marker`, `vna_marker_search_min`, `vna_marker_search_max`, `vna_marker_bandwidth` |
| **Calibration** | `vna_calibration_status`, `vna_calibration_start`, `vna_calibration_measure_standard`, `vna_calibration_apply`, `vna_correction_on`, `vna_correction_off` |
| **Export** | `vna_save_touchstone`, `vna_save_screenshot` |
| **Templates** | `vna_list_templates`, `vna_load_template`, `vna_apply_template` |
| **State** | `vna_save_state`, `vna_load_state`, `vna_get_full_state` |
| **Limits** | `vna_define_limit`, `vna_check_limits`, `vna_list_limits`, `vna_clear_limits` |
| **Software** | `vna_software_show`, `vna_software_hide` |
| **Low-level SCPI** | `vna_scpi_send`, `vna_scpi_query`, `vna_reset`, `vna_preset` |
Full tool reference in [`docs/tools.md`](docs/tools.md).
---
## Calibration
Standard cal flows are exposed as discrete tools so an agent can walk them step
by step.
**SOL (1-port reflection):**
1. `vna_calibration_start(method="SOL")`
2. `vna_calibration_measure_standard(standard="SHORT", port_num=1)`
3. `vna_calibration_measure_standard(standard="OPEN", port_num=1)`
4. `vna_calibration_measure_standard(standard="LOAD", port_num=1)`
5. `vna_calibration_apply()`
6. `vna_correction_on()`
**SOLT (2-port full):** SHORT/OPEN/LOAD on both ports, then `THRU` between
them, then apply.
Calibration is frequency-specific: recalibrate when the sweep range
changes substantially.
---
## Measurement templates
Pre-configured sweep + marker + trace setups for common DUT classes. Load by
name with `vna_load_template`, then `vna_apply_template` to push to the VNA.
| Category | Examples |
| -------- | -------- |
| **Antennas: WiFi/BLE** | `antenna_wifi_24ghz`, `antenna_ble_24ghz`, `antenna_wifi_5ghz`, `antenna_wifi_5ghz_unii1/unii3`, `antenna_wifi_6ghz`, `antenna_wifi_dual_band`, `antenna_wifi_tri_band` |
| **Antennas: MIMO** | `antenna_mimo_wifi_24ghz`, `antenna_mimo_wifi_5ghz`, `antenna_mimo_wifi_dual_band`, `antenna_mimo_cellular` |
| **Antennas: ISM/cellular/GNSS** | `antenna_ism_us915`, `antenna_ism_eu868`, `antenna_ism_worldwide`, `antenna_cellular`, `antenna_gps_l1`, `antenna_gnss_dual_band`, `antenna_nfc` |
| **Antennas: UWB** | `antenna_uwb_channel_5`, `antenna_uwb_channel_9`, `antenna_uwb_full_band` |
| **Cables** | `cable_dc_2_4ghz`, `cable_dc_8_5ghz` |
| **Filters** | `filter_wifi_24ghz`, `filter_wifi_5ghz`, `filter_ism_915mhz`, `filter_gps_l1`, `filter_bandpass_custom`, `filter_lowpass_custom` |
```python
await vna.load_template("antenna_wifi_5ghz")
await vna.apply_template()
# Custom filter: provide parameters at load time
await vna.load_template("filter_bandpass_custom",
center_freq_hz=1.5e9, bandwidth_hz=100e6)
await vna.apply_template()
```
---
## Workflows
`copper-mountain-vna-mcp` fits in the following [eng-mcp-suite](https://github.com/RFingAdam/eng-mcp-suite)
workflow bundles:
- **`lab-automation`**: pair with `mcp-rs-spectrum-analyzer`, `mcp-rs-siggen`,
and `mcp-rs-cmw500` for end-to-end RF bench-test workflows driven from a
single agent session.
- **`antenna-tuning`**: feed return-loss / VSWR traces into `mcp-nec2-antenna`
or `mcp-openems` for iterative match optimization.
Install the bundle with:
```bash
eng-mcp-suite install --workflow lab-automation
```
---
## Documentation
- ๐ **[Quick Start](docs/index.md)**: install through first call.
- ๐ ๏ธ **[Tool reference](docs/tools.md)**. Every MCP tool, every argument.
- ๐ **[Usage examples](docs/usage.md)**. A practical end-to-end S11 walkthrough.
- ๐๏ธ **[Architecture](docs/architecture.md)**: how this MCP fits in eng-mcp-suite.
- ๐ **[Changelog](CHANGELOG.md)**
---
## Part of eng-mcp-suite
<sub>This MCP server is part of</sub>
[](https://github.com/RFingAdam/eng-mcp-suite)
<sub>Part of [eng-mcp-suite](https://github.com/RFingAdam/eng-mcp-suite). An open
umbrella of MCP servers for RF / EMC / PCB / signal-integrity engineering. Drop
into the `lab-automation` workflow bundle with
`eng-mcp-suite install --workflow lab-automation`.</sub>
| Domain | Sibling MCPs |
| ------------------------- | ---------------------------------------------------------------------------- |
| **RF / Transmission lines** | [lineforge](https://github.com/RFingAdam/lineforge) |
| **EMC regulatory** | [mcp-emc-regulations](https://github.com/RFingAdam/mcp-emc-regulations) |
| **EM simulation** | mcp-openems, mcp-nec2-antenna |
| **Diagrams** | [drawio-engineering-mcp](https://github.com/RFingAdam/drawio-engineering-mcp) |
| **Lab gear** | copper-mountain-vna-mcp ยท [mcp-rs-spectrum-analyzer](https://github.com/RFingAdam/mcp-rs-spectrum-analyzer) ยท [mcp-rs-siggen](https://github.com/RFingAdam/mcp-rs-siggen) ยท [mcp-rs-cmw500](https://github.com/RFingAdam/mcp-rs-cmw500) |
---
## Contributing
Contributions welcome.
1. Pick a [GitHub issue](https://github.com/RFingAdam/copper-mountain-vna-mcp/issues).
2. Fork + branch (`feature/your-thing` or `fix/your-bug`).
3. Run the local check suite:
```bash
ruff check . && mypy src/coppermountain_vna_mcp
pytest --cov=coppermountain_vna_mcp
```
4. Open a PR: link the issue, request review.
---
## License
[AGPL-3.0-or-later](LICENSE). Copyright 2025-2026 Adam Engelbrecht
(RFingAdam). Relicensed from Apache-2.0 in v0.3.0 to align with the
eng-mcp-suite toolkit-wide AGPL move.
## Brand assets
The project name and the logo files in this repository are not part of the licensed
work. The licence above grants no permission to use them, except as needed to describe
the origin of the work.
## Acknowledgments
- **Copper Mountain Technologies**: for documenting the SCPI command set used
by RVNA / TRVNA / S2VNA / S4VNA software.
- **The MCP working group**: for the [Model Context Protocol](https://modelcontextprotocol.io)
specification.
<div align="center">
<sub>Part of <a href="https://github.com/RFingAdam/eng-mcp-suite">eng-mcp-suite</a>: built for RF engineers, PCB designers, EMC labs, and AI agents.</sub>
</div>
TDQS
Scored across 49 tools
Most tools target distinct operations (e.g., measure_return_loss vs. get_s_parameter, save_touchstone vs. save_state). A few pairs like reset/preset and configure_sweep/set_center_span have overlapping scope, but descriptions clarify their specific purposes.
All tools share the vna_ prefix and use consistent snake_case. Verbs like get_, set_, measure_, save_, and load_ follow a predictable pattern, with minor exceptions (output_on, calibration_start) that are still clear and consistent.
The server exposes 49 tools, which is well beyond the typical well-scoped range. While the VNA domain is complex, many tools could be consolidated (e.g., a single measure tool with parameters), making the surface feel excessive and harder to navigate.
The tool set covers the full VNA workflow: connection, configuration, measurement, calibration, marker analysis, state/template management, limit testing, and raw SCPI access. The inclusion of scpi_send/scpi_query provides a fallback for any missing functionality.