Skip to main content
Glama

claude-project — SoT netmiko MCP server + skill

A ready-to-copy project that gives an AI agent read-only access to routers, switches and firewalls over SSH, through the Model Context Protocol.

It ships two pieces and the wiring between them:

  • mcps/mcp_server_netmiko.py — a self-contained MCP server. Ten tools, every command validated against an operator-defined allow/deny list, output parsed into JSON with ntc-templates, and a fail-closed audit trail of every attempt.

  • .claude/skills/netmiko/SKILL.md — the skill that teaches the agent when to reach for those tools, what the per-platform CLI dialects look like, and how to read a refusal.

Nothing here writes to a device. The allow list is default-deny — an empty one permits nothing — and the deny side always wins over the allow side.

Everything that happens goes into an audit trail, and netmiko.query_audit_trail makes it answerable in conversation: "everything done on SW-CORE-01, by date", "the last 6 actions", "which commands were refused this week". With no UI in this project, that tool is the only way to read it.

Authors and provenance

This project is authored by Ed Scrimagliaedgardo.scrimaglia@gmail.com, Octupus. Server, skill, configuration model and documentation are his work, written for the Niko agent and packaged here as a standalone project.

It began from a fork, and that origin is acknowledged rather than hidden: the starting point was Kirk Byers' work, and the project grew well past it. What is here now — the source-of-truth-backed inventory, credential resolution, the three deployment flavors, output paging, the audit trail, the skill and this documentation — did not come from upstream.

The two upstream projects by Kirk Byers:

  • Netmiko — the multi-vendor SSH library that does the actual talking to the devices.

  • netmiko_mcp — the MCP server this one was forked from. One part of it survives largely as it was: the security core (command validation, glob handling, the allow/deny asymmetry), kept a faithful port on purpose so that upstream patches can still be diffed in. That was an engineering decision, not a limit on the rest of the work.

Related MCP server: MCP-Telecom

About Niko

This server was written for Niko, Neural Intelligence Knowledge Orchestrator AI agent built by Ed Scrimaglia at Octupus. Niko fronts a set of MCP servers — the source-of-truth server, this one, Jira, send emails, create files and others — so that an operator can ask a question in plain language and have it answered from the real estate: the SoT for what should be true, the devices themselves for what is.

Fedele is Niko's source of truth, which is why the SoT variables carry the FEDELE_ prefix even when they point at a NetBox instance.

License

This project's own code is MIT — see LICENSE.

It is a derivative work, so two licenses apply and both files ship with it:

License

File

This project's code, docs and skill

MIT

LICENSE

Portions ported from ktbyers/netmiko_mcp

Apache-2.0

LICENSE-APACHE-2.0

NOTICE carries the attribution and the statement of modifications that Apache-2.0 §4(b) requires. Netmiko is an ordinary MIT dependency: imported, not vendored, nothing to redistribute.


Layout

claude-project/
├── .mcp.json                     # declares the server (project scope)
├── .env.example                  # → copy to .env with the SSH credentials
├── .claude/skills/netmiko/
│   └── SKILL.md                  # one directory per skill, file named SKILL.md
├── mcps/
│   └── mcp_server_netmiko.py     # NOT at the root: the server reads ../.env
├── config/netmiko/
│   ├── commands.yml              # allow/deny list — without it, a 16-command fallback applies
│   └── inventory.yml             # inventory in netmiko_tools format
├── logs/                         # netmiko-mcp.log + netmiko-audit.jsonl
├── mcpr/netmiko/                 # created on demand (0700): large outputs
├── LICENSE  LICENSE-APACHE-2.0  NOTICE
└── pyproject.toml

Two rules that are not negotiable:

  1. The skill lives in .claude/skills/<name>/SKILL.md. Claude Code does not read skills/netmiko.md: it needs the directory and that exact file name.

  2. The server lives in mcps/, not at the root. PARENT_DIR is the parent of the directory holding the .py (mcp_server_netmiko.py:62), and that is where the .env comes from. With the server at the root, the .env would be looked up one level above the project.

Getting it running

uv venv --python 3.12
uv pip install -r <(uv pip compile pyproject.toml)   # or: uv sync
cp .env.example .env && $EDITOR .env                 # SSH credentials
# .mcp.json needs no editing: its paths are project-relative
claude                                               # approve the project server

Inside the session: /mcp lists the 10 tools, /skills confirms the skill was loaded. First check, without touching the network:

which command policy is the netmiko MCP enforcing?


The three flavors

Where the inventory comes from and where the credentials come from are two independent axes. That is what makes three deployments out of one server — and the reason the server never has to be modified to move between them: two environment variables decide.

Inventory

Credentials

What you need

When to use it

A — SoT everything

Fedele

Fedele

API token + Fernet key

The SoT is authoritative and already holds the device credentials

B — SoT inventory, local credentials

Fedele or NetBox

.env

API token

You have a SoT but not its credential plugin. The usual starting point

C — Self-contained

local YAML

.env

nothing external

Lab, air-gapped, a demo, or degraded mode when the SoT is down

netmiko.get_metadata reports which one is actually running — never assume from the config file:

{
  "inventory": {"backend": "fedele", "scope_filter": null, "available": true},
  "credential_source": "env",
  "device_types_in_inventory": ["cisco_ios", "huawei_vrp", "…"]
}

A — Fedele as the source of truth, credentials included

The agent asks for a device by name; the server resolves address, platform and credentials against the SoT at call time. Nothing about the estate lives in this project: add a device to the SoT and it is reachable on the next call, with no file to edit and no restart.

// .mcp.json → env
"NETMIKO_MCP_INVENTORY_TYPE": "fedele",
"NETMIKO_MCP_CREDENTIAL_SOURCE": "fedele"
# .env
FEDELE_URL=https://fedele.example.com
FEDELE_TOKEN=<API token>
FEDELE_CREDENTIALS_KEY=<Fernet key of the fedele_credentials plugin>

