Skip to main content
Glama

claude-project — netmiko MCP-Server + Skill

Ein fertig kopierbares Projekt, das einem KI-Agenten schreibgeschützten Zugriff auf Router, Switches und Firewalls über SSH ermöglicht, über das Model Context Protocol.

Es liefert zwei Komponenten und die Verbindung zwischen ihnen:

  • mcps/mcp_server_netmiko.py — ein eigenständiger MCP-Server. Neun Tools, jeder Befehl gegen eine vom Operator definierte Erlaubnis-/Verbotsliste validiert, die Ausgabe mit ntc-templates in JSON geparst und ein fehlschließender Prüfpfad für jeden Versuch.

  • .claude/skills/netmiko/SKILL.md — die Skill, die dem Agenten beibringt, wann er diese Tools einsetzen soll, wie die plattformspezifischen CLI-Dialekte aussehen und wie man eine Verweigerung liest.

Nichts hier schreibt auf ein Gerät. Die Erlaubnisliste ist standardmäßig verweigernd — eine leere erlaubt nichts — und die Verbotsseite gewinnt immer über die Erlaubnisseite.

Autoren und Herkunft

Dieses Projekt wurde von Ed Scrimaglia erstelltedgardo.scrimaglia@gmail.com, Octupus. Server, Skill, Konfigurationsmodell und Dokumentation sind seine Arbeit, geschrieben für den Niko-Agenten und hier als eigenständiges Projekt verpackt.

Es begann als Fork, und dieser Ursprung wird anerkannt, nicht versteckt: Der Ausgangspunkt war die Arbeit von Kirk Byers, und das Projekt ist weit darüber hinausgewachsen. Was jetzt hier ist — das auf einer Quelle der Wahrheit basierende Inventar, die Auflösung von Anmeldeinformationen, die drei Bereitstellungsvarianten, die Ausgabenseitennummerierung, der Prüfpfad, die Skill und diese Dokumentation — stammt nicht aus dem Upstream.

Die beiden Upstream-Projekte von Kirk Byers:

  • Netmiko — die Multi-Vendor-SSH-Bibliothek, die die eigentliche Kommunikation mit den Geräten übernimmt.

  • netmiko_mcp — der MCP-Server, von dem dieser abgespalten wurde. Ein Teil davon ist weitgehend so erhalten geblieben, wie er war: der Sicherheitskern (Befehlsvalidierung, Glob-Handhabung, die Erlaubnis-/Verbotsasymmetrie), absichtlich als originalgetreuer Port beibehalten, damit Upstream-Patches immer noch eingespielt werden können. Das war eine technische Entscheidung, keine Einschränkung der übrigen Arbeit.

Über Niko

Dieser Server wurde für Niko geschrieben, den Neural Intelligence Knowledge Orchestrator KI-Agenten, der von Ed Scrimaglia bei Octupus entwickelt wurde. Niko bedient eine Reihe von MCP-Servern — den Source-of-Truth-Server, diesen hier, Jira, E-Mail-Versand, Dateierstellung und andere —, sodass ein Operator eine Frage in natürlicher Sprache stellen kann und die Antwort aus der realen Umgebung erhält: die SoT für das, was wahr sein sollte, die Geräte selbst für das, was ist.

Innerhalb von Niko läuft dieselbe Datei etwas anders, und das ist wissenswert, weil es einige Dinge im Code erklärt:

  • Server laufen über HTTP auf Loopback, ein Port pro Server, deklariert in mcps/mcp_config.json mit url / transport / local / env — dieselbe unten beschriebene Zwei-Achsen-Konfiguration, ausgedrückt in Nikos eigenem Format.

  • Die Installation erfolgt über die App, nicht durch Kopieren von Dateien: Der Upload wird validiert, die Abhängigkeiten werden aus dem Code selbst aufgelöst, und eine fehlgeschlagene Installation wird zurückgesetzt, anstatt einen halben Server zurückzulassen.

