Skip to main content
Glama

network-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: This is a community-maintained open-source project and is not affiliated with, endorsed by, or sponsored by Cisco, Arista, Juniper, NetBox Labs, or any network vendor. Vendor and product names are trademarks of their respective owners. Source code is publicly auditable at github.com/AIops-tools/Network-AIops under the MIT license.

Governed multi-vendor network device operations for AI agents — 33 MCP tools, every one wrapped with the bundled @governed_tool harness: a local unified audit log under ~/.network-aiops/, token/runaway budget guard, undo-token recording, and descriptive risk-tier labels. Credentials (device passwords + the NetBox token) are kept in an encrypted store (secrets.enc), never plaintext on disk.

Devices are reached over NAPALM; an optional NetBox block adds source-of-truth lookups.

Standalone: the governance harness is bundled in the package (network_aiops.governance) — network-aiops has no external skill-family dependency. Coverage focuses on common device operations and is not yet exhaustive.

Verification status: the test suite is mock-based; not yet validated against live devices — self-testable with cEOS / vMX / containerlab. See docs/VERIFICATION.md.

What works

Read device facts, interfaces (+ counters/IP), BGP/LLDP neighbors (summary and detail), ARP/MAC tables, VLANs, route lookups, hardware environment, optics, NTP, users, SNMP info, VRFs, and an aggregated device_health; run read-only RCA diagnostics that flag down/erroring/flapping interfaces and unhealthy BGP neighbors — each finding citing the measured number that tripped it; back up the running config, dry-run a config diff, and merge/replace/rollback config — across the five core NAPALM platforms below. Optional NetBox lookups (devices + interfaces) confirm intended state before a change.

NAPALM does not implement every getter on every platform; an unsupported getter returns a teaching error ("not supported by the <driver> driver") rather than crashing. Secrets are never returned — get_users redacts password hashes and get_snmp_information redacts community strings.

Related MCP server: Cisco Meraki MCP Server

Supported devices

Platform

NAPALM driver

Transport

Cisco IOS / IOS-XE

ios

SSH

Cisco Nexus NX-OS

nxos (NX-API) / nxos_ssh (SSH)

HTTPS / SSH

Cisco IOS-XR

iosxr

SSH (XML agent)

Arista EOS

eos

eAPI (HTTPS)

Juniper Junos

junos

NETCONF (SSH)

Additional platforms (Nokia SR OS / SR Linux, Huawei VRP, etc.) are reachable via NAPALM community drivers but are not officially tested here. Need one? See Contributing.

Supported actions

Action

Tool

R/W

Risk

Device facts (hostname/vendor/model/OS/serial/uptime)

device_facts

R

low

Interfaces (up/down, speed, description)

get_interfaces

R

low

Interface traffic + error counters

get_interfaces_counters

R

low

Interface IP addresses

get_interfaces_ip

R

low

BGP neighbors (summary / detail)

get_bgp_neighbors / get_bgp_neighbors_detail

R

low

LLDP neighbors (summary / detail)

get_lldp_neighbors / get_lldp_neighbors_detail

R

low

ARP table

get_arp_table

R

low

MAC address table

get_mac_address_table

R

low

VLANs

get_vlans

R

low

Route lookup

get_route_to

R

low

Hardware environment (fans/temp/power/CPU/mem)

get_environment

R

low

Optical transceiver levels

get_optics

R

low

NTP servers / sync stats

get_ntp_servers / get_ntp_stats

R

low

Local users (hashes redacted)

get_users

R

low

SNMP info (communities redacted)

get_snmp_information

R

low

Network instances (VRFs)

get_network_instances

R

low

Aggregated device health

device_health

R

low

Interface health RCA (down / errors / discards / flaps)

interface_health_rca

R

low

BGP neighbor RCA (down / shut / reset / route-less)

bgp_neighbor_rca

R

low

Back up running config

config_backup

R

low

Diff a candidate (dry-run)

config_diff

R

low

Merge config + commit

config_merge

W

medium

Replace full config + commit

config_replace

W

high

Roll back last commit

config_rollback

W

medium

NetBox list devices

netbox_list_devices

R

low

NetBox get device

netbox_get_device

R

low

NetBox device interfaces

netbox_device_interfaces

R

low

List recorded reversible writes

undo_list

R

low

Apply a recorded inverse (governed, single-use, dry-run capable)