Files: none are mandatory. commands.yml is recommended — without it the built-in fallback policy applies. No local inventory is involved, and no NETMIKO_USERNAME / NETMIKO_PASSWORD; with credential_source=fedele, NETMIKO_SECRET is ignored — the enable password comes from the SoT too.

How the credential lookup works, three hops:

GET dcim/devices/?name=<name>                          → device.id
GET plugins/credentials/devicecredentials/?device=<id> → credential id
GET plugins/credentials/networkcredentials/<id>/       → username + encrypted password
                                                          decrypted locally with the Fernet key

Things worth knowing before you pick this flavor:

  • The Fernet key is the whole security boundary. It decrypts device passwords in the server's memory. Treat it like the passwords themselves.

  • Without FEDELE_CREDENTIALS_KEY the server still starts, and every tool returns the same Startup Error naming the missing variable. It fails loudly, not silently.

  • The inventory is the whole estate unless you scope it.. Running that way is a supported posture, not a misconfiguration — the containment is then commands.yml, which commands are allowed rather than which devices are reachable. The server still logs a warning at startup and returns one in netmiko.get_metadata; unscoped, that pair is expected output.

  • A device without a primary_ip, without a platform, or whose platform is not a Netmiko device_type is excluded from the inventory — SoTs also inventory cameras, badge readers and chassis. Exclusions are counted and reported, so the agent never claims "these are all the devices" over a subset.

  • There is a circuit breaker: after a transport error or a 5xx the client stops calling the SoT for 30 s. A group command against 40 devices with the SoT down fails once, not forty times.

B — SoT for the inventory, credentials in the .env

Identical to A with one variable flipped:

"NETMIKO_MCP_CREDENTIAL_SOURCE": "env",
# .env
FEDELE_URL=https://sot.example.com
FEDELE_TOKEN=<API token>
NETMIKO_USERNAME=<service account>
NETMIKO_PASSWORD=<password>
NETMIKO_SECRET=<enable password, if any device asks for it>

You get the dynamic inventory — the part that pays for itself — without the credential plugin and without the Fernet key. One service account is used for every device.

NetBox, or any NetBox-shaped SoT

The inventory backend speaks the NetBox REST dialect, so NetBox itself works in this flavor, unmodified:

What the backend calls

What it reads

dcim/devices/

the device list, paginated, and filtered by the scope filter if one is set

extras/tags/, dcim/device-roles/, dcim/sites/

whichever one FEDELE_GROUP_SOURCE selects becomes the device groups — always read unfiltered

device.primary_ip.address

the SSH host, mask stripped

device.platform.name

the Netmiko device_type, validated against CLASS_MAPPER

Point FEDELE_URL at the NetBox instance (/api is appended if you leave it off) and FEDELE_TOKEN at a NetBox API token — the client authenticates with the Authorization: Token … header NetBox expects. The variables keep the FEDELE_ prefix; that is a naming legacy, not a product requirement.

The one requirement NetBox does not satisfy by default: platform.name must be exactly a Netmiko device_typecisco_ios, arista_eos, huawei_vrp, juniper_junos. A platform named "Cisco IOS 15.2" is not a device_type, so every device carrying it is excluded from the inventory. Either rename the platforms in NetBox or accept the exclusions, which are reported.

Credentials are the part NetBox does not cover: the plugins/credentials/… endpoints belong to Fedele's plugin. With plain NetBox, flavor A is not available — stay on B.

C — Self-contained: no SoT at all

Everything lives in this project. No external service is contacted, ever.

// .mcp.json → env
"NETMIKO_MCP_INVENTORY_TYPE": "yaml",
"NETMIKO_MCP_CREDENTIAL_SOURCE": "env",
"NETMIKO_MCP_INVENTORY_FILE": "/abs/path/claude-project/config/netmiko/inventory.yml"
# .env
NETMIKO_USERNAME=<service account>
NETMIKO_PASSWORD=<password>
NETMIKO_SECRET=<enable password, if any device asks for it>

Files: inventory.yml is required here — it is the only place the devices exist. commands.yml remains recommended, not required. The inventory is the netmiko_tools format — a flat mapping of name to connection data, plus group keys:

CORE-RTR-01:
  device_type: cisco_xr        # must be a Netmiko device_type, verbatim
  host: 192.0.2.11

CORE-SW-01:
  device_type: arista_eos
  host: 192.0.2.21

core:                          # a group is a list of device names
- CORE-RTR-01
- CORE-SW-01

The file this project ships is example data: 12 fictional devices on the RFC 5737 documentation ranges, 7 groups, and platforms picked so that every CLI dialect the allow list mentions is represented. Replace it with your own estate.

This is the flavor this project ships configured, and it is also degraded mode: if the SoT goes down, two variables and a restart move a flavor-A or flavor-B deployment here. That is worth rehearsing before you need it.

The cost is that the file goes stale. scripts/export_inventory.py in the parent repository regenerates it from the SoT; run it on a schedule. A backup inventory carrying addresses from six months ago is worse than no backup at all, because you find out while operating.

What stays the same in all three

The command policy, the audit trail, the output paging and the tool surface do not change between flavors. The agent-facing contract is identical, which is why the skill needs no per-flavor variant.

commands.yml is recommended, not required

The server runs without it. If the file is missing it does not deny everything and it does not refuse to start: a built-in fallback of 16 read-only commands takes over — show version, show ip interface brief, display version and their Junos/VRP equivalents. That is deliberate. An empty policy would deny every command while the server still reported itself healthy, which reads to an operator as "the device refused" rather than "nobody wrote a policy". The fallback is announced at startup, netmiko.get_command_policy reports policy_source: "fallback", and every audited attempt carries the source.

So the file is a policy decision, not an installation step: the fallback lets you run the server on the first try, and you write commands.yml when you want the estate's own policy instead of a conservative default. What you cannot do is have a policy you did not choose and not know it — the server says which one is in force, every time it is asked.


The .mcp.json file

.mcp.json at the project root declares the MCP servers for this project. Claude Code asks for approval the first time it sees the file, and the file is meant to be committed: it is how the whole team gets the same server.

Two other scopes exist for the same server definition:

Scope

Where it lives

