Configuration Reference
July 28, 2026 · View on GitHub
This document provides comprehensive reference documentation for configuring the Kubernetes MCP Server via TOML configuration files.
The server supports two configuration methods:
- Command-line arguments - For quick configuration and overrides
- TOML configuration files - For complex, persistent, and shareable configurations
This reference focuses on TOML file configuration. For CLI arguments, see the Configuration Options section or run kubernetes-mcp-server --help.
Table of Contents
- Table of Contents
- Configuration Loading
- Drop-in Configuration
- Dynamic Configuration Reload
- Configuration Reference
- CLI Configuration Options
- Complete Example
- Related Documentation
Configuration Loading
Configuration values are loaded and merged in the following order (later sources override earlier ones):
- Internal Defaults - Built-in default values
- Main Configuration File - Loaded via
--configflag or$K8S_MCP_CONFIG_PATH(the flag takes precedence) - Drop-in Files - Loaded from
--config-dirin lexical (alphabetical) order
Usage
# Use a main configuration file
kubernetes-mcp-server --config /etc/kubernetes-mcp-server/config.toml
# or
K8S_MCP_CONFIG_PATH=/etc/kubernetes-mcp-server/config.toml kubernetes-mcp-server
# Use only drop-in configuration files (no main config)
kubernetes-mcp-server --config-dir /etc/kubernetes-mcp-server/conf.d/
# Use both main config and explicit drop-in directory
kubernetes-mcp-server --config /etc/kubernetes-mcp-server/config.toml \
--config-dir /etc/kubernetes-mcp-server/config.d/
Drop-in Configuration
Drop-in files allow you to split configuration into multiple files and override specific settings without modifying the main configuration file.
How Drop-in Files Work
- Default Directory: If
--config-diris not specified, the server looks for drop-in files inconf.d/relative to the main config file's directory (when--configis provided) - File Naming: Use numeric prefixes to control loading order (e.g.,
00-base.toml,10-cluster.toml,99-override.toml) - File Extension: Only
.tomlfiles are processed; dotfiles (starting with.) are ignored - Partial Configuration: Drop-in files can contain only a subset of configuration options
- Merge Behavior: Values present in a drop-in file override previous values; missing values are preserved
Example Directory Structure
/etc/kubernetes-mcp-server/
├── config.toml # Main configuration
└── conf.d/ # Default drop-in directory
├── 00-base.toml # Base overrides
├── 10-toolsets.toml # Toolset-specific config
└── 99-local.toml # Local overrides (highest priority)
Example Drop-in Files
10-toolsets.toml - Override only the toolsets:
toolsets = ["core", "config", "helm", "kubevirt"]
99-local.toml - Local development overrides:
log_level = 9
read_only = true
Dynamic Configuration Reload
Configuration can be reloaded at runtime by sending a SIGHUP signal to the running server process.
Prerequisite: SIGHUP reload requires the server to be started with either the --config flag or --config-dir flag (or both). If neither is specified, SIGHUP signals are ignored.
How to Reload
# Find the process ID
ps aux | grep kubernetes-mcp-server
# Send SIGHUP to reload configuration
kill -HUP <pid>
# Or use pkill
pkill -HUP kubernetes-mcp-server
What Gets Reloaded
The server will:
- Reload the main config file and all drop-in files
- Update configuration values (log level, output format, etc.)
- Rebuild the toolset registry with new tool configurations
- Log the reload status
Limitations
- Requires restart:
kubeconfigor cluster-related settings - Not available on Windows: Restart the server to reload configuration
Configuration Reference
Server Settings
| Field | Type | Default | Description |
|---|---|---|---|
log_level | integer | 0 | Logging verbosity level (0-9). Higher values produce more verbose output. Similar to kubectl logging levels. |
log_file | string | "" | Path to a server log file. Required for logging in stdio mode (where stdout is reserved for the MCP protocol); replaces stdout logging in HTTP mode. The file is created if it does not exist and opened in append mode (O_APPEND, 0o600). Use the special value stderr to route logs to stderr without opening a file. |
port | string | "" | When set, starts the MCP server in HTTP mode (Streamable HTTP at /mcp, SSE at /sse) on the specified port. |
bind_address | string | "0.0.0.0" | Address to bind the HTTP server to. Set to 127.0.0.1 to restrict to localhost. A warning is logged when listening on all interfaces (0.0.0.0 or ::) without TLS or OAuth. |
sse_base_url | string | "" | Base URL for Server-Sent Events (SSE) connections. Used when the server is behind a reverse proxy. |
list_output | string | "table" | Output format for resource list operations. Valid values: yaml, table. |
stateless | boolean | false | When true, disables tool and prompt change notifications. Useful for container deployments, load balancing, and serverless environments. |
tls_cert | string | "" | Path to TLS certificate file for HTTPS. When set along with tls_key, the server serves HTTPS instead of HTTP. |
tls_key | string | "" | Path to TLS private key file for HTTPS. Must be set together with tls_cert. |
require_tls | boolean | false | When true, enforces TLS for all connections. Server refuses to start without TLS certificates, and outbound connections to non-HTTPS endpoints (e.g., Kiali) are rejected. |
tls_min_version | string | "" | Minimum TLS version (e.g., "1.2", "1.3"; "1.0" and "1.1" are accepted for operator parity but not recommended). Defaults to TLS 1.2 if not set. Can be overridden by TLS_MIN_VERSION. Applies to inbound HTTPS and outbound clients (Kiali, NetObserv, OAuth, token exchange, well-known metadata). |
tls_cipher_suites | array | [] | TLS 1.2 cipher suites (TLS 1.3 cipher suites are not configurable). If empty, Go's defaults are used. Can be overridden by TLS_CIPHER_SUITES (comma-separated). Applies to inbound HTTPS and outbound clients. |
Example:
log_level = 2
log_file = "/var/log/kubernetes-mcp-server.log"
port = "8080"
list_output = "yaml"
stateless = true
# Enable TLS for HTTPS
tls_cert = "/etc/tls/tls.crt"
tls_key = "/etc/tls/tls.key"
# Enforce TLS for all connections (requires tls_cert and tls_key)
require_tls = true
# Global TLS version and cipher suites (inbound + outbound; env vars override)
tls_min_version = "1.2"
tls_cipher_suites = [
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"
]
TLS Environment Variables:
TLS_MIN_VERSION and TLS_CIPHER_SUITES configure TLS for both inbound and outbound connections. When set, they override the corresponding global TOML values (tls_min_version, tls_cipher_suites):
| Setting | Inbound (HTTP server) | Outbound (Kiali, NetObserv, OAuth, token exchange, well-known metadata) |
|---|---|---|
tls_min_version / tls_cipher_suites (TOML) | ✅ fallback | ✅ fallback |
TLS_MIN_VERSION / TLS_CIPHER_SUITES (env) | ✅ overrides TOML (at startup) | ✅ overrides TOML |
When neither TOML nor env is set, both inbound and outbound default to TLS 1.2 with Go's default cipher suites.
Note: Inbound HTTPS (
tls_min_version,tls_cipher_suites, and their env overrides) is applied when the server starts. Changing these settings requires a process restart; they are not updated on SIGHUP config reload. Outbound clients (OAuth, token exchange, well-known metadata) pick up changes on reload; Kiali and NetObserv re-read TLS settings on each tool invocation.
# Example: Enforce TLS 1.3 minimum version (inbound + outbound)
export TLS_MIN_VERSION="1.3"
# Example: Restrict TLS 1.2 cipher suites (inbound + outbound; TLS 1.3 ciphers are not configurable)
export TLS_MIN_VERSION="1.2"
export TLS_CIPHER_SUITES="TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"
Note: TLS 1.3 uses a fixed set of cipher suites that cannot be configured. The
TLS_CIPHER_SUITESsetting only affects TLS 1.2 and earlier connections.
Note: When the minimum TLS version is below
"1.3"and you set a custom cipher list, include at least one HTTP/2-compatible suite (for example,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256). Omitting it can break HTTPS/HTTP2 clients even when TLS 1.2 handshakes succeed.
Note:
TLS_MIN_VERSIONvalues"1.0"and"1.1"are accepted for operator parity with cluster-wide TLS settings but are not recommended for production use.
HTTP Server Security
Configure HTTP server settings to protect against denial-of-service attacks.
| Field | Type | Default | Description |
|---|---|---|---|
http.read_header_timeout | duration | "10s" | Maximum duration for reading request headers. Primary defense against Slowloris attacks. |
http.max_body_bytes | integer | 16777216 | Maximum size of request body in bytes (default: 16 MB). |
http.rate_limit_rps | float | 0 | Maximum requests per second per session. When 0 (default), rate limiting is disabled. |
http.rate_limit_burst | integer | 10 | Maximum burst size for rate limiting. Allows short bursts above the rate limit. Only effective when rate_limit_rps > 0. |
Duration values use Go duration syntax: "30s", "5m", "1h30m".
Security Considerations:
read_header_timeoutis the primary defense against Slowloris attacks, which send headers extremely slowly to exhaust server connectionsmax_body_bytesprevents memory exhaustion from unbounded request payloads. The 16 MB default accommodates large Kubernetes manifests (CRDs, ConfigMaps)rate_limit_rpsprevents any single session from overwhelming the server with requests. Rate limiting is per-session, so one client hitting the limit does not affect other sessions. Requests with no session ID (e.g., STDIO transport) bypass rate limiting.
Example:
[http]
read_header_timeout = "10s"
max_body_bytes = 16777216 # 16 MB
rate_limit_rps = 5 # 5 requests per second per session
rate_limit_burst = 10 # allow bursts of up to 10 requests
Kubernetes Connection
| Field | Type | Default | Description |
|---|---|---|---|
kubeconfig | string | "" | Path to the Kubernetes configuration file. If not provided, the server uses the in-cluster configuration or the default kubeconfig location (~/.kube/config). |
cluster_provider_strategy | string | auto-detect | How the server finds clusters. Valid values: kubeconfig, in-cluster, kcp, disabled. |
Example:
kubeconfig = "/home/user/.kube/config"
cluster_provider_strategy = "kubeconfig"
Cross-Cluster Access from a Pod
When the MCP server runs inside a Kubernetes pod, it automatically detects the in-cluster environment and uses the in-cluster provider strategy to connect to the local cluster's API server.
If you need the server to connect to a different cluster instead, you must explicitly provide both kubeconfig and cluster_provider_strategy. This overrides the automatic in-cluster detection.
Required configuration:
kubeconfig = "/etc/kubernetes-mcp-server/external-kubeconfig"
cluster_provider_strategy = "kubeconfig"
Or via CLI flags:
kubernetes-mcp-server --kubeconfig /etc/kubernetes-mcp-server/external-kubeconfig --cluster-provider kubeconfig
Important: Both settings are required. Setting
--cluster-provider kubeconfigalone (without--kubeconfig) will fail because the server still detects the in-cluster environment. The explicit--kubeconfigpath overrides this detection.
Mounting the kubeconfig in a pod:
To make an external kubeconfig available inside a pod, mount it from a Secret or ConfigMap:
apiVersion: v1
kind: Secret
metadata:
name: external-kubeconfig
namespace: mcp
type: Opaque
data:
kubeconfig: <base64-encoded-kubeconfig>
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: kubernetes-mcp-server
namespace: mcp
spec:
template:
spec:
containers:
- name: kubernetes-mcp-server
args:
- --kubeconfig
- /etc/kubernetes-mcp-server/kubeconfig
- --cluster-provider
- kubeconfig
volumeMounts:
- name: external-kubeconfig
mountPath: /etc/kubernetes-mcp-server
readOnly: true
volumes:
- name: external-kubeconfig
secret:
secretName: external-kubeconfig
Troubleshooting cross-cluster access:
If the server starts but operations fail (e.g., failed to list namespaces: unknown), verify:
- Network connectivity — The pod must be able to reach the external cluster's API server. Check network policies, firewalls, and DNS resolution.
- Kubeconfig validity — Ensure the kubeconfig contains valid credentials (token, client certificate, etc.) and points to the correct API server address.
- Permissions — The credentials in the kubeconfig must have sufficient RBAC permissions on the target cluster.
- TLS certificates — If the external cluster uses a private CA, the CA certificate must be included in the kubeconfig or mounted separately.
Access Control
Control what operations the MCP server can perform on your Kubernetes cluster. These options help enforce the principle of least privilege, ensuring AI assistants only have the permissions they need for their intended tasks.
| Field | Type | Default | Description |
|---|---|---|---|
read_only | boolean | false | When true, only exposes tools annotated with readOnlyHint=true. Prevents any write operations on the cluster. |
disable_destructive | boolean | false | When true, disables tools annotated with destructiveHint=true (delete, update operations). Has no effect when read_only is true. |
experimental_enable_target_compatibility_tool_filters | boolean | false | Controls cluster-capability tool filtering. Tools that require API groups absent from the cluster (for example the OpenShift-only projects_list) are hidden. NOTE: This feature is experimental, and this option is subject to change or removal in a future release. |
Example:
# Production-safe configuration
read_only = true
# Or allow writes but prevent deletions
disable_destructive = true
# Probe every target for API-group compatibility
experimental_enable_target_compatibility_tool_filters = true
Toolsets
Toolsets group related tools together. Enable only the toolsets you need to reduce context size and improve LLM tool selection accuracy.
| Field | Type | Default | Description |
|---|---|---|---|
toolsets | string[] | ["core", "config", "helm"] | List of toolsets to enable. |
Available Toolsets:
| Toolset | Description | Default |
|---|---|---|
| config | View and manage the current local Kubernetes configuration (kubeconfig) | ✓ |
| core | Most common tools for Kubernetes management (Pods, Generic Resources, Events, etc.) | ✓ |
| helm | Tools for managing Helm charts and releases | |
| kcp | Manage kcp workspaces and multi-tenancy features | |
| kiali | Most common tools for managing Kiali, check the Kiali documentation for more details. | |
| kubevirt | KubeVirt virtual machine management tools, check the KubeVirt documentation for more details. | |
| netobserv | Network observability tools backed by the NetObserv console plugin API (flows, metrics, export). Check the NetObserv documentation for more details. | |
| tekton | Tekton pipeline management tools for Pipelines, PipelineRuns, Tasks, TaskRuns, and troubleshooting. |
Example:
# Enable specific toolsets
toolsets = ["core", "config", "helm", "kubevirt"]
Available Resources:
Available Resource Templates:
Tool Filtering
Fine-grained control over individual tools within enabled toolsets.
| Field | Type | Default | Description |
|---|---|---|---|
enabled_tools | string[] | [] | Allowlist of specific tools to enable. When set, only these tools are available. |
disabled_tools | string[] | [] | Denylist of specific tools to disable. Applied after enabled_tools. |
Example:
# Only enable specific tools
enabled_tools = ["pods_list", "pods_get", "pods_log"]
# Or disable specific tools from enabled toolsets
disabled_tools = ["resources_delete", "pods_delete"]
Tool Overrides
Customize tool descriptions shown to MCP clients without modifying source code. This enables adding domain-specific guidance to tool descriptions (e.g., "Prefer using label selectors over listing all pods").
| Field | Type | Default | Description |
|---|---|---|---|
tool_overrides | map | {} | Map of tool name to override configuration. |
Override Fields:
description(optional): Custom description for the tool. Empty strings are ignored.
Tools are keyed by their flat name (e.g., pods_list, resources_get), consistent with enabled_tools and disabled_tools.
Example:
[tool_overrides.pods_list]
description = "List pods in the cluster. Prefer using label selectors over listing all pods when the namespace has many workloads."
[tool_overrides.resources_get]
description = "Get a Kubernetes resource by name. Always specify the namespace explicitly rather than relying on the default."
Denied Resources
Prevent access to specific Kubernetes resource types.
| Field | Type | Default | Description |
|---|---|---|---|
denied_resources | array | [] | List of GroupVersionKind objects that should not be accessible. |
Example:
# Deny access to Secrets and ConfigMaps
[[denied_resources]]
group = ""
version = "v1"
kind = "Secret"
[[denied_resources]]
group = ""
version = "v1"
kind = "ConfigMap"
# Deny access to RBAC resources for additional security
[[denied_resources]]
group = "rbac.authorization.k8s.io"
version = "v1"
kind = "Role"
[[denied_resources]]
group = "rbac.authorization.k8s.io"
version = "v1"
kind = "RoleBinding"
[[denied_resources]]
group = "rbac.authorization.k8s.io"
version = "v1"
kind = "ClusterRole"
[[denied_resources]]
group = "rbac.authorization.k8s.io"
version = "v1"
kind = "ClusterRoleBinding"
Server Instructions
Provide hints to MCP clients (like Claude Code) about when to use this server's tools. Useful for clients that support MCP Tool Search.
| Field | Type | Default | Description |
|---|---|---|---|
server_instructions | string | "" | Instructions for MCP clients on when to use this server. |
Example:
server_instructions = """
Use this server for Kubernetes and OpenShift cluster management tasks including:
- Pods: list, get details, logs, exec commands, delete
- Resources: get, list, create, update, delete any Kubernetes resource
- Namespaces and projects: list, create, switch context
- Nodes: list, view logs, get resource usage statistics
- Events: view cluster events for debugging
- Helm: install, upgrade, uninstall charts and releases
- KubeVirt: create and manage virtual machines
- Cluster config: view and switch kubeconfig contexts
"""
Prompts
Define custom MCP prompts for workflow templates. See prompts.md for detailed documentation.
| Field | Type | Description |
|---|---|---|
prompts | array | List of prompt definitions. |
Prompt Fields:
name(required): Unique identifiertitle(optional): Human-readable display namedescription(required): Brief explanationarguments(optional): List of parametersmessages(required): Conversation template
Example:
[[prompts]]
name = "check-pod-logs"
title = "Check Pod Logs"
description = "Quick way to check pod logs"
[[prompts.arguments]]
name = "pod_name"
description = "Name of the pod"
required = true
[[prompts.arguments]]
name = "namespace"
description = "Namespace of the pod"
required = false
[[prompts.messages]]
role = "user"
content = "Show me the logs for pod {{pod_name}} in {{namespace}}"
[[prompts.messages]]
role = "assistant"
content = "I'll retrieve and analyze the logs for you."
OAuth and Authorization
Configure OAuth/OIDC authentication for HTTP mode deployments.
| Field | Type | Default | Description |
|---|---|---|---|
require_oauth | boolean | false | When true, requires OAuth authentication for all requests. This DOES NOT determine validation strategy, which is done separately by authorization_url and skip_jwt_verification |
oauth_audience | string | "" | Valid audience for OAuth tokens (for offline JWT claim validation). |
authorization_url | string | "" | URL of the OIDC authorization server for token validation and STS exchange. |
skip_jwt_verification | boolean | false | When true and authorization_url is unset, the server forwards the bearer token without any local validation (no parse, no claims check, no audience check). Required to enable pure passthrough with non-JWT tokens (e.g., OpenShift OAuth sha256~…). When true and authorization_url is set, this flag has no effect — the configured OIDC provider validates tokens normally. Only use the no-authorization_url form when a downstream component (cluster, reverse proxy) is the authority. |
disable_dynamic_client_registration | boolean | false | When true, disables dynamic client registration in .well-known endpoints. |
oauth_scopes | string[] | [] | Supported client scopes for the OAuth flow. |
sts_client_id | string | "" | OAuth client ID for backend token exchange. |
sts_client_secret | string | "" | OAuth client secret for backend token exchange. |
sts_audience | string | "" | Audience for STS token exchange. |
sts_scopes | string[] | [] | Scopes for STS token exchange. |
token_exchange_strategy | string | "" | Token exchange strategy: rfc8693, keycloak-v1, or entra-obo. |
sts_auth_style | string | "params" | How client credentials are sent: params (body), header (Basic Auth), assertion (JWT), or federated (external IdP token file). |
sts_client_cert_file | string | "" | Path to client certificate PEM file (for assertion auth style). |
sts_client_key_file | string | "" | Path to client private key PEM file (for assertion auth style). |
sts_federated_token_file | string | "" | Path to a JWT file from an external identity provider, e.g., SPIRE JWT-SVID (for federated auth style). |
cluster_auth_mode | string | "" | Cluster auth mode: passthrough (forward Authorization header when present, fall back to kubeconfig when absent) or kubeconfig (always use kubeconfig credentials). Defaults to passthrough. |
certificate_authority | string | "" | Path to CA certificate for validating authorization server connections. |
server_url | string | "" | Public URL of the MCP server (used for OAuth metadata). |
Example (with client secret):
require_oauth = true
authorization_url = "https://keycloak.example.com/realms/mcp"
oauth_audience = "kubernetes-mcp-server"
oauth_scopes = ["openid", "profile"]
sts_client_id = "mcp-backend"
sts_client_secret = "your-client-secret"
sts_audience = "kubernetes-api"
Example (with certificate-based auth for Entra ID):
require_oauth = true
authorization_url = "https://login.microsoftonline.com/<TENANT_ID>/v2.0"
oauth_audience = "<CLIENT_ID>"
token_exchange_strategy = "entra-obo"
sts_client_id = "<CLIENT_ID>"
sts_auth_style = "assertion"
sts_client_cert_file = "/path/to/client.crt"
sts_client_key_file = "/path/to/client.key"
sts_scopes = ["api://<DOWNSTREAM_API>/.default"]
Pure token passthrough (delegate validation to the cluster):
require_oauth = true
skip_jwt_verification = true
cluster_auth_mode = "passthrough"
# authorization_url is not set
- The MCP server performs no token validation in this mode; it only enforces that a bearer header is present and forwards it to the cluster
- Security note: Use this ONLY when the cluster (or a trusted upstream component such as a reverse proxy or OIDC sidecar) is configured to validate tokens. Without that, the MCP server is effectively unauthenticated
oauth_audience,authorization_url, and other JWT-related options are ignored in this mode
For a complete OIDC setup guide, see KEYCLOAK_OIDC_SETUP.md or ENTRA_ID_SETUP.md.
Telemetry
Configure OpenTelemetry distributed tracing and metrics. See OTEL.md for detailed documentation.
| Field | Type | Default | Description |
|---|---|---|---|
telemetry.enabled | boolean | auto | Explicitly enable/disable telemetry. Auto-enabled when endpoint is set. |
telemetry.endpoint | string | "" | OTLP endpoint URL (e.g., http://localhost:4317). Can be overridden by OTEL_EXPORTER_OTLP_ENDPOINT. |
telemetry.protocol | string | "grpc" | OTLP protocol: grpc or http/protobuf. Can be overridden by OTEL_EXPORTER_OTLP_PROTOCOL. |
telemetry.traces_sampler | string | "" | Trace sampling strategy. Can be overridden by OTEL_TRACES_SAMPLER. |
telemetry.traces_sampler_arg | float | - | Sampling ratio (0.0-1.0) for ratio-based samplers. Can be overridden by OTEL_TRACES_SAMPLER_ARG. |
Available Samplers:
always_on- Sample all tracesalways_off- Disable tracingtraceidratio- Sample a percentage of tracesparentbased_always_on- Respect parent span, default to always_onparentbased_always_off- Respect parent span, default to always_offparentbased_traceidratio- Respect parent span, default to ratio
Example:
[telemetry]
endpoint = "http://localhost:4317"
traces_sampler = "traceidratio"
traces_sampler_arg = 0.1 # 10% sampling
Validation
Pre-execution validation catches errors before they reach the Kubernetes API, providing clearer error messages for issues like typos in resource names, invalid fields, and missing permissions.
| Field | Type | Default | Description |
|---|---|---|---|
validation_enabled | boolean | false | When true, enables schema validation and RBAC pre-checks for all API requests. Resource existence is always checked regardless of this setting. |
When enabled, the validation layer runs at the HTTP RoundTripper level, intercepting all Kubernetes API calls (including those from plugins like Helm, KubeVirt, and Kiali). It performs:
- Schema validation — Validates resource manifests against the cluster's OpenAPI schema for create/update operations
- RBAC pre-checks — Verifies permissions using
SelfSubjectAccessReviewbefore attempting operations
Resource existence validation (catching typos like "Deploymnt" instead of "Deployment") runs as part of access control regardless of this setting.
For detailed information about the validation flow, error codes, and behavior, see the validation specification.
Example:
validation_enabled = true
Confirmation Rules
Prompt users for confirmation before dangerous actions. Rules operate at two levels:
- Tool-level — matches on tool name or
DestructiveHintannotation. Fires once before the tool handler runs. - Kube-level — matches on Kubernetes API verb, kind, group, version, name, or namespace. Fires per API call during handler execution.
When a client doesn't support elicitation, the confirmation_fallback determines behavior: "allow" proceeds silently (with a warning log), "deny" blocks the action. The default is "allow".
If multiple rules match at the same level, their messages are merged into a single prompt.
| Field | Type | Level | Description |
|---|---|---|---|
confirmation_fallback | string | global | Default fallback: "allow" or "deny" (default: "allow") |
tool | string | tool | Tool name to match (e.g. "helm_uninstall") |
destructive | boolean | tool | Match tools with DestructiveHint annotation |
verb | string | kube | Kubernetes verb ("get", "delete", "list", etc.) |
kind | string | kube | Resource kind ("Secret", "Deployment", etc.) |
group | string | kube | API group ("apps", "" for core, etc.) |
version | string | kube | API version ("v1", "v1beta1", etc.) |
name | string | kube | Resource name to match |
namespace | string | kube | Namespace to match |
message | string | both | Message shown in the confirmation prompt |
A rule must be either tool-level or kube-level. It must not mix tool-level fields (tool, destructive) with kube-level fields (verb, kind, group, version, name, namespace), and must set at least one of these fields.
Examples:
confirmation_fallback = "deny"
# Confirm before uninstalling any Helm release
[[confirmation_rules]]
tool = "helm_uninstall"
message = "This will uninstall a Helm release."
# Confirm all destructive tool operations
[[confirmation_rules]]
destructive = true
message = "Destructive operation."
# Confirm Kubernetes delete calls in kube-system
[[confirmation_rules]]
verb = "delete"
namespace = "kube-system"
message = "Deleting in kube-system."
# Confirm reading Secrets
[[confirmation_rules]]
verb = "get"
kind = "Secret"
message = "Accessing a Secret."
Toolset-Specific Configuration
Some toolsets accept additional configuration via the toolset_configs map.
| Field | Type | Description |
|---|---|---|
toolset_configs | map | Toolset-specific configuration sections. |
Example (Kiali):
[toolset_configs.kiali]
url = "https://kiali.example.com"
token = "your-kiali-token"
Example (Helm):
[toolset_configs.helm]
allowed_registries = ["oci://ghcr.io/myorg", "https://charts.example.com"]
storage_driver = "configmap"
Helm Configuration
| Field | Type | Description |
|---|---|---|
allowed_registries | string array | Optional list of permitted chart registry URL prefixes. Only oci:// and https:// schemes are accepted. |
storage_driver | string | Optional default storage driver for Helm operations. Supported values: secret (default) and configmap. |
The Helm toolset supports an optional allowed_registries allowlist to restrict which registries
helm_install can fetch charts from.
Behavior:
file://andhttp://chart references are always blocked regardless of configuration.- When
allowed_registriesis not configured, anyoci://orhttps://chart reference is allowed, as well as non-URL references (e.g.stable/grafana) that resolve through Helm's local repository configuration. - When
allowed_registriesis configured, chart references must be URL-based and prefix-match an entry in the list. Non-URL references (local paths, repo/chart names) are rejected.
Accepted risk: bare filesystem paths (e.g. /absolute/path, ./relative/path) are not blocked when no allowlist is configured, because they are indistinguishable from Helm repository references at the string level. When the server runs in a container, the blast radius is limited to the container filesystem. To fully restrict chart sources, configure allowed_registries.
Refer to individual toolset documentation for available options:
Cluster Provider Configuration
Configure cluster provider-specific settings via the cluster_provider_configs map.
| Field | Type | Description |
|---|---|---|
cluster_provider_configs | map | Provider-specific configuration sections. |
Example:
[cluster_provider_configs.kcp]
# kcp-specific configuration
CLI Configuration Options
The following options can be set via command-line arguments. CLI arguments override TOML configuration values.
| Option | Description |
|---|---|
--port | Start in HTTP mode on the specified port |
--bind-address | Address to bind the HTTP server to (default: 0.0.0.0) |
--log-level | Logging verbosity (0-9) |
--log-file | Path to a server log file. Required for logging in stdio mode; replaces stdout logging in HTTP mode. Use stderr to log to the standard error stream. |
--config | Path to main TOML configuration file |
--config-dir | Path to drop-in configuration directory |
--kubeconfig | Path to Kubernetes configuration file |
--list-output | Output format for list operations (yaml or table) |
--read-only | Enable read-only mode |
--disable-destructive | Disable destructive operations |
--stateless | Enable stateless mode (no notifications) |
--toolsets | Comma-separated list of toolsets to enable |
--disable-multi-cluster | Disable multi-cluster support |
--cluster-provider | Cluster provider strategy (kubeconfig, in-cluster, kcp, disabled) |
--tls-cert | Path to TLS certificate file for HTTPS (must be used with --tls-key) |
--tls-key | Path to TLS private key file for HTTPS (must be used with --tls-cert) |
--require-tls | Enforce TLS for server and all outbound connections |
Complete Example
A comprehensive configuration file demonstrating all major options:
# Server settings
log_level = 2
log_file = "/var/log/kubernetes-mcp-server.log"
port = "8080"
bind_address = "0.0.0.0"
list_output = "table"
stateless = false
# HTTP server security
[http]
read_header_timeout = "10s" # Slowloris protection
max_body_bytes = 16777216 # 16 MB for large K8s manifests
rate_limit_rps = 5 # Per-session rate limiting
rate_limit_burst = 10
# Kubernetes connection
kubeconfig = "/home/user/.kube/config"
cluster_provider_strategy = "kubeconfig"
# Access control
read_only = false
disable_destructive = true
# Toolsets
toolsets = ["core", "config", "helm", "kubevirt"]
# Tool filtering
disabled_tools = ["resources_delete"]
# Tool overrides
[tool_overrides.pods_list]
description = "List pods in the cluster. Prefer using label selectors over listing all pods when the namespace has many workloads."
# Denied resources
[[denied_resources]]
group = ""
version = "v1"
kind = "Secret"
# Server instructions for MCP clients
server_instructions = """
Use this server for Kubernetes cluster management including pods, deployments,
services, and Helm releases. This server is configured with read-only access
to Secrets.
"""
# Custom prompts
[[prompts]]
name = "debug-pod"
description = "Debug a failing pod"
[[prompts.arguments]]
name = "pod_name"
required = true
[[prompts.messages]]
role = "user"
content = "Help me debug the pod {{pod_name}}"
# Telemetry (OpenTelemetry)
[telemetry]
endpoint = "http://localhost:4317"
traces_sampler = "traceidratio"
traces_sampler_arg = 0.1
# Toolset-specific configuration
[toolset_configs.kiali]
url = "https://kiali.example.com"
[toolset_configs.helm]
allowed_registries = ["oci://ghcr.io/myorg", "https://charts.example.com"]
Related Documentation
- prompts.md - MCP Prompts configuration
- OTEL.md - OpenTelemetry observability
- KIALI.md - Kiali toolset configuration
- KEYCLOAK_OIDC_SETUP.md - OAuth/OIDC setup guide
- getting-started-kubernetes.md - Kubernetes setup guide