undo_apply

W

medium

What this tool does, and does not, decide

It delivers multi-vendor network device (NAPALM) + NetBox 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: log in with a device account at a read-only privilege level (and give NetBox a read-only API token), and the writes fail at the server — 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 ~/.network-aiops/audit.db, and destructive writes still capture their before-state and record an inverse where one exists.

Each tool declares a risk_level, carried into the audit row as a descriptive tier (none/confirm/review) — so a reviewer can see at a glance that a row was a high-risk delete. It is a label, not a gate.

Running a smaller / local model? See agent-guardrails.md — it lists the guardrails this tool enforces for you (so you don't spend prompt budget restating them) and gives a ready-made system prompt for what's left.

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 network-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 network-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/network-aiops
openclaw skills info network-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 network-aiops
network-aiops init                                  # wizard: device + driver + host + encrypted password
network-aiops doctor
network-aiops device facts -t core-sw1
network-aiops device health -t core-sw1
network-aiops diagnose interface-health -t core-sw1   # worst-first interface RCA
network-aiops diagnose bgp -t core-sw1                # worst-first BGP-neighbor RCA
network-aiops config backup -t core-sw1 -o core-sw1.cfg
# 1. Ask the device what's actually wrong — findings are ranked worst-first and
#    each cites the measured value (error count, last-flap seconds, uptime).
network-aiops diagnose interface-health -t core-sw1
network-aiops diagnose bgp -t core-sw1

# 2. If interface-health flags a link admin-up/oper-down with climbing errors and
#    BGP shows the peer on that path recently reset, you have your root cause: a
#    physical-layer fault (cable/optic) resetting the session — not routing.

# 3. Confirm intended state, then remediate with the governed, audited path.
network-aiops device counters -t core-sw1
network-aiops config diff -t core-sw1 -f fix.cfg      # dry-run the change first

Create ~/.network-aiops/config.yaml:

devices:
  - name: core-sw1            # used as -t core-sw1
    driver: eos               # ios | nxos | nxos_ssh | iosxr | eos | junos
    host: 10.0.0.1
    username: admin
    optional_args:            # passed verbatim to NAPALM (optional)
      secret: enable-pw       # enable/secret
      port: 443
# Optional source-of-truth:
netbox:
  url: https://netbox.example.com

Secrets are stored encrypted in ~/.network-aiops/secrets.enc (Fernet/AES + scrypt-derived key; chmod 600) — never in config.yaml or a plaintext .env. Device passwords are keyed by device name; the NetBox token uses the reserved name netbox-token:

network-aiops init                     # interactive wizard (recommended)
network-aiops secret set core-sw1      # store a device password (hidden prompt)
network-aiops secret set netbox-token  # store the NetBox API token
network-aiops secret list              # names only — values are never printed
network-aiops secret migrate           # import a legacy plaintext .env, then delete it

Export NETWORK_AIOPS_MASTER_PASSWORD to unlock the store non-interactively (MCP server / cron). Legacy plaintext env vars (NETWORK_<TARGET_UPPER>_PASSWORD, NETWORK_NETBOX_TOKEN) remain a deprecated fallback. An empty device password is allowed for key-based SSH auth.

MCP

{
  "command": "network-aiops",
  "args": ["mcp"],
  "env": {
    "NETWORK_AIOPS_CONFIG": "~/.network-aiops/config.yaml",
    "NETWORK_AIOPS_MASTER_PASSWORD": "…"   // unlocks the encrypted secret store
  }
}

Audit & Safety

  • Every tool call is logged to ~/.network-aiops/audit.db (local SQLite; relocate with NETWORK_AIOPS_HOME).

  • config_merge / config_replace capture the pre-change running config and record an inverse config_replace-to-backup undo descriptor.

  • config_replace is risk_level=high; CLI destructive commands (config merge/replace/rollback) require double confirmation and support --dry-run (which prints the diff without committing).

  • All device text passes through sanitize() (output hygiene: control/format-char stripping + truncation).

  • Device passwords and the NetBox token live only in the encrypted secrets.enc (chmod 600); tools never return passwords, SNMP community strings, or hashes.

See skills/network-aiops/SKILL.md and SECURITY.md for details.

Companion Skills

If you want…

Use

Network device config / facts (Cisco/Arista/Juniper)

network-aiops (this)

Kubernetes cluster operations

a cluster ops skill

Hypervisor VM lifecycle

a hypervisor ops skill

Contributing & feature requests

Coverage is intentionally focused. Need a device or action that isn't here yet? Open an issue or pull request at github.com/AIops-tools/Network-AIops — contributions, feature requests, and comments are all welcome.

License

MIT — github.com/AIops-tools/Network-AIops

Available Tools

33 tools
bgp_neighbor_rcaA
Read-only

[READ] Flag BGP neighbors that are down, shut, recently reset, or route-less.

Pulls get_bgp_neighbors and reports worst-first findings, each citing the session state (is_up / is_enabled) or uptime, with a cause and an action (check peer reachability / ACL / MD5 auth).

Args: target: Device name from config; omit to use the default device.

Inputs: target.

config_backupA
Read-only

[READ] Return the device running config, credential values masked by default.

Password/secret hashes, SNMP communities, SNMPv3 auth+priv keys, IKE pre-shared keys and RADIUS/TACACS/keychain keys are replaced with ""; every other line comes back untouched, so interface, routing and policy config reads exactly as the device wrote it.

The result always carries a "redaction" block saying how many lines were changed. Redaction is pattern-based across five vendor syntaxes, so it REDUCES exposure rather than guaranteeing none remains — in particular it cannot see multi-line PKI key blocks.

Prefer the CLI's '-o ' flag over include_secrets when a human needs the real config: it writes the raw text to a file instead of into this transcript.

Args: include_secrets: True to return the verbatim config, credentials and all. Every secret in it then lives wherever this result is stored. target: Device name from config; omit to use the default device.

Inputs: target, include_secrets.

config_diffA
Read-only

[READ] DRY-RUN: stage a candidate, return the diff, then discard it.

Nothing is committed. This is the dry-run primitive for previewing a change.

The diff is credential-redacted like config_backup, and for the same reason: a diff that ADDS 'snmp-server community X' contains X, and one that removes a line quotes the credential the device already had. The result carries a "redaction" block with the count.

Args: config_text: The configuration snippet (merge) or full config (replace). replace: True to diff as a full-config replacement; False (default) to merge. include_secrets: True to return the verbatim diff — use when verifying that the literal key you are pushing is the one that will land. target: Device name from config.

Inputs: config_text (required), target, replace, include_secrets.

config_mergeA
Destructive

[WRITE] Merge a config snippet and commit under a device-side revert timer.

The device REVERTS the change by itself after revert_in seconds unless confirm_commit follows — so a change that severs your own management access heals without anyone having to reach the box. Verify reachability, THEN call confirm_commit. Check commit.safetyNet in the result: drivers that cannot arm a timer commit permanently and say so in commit.warning.

Returns diff and a backup digest (size + sha256). The full config is deliberately NOT returned — it carries credential hashes and PSKs — but the raw text is retained in undo.db for the recorded rollback. The diff is credential-redacted with no opt-out (see the redaction block); use config_diff(include_secrets=True) first if you must verify a literal key.

dry_run=True stages the candidate, returns the diff, discards it, and runs the SAME refusal the real commit would — so a green preview is never followed by a refusal.

Args: config_text: The configuration snippet to merge. revert_in: Device-side revert timer in seconds (default 300). 0 disables it, leaving the recorded undo as the only rollback path. dry_run: If True, preview the diff + safety assessment without committing. target: Device name from config.

Inputs: config_text (required), target, dry_run, revert_in.

config_replaceA
Destructive

[WRITE] Replace the full config and commit under a revert timer. HIGH RISK.

Same commit-confirm contract as config_merge: the device reverts after revert_in seconds unless confirm_commit follows. Verify reachability first, then confirm. Check commit.safetyNet — when no timer could be armed the change is permanent on landing.

Returns diff and a backup digest; the raw pre-change config is kept in undo.db (0600) for the recorded rollback, not echoed back here. The diff is credential-redacted with no opt-out (see the redaction block); use config_diff(include_secrets=True) first if you must verify a literal key.

dry_run=True previews the diff and runs the same refusal the real commit would, so the preview can never disagree with the commit.

Args: config_text: The full replacement configuration. revert_in: Device-side revert timer in seconds (default 300). 0 disables it, leaving the recorded undo as the only rollback path. dry_run: If True, preview the diff + safety assessment without committing. target: Device name from config.

Inputs: config_text (required), target, dry_run, revert_in.

config_rollbackA
Destructive

[WRITE] Revert the last committed change via NAPALM rollback(). No undo.

Device support varies (rollback depth is platform-dependent).

dry_run=True cannot predict the resulting config without the device, so it opens a session (verifying reachability) and reports a digest of the current running config — the state rollback would replace — without rolling back.

Args: dry_run: If True, verify reachability and state what rollback would attempt. target: Device name from config.

Inputs: target, dry_run.

confirm_commitA
Destructive

[WRITE] Confirm a pending commit-confirm change, cancelling its revert timer.

The second half of the commit-confirm workflow. Run it only AFTER verifying the device is still reachable and healthy — doing nothing is the safe alternative, because the device then reverts on its own.

dry_run=True reads whether a commit-confirm is actually pending (nothing is confirmed; the revert timer keeps running).

Args: dry_run: If True, report whether a pending commit exists without confirming. target: Device name from config.

Inputs: target, dry_run.

device_factsA
Read-only

[READ] Core device facts: hostname, vendor, model, OS version, serial, uptime.

Also returns the interface name list. Use get_interfaces for per-interface state/speed.

Args: target: Device name from config; omit to use the default device.

Inputs: target.

device_healthA
Read-only

[READ] Aggregated health: facts + interface up/down counts + environment.

Resilient to drivers lacking get_environment (that section becomes a note). Returns a 'healthy' flag and an 'issues' list summarising attention points.

Args: target: Device name from config; omit to use the default device.

Inputs: target.

get_arp_tableB
Read-only

[READ] ARP table entries: interface, IP, MAC, age.

Args: target: Device name from config.

Inputs: target.

get_bgp_neighborsB
Read-only

[READ] BGP neighbors per VRF: peer, remote AS, up state, prefix counts.

Args: target: Device name from config.

Inputs: target.

get_bgp_neighbors_detailA
Read-only

[READ] Detailed BGP neighbors per VRF: state, router id, AS, prefix stats.

Args: target: Device name from config; omit to use the default device.

Inputs: target.

get_environmentA
Read-only

[READ] Hardware environment: fans, temperature, power, CPU, memory.

Args: target: Device name from config; omit to use the default device.

Inputs: target.

get_interfacesB
Read-only

[READ] Interfaces with up/down state, enabled flag, speed, and description.

Args: target: Device name from config.

Inputs: target.

get_interfaces_countersB
Read-only

[READ] Per-interface traffic + error counters (octets, packets, errors, discards).

Args: target: Device name from config.

Inputs: target.

get_interfaces_ipB
Read-only

[READ] Per-interface IPv4/IPv6 addresses and prefix lengths.

Args: target: Device name from config.

Inputs: target.

get_lldp_neighborsB
Read-only

[READ] LLDP neighbors: local port, remote hostname, remote port.

Args: target: Device name from config.

Inputs: target.

get_lldp_neighbors_detailB
Read-only

[READ] Detailed LLDP neighbors: chassis id, system name/description, capabilities.

Args: target: Device name from config.

Inputs: target.

get_mac_address_tableB
Read-only

[READ] MAC address table: MAC, interface, VLAN, static/active flags.

Args: target: Device name from config.

Inputs: target.

get_network_instancesB
Read-only

[READ] Network instances (VRFs): name, type, state, member interfaces.

Args: target: Device name from config.

Inputs: target.

get_ntp_serversA
Read-only

[READ] Configured NTP servers.

Args: target: Device name from config.

Inputs: target.

get_ntp_statsB
Read-only

[READ] NTP peer synchronization stats (stratum, offset, jitter, reachability).

Args: target: Device name from config.

Inputs: target.

get_opticsB
Read-only

[READ] Optical transceiver levels per interface/channel (rx/tx power, bias).

Args: target: Device name from config.

Inputs: target.

get_route_toA
Read-only

[READ] Routing-table lookup for a destination prefix (optionally by protocol).

Args: destination: The destination prefix to look up (e.g. 10.0.0.0/24). protocol: Optional protocol filter (e.g. bgp, ospf, static). target: Device name from config.

Inputs: destination (required), target, protocol.

get_snmp_informationA
Read-only

[READ] SNMP metadata: chassis id, contact, location. Community strings redacted.

Args: target: Device name from config.

Inputs: target.

get_usersA
Read-only

[READ] Local users and privilege levels. Password hashes are NOT returned.

Args: target: Device name from config.

Inputs: target.

get_vlansB
Read-only

[READ] VLANs: id, name, and member interfaces (driver support varies).

Args: target: Device name from config.

Inputs: target.

interface_health_rcaA
Read-only

[READ] Flag admin-up/oper-down, erroring, discarding, or flapping interfaces.

Pulls get_interfaces + get_interfaces_counters and reports worst-first findings — each citing the measured number (error/discard count, last-flap seconds) that tripped it, with a cause and a concrete action.

Args: target: Device name from config; omit to use the default device.

Inputs: target.

netbox_device_interfacesA
Read-only

[READ] List a NetBox device's interfaces (name, type, enabled, description).

The intended interface inventory from source-of-truth — compare against live device state (get_interfaces) to spot drift.

Returns {"interfaces": [...], "returned": N, "limit": L, "truncated": bool}. Do NOT report drift from a truncated list — re-run with a higher limit.

Args: device: Exact NetBox device name (see netbox_list_devices). limit: Maximum interfaces to return (default 100).

Inputs: device (required), limit.

netbox_get_deviceA
Read-only

[READ] Return a single NetBox device by exact name.

Args: name: Exact NetBox device name (see netbox_list_devices).

Inputs: name (required).

netbox_list_devicesA
Read-only

[READ] List NetBox devices (name, role, site, status, primary IP).

Requires a configured NetBox block. Use this to confirm intended state before pushing config to a device.

Returns {"devices": [...], "returned": N, "limit": L, "truncated": bool}. When truncated is true the estate is larger than what you were shown — re-run with a higher limit before concluding anything about coverage.

Args: name: Optional name filter (contains match). limit: Maximum devices to return (default 50).

Inputs: name, limit.

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 in that tool's audit row. 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.

Returns {"undos": [...], "returned": N, "limit": L, "truncated": bool}. truncated is measured (one extra row is fetched), not guessed from a length coincidence: when it is true there are MORE tokens than shown, so re-run with a higher limit rather than reporting the list as complete.

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, capped at 500). target: Unused (undo state is host-local); accepted for CLI uniformity.

