kops

kops

A read-only kubectl MCP server for AI assistants. The kubectl verb is hardcoded in each tool (get/describe/logs/events) and user input only fills argument values — no mutation path even with malicious input, and Secret/ConfigMap values are never returned (metadata only). Returns structured JSON, plus one-shot k8s_triage (health scan) and k8s_inventory (cluster snapshot).

Category
访问服务器

README

kops

Read-only kubectl helper exposed to Claude Code via MCP. Six tools, all strictly read-only — verbs (get, describe, logs) are hardcoded; user input only fills argument values, never the verb itself.

Tool What it does
k8s_get List/fetch resources, returns summarized key fields per kind
k8s_describe kubectl describe text output for one resource
k8s_logs Pod logs with tail / since / previous flags
k8s_events Recent events filtered by namespace / kind / name
k8s_triage ⭐ One-shot cluster health scan — start here for diagnostics
k8s_inventory ⭐ One-shot comprehensive snapshot — start here for documentation / audits

Why

kubectl over Bash gives Claude text tables that need re-parsing every turn. Wrapping it as MCP returns structured JSON Claude can reason over directly — fewer tokens, fewer parse errors, and built-in safety boundaries (read-only verbs, name validation, output size caps).

Two aggregator tools (k8s_triage, k8s_inventory) compress common multi-step queries into single round-trips:

  • k8s_triage — "what's broken?" → 4 concurrent kubectl calls, returns problem pods + warning events + unhealthy nodes + stale deployments
  • k8s_inventory — "show me everything" → 14+ concurrent kubectl calls, returns cluster-wide snapshot grouped by namespace. Replaces ~50 individual k8s_get calls (~6× faster end-to-end for cluster docs).

Install

Requires uv and kubectl in your PATH.

git clone https://github.com/kaka-milan-22/kops.git
cd kops
uv sync

The commands below use /path/to/kops for the absolute path of this clone — replace it with your actual path (e.g. the output of pwd run from inside the cloned directory). uv --directory needs an absolute path.

Smoke test (no cluster needed)

MCP requires a handshake (initializenotifications/initialized) before any business request, so a bare tools/list over stdin is rejected with Received request before initialization was complete. Feed all three messages in order:

{
  printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"smoke","version":"0"}}}'
  printf '%s\n' '{"jsonrpc":"2.0","method":"notifications/initialized"}'
  printf '%s\n' '{"jsonrpc":"2.0","id":2,"method":"tools/list"}'
} | uv run kops

Expect: an initialize response, then a tools/list response listing the 6 tools with input schemas. (The notification has no id and produces no reply.)

Visual debug with MCP Inspector

For interactive debugging, skip the raw stdio dance and use the official tools — they handle the handshake for you:

# Option A: MCP Inspector (browser UI)
npx @modelcontextprotocol/inspector uv --directory /path/to/kops run kops

# Option B: mcp dev (bundled with the mcp[cli] extra already in deps)
uv run mcp dev src/kops/server.py

Open the URL each prints, click a tool, exercise its parameters.

Register with Claude Code

claude mcp add -s user kops -- uv --directory /path/to/kops run kops

Or manually in ~/.claude.json under mcpServers:

{
  "mcpServers": {
    "kops": {
      "command": "uv",
      "args": ["--directory", "/path/to/kops", "run", "kops"]
    }
  }
}

Reload Claude Code (or open a new session). Tools surface as mcp__kops__k8s_get, mcp__kops__k8s_triage, mcp__kops__k8s_inventory, etc.

Multi-cluster (kubeconfig isolation)

To talk to a foreign cluster without polluting ~/.kube/config, register a separate server entry with its own KUBECONFIG:

claude mcp add -s user -e KUBECONFIG=/path/to/qa-cluster.yaml \
  kops-qa -- uv --directory /path/to/kops run kops

Tools then surface as mcp__kops_qa__k8s_triage etc, fully isolated.

End-to-end smoke (with a kind cluster)

kind create cluster --name kops-test
kubectl run broken --image=nonexistent:fake --restart=Never
sleep 30

