kubernetools MCP Server

offiziell

Hilft KI-Agenten dabei, präzise und aktuelle Kubernetes-Manifeste zu erstellen, indem es ihnen die offizielle Kubernetes-API-Referenz bereitstellt, sodass sie Arten, Felder und verschachtelte Typen mit aktuellen Spezifikationen für die neueste und drei vorherige Kubernetes-Versionen nachschlagen können.

Dokumentation

kubernetools/mcp-server

Container-Image für den kubernetools MCP-Server.

Registry: ghcr.io/kubernetools/mcp-server

Schnellstart

Anonymer Modus (lokale Nutzung)

Keine Authentifizierung erforderlich; alle Verbindungen werden pro Quell-IP auf das Free-Tier-Limit ratenbegrenzt.

podman run -d \
  -p 3000:3000 \
  -e K8S_VERSIONS=v1.33 \
  ghcr.io/kubernetools/mcp-server:latest

Mit API-Key-Authentifizierung

# 1. Create a key store file
echo '[{"key":"mykey","tier":"free"}]' > keys.json

# 2. Start the server
podman run -d \
  -p 3000:3000 \
  -v "$(pwd)/keys.json:/keys.json:ro" \
  -e K8S_VERSIONS=v1.33,v1.34,v1.35,v1.36 \
  -e KEY_STORE_PATH=/keys.json \
  ghcr.io/kubernetools/mcp-server:latest

Konfiguration

ParameterUmgebungsvariableBeschreibung
Kubernetes-VersionenK8S_VERSIONSKommagetrennte Liste der vorzuladenden Versionen (z. B. v1.33,v1.34). Standard: v1.33.
GitHub-TokenGITHUB_TOKENPersönliches Zugriffstoken (keine zusätzlichen Bereiche erforderlich). Optional; erhöht das GitHub-API-Ratenlimit von 60 auf 5 000 Anfragen/Stunde – empfohlen beim Laden mehrerer Versionen.
SchlüsselspeicherKEY_STORE_PATHPfad zur API-Key-JSON-Datei (in den Container einbinden). Wenn weggelassen, läuft der Server im anonymen Modus: Keine Authentifizierung erforderlich, alle Verbindungen werden pro Quell-IP auf das Free-Tier-Limit ratenbegrenzt.
Erlaubte HostsALLOWED_HOSTSKommagetrennte Host-Header-Werte, die akzeptiert werden (z. B. mcp.example.com,mcp.example.com:443). Wenn weggelassen, ist die Host-Validierung deaktiviert – nur für die lokale Entwicklung geeignet. In der Produktion immer setzen, um DNS-Rebinding-Angriffe zu verhindern.
Browser-WeiterleitungBROWSER_REDIRECT_URLURL, an die einfache Browser-GET-Anfragen weitergeleitet werden. MCP-Clients werden anhand von Accept: text/event-stream erkannt; Browser erhalten stattdessen ein 307 auf diese URL. Wenn weggelassen, geben Browser-GETs 400 zurück.
Log-LevelRUST_LOGLog-Level-Filter (z. B. info, debug, mcp=debug).
Port--publishDer Server lauscht auf Port 3000.

Authentifizierung

API-Key-Speicher

Der Schlüsselspeicher ist ein flaches JSON-Array, das einmalig beim Start geladen wird:

[
  { "key": "free-key-abc", "tier": "free" },
  { "key": "paid-key-xyz", "tier": "paid" }
]

Jede Anfrage muss den Schlüssel im Authorization-Header enthalten:

Authorization: Bearer free-key-abc

Anfragen ohne gültigen Schlüssel erhalten 401 Unauthorized.

Anonymer Modus

Wenn KEY_STORE_PATH nicht gesetzt ist, läuft der Server ohne Authentifizierung. Alle Verbindungen werden akzeptiert und pro Quell-IP auf das Free-Tier-Limit ratenbegrenzt. Praktisch für die lokale Nutzung; nicht öffentlich zugänglich machen.

Stufen und Ratenlimits

StufeLimit
free10 Anfragen / Minute, Burst 10
paid~1 000 Anfragen / Sekunde, Burst 1 000 (praktisch unbegrenzt)

Anfragen, die das Limit überschreiten, erhalten 429 Too Many Requests. Limits werden pro API-Key verfolgt, nicht pro IP.

Verbinden eines MCP-Clients

Der Server implementiert den MCP Streamable HTTP-Transport. Der Endpunkt ist:

http://<host>:<port>/[?version=<k8s-version>]

Der version-Query-Parameter wählt die für die Sitzung zu verwendende Kubernetes-Version aus. Wenn weggelassen, wird die erste geladene Version verwendet. Eine unbekannte Version gibt 400 Bad Request zurück.