Jede dieser Integrationen ist ein optionaler Import mit einem Fallback, sodass niko nie installiert sein muss. Es gibt vier, und dies ist, wozu jede herabgestuft wird, wenn der Import fehlschlägt:

Import

Zeile

Eigenständiger Fallback

niko.srvclass_logging.MCPLogging

60

NIKO_AVAILABLE = False; der Server konfiguriert sein eigenes logging

niko.niko_paths.NikoPaths

68

None; Pfade stammen aus den NETMIKO_MCP_*-Variablen, weshalb dieses Projekt sie explizit setzt

niko.srvclass_logging.SyncedConcurrentTimedRotatingFileHandler

436

FailClosedFileHandler — immer noch fehlschließend, nur nicht mehr prozesssicher

niko.srvclass_list_budget.apply_budget_to_payload

2709

ein No-Op, das die Nutzlast unverändert zurückgibt

Es geht nichts verloren, was außerhalb von Niko wichtig wäre: Der nebenläufige Handler löst ein Mehrere-Prozesse-eine-Datei-Problem, das hier nicht auftritt, und das Listenbudget kürzt lange Nutzlasten für einen Agenten, der seine eigene Kontextabrechnung hat. Eine Datei, zwei Zuhause, kein Fork.

Fedele ist Nikos Quelle der Wahrheit, weshalb die SoT-Variablen das FEDELE_-Präfix tragen, selbst wenn sie auf eine NetBox-Instanz verweisen.

Lizenz

Der eigene Code dieses Projekts ist MIT — siehe LICENSE.

Es ist eine abgeleitete Arbeit, daher gelten zwei Lizenzen und beide Dateien werden mitgeliefert:

Lizenz

Datei

Code, Dokumentation und Skill dieses Projekts

MIT

LICENSE

Aus ktbyers/netmiko_mcp portierte Teile

Apache-2.0

LICENSE-APACHE-2.0

NOTICE enthält die Namensnennung und die Erklärung der Änderungen, die Apache-2.0 §4(b) verlangt. Netmiko ist eine gewöhnliche MIT-Abhängigkeit: importiert, nicht eingebunden, nichts zum Weiterverteilen.


Aufbau

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

Zwei nicht verhandelbare Regeln:

  1. Die Skill lebt in .claude/skills/<name>/SKILL.md. Claude Code liest skills/netmiko.md nicht: Es braucht das Verzeichnis und diesen genauen Dateinamen.

  2. Der Server lebt in mcps/, nicht im Stammverzeichnis. PARENT_DIR ist das übergeordnete Verzeichnis des Ordners, der die .py enthält (mcp_server_netmiko.py:62), und dorther kommt die .env. Wenn der Server im Stammverzeichnis wäre, würde die .env eine Ebene über dem Projekt gesucht.

Inbetriebnahme

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

Innerhalb der Sitzung: /mcp listet die 9 Tools auf, /skills bestätigt, dass die Skill geladen wurde. Erste Überprüfung, ohne das Netzwerk zu berühren:

Welche Befehlspolicy setzt der netmiko MCP durch?


Die drei Varianten

Woher das Inventar kommt und woher die Anmeldeinformationen kommen, sind zwei unabhängige Achsen. Das macht aus einem Server drei Bereitstellungen — und der Grund, warum der Server nie modifiziert werden muss, um zwischen ihnen zu wechseln: Zwei Umgebungsvariablen entscheiden.

Inventar

Anmeldeinformationen

Was Sie brauchen

Wann verwenden

A — SoT alles

Fedele

Fedele

API-Token + Fernet-Key

Die SoT ist maßgeblich und enthält bereits die Geräte-Anmeldeinformationen

B — SoT-Inventar, lokale Anmeldeinformationen

Fedele oder NetBox

.env

API-Token

Sie haben eine SoT, aber nicht deren Anmeldeinformations-Plugin. Der übliche Ausgangspunkt

