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

Configuration Loading

Configuration values are loaded and merged in the following order (later sources override earlier ones):

  1. Internal Defaults - Built-in default values
  2. Main Configuration File - Loaded via --config flag or $K8S_MCP_CONFIG_PATH (the flag takes precedence)
  3. Drop-in Files - Loaded from --config-dir in 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-dir is not specified, the server looks for drop-in files in conf.d/ relative to the main config file's directory (when --config is provided)
  • File Naming: Use numeric prefixes to control loading order (e.g., 00-base.toml, 10-cluster.toml, 99-override.toml)
  • File Extension: Only .toml files 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: kubeconfig or cluster-related settings
  • Not available on Windows: Restart the server to reload configuration

Configuration Reference

Server Settings

FieldTypeDefaultDescription
log_levelinteger0Logging verbosity level (0-9). Higher values produce more verbose output. Similar to kubectl logging levels.
log_filestring""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.
portstring""When set, starts the MCP server in HTTP mode (Streamable HTTP at /mcp, SSE at /sse) on the specified port.
bind_addressstring"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_urlstring""Base URL for Server-Sent Events (SSE) connections. Used when the server is behind a reverse proxy.
list_outputstring"table"Output format for resource list operations. Valid values: yaml, table.
statelessbooleanfalseWhen true, disables tool and prompt change notifications. Useful for container deployments, load balancing, and serverless environments.
tls_certstring""Path to TLS certificate file for HTTPS. When set along with tls_key, the server serves HTTPS instead of HTTP.
tls_keystring""Path to TLS private key file for HTTPS. Must be set together with tls_cert.
require_tlsbooleanfalseWhen 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_versionstring""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_suitesarray[]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):