Then in Claude Code, ask: "this cluster has problems, what's wrong?"

Expected: Claude calls mcp__kops__k8s_triage first, sees the broken pod in ImagePullBackOff, then k8s_describe for root cause.

For a documentation example, ask: "give me a full report of this cluster".

Expected: Claude calls mcp__kops__k8s_inventory once and assembles a structured markdown report covering nodes, namespaces, workloads, services, exposure surface, and configuration counts.

What k8s_get returns per kind

_summarize_resource extracts only the fields most useful for diagnostics and documentation. Avoids dumping full spec to keep token usage sane.

Kind Summarized fields
Pod phase, ready, restarts, node, podIP, images, containerCount, resources (when declared), reason (when stuck)
Service type, clusterIP, externalIPs, loadBalancer, ports[] (incl. nodePort)
Deployment desired, available, updated, ready, images, containerCount, resources
StatefulSet / DaemonSet / ReplicaSet desired, ready, images, containerCount, resources
Node ready, kubeletVersion, internalIP, pressures (only if any are True)
Ingress hosts[]
Namespace / generic name, namespace, kind, age, labels (top 5)

Where resources is the sum across all main containers of requests and limits (init containers excluded — they don't run concurrently with steady state, so don't add to scheduling footprint). CPU normalized to millicores, memory normalized to binary units (Ki/Mi/Gi). Init containers still appear in images[] with an init: True flag.

What k8s_inventory returns

{
  "summary": {
    "scope": "cluster-wide" | "namespace=<name>",
    "namespaces": int, "nodes": int, "pods_total": int,
    "by_kind_counts": {"deployments": N, "services": N, ...},
    "istio_present": bool,
    "include_istio": bool,
  },
  "nodes": [<summarized node>, ...],         # cluster-scoped only
  "namespaces": [
    {
      "name": "...", "age": "...", "labels": {...},
      "pods": int,                            # count only (full pod list not included)
      "deployments": [<summarized>, ...],
      "statefulsets": [...], "daemonsets": [...],
      "services": [...], "ingresses": [...], "hpa": [...],
      "pvcs": [...], "configmaps": [...], "secrets": [...],
      "jobs": [...], "cronjobs": [...],
      "istio_gateways": [...], "istio_virtualservices": [...], "istio_destinationrules": [...],
    },
    ...
  ]
}

ConfigMap data and Secret values are never returned — only metadata (names, key lists, age). This is a hard safety boundary; if you need actual config content, go through Bash + kubectl under explicit permission.

Pods are not included as a list (potentially huge). Use k8s_triage for pod health, k8s_get pod for specific pods.

Safety

  • Mutation defense: verb is hardcoded inside each tool function. User input only fills argument values, never the verb. There is no path to delete / apply / patch / scale / exec from any input.
  • Injection defense: subprocess.run([...], shell=False) everywhere. Names/namespaces/containers validated against ^[a-zA-Z0-9._-]{1,253}$. Selectors validated against a K8s label-selector character set.
  • Resource limits: kubectl invoked with 30s timeout. Log tail clamped to 1000 lines. Output size capped (30KB describe, 50KB logs).
  • Context isolation: default uses kubectl config current-context. The optional context argument can override but cannot inject a KUBECONFIG path. For full isolation across clusters, register a separate MCP server entry with its own KUBECONFIG env var.

Extending

Add another tool by writing a new @mcp.tool() function in src/kops/server.py:

  • Hardcode the verb.
  • Validate inputs with the existing helpers (_validate_kind, _validate_name, _validate_selector, _validate_since).
  • Call kubectl via _run_kubectl([...]).
  • Reuse _summarize_resource for output shaping if your tool returns resources.
  • Type hints on the function signature become the JSON-RPC input schema automatically (FastMCP handles this).

For aggregator tools (triage / inventory style), follow the pattern: build a list of kubectl get -A -o json arg vectors, fan out via ThreadPoolExecutor(max_workers=8), post-process and group locally. CRD detection is graceful — wrap the per-kind kubectl call in a try/except RuntimeError and skip absent kinds silently.

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选