C — In sich geschlossen

lokales YAML

.env

nichts Externes

Labor, abgeschottet, eine Demo oder herabgestufter Modus, wenn die SoT ausfällt

netmiko.get_metadata meldet, welche tatsächlich läuft — niemals aus der Konfigurationsdatei ableiten:

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

A — Fedele als Quelle der Wahrheit, einschließlich Anmeldeinformationen

Der Agent fragt nach einem Gerät mit Namen; der Server löst Adresse, Plattform und Anmeldeinformationen zum Zeitpunkt des Aufrufs gegen die SoT auf. Nichts über die Umgebung lebt in diesem Projekt: Fügen Sie ein Gerät zur SoT hinzu, und es ist beim nächsten Aufruf erreichbar, ohne dass eine Datei bearbeitet oder ein Neustart erforderlich ist.

// .mcp.json → env
"NETMIKO_MCP_INVENTORY_TYPE": "fedele",
"NETMIKO_MCP_CREDENTIAL_SOURCE": "fedele",
"NETMIKO_MCP_FEDELE_GROUP_SOURCE": "tags",        // tags | device_roles | sites
"NETMIKO_MCP_FEDELE_DEVICE_FILTER": "tag=lab",    // the scope filter — read the warning
"NETMIKO_MCP_FEDELE_CACHE_TTL": "60"
# .env
FEDELE_URL=https://fedele.example.com
FEDELE_TOKEN=<API token>
FEDELE_CREDENTIALS_KEY=<Fernet key of the fedele_credentials plugin>

Dateien: Keine sind zwingend erforderlich. commands.yml wird empfohlen — ohne sie gilt die integrierte Fallback-Policy. Es ist kein lokales Inventar beteiligt, und es gibt keine NETMIKO_USERNAME / NETMIKO_PASSWORD; bei credential_source=fedele wird NETMIKO_SECRET ignoriert — das Enable-Passwort kommt ebenfalls von der SoT.

So funktioniert die Suche nach Anmeldeinformationen, drei Schritte:

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

Wissenswertes, bevor Sie diese Variante wählen:

  • Der Fernet-Key ist die gesamte Sicherheitsgrenze. Er entschlüsselt Gerätepasswörter im Arbeitsspeicher des Servers. Behandeln Sie ihn wie die Passwörter selbst.

  • Ohne FEDELE_CREDENTIALS_KEY startet der Server trotzdem, und jedes Tool gibt denselben Startup Error zurück, der die fehlende Variable nennt. Er scheitert lautstark, nicht still.

  • Setzen Sie den Bereichsfilter. Ohne NETMIKO_MCP_FEDELE_DEVICE_FILTER ist das Inventar die gesamte Umgebung, die die SoT kennt, was auch die gesamte Menge der Geräte ist, die der Agent erreichen kann. Der Server protokolliert eine Warnung, wenn er fehlt; der Filter akzeptiert Abfragesyntax, tag=lab&status=active.

  • Ein Gerät ohne primary_ip, ohne platform oder dessen Plattform kein Netmiko device_type ist, wird ausgeschlossen vom Inventar — SoTs inventarisieren auch Kameras, Badge-Leser und Chassis. Ausschlüsse werden gezählt und gemeldet, sodass der Agent nie behauptet "das sind alle Geräte" über eine Teilmenge.

  • Es gibt einen Schutzschalter: Nach einem Transportfehler oder einem 5xx-Fehler ruft der Client die SoT 30 s lang nicht mehr auf. Ein Gruppenbefehl gegen 40 Geräte mit ausgefallener SoT schlägt einmal fehl, nicht vierzigmal.

B — SoT für das Inventar, Anmeldeinformationen in der .env

Identisch zu A mit einer umgedrehten Variable:

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

Sie erhalten das dynamische Inventar — der Teil, der sich auszahlt — ohne das Anmeldeinformations-Plugin und ohne den Fernet-Key. Ein Dienstkonto wird für jedes Gerät verwendet.

NetBox oder jede NetBox-förmige SoT

Das Inventar-Backend spricht den NetBox-REST-Dialekt, daher funktioniert NetBox selbst in dieser Variante, unverändert:

Was das Backend aufruft

Was es liest

dcim/devices/

die Geräteliste, gefiltert durch den Bereichsfilter und paginiert

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

welches auch immer FEDELE_GROUP_SOURCE auswählt, wird zu den Gerätegruppen

device.primary_ip.address

der SSH-Host, Maske entfernt

device.platform.name

der Netmiko device_type, validiert gegen CLASS_MAPPER

Zeigen Sie FEDELE_URL auf die NetBox-Instanz (/api wird angehängt, wenn Sie es weglassen) und FEDELE_TOKEN auf ein NetBox-API-Token — der Client authentifiziert sich mit dem Authorization: Token …-Header, den NetBox erwartet. Die Variablen behalten das FEDELE_-Präfix; das ist ein Benennungs-Erbe, keine Produktanforderung.

Die eine Anforderung, die NetBox standardmäßig nicht erfüllt: platform.name muss exakt ein Netmiko device_type seincisco_ios, arista_eos, huawei_vrp, juniper_junos. Eine Plattform namens "Cisco IOS 15.2" ist kein device_type, daher wird jedes Gerät, das sie trägt, aus dem Inventar ausgeschlossen. Benennen Sie entweder die Plattformen in NetBox um oder akzeptieren Sie die Ausschlüsse, die gemeldet werden.

Anmeldeinformationen sind der Teil, den NetBox nicht abdeckt: Die plugins/credentials/…-Endpunkte gehören zu Fedeles Plugin. Mit einfachem NetBox ist Variante A nicht verfügbar — bleiben Sie bei B.

C — In sich geschlossen: keine SoT

Alles lebt in diesem Projekt. Es wird nie ein externer Dienst kontaktiert.

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

Dateien: inventory.yml ist hier erforderlich — es ist der einzige Ort, an dem die Geräte existieren. commands.yml bleibt empfohlen, nicht erforderlich. Das Inventar ist das netmiko_tools-Format — eine flache Zuordnung von Name zu Verbindungsdaten, plus Gruppenschlüssel:

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

Die Datei, die dieses Projekt ausliefert, enthält Beispieldaten: 12 fiktive Geräte in den RFC 5737-Dokumentationsbereichen, 7 Gruppen und Plattformen, die so ausgewählt wurden, dass jeder in der Zulassungsliste erwähnte CLI-Dialekt vertreten ist. Ersetzen Sie sie durch Ihre eigene Umgebung.

Dies ist die Konfiguration, die dieses Projekt standardmäßig ausliefert, und es ist auch der Degraded Mode: Wenn die SoT ausfällt, verschieben zwei Variablen und ein Neustart ein Flavor-A- oder Flavor-B-Deployment hierher. Es lohnt sich, das zu üben, bevor man es braucht.

Der Preis dafür ist, dass die Datei veraltet. scripts/export_inventory.py im übergeordneten Repository regeneriert sie aus der SoT; führen Sie es regelmäßig aus. Ein Backup-Inventar mit Adressen von vor sechs Monaten ist schlimmer als gar kein Backup, weil man es erst während des Betriebs merkt.

Was in allen drei gleich bleibt

Die Befehlspolicy, der Audit-Trail, das Output-Paging und die Tool-Oberfläche ändern sich nicht zwischen den Flavors. Der agentenseitige Vertrag ist identisch, weshalb die Fähigkeit keine variantenspezifische Anpassung benötigt.

commands.yml ist empfohlen, nicht erforderlich

Der Server läuft auch ohne sie. Wenn die Datei fehlt, verweigert er nicht alles und weigert sich nicht zu starten: Ein eingebauter Fallback von 16 schreibgeschützten Befehlen übernimmt — show version, show ip interface brief, display version und ihre Junos/VRP-Äquivalente. Das ist beabsichtigt. Eine leere Policy würde jeden Befehl verweigern, während der Server sich selbst als gesund meldet, was für einen Operator wie "das Gerät hat verweigert" aussieht, nicht wie "niemand hat eine Policy geschrieben". Der Fallback wird beim Start angekündigt, netmiko.get_command_policy meldet policy_source: "fallback", und jeder geprüfte Versuch trägt die Quelle.

Die Datei ist also eine Policy-Entscheidung, kein Installationsschritt: Der Fallback lässt Sie den Server beim ersten Versuch ausführen, und Sie schreiben commands.yml, wenn Sie die eigene Policy der Umgebung anstelle einer konservativen Vorgabe möchten. Was Sie nicht tun können, ist eine Policy zu haben, die Sie nicht gewählt haben, und es nicht zu wissen — der Server sagt jedes Mal, welche in Kraft ist, wenn er gefragt wird.


Die .mcp.json-Datei

.mcp.json im Projektstammverzeichnis deklariert die MCP-Server für dieses Projekt. Claude Code fragt nach Zustimmung, wenn es die Datei zum ersten Mal sieht, und die Datei soll eingecheckt werden: So erhält das gesamte Team denselben Server.

Zwei andere Bereiche existieren für dieselbe Serverdefinition:

Bereich

Wo es lebt

Wer es sieht

project

.mcp.json im Projektstammverzeichnis

jeder, der das Projekt öffnet (nach Zustimmung)

user

~/.claude.json

jedes Projekt dieses Benutzers, auf diesem Rechner

local

~/.claude.json, nach Projektpfad indiziert

nur dieser Benutzer, nur in diesem Projekt

claude mcp add --scope project netmiko -- /path/to/python /path/to/server.py schreibt den project-Eintrag für Sie; das manuelle Bearbeiten der JSON ist gleichwertig.

Form der Datei

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

Der Servername ist nicht kosmetisch: Claude Code stellt jedes Tool als mcp__<server-name>__<tool-name> dar. Mit dem Namen netmiko und dem Tool netmiko.get_metadata, das der Server registriert, ist das Tool, das Claude tatsächlich sieht, mcp__netmiko__netmiko.get_metadata. Führen Sie /mcp aus, um die genauen Namen zu lesen, bevor Sie sie in eine allowed-tools-Liste oder eine Berechtigungsregel schreiben.

Feldreferenz

Feld

Transport

Bedeutung

type

beide

"stdio" (Standard, wenn weggelassen), "http" oder "sse"

command

stdio

die auszuführende ausführbare Datei. Absoluter Pfad — kein cwd annehmen

args

stdio

Argumentliste, jedes Element getrennt

env

stdio

Umgebung für den Kindprozess. Über die geerbte Umgebung gelegt

url

http / sse

vollständige Endpunkt-URL, einschließlich Pfad

headers

http / sse

zusätzliche Anfrage-Header, typischerweise Authorization

Werte unterstützen Umgebungserweiterung: ${VAR} und ${VAR:-default}. Nützlich, um ein Token aus der eingecheckten Datei herauszuhalten:

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

Transport 1 — stdio (der von diesem Projekt verwendete)

Claude Code startet den Server als Kindprozess und kommuniziert über JSON-RPC über dessen stdin/stdout. Es lauscht nichts auf einem Port, nichts ist aus dem Netzwerk erreichbar, und die Prozesslebensdauer ist die der Sitzung. Dies ist die richtige Voreinstellung für einen Server, der SSH-Anmeldedaten enthält.

{
  "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"
      }
    }
  }
}

