Unofficial / community project. This repository is an independent, community-driven project. It is not affiliated with, endorsed by, sponsored by, or supported by Hewlett Packard Enterprise, Aruba Networks, or Juniper Networks. "HPE", "Aruba", "Aruba Central", "Aruba ClearPass", "HPE GreenLake", "Juniper", and "Juniper Mist" are trademarks of their respective owners and are used here only to describe what this software interoperates with. Please direct support and licensing questions about those products to the respective vendors.
A unified Model Context Protocol (MCP) server that brings Juniper Mist, Aruba Central, HPE GreenLake, Aruba ClearPass, Juniper Apstra, Axis Atmos Cloud, Aruba OS 8, HPE UXI, and Aruba EdgeConnect together into a single, deployable service. One container. One endpoint. All your HPE networking tools.
Managing HPE networking infrastructure with AI assistants today means juggling multiple separate MCP servers — each with its own setup, credentials, and quirks. This project consolidates them into one:
| Category | Mist | Central | GreenLake | ClearPass | Apstra | Axis | AOS8 | UXI | EdgeConnect |
|---|---|---|---|---|---|---|---|---|---|
| Site Health & Performance Metrics | ✅ | ✅ | — | — | — | — | ✅ | ✅ | ✅ |
| WLANs / SSIDs | ✅ | ✅ | — | — | — | — | ✅ | — | — |
| Device Inventory | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Device Details (AP/Switch/GW) | ✅ | ✅ | — | — | — | — | ✅ | — | — |
| Device Stats & Utilization | ✅ | ✅ | — | — | — | ✅ | ✅ | ✅ | ✅ |
| Client Connectivity | ✅ | ✅ | — | — | — | — | ✅ | — | — |
| Events | ✅ | ✅ | — | ✅ | — | — | ✅ | — | — |
| Alerts / Alarms | ✅ | ✅ | — | ✅ | ✅ | — | ✅ | — | ✅ |
| Audit Logs | ✅ | ✅ | ✅ | ✅ | — | — | ✅ | — | ✅ |
| Application Visibility | ✅ | ✅ | — | — | — | ✅ | — | — | ✅ |
| Troubleshooting (Ping/Traceroute/Bounce) | ✅ | ✅ | — | — | — | — | ✅ | — | — |
| Session Control / Client Disconnect | ✅ | ✅ | — | ✅ | — | — | ✅ | — | — |
| Configuration Management | ✅ | ✅ | — | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Configuration Write (CRUD) | ✅ | ✅ | — | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Radio Resource Management | ✅ | — | — | — | — | — | ✅ | — | — |
| Rogue AP Detection | ✅ | ✅ | — | — | — | — | ✅ | — | — |
| Firmware Management | ✅ | ✅ | — | — | — | — | ✅ | — | ✅ |
| Subscriptions / Licensing | ✅ | — | ✅ | ✅ | — | — | ✅ | — | ✅ |
| User Management | ✅ | ✅ | ✅ | ✅ | — | ✅ | — | — | ✅ |
| Workspaces | — | — | ✅ | — | — | — | — | — | — |
| Scope & Configuration Hierarchy | ✅ | ✅ | — | — | — | ✅ | ✅ | — | — |
| Guest Management | ✅ | ✅ | — | ✅ | — | — | — | — | — |
| NAC / Policy Management | ✅ | ✅ | — | ✅ | — | — | — | — | — |
| Endpoint Profiling | ✅ | ✅ | — | ✅ | — | — | — | — | — |
| Certificates | ✅ | ✅ | — | ✅ | — | — | — | — | — |
| Webhooks | ✅ | ✅ | — | — | — | — | — | — | — |
| Reports / Scheduled Reports | ✅ | ✅ | — | ✅ | — | — | — | — | ✅ |
| Floor Plans / Sitemaps | ✅ | ✅ | — | — | — | — | — | — | — |
| BLE Asset Tracking / IoT Beacons | ✅ | ✅ | — | — | — | — | — | — | — |
| Marvis / AI Assistant | ✅ | — | — | — | — | — | — | — | — |
| Datacenter Blueprints / Templates | — | — | — | — | ✅ | — | — | — | — |
| Virtual Networks / EVPN / Routing Zones | — | — | — | — | ✅ | — | — | — | — |
| Connectivity Templates / Policy Apply | — | — | — | — | ✅ | — | — | — | — |
| Fabric Deploy / Diff Status | — | — | — | — | ✅ | — | — | — | — |
| BGP / Protocol Session Monitoring | — | — | — | — | ✅ | — | — | — | — |
| SASE Cloud Connectors / Tunnels | — | — | — | — | — | ✅ | — | — | — |
| URL / Web Category Filtering | — | — | — | — | — | ✅ | — | — | — |
| SSL Inspection Exclusions | — | — | — | — | — | ✅ | — | — | — |
| Staged Writes + Commit Workflow | — | — | — | — | ✅ | ✅ | — | — | — |
| Guided Prompts | ✅ | ✅ | — | — | — | — | ✅ | — | — |
| Dynamic Tool Discovery | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Underlying tools | 1050 + 2 prompts | 669 + 12 prompts | 10 | 142 | 19 | 25 | 48 + 9 prompts | 21 | 1216 |
| Exposed meta-tools (dynamic mode) | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 |
| Cross-Platform | 3 tools + 3 prompts | 3 tools + 3 prompts | — | 1 tool | — | — | — | — | — |
Default tool surface (v3.0.0.0+): ships with
MCP_TOOL_MODE=codeby default. Code mode exposes onlyexecute+ 5 discovery tools (tags,search,get_schema,skills_list,skills_load); all 4109 underlying tools are reachable viaawait call_tool(name, params)inside a sandboxed Pythonexecute()block. Smallest initial token cost (~minimal context); best for orchestrators driving small / local LLMs. SetMCP_TOOL_MODE=dynamicto use the v2.x default behavior — each platform exposes 3 meta-tools (<platform>_list_tools,<platform>_get_tool_schema,<platform>_invoke_tool) plus the 4 cross-platform static tools and 2 skills tools (24 total surface, ~3,700 tokens). Thestaticmode was REMOVED in v3.0.0.0. Every tool's response is wrapped in a uniform envelope{ok, status, data, message, tool, platform}. v2.3.0.0 introduces Skills — markdown-defined multi-step procedures discoverable viaskills_list/skills_load; see docs/TOOLS.md#skills. v2.4.0.0 adds AOS8 (48 tools + 9 prompts) — see INSTRUCTIONS.md for AOS8-specific operator guidance. v3.2.0.0 adds HPE UXI (21 tools). See docs/MIGRATING_TO_V2.md.
The Central module includes 12 guided prompts — multi-step workflow templates that walk the AI through common network operations tasks using the available tools. These prompts orchestrate multiple tool calls in the correct order, so you can simply invoke the prompt and let the AI handle the rest.
- Network Health Overview — Assess the health of all sites across your network, flagging those with poor scores or high alert counts for deeper investigation.
- Troubleshoot Site — Deep-dive into a specific site: check health metrics, review active alerts by severity, list all devices, and recommend next steps.
- Client Connectivity Check — Investigate a client by MAC address: find the client, check the connected device's health, review site-level alerts, and identify the likely root cause.
- Investigate Device Events — Pull recent events for a specific device to build a timeline of what happened, highlight recurring issues, and suggest follow-up actions.
- Site Event Summary — Summarize all events at a site over a time window, grouped by category and type, to spot patterns and anomalies.
- Failed Clients Investigation — Find all failed client connections at a site, check the health of the devices they were connected to, and identify common failure patterns.
- Site Client Overview — Get a breakdown of all clients at a site by connection type, status, VLAN, and WLAN to understand the connectivity landscape.
- Device Type Health — Check the health of all devices of a specific type (AP, switch, or gateway) at a site, including alerts and recent event activity.
- Critical Alerts Review — Review all active critical alerts across the entire network, grouped by site and category, with recommended immediate actions.
- Compare Site Health — Side-by-side comparison of health scores, device counts, client counts, and alert breakdowns across multiple sites.
- Scope Configuration Overview — View committed configuration resources at a scope level, grouped by persona and category.
- Scope Effective Config — View effective (inherited + committed) configuration at a scope, showing what each level contributes.
The AOS8 module includes 9 guided prompts for common Mobility Conductor operator workflows. See INSTRUCTIONS.md for the complete parameter reference and workflow descriptions.
- Triage Client (
aos8_triage_client) — Find a client by MAC, check AP health, review auth/association events, identify likely root cause. - Triage AP (
aos8_triage_ap) — Deep-dive an AP: radio state, clients, alarms, ARM history, event timeline. - Health Check (
aos8_health_check) — Network-wide health: controllers, AP counts, clients, alarms, firmware drift. - Audit Change (
aos8_audit_change) — Recent audit-trail review with high-risk-change flagging. - RF Analysis (
aos8_rf_analysis) — Channel distribution, co-channel clusters, ARM oscillation, interferers/rogues. - WLAN Review (
aos8_wlan_review) — SSID/VAP/AP-group/role inventory and consistency check. - Client Flood (
aos8_client_flood) — High-client-count / failed-connection investigation at a scope. - Compare MD Config (
aos8_compare_md_config) — Side-by-side effective-config diff between two MDs or AP groups. - Pre-Change Check (
aos8_pre_change_check) — Pre-maintenance checklist: alarms, controller stats, audit trail, pending changes, write_memory reminder.
Tools that span multiple platforms and return pre-aggregated results — each one replaces several individual tool calls, so the AI gets a compact answer instead of paging through raw responses.
- Site Health Check (
site_health_check) — One call returns a unified health report for a site across every enabled platform: Mist site stats and alarms, Central site health and active alerts, and (when ClearPass is configured) session and auth-failure counts for the site's network access devices. Replaces ~8–12 separate tool calls with a compact report including overall status, top alerts, and concrete next-step recommendations. Registered when at least Mist or Central is enabled; ClearPass is additive. - Site RF Check (
site_rf_check) — One call returns per-AP, per-band radio state from Mist AND Central in parallel: current channel, bandwidth, TX power, channel utilization, and noise floor for every AP at a site. Aggregates the channel distribution per band (2.4 / 5 / 6 GHz), flags co-channel clusters and high utilization, and ships a pre-rendered ASCII RF dashboard so even clients that don't draw charts get a visual report. Whensite_nameis omitted the tool returns a list of selectable sites with AP counts per platform — pick one and call back. Registered when at least Mist or Central is enabled. - Translate WLAN (
translate_wlan_preview/translate_wlan_apply) — Translate a WLAN between platforms (Mist↔Central, AOS8→either) via the canonical translation engine.translate_wlan_previewfetches the source WLAN + all context and returns the exact target API calls for review (read-only, secrets redacted);translate_wlan_applyexecutes them against the target, gated by the target platform's write-enable flag and a confirmation prompt. Handles opmode/RADIUS/alias/VLAN/assignment translation automatically. Registered in every mode (including code). Requires Mist and/or Central. - Translate Config (
translate_config_preview/translate_config_apply) — Translate an AOS 8 → Central config object via the same canonical engine, for the 12 non-WLAN kinds:vlan_id,named_vlan,net_group,role,policy, the AAA chain (auth_server,server_group,dot1x_auth,mac_auth,captive_portal,aaa_profile), andgateway_cluster.translate_config_previewreturns the ordered Central calls per source record (read-only, PII-scrubbed);translate_config_applyexecutes against Central, gated byENABLE_CENTRAL_WRITE_TOOLS+ confirmation (and blocksauth_serveruntil secret tokenization ships). Drives theaos-migrationskill's Stage 9b. Registered in every mode (including code). Requires Central.
- Sync WLANs Mist → Central — Resolve Mist template variables, map fields, create Central WLAN profiles, assign to matching scopes.
- Sync WLANs Central → Mist — Resolve Central aliases, server groups, and named VLANs, create Mist WLANs with template variables.
- Sync WLANs Bidirectional — Compare WLANs across both platforms, show field-level differences, and sync in either direction.
- Docker and Docker Compose
git clone https://github.com/nowireless4u/hpe-networking-mcp.git
cd hpe-networking-mcpNo build required. The
docker-compose.ymlpulls a pre-built image from GitHub Container Registry by default. To build from source instead, editdocker-compose.ymland swapimage:forbuild: ..
Copy the environment template and fill in credentials for the platforms you use:
cp .env.example .env
# Edit .env — uncomment and fill in only the platforms you needOnly platforms with all required credentials set will be enabled. Leave unused platforms commented out or empty — they're automatically disabled.
Example .env for a Mist-only deployment:
MIST_API_TOKEN=your-mist-api-token-here
MIST_HOST=api.mist.comExample .env for Mist + Central:
MIST_API_TOKEN=your-mist-api-token-here
MIST_HOST=api.mist.com
CENTRAL_BASE_URL=https://apigw-us5.central.arubanetworks.com
CENTRAL_CLIENT_ID=your-client-id
CENTRAL_CLIENT_SECRET=your-client-secretSecurity:
.envis git-ignored and never committed. Restrict file permissions:chmod 600 .env. For production deployments where env vars indocker inspectare unacceptable, see Docker Secrets (Production) below.
Axis token note: Generate the token in the Axis admin portal at Settings → Admin API → New API Token. Pick read or read+write scope and an expiration. The MCP server decodes the JWT's
expclaim at startup and logs a warning when the token has fewer than 30 days remaining; thehealthtool also surfaces atoken_expires_in_dayscountdown when inside that window. There is no refresh — regenerate the token in the portal before it lapses.
Credentials from a .env file use the env overlay, which drops the base file's Docker-secret mounts so no secrets/* files are needed:
docker compose -f docker-compose.yml -f docker-compose.env.yml up -dUsing Docker secret files instead of
.env? Run the plaindocker compose up -d— the base compose mounts the secret files directly (unchanged from prior releases). See Docker Secrets (Production).
docker compose logsLook for lines like Mist: 1050 underlying tools registered (code mode), ClearPass: 142 underlying tools registered (code mode), Axis: 25 underlying tools registered (code mode), AOS8: 48 underlying tools (code mode), UXI: 21 underlying tools (code mode), EdgeConnect: registered 187 generated tool module(s) (code mode), GreenLake: registered 919 tools across 163 tool module(s) (code mode), Tool mode: code, and Uvicorn running on http://0.0.0.0:8000. Your MCP server is running at http://localhost:8000/mcp. In the default code mode (since v3.0.0.0), only execute + 5 discovery tools (tags, search, get_schema, skills_list, skills_load) are exposed at the top level; all 4109 underlying tools are reachable via await call_tool(name, params) inside a sandboxed Python execute() block. Set MCP_TOOL_MODE=dynamic to use the v2.x meta-tool surface instead. Mist registers 2 guided prompts; Central registers 12; AOS8 registers 9.
The server exposes plain HTTP endpoints for container/orchestrator health checks. They require no MCP stream negotiation (unlike /mcp, which can return 405/406 to a naive probe) and never call external platforms, so a transient upstream outage can't mark the process unhealthy:
| Endpoint | Success | Purpose |
|---|---|---|
GET /livez |
200 ok |
Process is alive and serving HTTP. Use for liveness. |
GET /readyz |
200 ok (else 503 starting) |
Startup complete and ready for MCP traffic. Use for readiness/startup. |
GET /healthz |
200 + JSON |
Operator info: service, version, status, enabled platform names, uptime_seconds. No secrets. |
The deeper per-platform reachability check remains the MCP health tool — it is intentionally not used for liveness, so an upstream platform being unreachable never restarts the container.
The Docker/Compose healthcheck already targets /livez. Kubernetes example:
startupProbe:
httpGet: { path: /livez, port: 8000 }
failureThreshold: 30
periodSeconds: 10
livenessProbe:
httpGet: { path: /livez, port: 8000 }
periodSeconds: 20
timeoutSeconds: 2
failureThreshold: 3
readinessProbe:
httpGet: { path: /readyz, port: 8000 }
periodSeconds: 10
timeoutSeconds: 2
failureThreshold: 3Kubernetes probes reach the pod IP, so keep the default
MCP_HOST=0.0.0.0bind (loopback-only binds are unreachable by the kubelet). Probes send noOriginheader and are allowed through origin validation.
The pre-built image is available on GitHub Container Registry:
ghcr.io/nowireless4u/hpe-networking-mcp:latest
ghcr.io/nowireless4u/hpe-networking-mcp:0.6.0
You can also pull it directly:
docker pull ghcr.io/nowireless4u/hpe-networking-mcp:latestYou don't need credentials for all nine platforms. The server detects which platforms have valid credentials at startup and only enables those. A platform is disabled if any of its required credentials is empty or absent — whether provided via environment variable or Docker secret file.
- All nine platforms configured → All tools available (Mist + Central + GreenLake + ClearPass + Apstra + Axis + AOS8 + UXI + EdgeConnect)
- Only Mist configured → Only
mist_*tools available; other platforms disabled - Only AOS8 configured → Only
aos8_*tools available; other platforms disabled - Only ClearPass configured → Only
clearpass_*tools available; other platforms disabled - No valid credentials → Server refuses to start with a clear error message
Add a platform later by setting its credentials in .env (or via Docker secrets) and restarting the container. The server logs which platforms are enabled at startup:
Mist: credentials loaded (token: abcd...wxyz, host: api.mist.com)
Central: disabled (missing secrets: central_client_id, central_client_secret)
GreenLake: disabled (missing secrets: greenlake_client_id)
AOS8: disabled (missing secrets: aos8_host)
Enabled platforms: mist
Tool mode: code
Claude Desktop doesn't natively support streamable HTTP, so it needs a stdio-to-HTTP bridge called supergateway. This bridge translates between Claude Desktop's stdio protocol and the MCP server's HTTP endpoint.
Prerequisites: Node.js must be installed on your machine. Verify with npx --version in your terminal.
Step 1: Open the Claude Desktop configuration file in a text editor:
| OS | File Location |
|---|---|
| macOS | ~/Library/Application Support/Claude/claude_desktop_config.json |
| Windows | %APPDATA%\Claude\claude_desktop_config.json |
Tip: You can also open this file from within Claude Desktop: go to Settings (gear icon) > Developer > Edit Config.
Step 2: If the file is empty or doesn't exist, paste this entire block as-is:
{
"mcpServers": {
"hpe-networking": {
"command": "npx",
"args": ["-y", "supergateway", "--streamableHttp", "http://localhost:8000/mcp"]
}
}
}If you already have other MCP servers configured, add the "hpe-networking" entry inside the existing "mcpServers" object. Do not create a second "mcpServers" key. For example, if you already have a server called "my-other-server":
{
"mcpServers": {
"my-other-server": {
"command": "some-command",
"args": ["some-args"]
},
"hpe-networking": {
"command": "npx",
"args": ["-y", "supergateway", "--streamableHttp", "http://localhost:8000/mcp"]
}
}
}Common mistakes:
- Missing comma between server entries (add a
,after the closing}of the previous server)- Duplicate
"mcpServers"keys (only one is allowed — merge your servers into it)- Trailing comma after the last entry (JSON does not allow trailing commas)
- Editing the wrong file or creating a new file instead of editing the existing one
Step 3: Save the file and fully restart Claude Desktop (quit and reopen, not just close the window). MCP servers are discovered at startup — changes won't take effect until you restart.
Step 4: Verify the server connected. In Claude Desktop, look for the MCP server icon (hammer) in the chat input area. Click it — you should see hpe-networking listed with its tools.
No config file needed — run this single command:
claude mcp add hpe-networking --transport http http://localhost:8000/mcpAdd to your .vscode/mcp.json (create the file if it doesn't exist) or VS Code MCP settings:
{
"servers": {
"hpe-networking": {
"type": "streamable-http",
"url": "http://localhost:8000/mcp"
}
}
}Tool responses are walked before reaching the AI:
- MAC normalization (always-on, no toggle) — every MAC address in tool responses is rewritten to canonical
aa:bb:cc:dd:ee:ffform (lowercase, colon-separated). Mist's API returns MACs in four different formats across endpoints; consistent format means the AI can correlateaa:bb:cc:dd:ee:ffto itself across audits. - PII tokenization (opt-in via
ENABLE_PII_TOKENIZATION=true) — sensitive fields (PSKs, RADIUS secrets, certificates) and customer-identifying values (hostnames, FQDNs, emails, usernames, hardware serials) are replaced with session-stable[[KIND:uuid]]tokens before reaching the AI. The AI can pass tokens back into write tools and the inbound side substitutes plaintext before the API call. Storage is in-memory only; the keymap is keyed byMcp-Session-Idand never touches disk.
Deliberately NOT tokenized:
- MAC addresses — observable to anyone in radio range (BSSID broadcast, client probe requests). Normalized only.
- SSIDs / ESSIDs — broadcast in beacon frames (refined in v2.3.1.1).
- Platform UUIDs like
org_id,site_id,device_id,template_id— already opaque random identifiers in Mist's API; replacing one UUID with another adds no privacy (refined in v2.3.1.1). - Geographic data —
address,city,state,zip,latitude,longitude,room,building— typically findable on the company's website (refined in v2.3.1.1). - All IP addresses (v2.3.1.2) — internal RFC1918, public WAN, CIDR ranges. Internal subnet topology is generally known to anyone on-network, and CIDR / route analysis is a core audit task.
Always tokenized regardless of field name (v2.3.1.2):
- Email addresses — caught even when the field is named
name,username, or anything else. Mist's MPSK pattern of using the user's email as the PSK display name was a leak before this. - AWS-signed URL credentials — any string containing
X-Amz-Security-Token,X-Amz-Credential, orX-Amz-Signatureis treated as a temporary AWS credential and tokenized whole asAPITOKEN. Catches theportal_template_urlleak from Mist's S3-backed captive-portal previews.
Central coverage (v2.3.1.3): the ruleset now also covers Central response shapes — user_name, updated_by, created_by (audit-log fields) tokenize as USER; hyphenated keys like wpa-passphrase and shared-secret match the same secret rules as their snake_case equivalents. Central organizational structure (device_group_name, scope_name) passes through as cleartext.
Round-trip works for every kind. Same plaintext → same token within a session. WLAN sync, AOS 8 → AOS 10 migration, and mass PSK rotation all work because tokenization is round-trippable.
Secrets — tokenized unconditionally when the field name matches (case-insensitive; hyphens and spaces normalized to underscores):
| Category | Field names | Token form |
|---|---|---|
| WPA2 / WPA3 keys | psk, passphrase, wpa_passphrase, wpa2_passphrase, wpa3_psk, ppsk |
[[PSK:uuid]] |
| SAE / Personal-Plus | sae_password, sae_pwd |
[[PSK:uuid]] |
| VRRP cluster key | vrrp_passphrase |
[[PSK:uuid]] |
| RADIUS shared secret | shared_secret, radius_secret, radsec_secret, coa_secret (v3.1.0.4 / #321); structural pairs rad_key.key, coa_servers[].secret |
[[RAD:uuid]] |
| EAP / inner password | eap_password, inner_password |
[[RAD:uuid]] |
| TACACS+ | structural pair tacacs_key.key |
[[TACACS:uuid]] |
| CoA / RFC-3576 endpoint identifiers | coa_servers[].ip, rfc_3576_server_list[].name; AOS 8 single-server detail-form wrapper key "RFC 3576 Server <ip>" rewritten in place (v3.1.0.4 / #319) |
[[COA:uuid]] |
| SNMP community | community, community_string |
[[SNMP:uuid]] |
| SNMP v3 passwords | auth_password, priv_password, snmp_v3_auth_pass, snmp_v3_priv_pass |
[[SNMP:uuid]] |
| Admin / enable passwords | admin_password, manager_password, support_user_password, enable_password, enable_secret, cli_password |
[[PASSWORD:uuid]] |
| IPSec / VPN PSK | pre_shared_key, ipsec_psk, vpn_psk |
[[VPNPSK:uuid]] |
| API tokens / OAuth | api_token, apitoken, api_key, apikey, client_secret |
[[APITOKEN:uuid]] |
| OAuth bearer / refresh | bearer_token, access_token, refresh_token |
[[APITOKEN:uuid]] |
| Webhook secrets | webhook_secret, webhook_token |
[[APITOKEN:uuid]] |
| AWS-signed URL (value-shape) | Any string containing X-Amz-Security-Token, X-Amz-Credential, or X-Amz-Signature |
[[APITOKEN:uuid]] |
| Certificates | cert, certificate, client_cert, server_cert, ca_cert, chain, pkcs12, p12_data, pem |
[[CERT:uuid]] |
| Certificate PEM in free-text | PEM blocks (-----BEGIN ... -----END) found in description / notes / comment |
[[CERT:uuid]] |
| Private keys | private_key, privkey, kerberos_keytab, keytab |
[[KEY:uuid]] |
| Private-key PEM in free-text | PEM key blocks in description / notes / comment |
[[KEY:uuid]] |
| Generic (shape-checked) | password, pwd → PASSWORD; secret → RAD; token, key → APITOKEN. Only when value passes length ≥ 8 + character-class diversity check (suppresses {"key": "ssid"}). |
varies |
Source-masked secrets — when the source platform itself masks the value (v3.1.0.4 / #276):
| Source value | Rewritten to | Notes |
|---|---|---|
******** (any field — AOS 8 masks RADIUS / TACACS / RFC-3576 shared secrets server-side) |
REPLACE_ME |
Literal directive, not a token. An unambiguous "operator must set this" marker for migration output — ******** reads as "redacted/hidden", REPLACE_ME reads as an instruction. The walk is idempotent and REPLACE_ME is never tokenized even in an exact-match secret field. |
Identifiers — tokenized when the field name matches:
| Category | Field names | Token form |
|---|---|---|
| Hostnames / FQDNs | hostname, host_name, fqdn |
[[HOSTNAME:uuid]] |
| Device names | device_name, ap_name, controller_name, switch_name |
[[HOSTNAME:uuid]] |
AAA-server host carve-out |
host (AOS 8 RADIUS / TACACS / LDAP server IP or FQDN) |
[[HOSTNAME:uuid]] |
Bare name (heuristic) |
name field when parent dict has ≥ 2 device-shape siblings: mac, model, serial, device_type, hw_rev, firmware, version, release_type |
[[HOSTNAME:uuid]] |
| Usernames | username, user, user_name, login |
[[USER:uuid]] |
| Personal names | first_name, last_name, full_name, display_name |
[[USER:uuid]] |
| Audit-log actors | updated_by, created_by |
[[USER:uuid]] |
email field; also matched by value-shape regex in any string field |
[[EMAIL:uuid]] |
|
| Phone | phone, phone_number, mobile |
[[PHONE:uuid]] |
| Hardware serials | serial, serial_number, sn |
[[SERIAL:uuid]] |
| Cellular IMEI | imei |
[[IMEI:uuid]] |
| Cellular IMSI | imsi |
[[IMSI:uuid]] |
| Cellular ICCID | iccid |
[[ICCID:uuid]] |
Cleartext — deliberately NOT tokenized:
| Field family | Why cleartext |
|---|---|
| MAC addresses | Observable in radio range (BSSID, probe requests). Normalized to canonical aa:bb:cc:dd:ee:ff regardless of ENABLE_PII_TOKENIZATION. |
| IP addresses (generic) | On-network topology is generally known; CIDR/route analysis is core audit utility. Carve-outs: CoA endpoint IPs and RADIUS/TACACS server host IPs (AOS 8 AAA-server detail) ARE tokenized. |
| SSIDs / ESSIDs | Broadcast in beacon frames |
| Platform UUIDs | org_id, site_id, device_id, template_id, scope_id — already opaque random IDs |
| Geographic data | address, city, state, zip, latitude, longitude, room, building — typically public on company websites |
| Organizational labels | org_name, site_name, vlan_name, subnet_name, scope_name, device_group_name — architectural labels, not people |
| Source-masked placeholders | e.g. AOS 8 ******** — tokenizing the mask creates a dangerous illusion; round-trip restores only the placeholder and silently breaks downstream writes |
Audit logging fires on every tokenize/detokenize event in docker compose logs — kind, token ID, value-hash (SHA-256 truncated), but never the plaintext.
Limitations: Mist ruleset only this release; Central / GreenLake / ClearPass / Apstra / Axis follow in the next minor. Anything the user pastes into the AI prompt is outside our threat model — that turn already has the literal in conversation context. The keymap dies on server restart; saved chat references to old tokens become unresolvable.
The MCP HTTP transport ships with two layers of defense out of the box:
- Loopback-only port publish —
docker-compose.ymlpublishes127.0.0.1:8000:8000, so only processes on the host can reach the MCP endpoint. No LAN host can connect, even if it knows the IP. (Inside the container the app still binds0.0.0.0— that's the container's own network namespace and is what Docker's port-forwarder forwards into; do not change it.) Originheader allowlist — required by the MCP Streamable HTTP spec to defend against browser-driven DNS rebinding. The server rejects any request whoseOriginis set to a value outsideALLOWED_ORIGINS(default:localhostand127.0.0.1). Non-browser clients (supergateway, curl, native MCP clients) don't sendOriginand pass through.
If you put the server behind an authenticating reverse proxy that already validates origins, set ALLOWED_ORIGINS=* to bypass the in-process check. See the Configuration table for details.
Multi-host / remote access is not a supported configuration. The server has no built-in authentication on
/mcp— anyone who can reach the port has full admin of every connected platform. If you need remote access, terminate at a reverse proxy (nginx + mTLS / OIDC, Cloudflare Access, Tailscale Funnel, etc.) and never expose the published port directly.
Credentials are loaded via a two-tier lookup for each value:
- Docker secret file at
SECRETS_DIR/<name>— highest priority (production) - Environment variable with the UPPER_CASE equivalent — fallback (development)
If both exist, the Docker secret file wins. If neither exists, the platform is disabled.
The quickest setup for development — no per-platform secret files. Create a .env and start with the env overlay (docker-compose.env.yml), which removes the base file's Docker-secret mounts so no secrets/* files need to exist:
cp .env.example .env
chmod 600 .env
# Edit .env with your credentials
docker compose -f docker-compose.yml -f docker-compose.env.yml up -dThe .env file is git-ignored and never leaves your machine. For multiple isolated instances, add --env-file .env-<name> -p <name> (see .env.example).
For production deployments where credentials must not be visible in docker inspect or /proc/<pid>/environ, use Docker secret files. They are wired into the base docker-compose.yml, so the plain command works unchanged from prior releases — just create the files and start:
# Create secret files from templates
cp secrets/mist_api_token.example secrets/mist_api_token
cp secrets/mist_host.example secrets/mist_host
# Edit with real values...
docker compose up -dA credential present as a secret file takes priority over the matching environment variable, so you can mix the two (secret files for sensitive platforms, .env for the rest — omit the env overlay when you want the secret mounts).
Docker secrets are:
- Mounted read-only at
/run/secrets/inside the container - Not visible in
docker inspector environment variables - Not baked into the Docker image
Note: the base
docker-compose.ymldeclares a secret file for every platform, so plaindocker compose up -dexpects those files to exist. Either create a file per platform you use (and comment out the rest in thesecrets:sections), or supply credentials via.envwith the env overlay above — that path needs nosecrets/*files at all.
| Environment Variable | Docker Secret File | Required | Platform |
|---|---|---|---|
MIST_API_TOKEN |
mist_api_token |
yes | Mist |
MIST_HOST |
mist_host |
yes | Mist |
CENTRAL_BASE_URL |
central_base_url |
yes | Central |
CENTRAL_CLIENT_ID |
central_client_id |
yes | Central |
CENTRAL_CLIENT_SECRET |
central_client_secret |
yes | Central |
GREENLAKE_API_BASE_URL |
greenlake_api_base_url |
yes | GreenLake |
GREENLAKE_CLIENT_ID |
greenlake_client_id |
yes | GreenLake |
GREENLAKE_CLIENT_SECRET |
greenlake_client_secret |
yes | GreenLake |
GREENLAKE_WORKSPACE_ID |
greenlake_workspace_id |
yes | GreenLake |
CLEARPASS_SERVER |
clearpass_server |
yes | ClearPass |
CLEARPASS_CLIENT_ID |
clearpass_client_id |
yes | ClearPass |
CLEARPASS_CLIENT_SECRET |
clearpass_client_secret |
yes | ClearPass |
CLEARPASS_VERIFY_SSL |
clearpass_verify_ssl |
no (default: true) |
ClearPass |
APSTRA_SERVER |
apstra_server |
yes | Apstra |
APSTRA_USERNAME |
apstra_username |
yes | Apstra |
APSTRA_PASSWORD |
apstra_password |
yes | Apstra |
APSTRA_PORT |
apstra_port |
no (default: 443) |
Apstra |
APSTRA_VERIFY_SSL |
apstra_verify_ssl |
no (default: true) |
Apstra |
AXIS_API_TOKEN |
axis_api_token |
yes | Axis |
AOS8_HOST |
aos8_host |
yes | AOS8 |
AOS8_USERNAME |
aos8_username |
yes | AOS8 |
AOS8_PASSWORD |
aos8_password |
yes | AOS8 |
AOS8_PORT |
aos8_port |
no (default: 4343) |
AOS8 |
AOS8_VERIFY_SSL |
aos8_verify_ssl |
no (default: true) |
AOS8 |
UXI_CLIENT_ID |
uxi_client_id |
yes | UXI |
UXI_CLIENT_SECRET |
uxi_client_secret |
yes | UXI |
| Credential | How to Obtain |
|---|---|
MIST_API_TOKEN |
Mist Dashboard > Organization > Settings > API Token |
MIST_HOST |
api.mist.com (Global), api.eu.mist.com (EU), api.gc1.mist.com (GovCloud) |
| Credential | How to Obtain |
|---|---|
CENTRAL_BASE_URL |
HPE GreenLake Platform > Aruba Central > API Gateway |
CENTRAL_CLIENT_ID |
HPE GreenLake Platform > API Clients |
CENTRAL_CLIENT_SECRET |
HPE GreenLake Platform > API Clients |
| Credential | How to Obtain |
|---|---|
GREENLAKE_API_BASE_URL |
Typically https://global.api.greenlake.hpe.com |
GREENLAKE_CLIENT_ID |
HPE GreenLake Platform > API Clients |
GREENLAKE_CLIENT_SECRET |
HPE GreenLake Platform > API Clients |
GREENLAKE_WORKSPACE_ID |
HPE GreenLake Platform > Workspaces |
| Credential | How to Obtain |
|---|---|
CLEARPASS_SERVER |
https://your-clearpass-server/api — the CPPM server hostname with /api path |
CLEARPASS_CLIENT_ID |
ClearPass Admin > API Clients > Create API Client |
CLEARPASS_CLIENT_SECRET |
ClearPass Admin > API Clients > Client Secret |
CLEARPASS_VERIFY_SSL |
true (default) or false for self-signed certificates |
| Credential | Required | Default | Purpose |
|---|---|---|---|
AOS8_HOST |
yes | — | Conductor or standalone controller hostname/IP |
AOS8_USERNAME |
yes | — | API username with sufficient role |
AOS8_PASSWORD |
yes | — | API password |
AOS8_PORT |
no | 4343 |
HTTPS port (Mobility Conductor API port) |
AOS8_VERIFY_SSL |
no | true |
Set to false for self-signed certs (logged as WARNING) |
Set ENABLE_AOS8_WRITE_TOOLS=true to expose the 12 AOS8 write tools (gated by elicitation middleware; default false).
| Credential | Required | Default | Purpose |
|---|---|---|---|
UXI_CLIENT_ID |
yes | — | HPE SSO OAuth2 client ID |
UXI_CLIENT_SECRET |
yes | — | HPE SSO OAuth2 client secret |
Set ENABLE_UXI_WRITE_TOOLS=true to expose the 10 UXI write tools (gated by elicitation middleware; default false).
┌─────────────────────────────────────────────────────────────────────────────────────────┐
│ MCP Client (Claude, VS Code, etc.) │
└───────────────────────────────────────┬─────────────────────────────────────────────────┘
│ Streamable HTTP
▼
┌─────────────────────────────────────────────────────────────────────────────────────────┐
│ HPE Networking MCP Server (:8000) — MCP_TOOL_MODE=code (default since v3.0.0.0) │
│ │
│ Exposed to the AI (6 tools in code mode): │
│ • execute (sandboxed Python; await call_tool(name, params) inside) │
│ • 5 discovery tools: tags, search, get_schema, skills_list, skills_load │
│ Set MCP_TOOL_MODE=dynamic to use the v2.x meta-tool surface (24 tools). │
│ │
│ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐│
│ │ Mist │ │Central │ │GreenLk │ │ClrPass │ │ Apstra │ │ Axis │ │ AOS8 │ │ UXI ││
│ │ mist_* │ │centrl_*│ │grnlake │ │clrpass │ │apstra_*│ │ axis_* │ │ aos8_* │ │ uxi_* ││
│ │ 1050 │ │669tools│ │10 tools│ │142 tool│ │19 tools│ │25 tools│ │48 tools│ │21 tools││
│ │+2 prmt │ │+12prmt │ │ │ │ │ │ │ │ │ │+9 prmt │ │ ││
│ │
│ All 4109 underlying tools reachable via call_tool() in code mode or via │
│ per-platform meta-tools (<platform>_list_tools / get_schema / invoke) in dynamic mode. │
│ └───┬────┘ └───┬────┘ └───┬────┘ └───┬────┘ └───┬────┘ └───┬────┘ └───┬────┘ └───┬────┘│
│ │ │ │ │ │ │ │ │ │
└─────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼───────┘
▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼
Mist Cloud Aruba GreenLake ClearPass Apstra Axis Mobility HPE UXI
API Central API CPPM API Fabric API Atmos Conductor API
API Cloud API
+ EdgeConnect (Silver Peak) Orchestrator API — edgeconnect_* (1216 SD-WAN tools, /gms/rest)
Key design decisions:
- FastMCP framework with Python 3.12+
- Streamable HTTP transport (modern MCP standard)
- Code tool mode by default (since v3.0.0.0) — only
execute+ 5 discovery tools exposed; all 4109 underlying tools reachable viaawait call_tool(name, params)inside the sandbox. Smallest initial token cost; best for orchestrators driving small / local LLMs. SetMCP_TOOL_MODE=dynamicfor the v2.x meta-tool surface (24 tools, ~3,700 tokens). - Tool namespacing —
mist_*,central_*,greenlake_*,clearpass_*,apstra_*,axis_*,aos8_*,uxi_*prefixes prevent collisions - Platform isolation — each module manages its own API client and auth; a failing platform doesn't affect the others
- Non-root container — runs as
mcpuser(uid 1000)
Write/mutation tools (e.g., creating WLANs in Mist, modifying configurations) are supported with safety controls:
- Disabled by default — enable per-platform with
ENABLE_MIST_WRITE_TOOLS=true,ENABLE_CENTRAL_WRITE_TOOLS=true,ENABLE_CLEARPASS_WRITE_TOOLS=true,ENABLE_APSTRA_WRITE_TOOLS=true,ENABLE_AXIS_WRITE_TOOLS=true,ENABLE_AOS8_WRITE_TOOLS=true, orENABLE_GREENLAKE_WRITE_TOOLS=true - Elicitation required — write tools prompt for user confirmation before executing
- Annotation-based — all tools carry MCP annotations (
readOnlyHint,destructiveHint, etc.)
| Environment Variable | Default | Effect |
|---|---|---|
ENABLE_MIST_WRITE_TOOLS |
false |
Enable Mist write/mutation tools |
ENABLE_CENTRAL_WRITE_TOOLS |
false |
Enable Central write/mutation tools |
ENABLE_CLEARPASS_WRITE_TOOLS |
false |
Enable ClearPass write/mutation tools |
ENABLE_APSTRA_WRITE_TOOLS |
false |
Enable Apstra write/mutation tools |
ENABLE_AXIS_WRITE_TOOLS |
false |
Enable Axis Atmos Cloud write/mutation tools (every write stages — call axis_commit_changes to apply) |
ENABLE_AOS8_WRITE_TOOLS |
false |
Enable AOS8 write tools (12 tools; every write returns requires_write_memory_for — call aos8_write_memory explicitly) |
ENABLE_UXI_WRITE_TOOLS |
false |
Enable UXI write tools (10 tools: sensor/agent/group/assignment mutations) |
ENABLE_GREENLAKE_WRITE_TOOLS |
false |
Enable GreenLake write tools (424 spec-generated writes/deletes + greenlake_bulk_add_devices bulk CSV device onboarding) |
MCP_APP_ENABLE |
false |
Single switch for all MCP-Apps capabilities. Registers the FastMCP FileUpload provider (file_manager drag/pick upload UI + list_files for file metadata) and the GenerativeUI provider (generate_prefab_ui — the model writes a live Prefab dashboard from data it collected — + search_prefab_components). All UIs render only in MCP-Apps hosts (e.g. Claude Desktop / ChatGPT / claude.ai). Uploaded files are read server-side only — the content-returning read_file tool is deliberately removed so upload contents (device serials/MACs, AOS 8 PSKs / RADIUS secrets) never enter the model context; consuming tools (greenlake_bulk_add_devices, aos8_parse_config) read by name inside the server. |
DISABLE_ELICITATION |
false |
Skip user confirmation for write tools (use with caution) |
The server transparently retries transient API failures so the AI doesn't have to reason about flakey upstream services.
- 5xx errors on read tools — auto-retried with exponential backoff (1s, 2s, 4s — 3 attempts total)
- 429 rate-limit responses — retried on both reads and writes (always safe — the server is asking us to slow down). Honors the
Retry-Afterresponse header when present, capped at 60s - Write tools (5xx) — never auto-retried for idempotency safety. The error surfaces to the AI which can decide whether to re-issue
- 4xx errors (other than 429) — never retried; surface immediately
The retry logic detects transient failures in two patterns: response-dict (Mist/Central/ClearPass return {"status_code": 503, ...}) and httpx exception (GreenLake/Apstra/Axis raise httpx.HTTPStatusError). Read/write classification is via the underlying tool's tags — anything tagged *_write or *_write_delete is treated as a write.
| Environment Variable | Default | Effect |
|---|---|---|
RETRY_MAX_ATTEMPTS |
3 |
Max attempts including the first call. Set to 1 to disable retry entirely |
RETRY_INITIAL_DELAY |
1.0 |
Initial backoff delay in seconds (doubles per attempt up to RETRY_MAX_DELAY) |
RETRY_MAX_DELAY |
60.0 |
Cap on a single sleep — also caps Retry-After header values |
| Environment Variable | Default | Description |
|---|---|---|
MCP_PORT |
8000 |
Port the MCP server listens on |
MCP_HOST |
0.0.0.0 |
Bind address inside the container's namespace — leave at 0.0.0.0 so Docker's port-forwarder can reach the app. Restrict who can reach the host port via ports: in compose, not this. |
ALLOWED_ORIGINS |
http://localhost:<HOST_PORT>,http://127.0.0.1:<HOST_PORT> |
Comma-separated allowlist for the Origin request header (DNS-rebinding defense per MCP spec). Compose derives the default from HOST_PORT so multi-instance setups get the right origin automatically. Browsers always send Origin; non-browser clients (supergateway, curl) don't and pass through. Set to * to disable the check (use only behind an auth proxy). |
SECRETS_DIR |
/run/secrets |
Directory for Docker secret files (credentials in files here take priority over env vars) |
LOG_LEVEL |
info |
Logging level (debug, info, warning, error) |
ENABLE_MIST_WRITE_TOOLS |
false |
Enable Mist write/mutation tools |
ENABLE_CENTRAL_WRITE_TOOLS |
false |
Enable Central write/mutation tools |
ENABLE_CLEARPASS_WRITE_TOOLS |
false |
Enable ClearPass write/mutation tools |
ENABLE_APSTRA_WRITE_TOOLS |
false |
Enable Apstra write/mutation tools |
ENABLE_AXIS_WRITE_TOOLS |
false |
Enable Axis write/mutation tools (staged; commit with axis_commit_changes) |
ENABLE_AOS8_WRITE_TOOLS |
false |
Enable AOS8 write tools (call aos8_write_memory after each change to persist) |
ENABLE_UXI_WRITE_TOOLS |
false |
Enable UXI write tools (sensor/agent/group/assignment mutations) |
ENABLE_GREENLAKE_WRITE_TOOLS |
false |
Enable GreenLake write tools (424 spec-generated writes/deletes + greenlake_bulk_add_devices bulk CSV device onboarding) |
DISABLE_ELICITATION |
false |
Disable write confirmation prompts |
MCP_TOOL_MODE |
code |
Tool exposure: code (default since v3.0.0.0 — 6 tools at top level: execute + 5 discovery; all 4109 underlying tools reachable via call_tool() inside the sandbox) or dynamic (24 tools — 4 cross-platform + 21 per-platform meta-tools + 2 skills tools; underlying tools hidden until invoked via <platform>_invoke_tool). The static value was REMOVED in v3.0.0.0 |
RETRY_MAX_ATTEMPTS |
3 |
Max retry attempts on transient failures (5xx reads, 429 reads+writes). Set to 1 to disable retry |
RETRY_INITIAL_DELAY |
1.0 |
Initial retry backoff seconds (exponential: 1s, 2s, 4s) |
RETRY_MAX_DELAY |
60.0 |
Cap on a single retry sleep (also caps Retry-After header values) |
ENABLE_PII_TOKENIZATION |
false |
Tokenize sensitive fields (PSKs, RADIUS secrets, hostnames, emails, etc.) in tool responses before they reach the AI. Round-trips: AI passes tokens back into write tools and the middleware substitutes plaintext. MAC normalization is always-on regardless of this toggle. See PII Tokenization above. |
PII_MAX_TOKENS_PER_SESSION |
10000 |
Soft cap on the per-session keymap size. Cap-hit logs a warning and falls through with plaintext rather than erroring out the call. |
PII_SESSION_TTL_SECONDS |
3600 |
Idle-TTL for per-session token keymaps. A session not accessed within this window is purged on the next tool call, bounding how long plaintext secrets linger for dead sessions. 0/negative disables the sweep (keymaps live until restart). |
CODE_SANDBOX_MAX_DURATION_SECS |
30.0 |
Wall-clock budget for a single code-mode execute() block. Raise it when driving poll-and-wait tools (e.g. central_cable_test, which blocks up to ~25s). Invalid / non-positive values fall back to 30.0. |
All development happens inside Docker containers.
Edit docker-compose.yml — comment out image: and uncomment build::
services:
hpe-networking-mcp:
# image: ghcr.io/nowireless4u/hpe-networking-mcp:latest
build: .Then rebuild:
docker compose up -d --builddocker compose -f docker-compose.yml -f docker-compose.dev.yml run --rm \
hpe-networking-mcp uv run pytest tests/ -vRun this before pushing to catch issues early:
docker compose -f docker-compose.yml -f docker-compose.dev.yml run --rm \
hpe-networking-mcp sh -c \
"uv run ruff check . && uv run ruff format --check . && \
uv run mypy src/ --ignore-missing-imports && uv run pytest tests/ -q"See CONTRIBUTING.md for the full development workflow.
hpe-networking-mcp/
├── src/hpe_networking_mcp/
│ ├── __main__.py # CLI entry point
│ ├── server.py # FastMCP server setup and lifespan
│ ├── config.py # Credential loading (env vars + Docker secrets)
│ ├── INSTRUCTIONS.md # LLM instructions for all platforms
│ ├── middleware/ # null-strip, validation-catch, sandbox-error-catch, elicitation, retry
│ ├── skills/ # Markdown-defined multi-step procedures + skills engine
│ └── platforms/
│ ├── _common/ # Shared tool registry, capability annotations, async auth primitive
│ ├── health.py # Cross-platform health probe tool
│ ├── mist/ # 1050 Mist tools (spec-driven) + 2 prompts + API client
│ ├── central/ # 669 Central tools + 12 prompts + API client
│ ├── greenlake/ # 919 GreenLake tools (spec-generated) + bulk_add + OAuth2 client
│ ├── clearpass/ # 142 ClearPass tools + async httpx client
│ ├── apstra/ # 19 Apstra tools + async httpx client
│ ├── axis/ # 25 Axis Atmos Cloud tools + httpx client (JWT bearer)
│ ├── aos8/ # 48 AOS8 tools + 9 prompts + UIDARUBA session client
│ ├── uxi/ # 21 UXI tools + OAuth2 client
│ ├── edgeconnect/ # 1216 EdgeConnect (Silver Peak) Orchestrator tools (spec-driven) + session/API-key client
│ ├── manage_wlan.py # Cross-platform WLAN management tool
│ ├── sync_prompts.py # Cross-platform WLAN sync prompts
│ ├── site_health_check.py # Cross-platform site health aggregator
│ └── site_rf_check.py # Cross-platform Wi-Fi RF dashboard
├── tests/ # Unit and integration tests (2150+ unit tests)
├── docs/ # PRD, PRP, tool reference
├── secrets/ # Secret file templates (.example only in git)
├── .env.example # Environment variable template (copy to .env)
├── .github/workflows/ # CI, security, Docker publish
├── Dockerfile # Multi-stage build, non-root user
├── docker-compose.yml # Base — mounts Docker secret files (plain `up -d`)
├── docker-compose.env.yml # Overlay — drops secret mounts for the `.env` path
└── docker-compose.dev.yml # Development (mounts tests)
Always start here when something isn't working:
docker compose logs # All logs
docker compose logs --tail 50 # Last 50 lines
docker compose logs -f # Follow liveIf a platform shows as disabled, its credentials are missing or empty:
Mist: disabled (mist_api_token secret not found)
Central: disabled (missing secrets: central_client_id, central_client_secret)
Fix: Set the missing credentials in your .env file (or the matching Docker secret file). If you intended to disable that platform, ignore the message — the server continues running with the platforms that do have credentials.
Error response from daemon: invalid mount config for type "bind":
bind source path does not exist: .../secrets/apstra_verify_ssl
This means the base docker-compose.yml declares a secret file for a platform whose file doesn't exist on disk (Docker requires every referenced secret file to be present before the container starts).
Fix — pick one:
- Using
.envfor credentials? Add the env overlay, which removes all secret mounts:docker compose -f docker-compose.yml -f docker-compose.env.yml up -d. Nosecrets/*files are needed on this path. - Using Docker secret files? Create the missing file (
cp secrets/<name>.example secrets/<name>and populate it), or comment out that platform's entries in thesecrets:sections ofdocker-compose.yml.
Mist — Permission Denied or 401 Unauthorized:
- Verify your API token is valid in the Mist Dashboard
- Check that
mist_hostmatches your region (api.mist.com,api.eu.mist.com,api.gc1.mist.com)
Central — Login Failed or token errors:
- Verify
central_base_urlmatches your Central instance (e.g.,https://us5.api.central.arubanetworks.com) - Ensure the OAuth2 client ID and secret are correct and not expired
- Check that the API client has the correct scopes in HPE GreenLake Platform
GreenLake — Access token acquisition failed:
- Verify
greenlake_api_base_url(typicallyhttps://global.api.greenlake.hpe.com) - Check that the client credentials are valid and the workspace ID is correct
- Token refresh happens automatically — if it fails, check the logs for details
ClearPass — ClearPass: failed to initialize:
- Verify
clearpass_serveris the correct CPPM hostname with/apipath (e.g.,https://clearpass.example.com/api) - Ensure the OAuth2 API client has been created in ClearPass Admin with
client_credentialsgrant type - For self-signed certificates, set
clearpass_verify_ssltofalse - Check the logs for the specific error:
docker compose logs | grep ClearPass
Apstra — Apstra: failed to initialize or login errors:
- Verify
apstra_serveris just the hostname (no scheme, no port), e.g.,apstra.example.com - Set
apstra_portonly if your Apstra server listens somewhere other than443 - Ensure
apstra_usernameandapstra_passwordbelong to an Apstra account that can reach/api/user/login - For self-signed Apstra certificates, set
apstra_verify_ssltofalse(defaults totrue) - Check the logs for the specific error:
docker compose logs | grep Apstra
docker compose ps # Check container is running
docker compose restart # Restart the containerIf port 8000 is already in use by another service, change the port in docker-compose.yml (keep the 127.0.0.1: prefix):
ports:
- "127.0.0.1:8080:8000" # Map to port 8080 instead, loopback-onlyIf you change the host port via HOST_PORT, the Compose default for ALLOWED_ORIGINS tracks it automatically (http://localhost:<HOST_PORT>). You only need to set ALLOWED_ORIGINS explicitly if you're using a custom domain or reverse-proxy URL.
- Check the server is running:
docker compose logs | grep "registered" - Verify the endpoint is reachable:
curl -s -o /dev/null -w "%{http_code}" http://localhost:8000/mcp(expect406— this is normal for a plain GET) - Restart your AI client after adding or changing the MCP server config — tools are discovered at session start
Claude Desktop doesn't natively support streamable HTTP — it requires a stdio bridge. Use supergateway:
{
"mcpServers": {
"hpe-networking": {
"command": "npx",
"args": ["-y", "supergateway", "--streamableHttp", "http://localhost:8000/mcp"]
}
}
}If tools time out after ~4 minutes, check that:
- The Docker container is running and healthy:
docker compose ps - Node.js is installed:
npx --version - The container didn't lose connectivity after sleep:
docker compose restart
Since v3.0.0.0, the server defaults to MCP_TOOL_MODE=code: only execute + 5 discovery tools (tags, search, get_schema, skills_list, skills_load) are visible at the top level. All 4109 underlying tools are reachable via await call_tool(name, params) inside a sandboxed Python execute() block. A correctly configured server with all 9 platforms enabled will advertise 6 tools to the AI client.
Check the mode in the logs:
docker compose logs | grep "Tool mode"
# "Tool mode: code" → default since v3.0.0.0 (6 exposed tools, 4109 underlying via call_tool)
# "Tool mode: dynamic" → opt-in to v2.x meta-tool surface (24 exposed: 21 per-platform + 4 cross-platform + 2 skills)To use the v2.x meta-tool discovery surface (each platform exposes <platform>_list_tools, <platform>_get_tool_schema, <platform>_invoke_tool), set MCP_TOOL_MODE=dynamic in docker-compose.yml under environment:
- MCP_TOOL_MODE=dynamic # 24 exposed; per-platform meta-tools + cross-platform + skills
- MCP_TOOL_MODE=code # 6 exposed; sandboxed call_tool() reaches all 4109 (default since v3.0.0.0)The static mode (every underlying tool visible up front) was REMOVED in v3.0.0.0 — at 4109 tools / ~64K tokens it was no longer practical. Setting MCP_TOOL_MODE=static now raises an error at startup with a migration message.
See docs/MIGRATING_TO_V2.md for the v1.x → v2.x meta-tool history.
Write tools are disabled by default. Enable them per-platform in docker-compose.yml:
- ENABLE_MIST_WRITE_TOOLS=true
- ENABLE_CENTRAL_WRITE_TOOLS=true
- ENABLE_CLEARPASS_WRITE_TOOLS=trueThen restart: docker compose restart
Check the exit code and logs:
docker compose ps -a # Check exit code
docker compose logs --tail 100 # Check recent logsCommon causes:
- No valid credentials — the server exits if zero platforms can be initialized
- Port conflict — another service is using port 8000
- Out of memory — increase Docker's memory allocation
Contributions are welcome! The main branch is protected — all changes go through pull requests with CI checks. See CONTRIBUTING.md for the full development workflow.
For a complete list of every tool and its parameters, see docs/TOOLS.md.