Inputs: limit, target.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A3.5/5.0

    Scored across 33 tools

    Disambiguation3/5

    Several tool families overlap in purpose: get_bgp_neighbors vs get_bgp_neighbors_detail vs bgp_neighbor_rca, get_lldp_neighbors vs get_lldp_neighbors_detail, config_diff vs config_merge/replace dry_run, and device_health vs its underlying getters. Descriptions clarify the distinctions, but an agent still faces non-trivial choices among near-equivalent read/diagnostic tools.

    Naming Consistency4/5

    Names are all snake_case and mostly follow domain prefixes (get_, config_, netbox_, undo_, *_rca, device_). Minor deviations exist, such as device_facts/device_health lacking get_, and netbox_device_interfaces lacking a verb while netbox_list_devices and netbox_get_device include one.

    Tool Count2/5

    33 tools is high for a single MCP server and exceeds the 25-tool threshold where count becomes unwieldy. Though the network domain is broad, several tools are redundant variants of summary/detail or aggregate/raw operations, suggesting consolidation is possible.

    Completeness4/5

    The surface covers config lifecycle, wide read telemetry, targeted RCA, NetBox inventory, and undo tokens, which is strong for network AIOps. Gaps remain, including OSPF/ISIS neighbor state, an explicit ping/reachability test for safe commits, and a tool to list locally configured target devices.

    Maintenance

    ActivityActive
    ResponsivenessLimited data

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      D
      maintenance
      A read-only MCP server for interacting with Nautobot, enabling network source of truth queries, device management, IPAM, and data quality audits via tools and prompts.
      MIT
    • F
      license
      A
      quality
      D
      maintenance
      Provides MCP tools to query, compare, and analyze network device configurations managed by Oxidized, such as listing devices, viewing backup status, and generating diffs between configuration versions.
      8
      -
    • A
      license
      Not graded
      quality
      D
      maintenance
      Enables safe interaction with Juniper Junos devices (SRX firewalls) via MCP, providing operational read tools and a configuration change flow with device-side diff preview and automated rollback.
      Apache 2.0