Skip to main content
Glama

Cisco Meraki / Catalyst / ACI & Multi-vendor Controller AIops

Audit availability: Real writes require a committed pending audit 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 mcp or fabric-aiops-mcp): 37 tools (28 read, 9 write), every one wrapped with the bundled @governed_tool harness.

  • 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 from FABRIC_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_vlan restore 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-run and requires double confirmation; every write MCP tool takes a dry_run preview.

Capability matrix (37 MCP tools)

Domain

Tools

Count

R/W

Overview

overview

1

read

Organizations

org_list, org_get, org_licensing, org_admins, org_device_statuses, org_api_requests

6

read

Networks

network_list, network_get, network_vlans, network_alerts, network_traffic

5

read

Devices

device_inventory, device_status, device_uplinks, switch_ports, wireless_ssids

5

read

Clients

client_list, client_get, client_usage, client_connectivity

4

read

Health (flagship)

uplink_loss_and_latency_rca, network_health_score, config_template_drift

3

read

Cisco ACI (APIC only)

aci_endpoint_trace, aci_epg_segment, aci_faults_list

3

read

Remediation

reboot_device, claim_devices_into_network, remove_device_from_network, bind_network_to_template, unbind_network_from_template

5

write (high)

update_device, update_network_vlan

2

write (medium)

blink_device_leds

1

write (low)

Undo

undo_list

1

read

undo_apply

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

overview (org/site/container rollup)

✅

✅

✅

✅

org_list / org_get

✅

✅ sites

✅ containers

✅ sites (list; get ❌)

org_licensing, org_api_requests

✅

❌

❌

❌

org_admins

✅

❌

✅ users

❌

org_device_statuses

✅

✅ device-health

✅ inventory + streaming status

✅ stat/device (state, uptime, firmware)

network_list / network_get

✅

✅ site-health / site

✅ containers

✅ sites / stat/health (subsystem rollup)

network_vlans, network_traffic

✅

❌

❌

❌

network_alerts

✅

✅ issues (P1→critical, P2→warning)

✅ events

✅ alarms (*_Lost_Contact→critical)

device_inventory, device_status

✅

✅ network-device

✅ inventory (+ complianceCode drift signal)

✅ stat/device (id = device MAC)

device_uplinks

✅

❌

❌

❌

switch_ports

✅

✅ interface stats (pass the device uuid)

❌

✅ device port_table (pass the device MAC)

wireless_ssids

✅

❌

❌

❌

client_list / client_get

✅

✅ client-health (aggregate) / client-detail (by MAC)

❌

✅ stat/sta (connected) / stat/user (by MAC)

client_usage, client_connectivity

✅

❌

❌

❌

uplink_loss_and_latency_rca (live pull)

✅

❌ (injected records still work)

❌ (injected records still work)

❌ (injected records still work)

network_health_score, config_template_drift (injected-only)

✅

✅

✅

✅

reboot_device

✅

❌ teaching error

❌ teaching error

✅ cmd/devmgr restart-device

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

aci_endpoint_trace (aci trace --mac/--ip)

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

aci_epg_segment (aci segment TENANT APP EPG)

The same EPG → BD → VRF → contracts chain from an EPG name

aci_faults_list (aci faults)

Fabric faults, worst severity first

How to read them:

  • A static reconstruction, not a reachability test. staticPathResolved: true means 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 into common are followed; a relation that is not formed is 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 delegated record 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

platform:

Secret stored (encrypted)

Auth on the wire

Base URL

Cisco Meraki Dashboard

meraki

API key (Dashboard → Organization → Settings → API access)

Authorization: Bearer (or auth_style: meraki-key → X-Cisco-Meraki-API-Key)

default https://api.meraki.com/api/v1

Cisco Catalyst Center

catalyst

username:password (one string)

exchanged via POST /dna/system/api/v1/auth/token (HTTP Basic) for a ~1 h X-Auth-Token, auto-refreshed once on a 401

required, e.g. https://<catalyst-center-host>

Arista CloudVision Portal

cvp

service-account token (Settings → Access Control → Service Accounts)

Authorization: Bearer

required, e.g. https://<cvp-host>

Cisco ACI (APIC)

aci

username:password (one string; a read-only role is enough — every ACI read is a GET, only the login is a POST)

POST /api/aaaLogin.json opens a session carried as a cookie; extended via /api/aaaRefresh.json at half its lifetime; one fresh login on a 401/403 (APIC reports an expired session as 403)

required, e.g. https://<apic-host>

UniFi Network

unifi

API key (UniFi OS: Settings → Control Plane → Integrations; self-hosted Network Server 9.0+)

X-API-KEY (stateless; legacy cookie login is a known deferral)

required — classic controller https://<host>:8443, or UniFi OS console https://<console>/proxy/network (keep the prefix)

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-tools

The 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: yes

Restart 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 org

Run as an MCP server (stdio):

export FABRIC_AIOPS_MASTER_PASSWORD=...   # unlock secrets non-interactively
fabric-aiops-mcp

Where 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 via FABRIC_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 via FABRIC_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 tools
aci_endpoint_traceA
Read-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_segmentA
Read-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_listA
Read-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_templateA
Destructive

[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.

claim_devices_into_networkA
Destructive

[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_connectivityA
Read-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_getA
Read-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_listA
Read-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_usageB
Read-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_driftA
Read-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_inventoryA
Read-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_statusA
Read-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.

network_alertsA
Read-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_getA
Read-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_scoreA
Read-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_listA
Read-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_trafficA
Read-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_vlansB
Read-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_adminsA
Read-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_requestsB
Read-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_statusesA
Read-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_getA
Read-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_licensingA
Read-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_listA
Read-only

[READ] Organizations visible to the API key (id, name, url, apiEnabled).

Args:
    target: Target name from config; omit for the default.

Inputs: target.

overviewA
Read-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_deviceA
Destructive

[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_networkA
Destructive

[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_portsB
Read-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_templateA
Destructive

[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_applyA
Destructive

[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_listA
Read-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_deviceA
Destructive

[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_vlanA
Destructive

[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.

wireless_ssidsA
Read-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

    A3.6/5.0

    Scored across 37 tools

    Disambiguation4/5

    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.

    Naming Consistency3/5

    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.

    Tool Count3/5

    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.

    Completeness4/5

    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

    ActivityActive
    ResponsivenessOutdated data

    Related MCP Connectors

    Related MCP Servers

    • F
      license
      Not graded
      quality
      D
      maintenance
      Provides 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
      -
    • A
      license
      A
      quality
      B
      maintenance
      Governed 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.
      39
      MIT
    • A
      license
      A
      quality
      B
      maintenance
      Governed 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.
      35
      2
      MIT
    • A
      license
      A
      quality
      B
      maintenance
      Governed 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.
      28
      MIT