SettingInbound (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_SUITES setting 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_VERSION values "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.

FieldTypeDefaultDescription
http.read_header_timeoutduration"10s"Maximum duration for reading request headers. Primary defense against Slowloris attacks.
http.max_body_bytesinteger16777216Maximum size of request body in bytes (default: 16 MB).
http.rate_limit_rpsfloat0Maximum requests per second per session. When 0 (default), rate limiting is disabled.
http.rate_limit_burstinteger10Maximum 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_timeout is the primary defense against Slowloris attacks, which send headers extremely slowly to exhaust server connections
  • max_body_bytes prevents memory exhaustion from unbounded request payloads. The 16 MB default accommodates large Kubernetes manifests (CRDs, ConfigMaps)
  • rate_limit_rps prevents 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

FieldTypeDefaultDescription
kubeconfigstring""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_strategystringauto-detectHow 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 kubeconfig alone (without --kubeconfig) will fail because the server still detects the in-cluster environment. The explicit --kubeconfig path 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:

  1. Network connectivity — The pod must be able to reach the external cluster's API server. Check network policies, firewalls, and DNS resolution.
  2. Kubeconfig validity — Ensure the kubeconfig contains valid credentials (token, client certificate, etc.) and points to the correct API server address.
  3. Permissions — The credentials in the kubeconfig must have sufficient RBAC permissions on the target cluster.
  4. 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.

FieldTypeDefaultDescription
read_onlybooleanfalseWhen true, only exposes tools annotated with readOnlyHint=true. Prevents any write operations on the cluster.
disable_destructivebooleanfalseWhen true, disables tools annotated with destructiveHint=true (delete, update operations). Has no effect when read_only is true.
experimental_enable_target_compatibility_tool_filtersbooleanfalseControls 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.

FieldTypeDefaultDescription
toolsetsstring[]["core", "config", "helm"]List of toolsets to enable.

Available Toolsets:

ToolsetDescriptionDefault
configView and manage the current local Kubernetes configuration (kubeconfig)
coreMost common tools for Kubernetes management (Pods, Generic Resources, Events, etc.)
helmTools for managing Helm charts and releases
kcpManage kcp workspaces and multi-tenancy features
kialiMost common tools for managing Kiali, check the Kiali documentation for more details.
kubevirtKubeVirt virtual machine management tools, check the KubeVirt documentation for more details.
netobservNetwork observability tools backed by the NetObserv console plugin API (flows, metrics, export). Check the NetObserv documentation for more details.
tektonTekton 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.

FieldTypeDefaultDescription
enabled_toolsstring[][]Allowlist of specific tools to enable. When set, only these tools are available.
disabled_toolsstring[][]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").

FieldTypeDefaultDescription
tool_overridesmap{}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.

FieldTypeDefaultDescription
denied_resourcesarray[]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.

FieldTypeDefaultDescription
server_instructionsstring""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.

FieldTypeDescription
promptsarrayList of prompt definitions.

Prompt Fields:

  • name (required): Unique identifier
  • title (optional): Human-readable display name
  • description (required): Brief explanation
  • arguments (optional): List of parameters
  • messages (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.

FieldTypeDefaultDescription
require_oauthbooleanfalseWhen 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_audiencestring""Valid audience for OAuth tokens (for offline JWT claim validation).
authorization_urlstring""URL of the OIDC authorization server for token validation and STS exchange.
skip_jwt_verificationbooleanfalseWhen 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_registrationbooleanfalseWhen true, disables dynamic client registration in .well-known endpoints.
oauth_scopesstring[][]Supported client scopes for the OAuth flow.
sts_client_idstring""OAuth client ID for backend token exchange.
sts_client_secretstring""OAuth client secret for backend token exchange.
sts_audiencestring""Audience for STS token exchange.
sts_scopesstring[][]Scopes for STS token exchange.
token_exchange_strategystring""Token exchange strategy: rfc8693, keycloak-v1, or entra-obo.
sts_auth_stylestring"params"How client credentials are sent: params (body), header (Basic Auth), assertion (JWT), or federated (external IdP token file).
sts_client_cert_filestring""Path to client certificate PEM file (for assertion auth style).
sts_client_key_filestring""Path to client private key PEM file (for assertion auth style).
sts_federated_token_filestring""Path to a JWT file from an external identity provider, e.g., SPIRE JWT-SVID (for federated auth style).
cluster_auth_modestring""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_authoritystring""Path to CA certificate for validating authorization server connections.
server_urlstring""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.

FieldTypeDefaultDescription
telemetry.enabledbooleanautoExplicitly enable/disable telemetry. Auto-enabled when endpoint is set.
telemetry.endpointstring""OTLP endpoint URL (e.g., http://localhost:4317). Can be overridden by OTEL_EXPORTER_OTLP_ENDPOINT.
telemetry.protocolstring"grpc"OTLP protocol: grpc or http/protobuf. Can be overridden by OTEL_EXPORTER_OTLP_PROTOCOL.
telemetry.traces_samplerstring""Trace sampling strategy. Can be overridden by OTEL_TRACES_SAMPLER.
telemetry.traces_sampler_argfloat-Sampling ratio (0.0-1.0) for ratio-based samplers. Can be overridden by OTEL_TRACES_SAMPLER_ARG.

Available Samplers:

  • always_on - Sample all traces
  • always_off - Disable tracing
  • traceidratio - Sample a percentage of traces
  • parentbased_always_on - Respect parent span, default to always_on
  • parentbased_always_off - Respect parent span, default to always_off
  • parentbased_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.

FieldTypeDefaultDescription
validation_enabledbooleanfalseWhen 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 SelfSubjectAccessReview before 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 DestructiveHint annotation. 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.

FieldTypeLevelDescription
confirmation_fallbackstringglobalDefault fallback: "allow" or "deny" (default: "allow")
toolstringtoolTool name to match (e.g. "helm_uninstall")
destructivebooleantoolMatch tools with DestructiveHint annotation
verbstringkubeKubernetes verb ("get", "delete", "list", etc.)
kindstringkubeResource kind ("Secret", "Deployment", etc.)
groupstringkubeAPI group ("apps", "" for core, etc.)
versionstringkubeAPI version ("v1", "v1beta1", etc.)
namestringkubeResource name to match
namespacestringkubeNamespace to match
messagestringbothMessage 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.

FieldTypeDescription
toolset_configsmapToolset-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

FieldTypeDescription
allowed_registriesstring arrayOptional list of permitted chart registry URL prefixes. Only oci:// and https:// schemes are accepted.
storage_driverstringOptional 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:// and http:// chart references are always blocked regardless of configuration.
  • When allowed_registries is not configured, any oci:// or https:// chart reference is allowed, as well as non-URL references (e.g. stable/grafana) that resolve through Helm's local repository configuration.
  • When allowed_registries is 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.

FieldTypeDescription
cluster_provider_configsmapProvider-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.

OptionDescription
--portStart in HTTP mode on the specified port
--bind-addressAddress to bind the HTTP server to (default: 0.0.0.0)
--log-levelLogging verbosity (0-9)
--log-filePath 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.
--configPath to main TOML configuration file
--config-dirPath to drop-in configuration directory
--kubeconfigPath to Kubernetes configuration file
--list-outputOutput format for list operations (yaml or table)
--read-onlyEnable read-only mode
--disable-destructiveDisable destructive operations
--statelessEnable stateless mode (no notifications)
--toolsetsComma-separated list of toolsets to enable
--disable-multi-clusterDisable multi-cluster support
--cluster-providerCluster provider strategy (kubeconfig, in-cluster, kcp, disabled)
--tls-certPath to TLS certificate file for HTTPS (must be used with --tls-key)
--tls-keyPath to TLS private key file for HTTPS (must be used with --tls-cert)
--require-tlsEnforce 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"]