Kubernetes · Model Context Protocol · Local-first

Two faces. One cluster. No exposed keys.

An MCP server that gives AI assistants a safe, controlled window into your Kubernetes clusters. It runs locally, holds your KUBECONFIG close to its chest, and lets the model operate through carefully scoped tools: no token, certificate, or API server URL ever leaves your machine.

Quick start View the source
$ { ,  ,  }  install janus-mcp-server

0
Secrets in the kind registry
3
Redaction layers per response
5
Security invariants, CI-verified
1
Pinned kubeconfig context

How it works
What the model sees

Declarative tool definitions and sanitized results, never raw cluster state, never a text dump.

  • Tools carry ToolAnnotations: readOnlyHint, openWorldHint: false, so the client knows what is safe to call unattended.
  • Clients that support MCP resources can pin cluster://summary into context: a cached health overview for free, no tool call spent.
  • Where elicitation is supported, write approvals arrive as native cards showing live state; elsewhere the tool returns status=pending with an approval id.
Where the policy lives

Operator-authoritative config, checked at startup and again at call time.

  • The kubeconfig context is pinned by exact match. The server refuses to start on any other one, and warns if those credentials can read Secrets.
  • ScopeGuard (deny wins), token-bucket rate limits per tool, and an ApprovalGate that binds a SHA-256 of the exact arguments to the approval id and burns it on use.
  • Strict config parsing rejects unknown keys, so a typo in a security-relevant setting fails at startup rather than silently opening a door.
  • Every call lands in an append-only audit log at ~/.local/state/janus-mcp/audit.jsonl.
The absence is the control

Secrets are not filtered out of the kind registry. They were never in it.

  • A single module imports the Kubernetes client library; raw client errors embed the API server URL, so each one is mapped to a typed, generic message before it can travel.
  • The shipped RBAC manifests grant least privilege, and list no Secret verbs anywhere.
  • EKS, GKE and AKS need nothing janus-specific: auth is whatever your kubeconfig says, including exec: credential plugins.
  • Node provider IDs, external IPs, cloud labels and IAM role annotations are masked by the redaction engine by default.
Every tool call runs the same pipeline
validate → ScopeGuard → RateLimiter → kube call → structural redaction → pattern + entropy scrub → envelope byte-cap → audit

Rendering failures fail closed: the model gets a generic error, never a partially-redacted payload.


The surface

Tools, not text dumps.

Read-only diagnostics come free. Write tools only register when an operator lists them in the config, and a global read-only switch removes them from the listing entirely.

get_pods get_events get_logs list_namespaces describe_resource get_cluster_summary cluster://summary rollout_restart scale_deployment
ToolWhat it returnsMode
get_podsPod inventory and status for an allowed namespaceread
get_eventsRecent warning and normal events, sanitizedread
get_logsBounded log tail, scrubbed for secrets and high-entropy stringsread
list_namespacesNamespaces the operator has put in scoperead
describe_resourceOne resource by kind and name, without env-var values or credential annotationsread
get_cluster_summaryOne-screen health overview, cachedread
cluster://summaryThe same overview as a pinnable MCP resourceresource
rollout_restartRestarts a deployment after human approvalwrite
scale_deploymentScales within max_replicas after human approvalwrite

Every tool declares its annotations up front, output is bounded by a byte cap, and each call is rate-limited per tool. Parameter reference lives in the operator runbook.


Quick start
01 Install

Three ways from PyPI, all giving you the janus-mcp CLI. Contributors can clone and uv sync instead.

uv uv tool install janus-mcp-server
pipx pipx install janus-mcp-server
pip pip install janus-mcp-server

No install at all: uvx janus-mcp-server serve runs it one-shot.

02 Configure

Two settings are required: the pinned context and the namespaces it may touch. The server refuses to start on any other context.

context: limited-sa@prod-cluster
scope:
  allowed_namespaces: ["prod", "staging"]
  denied_namespaces: ["kube-system"]
  allow_cluster_scoped: false
read_only: false
write_tools:
  enabled: ["rollout_restart", "scale_deployment"]
  max_replicas: 20
03 Register with your client
{{ snippetPath }}
{{ snippetCode }}

{{ snippetNote }}

04 Ask it something
Why are pods crashing in the prod namespace? Summarize the health of my cluster. Show me recent warning events for payments-api.