Releases: achetronic/kubernetes-mcp
v0.5.1
Hot-reload fix for kubeconfig contexts
When using contexts_dir with a sidecar that periodically regenerates kubeconfig files (e.g., GCP token refresh), the MCP server would fail to reload them:
failed to load new kubeconfig: context name collision: "my-context" already defined (from /shared/kubeconfigs/my-context.yaml)
This happened because sidecars typically write kubeconfigs using atomic writes (temp file + rename), which the file watcher sees as a Create event instead of a Write event. The Create handler rejected any context that already existed.
Now, if a kubeconfig is created for a context that already exists, the client is replaced instead of rejected. New contexts are still registered normally.
v0.5.0
⚠️ Breaking: RBAC authorization redesigned
The authorization config format has changed in a way its much more powerful now, BUT You need to update your config files.
What changed:
allow:/deny:blocks replaced by arules:list where each rule haseffect: alloworeffect: denykinds:(e.g.Pod,Secret) replaced byresources:with plural lowercase names (e.g.pods,secrets)- Virtual resources renamed:
APIDiscovery→apidiscovery,ClusterInfo→clusterinfo,Context→contexts - Glob patterns now work everywhere:
*,prefix*,*suffix,a*b*c
Before (v0.4.x):
authorization:
policies:
- name: "my-policy"
match:
expression: "true"
allow:
tools: ["get_*", "list_*"]
resources:
- groups: [""]
kinds: ["Pod", "Service"]
deny:
tools: ["get_*"]
resources:
- groups: [""]
kinds: ["Secret"]After (v0.5.0):
authorization:
policies:
- name: "my-policy"
match:
expression: "true"
rules:
- effect: allow
tools: ["get_*", "list_*"]
resources:
- groups: [""]
resources: ["pods", "services"]
- effect: deny
tools: ["get_*"]
resources:
- groups: [""]
resources: ["secrets"]What's new
• Rules with explicit effect — Put allow and deny rules together in the same policy. No more separate blocks.
• Resource names match the Kubernetes API — Use the same plural lowercase names you see in kubectl api-resources (pods, deployments , configmaps ).
• Full glob support — All fields support wildcards: get_* , -suffix , team--prod . Works in tools, contexts, groups resources, namespaces, and names.
• Deny always wins — If any deny rule matches, access is denied. No surprises from rule ordering.
• Default deny — If no allow rule matches, access is denied. Tools not listed in any allow rule are blocked automatically.
• Empty fields match everything — Skip tools , contexts , or resources in a rule to match all.
Tests
• 1,700+ unit tests covering glob matching, deny priority, multi-policy evaluation, virtual resources, and edge cases
• Integration tests that run against a real cluster — discover all API resources and verify every tool/resource combination. Set KUBE_CONTEXT=your-context to run them; they skip automatically otherwise
• Validated with 0 violations against a live cluster (185 resource types, 374 delete checks, 370 apply/patch denials)
Also updated
• Example configs in docs/ updated to new format
• README rewritten with new authorization reference and examples
v0.4.0
API Key Authentication
You can now use static API keys alongside JWT for authentication. Useful for CI/CD pipelines, service accounts, or setups without an identity provider.
middleware:
api_keys:
enabled: true
keys:
- name: "ci-cd-pipeline"
token: "$CI_API_KEY"
payload:
sub: "ci-cd-service"
groups: ["ci-cd"]API keys and JWTs produce the same payload, so your existing authorization policies just work — no changes needed.
When both are enabled, JWT is tried first. If the token isn't a valid JWT, it falls back to API key matching.
Security notes
- Tokens are hashed (SHA-256) at startup and compared in constant time to prevent timing attacks
- Use environment variables for tokens (
$CI_API_KEY) instead of hardcoding them
Simpler JWT config
The JWT config is now flat — no more strategy, forwarded_header, or local: nesting:
# Before
middleware:
jwt:
validation:
strategy: "local"
forwarded_header: "X-Validated-Jwt"
local:
jwks_uri: "https://..."
cache_interval: "10s"
# After
middleware:
jwt:
validation:
jwks_uri: "https://..."
cache_interval: "10s"Breaking changes
| Removed | Why |
|---|---|
middleware.jwt.validation.strategy |
JWT is now always validated locally against JWKS |
middleware.jwt.validation.forwarded_header |
Auth payload is now handled internally |
middleware.jwt.validation.local nesting |
Fields moved up to middleware.jwt.validation |
authorization.identity_claim |
Was never used. Removed |
v0.3.2
Tool name prefixing
MCP tools are now automatically prefixed with a sanitized version of server.name from the config. This prevents tool name collisions when multiple MCP servers are connected to the same client.
For example, with server.name: "some-mcp", a tool registered as something is exposed to the client as some_mcp_something.
How it works
server.nameis lowercased, non-alphanumeric characters are replaced with_, and a trailing_is appended.- If
server.nameis not set, each project falls back to its own default (e.g.some-mcp.).
v0.3.1
Bug Fixes
• Watch new kubeconfig files in contexts_dir : Kubeconfig files added to the contexts_dir after the server starts
are now automatically detected and loaded (#1)
• Debounce for new file detection: Added 500ms debounce when detecting new files to avoid reading incomplete files (e.
g., when an editor creates the file before writing content)
• Watch dynamically loaded kubeconfigs: Newly loaded kubeconfig files are now added to the file watcher, so subsequent
changes are detected and trigger client reload
• Improved error handling: Properly handle and log filepath.Abs errors instead of silently ignoring them
Contributors:
v0.3.0
Features
• Contexts as list: kubernetes.contexts configuration is now a list with explicit name field instead of a map
contexts:
- name: "production"
kubeconfig: "/path/to/kubeconfig"
kubeconfig_context: "gke_myproject_prod" # optional
description: "Production cluster"• Auto-load from directory: New contexts_dir field to automatically load kubeconfigs from a directory. Context name
is taken from each file's current-context
contexts_dir: "/shared/kubeconfigs/"
• Kubeconfig hot-reload: Kubeconfig files are automatically watched. When a sidecar or external process updates them,
the client reloads without server restart
• Collision detection: Duplicate context names (between explicit, auto-loaded, or both) cause server startup to fail
with a clear error message
Breaking Changes
kubernetes.contexts format changes from map to list. Migration:
# Before
contexts:
production:
kubeconfig: "/path/to/kubeconfig"
# After
contexts:
- name: "production"
kubeconfig: "/path/to/kubeconfig"
Contributors:
v0.2.0
Features
• Resource-level RBAC: filter by API group, kind, namespace, and name
• Virtual resources: non-K8s tools mapped to group _ (APIDiscovery, ClusterInfo, Context)
• Wildcard patterns: prefix-*, *-suffix for namespaces and names
Example
deny:
resources:
- groups: [""]
kinds: ["Secret"]
- groups: ["rbac.authorization.k8s.io"]
kinds: ["*"]Docs
• New logo and header
• Resource authorization examples in README
Upgrade
Backwards compatible. Existing configs work without changes.
Contributors
v0.1.0
💥💥💣💣💣 Initial release 💣💣💣💥💥 Yes, some places need emojis to bother others
Features
• 25 Kubernetes tools: read, modify, scale, rollout, logs, exec, metrics, diff, context management
• yq filtering: filter responses at source to save context window
• CEL-based RBAC: fine-grained access control per tool and context
• Multi-cluster support: named contexts with independent configurations
• OAuth 2.1: RFC 8414 / RFC 9728 compliant for safe public exposure
• JWT validation: local (JWKS) or external (Istio/Envoy)
Deployment
• Binaries: Linux (amd64, arm64, 386), macOS (amd64, arm64)
• Docker: ghcr.io/achetronic/kubernetes-mcp:v0.1.0
• Helm: via bjw-s/app-template