Zwei Dinge, die beißen:

  • Keine hartcodierten Pfade, und das Arbeitsverzeichnis ist nicht verlässlich. ${CLAUDE_PROJECT_DIR:-.} ist das, was die Datei so committbar hält; der nächste Abschnitt erzählt die ganze Geschichte, weil die offensichtliche Lesart falsch ist.

  • Der Server darf nicht auf stdout schreiben. stdout ist der Protokollkanal, und eine einzelne fehlgeleitete Zeile dort unterbricht die Sitzung. Logging erfolgt auf stderr plus die rotierende Datei unter LOG_FILE (5 MB × 3, erstellt 0600 — bei DEBUG enthält diese Datei Geräteausgaben). Innerhalb von Niko wird dieselbe Variable stattdessen von MCPLogging behandelt.

Woher ${CLAUDE_PROJECT_DIR:-.} kommt

Zwei separate Dinge in einem String: eine Syntax und eine Variable.

Die Syntax. ${VAR} und ${VAR:-default} ist die POSIX-Parametersubstitution ("verwende VAR; wenn es nicht gesetzt oder leer ist, verwende default"), aber es ist keine Shell beteiligt — eine JSON-Datei durchläuft nie eine. Claude Code implementiert die Erweiterung selbst, wenn es die Datei liest, in command, args, env, url und headers. Es ist eine Konvention dieses Clients, nicht Teil der MCP-Spezifikation: Ein anderer Client implementiert sie möglicherweise nicht (siehe Nicht-Claude-Agenten, wo die Pfade dann literal sein müssen), und VS Code hat seine eigene Schreibweise, ${workspaceFolder}.

Die Variable. CLAUDE_PROJECT_DIR wird von Claude Code auf das Projektstammverzeichnis gesetzt, denselben Wert, den Hooks erhalten. Sie ist stabil — das Gewähren zusätzlicher Arbeitsverzeichnisse während einer Sitzung mit --add-dir verschiebt sie nicht.

Der Teil, der kontraintuitiv ist, und der Grund, warum :-. keine Dekoration ist: Claude Code setzt diese Variable in der Umgebung des Servers, den es startet, nicht in seiner eigenen. Die Erweiterung erfolgt jedoch vor dem Start, gegen die Umgebung von Claude Code — wo die Variable nicht existiert. Ein bloßes ${CLAUDE_PROJECT_DIR} würde sich daher zu nichts erweitern und /config/netmiko/inventory.yml hinterlassen, einen absoluten Pfad zum Wurzelverzeichnis des Dateisystems.

In einer projektspezifischen .mcp.json ist der Standardwert also kein Fallback für einen Randfall: es ist der Wert, der jedes Mal verwendet wird. Was den Prozess erreicht, ist ./config/netmiko/inventory.yml. Die eine Ausnahme ist eine MCP-Konfiguration, die von einem Plugin mitgeliefert wird — dort setzt Claude Code die Variable direkt ein und es wird kein Standardwert benötigt.

Das zwingt den Server in die Knie. Ein relativer Wert würde gegen das cwd des Kindprozesses aufgelöst, und das cwd ist die Wahl des Clients, nicht des Projekts. Daher resolve_project_path(): Jede relative Pfadeinstellung wird beim Laden der Einstellungen an PARENT_DIR verankert — das übergeordnete Verzeichnis von mcps/, dieselbe Wurzel, von der die .env kommt. Eine von überall gestartete Sitzung findet config/netmiko/, und validate_startup() nennt die absolute Datei, wenn eine fehlt. Ein ~ bedeutet immer das Home-Verzeichnis des Operators, niemals eine Datei innerhalb des Projekts.

Die Variable ist immer noch nützlich, wie die Dokumentation es vorsieht, wenn sie von innerhalb des Servers gelesen wird (os.environ["CLAUDE_PROJECT_DIR"]), wo sie gesetzt ist. Dieser Server benötigt sie nicht: PARENT_DIR leitet sich von __file__ ab und hängt daher von keinem Client ab — derselbe Grund, warum der HTTP-Transport, wo niemand diese Variable setzt, keinen Sonderfall benötigt.

