microk8s-mcp View on GitHub

Configuration

Everything is environment variables, passed at registration time. There is no config file, and nothing is read from your shell — Claude Code launches the server with its own environment.

How to set them

Pass each one with --env when registering:

claude mcp add --transport stdio microk8s \
  --env MICROK8S_MCP_KUBECONFIG=/home/you/.kube/claude-mcp.kubeconfig \
  --env MICROK8S_MCP_SSH_HOST=you@your-node \
  --env MICROK8S_MCP_MODE=read-write \
  --env MICROK8S_MCP_NAMESPACES=apps,staging \
  -- /home/you/microk8s-mcp/.venv/bin/microk8s-mcp

The make register and make register-rw targets set the common ones for you with absolute paths filled in. To see what is actually registered at any point:

claude mcp get microk8s

Boolean variables accept 1, true, yes or on (case-insensitive). Anything else is false.

Core settings

VariableDefaultEffect
MICROK8S_MCP_MODE read-only Set read-write (or rw) to unlock the mutating tools. Anything else keeps the server read-only.
MICROK8S_MCP_KUBECONFIG kubectl default Path to the scoped kubeconfig. Leave unset to use whatever kubectl would use on its own.
MICROK8S_MCP_CONTEXT current kubeconfig context to select, if the file holds more than one.
MICROK8S_MCP_KUBECTL kubectl Path to the kubectl binary. Set this to an absolute path — see the warning below.

MICROK8S_MCP_KUBECTL is worth setting explicitly. If the server cannot find kubectl it falls back to microk8s kubectl on the node, which runs under the node's admin credential — the scoped kubeconfig and the RBAC role stop applying. A kubectl in ~/.local/bin is on your PATH but not necessarily on the PATH Claude Code hands the server, so relying on PATH is exactly how you end up escalated without noticing. make register bakes in the absolute path for you.

Node backend settings

These control how the server reaches the microk8s command itself, for addon management and snap-level status. Under topology B (server on the node) you can leave all of them unset.

VariableDefaultEffect
MICROK8S_MCP_SSH_HOST unset user@host for the node backend. Unset means the node backend runs locally.
MICROK8S_MCP_SSH_KEY agent/default Identity file for SSH, if you are not using an agent.
MICROK8S_MCP_SSH ssh The ssh binary to use.
MICROK8S_MCP_MICROK8S microk8s Path to the microk8s binary on the node. Set /snap/bin/microk8s if a non-interactive SSH shell cannot find it.

SSH always runs with BatchMode=yes and StrictHostKeyChecking=accept-new, so key-based auth is required — the server never prompts for a password.

Policy switches

These are what the server is willing to do. They are enforced by this process, not by the API server — read the two layers before relying on them.

VariableDefaultEffect
MICROK8S_MCP_NAMESPACES * Comma-separated namespace allowlist. Any tool call naming a namespace outside it is refused.
MICROK8S_MCP_PROTECTED_NAMESPACES kube-system,kube-public,kube-node-lease,default Readable, but writes are blocked unless the next switch is on.
MICROK8S_MCP_ALLOW_PROTECTED_WRITES false Permit writes to the protected namespaces above.
MICROK8S_MCP_ALLOW_ADDON_CHANGES false Permit manage_addon to enable/disable addons. This is snap-level root on the node — RBAC does not constrain it at all.
MICROK8S_MCP_ALLOW_NODE_OPS false Permit node_maintenance to cordon, uncordon or drain. On a single-node cluster a drain evicts everything.

Limits and logging

VariableDefaultEffect
MICROK8S_MCP_TIMEOUT 60 Per-command timeout in seconds. Addon and node operations raise this internally.
MICROK8S_MCP_MAX_OUTPUT 24000 Output longer than this is clipped in the middle, keeping both ends.
MICROK8S_MCP_LOG_LEVEL INFO Every command executed is logged to stderr. Capture it if you want an audit trail.
MICROK8S_MCP_TRANSPORT stdio MCP transport. Leave it alone unless you know you need something else.

make register switches

make register-rw takes four switches and prints the resulting grant before it acts:

VariableDefaultEffect
RW_SERVER_NAMEmicrok8s-rwPass microk8s to replace the read-only entry instead of running both.
ALLOW_ADDON_CHANGEStrueLets manage_addon run microk8s enable/disable over SSH.
ALLOW_NODE_OPSfalseEnables node_maintenance (cordon/uncordon/drain).
ALLOW_PROTECTED_WRITESfalsePermits writes to the protected namespaces.

Both register targets also accept:

VariableEffect
SERVER_NAMEName to register under (default microk8s).
KUBECONFIG_PATHPath to the scoped kubeconfig.
SSH_HOSTuser@host for the node backend; omit under topology B.
SSH_KEYIdentity file, if not using an agent.
NAMESPACESComma-separated namespace allowlist.
SCOPEPass SCOPE=user to register for every project.
KUBECTL_BINLocal kubectl to bake in; defaults to command -v kubectl.
VENVWhich virtualenv to register the entry point from.

Common setups

Read-only, everything visible

Where you should start. No policy switches needed — read-only is the default.

make register SSH_HOST=you@your-node

Write access, two namespaces, nothing else

Writes are limited to apps and staging; protected namespaces, node operations and addon changes all stay off.

make register-rw SSH_HOST=you@your-node NAMESPACES=apps,staging \
  ALLOW_ADDON_CHANGES=false

Full homelab control

Everything unlocked. Reasonable on a cluster you can rebuild in ten minutes; unreasonable anywhere else.

make register-rw SSH_HOST=you@your-node \
  ALLOW_NODE_OPS=true ALLOW_PROTECTED_WRITES=true

Two servers side by side

A read-only entry pointed at everything, plus a write-enabled entry scoped to what you actually deploy to. Ask the read-only one your questions and the other one for changes.

make register    SSH_HOST=you@your-node
make register-rw SSH_HOST=you@your-node NAMESPACES=apps