hpe-cx-mcp
Allows the server to resolve device credentials from HashiCorp Vault for inventory management.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@hpe-cx-mcpCheck interface status and VLANs on all switches in the Boston site"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
ArubaOS-CX MCP Server (hpe-cx-mcp)
A Model Context Protocol (MCP) server that
exposes Aruba CX (AOS-CX) switches to MCP-capable AI agents (Claude, VS Code
Copilot, etc.). It turns the switch REST API (/rest/v10.x) and the SSH CLI into
a curated set of safe, structured tools for observability, troubleshooting and
configuration of a campus / data-center fabric (VLANs, routing, BGP/OSPF,
EVPN-VXLAN, VSX/VSF, port access / 802.1X, NAE, ARC…).
The server runs as a Docker container, speaks MCP over streamable HTTP, and ships with optional named Bearer-token authentication and JSON audit logging.
Quick start
cd cx-mcp
# 1) Provide credentials (git-ignored)
cp .env.example .env # then edit: set ARUBA_DEFAULT_PASSWORD (and any source tokens)
# 2) Provide the device list (git-ignored)
cp inventory/inventory.example.yaml inventory/inventory.yaml # then edit: your switches & IPs
# 3) Build and start
docker compose up -d --build
# 4) Watch it come up
docker compose logs -f hpe-cx-mcp # wait for "✅ hpe-cx-mcp server is up and running"The MCP endpoint is then available at http://<docker-host>:8002/mcp. Point
your MCP client at it (see §10). Full details and
platform notes are in §3.
Related MCP server: HPE Aruba Networking Central MCP Server
Table of contents
1. What this server does
Single entry point to a fleet of AOS-CX switches described in an inventory.
Read (observe): interfaces, VLANs, routing/ARP/MAC tables, BGP/OSPF/EVPN, VXLAN tunnels, VSX/VSF stack state, hardware health, logs, 802.1X / port-access, NAE scripts, application recognition (ARC), full configs.
Write (configure): VLAN services, VLANs/SVIs/trunks, LAGs (static, LACP, MC-LAG, EVPN multihoming), loopbacks, routed ports, VRFs, static routes, BGP, OSPF, redistribution, EVPN/VXLAN, VSX, DHCP relay, port groups, port authentication, virtual-MAC, ARC — each paired with a
verify_*read-back tool.Orchestrate: multi-step workflows (VSX pair, L3 links, access ports, RADIUS/802.1X, VXLAN overlay and VLAN services, full fabric underlay/overlay) in one plan → apply call, with a per-device checkpoint.
Safety rails:
Per-device
access_mode(read-onlyby default; writes are denied unless a device is explicitlyread-write).Site-scoped operations (
siteparameter) to act on a group of devices.SSH write-command detection to block configuration changes via raw CLI on read-only devices.
Dynamic inventory: merge the local file with NetBox / Nautobot sources of truth, with optional HashiCorp Vault credential resolution.
2. Available tools
Tools are grouped by purpose. Read tools require a device to be reachable; write
tools additionally require the device to be read-write.
Inventory & sessions
Tool | Role |
| List inventory devices (optional |
| List sites and their attached devices. |
| List configured sources and their priority ( |
| Search devices by name/site/tenant/tag/custom field across sources. |
| Resolve a device by name or management IP across all sources. |
| Reload the local file and re-pull external sources. |
| Run a read-only diagnostic on every device of a site. |
| Close pooled REST/SSH sessions (call at end of a workflow). |
Raw access (escape hatches)
Tool | Role |
| Primary CLI escape hatch: run arbitrary CLI command(s) over SSH (output not exposed by REST). |
| Fallback for |
| Try to list CLI commands supported via REST |
| Raw GET against an arbitrary REST path. |
System & hardware
get_system_info, get_hardware_health, get_boot_history, get_transceivers,
get_ssh_config, get_logs, get_poe_status (Power-over-Ethernet: per-port
draw in watts/amps/volts, powering state, powered-device class, plus the
chassis-wide PoE power budget).
Containers & licensing
get_containers (on-switch application containers: status, image, CPU/memory
limits, VRF networks), get_feature_pack (licensing / subscription state:
management mode, validity, expiration, per-feature enforcement).
Cloud management
get_aruba_central (HPE ANW Central / Aruba Central connection state: connected,
instantiation, config source, location, VRF/source IP, Activate connectivity).
L2 / L3 state
get_interfaces, get_loopbacks, get_routed_ports, get_vlan_interfaces,
get_vlans, get_lldp_neighbors, get_mac_table, get_arp_table,
get_routing_table, get_spanning_tree.
Routing protocols
get_bgp_neighbors, get_bgp_config, get_bgp_routes, get_ospf_overview,
get_ospf_neighbors, get_ospf_interfaces.
EVPN / VXLAN
get_evpn_config, get_evpn_routes, get_evpn_multihoming, get_vxlan_config,
get_vxlan_tunnels, get_vxlan_static_peers, get_evpn_vtep_neighbors.
High availability (VSX / VSF)
get_vsx_status, get_vsx_config, get_vsx_sync, get_vsf_status,
get_vsf_config, get_maintenance_mode.
NAE (Network Analytics Engine)
get_nae_scripts, get_nae_script, get_nae_agents, get_nae_agent.
Port access / AAA / 802.1X
get_port_access_clients, get_port_access_client_detail,
get_port_access_auth_config, get_port_access_summary,
get_port_access_policies, get_port_access_roles, get_port_access_gbps,
get_gbp_role_maps, get_port_access_abps, get_radius_servers,
get_tacacs_servers, get_aaa_authentication, get_aaa_accounting.
Application Recognition & Control (ARC)
get_app_recognition, get_app_visibility.
Configuration management
list_configs, get_config, get_full_config, compare_configs,
manage_config (save / checkpoint / rollback), backup_config (export
campaign to an external SFTP/TFTP server, see §5).
Configure (write) + verify pairs
Each configure_* tool has a matching verify_* read-back tool:
Configure | Verify | Scope |
| — | VLAN + optional SVI |
|
| Loopback (router-id / VTEP source) |
|
| L3 port |
|
| VTEP |
|
| Global EVPN |
|
| OSPF instance |
|
| BGP router |
|
| VRF + route-targets |
|
| 802.1X / MAC-Auth |
|
| ARC |
|
| Global EVPN virtual-MAC |
|
| VLAN(s), single or batch ( |
|
| SVI + active-gateway |
|
| Trunk port allowed / native VLANs |
|
| LAG: static, LACP, MC-LAG (VSX), EVPN multihoming (ESI) |
|
| Port admin up/down |
|
| Port-group speed ( |
|
| DHCP relay (IP helper) per interface/VRF |
|
| Hostname (single or batch) |
|
| Static routes + next-hops |
|
| BGP/OSPF redistribution |
|
| VSX pairing (asymmetric per peer) |
|
| AAA, local user roles |
Orchestrators (multi-step writes)
Each orchestrator builds one ordered step list per device, runs it inside a single auto-checkpoint and stops at the first failing step (the switch then reverts). Plan mode shows every step and, for the fabric tools, the IP allocation, without writing anything.
Orchestrator | Verify | Does |
|
| Keepalive VRF/port, ISL LAG, VSX pairing (or full teardown with |
|
| Routed P2P link(s) + optional VRF/OSPF; batch with |
|
| L2 access port(s) + STP guards + 802.1X. |
|
| RADIUS servers/group + global AAA + per-port 802.1X. |
|
| Device-level VTEP: VXLAN interface, global EVPN, virtual-MAC, optional BGP-EVPN ( |
|
| Batch of VLAN → L2VNI → EVPN RT and/or static peers ( |
|
| Legacy single-service variants (prefer |
| — | Whole fabric underlay: loopback0/1 and /31 P2P addressing from pools, OSPF P2P, cabling from LLDP or explicit. |
| — | Whole iBGP-EVPN control plane (spines as route reflectors), VXLAN interface and virtual-MAC on every leaf. |
Per-device values (ip_address, source_ip, virtual_mac, router_id) accept
a {device: value} mapping or loopback0/auto. A shared literal is refused
unless the devices sharing it are one VSX pair. VSF secondary members are refused
as targets (address the conductor instead).
Write protection: a
configure_*/create_*/delete_*/manage_configcall on aread-onlydevice is refused. Mark the deviceaccess_mode: read-writein the inventory to allow changes.
Tool exposure: flat toolset (default) vs legacy atomic tools
The server can expose its capabilities in two mutually exclusive ways, chosen
by the CX_FLAT_TOOLSET flag (see §5):
Flat toolset (CX_FLAT_TOOLSET=true — the default). The atomic tools
listed above are collapsed into 19 flat dispatchers (plus the 10 kept-atomic
tools below — 29 tools advertised in total) driven by a scope (and, for
writes, an action) argument. The underlying REST client code is
unchanged — the dispatchers only route to it, so there is no behavioural
regression. Every read dispatcher also accepts device: str | list, site
or source (an external source-of-truth query) and fans the call out in
parallel, returning one envelope {scope, results, errors, summary}. An optional
limit caps long list fields in the response.
Dispatcher |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| omit |
Plus 10 kept-atomic tools: list_devices, list_sites, get_logs,
run_ssh_commands, manage_config, backup_config, logout, rollback,
orchestrate_fabric_underlay, orchestrate_fabric_overlay (these two take
spines/leafs lists instead of a single device). Write dispatchers keep
the plan → apply → verify lifecycle and the per-device read-only guard. Domain
fields are passed in a params object (keys documented in each dispatcher's
docstring).
Legacy atomic tools (CX_FLAT_TOOLSET=false). The full per-tool catalog above
is exposed instead, optionally shaped by the three layers below. Use this for an
instant rollback to the previous behaviour.
Progressive disclosure, functional prefixes & write safety (legacy mode only)
Three optional layers (active only when CX_FLAT_TOOLSET=false, each gated
by its own env flag — see §5) shape how the legacy
tools are exposed:
1. Progressive disclosure (CX_DEFERRED_TOOLS) — instead of advertising the
full catalog (100+ tools), the server publishes only ~27 Tier-1 tools (the
most-used read/diagnostic tools, the escape hatches, the orchestrators and the
meta-tools). Every other tool is deferred (Tier-2) and reached on demand via
two meta-tools:
Meta-tool | Role |
| Discover deferred tools by keyword. Returns each match's name, description, tags, |
| Execute a deferred tool by name with an |
This keeps the agent's tool list small and cheap while leaving the entire surface reachable.
2. Functional prefixes (CX_TOOL_PREFIXES) — advertised tools are renamed
<domain>__<tool> to group them by domain, e.g. routing__get_bgp_neighbors,
overlay__configure_evpn, service__create_vlan_service, meta__invoke_tool.
Domains: inventory, exec, system, interface, switching, routing,
overlay, redundancy, security, app, nae, config, service, meta.
invoke_tool accepts either the prefixed or the bare name.
3. Write safety (CX_WRITE_SAFETY) — a preview→apply workflow with rollback:
Meta-tool | Role |
| Apply a previewed write by its |
| Undo a reversible applied write by its |
Workflow: call any write tool with apply=false (the default) to get a plan and
a dry_run_token; then call apply_plan(dry_run_token=…) to apply that exact plan.
Idempotent configure_* merges have no automatic inverse and are reported as
unsupported by rollback. When CX_REQUIRE_DRY_RUN_TOKEN=true (the shipped
default), a direct apply is refused on every write path:
Flat toolset (
configure_interface/configure_routing/configure_security/configure_service):action=planreturns adry_run_token;action=apply(ordelete) must passdry_run_token=…with the sameparams. The plan is re-computed and hash-compared before the write (TOCTOU guard), the token is single-use, and arollback_idis attached when the plan is reversible.Legacy layer:
apply=truethroughinvoke_toolis refused — use the preview→apply_planpath.
3. Installation (macOS / Linux / Windows)
Prerequisites
Docker and Docker Compose v2 (
docker compose …).macOS / Windows: Docker Desktop.
Linux: Docker Engine + the Compose plugin.
Network reachability from the Docker host to the switches' management IPs (HTTPS/443 for REST, TCP/22 for SSH).
REST access must be configured on the target devices and in the correct VRF: in Read-Write mode for Read and Write access, and Read-only mode for read-only access.
SSH access must also be configured on the target devices for the tools that require it.
Configure (first run)
Secrets and deployment-specific settings live outside docker-compose.yml,
in files that are git-ignored so they are never committed. Two templates are
shipped — copy each one and fill it in:
cd cx-mcp
# 1) Credentials & external source tokens → .env (git-ignored)
cp .env.example .env
# then edit .env and set at least ARUBA_DEFAULT_PASSWORD
# 2) Device inventory → inventory/inventory.yaml (git-ignored)
cp inventory/inventory.example.yaml inventory/inventory.yaml
# then edit it: list your switches, their IPs and per-device access_mode.env is injected into the container via env_file: in docker-compose.yml.
Minimum content (see .env.example for the full list):
ARUBA_DEFAULT_USERNAME=admin
ARUBA_DEFAULT_PASSWORD=your-switch-password
ARUBA_API_VERSION=latest
# Optional external sources of truth (leave empty if unused):
NETBOX_URL=
NETBOX_TOKEN=
INFRAHUB_URL=
INFRAHUB_TOKEN=Never commit
.envorinventory/inventory.yaml— they hold real credentials and device IPs. Only the*.exampletemplates are tracked by git.
Build & start (all platforms)
cd cx-mcp
docker compose up -d --buildThe server listens on http://<host>:8002/mcp (host port 8002 → container
8000, see docker-compose.yml). The image is built as hpe-cx-mcp:latest and
runs as the container hpe-cx-mcp.
Check it is running:
docker compose logs -f hpe-cx-mcp
# look for, in order:
# "Uvicorn running on http://0.0.0.0:8000"
# "✅ hpe-cx-mcp server is up and running on http://0.0.0.0:8000 — if your agent
# already has an open MCP connection, reset it (MCP: Disconnect → Connect) …"The ✅ … server is up and running line is emitted once the listener is ready.
If startup fails instead, the server logs ❌ hpe-cx-mcp server failed to start
followed by the full traceback (then exits non-zero).
Note: every
docker compose up -d --buildrebuilds the image and restarts the server, which invalidates any existing MCP session. After a rebuild, reconnect your client (MCP: Disconnect → Connect) to pick up the current tools.
Platform notes
Linux
Bind-mounted folders are owned by your host user. The container runs as uid 1000; if your host user is not uid 1000, make the writable folders readable/writable by uid 1000:
mkdir -p logs secrets sudo chown -R 1000:1000 logs secrets chmod 700 secretsTo reach switches on the host's local L2 network you may uncomment
network_mode: hostindocker-compose.yml(Linux only).
macOS (Docker Desktop)
File sharing is handled by the VM; bind mounts work out of the box and uid remapping is automatic — no manual
chownneeded in most cases.network_mode: hostis not supported the same way as on Linux; keep the defaultports:mapping (8002:8000).
Windows (Docker Desktop + WSL2)
Run the commands from a WSL2 shell or PowerShell. Storing the project inside the WSL2 filesystem (e.g.
\\wsl$\…/~/cx-mcp) is strongly recommended for correct file permissions and performance.Use forward slashes in
docker-compose.ymlvolume paths (./inventory:/app/inventory:ro).network_mode: hostis not available; keep theports:mapping.
4. Volumes
Three host folders are mounted into the container:
Host path | Container path | Mode | Purpose |
|
| read-only ( | Device inventory ( |
|
| read-write | Audit log output ( |
|
| read-write | Named Bearer tokens ( |
volumes:
- ./inventory:/app/inventory:ro
- ./logs:/app/logs
- ./secrets:/app/secretsThe application code is baked into the image — only these data folders are mounted. After changing any
*.py, rebuild withdocker compose up -d --build(a plain restart is not enough).
Ownership (Linux): logs/ and secrets/ must be writable by container uid
1000. secrets/ should be 0700 and its .tokens file is written 0600 by the
server itself.
5. Environment variables
Secrets and deployment-specific values (credentials, external-source tokens) are
provided through the git-ignored .env file, which docker-compose.yml
loads via env_file: (copy .env.example to .env, see
§3). Non-secret operational flags
(MCP_*, CX_*, INVENTORY_FILE) are set directly in docker-compose.yml
under environment:. Booleans accept true/1/yes/on.
Transport
Variable | Default | Description |
|
| MCP transport. |
|
| Bind address inside the container. |
|
| Bind port inside the container (mapped to host |
|
| URL path guarded by the security middleware. |
Device credentials & API (set in .env; overridable per device in the inventory)
Variable | Default | Description |
|
| Default REST/SSH username. |
| (empty) | Default password. Required unless set per device. |
|
| Default REST API version ( |
|
| Default SSH port. |
Inventory & external sources
Variable | Default | Description |
|
| Path to the inventory file (YAML/JSON/TOML). |
| — | NetBox source connection (set in |
| — | Nautobot source connection (set in |
| — | Infrahub source connection (GraphQL API; set in |
| — | Generic per-named-source connection. |
| — | HashiCorp Vault for credential resolution. |
SFTP/TFTP configuration backups
Variable | Default | Description |
| — | Approved SFTP backup server. A |
| — | SFTP credentials; set in |
|
| SFTP port. |
|
| Default absolute directory on the SFTP server. |
| — | Optional comma-separated target allow-list. |
|
| Connection and transfer timeout in seconds. |
| — | Approved TFTP backup server. A |
|
| TFTP port. |
|
| Default relative directory prefix on the TFTP server. |
| — | Optional comma-separated target allow-list. |
|
| Transfer timeout in seconds. |
Use backup_config to run an export campaign for a device or an entire
site. protocol="sftp" is the default; protocol="tftp" is available for
legacy backup servers but has neither encryption nor authentication, so use it
only on a trusted management network. It transfers running-config by default (or startup-config) and
returns the remote path and byte count per device, never the configuration
content. The default filename is {hostname}_{timestamp}_config.cfg; pass
filename_format to change it. Only {hostname} and UTC {timestamp}
(YYYYMMDDTHHMMSSZ) are permitted.
TLS verification towards the switches
Variable | Default | Description |
|
| Default |
|
| PEM chain of the internal CA that signed the switch certificates (mount |
Bearer authentication (ON in the shipped compose)
Variable | Default | Description |
|
| Require a valid Bearer token on every request. If enabled with no token yet, the server starts in LOCKED mode and refuses every MCP request with HTTP 503 until you create the first token and hot-reload ( |
|
| Token store path. |
|
| Trust |
Audit logging (ON in the shipped compose, writes)
Variable | Default | Description |
|
| Emit a JSON record per tool call. |
|
| Output file (rotating, 10 MB × 5) on the |
|
|
|
|
| Also mirror records to stdout so the Docker logging driver can ship them (Loki/SIEM). |
Progressive disclosure, prefixes & write safety (optional)
Variable | Default | Description |
|
| Collapse the atomic tools into 19 flat |
|
| (Legacy mode only) Advertise only Tier-1 tools; reach the rest via |
|
| (Legacy mode only) Rename advertised tools |
|
| Allow write tools to run through |
|
| Enable the |
|
| Refuse any apply without a valid |
|
| Lifetime (seconds) of a |
|
| A token is bound to (operation, plan hash, TTL), not to a caller. |
|
| Directory for the write-safety stores ( |
Apply-time safety rails
Variable | Default | Description |
|
| Wrap every |
|
| Auto-checkpoint timer (1-60). |
| (empty) | Comma-separated fnmatch globs on the URL-decoded REST path; matching resources refuse PUT/DELETE unless the call passes |
| from | Build/runtime version reported by |
6. Inventory management
The inventory file (inventory/inventory.yaml) declares the devices and how to reach them. It is git-ignored (it holds real IPs and credentials); create it once from the shipped template:
cp inventory/inventory.example.yaml inventory/inventory.yamlValues in the file override environment variables. Supported formats: YAML, JSON, TOML.
Minimal example
defaults:
username: admin
password: "secret"
api_version: latest # auto-detect the newest REST version
verify_ssl: false # lab only (self-signed certs); default is true
timeout: 30
access_mode: read-only # writes denied unless overridden per device
devices:
Spine1:
host: 192.0.2.21
description: "Core switch"
tags: [core, spine]
site: campus-principal
access_mode: read-write # allow configuration changes on this device
Access-01:
host: 192.0.2.23
site: campus-principalPer-device options
host (required), username, password, api_version, verify_ssl, timeout,
tags, description, site, ssh_port, ssh_username, ssh_password,
access_mode (read-only | read-write), vault (true to fetch credentials
from Vault).
Sites
The site concept is optional and lets tools target a group of devices
(list_devices(site=…), run_on_site(site, …)). Use either a per-device site:
field or a top-level sites: block grouping devices.
Inventory source options
There are several ways to decide where the device list comes from:
Local only (default) — devices from the file:
source: local # may be omittedSingle external source — pull from a source of truth:
source: netbox sources: netbox: type: netbox # netbox | nautobot | infrahub url: https://netbox.example.com token: "<api-token>" # or via NETBOX_TOKEN env var verify_ssl: falseMerged sources with priority — a device present in several sources is taken from the higher-priority one:
source: [local, netbox] source_priority: [local, netbox] # local wins over netbox
Credential resolution priority (highest first):
Device-specific credentials set on the device entry.
HashiCorp Vault (when
vaultis enabled globally or per device).Environment variables / inventory defaults.
After editing the inventory, apply changes without rebuilding via the
refresh_inventory tool, or restart the container.
Startup validation (fail-fast)
The inventory file is validated at startup. If it cannot be parsed (YAML/JSON/
TOML syntax error) or violates the expected schema (e.g. a mis-indented source:
key, or source set to a non-string/list value), the server logs a specific
English error and refuses to start rather than silently running with an empty
or partial inventory:
❌ Inventory file '/app/inventory/inventory.yaml' failed validation — the server will NOT start.
YAML syntax error: expected '<document start>', but found '<block mapping start>'
in "<unicode string>", line 22, column 1
Fix the inventory file, then restart the container.The container exits with a non-zero status code (visible in docker logs /
docker compose ps). Fix the reported line and restart. Notes:
A missing inventory file is only a warning (it can be mounted later) — the server still starts.
External source reachability (NetBox / Nautobot / Infrahub being down) is not fatal: the parsed local inventory remains usable and the dynamic merge degrades gracefully.
The runtime
refresh_inventorytool applies the same validation but never crashes a running server: on a bad file it returns an error and keeps the previously loaded inventory.
7. Security: Bearer auth & audit logging
Both features are disabled by default and fully backward compatible.
Authentication (
CX_AUTH_ENABLED=true): every request to/mcpmust carryAuthorization: Bearer <token>. Missing/invalid tokens get HTTP 401. The token's name becomes theactorrecorded in the audit log, so you always know who did what. If auth is enabled but no token exists yet, the server still starts but in LOCKED mode: every MCP request is refused with HTTP 503 (fail-closed) so the services are unreachable. Create the first token (see §8) and restart the container to unlock — the token store is loaded once at startup.Audit (
CX_AUDIT_ENABLED=true): one JSON line per tool call inlogs/audit.jsonl, includingactor,src_ip,tool,category(read/write), targeteddevice, redactedarguments,outcome, HTTPstatus_codeandduration_ms. Secrets (passwords/tokens) are masked.
Enable both:
# docker-compose.yml
CX_AUTH_ENABLED: "true"
CX_AUDIT_ENABLED: "true"docker compose up -d --build8. Token management
Tokens are stored in secrets/.tokens (perms 0600). Manage them inside the
running container with the bundled CLI:
# Create a named token (prints the secret once — save it)
docker compose exec hpe-cx-mcp python security/cx_token_manager.py generate --name vscode-dev
# List tokens (names, descriptions, created — secret truncated)
docker compose exec hpe-cx-mcp python security/cx_token_manager.py list
# Show one token
docker compose exec hpe-cx-mcp python security/cx_token_manager.py show --name vscode-dev
# Revoke a token
docker compose exec hpe-cx-mcp python security/cx_token_manager.py revoke --name vscode-devGenerated tokens are prefixed cx_. Use one distinct token per client/agent to
get per-actor attribution in the audit log.
First token: when authentication is enabled, the server starts LOCKED (HTTP 503 on every request) until a token exists. After creating the first token, apply it without a restart by hot-reloading (see below):
docker compose exec hpe-cx-mcp python security/cx_reload.py(a
docker compose restart hpe-cx-mcpalso works).
Hot reload (no rebuild / no restart)
Token and inventory files are loaded into memory at startup. After editing
secrets/.tokens (via the CLI above) or inventory/inventory.yaml, apply the
changes to the running server by sending it a reload signal:
docker compose exec hpe-cx-mcp python security/cx_reload.pyThis reloads both the tokens and the inventory in place — adding/revoking a token, or adding/updating a device, takes effect on the next request. The command only sends the signal; the outcome (counts, errors) is written to the logs:
docker compose logs --tail=20 hpe-cx-mcpReloading is manual and explicit — there is no automatic file watching.
If clients connect through a shared relay, all calls appear under the relay's single token; for per-agent attribution, connect directly to
hpe-cx-mcpwith distinct tokens.
9. Operations runbook
Day-2 procedures for a production deployment. Every command runs from the
cx-mcp/ directory on the Docker host.
9.1 Health & version
curl -s http://localhost:8002/healthz | jq # 200 ok/degraded, 503 unavailable
docker inspect --format '{{.State.Health.Status}}' hpe-cx-mcp
docker inspect --format '{{index .Config.Labels "org.opencontainers.image.version"}}' hpe-cx-mcp/healthz needs no token and never returns secrets. problems[] names the
cause (locked, inventory: 0 devices, inventory reload failed). It is what
the Docker HEALTHCHECK and any load balancer should probe.
9.2 Upgrade / rollback of the server
# upgrade: bump ./VERSION, add a CHANGELOG entry, then
export CX_VERSION=$(cat VERSION) && docker compose up -d --build
# rollback: re-run with the previous, still-present image tag
CX_VERSION=1.0.0 docker compose up -d --no-buildImages are tagged hpe-cx-mcp:<version> (never latest). After any rebuild,
MCP clients must reconnect (tool schemas are cached client-side).
9.3 Token lifecycle (one token per client)
docker compose exec hpe-cx-mcp python security/cx_token_manager.py generate --name <client>
docker compose exec hpe-cx-mcp python security/cx_token_manager.py list
docker compose exec hpe-cx-mcp python security/cx_token_manager.py revoke --name <client>
docker compose exec hpe-cx-mcp python security/cx_reload.py # apply without restartRotate: generate the new token, hand it over, revoke the old one, reload.
If /healthz reports locked, no token exists: generate one and reload.
9.4 Inventory change
Edit inventory/inventory.yaml, then python security/cx_reload.py (as above).
A syntax/schema error keeps the previous inventory in memory and is
reported in /healthz → inventory.last_error and the logs. Fix and reload.
9.5 Applying a change safely (what the agent goes through)
configure_*(action='plan', …)→ plan +dry_run_token(TTLCX_DRY_RUN_TTL).configure_*(action='apply', dry_run_token=…, same params)→ the plan is recomputed and hash-compared; the write runs inside a firmware auto-checkpoint; on success the checkpoint is confirmed and arollback_idis returned.Protected objects (
CX_PROTECTED_OBJECTS) are refused unlessforce=true.
If an apply fails mid-way the response says auto-checkpoint left ARMED: the
switch reverts by itself after CX_AUTO_CHECKPOINT_MINUTES. To keep the partial
state instead, call manage_config(device, action='confirm') before the
deadline. The safety net is on by default; disable it globally with
CX_AUTO_CHECKPOINT=false, or for one call with auto_checkpoint=false
(the per-device result then reports checkpoint: disabled).
9.6 Undoing a change
rollback(rollback_id='rb_…') # objects CREATED by the apply
manage_config(device, action='list_checkpoints') # otherwise: firmware checkpoints
manage_config(device, action='restore_checkpoint', name='<checkpoint>')rollback only removes objects the apply created (VLAN-service steps,
loopbacks, VRFs, L3 VNIs). Updates of pre-existing objects are listed as
unsupported — restore a checkpoint (or startup-config) for those.
9.7 Reading the audit trail
tail -f logs/audit.jsonl | jq '{ts,actor,src_ip,tool,category,outcome,duration_ms}'
jq -c 'select(.category=="write" and .outcome!="completed")' logs/audit.jsonl
docker compose logs -f hpe-cx-mcp | grep '"tool"' # same records on stdoutOne JSON line per call (CX_AUDIT_LEVEL=writes → writes only); actor is the
token name, arguments are redacted. Files rotate 10 MB × 5 under ./logs.
9.8 Incident checklist
Symptom | Check | Action |
Clients get 401 |
| Token revoked/typo → issue a new one (§9.3). |
Clients get 503 |
|
|
Tool returns | — | Expected: run |
|
| Intentional guard; re-run with |
| pending checkpoint on the switch |
|
Stale MCP session / 404 after rebuild | container logs | Disconnect → Connect the MCP server in the client. |
Switch unreachable / TLS error |
| Mount the CA chain in |
10. Connecting an MCP client
Point your MCP client at the streamable-HTTP endpoint:
URL: http://<docker-host>:8002/mcpWhen authentication is enabled, add the header:
Authorization: Bearer cx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxExample (VS Code mcp.json style):
{
"servers": {
"hpe-cx-mcp": {
"type": "http",
"url": "http://localhost:8002/mcp",
"headers": { "Authorization": "Bearer cx_xxxxxxxxxxxxxxxxxxxx" }
}
}
}11. Prompts (guided operations) & skills
Prompts
Beyond individual tools, the server exposes MCP prompts (tools/prompts.py)
— reusable, multi-step operation guides an agent can follow end-to-end instead
of being told which tool to call at each step. Each prompt returns a short plan
referencing the tools/dispatchers above; the agent still asks for confirmation
before any apply-mode write.
Data Center
Prompt | Purpose |
| Site-wide fabric health: system/interfaces/vlans/logs, VXLAN tunnels, EVPN routes, VSX sync, underlay BGP. |
| Guided plan → apply → verify walkthrough of |
| Cross-check both VSX peers for role/sync/keepalive consistency. |
| Hardware scale-limit utilization, feature-pack licensing state, container review. |
Campus
Prompt | Purpose |
| Guided 802.1X/MAC-Auth rollout: RADIUS/TACACS+ reachability check, then plan → apply → verify. |
| PoE power budget audit (per-port draw + chassis-wide budget). |
| Site-wide LLDP-based topology mapping and cabling/loop anomaly detection. |
| Review guest/BYOD role, GBP/ABP and policy bindings for over-broad access. |
Cross-domain (DC + Campus)
Prompt | Purpose |
| Full health check of a single switch (system, interfaces, VLANs, logs). |
| Diagnose BGP + OSPF (neighbor state, route table). |
| Troubleshoot a client that can't authenticate (802.1X/MAC-Auth). |
| Check EVPN/VXLAN overlay health on one switch. |
| Locate a MAC/client (MAC table, ARP, LLDP, port-access). |
| Configuration + AAA audit against best practices. |
| Audit against the official AOS-CX 10.17 Hardening Guide (see the matching skill below). |
| Checkpoint → change → diff → restore-if-needed safety workflow. |
| Site-wide STP state cross-referenced with LLDP to spot loops/instability. |
Skills
skills/ holds installable SKILL.md domain-knowledge packages (playbooks,
gotchas, thresholds) that complement the prompts above:
Skill | Covers |
| Full control-domain checklist from the official AOS-CX 10.17 Hardening Guide (mgmt access, AAA, SSH, SNMP, NTP, PKI, CoPP, L2 hardening, routing-protocol security, multicast, NAE scripts). |
| EVPN/VXLAN tunnel-down triage, VSX split-brain/config-sync diagnosis. |
| 802.1X/MAC-Auth rollout checklist and client-authentication troubleshooting. |
| Checkpoint/diff/restore workflow, PUT-replaces-wholesale gotcha, auto-checkpoint safety net. |
| Capacity/feature-pack/PoE-budget thresholds and what counts as a real gap. |
| Efficient |
| Safety-gated migration of a legacy network (VSX core, LAGs, VLANs, static routes) to a VXLAN-EVPN fabric (OSPF underlay, BGP-EVPN with spine RRs) using the orchestrators. |
Each skill is a self-contained SKILL.md (YAML frontmatter name+description
plus a Markdown body) — install/copy it into your assistant's skills directory
to load the domain knowledge alongside this MCP server's tools.
This server cannot be deployed
Maintenance
Related MCP Connectors
Protocol-native energy infrastructure orchestration for AI data centers. Provides 46 MCP tools across 8 grid protocols (IEC-61850, DNP3, Modbus, OCPP, OpenADR, IEEE 2030.5, IEC 60870-5-104, ICCP) with 5 core API primitives: connect, dispatch, settle, comply, and intel. Enables AI agents to programmatically interact with substations, grid interfaces, and energy assets for real-time workload-grid coordination.
Compliance frameworks (SOC 2, ISO 27001, CMMC, NIST, more) delivered to AI agents as MCP tools.
Secure and manage MCP servers through the Speakeasy AI Control Plane from your agent.
- gatewayOAuthai.sealgate
MCP gateway with runtime security policy, tool-call-level control, and audit of agent actions.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceProvides AI assistants with direct access to multi-vendor network devices for tasks like configuration management, health checks, and topology discovery through 35 specialized tools. It enables natural language control over platforms including Cisco, Juniper, and Nokia using SSH, NETCONF, and SNMP protocols.12MIT
- FlicenseNot gradedqualityDmaintenanceProduction-grade MCP server that exposes the complete HPE Aruba Networking Central REST API as 90 tools across 19 categories, enabling AI assistants to manage Aruba Central networks.-
- AlicenseBqualityCmaintenanceEnables AI applications to interact with Zyxel switches via CLI for network configuration, monitoring, and management, supporting SSH/Telnet sessions and MCP-compliant tools, resources, and prompts.19MIT
- FlicenseNot gradedqualityBmaintenanceEnables AI agents to safely troubleshoot networks through read-only tools for device inventory, interface status, VLAN paths, BGP neighbors, route lookups, and interface error detection. Integrates with Microsoft Copilot Studio and Teams for natural-language-driven network diagnostics.-