Quelle: Claude Code — MCP, Abschnitte Add a local stdio server und Environment variable expansion in .mcp.json.

Transport 2 — HTTP (streamable HTTP)

Claude Code unterstützt es, und jeder andere MCP-Client auch. Es ist der Transport, der verwendet werden sollte, wenn der Server woanders läuft: ein anderer Host, ein Container, ein von mehreren Agenten gemeinsam genutzter Dienst oder ein Agent, der nicht Claude ist.

Die Serverdatei ruft immer mcp.run(transport="stdio") unter ihrem __main__-Guard auf, daher wird HTTP stattdessen von der FastMCP-CLI bereitgestellt — keine Codeänderung:

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

Die NETMIKO_MCP_*-Variablen sind nicht mehr Teil der Client-Konfiguration: Der Serverprozess wird von Ihnen gestartet, daher gehören sie zu seiner Umgebung (ein Shell-Export, eine systemd-Unit, ein environment:-Block eines Containers).

Clientseite:

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

Oder äquivalent: claude mcp add --transport http netmiko http://127.0.0.1:8123/mcp/.

--transport sse und "type": "sse" funktionieren ebenfalls; SSE ist der ältere Remote-Transport und wird für Clients beibehalten, die noch nicht auf streamable HTTP umgestiegen sind.

Sicherheit. Die FastMCP-CLI stellt dies ohne Authentifizierung bereit: Jeder, der den Port erreicht, kann Show-Befehle gegen jedes Gerät im Inventar ausführen, unter Verwendung der Anmeldedaten in der Serverumgebung. Binden Sie für einen lokalen Test an 127.0.0.1, und für alles, was geteilt wird, setzen Sie es hinter einen Reverse-Proxy, der TLS beendet und den Authorization-Header prüft. Der headers-Block oben ist das, was der Client sendet; der Proxy muss es überprüfen.

Nicht-Claude-Agenten

Das hier gezeigte mcpServers-Objekt ist die De-facto-Form: Claude Code, Claude Desktop, Cursor und Windsurf lesen alle dieselben drei Felder für stdio (command / args / env) und dieselben zwei für Remote (url / headers). Das Kopieren eines Eintrags zwischen ihnen funktioniert normalerweise unverändert.

Bekannte Unterschiede, die es wert sind, vor dem Kopieren überprüft zu werden:

  • VS Code verwendet mcp.json mit einem "servers"-Schlüssel auf oberster Ebene anstelle von "mcpServers" und erwartet, dass "type" explizit angegeben wird.

  • Einige Clients implementieren keine ${VAR}-Erweiterung; dort muss der Wert literal sein, was ein Argument für den HTTP-Transport plus einen Proxy ist, anstatt ein Token in eine eingecheckte Datei einzufügen.

  • Ein Agent ohne Konfigurationsdatei kann trotzdem direkt mit dem HTTP-Endpunkt sprechen — die URL und der Authorization-Header sind der gesamte Vertrag.

Der env-Block

Die NETMIKO_MCP_*-Einträge haben Vorrang vor jeder YAML-Konfigurationsdatei. Sie werden explizit gesetzt, weil es außerhalb von Niko kein NikoPaths gibt, sodass die Standardwerte auf ~/commands.yml und ~/.netmiko_mcp_tmp zurückfallen.

Jeder Pfad hier kann relativ zum Projektstammverzeichnis angegeben werden: Der Server verankert relative Werte beim Laden der Einstellungen an PARENT_DIR, sodass das cwd des gestarteten Prozesses niemals entscheidet, wo das Inventar oder der Audit-Trail liegt. Ein absoluter Pfad oder ein ~ wird wie geschrieben übernommen.

Variable

Standard

Zweck

NETMIKO_MCP_INVENTORY_TYPE

netmiko_tools

yaml (lokale Datei) oder fedele (SoT)

