The reason to reach for this over raw pyATS is the guardrail layer: show commands are validated, config changes are screened for `reload`, `erase`, `delete` and `format`, dynamic scripts run in a restricted sandbox, and Genie Clean can never run a stage that reboots or reimages a device. The learn-diff pair is the workflow that pays off — snapshot a feature, apply a change, snapshot again, and read exactly what moved. It drives a real testbed, so the prerequisite is a working `testbed.yaml`, not a simulator.
An MCP server that wraps Cisco pyATS and Genie as structured, guarded tools an agent can call against a live network testbed over Streamable HTTP. pyATS already knows how to parse show output, push config, learn feature state and run declarative tests; this exposes those capabilities to a model, with dangerous paths blocked before they reach a device and every call written to an in-memory audit log.
- Devices listed and fuzzy-searched from the testbed — `pyats_list_devices`, `pyats_search_devices`
- Show commands run and parsed into JSON, one device or many at once, with a process-per-device option for real isolation — `pyats_run_show_command`, `pyats_run_show_command_multi`, `pyats_pcall_show_command`
- Configuration applied with guardrails, applied with a before/after diff, or rolled back to the last snapshot — `pyats_configure_device`, `pyats_configure_with_diff`, `pyats_rollback_config`
- Feature state learned with Genie and two snapshots diffed, to see what a change moved — `pyats_learn_feature`, `pyats_diff_learned_snapshots`
- Declarative tests run — Blitz YAML, Robot Framework, or a sandboxed AEtest script — `pyats_run_blitz`, `pyats_run_robot`, `pyats_run_dynamic_test`
- Generic REST/RESTCONF calls and Cisco XPresso requests — `pyats_rest_request`, `pyats_xpresso_request`
- The in-memory operation log the agent can review mid-session — `pyats_get_operation_log`
Python 3.10+, and a pyATS `testbed.yaml` pointed at real or virtual devices Unicon can reach over SSH/Telnet — the server drives a network, it does not simulate one. Install is a clone plus `pip install -r requirements.txt`; run `python3 pyats_mcp_server.py`, which starts a Streamable HTTP server on `0.0.0.0:8080` by default, reachable at `http://<host>:<port>/mcp`. All device details and credentials live in `.env` and are pulled into the testbed via `%ENV{}` substitution — nothing is hard-coded. `PYATS_TESTBED_PATH` points at the testbed; `PYATS_MCP_TRANSPORT_MODE` chooses `stateful` or `stateless`. The pyproject names the package `pyats-mcp` at 0.1.0. Clients connect over HTTP — Claude Desktop, which is stdio-only, needs an `mcp-remote` bridge.