Claude Desktop

Folgendes zu claude_desktop_config.json hinzufügen:

{
  "mcpServers": {
    "kubernetools": {
      "url": "http://localhost:3000/?version=v1.36",
      "headers": {
        "Authorization": "Bearer mykey"
      }
    }
  }
}

Verfügbare Werkzeuge

list_resources

Leichtgewichtige Erkundung – gibt einen Eintrag pro Ressource zurück, sortiert nach (group, kind, api_version). Zuerst verwenden, um Kind-Namen zu finden.

Optionale Filter: group (z. B. "apps", "core"), api_version (z. B. "v1").

get_resource

Vollständige Ressourcendetails – Felder, Spec, Status und Listenfelder – genug, um ein Manifest in einem Aufruf zu schreiben. Erforderlich: kind. Optional: group, api_version (Standard: aktuellste).

Felder mit einem nicht-null type_ref und leerem sub_fields sollten mit get_type weiter aufgeschlüsselt werden.

get_type

Einen einzelnen zusammengesetzten Typ aufschlüsseln, der über type_ref in der get_resource-Ausgabe referenziert wird. Erforderlich: type_name (z. B. "Container", "PodFailurePolicy").

Typischer Abfrageablauf

list_resources                          → discover kind names and groups
  └─ get_resource(kind="Deployment")   → see all top-level fields + spec/status
       └─ get_type(type_name="...")    → drill into any complex type_ref

Gesundheitscheck

GET /healthz auf Port 3000.

  • Gibt 503 Service Unavailable (Body: loading) zurück, während die Kubernetes-API-Dokumentation geladen wird.
  • Gibt 200 OK (Body: ok) zurück, sobald der Server bereit ist.

Dieser Endpunkt umgeht Authentifizierung und Ratenbegrenzung.

Für Startup-, Readiness- und Liveness-Probes verwenden:

startupProbe:
  httpGet:
    path: /healthz
    port: 3000
  failureThreshold: 30   # allow up to 5 min for version loading
  periodSeconds: 10
readinessProbe:
  httpGet:
    path: /healthz
    port: 3000
livenessProbe:
  httpGet:
    path: /healthz
    port: 3000
  initialDelaySeconds: 10

Fehlerantworten

HTTP-StatusUrsache
307 Temporary RedirectBrowser-GET, wenn BROWSER_REDIRECT_URL gesetzt ist
400 Bad RequestBrowser-GET, wenn BROWSER_REDIRECT_URL nicht gesetzt ist, oder version-Parameter benennt eine beim Start nicht geladene Version
401 UnauthorizedFehlender oder ungültiger Authorization: Bearer <key>-Header
429 Too Many RequestsRatenlimit für die Stufe des Schlüssels überschritten

MCP-Level-Fehler (unbekannter Werkzeugname, fehlendes erforderliches Argument, Kind nicht gefunden) werden als MCP-Fehlerinhalt innerhalb einer normalen 200-Antwort zurückgegeben.

Beispiele

Mehrere Kubernetes-Versionen

podman run -d \
  -p 3000:3000 \
  -v "$(pwd)/keys.json:/keys.json:ro" \
  -e K8S_VERSIONS=v1.33,v1.34,v1.35,v1.36 \
  -e GITHUB_TOKEN=ghp_... \
  -e KEY_STORE_PATH=/keys.json \
  ghcr.io/kubernetools/mcp-server:latest

Produktionssetup mit Host-Validierung

podman run -d \
  -p 3000:3000 \
  -v "$(pwd)/keys.json:/keys.json:ro" \
  -e K8S_VERSIONS=v1.36 \
  -e KEY_STORE_PATH=/keys.json \
  -e ALLOWED_HOSTS=mcp.example.com,mcp.example.com:443 \
  -e BROWSER_REDIRECT_URL=https://example.com/docs \
  ghcr.io/kubernetools/mcp-server:latest

Debug-Logging

podman run -d \
  -p 3000:3000 \
  -e K8S_VERSIONS=v1.33 \
  -e RUST_LOG=debug \
  ghcr.io/kubernetools/mcp-server:latest

Auf eine bestimmte Version festlegen

podman run -d \
  -p 3000:3000 \
  -e K8S_VERSIONS=v1.33 \
  ghcr.io/kubernetools/mcp-server:0.1.0

Image

Gebaut auf registry.access.redhat.com/hi/core-runtime:2.42-openssl – einer minimalen, distributionslosen glibc- + OpenSSL-Laufzeitumgebung. Keine Shell oder Paketverwaltung.