NETMIKO_MCP_INVENTORY_FILE

(netmiko-tools-Suche)

Inventarpfad, wenn der Typ yaml ist

NETMIKO_MCP_CREDENTIAL_SOURCE

env

env (liest die .env) oder fedele

NETMIKO_MCP_FEDELE_GROUP_SOURCE

tags

Was eine Gruppe definiert: tags, device_roles, sites

NETMIKO_MCP_FEDELE_DEVICE_FILTER

(keiner)

Bereichsfilter, tag=lab&status=active. Ohne Angabe: das gesamte Inventar

NETMIKO_MCP_FEDELE_CACHE_TTL

60

SoT-Auflösungs-Cache, in Sekunden

NETMIKO_MCP_COMMAND_FILE

~/commands.yml außerhalb von Niko

Erlaubnis-/Verbotsliste

NETMIKO_MCP_ALLOW_PIPE

false

Aktiviert Pipes in Befehlen

NETMIKO_MCP_SSH_CONFIG_FILE

(keiner)

OpenSSH ssh_config. Erforderlich für Jumphosts – Netmiko liest ~/.ssh/config nicht von selbst

NETMIKO_MCP_MAX_WORKERS

10

Gleichzeitige Verbindungen bei Gruppenbefehlen

NETMIKO_MCP_SAVE_OUTPUT_DIR

~/.netmiko_mcp_tmp außerhalb von Niko

Puffer für große Ausgaben

NETMIKO_MCP_SAVE_THRESHOLD

1000

Zeilenanzahl, ab der die Ausgabe gespeichert statt inline zurückgegeben wird

NETMIKO_MCP_AUDIT_LOG_FILE

(siehe übergeordnete README)

Prüfpfad (JSON, Fail-Closed)

NETMIKO_MCP_CONFIG

~/.netmiko-mcp.yml

Pfad zu einer YAML-Konfigurationsdatei mit denselben Einstellungen

LOG_FILE / LOG_LEVEL

Niko.log / INFO

Betriebsprotokoll: stderr immer, plus diese rotierende Datei (5 MB × 3, 0600). LOG_LEVEL wird mit seinem Standardwert angegeben, damit der Drehknopf dort ist, wo Sie ihn suchen – setzen Sie ihn auf DEBUG und die Geräteausgabe landet im Log

Anmeldeinformationen werden nicht hier gesetzt. NETMIKO_USERNAME, NETMIKO_PASSWORD, NETMIKO_SECRET und die FEDELE_*-Variablen werden aus <project-root>/.env gelesen, sodass sie nie in einer committeten JSON-Datei landen. Priorität: Was im env-Block steht, gewinnt gegenüber der .env, stillschweigend – definieren Sie jede Variable genau an einer Stelle.

Jede andere Variable ist in der README des übergeordneten Repositorys dokumentiert.

Überprüfen, ob es funktioniert

claude mcp list          # netmiko: ✓ connected

Innerhalb der Sitzung listet /mcp die Tools auf und /skills bestätigt, dass das Skill geladen wurde. Fragen Sie, welche Richtlinie in Kraft ist, und netmiko.get_command_policy nennt die Datei, die es liest – oder meldet "fallback", was bedeutet, dass es die Datei nie gefunden hat und mit den 16 integrierten Befehlen läuft.


Autor: Ed Scrimaglia edgardo.scrimaglia@gmail.com — zuletzt aktualisiert: 2026-08-18.

-
license - not tested
-
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

  • Let AI operate servers without SSH. Choose actions, approve risky changes, and audit every step.

  • Read-only bank access for your AI agent. Connects Claude, ChatGPT, Cursor, Gemini, Codex.

  • Operate Linux, macOS and Windows from your LLM. Every action runs through an auditable allowlist.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/escrimaglia/netmiko-mcp-claude'

If you have feedback or need assistance with the MCP directory API, please join our Discord server