Metadata-Version: 2.4
Name: netmiko-mcp
Version: 0.2.0
Summary: MCP Server for Netmiko Network Automation Library.
Author-email: Kirk Byers <ktbyers@twb-tech.com>
License: Apache-2.0
Project-URL: Homepage, https://github.com/ktbyers/netmiko_mcp
Project-URL: Repository, https://github.com/ktbyers/netmiko_mcp
Keywords: netmiko,mcp,network-automation,ssh
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Topic :: System :: Networking
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: mcp>=1.27.1
Requires-Dist: netmiko>=4.7.0
Requires-Dist: ntc-templates>=4.1.0
Requires-Dist: pydantic-settings>=2.14.1
Requires-Dist: pyyaml>=6.0.3
Requires-Dist: uvicorn>=0.48.0
Dynamic: license-file

# Netmiko MCP Server

> **WARNING:** You can make serious, incredibly detrimental mistakes by using this tool. This tool could cause massive outages in your environment. You, and you alone, are solely responsible for using this tool. Don't say I didn't warn you.

> I have tried to make reasonable defaults and to limit what the Netmiko-MCP server allows (by default). It is highly advisable to start with ONLY show commands executed against ONLY test or lab devices. You should also strongly consider additional security mechanisms completely outside of the LLM and Netmiko- MCP (for example, a tightly-controlled AAA solution). LLMs and LLM-agents inherently have a lot of variance and are difficult to predict and control.
<br />

## Welcome to an LLM-assisted Method of Interacting with your Network

netmiko-mcp is a Model Context Protocol server that gives your AI client (Claude, Claude Code, Cursor, VS Code Copilot, and others) direct, controlled access to your network devices via SSH (and Telnet if absolutely necessary). Ask a question in plain English; the agent figures out which devices to query, runs the permitted commands, and returns results as a conversation, a formatted table, or structured JSON.  Whatever fits your workflow.

This repository is a starting point for network engineers curious about what AI agents can do when given access to real devices. 

The setup process itself is AI-assisted: the `skills/` directory contains reference files that load directly into your AI client's context, so you can ask your AI-client to help you configure the server, set up inventory, or troubleshoot a connection. The skills should have the relevant details.
<br />

## Security Recommendations

The controls in Netmiko-MCP are a best-effort layer and should not be your only line of defense. You should strongly consider using AAA (e.g. TACACS+) with a dedicated read-only service account. AAA should independently authorize and audit what commands the account can execute on your devices. The MCP command authorization can potentially be bypassed, so this tool should only be used by authorized personnel. Untrusted input should not be used with this MCP.
<br />
<br />

## What Is MCP?

MCP (Model Context Protocol) is a standardized protocol for interfacing AI clients to additional services (in this case network devices). With netmiko-mcp registered as an MCP server, your AI client can connect to your network devices directly providing your AI client the means to discover your inventory, run commands, and return results. All triggered by text-based prompting in the AI client.

With Netmiko MCP, you define allowed and denied commands (by default, all commands are denied). The Netmiko MCP server enforces these restrictions on every request. In other words, you prompt the LLM; the LLM performs a tool call to the Netmiko MCP via your AI client, the Netmiko MCP determines if the command is allowed or denied and then sends the request to the network devices (assuming allowed).

## How This Works

netmiko-mcp sits between your AI client and your network devices. It supports two transport modes:

**stdio** - Your AI client launches the server as a local subprocess and communicates over standard input/output. No ports are opened and nothing listens on the network. The process starts when you open a session and stops when you close it. This is the simplest setup and the right choice for a single user running the server on their own machine.

**Streamable HTTP** - The server runs as a standalone service that listens on a network port. Your AI client connects to it over HTTP rather than launching it as a subprocess. This allows the server to run on a remote host and be shared across multiple machines or clients. It also enables centralized control and auditing/logging of all device interactions in one place. The tradeoff is a slightly more involved deployment (you are responsible for starting the process and keeping it running).
<br />

## Prerequisites

- **uv**  Python package manager used to install and run the server. See details online regarding installation instructions.
- **An AI client that supports MCP (for example, Claude Code, Claude Desktop, Cursor, VS Code + Copilot, Codex)**  

## Installation

**Option 1 — uv tool (recommended for most users):**

```bash
uv tool install netmiko-mcp
```

**Option 2 — Clone from source:**

```bash
git clone https://github.com/ktbyers/netmiko_mcp
cd netmiko_mcp
uv sync
```

> **Note:** `uv sync` installs into the project's local virtual environment, which works for Claude Code but not for clients like Claude Desktop, Cursor, Devin (formerly Windsurf) that launch the server from a different working directory.

<br />

## Getting Started

