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_get
  • kubectl_describe
  • kubectl_logs
  • kubectl_context
  • explainResource
  • listApiResources
  • ping

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 destructiveTools blacklist from the complete allTools collection, 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 the readonlyTools whitelist and destructiveTools blacklist.
  • 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →