Read-Only vs Non-Destructive Mode in the MCP Server: Understanding the Distinction
Read-only mode exposes only observation tools like kubectl_get and kubectl_describe, while non-destructive mode permits resource modifications but blocks deletions by filtering out destructive operations.
The flux159/mcp-server-kubernetes repository implements two independent safety mechanisms to control which Kubernetes operations are available through the Model Context Protocol (MCP). These modes allow administrators to restrict the server's capabilities based on operational requirements, distinguishing between pure observation and protected modification workflows.
Environment Variables That Control Tool Access
The MCP server evaluates two environment flags at startup in src/index.ts to determine which tools to register. These flags operate independently and create distinct security boundaries.
Read-Only Mode (ALLOW_ONLY_READONLY_TOOLS)
When ALLOW_ONLY_READONLY_TOOLS is set to "true", the server exposes only the explicitly marked read-only tools. These tools can retrieve information from a cluster but cannot create, modify, or delete any resources.
In src/index.ts, the readonlyTools array defines this whitelist:
kubectl_getkubectl_describekubectl_logskubectl_contextexplainResourcelistApiResourcesping
This mode strictly limits the API to pure observation, making it impossible for users to affect cluster state regardless of their intent.
Non-Destructive Mode (ALLOW_ONLY_NON_DESTRUCTIVE_TOOLS)
When ALLOW_ONLY_NON_DESTRUCTIVE_TOOLS is set to "true", the server filters out the destructive tools while preserving the rest of the toolset. This permits actions that modify resources—such as kubectl_apply, kubectl_create, and kubectl_scale—while protecting against irreversible deletions.
The implementation in src/index.ts reads this flag at startup and subtracts the destructiveTools blacklist from the allTools collection. Destructive operations removed in this mode include delete operations, Helm uninstall commands, cleanup utilities, generic destructive kubectl commands, and node-drain functions.
Key Distinctions Between the Two Modes
Understanding the practical differences between these modes helps you select the appropriate restriction level for your environment.
Scope of Allowed Actions
Read-only mode limits the API to pure observation. Users cannot create, patch, scale, or delete resources. This represents the most restrictive operational stance.
Non-destructive mode still allows creation, updates, and scaling. It only blocks operations that delete or otherwise remove resources from the cluster. This provides a middle ground between full access and complete restriction.
Implementation Differences
The two modes use fundamentally different filtering strategies in the source code:
- Read-only selects a pre-defined whitelist (
readonlyTools) containing only the seven observation tools. - Non-destructive builds the allowed list by subtracting the
destructiveToolsblacklist from the completeallToolscollection, leaving all non-destructive operations intact.
When to Use Each Mode
Select read-only mode for environments where users must never affect the cluster, such as audit dashboards, monitoring interfaces, or production observation consoles where accidental modifications could cause outages.
Select non-destructive mode when you want to let users manage configuration and scale resources but safeguard against accidental deletions or infrastructure teardown. This suits development environments, CI/CD pipelines, or scenarios requiring configuration management without destruction risk.
Practical Configuration Examples
Enable read-only mode before starting the server to restrict operations to observation only:
export ALLOW_ONLY_READONLY_TOOLS=true
bun run start
The server will now return only the seven read-only tools when clients call listTools.
Enable non-destructive mode to allow modifications while blocking deletions:
export ALLOW_ONLY_NON_DESTRUCTIVE_TOOLS=true
bun run start
In this configuration, destructive tools including delete operations, Helm uninstall, and node-drain commands are omitted from the available set, but apply, create, and scale remain accessible.
Verify the active tool set programmatically:
const tools = await client.request({ method: "listTools" });
console.log(tools);
// Read-only mode: returns only readonlyTools array items
// Non-destructive mode: returns allTools minus destructiveTools
How Tool Filtering Works in the Source Code
The filtering logic resides in src/index.ts and determines tool visibility at server initialization.
For read-only mode, the code explicitly exports the readonlyTools array (lines 85-94), containing tool schemas that only retrieve data. When the environment variable is detected, the server limits the toolset to this specific collection.
For non-destructive mode, the code checks ALLOW_ONLY_NON_DESTRUCTIVE_TOOLS (lines 82-84) and applies a filter function that removes any tool listed in the destructiveTools array (lines 96-104) from the complete allTools collection. This subtractive approach ensures that any new non-destructive tools added to the codebase automatically become available in this mode without explicit whitelisting.
The test suite validates these behaviors in tests/non_destructive_tools.test.ts, confirming that the environment flag correctly filters out destructive operations while preserving modification capabilities.
Summary
- Read-only mode uses a whitelist approach via
ALLOW_ONLY_READONLY_TOOLS, exposing only seven observation tools and preventing any cluster modifications. - Non-destructive mode uses a blacklist approach via
ALLOW_ONLY_NON_DESTRUCTIVE_TOOLS, allowing resource creation and modification while blocking deletions and uninstalls. - Implementation location for both modes is
src/index.ts, which defines thereadonlyToolswhitelist anddestructiveToolsblacklist. - Default behavior exposes all tools when neither environment variable is set, including both destructive and non-destructive operations.
Frequently Asked Questions
Can I enable both read-only and non-destructive modes simultaneously?
While both flags can technically be set in the environment, src/index.ts processes ALLOW_ONLY_READONLY_TOOLS first. If set to true, the server exposes only the readonlyTools whitelist, effectively overriding the non-destructive filter. Read-only mode represents the more restrictive constraint, so it takes precedence when both are active.
Does non-destructive mode prevent all resource modifications?
No. Non-destructive mode specifically removes tools defined in the destructiveTools array—primarily delete operations, Helm uninstalls, and node drains. It explicitly permits modifying operations such as kubectl_apply, kubectl_create, kubectl_scale, and kubectl_patch. This distinction protects against irreversible deletions while allowing legitimate configuration management.
Where are the destructive tools defined in the codebase?
The destructiveTools array is defined in src/index.ts alongside the filtering logic. This array contains references to tool schemas located in the src/tools/ directory, including files like kubectl_delete.ts and Helm uninstall utilities. The test file tests/non_destructive_tools.test.ts provides the definitive list of which specific tools are filtered when non-destructive mode is active.
Which mode should I use for production environments?
For production environments where the MCP server provides observability without operational risk, read-only mode is the safer choice. It guarantees that connected clients cannot accidentally or maliciously modify cluster state. Use non-destructive mode only in production if you have specific operational workflows requiring safe configuration updates with strict protection against resource deletion.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →