kubernetools MCP Server

официальный

Help AI agents write accurate, up-to-date Kubernetes manifests by giving them the official Kubernetes API reference, so they can look up kinds, fields, and nested types with current specs across the latest and three previous Kubernetes versions

Документация

kubernetools/mcp-server

Образ контейнера для MCP-сервера kubernetools.

Реестр: ghcr.io/kubernetools/mcp-server

Быстрый старт

Анонимный режим (локальное использование)

Аутентификация не требуется; все подключения ограничиваются по частоте на уровне бесплатного тарифа для каждого исходного IP-адреса.

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

С аутентификацией по API-ключу

# 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

Конфигурация

ПараметрПеременная окруженияОписание
Версии KubernetesK8S_VERSIONSСписок версий для предварительной загрузки через запятую (например, v1.33,v1.34). По умолчанию: v1.33.
Токен GitHubGITHUB_TOKENПерсональный токен доступа (дополнительные разрешения не требуются). Необязательный параметр; повышает лимит частоты запросов к GitHub API с 60 до 5 000 запросов/ч — рекомендуется при загрузке нескольких версий.
Хранилище ключейKEY_STORE_PATHПуть к JSON-файлу с API-ключами (смонтируйте его в контейнер). Если не указан, сервер работает в анонимном режиме: аутентификация не требуется, и все подключения ограничиваются по частоте на уровне бесплатного тарифа для каждого исходного IP-адреса.
Разрешённые хостыALLOWED_HOSTSСписок допустимых значений заголовка Host через запятую (например, mcp.example.com,mcp.example.com:443). Если не указан, проверка хоста отключена — подходит только для локальной разработки. В production-среде всегда задавайте этот параметр для предотвращения атак с повторной привязкой DNS.
Перенаправление из браузераBROWSER_REDIRECT_URLURL для перенаправления обычных GET-запросов из браузера. MCP-клиенты определяются по Accept: text/event-stream; браузеры вместо этого получают 307 на этот URL. Если не указан, GET-запросы из браузера возвращают 400.
Уровень логированияRUST_LOGФильтр уровня логирования (например, info, debug, mcp=debug).
Порт--publishСервер слушает порт 3000.

Аутентификация

Хранилище API-ключей

Хранилище ключей представляет собой плоский JSON-массив, загружаемый один раз при запуске:

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

Каждый запрос должен содержать ключ в заголовке Authorization:

Authorization: Bearer free-key-abc

Запросы без действительного ключа получают 401 Unauthorized.

Анонимный режим

Если KEY_STORE_PATH не задан, сервер работает без аутентификации. Все подключения принимаются и ограничиваются по частоте на уровне бесплатного тарифа для каждого исходного IP-адреса. Удобно для локального использования; не открывайте публичный доступ.

Тарифы и ограничения частоты

ТарифЛимит
free10 запросов/минуту, всплеск 10
paid~1 000 запросов/секунду, всплеск 1 000 (фактически безлимитный)

Запросы, превышающие лимит, получают 429 Too Many Requests. Лимиты отслеживаются для каждого API-ключа, а не для IP-адреса.

Подключение MCP-клиента

Сервер реализует транспорт MCP Streamable HTTP. Конечная точка:

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

Параметр запроса version выбирает версию Kubernetes для сессии. Если не указан, используется первая загруженная версия. При указании неизвестной версии возвращается 400 Bad Request.

Claude Desktop

Добавьте следующее в claude_desktop_config.json:

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

Доступные инструменты

list_resources

Облегчённое обнаружение — возвращает по одной записи на ресурс, отсортированной по (group, kind, api_version). Используйте этот инструмент в первую очередь для поиска имён типов (kind).

Необязательные фильтры: group (например, "apps", "core"), api_version (например, "v1").

get_resource

Полная информация о ресурсе — поля, spec, status и поля списков — достаточная для написания манифеста за один вызов. Обязательный параметр: kind. Необязательные: group, api_version (по умолчанию — самая последняя версия).

Поля с непустым type_ref и пустым sub_fields следует детализировать с помощью get_type.

get_type

Детализация отдельного составного типа, на который ссылается type_ref в выводе get_resource. Обязательный параметр: type_name (например, "Container", "PodFailurePolicy").

Типичный поток запросов

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

Проверка работоспособности

GET /healthz на порту 3000.

  • Возвращает 503 Service Unavailable (тело: loading) во время загрузки документации Kubernetes API.
  • Возвращает 200 OK (тело: ok) после готовности сервера.

Эта конечная точка не требует аутентификации и не имеет ограничений по частоте.

Используйте её для проб запуска, готовности и живости:

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

Ответы с ошибками

HTTP-статусПричина
307 Temporary RedirectGET-запрос из браузера, когда задан BROWSER_REDIRECT_URL
400 Bad RequestGET-запрос из браузера, когда BROWSER_REDIRECT_URL не задан, или параметр version указывает версию, не загруженную при запуске
401 UnauthorizedОтсутствует или недействителен заголовок Authorization: Bearer <key>
429 Too Many RequestsПревышен лимит частоты для тарифа ключа

Ошибки уровня MCP (неизвестное имя инструмента, отсутствует обязательный аргумент, тип не найден) возвращаются как содержимое ошибки MCP внутри обычного ответа 200.

Примеры

Несколько версий Kubernetes

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

Production-настройка с проверкой хоста

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

Отладочное логирование

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

Привязка к конкретному релизу

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

Образ

Собран на основе registry.access.redhat.com/hi/core-runtime:2.42-openssl — минимального, бездистрибутивного рантайма glibc + OpenSSL. Без оболочки и менеджера пакетов.