Setup requires three things: an MCP configuration file, a device inventory, and a commands whitelist.

> **Simplest setup:** Place all three files in your home directory using the default names:  `~/.netmiko-mcp.yml`, `~/.netmiko.yml`, and `~/commands.yml`. The server finds them automatically with no environment variables or extra configuration required in any client.

If you need to use different locations, set the `NETMIKO_MCP_CONFIG` environment variable to point at your configuration file which can point to custom locations for your inventory and command YML files:

```bash
export NETMIKO_MCP_CONFIG="$HOME/.netmiko-mcp.yml"
```
<br />

### Step 1 - Create the Netmiko-MCP configuration file

Create `~/.netmiko-mcp.yml`:

```yaml
inventory_type: "netmiko_tools"
inventory_file: "~/.netmiko.yml"
command_file: "~/commands.yml"
```

Additional details on the Netmiko-MCP configuration file and corresponding environment variables: [docs/configuration.md](docs/configuration.md)
<br />
<br />

### Step 2 - Create the device inventory

Currently, device inventory is limited to Netmiko Tools' [device inventory](https://pynet.twb-tech.com/blog/netmiko-grep-command-line-utility.html#creating-the-inventory). It is likely this will be expanded in the future to support additional inventory sources.


Create the `~/.netmiko.yml` device inventory. This file contains device dictionaries and groups of devices.

**A note on credentials:** The Netmiko Tools inventory format requires that device usernames and passwords be stored in this file. Plaintext credentials are perfectly fine for lab or test environments. For anything beyond that, it is strongly recommended to use the built-in encryption option.  Netmiko can encrypt the credential fields so the file can be stored safely without exposing passwords in cleartext. See the [netmiko-tools-yml skill](skills/netmiko-tools-yml/SKILL.md) for details on both plaintext and encrypted approaches.

Netmiko Tools AI [skill file](https://github.com/ktbyers/netmiko_mcp/blob/main/skills/netmiko-tools-yml/SKILL.md)
<br />
<br />

### Step 3 - Create the commands whitelist

Create `~/commands.yml` to define what the LLM is allowed to send to devices. By default
**no commands are permitted**:

```yaml
allowed_commands:
  - "show version"
  - "show ip interface brief"

denied_commands: []
```

The default location is `~/commands.yml`. To use a different path, set `command_file` in your `~/.netmiko-mcp.yml`:

```yaml
command_file: "~/network/commands.yml"
```

Or override it with an environment variable:

```bash
export NETMIKO_MCP_COMMAND_FILE="~/network/commands.yml"
```

Full details on allowed/denied matching, globbing, pipes, and allowed characters: [docs/commands.md](docs/commands.md)
<br />
<br />

## Registering with Your AI Client

With the server installed and the three config files in place, register `netmiko-mcp` with your AI client. Each client has its own config file or CLI command for registering the server - see the [mcp-client-config skill](skills/mcp-client-config/SKILL.md) for per-client instructions covering Claude Code, Claude Desktop, Cursor, Devin Desktop, VS Code + GitHub Copilot, and Kiro.

## Supported MCP Clients (June 2026)

| Client | stdio | HTTP | Verified | Notes |
|---|---|---|---|---|
| Claude Code | ✓ | ✓ | ✓ | Recommended for development and testing |
| Claude Desktop | ✓ | ✓ | ✓ | Agent mode; deferred tool loading |
| Cursor | ✓ | ✓ | ✓ | Agent mode required; use Streamable HTTP transport (SSE is deprecated and has a known bug in Cursor) |
| Devin Desktop (formerly Windsurf) | ✓ | ✓ | ✓ | Agent mode (Cascade) required |
| VS Code + GitHub Copilot | ✓ | ✓ | ✓ | Agent mode only; free tier sufficient |
| Kiro (AWS IDE) | ✓ | ✓ | - | Not tested; based on documentation |
| Cline | ✓ | ✓ | - | Not tested |
| Gemini CLI | ✓ | ✓ | - | Not tested |
| ChatGPT | ✗ | ✗ | ✗ | SSE-only; complex workaround required; not recommended |
<br />


## Reference Documentation

| Document | Description |
|---|---|
| [docs/configuration.md](docs/configuration.md) | Netmiko-MCP configuration file settings |
| [docs/commands.md](docs/commands.md) | Netmiko-MCP allowed commands, denied commands |
| [skills/mcp-client-config/SKILL.md](skills/mcp-client-config/SKILL.md) | Per-client MCP configuration (Claude Code, Claude Desktop, Cursor, Devin Desktop, VS Code, Kiro) |
| [skills/netmiko-tools-yml/SKILL.md](skills/netmiko-tools-yml/SKILL.md) | Device inventory format, credential encryption, secrets manager integration |
<br />


## Skills

The `skills/` directory contains references to various skills.

**Available skills:**

| Slash command | What it loads |
|---|---|
| `/netmiko-mcp` | Reference `~/.netmiko-mcp.yml` fields, commands whitelist format, pipe rules, all 7 MCP tool signatures |
| `/mcp-client-config` | Copy-paste JSON config blocks for Claude Code, Claude Desktop, Cursor, Devin Desktop, VS Code + Copilot, and Kiro — with per-client instructions |
| `/netmiko-tools-yml` | Inventory format, step-by-step encryption process |
| `/mcp-http-transport` | When to use HTTP vs stdio, SSE vs Streamable HTTP, Claude.ai web client setup |
| `/caddy-tls` | Caddy install, Caddyfile examples for internal CA and Let's Encrypt, `NODE_EXTRA_CA_CERTS` fix, WSL2/Windows split-host setup |
<br />


## MCP Tools

The server exposes seven tools to MCP clients:

| Tool | Description |
|---|---|
| `send_show_command` | Connect to a single device and execute a show command. Accepts `device_name`, `command`, and optional `use_textfsm=True` to return structured JSON instead of raw text. |
| `send_show_command_to_group` | Execute a show command concurrently across a device group. Accepts `device_or_group`, `command`, optional `use_textfsm=True`, and optional `save_output=True` to write per-device files instead of returning raw output. |
| `list_devices` | List devices from the inventory. Accepts an optional `device_or_group` argument (defaults to `"all"`). Credentials are never included in the response. |
| `list_groups` | List all device group names defined in the inventory. Returns a list of strings. |
| `list_device_outputs` | List saved output files for a device, group, or `"all"`. Returns a dict mapping device names to lists of saved filenames (newest first). |
| `read_device_output` | Read a previously saved output file. Accepts `device_name` and `filename` (as returned by `list_device_outputs`). |
| `ping` | Health check. Returns `"pong"`. |


## Usage Examples

### Human-readable table output

> **Prompt:** Execute show version on all the switches configured for my Netmiko MCP server

The LLM discovers devices via `list_devices`, runs `show version` on each in parallel, and formats the results as a table:

| Field | core01 | access01 |
|-------|--------|----------|
| Platform | Arista cEOSLab | Arista cEOSLab |
| EOS Version | 4.35.2F (engineering build) | 4.35.2F (engineering build) |
| Architecture | x86_64 | x86_64 |
| Kernel | 5.15.0-181-generic | 5.15.0-181-generic |
| Serial | 34142FDC416C66E78611C8DF0D03306C | B1AFD6AA33B7A826E56244D42BBD9B8C |
| System MAC | 001c.7395.64b0 | 001c.7333.16be |
| Uptime | 1d 22h 15m | 1d 22h 15m |
| Total Memory | ~16 GB | ~16 GB |
| Free Memory | ~12.2 GB | ~12.2 GB |


### Structured JSON output

> **Prompt:** Execute show version on all the switches configured for my Netmiko MCP server and return the data in JSON format.

Adding "in JSON format" to your prompt causes the LLM to invoke `send_show_command` with `use_textfsm=True`, which parses the raw output into structured data via ntc-templates:

```json
{
  "core01": {
    "model": "cEOSLab",
    "hw_version": "",
    "serial_number": "34142FDC416C66E78611C8DF0D03306C",
    "sys_mac": "001c.7395.64b0",
    "image": "4.35.2F-46221466.4352F",
    "total_memory": "16336752",
    "free_memory": "12870640",
    "uptime": "1 day, 22 hours and 16 minutes"
  },
  "access01": {
    "model": "cEOSLab",
    "hw_version": "",
    "serial_number": "B1AFD6AA33B7A826E56244D42BBD9B8C",
    "sys_mac": "001c.7333.16be",
    "image": "4.35.2F-46221466.4352F",
    "total_memory": "16336752",
    "free_memory": "12876236",
    "uptime": "1 day, 22 hours and 16 minutes"
  }
}
```

The structured output is useful when you want to pipe results into another tool, compare fields programmatically, or ask the LLM follow-up questions that require field-level access (e.g., "which devices are running a version older than 4.34?").


### Saving output to local files

> **Prompt:** Run `show version` on every device in my Netmiko MCP inventory, return structured JSON, and save each device's output to a file named `<device-name>.json` in my current directory.

The LLM will collect results for all devices and write one file per device. Being explicit about the filename convention (`<device-name>.json`) and the target location (`current directory`) prevents it from guessing.

> **Tip:** If you omit the directory, the LLM will save files relative to whatever working directory your AI client is running from - which may not be where you expect. Specify an absolute path (e.g., `~/network/output/`) if you want the files in a particular location.