Who sees it

project

.mcp.json at the project root

anyone who opens the project (after approving it)

user

~/.claude.json

every project of that user, on that machine

local

~/.claude.json, keyed by project path

only that user, only in that project

claude mcp add --scope project netmiko -- /path/to/python /path/to/server.py writes the project entry for you; editing the JSON by hand is equivalent.

Shape of the file

{
  "mcpServers": {           // ← the top-level key. Not "servers", not "mcp".
    "netmiko": {            // ← the server name; it becomes the tool prefix
      ...                   //    mcp__netmiko__<tool>
    }
  }
}

The server name is not cosmetic: Claude Code exposes each tool as mcp__<server-name>__<tool-name>. With the name netmiko and the tool netmiko.get_metadata that the server registers, the tool Claude actually sees is mcp__netmiko__netmiko.get_metadata. Run /mcp to read the exact names before writing them into an allowed-tools list or a permission rule.

Field reference

Field

Transport

Meaning

type

both

"stdio" (default when omitted), "http", or "sse"

command

stdio

the executable to spawn. Absolute path — do not assume a cwd

args

stdio

argument list, each element separate

env

stdio

environment for the child process. Merged on top of the inherited one

url

http / sse

full endpoint URL, including the path

headers

http / sse

extra request headers, typically Authorization

Values support environment expansion: ${VAR} and ${VAR:-default}. Useful for keeping a token out of the committed file:

"headers": { "Authorization": "Bearer ${NETMIKO_MCP_TOKEN}" }

Transport 1 — stdio (the one this project uses)

Claude Code spawns the server as a child process and speaks JSON-RPC over its stdin/stdout. Nothing listens on a port, nothing is reachable from the network, and the process lifetime is the session's. This is the right default for a server that holds SSH credentials.

{
  "mcpServers": {
    "netmiko": {
      "type": "stdio",
      "command": "${CLAUDE_PROJECT_DIR:-.}/.venv/bin/python",
      "args": ["${CLAUDE_PROJECT_DIR:-.}/mcps/mcp_server_netmiko.py"],
      "env": {
        "NETMIKO_MCP_INVENTORY_TYPE": "yaml",
        "NETMIKO_MCP_INVENTORY_FILE": "${CLAUDE_PROJECT_DIR:-.}/config/netmiko/inventory.yml",
        "NETMIKO_MCP_COMMAND_FILE": "${CLAUDE_PROJECT_DIR:-.}/config/netmiko/commands.yml",
        "NETMIKO_MCP_CREDENTIAL_SOURCE": "env",
        "NETMIKO_MCP_SAVE_OUTPUT_DIR": "${CLAUDE_PROJECT_DIR:-.}/mcpr/netmiko",
        "NETMIKO_MCP_AUDIT_LOG_FILE": "${CLAUDE_PROJECT_DIR:-.}/logs/netmiko-audit.jsonl",
        "LOG_FILE": "${CLAUDE_PROJECT_DIR:-.}/logs/netmiko-mcp.log",
        "LOG_LEVEL": "INFO"
      }
    }
  }
}

Two things that bite:

  • No hard-coded paths, and the working directory is not something to rely on. ${CLAUDE_PROJECT_DIR:-.} is what keeps the file committable as-is; the next section is the whole story, because the obvious reading of it is wrong.

  • The server must not write to stdout. stdout is the protocol channel, and one stray line there breaks the session. Logging goes to stderr plus the rotating file at LOG_FILE (5 MB × 3, created 0600 — at DEBUG this file carries device output). Inside Niko the same variable is handled by MCPLogging instead.

Where ${CLAUDE_PROJECT_DIR:-.} comes from

Two separate things in one string: a syntax and a variable.

The syntax. ${VAR} and ${VAR:-default} is POSIX parameter substitution ("use VAR; if it is unset or empty, use default"), but no shell is involved — a JSON file never passes through one. Claude Code implements the expansion itself when it reads the file, in command, args, env, url and headers. It is a convention of that client, not part of the MCP specification: another client may not implement it (see Non-Claude agents, where the paths then have to be literal), and VS Code has its own spelling, ${workspaceFolder}.

The variable. CLAUDE_PROJECT_DIR is set by Claude Code to the project root, the same value hooks receive. It is stable — granting extra working directories mid-session with --add-dir does not move it.

The part that is counterintuitive, and the reason the :-. is not decoration: Claude Code sets that variable in the environment of the server it spawns, not in its own. The expansion, though, happens before the spawn, against Claude Code's environment — where the variable does not exist. A bare ${CLAUDE_PROJECT_DIR} would therefore expand to nothing and leave /config/netmiko/inventory.yml, an absolute path to the root of the filesystem.

So in a project-scoped .mcp.json the default is not a fallback for some edge case: it is the value that is used, every time. What reaches the process is ./config/netmiko/inventory.yml. The one exception is an MCP config shipped by a plugin — there Claude Code substitutes the variable directly and no default is needed.

That is what forces the server's hand. A relative value would resolve against the cwd of the child process, and the cwd is the client's choice, not the project's. Hence resolve_project_path(): every relative path setting is anchored to PARENT_DIR — the parent of mcps/, the same root the .env comes from — when the settings load. A session launched from anywhere finds config/netmiko/, and validate_startup() names the absolute file when one is missing. A ~ still means the operator's home, never a file inside the project.

The variable is still useful the way the documentation intends, read from inside the server (os.environ["CLAUDE_PROJECT_DIR"]), where it is set. This server does not need it: PARENT_DIR derives from __file__ and so depends on no client at all — the same reason the HTTP transport, where nobody sets that variable, needs no special case.

Source: Claude Code — MCP, sections Add a local stdio server and Environment variable expansion in .mcp.json.

Transport 2 — HTTP (streamable HTTP)

Claude Code supports it, and so does any other MCP client. It is the transport to use when the server runs somewhere else: another host, a container, a service shared by several agents, or an agent that is not Claude.

The server file always calls mcp.run(transport="stdio") under its __main__ guard, so HTTP is served by the FastMCP CLI instead — no code change:

