Skip to main content
Glama
sydasif

nornir-mcp-server

by sydasif
README.md
# Nornir MCP Server

[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue.svg)](https://www.python.org/downloads/)
[![MCP](https://img.shields.io/badge/MCP-Protocol-orange.svg)](https://modelcontextprotocol.io)
[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)

An enterprise-ready **Model Context Protocol (MCP)** server that brings the power of [Nornir](https://nornir.tech/) to LLMs like Claude. It seamlessly integrates [NAPALM](https://github.com/napalm-automation/napalm) for structured data retrieval and [Netmiko](https://github.com/ktbyers/netmiko) for flexible CLI execution, enabling natural language orchestration of complex network infrastructure.

---

## 🚀 Overview

The Nornir MCP Server provides a specialized set of tools for network engineers and AI agents to interact with multi-vendor environments safely and efficiently.

- **Multi-Vendor Support**: Standardized interaction for Cisco (IOS, NX-OS, XR), Arista (EOS), Juniper (Junos), and 100+ others.
- **Dual-Engine Architecture**: Combines NAPALM's normalized getters with Netmiko's robust SSH command execution.
- **Intelligent Filtering**: Schema-agnostic device selection by hostname, group, or platform.
- **Security First**: Built-in command blacklisting, input validation (Pydantic), and backup path restrictions.
- **Per-Call Inventory Reloading**: Every MCP tool invocation reloads `config.yaml` and inventory data from disk.
- **Production Ready**: Comprehensive logging and asynchronous execution.

---

## đź“‹ Table of Contents

- [Installation](#-installation)
- [Quick Start](#-quick-start)
- [Lab Environment](#-lab-environment)
- [Available Tools](#-available-tools)
- [Configuration](#-configuration)
- [Claude Integration](#-claude-integration)
- [Security](#-security)
- [Development](#-development)
- [Testing](#-testing)

---

## đź›  Installation

### Using `uv` (Recommended)

```bash
# Install as a global tool
uv tool install git+https://github.com/sydasif/nornir-mcp-server.git

# Upgrade to latest
uv tool upgrade nornir-mcp-server
```

### Using `pip`

```bash
pip install git+https://github.com/sydasif/nornir-mcp-server.git
```

---

## ⚡ Quick Start

1.  **Initialize Configuration**:

    Create a `config.yaml` and basic inventory files in your working directory. See [Minimal Inventory Example](#-minimal-inventory-example) below.

2.  **Launch the Server**:

    ```bash

    nornir-mcp

    ```

3.  **Verify Inventory**:

    The server will look for `config.yaml` in the current directory to load your Nornir inventory.

---

## 📦 Minimal Inventory Example

To get started quickly, create these three files in your project root:

**`hosts.yaml`**

```yaml
R1:
  hostname: 192.168.1.1
  platform: ios
  groups:
    - cisco_ios
```

**`groups.yaml`**

```yaml
cisco_ios:
  platform: ios
  username: admin
  password: password
```

**`defaults.yaml`**

```yaml
# Global defaults
data:
  site: NYC
```

**`config.yaml`**

```yaml
inventory:
  plugin: SimpleInventory
  options:
    host_file: "hosts.yaml"
    group_file: "groups.yaml"
    defaults_file: "defaults.yaml"
```

---

## đź§Ş Lab Environment

For a ready-to-use Containerlab lab with Cisco CSR1000v and Arista cEOS devices, see the companion repository: [nornir-mcp-lab](https://github.com/sydasif/nornir-mcp-lab)

**Prerequisites**: Containerlab, Docker, Python 3.12+

---

## đź§° Available Tools

The server exposes 5 tools categorized by operational intent. All tools support individual filter parameters for device selection.

**Filter Parameters:**

- `filter_name`: Filter by device name in inventory
- `filter_hostname`: Filter by specific hostname or IP address
- `filter_group`: Filter by group membership (e.g., "cisco", "arista")
- `filter_platform`: Filter by platform (e.g., "eos", "ios", "junos")

All filter parameters are optional. When multiple filters are provided, they are combined with AND logic.

| Category       | Tool             | Description                                            |
| :------------- | :--------------- | :----------------------------------------------------- |
| **Inventory**  | `list_devices`   | List hosts, groups, and metadata.                      |
| **Monitoring** | `fetch_data`     | Generic access to any NAPALM getter (ARP, VLAN, etc.). |
|                | `show_commands`  | Execute arbitrary show commands safely.                |
| **Management** | `apply_config`   | Deploy configuration changes with validation.          |
|                | `backup_configs` | Securely save configurations to local disk.            |

---

## ⚙️ Configuration

Every MCP tool call reloads `config.yaml` from the current working directory. The server does not cache a long-lived `Nornir` instance between requests.

### Nornir Setup (`config.yaml`)

```yaml
inventory:
  plugin: SimpleInventory
  options:
    host_file: "hosts.yaml"
    group_file: "groups.yaml"
    defaults_file: "defaults.yaml"

runner:
  plugin: threaded
  options:
    num_workers: 100

logging:
  enabled: true
  level: INFO
```

### Command Security

The server includes a built-in security engine that validates all CLI commands against a multi-stage validation system before execution. This prevents accidental or malicious use of destructive commands while minimizing false positives for read-only operations.

**Security Features:**

- **Read-Only Enforcement**: Tools like `show_commands` enforce an **allowlist prefix** (e.g., `show`, `display`, `get`, `ping`, `traceroute`).
- **Smart Denylist**: Destructive keywords (`erase`, `format`, `delete`, `reload`) are blocked only when they appear as the **first token** of a command. This allows legitimate commands like `show reload history` while blocking a bare `reload`.
- **Chaining & Redirection Protection**: Prevents the use of `;`, `&&`, `>`, and `<` to ensure single-command integrity.
- **Path Sandboxing**: Configuration backups are protected against directory traversal attacks (`..`).

---

## 🤖 CLI Integration

Add the following to your claude config:

```json
{
  "mcpServers": {
    "nornir": {
      "command": "nornir-mcp"
    }
  }
}
```

Add the following to your opencode config:

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "nornir": {
      "type": "local",
      "command": ["nornir-mcp"]
    }
  }
}
```

**Try these prompts:**

- _"Show me all core routers in the US-West region."_
- _"Are there any BGP neighbors down on R1?"_
- _"Backup the running configuration of all Arista switches."_
- _"Check if there are any errors on the interfaces of the edge-group."_

---

## đź”’ Security

- **Command Validation**: All CLI inputs pass through a multi-stage built-in denylist filter (Keywords and Patterns).
- **Path Sandboxing**: Configuration backups are restricted to the defined root directory to prevent traversal.

---

## 👨‍💻 Development

```bash
# Clone and setup
git clone https://github.com/sydasif/nornir-mcp-server.git
cd nornir-mcp-server
uv sync

# Run tests
uv run pytest

# Lint and Format
uv run ruff check . --fix
uv run ruff format .
```

If `uv run` is unstable in the local environment, use `.venv/bin/pytest` and `.venv/bin/ruff` directly.

Relevant internal paths:

- `src/nornir_mcp/services/runner.py`: shared async task execution. Mandatory entry point for all network tasks; accepts filter kwargs (`name`, `hostname`, `group`, `platform`).
- `src/nornir_mcp/services/inventory.py`: shared inventory loading and filtering helper. Reloads `config.yaml` from disk on every call. Accepts filter kwargs directly.
- `src/nornir_mcp/services/napalm.py`: shared NAPALM getter execution helper used by monitoring and backup tools. Accepts filter kwargs directly.
- `src/nornir_mcp/tools/monitoring.py`: monitoring tools for NAPALM getters and Netmiko show commands.
- `src/nornir_mcp/tools/management.py`: management tools for configuration deployment and backups.

---

## âś… Testing

The repository includes a pytest suite under `tests/` covering filters, inventory loading, inventory tools, monitoring tools, NAPALM helper behavior, security validation, runner error handling, and backup behavior.

```bash
# Run the full test suite
uv run pytest

# Fallback if uv run is unstable
.venv/bin/pytest
```

---

## đź“„ License

This project is licensed under the **MIT License**. See [LICENSE](LICENSE) for details.

---

<p align="center">Built with ❤️ for Network Automation</p>

TDQS

A4/5.0

Scored across 5 tools

Disambiguation4/5

The tools are mostly distinct: list_devices handles inventory, apply_config pushes configs, backup_configs saves configs, while fetch_data and show_commands both retrieve device data but via different methods (structured NAPALM getters vs raw CLI). This slight overlap prevented a perfect score, but descriptions clarify the distinction.

Naming Consistency5/5

All tool names follow a consistent verb_noun pattern (list_devices, apply_config, backup_configs, fetch_data, show_commands) using snake_case and imperative verbs. There are no naming deviations or mixed conventions.

Tool Count5/5

The server provides 5 tools, which is well-scaled for a network automation MCP server. Each tool covers a core function—inventory, config push, backup, data collection, and CLI commands—without unnecessary bloat.

Completeness4/5

The tool surface covers the primary network operations: inventory access, configuration management (apply and backup), structured data retrieval, and raw command execution. Minor gaps exist (e.g., no explicit config comparison or device reboot), but most workflows can be accomplished via the existing tools, such as using fetch_data with the 'config' getter.

Maintenance

ActivityInactive
ResponsivenessNo issues