microk8s-mcp View on GitHub

Installation

About fifteen minutes, most of it waiting for pip. The short version is three commands; the rest of this page explains what each one does and how to vary it.

make install
make node-setup SSH_HOST=you@your-node
make register   SSH_HOST=you@your-node

1. Decide where the server runs

Pick this first, because it decides which machine you run the later steps on.

Topology A — server on your workstation (recommended)

workstation                                  microk8s node
claude CLI ── stdio ── mcp server ── :16443 ── kube-apiserver
                                  └─ ssh ───── microk8s snap

Everything installs on your workstation. The server holds a scoped kubeconfig and reaches the API server over the network. SSH is only needed for microk8s_status and manage_addon — skip it and everything else still works. Nothing is installed on the node.

Topology B — server on the node

workstation                                  microk8s node
claude CLI ── ssh ──────────────────────────── mcp server ── localhost

Install on the node itself. No SSH configuration needed; the node backend runs locally.

The rest of this page assumes topology A and calls out where B differs.

2. Prerequisites

On the machine that will run the server:

On the MicroK8s node: a running cluster, which microk8s status --wait-ready will confirm.

Install kubectl locally. Without it the server falls back to microk8s kubectl on the node, which runs under MicroK8s' own admin credential — the scoped kubeconfig and the bundled reader role stop applying, and Secrets become readable again. The server logs a warning when this happens, but it is easy to miss. More on this.

Match your cluster's minor version. No root required:

V=v1.26.15   # match `kubectl version` on the node
curl -fsSLO "https://dl.k8s.io/release/$V/bin/linux/amd64/kubectl"
curl -fsSLO "https://dl.k8s.io/release/$V/bin/linux/amd64/kubectl.sha256"
echo "$(cat kubectl.sha256)  kubectl" | sha256sum --check
install -m 755 kubectl ~/.local/bin/kubectl

Check what you have — this installs nothing:

make doctor

It reports your Python version, whether the venv exists, and whether kubectl, claude, ssh and the kubeconfig are present. Add SSH_HOST= and it also probes the node for reachability, whether microk8s is on PATH in a non-interactive shell there, and which API server address will be used.

3. Install the server

Two ways in. Clone the repository if you want the setup tooling with it — that is the path the rest of this guide follows. Install from PyPI if you only want the server binary.

From the repository (recommended)

git clone https://github.com/pierrejochem/microk8s-mcp
cd microk8s-mcp
make install
make check

make check should print an import ok line and the absolute path to the entry point. Note that path — the registration needs it, and it must be absolute.

From PyPI

The package is published as microk8s-mcp. Install it into a virtualenv of its own — not system-wide, and not into a project venv you might delete:

python3 -m venv ~/.local/share/microk8s-mcp/venv
~/.local/share/microk8s-mcp/venv/bin/pip install microk8s-mcp

Check it starts. The server speaks MCP over stdin, so closing stdin makes it log its effective policy and exit — which is exactly the confirmation you want:

~/.local/share/microk8s-mcp/venv/bin/microk8s-mcp < /dev/null

starting microk8s-mcp: mode=read-only kubeconfig=(default) node_backend=local namespaces=*

The entry point is then ~/.local/share/microk8s-mcp/venv/bin/microk8s-mcp — that absolute path is what you register in step 5.

The wheel is the server, not the setup. rbac.yaml, make-kubeconfig.sh and the make targets are operator tooling and deliberately stay in the repository. Installing from PyPI skips step 4 entirely, so you still need those files — clone the repo anyway, or apply the RBAC and mint the kubeconfig by hand on the node. You will also register with claude mcp add directly rather than make register, since that target lives in the Makefile.

Given that, PyPI is the better choice when the cluster identity already exists — a second workstation, a rebuild, or an upgrade — and the repository is the better choice for a first install. Upgrading a PyPI install is the ordinary thing:

~/.local/share/microk8s-mcp/venv/bin/pip install --upgrade microk8s-mcp

Editable versus copy installs

The default is an editable install into ./.venv: the venv only links back to this checkout, so your edits are live and the source has to stay put. That is ideal while you are iterating, and a trap if you later move or delete the repository — the registered server breaks, and if you registered at user scope it breaks in every project at once.

For an install that outlives the checkout, put the venv somewhere stable and copy the package in:

make install VENV=~/.local/share/microk8s-mcp/venv EDITABLE=0

EDITABLE=0 copies rather than links, so the result is self-contained. The tradeoff is that source edits then need a reinstall. The target force-reinstalls on every run, deliberately: pip treats an already-installed same-version package as satisfied and would otherwise leave stale code in place while reporting success.

Pass the same VENV= to every target that needs it — check, register and register-rw.

4. Give it a scoped identity

Do not hand the server your admin kubeconfig. Mint a credential bound to a purpose-built ServiceAccount instead. Under topology A the node-* targets do all of this over SSH from your workstation:

make node-setup SSH_HOST=you@your-node

That is the whole step. It runs, in order:

StageWhat it does
check-apiserverConfirms the API server address resolves and answers from here
node-checkSSH reachability, microk8s on PATH, kubectl runnable
node-rbacStreams rbac.yaml to microk8s kubectl apply -f -
node-kubeconfigMints the kubeconfig on the node, writes it here at mode 600

It creates the mcp-system namespace, a claude-mcp ServiceAccount, a long-lived token Secret, and a reader ClusterRole bound to it. The reader role grants get/list/watch cluster-wide except Secrets — deliberately, so cluster credentials can never land in a model context.

About the API server address

APISERVER defaults to https://<node>:16443, where the node is SSH_HOST put through ssh -G. That resolution matters: SSH_HOST is very often an alias from ~/.ssh/config, and kubectl does not read that file. Given

Host k8s-node
    HostName 10.0.0.5

make node-setup SSH_HOST=k8s-node bakes https://10.0.0.5:16443 into the kubeconfig rather than the unusable https://k8s-node:16443. Override it when the node answers on a different address than you reach it at:

make node-setup SSH_HOST=you@10.0.0.5 APISERVER=https://k8s.example:16443

Either way the address is validated before anything is minted. Unresolvable is a hard stop; resolvable but unanswered is a warning, since the node may just be behind a VPN that is currently down. The kubeconfig is written to a temp file and checked before replacing the destination, so a dropped connection can never leave a truncated credential in place.

If you are already on the node (topology B)

make rbac
make kubeconfig APISERVER=https://k8s.example:16443

APISERVER is required here — there is no SSH_HOST to infer it from.

Applying rbac.yaml unchanged grants cluster-wide write access. The claude-mcp-operator ClusterRoleBinding is active in the repository as shipped. If you want read-only, comment it out before applying. The security model page covers all three ways to shape that grant.

5. Register with the Claude CLI

Read-only, which is where you should start:

make register SSH_HOST=you@your-node

That fills in absolute paths — including MICROK8S_MCP_KUBECTL, which matters because Claude Code launches the server with its own PATH. It expands to roughly:

claude mcp add --transport stdio microk8s \
  --env MICROK8S_MCP_KUBECONFIG=$HOME/.kube/claude-mcp.kubeconfig \
  --env MICROK8S_MCP_SSH_HOST=you@your-node \
  -- /abs/path/to/microk8s-mcp/.venv/bin/microk8s-mcp

For full management, scoped to a couple of namespaces:

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

That registers under the name microk8s-rw, sets MICROK8S_MCP_MODE=read-write, and prints the resulting grant before it acts. Four switches control the rest — see the configuration reference for all of them.

Under topology B, omit SSH_HOST entirely; the node backend runs locally. Use SCOPE=user to make the server available in every project rather than just the current directory.

Running both side by side works well: a read-only microk8s entry pointed at everything, and a microk8s-rw entry scoped to the namespaces you actually deploy to. Pass RW_SERVER_NAME=microk8s if you would rather have one entry — two registrations mean every tool appears twice in a session.

6. Verify

make list          # or: claude mcp list

Then restart Claude Code and run /mcp to see the tool inventory. Two things make a healthy registration look like a missing one:

Upgrading

With the default editable install, a pull is usually enough:

git pull
make install        # only needed if dependencies changed
make check

With a copy install, the pull changes nothing until you reinstall, because the venv holds its own copy:

git pull
make install VENV=~/.local/share/microk8s-mcp/venv EDITABLE=0
make check   VENV=~/.local/share/microk8s-mcp/venv

Forgetting that reinstall is the failure mode: everything reports success and the old code keeps running. If behaviour does not match the source, ask the venv where it imports from — from outside the checkout, since python -c prepends the working directory to sys.path:

cd /tmp && ~/.local/share/microk8s-mcp/venv/bin/python -c \
  "import microk8s_mcp, inspect; print(inspect.getfile(microk8s_mcp))"

Uninstalling

make unregister SERVER_NAME=microk8s
make distclean      # removes .venv and all build artefacts

To remove the cluster-side identity too:

make node-teardown SSH_HOST=you@your-node
rm -f ~/.kube/claude-mcp.kubeconfig

Delete the local kubeconfig as well — it holds a live token until the Secret is gone.

Something not working? The troubleshooting page covers the errors people actually hit.