.venv/bin/fastmcp run mcps/mcp_server_netmiko.py \
  --transport http --host 127.0.0.1 --port 8123
# endpoint: http://127.0.0.1:8123/mcp

The path has no trailing slash: /mcp is the route FastMCP registers, and /mcp/ answers 307 to it. Clients follow the redirect, so an old config with the slash still works — it just pays a round trip on every request.

The NETMIKO_MCP_* variables are no longer part of the client config: the server process is started by you, so they belong to its environment (a shell export, a systemd unit, a container's environment: block).

Client side:

{
  "mcpServers": {
    "netmiko": {
      "type": "http",
      "url": "http://127.0.0.1:8123/mcp",
      "headers": {
        "Authorization": "Bearer ${NETMIKO_MCP_TOKEN}"
      }
    }
  }
}

Or, equivalently, claude mcp add --transport http netmiko http://127.0.0.1:8123/mcp.

--transport sse and "type": "sse" also work; SSE is the older remote transport and is kept for clients that have not moved to streamable HTTP.

Security. The FastMCP CLI serves this without any authentication: whoever reaches the port can run show commands against every device in the inventory, using the credentials in the server's environment. Bind to 127.0.0.1 for a local test, and for anything shared put it behind a reverse proxy that terminates TLS and checks the Authorization header. The headers block above is what the client sends; the proxy is what has to verify it.

Binding to loopback is not by itself enough, which is why the server sets http_host_origin_protection = "auto" at import (§1). A page open in your browser can point its own domain at 127.0.0.1 and reach the port: to the browser that is same-origin, so no CORS applies and its JavaScript reads the response — needing no credentials, since the server holds them and asks the client for nothing. The foreign Host header is the only trace it leaves. With the guard on, a foreign Host gets 421 and a foreign Origin gets 403, while a legitimate localhost request is served. It costs nothing client-side: a non-browser client sends no Origin at all, so that half is never evaluated.

The server also sets stateless_http and json_response to True, so each request stands alone and is answered with a single application/json body instead of an SSE stream. Both are False by default in FastMCP.

Non-Claude agents

The mcpServers object shown here is the de facto shape: Claude Code, Claude Desktop, Cursor and Windsurf all read the same three fields for stdio (command / args / env) and the same two for remote (url / headers). Copying an entry between them normally works as-is.

Known differences worth checking before you copy:

  • VS Code uses mcp.json with a top-level "servers" key instead of "mcpServers", and it wants "type" stated explicitly.

  • Some clients do not implement ${VAR} expansion; there the value has to be literal, which is an argument for the HTTP transport plus a proxy rather than a token pasted into a committed file.

  • An agent with no config file at all can still speak to the HTTP endpoint directly — the URL and the Authorization header are the entire contract.

The env block

The NETMIKO_MCP_* entries win over any YAML config file. They are set explicitly because outside Niko there is no NikoPaths, so the defaults fall back to ~/commands.yml and ~/.netmiko_mcp_tmp.

Every path here may be written relative to the project root: the server anchors relative values to PARENT_DIR when the settings load, so the cwd of the spawned process never decides where the inventory or the audit trail lives. An absolute path or a ~ is taken as written.

Variable

Default

Purpose

NETMIKO_MCP_INVENTORY_TYPE

netmiko_tools

yaml (local file) or fedele (SoT)

NETMIKO_MCP_INVENTORY_FILE

(netmiko-tools lookup)

inventory path when the type is yaml

NETMIKO_MCP_CREDENTIAL_SOURCE

env

env (reads the .env) or fedele

NETMIKO_MCP_FEDELE_GROUP_SOURCE

tags

what defines a group: tags, device_roles, sites

NETMIKO_MCP_FEDELE_DEVICE_FILTER

(none)

optional scope filter, tag=lab&status=active. Unset: the whole estate the token can read

NETMIKO_MCP_FEDELE_CACHE_TTL

60

SoT resolution cache, in seconds

NETMIKO_MCP_COMMAND_FILE

~/commands.yml outside Niko

allow/deny list

NETMIKO_MCP_ALLOW_PIPE

false

enables pipes in commands

NETMIKO_MCP_SSH_CONFIG_FILE

(none)

OpenSSH ssh_config. Required for jumphosts — Netmiko does not read ~/.ssh/config on its own

NETMIKO_MCP_MAX_WORKERS

10

concurrent connections in group commands

NETMIKO_MCP_SAVE_OUTPUT_DIR

~/.netmiko_mcp_tmp outside Niko

buffer for large outputs

NETMIKO_MCP_SAVE_THRESHOLD

1000

line count above which output is saved instead of returned inline

NETMIKO_MCP_AUDIT_LOG_FILE

(see the parent README)

audit trail (JSON, fail-closed). Ask the agent to read it with netmiko.query_audit_trail

NETMIKO_MCP_CONFIG

~/.netmiko-mcp.yml

path to a YAML config file holding these same settings

LOG_FILE / LOG_LEVEL

Niko.log / INFO

operational log: stderr always, plus this rotating file (5 MB × 3, 0600). LOG_LEVEL is stated at its default so the knob is where you look for it — set it to DEBUG and the device output lands in the log

Credentials are not set here. NETMIKO_USERNAME, NETMIKO_PASSWORD, NETMIKO_SECRET and the FEDELE_* variables are read from <project-root>/.env, so that they never end up in a committed JSON file. Precedence: what is in the env block wins over the .env, silently — define each variable in exactly one place.

Every other variable is documented in the parent repository's README.

Checking that it works

claude mcp list          # netmiko: ✓ connected

Inside the session, /mcp lists the tools and /skills confirms the skill was loaded. Ask which policy is in force and netmiko.get_command_policy names the file it is reading — or reports "fallback", which means it never found the file and is running on the 16 built-in commands.


Author: Ed Scrimaglia edgardo.scrimaglia@gmail.com — last updated: 2026-08-18.

Available Tools

10 tools
netmiko.get_command_policyA

List the commands this server will accept, and where that policy comes from.

CALL THIS AFTER A REFUSAL, BEFORE RETRYING. A Security Error: Command ... is not permitted means the command is outside the operator's policy. Do not guess a variant and do not abbreviate — read the policy here, pick a command that is actually allowed, and if nothing fits, tell the user which command was refused and what the allow list does cover.

Also useful when the user asks what they can run on this deployment.

ANSWERING "which commands are available for Juniper / Huawei / Cisco": the lists are flat, because the operator writes one policy for the whole estate. Filter it yourself by dialect — you know the CLIs, and device_types_in_inventory tells you which platforms are actually present. show route* and show chassis* are Junos, display * is Huawei VRP and HPE Comware, show ip route is Cisco-style, and show version happens to work on several. Under the fallback, allowed_commands_by_platform already carries that split, verbatim and exact — use it as given instead of re-deriving it. Two rules when you answer:

  • Never list a command that is not in allowed_commands. It will be refused.

  • Say when the answer is empty: an allow list written for one vendor covers nothing on another, and that is the operator's doing, not a device fault.

policy_source says who wrote the policy in force:

  • "file" — the operator's allow/deny list, at command_file.

  • "fallback" — no policy file exists on this deployment, so only a small built-in read-only set runs. warning explains it; relay that to the user, because every other refusal follows from it and looks like a device problem otherwise.

How the lists are read (getting this wrong wastes attempts, and every attempt is audited):

  • Deny wins over allow, always.

  • The allow list does NOT cover abbreviations: show version does not permit sh ver. Send full commands.

  • The deny list DOES cover abbreviations of the same word count: a deny on configure also blocks conf.

  • * is a glob and only ever appears at the end. cmd* swallows whatever follows; cmd * requires at least one more word and does not match cmd on its own.

  • Anything the allow list does not name is denied.

Returns: str: JSON with policy_source, command_file, allowed_commands, denied_commands, their counts, a rules object, device_types_in_inventory, and — only under the fallback — allowed_commands_by_platform and a warning.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden. It extensively discloses behavior: how the policy lists are read (deny wins, no abbreviations, glob rules), what the return JSON contains, and the meaning of `policy_source` values. This is complete and transparent.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but well-structured with clear sections and bullet points. Every sentence adds value, though some content (e.g., repeated warnings about not listing commands not in the allow list) could be slightly more concise. It is front-loaded with the core purpose, making it effective.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (0 parameters, no output schema provided in structured form), the description is exceptionally complete. It explains the return structure, usage interpretation, edge cases (empty lists, fallback warning), and even includes guidance on how to handle the results. No gaps remain.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters, and the schema coverage is trivially 100%. The description adds no parameter-level semantics because there are none. Per the guidelines, baseline is 4 for zero-parameter tools, and the description does not need to compensate further.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: 'List the commands this server will accept, and where that policy comes from.' It uses a specific verb (list) and resource (commands policy), and distinguishes itself from sibling tools like netmiko.send_show_command by focusing on policy rather than executing commands.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit when-to-use guidance: 'CALL THIS AFTER A REFUSAL, BEFORE RETRYING.' It also explains what not to do (don't guess or abbreviate) and gives context for alternative scenarios ('when the user asks what they can run'). This is thorough and actionable.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

netmiko.get_metadataA

Return authoritative metadata about the Netmiko MCP server and its inventory.

MANDATORY — call this tool FIRST on EVERY user message that mentions, asks about, or relates to network devices, routers, switches, firewalls, show commands, device inventory or device groups, before any other netmiko tool and before answering from memory, system prompt, or RAG/FAQ.

It reports which inventory backend is active (Fedele or the local YAML file) and, for the local file, how old it is. That matters: operating from a stale local inventory can send a command to the wrong box.

This tool does NOT reach any network device. For "is the MCP alive" call netmiko.health_check. To actually query a device, use netmiko.send_show_command.

Returns: str: JSON with version, author, description, inventory, capabilities, command_policy and tool_routing. command_policy is "file" when the operator's allow/deny list is in force and "fallback" when no policy file exists — in that case a warning field says so, only a handful of read-only commands will be accepted, and you must relay that warning to the user instead of treating the denials as device failures.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description bears full responsibility. It discloses that the tool does not reach any network device, explains the returned fields (version, author, inventory, command_policy, etc.), and details the meaning of the command_policy field including the warning behavior. This fully compensates for missing annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is longer than average but each sentence adds essential information. It is front-loaded with the core purpose and mandatory call order, then provides behavioral details and return format. While slightly verbose, the structure is logical and the length is justified by the complexity of guidance needed.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the absence of annotations, the presence of an output schema (context signals), and zero parameters, the description fully covers all necessary aspects. It explains when to call, what it returns, the significance of inventory freshness, the command_policy states, and how to handle warnings. There is no missing information for an agent to use this tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has zero parameters, so schema description coverage is 100% trivially. The description does not need to explain parameters. It adds value by detailing the output fields and their significance, which is a bonus. Baseline for zero parameters is 4.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states 'Return authoritative metadata about the Netmiko MCP server and its inventory.' This is a specific verb+resource combination. It distinguishes itself from sibling tools like netmiko.health_check (server aliveness) and netmiko.send_show_command (device queries) by explaining what it does not do.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly demands: 'MANDATORY — call this tool FIRST on EVERY user message that mentions, asks about, or relates to network devices...' It provides concrete context for when to use it (first call for device-related queries) and when not to (e.g., 'This tool does NOT reach any network device. For "is the MCP alive" call netmiko.health_check'). This is exemplary usage guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

netmiko.health_checkA

Check whether the Netmiko MCP server itself is responsive and correctly configured.

IMPORTANT: If the user message involves network devices, call netmiko.get_metadata FIRST.

This checks the MCP server, NOT any network device and NOT the inventory backend reachability. "¿Está arriba el router X?" is not this tool — that requires actually running a command against the device with netmiko.send_show_command.

Returns: str: JSON with available, version, inventory_backend, credential_source and command_policy ("file" or "fallback"). When command_policy is "fallback" a warning field explains that no policy file exists and only built-in read-only commands run; report that warning to the user.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Since no annotations are provided, the description carries full burden. It discloses that the tool checks the MCP server (not devices or inventory), and documents the return fields including special behavior when command_policy is 'fallback' (warning field, suggesting the agent report it). It does not mention authentication needs, rate limits, or side effects, but for a health-check tool with no destructive potential, these are less critical.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with a brief header, an important usage note, a clear exclusion, and a detailed return format. It is not overly long, but the return section could be slightly more concise (e.g., listing the fields without the 'Returns:' prefix). Overall, it earns its sentences.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool has zero parameters, no annotations, and an output schema (which partially covers the return format), the description provides complete context: what the tool checks, what it doesn't check, when to call an alternative first, and the exact return structure with special behavior. This is fully sufficient for an agent to select and invoke the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters, and the schema provides full coverage (100%) of the empty parameter set. The description adds no parameter-level details because there are none, but the baseline of 4 is appropriate given the zero-parameter context and the rich return value description that compensates slightly.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool checks 'whether the Netmiko MCP server itself is responsive and correctly configured.' It distinguishes itself from tools that check network devices or inventory backend reachability by explicitly contrasting with those cases, and provides a language example ('¿Está arriba el router X?') to reinforce the boundary.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description tells the agent to call netmiko.get_metadata FIRST if the user message involves network devices, and clearly states what this tool is NOT for (network device checks, inventory backend reachability). It also explains when to use alternatives like netmiko.send_show_command, providing explicit when-to-use and when-not-to-use guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

netmiko.list_device_outputsA

List the output files already saved on disk for a device, group, or all devices.

IMPORTANT: If the user message involves network devices, call netmiko.get_metadata FIRST.

Outputs land here when save_output=True was used or when a command exceeded save_threshold. Read them with netmiko.read_device_output.

ParametersJSON Schema
NameRequiredDescriptionDefault
device_or_groupYesA device name, a group name, or 'all'.

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description must fully disclose behavior. It describes what the tool does (lists files), how outputs are generated (saved when save_output=True or threshold exceeded), and implies reading is a separate step. There are no contradictions, and for a listing tool this level of transparency is adequate.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is three sentences long, front-loaded with the core purpose, uses an IMPORTANT callout for critical workflow instruction, and every sentence adds value. No wasted words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's low complexity (single parameter, fully described in schema), the presence of an output schema, and clear context about when outputs exist and how to proceed after listing, the description is complete enough for an agent to use correctly without confusion.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%—the single parameter device_or_group is fully described in the schema. The description repeats 'for a device, group, or all devices' but adds no additional meaning beyond what the schema already states. With high coverage, baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states 'List the output files already saved on disk for a device, group, or all devices.' This provides a specific verb (List) and resource (output files) with clear scope options, distinguishing it effectively from sibling tools like netmiko.read_device_output which reads files.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit guidance: 'If the user message involves network devices, call netmiko.get_metadata FIRST.' It also explains the source of outputs ('save_output=True or exceeded save_threshold') and directs the agent to netmiko.read_device_output for reading. While it doesn't explicitly state when not to use this tool, the context is clear enough for an agent to understand its place in a workflow.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

netmiko.list_devicesA

List devices from the inventory, without credentials.

IMPORTANT: If the user message involves network devices, call netmiko.get_metadata FIRST.

Use this to discover exact device names before running a command. Device names are the only handle the other tools accept — never pass an IP address or a hostname you inferred.

ParametersJSON Schema
NameRequiredDescriptionDefault
device_or_groupNo'all' (default), a group name, or a device name.all

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden. It clearly states the operation is a list (read-only) and that it operates 'without credentials,' which is a notable behavioral trait. It does not mention pagination, rate limits, or other potential behaviors, but the simplicity of the tool makes this sufficient.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is extremely concise with two sentences plus a short IMPORTANT note. Information is front-loaded: the essential action comes first, followed by critical usage instructions. Every sentence earns its place with no redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's simplicity (one optional parameter with 100% schema coverage, an output schema present, and no annotations needed for a read-only list), the description covers all necessary aspects: purpose, when to use, behavioral trait (without credentials), and relationship to sibling tools. The output format is covered by the output schema, so no further detail is needed.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so baseline is 3. The description reinforces the parameter's purpose ('discover exact device names') but does not add new semantic information beyond what the schema's description already provides ('all, a group name, or a device name'). The emphasis on using exact names is helpful context but not additional parameter semantics.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool lists devices from the inventory without credentials, with a specific purpose to discover exact device names. It distinguishes from siblings by emphasizing that device names are the only handle other tools accept, and it notes the IMPORTANT prerequisite to call netmiko.get_metadata first.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit usage guidance is provided: 'Use this to discover exact device names before running a command' and 'Device names are the only handle the other tools accept — never pass an IP address or a hostname you inferred.' The IMPORTANT instruction to call netmiko.get_metadata first for network-related messages further clarifies when and how to use the tool.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

netmiko.list_groupsA

List every device group defined in the inventory.

IMPORTANT: If the user message involves network devices, call netmiko.get_metadata FIRST.

Groups are what netmiko.send_show_command_to_group accepts. Call this before assuming a group name exists — never invent one.

Returns: str: JSON with groups (list of group-name strings) and count.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description must carry the burden. It discloses the read-only nature (list operation) and the return format (JSON with groups and count), and warns against inventing group names. It does not mention error handling or performance, but for a simple list tool this is adequate.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise and well-structured: a one-line purpose, a bolded IMPORTANT note, a usage tip, and a returns section. Every sentence adds value, and it is front-loaded with the core purpose.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given no parameters, an output schema, and a straightforward list operation, the description fully covers usage, prerequisites, and return value. It also clarifies its role in relation to send_show_command_to_group, making it complete in context.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters, so no param info is needed. The description does not add parameter details because there are none; baseline 4 is appropriate for a zero-parameter tool. The output schema already covers the return structure, and the description reinforces it.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states 'List every device group defined in the inventory' — a specific verb and resource. It distinguishes from siblings like list_devices and send_show_command_to_group by focusing on groups, and the tool's role is unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit guidance is given: 'call netmiko.get_metadata FIRST' for network devices, and 'Call this before assuming a group name exists — never invent one.' This sets clear prerequisites and usage timing, effectively preventing misuse without overcomplicating.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

netmiko.query_audit_trailA

Read the audit trail: what this server was asked to do, and what happened.

Answers questions about PAST activity — "everything done on SW-CORE-01", "the last 6 netmiko actions", "which commands were refused this week", "who touched that switch and with which credential". It reads the audit records only; it never opens a connection and never returns device output.

Every argument is a filter, combined with AND. Leave one empty to not filter on it. Translate what the user asked into these arguments — do not ask for everything and sift through it.

The audit trail rotates daily and this reads the rotated files too, but only what is still on disk. files_scanned and oldest_available in the response say how far back the answer actually reaches: if the period the user asked about is older than that, say so instead of reporting "nothing happened".

matched is how many records satisfied the filters; returned is how many came back in this call. When they differ, the response is one page — never report returned as a total.

Calling this tool writes a tool_invocation record of its own — reading the trail is itself auditable — but those records are hidden from the results by default, so "the last 6 actions" is about the network and not about your own questions. audit_queries_hidden says how many were left out.

ParametersJSON Schema
NameRequiredDescriptionDefault
toolNoFull tool name, e.g. 'netmiko.send_show_command'.
eventNoRecord type. One of command_attempt (a command was validated), connection_outcome (an SSH attempt finished), tool_invocation (a tool that touches no device was called), credential_resolution (which credential was used).
limitNoMaximum records to return. Defaults to 50, capped at 500.
orderNo'desc' (newest first, the default) or 'asc'.desc
sinceNoISO 8601 date or datetime, UTC. '2026-08-17' means from midnight.
untilNoISO 8601 date or datetime, UTC.
deviceNoExact inventory device name, as netmiko.list_devices returns it.
reasonNoWhy a command was allowed or refused, e.g. DENY_MATCH, NO_ALLOW_MATCH.
outcomeNoHow an execution ended, e.g. SUCCESS, AUTH_FAILURE, TIMEOUT. Only connection_outcome records carry it.
verdictNoALLOWED or DENIED. Only command_attempt records carry it.
summary_byNoReturn counts instead of records, grouped by one of device, tool, outcome, verdict, event, day. Counts are exact over every matching record, not over one page. Use it for "how many" questions so a count does not cost hundreds of records. Combine it with an `event` filter to avoid a large '(absent)' bucket: records of one type do not carry the fields of another.
correlation_idNoTies the validation, the credential and the outcome of one single attempt together. Use it to reconstruct what happened in one case.
command_containsNoCase-insensitive substring of the command, e.g. 'running-config'.
include_audit_queriesNoInclude this tool's own invocations. Defaults to False. Set it to True only when the question is about who read the audit trail.

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description fully discloses all behavioral traits: it only reads records, never connects to devices, filters combine with AND, audit trail rotates and reads available files, response fields indicate coverage and pagination, and it records its own invocations which are hidden by default. No contradictions.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured and front-loaded with the core purpose. Each sentence adds unique value: examples of use, filtering rules, disk rotation caveats, response field semantics, and self-auditing behavior. No wasted words; the length is appropriate for the tool's complexity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (14 parameters, no annotations, but has output schema), the description covers all necessary aspects: purpose, usage guidance, filtering, pagination, audit trail rotation, and self-recording. It is sufficiently complete for an agent to invoke correctly without additional help.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema already describes all 14 parameters with complete descriptions (100% coverage). The description adds value beyond the schema by explaining the combined-AND filtering strategy, pagination behavior (matched vs. returned), and the context for include_audit_queries. This is meaningful but not extensive, so a 4 is warranted.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool reads the audit trail of past activity, with examples of questions it answers. It distinguishes itself from siblings like send_show_command and read_device_output by explicitly noting it never opens a connection or returns device output.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives strong guidance on when to use the tool (for past activity, not current state) and how to translate user questions into arguments. It instructs to avoid requesting all records and sifting through them. However, it does not explicitly name sibling alternatives to use instead, leaving the agent to infer from context.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

netmiko.read_device_outputA

Read a previously saved output file for one device, with pagination.

IMPORTANT: If the user message involves network devices, call netmiko.get_metadata FIRST.

The response header states the line range and the total line count. When lines remain, a continuation hint gives the offset to use next. Do not report a total based on a page you have not finished reading.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMaximum lines per call. Defaults to 500.
offsetNo0-indexed line to start from. Defaults to 0.
filenameYesExact filename as returned by netmiko.list_device_outputs.
device_nameYesDevice whose output directory to read from.

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations provided, so the description carries the full burden. It describes the pagination mechanism: response header with line range and total line count, continuation hint for next offset, and a warning about premature totals. This is relevant behavioral information beyond the tool name.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise at 4 sentences, with a clear front-loaded purpose and a bolded 'IMPORTANT' warning. No redundant phrasing; every sentence adds value. Could be slightly more structured, but it's efficient.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the existence of an output schema, the description adequately covers the pagination behavior and provides a critical prerequisite (get_metadata). It does not explicitly mention error handling or file existence, but the output schema likely covers return values. The description is sufficiently complete for an agent to use the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3. The description adds value by explaining the pagination behavior (continuation hint) which helps the agent understand how to use the offset and limit parameters effectively. This goes beyond the schema's parameter descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb and resource: 'Read a previously saved output file for one device, with pagination.' This distinguishes it from sibling tools like send_show_command (which sends commands) and list_device_outputs (which lists files).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly instructs to call netmiko.get_metadata FIRST when the user message involves network devices. Also provides guidance on pagination (do not report total based on incomplete pages). Does not explicitly mention alternatives for when not to use this tool, but the context is clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

netmiko.send_show_commandA

Connect to one network device over SSH and run a single show command.

IMPORTANT: If the user message involves network devices, call netmiko.get_metadata FIRST.

The command is validated against the operator's allow/deny list before execution. A rejection is NOT a bug and NOT something to work around: report it to the user and say which command was refused. Do not retry with an abbreviation — abbreviations are covered by the deny list, not by the allow list.

SYNTAX IS PER-PLATFORM. Netmiko drives 177 base device_types (416 with variants) from 102 vendors and their CLIs are NOT interchangeable. Check the device's device_type with netmiko.list_devices first and use that platform's syntax: Cisco IOS/Arista/Juniper use show ..., Huawei VRP and HPE Comware use display ..., MikroTik RouterOS uses /system resource print, F5 tmsh uses list/show with its own grammar. Never translate a command from one family to another by analogy, and never probe variants to see which one is accepted — each attempt is audited and may be denied for a different reason.

ParametersJSON Schema
NameRequiredDescriptionDefault
commandYesFull, un-abbreviated CLI command, e.g. 'show ip interface brief'.
device_nameYesExact device name from the inventory (netmiko.list_devices).
save_outputNoAlways write the output to disk and return the filename instead of the content. Useful when you will refer back to it several times.
use_textfsmNoParse the output into structured JSON via ntc-templates. Falls back to raw text when no template exists.

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description bears full responsibility. It discloses that the command is validated against an allow/deny list, that rejections are expected and not a bug, that syntax is per-platform across 177 base device types, and that probes are audited. This covers behavioral traits beyond the basic function.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is fairly long but well-structured, with a clear first sentence stating purpose, followed by an important prerequisite note, rejection behavior, and platform syntax warnings. Every section earns its place given the complexity, though it could be slightly more concise.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (4 parameters, 177 device types, output schema exists), the description is remarkably complete. It covers prerequisites, platform variations, rejection handling, and flag usage. The output schema exists, so return values do not need to be described. No gaps in essential context.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, establishing a baseline of 3. The description adds value by reinforcing the need for full, un-abbreviated commands and exact device names, and by providing context about platform-specific syntax. While much is already in the schema, the additional warnings about abbreviations and device type checking justify a 4.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description explicitly states 'Connect to one network device over SSH and run a single show command', providing a specific verb and resource. It distinguishes from siblings like netmiko.send_show_command_to_group and netmiko.list_devices by focusing on a single device and show command.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear when-to-use guidance: call netmiko.get_metadata FIRST for network device queries, check device_type with netmiko.list_devices first, and warns against probing variants or retrying rejected commands. It explicitly states that rejections are not bugs and must be reported to the user.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

netmiko.send_show_command_to_groupA

Run the same show command concurrently on every device of a group.

IMPORTANT: If the user message involves network devices, call netmiko.get_metadata FIRST.

The command is validated once before any connection is opened, so a denied command reaches no device at all. Per-device failures are returned per device: a partial result is normal and must be reported as partial, never summarised as if every device answered.

A GROUP MAY MIX PLATFORMS. The same command string is sent to every member, so a group holding both Cisco IOS and Huawei VRP devices will fail on half of them whatever you send — show version is invalid on VRP, display version is invalid on IOS. Check device_type across the group with netmiko.list_devices first; if the group is heterogeneous, issue one netmiko.send_show_command per platform instead of forcing a single string onto all of them.

ParametersJSON Schema
NameRequiredDescriptionDefault
commandYesFull, un-abbreviated CLI command.
save_outputNoSave per-device output to disk and return filenames.
use_textfsmNoParse each output into structured JSON where possible.
device_or_groupYesGroup name (netmiko.list_groups) or a single device name.

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description fully discloses concurrent execution, pre-validation of commands, per-device failure reporting, and the platform heterogeneity risk. No contradictions with structured data.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Well-structured with clear sections, important warnings highlighted, and logical flow. Slightly lengthy but every sentence serves a purpose; could be slightly more concise without losing clarity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Covers all critical aspects: concurrent execution, validation, partial failure reporting, platform heterogeneity, and prerequisites. Output schema exists so return values are not needed. Sufficient for a complex tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so baseline is 3. The description adds value beyond schema by explaining that the command is validated once before connections and warns about platform mixing for the 'command' parameter. It also reinforces the meaning of 'device_or_group' as linking to list_groups/list_devices.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states 'Run the same show command concurrently on every device of a group.' It specifies the verb (run), resource (show command), and scope (concurrently on every device of a group). This distinguishes it from sibling tool 'netmiko.send_show_command' which targets a single device.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides explicit guidance: call netmiko.get_metadata FIRST when involving network devices, and warns against using with heterogeneous groups—directing to use send_show_command per platform instead. Also explains validation behavior and partial failure handling.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

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

  1. 10 tool updatesv0.1.5
    • First observednetmiko.get_command_policy
    • First observednetmiko.get_metadata
    • First observednetmiko.health_check
    • First observednetmiko.list_device_outputs
    • First observednetmiko.list_devices
    • First observednetmiko.list_groups
    • First observednetmiko.query_audit_trail
    • First observednetmiko.read_device_output
    • First observednetmiko.send_show_command
    • First observednetmiko.send_show_command_to_group

TDQS

A4.5/5.0

Scored across 10 tools

Disambiguation4/5

Each tool targets a clear resource and action, and the descriptions explicitly define when each should be used. get_metadata and health_check overlap somewhat since both report server configuration details, but their distinct purposes are clearly explained.

Naming Consistency4/5

Most names follow a consistent verb_noun pattern such as list_devices, send_show_command, and query_audit_trail. health_check is the main deviation, being a noun phrase rather than a verb-led name, but the overall pattern remains predictable.

Tool Count5/5

10 tools is well within the ideal scope for a network automation server. Each tool earns its place by covering a distinct function: metadata, policy, health, inventory, command execution, output retrieval, and auditing.

Completeness5/5

The tool set covers the full read-only operational workflow: discover devices and groups, check command policy, run show commands individually or to a group, list and read saved outputs, and query the audit trail. There are no obvious dead ends—every inventory and output listing has a corresponding consumption tool.

Maintenance

ActivitySlowing
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers