fabric-aiops
fabric-aiops is a governed MCP/CLI server for multi-vendor network-fabric AIops across Meraki, Catalyst Center, CVP, UniFi, and read-only ACI.
Run read operations for orgs, networks, devices, clients, VLANs, traffic, alerts, licensing, admins, API usage, ports, SSIDs, and device statuses.
Use flagship analyses: MX WAN uplink loss/latency RCA, explainable network health scoring, and config-template drift detection.
Perform guarded writes on Meraki and UniFi: reboot/restart devices, claim/remove devices, bind/unbind templates, update device attributes/VLANs, blink LEDs, and apply undo tokens.
Use read-only ACI-native tools for endpoint path reconstruction, EPG segment tracing, and fabric fault listing.
Operate across Meraki (full read/write), Catalyst Center / CVP / UniFi (read subsets, UniFi device restart), and ACI (read-only) with teaching errors for unsupported ops.
Rely on governance harness: audit every call, runaway/budget guard, undo-token recording, risk tiers, encrypted credentials, dry-run previews, and before-state capture for reversible writes.
Integrate as an MCP server or CLI, with 37 tools total: 28 read and 9 write.
Provides management of Cisco network fabrics through the Meraki Dashboard API and Catalyst Center (DNA Center), including org/network/device/client reads, uplink loss and latency RCA, health scoring, config template drift analysis, and Meraki write operations (device updates, VLAN updates, device claim/remove, template bind/unbind, reboot, LED blink) with undo and audit tracking.
Provides integration with UniFi Network (self-hosted controller or UniFi OS console), enabling reads of sites, device status and inventory, connected clients, switch port tables, alarms, and network health rollups, plus device restart operations.
Cisco Meraki / Catalyst / ACI & Multi-vendor Controller AIops
Audit availability: Real writes require a committed
pendingaudit row and stop before contacting the platform if storage is unavailable. Reads and previews may continue with a warning; new audit rows store outcome summaries rather than full responses.
Disclaimer: Community-maintained open-source project. Not affiliated with, endorsed by, or sponsored by Cisco, Meraki, Arista, Ubiquiti, or any network-controller vendor. "Cisco", "Meraki", "Catalyst", "DNA Center", "Arista", "CloudVision", "Ubiquiti", "UniFi", "ACI", "APIC" and all product/trademark names belong to their respective owners. MIT licensed.
Governed AI-ops for network fabrics managed through a controller — the
Cisco Meraki Dashboard API (the reference platform, full read + write),
Cisco Catalyst Center (formerly DNA Center; read subset), Arista
CloudVision Portal (CVP) (read subset), and UniFi Network (self-hosted
controller or UniFi OS console; read subset + device restart), plus read-only
Cisco ACI (APIC) endpoint path reconstruction and faults — with a
built-in governance
harness: unified audit log, token/runaway budget guard,
undo-token recording, and descriptive risk tiers. Multi-platform by
construction: a registry keyed by platform maps every canonical operation
onto each controller's REST API (path templates + response adapters), so adding
a controller is a registry entry, never new ops/CLI/MCP surface. An operation a
platform doesn't map returns a clear teaching error ("not supported on X yet —
open an issue"), never a silent no-op. A production user has exercised ACI
read paths on APIC 5.3 and supplied anonymized real responses. Complete
end-to-end verification remains open — see
docs/VERIFICATION.md.
What it does
Three flagship signature analyses, plus the guarded reads and writes around them:
Uplink loss & latency RCA — pull MX WAN uplink loss + latency across an org, rank the worst uplinks by a composite of average loss and latency, and map each degraded uplink to a likely cause + recommended action. Every ranking carries its numbers, not a black-box verdict.
Network health score — a composite 0-100 score per network from device online %, uplink health %, and an alert-severity penalty (weighted 0.5/0.3/0.2), with every component returned so the number is explainable.
Config template drift — for networks bound to a config template, list the settings that have drifted from the template (expected vs actual).
Related MCP server: observability-aiops
What works
CLI (
fabric-aiops ...):init,overview,org,network,device,client,health,aci,remediate,secret,doctor,mcp.MCP server (
fabric-aiops mcporfabric-aiops-mcp): 37 tools (28 read, 9 write), every one wrapped with the bundled@governed_toolharness.Encrypted credentials: the controller secret (Meraki API key / Catalyst Center or APIC
username:password/ CVP service-account token / UniFi API key) lives in an encrypted store~/.fabric-aiops/secrets.enc(Fernet + scrypt) — never plaintext on disk. Unlock with a master password fromFABRIC_AIOPS_MASTER_PASSWORD(MCP/CI) or an interactive prompt (CLI).Reversibility: mutating writes fetch the real before-state first and record a faithful inverse (
update_device/update_network_vlanrestore prior values;claim↔remove;bind↔unbind/rebind). Irreversible ops (reboot_device,blink_device_leds) record the prior state for audit but declare no undo.Safety: every state-changing CLI op supports
--dry-runand requires double confirmation; every write MCP tool takes adry_runpreview.
Capability matrix (37 MCP tools)
Domain | Tools | Count | R/W |
Overview |
| 1 | read |
Organizations |
| 6 | read |
Networks |
| 5 | read |
Devices |
| 5 | read |
Clients |
| 4 | read |
Health (flagship) |
| 3 | read |
Cisco ACI (APIC only) |
| 3 | read |
Remediation |
| 5 | write (high) |
| 2 | write (medium) | |
| 1 | write (low) | |
Undo |
| 1 | read |
| 1 | write (medium) |
network_health_score and config_template_drift are injected-only (they score
data you already hold); uplink_loss_and_latency_rca accepts injected records
for offline analysis or pulls live from a configured target. Device models carry
a product-type prefix: MX appliance, MS switch, MR wireless AP, MV
camera, MG cellular gateway.
Platform support matrix
One tool, five controller platforms. For the four in the table below the
ops/CLI/MCP surface is identical everywhere; each platform maps the canonical
operations it supports and raises a teaching error for the rest ("not supported
on <platform> yet — open an issue or PR"). ACI maps none of these — see
Cisco ACI below.
Canonical operation | meraki | catalyst | cvp | unifi |
| ✅ | ✅ | ✅ | ✅ |
| ✅ | ✅ sites | ✅ containers | ✅ sites (list; get ❌) |
| ✅ | ❌ | ❌ | ❌ |
| ✅ | ❌ | ✅ users | ❌ |
| ✅ | ✅ device-health | ✅ inventory + streaming status | ✅ stat/device (state, uptime, firmware) |
| ✅ | ✅ site-health / site | ✅ containers | ✅ sites / stat/health (subsystem rollup) |
| ✅ | ❌ | ❌ | ❌ |
| ✅ | ✅ issues (P1→critical, P2→warning) | ✅ events | ✅ alarms (*_Lost_Contact→critical) |
| ✅ | ✅ network-device | ✅ inventory (+ complianceCode drift signal) | ✅ stat/device (id = device MAC) |
| ✅ | ❌ | ❌ | ❌ |
| ✅ | ✅ interface stats (pass the device uuid) | ❌ | ✅ device |
| ✅ | ❌ | ❌ | ❌ |
| ✅ | ✅ client-health (aggregate) / client-detail (by MAC) | ❌ | ✅ stat/sta (connected) / stat/user (by MAC) |
| ✅ | ❌ | ❌ | ❌ |
| ✅ | ❌ (injected | ❌ (injected | ❌ (injected |
| ✅ | ✅ | ✅ | ✅ |
| ✅ | ❌ teaching error | ❌ teaching error | ✅ |
The other 7 writes (blink/update/claim/remove/bind/unbind/VLAN) | ✅ | ❌ teaching error | ❌ teaching error | ❌ teaching error |
Concept mapping: canonical organizations/networks are Catalyst Center
sites, CVP containers, and UniFi sites (the canonical id is the
site's short name — the /api/s/{site}/ path segment); all have one global
tree, so the org scope does not filter their lists. On unifi, device-scoped
calls (device get / switch_ports / reboot) fill the site from the
target's default org_id — set it in config.yaml (or the init wizard). Writes
are Meraki-only except UniFi device restart — Catalyst Center and CVP
change models (task/configlet workflows) don't map cleanly onto these
canonical writes, so each write fails fast with a teaching error before any
controller call (never a silent no-op). CVP config-drift surfaces through
device_inventory (complianceCode/complianceIndication per device) and
network_alerts (events); configlet-content retrieval and deep pagination on
catalyst/cvp/unifi are known deferrals.
Cisco ACI (APIC)
ACI has two axes — tenant → VRF → bridge domain → EPG, and pod → node →
interface — and neither is an organization → network → device tree. Rather than
make every network_id mean something different per call, an aci target
answers the canonical tools with a teaching error and gets three read-only
ACI-native tools that take ACI references (MAC/IP, tenant/app/EPG names, DNs):
Tool (CLI) | What it answers |
| Where is this endpoint and what carries it: attachment (pod / leaf / interface or vPC) → EPG → bridge domain → VRF → the EPG's contracts → filter entries, plus faults whose DN names the EPG or the attachment interface |
| The same EPG → BD → VRF → contracts chain from an EPG name |
| Fabric faults, worst severity first |
How to read them:
A static reconstruction, not a reachability test.
staticPathResolved: truemeans the fabric is configured to carry the endpoint, not that traffic flows. Nothing is written to the APIC and no troubleshooting session is created.Links follow the relation APIC resolved (
tDn), so cross-tenant links intocommonare followed; a relation that is notformedis a finding with its state.Related faults are candidates matched by DN (the EPG, the attachment interface, the leaf's deployed copy of the EPG's policy) — proximity, not cause.
Fault rows are records, not incidents: a
delegatedrecord mirrors a fault on another object. A cleared fault keeps the description it had when raised.Not evaluated (listed in every result as
notChecked): vzAny contracts, taboo contracts, imported contract interfaces, preferred-group peers, service graphs / L3Out.
Leaf/spine inventory and interface state (fabricNode, topSystem, l1PhysIf)
are not in this release — they will be built once real responses for those
classes are available, as the ones above were.
Per-platform auth
Platform |
| Secret stored (encrypted) | Auth on the wire | Base URL |
Cisco Meraki Dashboard |
| API key (Dashboard → Organization → Settings → API access) |
| default |
Cisco Catalyst Center |
|
| exchanged via | required, e.g. |
Arista CloudVision Portal |
| service-account token (Settings → Access Control → Service Accounts) |
| required, e.g. |
Cisco ACI (APIC) |
|
|
| required, e.g. |
UniFi Network |
| API key (UniFi OS: Settings → Control Plane → Integrations; self-hosted Network Server 9.0+) |
| required — classic controller |
fabric-aiops init walks through the platform choice and stores the right kind
of secret; fabric-aiops doctor probes each target with the canonical
top-of-hierarchy read (organizations / sites / containers / UniFi sites; on an
APIC, the tenant count), exercising the full auth flow.
What this tool does, and does not, decide
It delivers network-fabric operations — reads and writes — accurately and efficiently, and records every one of them. It does not decide whether a write is allowed to happen. That is the agent's judgement, or the permission of the account you connect it with: give it a Meraki API key whose admin has read-only organization access (or the read-only equivalent on your controller) and the writes fail at the controller — the place that actually owns the permission.
So there is no read-only switch, no policy file, no approval gate to configure.
The one thing the tool guarantees is that nothing is silent: every call, over
MCP and over the CLI alike, lands an audit row in ~/.fabric-aiops/audit.db,
and mutating writes still capture their before-state and record an inverse where
one exists.
Each tool declares a
risk_level, kept in agreement with its[READ]/[WRITE]documentation tag by a test, and carried into the audit row as a descriptive tier — so a reviewer can see at a glance that a row was a high-risk delete. It is a label, not a gate.
Quick start
As a Claude Code plugin
One install gives an agent both the skill and the MCP server:
/plugin marketplace add AIops-tools/marketplace
/plugin install fabric-aiops@aiops-toolsThe MCP server is fetched with uv and pinned to the
package version this plugin declares, so an audit row can be traced back to the
code that wrote it. Credentials are still configured with fabric-aiops init — see below.
As an OpenClaw plugin
The same bundle is published on ClawHub, where one install delivers the skill and its MCP server together:
openclaw plugins install clawhub:@zw008/fabric-aiops
openclaw skills info fabric-aiops # expect: Visible to model: yesRestart the OpenClaw gateway afterwards so it loads the plugin. The MCP server is
fetched with uv, pinned to this exact release, so
uvx has to be on PATH — without it the skill still installs but reports
Visible to model: no. Credentials are configured exactly as below.
As a CLI or standalone MCP server
uv tool install fabric-aiops # or: pipx install fabric-aiops
fabric-aiops init # wizard: choose platform (meraki/catalyst/cvp/unifi) + store the secret (encrypted)
fabric-aiops doctor # verify config, secrets, connectivity (per-platform auth probe)
fabric-aiops overview # one-shot fabric fleet health
fabric-aiops health uplink-rca # rank worst MX WAN uplinks + cause/action (meraki)
fabric-aiops device inventory --model MS # switches in the orgRun as an MCP server (stdio):
export FABRIC_AIOPS_MASTER_PASSWORD=... # unlock secrets non-interactively
fabric-aiops-mcpWhere that password then lives: an exported variable is readable by every process this shell starts and is recorded by shell history. On a shared or long-lived host, prefer the interactive prompt, or inject it from a secret manager for the life of the one command that needs it.
Governance
Every operation — MCP and CLI — passes through the bundled @governed_tool
harness. It records; it does not authorize (see above).
Audit — every call (params, outcome summary, status, duration, risk tier, and any operator-supplied approver/rationale) is logged to
~/.fabric-aiops/audit.db(relocatable viaFABRIC_AIOPS_HOME). The CLI writes the same row the MCP path does — there is no unaudited entry point.Runaway guard — a safety backstop, not an authorization gate: the same call hammered in a tight loop trips a circuit breaker so a stuck agent can't burn unbounded calls/time. Disable with
FABRIC_RUNAWAY_MAX=0; optional hard ceilings viaFABRIC_MAX_TOOL_CALLS/FABRIC_MAX_TOOL_SECONDS.Undo recording — reversible writes record an inverse descriptor built from the fetched before-state.
Risk tier — a descriptive label on the audit row derived from
risk_level; it gates nothing.
Scope
This is the network-fabric / controller member of the AIops-tools family
(governed AI-ops with audit + budget + undo + risk tiers). Do NOT use it for
OT / industrial edge (Modbus, OPC-UA, PROFINET) — see the separate
industrial-aiops line — nor for device-level CLI/SSH network automation.
Missing a capability?
Coverage is intentionally a curated subset of each controller's API. Missing a call or a device family on Meraki? A ❌ in the support matrix you need on Catalyst Center, CloudVision Portal, or UniFi Network (writes included — e.g. the UniFi cookie-login fallback for pre-9.0 controllers)? Want another controller platform entirely? Open an issue or PR — contributions welcome (a platform is a single descriptor module: path templates + response adapters).
Status
No platform has yet been exercised by this tool against a live Meraki
organization, Catalyst Center appliance, CloudVision Portal instance, UniFi
controller or APIC. The first four platforms' API paths are modelled from the
public API shapes and tested against mocks. The ACI reads are tested against
real, anonymized APIC responses from a production fabric (endpoint, EPG,
bridge domain, VRF, contract, filter entry, faults) and their query mechanics
against Cisco's own SDK — but a live run of this tool against an APIC is still
outstanding. docs/VERIFICATION.md defines the checklist
a live run must cover; fabric-aiops doctor is the fastest live check.
Available Tools
37 toolsaci_endpoint_traceARead-only
[READ] Reconstruct an ACI endpoint's static fabric path from its MAC or IP.
One call follows: endpoint → attachment (pod / leaf / interface or vPC) →
EPG → bridge domain → VRF → contracts the EPG provides/consumes → filter
entries, plus faults whose DN names the EPG or the attachment interface.
Every link is the relation APIC resolved (its tDn), so cross-tenant links
into 'common' are followed correctly.
How to read the result (do not over-state it):
* It is NOT a reachability test. 'staticPathResolved: true' means the
fabric is configured to carry the endpoint, not that traffic flows.
* 'relatedFaultCandidates' are matched by DN only — proximity, not cause.
Never report one as the reason for a problem. 'faults: null' means no
fault scan succeeded (related faults unknown, not none); 'complete:
false' means some scan failed, hit its page limit, or could not run.
* 'tagRelations' in state 'missing-target' are policy-tag lookups and say
nothing about the attachment path; do not report them as a path failure.
* A section that is null with an entry in 'errors' was NOT read — never
describe it as empty or absent. 'segmentResolved'/'staticPathResolved'
are null in that case, not false.
* A cleared fault keeps the description it had when raised; judge it by
severity/lifecycle, not by its text.
* 'contracts.complete: false' means a contract or filter was not read or
not returned (its entry says 'read: false', 'exists: false' or has
'entries: null') — its rules are unknown, not absent. The EPG → BD →
VRF verdict is unaffected.
* An 'epg' with 'supported: false' is a parent object this read does not
trace (e.g. an L2Out external EPG) — the chain is undetermined, not broken.
* 'notFound' means the fabric has not learned the address now, or it is in
a tenant this account cannot see — not that the host is down.
* 'notChecked' lists what this read does not evaluate (vzAny, taboo
contracts, imported contracts, preferred-group peers, service graphs).
Args:
mac: Endpoint MAC (any case; e.g. 00:50:56:AB:CD:EF). Pass mac OR ip.
ip: Endpoint IPv4/IPv6 address. Pass mac OR ip.
limit: Max matching endpoints to trace (default 5, max 20); the result
carries returned/limit/truncated.
fault_limit: Max related-fault candidates per endpoint (default 20).
target: Target name from config (must be 'platform: aci').
endpoint.recordedPathMatch compares APIC's fabricPathDn with the formed
attachment: "exact", "vpc-member" (APIC records a vPC-learned endpoint on one
member leaf, e.g. paths-301 for protpaths-301-302 — the same attachment, not
a move), "differs" (a medium finding that does not claim a move), or null (no recorded
path, or no formed relation — not compared; never a match). Paths behind a FEX
are not excused as vPC members.
Returns dict: {query, endpoints:[{endpoint, ips, attachment, attachmentFormed,
tagRelations, epg, bd, vrf, contracts, segmentResolved, notChecked,
relatedFaultCandidates, staticPathResolved, findings:[{rank, severity,
signal, cause, action}], errors}], returned, limit, truncated,
serverReportedMatches, lookupErrors, note, notFound?}.
Inputs: ip, mac, limit, target, +1 more.
aci_epg_segmentARead-only
[READ] An ACI EPG's segment: bridge domain, VRF and contracts, by name.
Follows EPG → BD → VRF through the relations APIC resolved (cross-tenant
links into 'common' included) and expands the contracts the EPG provides
and consumes down to filter entries. Use it when you know the EPG but not
an endpoint in it.
A relation that is not 'formed' is reported as a finding with its state; a
read that failed is null with an entry in 'errors' (not empty — say it was
not read). An unenforced VRF means contracts do not restrict traffic in it.
'notChecked' lists what is not evaluated (vzAny, taboo, imported
contracts, preferred-group peers, service graphs).
Args:
tenant: Tenant name (e.g. 'tenant-A').
app: Application profile name.
epg: EPG name.
target: Target name from config (must be 'platform: aci').
Returns dict: {epg, bd, vrf, contracts:{contracts, returned, limit,
truncated, filters, filtersTruncated, complete}, segmentResolved,
notChecked,
findings:[{rank, severity, signal, cause, action}], errors}.
Inputs: app (required), epg (required), tenant (required), target.
aci_faults_listARead-only
[READ] ACI fabric faults, worst severity first.
Rows are fault RECORDS, not incidents: a record with 'delegated: true'
mirrors a fault raised on another object, so one condition can appear
twice — do not count them as separate problems. 'active' comes from
severity only; a cleared fault ('active: false') keeps its original
description, which is not current state. 'bySeverity.serverReported' is
APIC's own totalCount per level. Within one severity, rows are sorted
newest first among the rows APIC returned; when a level is truncated, rows
beyond the page may be newer — raise the limit before claiming "latest".
Args:
severity: One of critical/major/minor/warning/info/cleared; omit for
every active level.
include_cleared: Also read cleared faults when no severity is given.
limit: Max rows (default 50, max 500). The result carries
returned/limit/truncated; re-run with a higher limit when
'truncated' is true rather than treating the list as complete.
target: Target name from config (must be 'platform: aci').
Returns dict: {severities, faults:[{rank, code, severity, active, lifecycle,
delegated, dn, scope, pod, node, aboutDn, cause, descr, changeSet,
lastTransition, ...}], returned, limit, truncated,
bySeverity:{serverReported}, delegatedRecords, note}.
Inputs: limit, target, severity, include_cleared.
bind_network_to_templateADestructive
[WRITE][risk=high] Bind a network to a config template, capturing prior binding.
REFUSES when the network is unbound and carries local VLANs: the bind
overwrites them with the template's, unbinding does not put them back, and
this tool has no VLAN-create operation — so the undo would report success
having restored nothing.
Undo, precisely: rebind to the prior template when there was one (a faithful
restore — the configuration was template-derived either way); unbind when
the network was unbound with a VERIFIED empty VLAN set (restores the binding
state only, NOT firewall rules / group policies / static routes); and NO
undo at all when the prior VLAN set could not be read.
Pass dry_run=True to preview. The preview runs the same refusal check
(reads only), so it never previews green a bind the real call would refuse.
Args:
network_id: Meraki network id to bind.
template_id: Config template id to bind to.
auto_bind: Auto-bind switch/AP profiles (Meraki autoBind flag).
dry_run: If True, preview without binding.
target: Target name from config; omit for the default.
Inputs: network_id (required), template_id (required), target, dry_run, +1 more.
blink_device_ledsADestructive
[WRITE][risk=medium] Blink a device's locator LEDs to find it physically.
No configuration change (a locate aid), so no undo is recorded. It is still
a POST to the controller, so it is tiered as a write: ``risk_level="low"``
is what marks a tool as a *read*. Tiering this "low" would misreport a POST
as a read in the audit trail, contradicting its own [WRITE] tag.
Args:
serial: Device serial.
duration: Blink duration in seconds (5..120, default 20).
target: Target name from config; omit for the default.
Inputs: serial (required), target, duration.
claim_devices_into_networkADestructive
[WRITE][risk=high] Claim devices into a network. Inverse: remove them.
Records the claimed serials so the harness can offer an undo (remove them).
Pass dry_run=True to preview.
Args:
network_id: Meraki network id to claim into.
serials: Device serials to claim.
dry_run: If True, preview without claiming.
target: Target name from config; omit for the default.
Inputs: serials (required), network_id (required), target, dry_run.
client_connectivityARead-only
[READ] A client's connection-quality stats (assoc/auth/dhcp/dns/success).
Args:
network_id: Meraki network id.
client_id: Client id/MAC (from client_list).
target: Target name from config; omit for the default.
Inputs: client_id (required), network_id (required), target.
client_getARead-only
[READ] One client's detail (description, MAC, IP, VLAN, manufacturer).
Args:
network_id: Meraki network id.
client_id: Client id/MAC (from client_list).
target: Target name from config; omit for the default.
Inputs: client_id (required), network_id (required), target.
client_listARead-only
[READ] Clients seen on a network within a look-back window.
Args:
network_id: Meraki network id (from network_list).
timespan: Look-back window in seconds (7200..2592000, default 86400).
target: Target name from config; omit for the default.
Inputs: network_id (required), target, timespan.
client_usageBRead-only
[READ] A client's usage history rolled up to total sent/received KB.
Args:
network_id: Meraki network id.
client_id: Client id/MAC (from client_list).
target: Target name from config; omit for the default.
Inputs: client_id (required), network_id (required), target.
config_template_driftARead-only
[READ] For networks bound to a config template, list drifted settings.
Compares each network bound to the template against the template's settings
by exact value and reports expected-vs-actual for every drifted key. Pure
analysis over injected data — no live pull.
Args:
template: {id, name, settings:{key: value}} — the config template.
networks: rows {networkId, name, boundTemplateId, settings:{key: value}};
only those whose boundTemplateId matches template['id'] are checked.
limit: Max rows in the drifted list (default 100). The result carries
'returned'/'limit'/'truncated'; re-run with a higher limit when
'truncated' is true rather than treating the list as complete.
Returns dict: {templateId, templateName, boundNetworks, driftedCount,
compliantCount, settingsChecked, driftedNetworks:[{networkId, name,
deviations:[{setting, expected, actual}]}], returned, limit, truncated,
note}.
Example: config_template_drift(
template={"id":"T1","name":"branch","settings":{"timezone":"UTC"}},
networks=[{"networkId":"N1","boundTemplateId":"T1",
"settings":{"timezone":"PST"}}]).
Inputs: networks (required), template (required), limit.
device_inventoryARead-only
[READ] Org device inventory, optionally filtered by model family.
Buckets devices by Meraki model prefix (MX security appliance, MS switch, MR
wireless AP, MV camera, MG cellular gateway) and returns per-family counts.
Args:
org_id: Meraki organization id; omit to use the target's default org.
model: Model family/prefix to filter (e.g. 'MS', 'MR46'); omit for all.
limit: Max rows in the returned list (default 500). The result carries
'returned'/'limit'/'truncated'; re-run with a higher limit when
'truncated' is true rather than treating the list as complete.
target: Target name from config; omit for the default.
Inputs: limit, model, org_id, target.
device_statusARead-only
[READ] One device's availability status (online/offline/alerting/dormant).
Args:
serial: Device serial (e.g. Q2XX-XXXX-XXXX).
org_id: Meraki organization id; omit to use the target's default org.
target: Target name from config; omit for the default.
Inputs: serial (required), org_id, target.
device_uplinksBRead-only
[READ] Appliance/gateway uplink statuses across the org (WAN interfaces).
Args:
org_id: Meraki organization id; omit to use the target's default org.
target: Target name from config; omit for the default.
Inputs: org_id, target.
network_alertsARead-only
[READ] Current network health alerts, summarised by severity.
Args:
network_id: Meraki network id (from network_list).
limit: Max rows in the returned list (default 200). The result carries
'returned'/'limit'/'truncated'; re-run with a higher limit when
'truncated' is true rather than treating the list as complete.
target: Target name from config; omit for the default.
Inputs: network_id (required), limit, target.
network_getARead-only
[READ] One network by id (name, product types, timezone, bound template).
Args:
network_id: Meraki network id (from network_list).
target: Target name from config; omit for the default.
Inputs: network_id (required), target.
network_health_scoreARead-only
[READ] Composite fleet health score per network (0-100), worst-first.
Folds device online %%, uplink health %%, and an alert-severity penalty into
one weighted score per network (0.5 / 0.3 / 0.2), every component returned so
the number is explainable. Pure analysis over injected rows — no live pull.
Args:
device_statuses: rows {serial, networkId, status, productType} (e.g. from
org_device_statuses' 'devices').
uplinks: optional rows {networkId, status} (active/ready = healthy).
alerts: optional rows {networkId, severity} (critical/warning/info).
limit: Max rows in the ranked list (default 100). The result carries
'returned'/'limit'/'truncated'; re-run with a higher limit when
'truncated' is true rather than treating the list as complete.
Returns dict: {networksEvaluated, fleetScore, summary:{healthy, degraded,
critical}, weights, worst:[{networkId, score, band, devicesOnline,
devicesTotal, onlinePct, uplinkHealthPct, alertPenalty}], returned,
limit, truncated, note}.
Example: network_health_score(device_statuses=[
{"networkId":"N1","status":"online"},
{"networkId":"N1","status":"offline"}]).
Inputs: device_statuses (required), limit, alerts, uplinks.
network_listARead-only
[READ] Networks in the organization (id, name, productTypes, tags).
Args:
org_id: Meraki organization id; omit to use the target's default org.
target: Target name from config; omit for the default.
Inputs: org_id, target.
network_trafficARead-only
[READ] Application/protocol traffic mix for a network, top apps by bytes.
Args:
network_id: Meraki network id (from network_list).
timespan: Look-back window in seconds (7200..2592000, default 86400).
limit: Max rows in the returned list (default 25). The result carries
'returned'/'limit'/'truncated'; re-run with a higher limit when
'truncated' is true rather than treating the list as complete.
target: Target name from config; omit for the default.
Inputs: network_id (required), limit, target, timespan.
network_vlansBRead-only
[READ] Appliance VLANs configured on a network (id, subnet, appliance IP).
Args:
network_id: Meraki network id (from network_list).
target: Target name from config; omit for the default.
Inputs: network_id (required), target.
org_adminsARead-only
[READ] Dashboard administrators for the org (name, email, access level).
Args:
org_id: Meraki organization id; omit to use the target's default org.
target: Target name from config; omit for the default.
Inputs: org_id, target.
org_api_requestsBRead-only
[READ] Org API-request usage overview (response-code counts, 429 rate-limits).
Args:
org_id: Meraki organization id; omit to use the target's default org.
target: Target name from config; omit for the default.
Inputs: org_id, target.
org_device_statusesARead-only
[READ] Org-wide device availability rolled up by status + product type.
Args:
org_id: Meraki organization id; omit to use the target's default org.
limit: Max rows in the returned list (default 500). The result carries
'returned'/'limit'/'truncated'; re-run with a higher limit when
'truncated' is true rather than treating the list as complete.
target: Target name from config; omit for the default.
Inputs: limit, org_id, target.
org_getARead-only
[READ] One organization by id (name, url, api access, cloud region).
Args:
org_id: Meraki organization id; omit to use the target's default org.
target: Target name from config; omit for the default.
Inputs: org_id, target.
org_licensingARead-only
[READ] Org licensing overview: status, expiration, per-device-type counts.
Args:
org_id: Meraki organization id; omit to use the target's default org.
target: Target name from config; omit for the default.
Inputs: org_id, target.
org_listARead-only
[READ] Organizations visible to the API key (id, name, url, apiEnabled).
Args:
target: Target name from config; omit for the default.
Inputs: target.
overviewARead-only
[READ] One-shot fabric fleet health: networks + device status/product rollup.
Call this first to triage a Meraki organization before drilling into a
specific network or device.
Args:
org_id: Meraki organization id; omit to use the target's default org.
target: Target name from config; omit for the default.
Inputs: org_id, target.
reboot_deviceADestructive
[WRITE][risk=high] Reboot a device (no safe inverse).
Records the device's prior status for the audit trail; a reboot cannot be
undone, so no undo descriptor is offered. Pass dry_run=True to preview.
Args:
serial: Device serial to reboot.
dry_run: If True, preview without rebooting.
target: Target name from config; omit for the default.
Inputs: serial (required), target, dry_run.
remove_device_from_networkADestructive
[WRITE][risk=high] Remove device(s) from a network. Inverse: claim back.
The devices' current network is captured for undo, so the undo token is
genuinely applicable — but claiming a device back restores MEMBERSHIP, not
CONFIGURATION. A removed device is reset to an unconfigured state; it
returns with the network's defaults, without the name, tags, address, notes
or switch-port settings it carried before. Read those with device_status /
switch_ports first if you will need them back.
Pass dry_run=True to preview. Accepts a single ``serial`` or a ``serials``
list — the list form is how claim_devices_into_network's undo replays.
Args:
network_id: Meraki network id the devices are bound to.
serial: One device serial to remove (or use ``serials``).
serials: Device serials to remove (mutually exclusive with ``serial``).
dry_run: If True, preview without removing.
target: Target name from config; omit for the default.
Inputs: network_id (required), serial, target, dry_run, +1 more.
switch_portsBRead-only
[READ] Switch (MS) port configuration for a device by serial.
Args:
serial: MS switch serial.
target: Target name from config; omit for the default.
Inputs: serial (required), target.
unbind_network_from_templateADestructive
[WRITE][risk=high] Unbind a network from its config template. Inverse: rebind.
Captures the template the network was bound to, so undo rebinds to it. Pass
dry_run=True to preview.
Args:
network_id: Meraki network id to unbind.
dry_run: If True, preview without unbinding.
target: Target name from config; omit for the default.
Inputs: network_id (required), target, dry_run.
undo_applyADestructive
[WRITE][risk=medium] Apply a recorded undo by dispatching its inverse tool.
The inverse runs through its own governed tool, so its real risk tier is
recorded there. Pass dry_run=True to preview the inverse call without
executing it. A token can only be applied once.
Args:
undo_id: The undoId from undo_list (or an ``_undo_id`` in a write result).
dry_run: If True, preview the inverse tool + params without running it.
target: Passed through to the inverse tool when it accepts a target.
Inputs: undo_id (required), target, dry_run.
undo_listARead-only
[READ] List recorded, not-yet-applied undo tokens (most recent first).
Each entry names the original tool, the inverse tool that ``undo_apply``
would run, and a human note. Use the ``undoId`` with ``undo_apply``.
One extra row is fetched so ``truncated`` is **measured**, not guessed from
the returned count happening to equal the limit — a capped list that cannot
say "there is more" invites a weak model to report it as the whole story.
Each entry carries ``effectVerified``. False means the original write
lost its response, so the change it reverses is PROBABLE, not confirmed —
check the live state before applying, and do not report the result as a
restore of a state that may never have been reached.
Args:
limit: Max rows to return (default 50).
target: Unused (undo state is host-local); accepted for CLI uniformity.
Inputs: limit, target.
update_deviceADestructive
[WRITE][risk=medium] Update device attributes (name/tags/address/notes).
Captures the changed keys' prior values before the change, so the harness
records an undo (restore the prior values) and a faithful audit trail. Pass
dry_run=True to preview.
Args:
serial: Device serial.
attrs: Attributes to set — allowed keys: name, tags, address, notes,
lat, lng, floorPlanId.
dry_run: If True, preview without changing.
target: Target name from config; omit for the default.
Inputs: attrs (required), serial (required), target, dry_run.
update_network_vlanADestructive
[WRITE][risk=medium] Update an appliance VLAN, capturing its prior values.
Captures the changed keys' prior values before the change (undo restores
them). Pass dry_run=True to preview.
Args:
network_id: Meraki network id.
vlan_id: VLAN id to update.
attrs: Attributes to set — allowed keys: name, subnet, applianceIp,
groupPolicyId, dhcpHandling.
dry_run: If True, preview without changing.
target: Target name from config; omit for the default.
Inputs: attrs (required), vlan_id (required), network_id (required), target, +1 more.
uplink_loss_and_latency_rcaARead-only
[READ] Rank the worst MX WAN uplinks by loss + latency, map cause + action.
The flagship uplink RCA: pulls per-uplink loss/latency across the org (MX
security appliances), ranks the worst uplinks by a composite of average loss
and latency, flags each degraded uplink against the thresholds, and attaches
a likely cause and a recommended action. Every ranking carries its numbers,
not a black-box verdict. Pass 'records' for pure analysis, or an org/target
to pull live.
Args:
loss_pct: Avg loss %% at/above which an uplink is degraded (default 5.0).
latency_ms: Avg latency ms at/above which an uplink is degraded (default 150).
records: Injected uplink series — {serial, networkId, uplink, ip,
timeSeries:[{lossPercent, latencyMs}]}; skips live collection.
org_id: Meraki organization id for live pull; omit to use target default.
limit: Max rows in the ranked list (default 100). The result carries
'returned'/'limit'/'truncated'; re-run with a higher limit when
'truncated' is true rather than treating the list as complete.
target: Target name from config; omit for the default.
Returns dict: {uplinksEvaluated, degradedCount, thresholds, worst:[{serial,
networkId, uplink, ip, avgLossPct, maxLossPct, avgLatencyMs, maxLatencyMs,
degraded, cause, action}], returned, limit, truncated, note}.
Inputs: limit, org_id, target, records, +2 more.
wireless_ssidsARead-only
[READ] Wireless (MR) SSIDs configured on a network (number, name, enabled).
Args:
network_id: Meraki network id (from network_list).
target: Target name from config; omit for the default.
Inputs: network_id (required), target.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 37 tools
Most tools target a clearly distinct resource+action (client_get vs client_usage vs client_connectivity, aci_endpoint_trace vs aci_epg_segment, bind/unbind, claim/remove). The main overlap risk is among the health/summary reads — overview, org_device_statuses, device_status, network_health_score, and network_alerts all touch fleet/device health — but descriptions differentiate live rollups from single-entity reads from pure analysis. Only a few boundary pairs could occasionally be confused.
All names are snake_case, but conventions are mixed: read tools are noun-first (org_list, network_vlans, client_get, device_uplinks) while write tools are verb-first (reboot_device, update_device, claim_devices_into_network). Within a single prefix the second token also flips between verbs and nouns (org_list/org_get vs org_licensing/org_admins). Readable, but not one predictable pattern.
37 tools is heavy and sits above the comfortable 3-15 band, but the surface spans two distinct platforms (Meraki org/network/device/client/switch/wireless plus ACI fabric), three pure-analysis tools, and a governed write/undo layer, so most tools earn their place. It is borderline-heavy rather than padded.
Read coverage is broad and coherent (org, network, device, client, switch, wireless, ACI endpoints/EPGs/faults), writes cover the main remediation actions with undo tokens, and undo_list/undo_apply close the write loop. Gaps are minor: no network create/delete, no VLAN/SSID/switch-port creation or full config write, and ACI is read-only — workable but not full lifecycle.
Maintenance
Related MCP Connectors
Autonomous and governed SRE & MLOps control plane for AI agent platforms.
Governed MCP workflow automation for MSPs and agencies: approvals, durable state, signed evidence.
Deterministic IT asset registry operated by AI agents over MCP. Agents propose, humans approve.
One MCP URL for all your connectors — scoped writes, enforced constraints, and a full audit trail.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceProvides dynamic access to 400+ Meraki Dashboard API endpoints with intelligent discovery, plus advanced compliance auditing (PCI DSS, HIPAA, SOC2, ISO 27001, NIST), backup/restore operations, and network security analysis. Enables natural language queries to manage Meraki networks without pre-defined tools.4-
- AlicenseAqualityBmaintenanceGoverned Prometheus + Grafana operations — firing-alert and scrape-target RCA, alert noise/flapping analysis, silences, and dashboards, with unbypassable audit logging (MCP + CLI), budget/runaway guards, dry-run, and undo/rollback.39MIT
- AlicenseAqualityBmaintenanceGoverned OPNsense + pfSense firewall operations — gateway-health, rule-shadow, and blocked-traffic RCA, with guarded rule/alias writes, unbypassable audit logging (MCP + CLI), budget/runaway guards, dry-run, and undo/rollback.352MIT
- AlicenseAqualityBmaintenanceGoverned reverse-proxy operations for Traefik, Caddy, and HAProxy — backend-health, cert-expiry, 5xx, and route-conflict RCA, with unbypassable audit logging (MCP + CLI), budget/runaway guards, dry-run, and undo/rollback.28MIT