Agentic AI Agents AI MCP Orchestration

Kubernetes MCP Server


What is a Kubernetes MCP Server?

A Kubernetes MCP Server is a specialized Model Context Protocol (MCP) server that enables AI assistants, coding agents, and Large Language Models (LLMs) to interact with Kubernetes clusters through natural language commands. Think of it as a translator between human-friendly AI interfaces (like Claude, Cursor, GitHub Copilot, or VS Code) and the complex Kubernetes API.

The Problem It Solves

Before Kubernetes MCP servers, developers faced several challenges:

  • Fragmented integrations: Each AI tool required custom kubectl wrappers and manual configuration
  • Security risks: Direct kubectl access from AI agents posed significant security concerns
  • Context switching: Moving between AI chat interfaces and terminal windows disrupted workflow
  • Learning curve: Complex kubectl commands and YAML syntax slowed down operations
  • Inconsistent APIs: Different tools had different ways of interacting with Kubernetes

The MCP Solution

The Model Context Protocol, introduced by Anthropic in November 2024, provides a standardized interface for AI models to access external tools and data sources. A Kubernetes MCP server implements this protocol specifically for Kubernetes operations.

Key Benefits:

  • βœ… Natural language queries: “Show me all CrashLoopBackOff pods” instead of complex kubectl commands
  • βœ… RBAC-compliant: Respects your existing Kubernetes Role-Based Access Control
  • βœ… Multi-cluster support: Manage multiple clusters from a single interface
  • βœ… Real-time insights: Get immediate answers about cluster state and resource health
  • βœ… Automated troubleshooting: AI-powered diagnosis and remediation suggestions

Why Kubernetes MCP Server Matters in 2025

The Rise of AI-Assisted DevOps

According to recent trends, the DevOps landscape is rapidly shifting towards AI-assisted workflows. Here’s why Kubernetes MCP servers are becoming essential:

  1. Agent-First Development: Modern development workflows increasingly rely on AI coding agents that need safe, controlled access to infrastructure
  2. Reduced Context Switching: Developers can query cluster state, debug issues, and deploy applications without leaving their IDE
  3. Democratized Kubernetes: Non-experts can perform complex Kubernetes operations through conversational interfaces
  4. Audit and Compliance: MCP servers provide built-in logging and tracing for all AI-initiated operations

Market Adoption

Major tech companies have recognized the importance of MCP for Kubernetes:

  • Microsoft released an enterprise-ready MCP Gateway for Kubernetes
  • Docker integrated MCP Toolkit into Docker Desktop
  • AWS launched the EKS MCP Server for Amazon Elastic Kubernetes Service
  • Red Hat developed a dedicated OpenShift MCP Server
  • Google Cloud is working on GKE MCP Server integration

Architecture Deep Dive

Understanding MCP Components

To fully grasp how Kubernetes MCP servers work, we need to understand the three core components:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                     MCP Host                            β”‚
β”‚  (Claude Desktop, VS Code, Cursor, Gemini CLI, etc.)   β”‚
β”‚                                                         β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚              MCP Client                         β”‚   β”‚
β”‚  β”‚  - Sends tool calls                             β”‚   β”‚
β”‚  β”‚  - Receives structured responses                β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                  β”‚
                  β”‚ JSON-RPC over stdio/SSE/HTTP
                  β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              Kubernetes MCP Server                       β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚  Tools Layer                                     β”‚   β”‚
β”‚  β”‚  - list_pods, get_pod, delete_pod                β”‚   β”‚
β”‚  β”‚  - list_deployments, scale_deployment            β”‚   β”‚
β”‚  β”‚  - get_logs, exec_command                        β”‚   β”‚
β”‚  β”‚  - apply_yaml, helm_install                      β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚                 β”‚                                        β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚  Authentication & Authorization Layer           β”‚   β”‚
β”‚  β”‚  - RBAC validation                               β”‚   β”‚
β”‚  β”‚  - Service Account tokens                        β”‚   β”‚
β”‚  β”‚  - Multi-cluster context switching               β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚                 β”‚                                        β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚  Kubernetes Client Library                      β”‚   β”‚
β”‚  β”‚  - client-go (Go implementation)                 β”‚   β”‚
β”‚  β”‚  - @kubernetes/client-node (Node.js)             β”‚   β”‚
β”‚  β”‚  - kubernetes Python client                      β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                  β”‚
                  β”‚ Native Kubernetes API calls
                  β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚            Kubernetes API Server                         β”‚
β”‚                                                          β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”‚
β”‚  β”‚  Resources: Pods, Services, Deployments, etc.  β”‚     β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

1. MCP Host Application

The host is the application that provides the user interface. Examples include:

  • Claude Desktop: Chat interface with MCP support
  • VS Code: With MCP extensions
  • Cursor: AI-powered code editor
  • Claude Code: Command-line AI agent
  • Custom applications: Built with MCP client SDKs

The host manages:

  • User authentication and permissions
  • Multiple MCP client instances
  • UI rendering and interaction
  • LLM integration for natural language processing

2. MCP Client

The client lives inside the host application and:

  • Translates user intent into MCP protocol messages
  • Sends JSON-RPC requests to MCP servers
  • Receives and processes structured responses
  • Maintains session state

3. Kubernetes MCP Server

The server is the core component that:

  • Exposes Kubernetes operations as MCP tools
  • Handles kubeconfig and authentication
  • Makes direct API calls to Kubernetes
  • Returns results in MCP-compatible format

Communication Protocols

Kubernetes MCP servers support multiple transport protocols:

  1. stdio (Standard Input/Output)
    • Used for local, single-user scenarios
    • Server runs as a child process
    • Communication via stdin/stdout pipes
    • Example: npx kubernetes-mcp-server
  2. SSE (Server-Sent Events)
    • HTTP-based streaming protocol
    • Supports remote connections
    • Unidirectional server-to-client streaming
    • Example: http://localhost:8811/sse
  3. HTTP (Request/Response)
    • Traditional HTTP POST requests
    • Stateless communication
    • Easy to proxy and load balance
    • Example: POST http://gateway.example.com/mcp

Top Kubernetes MCP Server Implementations

1. containers/kubernetes-mcp-server (Red Hat/Official)

Repository: https://github.com/containers/kubernetes-mcp-server

Why it’s #1:

  • Native Go implementation – No kubectl dependency, direct API calls
  • Cross-platform binaries – Linux, macOS, Windows support
  • Highest performance – Direct API interaction, low latency
  • OpenShift support – Works with both Kubernetes and OpenShift
  • Production-ready – Extensive test suite and battle-tested

Architecture Highlights:

// The server uses client-go directly
import (
    "k8s.io/client-go/kubernetes"
    "k8s.io/client-go/rest"
)

// No shell commands, pure API calls
func (s *Server) listPods(ctx context.Context, namespace string) (*v1.PodList, error) {
    return s.clientset.CoreV1().Pods(namespace).List(ctx, metav1.ListOptions{})
}

Installation Methods:

# NPM (fastest for Claude Desktop)
npx -y kubernetes-mcp-server@latest

# Native binary (no Node.js needed)
curl -L https://github.com/containers/kubernetes-mcp-server/releases/latest/download/kubernetes-mcp-server-linux-amd64 -o kubernetes-mcp-server
chmod +x kubernetes-mcp-server
./kubernetes-mcp-server

# Docker container
docker run -v ~/.kube:/root/.kube ghcr.io/containers/kubernetes-mcp-server

# Python package
pip install kubernetes-mcp-server

2. Flux159/mcp-server-kubernetes

Repository: https://github.com/Flux159/mcp-server-kubernetes

Strengths:

  • Feature-rich – Comprehensive tool set including Helm support
  • Well-documented – Excellent examples and guides
  • Non-destructive mode – Read-only option for safety
  • Secrets masking – Automatic sensitive data redaction
  • Specialized prompts – Built-in troubleshooting workflows

Key Features:

// Available tools
const tools = [
  'get_pods',
  'get_pod_logs',
  'describe_pod',
  'delete_pod',
  'get_deployments',
  'scale_deployment',
  'get_services',
  'get_nodes',
  'helm_list',
  'helm_install',
  'cleanup_pods',  // Removes Evicted, Error, Completed pods
  'troubleshoot_pod' // Guided diagnostic flow
];

Claude Desktop Configuration:

{
  "mcpServers": {
    "kubernetes": {
      "command": "npx",
      "args": ["mcp-server-kubernetes"],
      "env": {
        "KUBECONFIG": "/home/user/.kube/config"
      }
    }
  }
}

3. k8s-mcp-server (reza-gholizade)

Repository: https://github.com/reza-gholizade/k8s-mcp-server

Unique Features:

  • SSE-first design – Real-time streaming updates
  • Safety by design – Destructive operations blocked by default
  • Multi-cluster routing – Deploy across hybrid environments
  • Go performance – Lightweight, fast startup

Ideal For:

  • Real-time dashboards
  • Monitoring systems
  • AI chatbots requiring live data
  • Multi-cluster federated environments

4. AWS EKS MCP Server

Official AWS Implementation

Strengths:

  • Zero kubeconfig needed – Automatic EKS authentication
  • CloudFormation integration – Infrastructure as Code support
  • Best practices built-in – EKS Auto Mode, security groups
  • Knowledge base – Access to AWS EKS documentation
  • Guided workflows – High-level abstractions for common tasks

Example Use Case:

// Create an EKS cluster with all prerequisites
// AI Assistant handles VPC, subnets, IAM roles automatically
"Create a production-ready EKS cluster named prod-cluster 
with 3 nodes in us-west-2"

// Behind the scenes, the MCP server:
// 1. Creates VPC with public/private subnets
// 2. Sets up NAT gateways and route tables
// 3. Creates IAM roles with least privilege
// 4. Provisions EKS cluster with best practices
// 5. Configures node groups with auto-scaling

5. Azure MCP Server (Kubernetes Tools)

Microsoft’s Official Implementation

Integration Points:

{
  "tools": [
    "azure_aks_get_clusters",      // List AKS clusters
    "azure_aks_get_cluster",        // Get specific cluster config
    "azure_aks_get_node_pools",     // List node pools
    "azure_aks_get_node_pool",      // Get node pool details
    "azure_aks_scale_node_pool"     // Scale operations
  ]
}

Natural Language Examples:

# Query clusters
"Show me my Azure Kubernetes Service clusters"

# Get configuration
"What's the configuration of AKS cluster 'prod-aks-001' 
in resource group 'production'"

# List node pools
"List node pools for AKS cluster 'dev-kubernetes' 
in 'development-rg'"

# Scale operations
"Scale node pool 'userpool' in cluster 'staging-aks' 
to 5 nodes"

Installation and Setup Guide {#installation}

Prerequisites

Before installing any Kubernetes MCP server, ensure you have:

  1. A Kubernetes Cluster # Verify cluster access kubectl cluster-info kubectl get nodes
  2. Valid kubeconfig # Check your kubeconfig echo $KUBECONFIG cat ~/.kube/config # Test multiple contexts kubectl config get-contexts kubectl config use-context production-cluster
  3. Appropriate RBAC Permissions # Check your permissions kubectl auth can-i list pods --all-namespaces kubectl auth can-i create deployments kubectl auth can-i delete pods
  4. An MCP-Compatible Client
    • Claude Desktop (macOS/Windows)
    • VS Code with MCP extension
    • Cursor IDE
    • Claude Code CLI
    • Custom client application

Step 1: Install Claude Desktop (Primary Client)

macOS:

# Download from official website
# https://claude.ai/download

# Or using Homebrew
brew install --cask claude

Windows:

# Download installer from
# https://claude.ai/download

# Or using Chocolatey
choco install claude

Verify Installation:

# Check if Claude Desktop is installed
# Open Claude Desktop app
# Go to Settings (Cmd+, or Ctrl+,)
# Navigate to Developer tab
# You should see "MCP Servers" section

Step 2: Install Kubernetes MCP Server

Option A: Using NPX (Recommended for Beginners)

Advantages:

  • No installation required
  • Always uses latest version
  • Works across platforms
  • Simple one-line setup
# Test the server
npx -y kubernetes-mcp-server@latest --version

# The server will auto-install when Claude Desktop starts it

Configuration for Claude Desktop:

  1. Open the configuration file: # macOS code ~/Library/Application\ Support/Claude/claude_desktop_config.json # Windows code %APPDATA%\Claude\claude_desktop_config.json # Linux code ~/.config/Claude/claude_desktop_config.json
  2. Add the MCP server configuration: { "mcpServers": { "kubernetes": { "command": "npx", "args": [ "-y", "kubernetes-mcp-server@latest" ] } } }
  3. Explanation of configuration:
    • "kubernetes": Server name (can be anything)
    • "command": "npx": Uses Node Package Execute
    • "-y": Auto-confirms package installation
    • "kubernetes-mcp-server@latest": Package name and version
  4. Restart Claude Desktop
  5. Verify installation:
    • Open a new chat in Claude
    • Look for the πŸ”Œ (plug) icon in the bottom-right
    • You should see “kubernetes” server listed
    • Tools should be available for selection

Option B: Native Binary (Best Performance)

Why choose native binary:

  • No Node.js dependency
  • Smallest memory footprint
  • Fastest startup time
  • Single executable file

Linux Installation:

# Download latest release
LATEST_VERSION=$(curl -s https://api.github.com/repos/containers/kubernetes-mcp-server/releases/latest | grep tag_name | cut -d '"' -f 4)

# AMD64
curl -L "https://github.com/containers/kubernetes-mcp-server/releases/download/${LATEST_VERSION}/kubernetes-mcp-server-linux-amd64" \
  -o /usr/local/bin/kubernetes-mcp-server

# ARM64
curl -L "https://github.com/containers/kubernetes-mcp-server/releases/download/${LATEST_VERSION}/kubernetes-mcp-server-linux-arm64" \
  -o /usr/local/bin/kubernetes-mcp-server

# Make executable
chmod +x /usr/local/bin/kubernetes-mcp-server

# Test
kubernetes-mcp-server --version

macOS Installation:

# Download for macOS
LATEST_VERSION=$(curl -s https://api.github.com/repos/containers/kubernetes-mcp-server/releases/latest | grep tag_name | cut -d '"' -f 4)

# Intel Macs
curl -L "https://github.com/containers/kubernetes-mcp-server/releases/download/${LATEST_VERSION}/kubernetes-mcp-server-darwin-amd64" \
  -o /usr/local/bin/kubernetes-mcp-server

# Apple Silicon (M1/M2/M3)
curl -L "https://github.com/containers/kubernetes-mcp-server/releases/download/${LATEST_VERSION}/kubernetes-mcp-server-darwin-arm64" \
  -o /usr/local/bin/kubernetes-mcp-server

chmod +x /usr/local/bin/kubernetes-mcp-server
kubernetes-mcp-server --version

Windows Installation:

# Download Windows binary
$LatestRelease = Invoke-RestMethod -Uri "https://api.github.com/repos/containers/kubernetes-mcp-server/releases/latest"
$DownloadUrl = $LatestRelease.assets | Where-Object { $_.name -like "*windows*" } | Select-Object -ExpandProperty browser_download_url

# Download to C:\Program Files\kubernetes-mcp-server\
New-Item -ItemType Directory -Path "C:\Program Files\kubernetes-mcp-server" -Force
Invoke-WebRequest -Uri $DownloadUrl -OutFile "C:\Program Files\kubernetes-mcp-server\kubernetes-mcp-server.exe"

# Add to PATH
$env:Path += ";C:\Program Files\kubernetes-mcp-server"

# Test
kubernetes-mcp-server.exe --version

Claude Desktop Configuration (Native Binary):

{
  "mcpServers": {
    "kubernetes": {
      "command": "/usr/local/bin/kubernetes-mcp-server",
      "args": []
    }
  }
}

Option C: Docker Container

When to use Docker:

  • Isolated environments
  • CI/CD pipelines
  • Server deployments
  • Testing different versions

Basic Docker Setup:

# Pull the image
docker pull ghcr.io/containers/kubernetes-mcp-server:latest

# Run with kubeconfig mounted
docker run -it --rm \
  -v ~/.kube:/root/.kube:ro \
  ghcr.io/containers/kubernetes-mcp-server:latest

Docker Compose Setup:

# docker-compose.yml
version: '3.8'

services:
  kubernetes-mcp-server:
    image: ghcr.io/containers/kubernetes-mcp-server:latest
    container_name: k8s-mcp
    volumes:
      - ~/.kube:/root/.kube:ro  # Mount kubeconfig (read-only)
    environment:
      - KUBECONFIG=/root/.kube/config
    restart: unless-stopped
    # Expose port if using SSE transport
    ports:
      - "8811:8811"
    command: ["--transport=sse", "--port=8811"]

Start the container:

docker-compose up -d

# View logs
docker-compose logs -f kubernetes-mcp-server

# Stop
docker-compose down

Option D: Python Package

Installation:

# Create virtual environment (recommended)
python -m venv mcp-env
source mcp-env/bin/activate  # On Windows: mcp-env\Scripts\activate

# Install package
pip install kubernetes-mcp-server

# Verify
python -m kubernetes_mcp_server --version

Claude Desktop Configuration:

{
  "mcpServers": {
    "kubernetes": {
      "command": "python",
      "args": [
        "-m",
        "kubernetes_mcp_server"
      ],
      "env": {
        "KUBECONFIG": "/home/user/.kube/config"
      }
    }
  }
}

Step 3: Configure Access and Security

Creating a Read-Only Service Account

For production environments, never use admin credentials with MCP servers. Create a dedicated service account with minimal permissions:

# k8s-mcp-rbac.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: mcp-reader
  namespace: default

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: mcp-cluster-reader
rules:
  # Pods
  - apiGroups: [""]
    resources: ["pods", "pods/log", "pods/status"]
    verbs: ["get", "list", "watch"]
  
  # Deployments
  - apiGroups: ["apps"]
    resources: ["deployments", "replicasets", "statefulsets", "daemonsets"]
    verbs: ["get", "list", "watch"]
  
  # Services
  - apiGroups: [""]
    resources: ["services", "endpoints"]
    verbs: ["get", "list", "watch"]
  
  # ConfigMaps (excluding secrets)
  - apiGroups: [""]
    resources: ["configmaps"]
    verbs: ["get", "list", "watch"]
  
  # Nodes
  - apiGroups: [""]
    resources: ["nodes"]
    verbs: ["get", "list", "watch"]
  
  # Events
  - apiGroups: [""]
    resources: ["events"]
    verbs: ["get", "list", "watch"]
  
  # Namespaces
  - apiGroups: [""]
    resources: ["namespaces"]
    verbs: ["get", "list", "watch"]

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: mcp-cluster-reader-binding
subjects:
  - kind: ServiceAccount
    name: mcp-reader
    namespace: default
roleRef:
  kind: ClusterRole
  name: mcp-cluster-reader
  apiGroup: rbac.authorization.k8s.io

Apply the configuration:

kubectl apply -f k8s-mcp-rbac.yaml

Generate a token for the service account:

# Create a token (Kubernetes 1.24+)
kubectl create token mcp-reader --duration=8760h -n default

# For older versions, create a secret
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Secret
metadata:
  name: mcp-reader-token
  namespace: default
  annotations:
    kubernetes.io/service-account.name: mcp-reader
type: kubernetes.io/service-account-token
EOF

# Get the token
kubectl get secret mcp-reader-token -n default -o jsonpath='{.data.token}' | base64 -d

Create a custom kubeconfig:

# Get cluster info
CLUSTER_NAME=$(kubectl config view -o jsonpath='{.clusters[0].name}')
CLUSTER_SERVER=$(kubectl config view -o jsonpath='{.clusters[0].cluster.server}')
CLUSTER_CA=$(kubectl config view --raw -o jsonpath='{.clusters[0].cluster.certificate-authority-data}')
TOKEN=$(kubectl get secret mcp-reader-token -n default -o jsonpath='{.data.token}' | base64 -d)

# Create new kubeconfig
cat > ~/.kube/mcp-config << EOF
apiVersion: v1
kind: Config
clusters:
- cluster:
    certificate-authority-data: ${CLUSTER_CA}
    server: ${CLUSTER_SERVER}
  name: ${CLUSTER_NAME}
contexts:
- context:
    cluster: ${CLUSTER_NAME}
    user: mcp-reader
  name: mcp-context
current-context: mcp-context
users:
- name: mcp-reader
  user:
    token: ${TOKEN}
EOF

# Test the new kubeconfig
KUBECONFIG=~/.kube/mcp-config kubectl get pods

Update Claude Desktop to use the restricted kubeconfig:

{
  "mcpServers": {
    "kubernetes": {
      "command": "npx",
      "args": ["-y", "kubernetes-mcp-server@latest"],
      "env": {
        "KUBECONFIG": "/home/user/.kube/mcp-config"
      }
    }
  }
}

Enabling Read-Only Mode

Most Kubernetes MCP servers support a --read-only flag:

{
  "mcpServers": {
    "kubernetes": {
      "command": "kubernetes-mcp-server",
      "args": ["--read-only"]
    }
  }
}

What read-only mode blocks:

  • ❌ create operations (apply, create)
  • ❌ update operations (patch, update)
  • ❌ delete operations (delete, destroy)
  • ❌ exec into pods
  • βœ… get operations (get, list)
  • βœ… log retrieval (logs)
  • βœ… describe operations

Step 4: Multi-Cluster Configuration

Managing multiple clusters from one MCP server:

{
  "mcpServers": {
    "kubernetes-production": {
      "command": "npx",
      "args": ["-y", "kubernetes-mcp-server@latest"],
      "env": {
        "KUBECONFIG": "/home/user/.kube/prod-config",
        "KUBERNETES_CONTEXT": "production-cluster"
      }
    },
    "kubernetes-staging": {
      "command": "npx",
      "args": ["-y", "kubernetes-mcp-server@latest"],
      "env": {
        "KUBECONFIG": "/home/user/.kube/staging-config",
        "KUBERNETES_CONTEXT": "staging-cluster"
      }
    },
    "kubernetes-development": {
      "command": "npx",
      "args": ["-y", "kubernetes-mcp-server@latest"],
      "env": {
        "KUBECONFIG": "/home/user/.kube/dev-config",
        "KUBERNETES_CONTEXT": "dev-cluster"
      }
    }
  }
}

Using context in queries:

# Claude will use the appropriate server based on your query
"Show me production pods in the frontend namespace"
"List staging deployments"
"What's the status of dev cluster nodes?"

Code Examples and Deep Explanations {#code-examples}

Example 1: Building a Custom Kubernetes MCP Server from Scratch

Let’s build a minimal Kubernetes MCP server to understand how everything works under the hood.

Step 1: Project Setup

# Create project directory
mkdir custom-k8s-mcp-server
cd custom-k8s-mcp-server

# Initialize Node.js project
npm init -y

# Install dependencies
npm install @modelcontextprotocol/sdk @kubernetes/client-node

Package.json:

{
  "name": "custom-k8s-mcp-server",
  "version": "1.0.0",
  "type": "module",
  "main": "index.js",
  "dependencies": {
    "@modelcontextprotocol/sdk": "^0.5.0",
    "@kubernetes/client-node": "^0.20.0"
  }
}

Step 2: Server Implementation

index.js:

#!/usr/bin/env node
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { 
  CallToolRequestSchema,
  ListToolsRequestSchema 
} from "@modelcontextprotocol/sdk/types.js";
import { KubeConfig, CoreV1Api, AppsV1Api } from '@kubernetes/client-node';

/**
 * Initialize Kubernetes client
 * This reads from ~/.kube/config by default
 * Can be overridden with KUBECONFIG environment variable
 */
const kc = new KubeConfig();
kc.loadFromDefault();  // Loads from default kubeconfig location

// Create API clients
const k8sApi = kc.makeApiClient(CoreV1Api);     // For pods, services, etc.
const appsApi = kc.makeApiClient(AppsV1Api);    // For deployments, statefulsets, etc.

/**
 * Create the MCP server instance
 * 
 * Server capabilities:
 * - name: Identifies the server in client applications
 * - version: Semantic versioning for compatibility
 */
const server = new Server(
  {
    name: "custom-kubernetes-mcp-server",
    version: "1.0.0",
  },
  {
    capabilities: {
      tools: {},  // Declares that this server provides tools
    },
  }
);

/**
 * Define available tools
 * 
 * This handler responds to the client's request for available tools
 * Each tool is defined with:
 * - name: Unique identifier
 * - description: What the tool does (used by AI to decide when to call it)
 * - inputSchema: JSON Schema defining required and optional parameters
 */
server.setRequestHandler(ListToolsRequestSchema, async () => {
  return {
    tools: [
      {
        name: "list_pods",
        description: "List all pods in a namespace or across all namespaces. Returns pod name, status, and basic information.",
        inputSchema: {
          type: "object",
          properties: {
            namespace: {
              type: "string",
              description: "Kubernetes namespace. Use 'all' for all namespaces, or specify a specific namespace name",
              default: "default"
            }
          }
        }
      },
      {
        name: "get_pod",
        description: "Get detailed information about a specific pod including its status, containers, and resource usage",
        inputSchema: {
          type: "object",
          properties: {
            name: {
              type: "string",
              description: "Name of the pod"
            },
            namespace: {
              type: "string",
              description: "Namespace where the pod exists",
              default: "default"
            }
          },
          required: ["name"]
        }
      },
      {
        name: "get_pod_logs",
        description: "Retrieve logs from a pod. Can specify container name for multi-container pods",
        inputSchema: {
          type: "object",
          properties: {
            name: {
              type: "string",
              description: "Name of the pod"
            },
            namespace: {
              type: "string",
              description: "Namespace where the pod exists",
              default: "default"
            },
            container: {
              type: "string",
              description: "Container name (optional, for multi-container pods)"
            },
            tail_lines: {
              type: "number",
              description: "Number of lines to retrieve from the end of logs",
              default: 100
            }
          },
          required: ["name"]
        }
      },
      {
        name: "list_deployments",
        description: "List all deployments in a namespace with their replicas and status",
        inputSchema: {
          type: "object",
          properties: {
            namespace: {
              type: "string",
              description: "Kubernetes namespace",
              default: "default"
            }
          }
        }
      }
    ]
  };
});

/**
 * Handle tool execution requests
 * 
 * When the AI decides to call a tool, this handler:
 * 1. Validates the tool name
 * 2. Extracts parameters from the request
 * 3. Calls the appropriate Kubernetes API
 * 4. Formats and returns the response
 */
server.setRequestHandler(CallToolRequestSchema, async (request) => {
  const { name, arguments: args } = request.params;
  
  try {
    switch (name) {
      case "list_pods": {
        /**
         * List pods implementation
         * 
         * Uses CoreV1Api.listNamespacedPod or listPodForAllNamespaces
         * Returns formatted pod information
         */
        const namespace = args.namespace || "default";
        let pods;
        
        if (namespace === "all") {
          // List pods across all namespaces
          const response = await k8sApi.listPodForAllNamespaces();
          pods = response.body.items;
        } else {
          // List pods in specific namespace
          const response = await k8sApi.listNamespacedPod(namespace);
          pods = response.body.items;
        }
        
        // Format the response
        const podList = pods.map(pod => ({
          name: pod.metadata.name,
          namespace: pod.metadata.namespace,
          status: pod.status.phase,
          ready: `${pod.status.containerStatuses?.filter(c => c.ready).length || 0}/${pod.spec.containers.length}`,
          restarts: pod.status.containerStatuses?.reduce((sum, c) => sum + c.restartCount, 0) || 0,
          age: calculateAge(pod.metadata.creationTimestamp)
        }));
        
        return {
          content: [
            {
              type: "text",
              text: JSON.stringify(podList, null, 2)
            }
          ]
        };
      }
      
      case "get_pod": {
        /**
         * Get single pod implementation
         * 
         * Retrieves detailed pod information including:
         * - Container statuses
         * - Resource requests/limits
         * - Labels and annotations
         * - Events
         */
        const { name, namespace = "default" } = args;
        
        // Get pod details
        const podResponse = await k8sApi.readNamespacedPod(name, namespace);
        const pod = podResponse.body;
        
        // Get events for this pod
        const eventsResponse = await k8sApi.listNamespacedEvent(
          namespace,
          undefined,
          undefined,
          undefined,
          `involvedObject.name=${name},involvedObject.kind=Pod`
        );
        const events = eventsResponse.body.items;
        
        // Format detailed response
        const podDetails = {
          name: pod.metadata.name,
          namespace: pod.metadata.namespace,
          labels: pod.metadata.labels,
          annotations: pod.metadata.annotations,
          status: {
            phase: pod.status.phase,
            conditions: pod.status.conditions,
            podIP: pod.status.podIP,
            hostIP: pod.status.hostIP,
            startTime: pod.status.startTime
          },
          containers: pod.spec.containers.map((container, index) => {
            const status = pod.status.containerStatuses?.[index];
            return {
              name: container.name,
              image: container.image,
              ready: status?.ready || false,
              restartCount: status?.restartCount || 0,
              state: status?.state,
              resources: container.resources
            };
          }),
          recentEvents: events.slice(0, 5).map(event => ({
            type: event.type,
            reason: event.reason,
            message: event.message,
            timestamp: event.lastTimestamp
          }))
        };
        
        return {
          content: [
            {
              type: "text",
              text: JSON.stringify(podDetails, null, 2)
            }
          ]
        };
      }
      
      case "get_pod_logs": {
        /**
         * Get pod logs implementation
         * 
         * Retrieves container logs with options for:
         * - Tail lines (last N lines)
         * - Specific container (for multi-container pods)
         * - Timestamps
         */
        const { 
          name, 
          namespace = "default", 
          container, 
          tail_lines = 100 
        } = args;
        
        try {
          // Read logs from Kubernetes API
          const logsResponse = await k8sApi.readNamespacedPodLog(
            name,
            namespace,
            container,      // Container name (optional)
            false,          // follow
            undefined,      // insecureSkipTLSVerifyBackend
            undefined,      // limitBytes
            false,          // pretty
            false,          // previous
            undefined,      // sinceSeconds
            tail_lines,     // tailLines
            true            // timestamps
          );
          
          return {
            content: [
              {
                type: "text",
                text: `Logs for pod ${name}${container ? ` (container: ${container})` : ''}:\n\n${logsResponse.body}`
              }
            ]
          };
        } catch (error) {
          // Handle common errors
          if (error.response?.statusCode === 404) {
            return {
              content: [
                {
                  type: "text",
                  text: `Pod ${name} not found in namespace ${namespace}`
                }
              ],
              isError: true
            };
          }
          throw error;
        }
      }
      
      case "list_deployments": {
        /**
         * List deployments implementation
         * 
         * Returns deployment information including:
         * - Replica counts (desired, current, ready)
         * - Update strategy
         * - Container images
         */
        const { namespace = "default" } = args;
        
        const deploymentsResponse = await appsApi.listNamespacedDeployment(namespace);
        const deployments = deploymentsResponse.body.items;
        
        const deploymentList = deployments.map(dep => ({
          name: dep.metadata.name,
          namespace: dep.metadata.namespace,
          replicas: {
            desired: dep.spec.replicas,
            current: dep.status.replicas,
            ready: dep.status.readyReplicas,
            available: dep.status.availableReplicas
          },
          strategy: dep.spec.strategy.type,
          images: dep.spec.template.spec.containers.map(c => c.image),
          age: calculateAge(dep.metadata.creationTimestamp)
        }));
        
        return {
          content: [
            {
              type: "text",
              text: JSON.stringify(deploymentList, null, 2)
            }
          ]
        };
      }
      
      default:
        throw new Error(`Unknown tool: ${name}`);
    }
  } catch (error) {
    // Error handling with detailed messages
    console.error(`Error executing tool ${name}:`, error);
    return {
      content: [
        {
          type: "text",
          text: `Error: ${error.message}\n\nDetails: ${JSON.stringify(error.response?.body || error, null, 2)}`
        }
      ],
      isError: true
    };
  }
});

/**
 * Helper function to calculate resource age
 * Converts ISO timestamp to human-readable duration
 */
function calculateAge(timestamp) {
  const now = new Date();
  const created = new Date(timestamp);
  const diffMs = now - created;
  const diffMins = Math.floor(diffMs / 60000);
  const diffHours = Math.floor(diffMs / 3600000);
  const diffDays = Math.floor(diffMs / 86400000);
  
  if (diffDays > 0) return `${diffDays}d`;
  if (diffHours > 0) return `${diffHours}h`;
  if (diffMins > 0) return `${diffMins}m`;
  return `${Math.floor(diffMs / 1000)}s`;
}

/**
 * Server startup
 * 
 * Creates a stdio transport (for local use)
 * Connects the server to the transport
 * Starts listening for requests
 */
async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
  console.error("Custom Kubernetes MCP Server running on stdio");
}

main().catch(console.error);

Step 3: Testing the Custom Server

Make it executable:

chmod +x index.js

Test directly:

# Run the server
node index.js

# It will wait for JSON-RPC messages on stdin
# You can test with the MCP Inspector
npx @modelcontextprotocol/inspector node index.js

Configure in Claude Desktop:

{
  "mcpServers": {
    "custom-kubernetes": {
      "command": "node",
      "args": ["/path/to/custom-k8s-mcp-server/index.js"],
      "env": {
        "KUBECONFIG": "/home/user/.kube/config"
      }
    }
  }
}

Example 2: Advanced Tool – Pod Troubleshooting Workflow

Let’s implement an intelligent troubleshooting tool that guides users through diagnosing pod issues:

/**
 * Advanced troubleshooting tool
 * 
 * This tool implements a systematic diagnostic workflow:
 * 1. Get pod status and events
 * 2. Check container states
 * 3. Analyze resource constraints
 * 4. Review logs for errors
 * 5. Suggest remediation steps
 */
{
  name: "troubleshoot_pod",
  description: "Systematically troubleshoot a pod issue by analyzing status, events, logs, and providing remediation suggestions",
  inputSchema: {
    type: "object",
    properties: {
      name: {
        type: "string",
        description: "Name of the pod to troubleshoot"
      },
      namespace: {
        type: "string",
        description: "Namespace of the pod",
        default: "default"
      }
    },
    required: ["name"]
  }
}

// Implementation in CallToolRequestSchema handler:
case "troubleshoot_pod": {
  const { name, namespace = "default" } = args;
  
  // Step 1: Get pod details
  const podResponse = await k8sApi.readNamespacedPod(name, namespace);
  const pod = podResponse.body;
  
  // Step 2: Get recent events
  const eventsResponse = await k8sApi.listNamespacedEvent(
    namespace,
    undefined, undefined, undefined,
    `involvedObject.name=${name}`
  );
  const events = eventsResponse.body.items
    .sort((a, b) => new Date(b.lastTimestamp) - new Date(a.lastTimestamp))
    .slice(0, 10);
  
  // Step 3: Analyze pod state
  const analysis = {
    podName: name,
    namespace: namespace,
    phase: pod.status.phase,
    issues: [],
    recommendations: []
  };
  
  // Check pod phase
  if (pod.status.phase === "Pending") {
    analysis.issues.push("Pod is stuck in Pending state");
    
    // Check for scheduling issues
    const schedulingEvents = events.filter(e => 
      e.reason === "FailedScheduling" || 
      e.reason === "Unschedulable"
    );
    
    if (schedulingEvents.length > 0) {
      const lastEvent = schedulingEvents[0];
      analysis.issues.push(`Scheduling failed: ${lastEvent.message}`);
      
      // Provide specific recommendations based on the error
      if (lastEvent.message.includes("Insufficient cpu")) {
        analysis.recommendations.push(
          "Increase node CPU capacity or reduce pod CPU requests"
        );
      } else if (lastEvent.message.includes("Insufficient memory")) {
        analysis.recommendations.push(
          "Increase node memory or reduce pod memory requests"
        );
      } else if (lastEvent.message.includes("node(s) didn't match pod affinity")) {
        analysis.recommendations.push(
          "Review pod affinity/anti-affinity rules and node labels"
        );
      }
    }
  }
  
  // Check container states
  if (pod.status.containerStatuses) {
    for (const containerStatus of pod.status.containerStatuses) {
      // CrashLoopBackOff
      if (containerStatus.state?.waiting?.reason === "CrashLoopBackOff") {
        analysis.issues.push(
          `Container ${containerStatus.name} is in CrashLoopBackOff`
        );
        
        // Get container logs
        try {
          const logsResponse = await k8sApi.readNamespacedPodLog(
            name, namespace, containerStatus.name,
            false, undefined, undefined, false,
            true,  // previous=true to get logs from crashed container
            undefined, 50
          );
          
          // Analyze logs for common issues
          const logs = logsResponse.body;
          if (logs.includes("ECONNREFUSED")) {
            analysis.recommendations.push(
              `Container ${containerStatus.name}: Connection refused error detected. Check if required services are running and accessible.`
            );
          } else if (logs.includes("OutOfMemory") || logs.includes("OOM")) {
            analysis.recommendations.push(
              `Container ${containerStatus.name}: Out of memory error. Increase memory limits or optimize application memory usage.`
            );
          } else if (logs.includes("panic") || logs.includes("fatal")) {
            analysis.recommendations.push(
              `Container ${containerStatus.name}: Application crash detected. Review application logs for specific error messages.`
            );
          } else {
            analysis.recommendations.push(
              `Container ${containerStatus.name}: Check container logs for error messages and stack traces.`
            );
          }
        } catch (error) {
          console.error("Error getting logs:", error);
        }
      }
      
      // ImagePullBackOff
      if (containerStatus.state?.waiting?.reason === "ImagePullBackOff" ||
          containerStatus.state?.waiting?.reason === "ErrImagePull") {
        analysis.issues.push(
          `Container ${containerStatus.name}: Failed to pull image ${containerStatus.image}`
        );
        
        const imagePullEvents = events.filter(e => 
          e.reason === "Failed" && e.message.includes("pull")
        );
        
        if (imagePullEvents.length > 0) {
          const errorMsg = imagePullEvents[0].message;
          if (errorMsg.includes("not found") || errorMsg.includes("404")) {
            analysis.recommendations.push(
              `Container ${containerStatus.name}: Image not found. Verify the image name and tag are correct.`
            );
          } else if (errorMsg.includes("unauthorized") || errorMsg.includes("authentication")) {
            analysis.recommendations.push(
              `Container ${containerStatus.name}: Authentication failed. Ensure image pull secrets are configured correctly.`
            );
          } else {
            analysis.recommendations.push(
              `Container ${containerStatus.name}: Image pull failed. Check network connectivity and registry availability.`
            );
          }
        }
      }
      
      // Resource constraints
      if (containerStatus.state?.terminated?.reason === "OOMKilled") {
        analysis.issues.push(
          `Container ${containerStatus.name} was killed due to out of memory`
        );
        analysis.recommendations.push(
          `Increase memory limits for container ${containerStatus.name} or optimize application memory usage`
        );
      }
    }
  }
  
  // Check for probe failures
  const probeFailEvents = events.filter(e => 
    e.reason === "Unhealthy" || e.reason === "ProbeError"
  );
  if (probeFailEvents.length > 0) {
    analysis.issues.push("Liveness or readiness probe failures detected");
    analysis.recommendations.push(
      "Review probe configuration (timeouts, thresholds) and ensure application responds correctly to health checks"
    );
  }
  
  // Format the complete troubleshooting report
  const report = `
=== Pod Troubleshooting Report ===
Pod: ${name}
Namespace: ${namespace}
Phase: ${pod.status.phase}

${analysis.issues.length > 0 ? `
IDENTIFIED ISSUES:
${analysis.issues.map((issue, i) => `${i + 1}. ${issue}`).join('\n')}
` : 'No obvious issues detected.'}

${analysis.recommendations.length > 0 ? `
RECOMMENDATIONS:
${analysis.recommendations.map((rec, i) => `${i + 1}. ${rec}`).join('\n')}
` : ''}

RECENT EVENTS:
${events.slice(0, 5).map(e => 
  `[${e.type}] ${e.reason}: ${e.message} (${e.lastTimestamp})`
).join('\n')}

CONTAINER STATUS:
${pod.status.containerStatuses?.map(c => `
  ${c.name}:
    Ready: ${c.ready}
    Restart Count: ${c.restartCount}
    State: ${JSON.stringify(c.state, null, 4)}
`).join('\n') || 'No container status available'}
`;
  
  return {
    content: [
      {
        type: "text",
        text: report
      }
    ]
  };
}

Example 3: Using Kubernetes MCP Server with Docker MCP Gateway

The Docker MCP Gateway provides enterprise-grade orchestration for MCP servers:

docker-compose.yml:

version: '3.8'

services:
  # MCP Gateway
  mcp-gateway:
    image: docker/mcp-gateway:latest
    container_name: mcp-gateway
    ports:
      - "8811:8811"  # SSE endpoint
    volumes:
      # Mount Docker socket for container management
      - /var/run/docker.sock:/var/run/docker.sock
      # Mount kubeconfig for Kubernetes access
      - ~/.kube:/root/.kube:ro
      # Mount MCP configuration
      - ./mcp-config:/mcp-config:ro
    environment:
      # Gateway configuration
      - MCP_TRANSPORT=sse
      - MCP_PORT=8811
      # Kubernetes configuration
      - KUBECONFIG=/root/.kube/config
      # Security settings
      - MCP_VERIFY_SIGNATURES=true
      - MCP_BLOCK_SECRETS=true
      - MCP_LOG_CALLS=true
    command: >
      --transport=sse
      --port=8811
      --servers=kubernetes
      --verify-signatures
      --block-secrets
      --log-calls
    restart: unless-stopped
    networks:
      - mcp-network

  # PostgreSQL for audit logs (optional)
  postgres:
    image: postgres:16-alpine
    container_name: mcp-postgres
    environment:
      POSTGRES_DB: mcp_gateway
      POSTGRES_USER: mcp
      POSTGRES_PASSWORD: secure_password_here
    volumes:
      - postgres-data:/var/lib/postgresql/data
      - ./init-db.sql:/docker-entrypoint-initdb.d/init.sql:ro
    networks:
      - mcp-network
    restart: unless-stopped

volumes:
  postgres-data:

networks:
  mcp-network:
    driver: bridge

Explanation of docker-compose configuration:

  1. MCP Gateway Service:
    • ports: "8811:8811": Exposes the SSE endpoint for clients to connect
    • /var/run/docker.sock: Allows gateway to manage Docker containers
    • ~/.kube:/root/.kube:ro: Mounts kubeconfig in read-only mode
    • MCP_VERIFY_SIGNATURES: Ensures only signed container images are used
    • MCP_BLOCK_SECRETS: Scans payloads for secrets before transmission
    • MCP_LOG_CALLS: Maintains audit trail of all MCP operations
  2. PostgreSQL Service:
    • Stores audit logs and session data
    • Enables compliance tracking
    • Supports multi-user environments

Gateway configuration file (mcp-config/gateway.yaml):

# Gateway configuration
gateway:
  # Server discovery and registration
  servers:
    kubernetes:
      enabled: true
      image: ghcr.io/containers/kubernetes-mcp-server:latest
      config:
        kubeconfig: /root/.kube/config
        read_only: false  # Set to true for production
      
      # Resource limits per container
      resources:
        cpu_limit: "1.0"
        memory_limit: "2Gb"
      
      # Security settings
      security:
        no_new_privileges: true
        read_only_rootfs: false
        
      # Network configuration
      network:
        mode: bridge
        
      # Auto-start configuration
      auto_start: true
      
      # Tool filtering (optional)
      tools:
        allow:
          - list_pods
          - get_pod
          - get_pod_logs
          - list_deployments
          - list_services
          - get_nodes
        deny:
          - delete_pod
          - exec_pod

  # Security policies
  security:
    # Signature verification
    verify_signatures: true
    
    # Secret blocking patterns
    secret_patterns:
      - "-----BEGIN (RSA |EC |OPENSSH |DSA )?PRIVATE KEY-----"
      - "aws_access_key_id"
      - "aws_secret_access_key"
      - "AKIA[0-9A-Z]{16}"
      - "ghp_[0-9a-zA-Z]{36}"
      
    # Rate limiting
    rate_limit:
      requests_per_minute: 60
      requests_per_hour: 1000
      
  # Logging configuration
  logging:
    level: info  # debug, info, warn, error
    format: json
    destination: stdout
    
    # Audit logging
    audit:
      enabled: true
      database: postgresql://mcp:secure_password_here@postgres:5432/mcp_gateway
      
  # Transport configuration  
  transports:
    sse:
      enabled: true
      port: 8811
      cors:
        allowed_origins:
          - "http://localhost:*"
          - "https://claude.ai"

Starting the gateway:

# Start all services
docker-compose up -d

# View logs
docker-compose logs -f mcp-gateway

# Check health
curl http://localhost:8811/health

# List active servers
curl http://localhost:8811/servers

# Get available tools
curl http://localhost:8811/tools

Connecting Claude Desktop to the gateway:

{
  "mcpServers": {
    "kubernetes-gateway": {
      "url": "http://localhost:8811/sse",
      "transport": "sse"
    }
  }
}

Production Deployment Patterns {#production-deployment}

Pattern 1: Kubernetes Deployment with StatefulSet

For production environments, deploy the MCP server as a Kubernetes workload:

kubernetes-mcp-server-deployment.yaml:

apiVersion: v1
kind: Namespace
metadata:
  name: mcp-system

---
# Service Account with limited permissions
apiVersion: v1
kind: ServiceAccount
metadata:
  name: kubernetes-mcp-server
  namespace: mcp-system

---
# ClusterRole defining allowed operations
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: kubernetes-mcp-reader
rules:
  # Read-only access to common resources
  - apiGroups: [""]
    resources: 
      - pods
      - pods/log
      - pods/status
      - services
      - endpoints
      - configmaps
      - namespaces
      - nodes
      - events
    verbs: ["get", "list", "watch"]
  
  - apiGroups: ["apps"]
    resources:
      - deployments
      - replicasets
      - statefulsets
      - daemonsets
    verbs: ["get", "list", "watch"]
  
  - apiGroups: ["batch"]
    resources:
      - jobs
      - cronjobs
    verbs: ["get", "list", "watch"]
  
  - apiGroups: ["networking.k8s.io"]
    resources:
      - ingresses
      - networkpolicies
    verbs: ["get", "list", "watch"]

---
# Bind the role to the service account
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: kubernetes-mcp-reader-binding
subjects:
  - kind: ServiceAccount
    name: kubernetes-mcp-server
    namespace: mcp-system
roleRef:
  kind: ClusterRole
  name: kubernetes-mcp-reader
  apiGroup: rbac.authorization.k8s.io

---
# ConfigMap for server configuration
apiVersion: v1
kind: ConfigMap
metadata:
  name: mcp-server-config
  namespace: mcp-system
data:
  config.yaml: |
    server:
      port: 8811
      transport: sse
      read_only: true
    
    kubernetes:
      in_cluster: true  # Use in-cluster config
      namespaces:
        - default
        - production
        - staging
    
    logging:
      level: info
      format: json
    
    security:
      rate_limit:
        enabled: true
        requests_per_minute: 30

---
# StatefulSet for consistent identity
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: kubernetes-mcp-server
  namespace: mcp-system
spec:
  serviceName: kubernetes-mcp-server
  replicas: 2  # High availability
  selector:
    matchLabels:
      app: kubernetes-mcp-server
  
  template:
    metadata:
      labels:
        app: kubernetes-mcp-server
    spec:
      serviceAccountName: kubernetes-mcp-server
      
      # Security context
      securityContext:
        runAsNonRoot: true
        runAsUser: 1000
        fsGroup: 1000
      
      containers:
        - name: mcp-server
          image: ghcr.io/containers/kubernetes-mcp-server:latest
          imagePullPolicy: Always
          
          # Container security
          securityContext:
            allowPrivilegeEscalation: false
            readOnlyRootFilesystem: true
            capabilities:
              drop:
                - ALL
          
          # Server configuration
          args:
            - --config=/config/config.yaml
            - --transport=sse
            - --port=8811
            - --read-only
          
          # Resource limits
          resources:
            requests:
              cpu: 100m
              memory: 128Mi
            limits:
              cpu: 500m
              memory: 512Mi
          
          # Health checks
          livenessProbe:
            httpGet:
              path: /health
              port: 8811
            initialDelaySeconds: 10
            periodSeconds: 30
            timeoutSeconds: 5
            failureThreshold: 3
          
          readinessProbe:
            httpGet:
              path: /ready
              port: 8811
            initialDelaySeconds: 5
            periodSeconds: 10
            timeoutSeconds: 3
            failureThreshold: 3
          
          # Port exposure
          ports:
            - name: sse
              containerPort: 8811
              protocol: TCP
          
          # Volume mounts
          volumeMounts:
            - name: config
              mountPath: /config
              readOnly: true
            - name: tmp
              mountPath: /tmp
      
      # Volumes
      volumes:
        - name: config
          configMap:
            name: mcp-server-config
        - name: tmp
          emptyDir: {}

---
# Headless Service for StatefulSet
apiVersion: v1
kind: Service
metadata:
  name: kubernetes-mcp-server
  namespace: mcp-system
spec:
  clusterIP: None  # Headless service
  selector:
    app: kubernetes-mcp-server
  ports:
    - name: sse
      port: 8811
      targetPort: 8811
      protocol: TCP

---
# LoadBalancer Service for external access
apiVersion: v1
kind: Service
metadata:
  name: kubernetes-mcp-server-lb
  namespace: mcp-system
  annotations:
    # AWS ELB annotations (adjust for your cloud provider)
    service.beta.kubernetes.io/aws-load-balancer-type: "nlb"
    service.beta.kubernetes.io/aws-load-balancer-internal: "true"
spec:
  type: LoadBalancer
  selector:
    app: kubernetes-mcp-server
  ports:
    - name: sse
      port: 443
      targetPort: 8811
      protocol: TCP

---
# NetworkPolicy for security
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: kubernetes-mcp-server-netpol
  namespace: mcp-system
spec:
  podSelector:
    matchLabels:
      app: kubernetes-mcp-server
  
  policyTypes:
    - Ingress
    - Egress
  
  # Ingress rules
  ingress:
    - from:
        # Allow from specific namespaces or IPs
        - namespaceSelector:
            matchLabels:
              name: ai-applications
        - podSelector:
            matchLabels:
              app: ai-gateway
      ports:
        - protocol: TCP
          port: 8811
  
  # Egress rules
  egress:
    # Allow DNS
    - to:
        - namespaceSelector:
            matchLabels:
              name: kube-system
        - podSelector:
            matchLabels:
              k8s-app: kube-dns
      ports:
        - protocol: UDP
          port: 53
    
    # Allow Kubernetes API
    - to:
        - namespaceSelector:
            matchLabels:
              name: default
      ports:
        - protocol: TCP
          port: 443

Deploy to Kubernetes:

# Apply the configuration
kubectl apply -f kubernetes-mcp-server-deployment.yaml

# Verify deployment
kubectl get all -n mcp-system

# Check logs
kubectl logs -n mcp-system -l app=kubernetes-mcp-server -f

# Get service endpoint
kubectl get svc -n mcp-system kubernetes-mcp-server-lb

# Test connection
ENDPOINT=$(kubectl get svc -n mcp-system kubernetes-mcp-server-lb -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')
curl -v https://${ENDPOINT}/health

Pattern 2: Multi-Region Deployment with Ingress

ingress-configuration.yaml:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: kubernetes-mcp-server-ingress
  namespace: mcp-system
  annotations:
    # NGINX Ingress annotations
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
    
    # Rate limiting
    nginx.ingress.kubernetes.io/limit-rps: "30"
    
    # Authentication (using OAuth2 proxy)
    nginx.ingress.kubernetes.io/auth-url: "https://oauth2-proxy.example.com/oauth2/auth"
    nginx.ingress.kubernetes.io/auth-signin: "https://oauth2-proxy.example.com/oauth2/start"
    
    # TLS configuration
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
    
spec:
  ingressClassName: nginx
  
  tls:
    - hosts:
        - mcp-k8s.example.com
      secretName: mcp-k8s-tls
  
  rules:
    - host: mcp-k8s.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: kubernetes-mcp-server
                port:
                  number: 8811

Pattern 3: Using Helm Chart

Chart.yaml:

apiVersion: v2
name: kubernetes-mcp-server
description: A Helm chart for Kubernetes MCP Server
type: application
version: 1.0.0
appVersion: "1.0.0"
keywords:
  - mcp
  - kubernetes
  - ai
  - llm
maintainers:
  - name: Your Name
    email: your.email@example.com

values.yaml:

# Default values for kubernetes-mcp-server

replicaCount: 2

image:
  repository: ghcr.io/containers/kubernetes-mcp-server
  pullPolicy: Always
  tag: "latest"

serviceAccount:
  create: true
  name: "kubernetes-mcp-server"

rbac:
  create: true
  readOnly: true

service:
  type: LoadBalancer
  port: 8811
  annotations: {}

ingress:
  enabled: true
  className: "nginx"
  annotations:
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
  hosts:
    - host: mcp-k8s.example.com
      paths:
        - path: /
          pathType: Prefix
  tls:
    - secretName: mcp-k8s-tls
      hosts:
        - mcp-k8s.example.com

resources:
  limits:
    cpu: 500m
    memory: 512Mi
  requests:
    cpu: 100m
    memory: 128Mi

autoscaling:
  enabled: true
  minReplicas: 2
  maxReplicas: 10
  targetCPUUtilizationPercentage: 80
  targetMemoryUtilizationPercentage: 80

nodeSelector: {}

tolerations: []

affinity:
  podAntiAffinity:
    preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        podAffinityTerm:
          labelSelector:
            matchExpressions:
              - key: app.kubernetes.io/name
                operator: In
                values:
                  - kubernetes-mcp-server
          topologyKey: kubernetes.io/hostname

config:
  readOnly: true
  transport: "sse"
  port: 8811
  logging:
    level: "info"
    format: "json"
  security:
    rateLimit:
      enabled: true
      requestsPerMinute: 30

monitoring:
  enabled: true
  serviceMonitor:
    enabled: true
    interval: 30s

Install with Helm:

# Add your Helm repository
helm repo add mcp-servers https://charts.example.com/mcp-servers
helm repo update

# Install the chart
helm install kubernetes-mcp-server mcp-servers/kubernetes-mcp-server \
  --namespace mcp-system \
  --create-namespace \
  --values custom-values.yaml

# Upgrade
helm upgrade kubernetes-mcp-server mcp-servers/kubernetes-mcp-server \
  --namespace mcp-system \
  --values custom-values.yaml

# Uninstall
helm uninstall kubernetes-mcp-server --namespace mcp-system

Security Best Practices {#security}

1. Principle of Least Privilege

Always create dedicated service accounts with minimal required permissions:

# Example: Read-only service account for dev environment
apiVersion: v1
kind: ServiceAccount
metadata:
  name: mcp-dev-reader
  namespace: development

---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: dev-reader
  namespace: development
rules:
  - apiGroups: [""]
    resources: ["pods", "pods/log"]
    verbs: ["get", "list"]
  - apiGroups: ["apps"]
    resources: ["deployments"]
    verbs: ["get", "list"]

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: mcp-dev-reader-binding
  namespace: development
subjects:
  - kind: ServiceAccount
    name: mcp-dev-reader
    namespace: development
roleRef:
  kind: Role
  name: dev-reader
  apiGroup: rbac.authorization.k8s.io

2. Network Segmentation

Implement strict network policies:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: mcp-server-strict-policy
  namespace: mcp-system
spec:
  podSelector:
    matchLabels:
      app: kubernetes-mcp-server
  policyTypes:
    - Ingress
    - Egress
  
  ingress:
    # Only allow from authenticated clients
    - from:
        - namespaceSelector:
            matchLabels:
              authorized: "true"
        - podSelector:
            matchLabels:
              role: ai-client
      ports:
        - protocol: TCP
          port: 8811
  
  egress:
    # Only allow to Kubernetes API and DNS
    - to:
        - namespaceSelector:
            matchLabels:
              name: kube-system
      ports:
        - protocol: TCP
          port: 443
        - protocol: UDP
          port: 53

3. Secrets Management

Never expose kubeconfig files directly. Use Kubernetes secrets:

# Create secret from kubeconfig
kubectl create secret generic mcp-kubeconfig \
  --from-file=config=/path/to/restricted-kubeconfig \
  --namespace=mcp-system

# Mount as volume in deployment
volumes:
  - name: kubeconfig
    secret:
      secretName: mcp-kubeconfig
      defaultMode: 0400  # Read-only for owner

volumeMounts:
  - name: kubeconfig
    mountPath: /config
    readOnly: true

4. Audit Logging

Enable comprehensive audit logging:

# ConfigMap for audit policy
apiVersion: v1
kind: ConfigMap
metadata:
  name: mcp-audit-policy
  namespace: mcp-system
data:
  policy.yaml: |
    apiVersion: audit.k8s.io/v1
    kind: Policy
    rules:
      # Log all requests at RequestResponse level
      - level: RequestResponse
        verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
        resources:
          - group: ""
            resources: ["pods", "services", "configmaps"]
          - group: "apps"
            resources: ["deployments", "statefulsets"]

5. Token Expiration

Use short-lived tokens:

# Generate token with 24-hour expiration
TOKEN=$(kubectl create token mcp-reader --duration=24h -n default)

# Use in kubeconfig
kubectl config set-credentials mcp-reader \
  --token="${TOKEN}"

# Automated token rotation script
#!/bin/bash
while true; do
  NEW_TOKEN=$(kubectl create token mcp-reader --duration=24h -n default)
  kubectl config set-credentials mcp-reader --token="${NEW_TOKEN}"
  sleep 86400  # Rotate daily
done

6. TLS Encryption

Always use TLS for external connections:

# Certificate request
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: mcp-server-tls
  namespace: mcp-system
spec:
  secretName: mcp-server-tls
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer
  dnsNames:
    - mcp-k8s.example.com
  privateKey:
    algorithm: RSA
    size: 4096

Real-World Use Cases {#use-cases}

Use Case 1: Automated Incident Response

Scenario: On-call engineer gets paged about a service outage.

Traditional Workflow:

# 1. SSH to bastion
ssh bastion.example.com

# 2. Set context
kubectl config use-context production

# 3. Identify failing pods
kubectl get pods -n frontend | grep -v Running

# 4. Check specific pod
kubectl describe pod frontend-7d8f9c-xk2lm -n frontend

# 5. Get logs
kubectl logs frontend-7d8f9c-xk2lm -n frontend --tail=100

# 6. Check events
kubectl get events -n frontend --sort-by='.lastTimestamp'

# 7. Investigate deployment
kubectl describe deployment frontend -n frontend

# 8. Check resource usage
kubectl top pods -n frontend

# ~15-20 minutes of investigation

With Kubernetes MCP Server (Using Claude):

Engineer: "What's wrong with the frontend service in production?"

Claude: [Uses MCP tools automatically]
  - Checks pod status in frontend namespace
  - Identifies 3 pods in CrashLoopBackOff
  - Retrieves logs showing "Connection refused on port 5432"
  - Checks deployment configuration
  - Discovers database service is unavailable

Claude: "The frontend service is failing because the PostgreSQL database
is unavailable. Three pods are in CrashLoopBackOff attempting to connect
to postgres:5432. The postgres service exists but has no healthy endpoints.
Would you like me to investigate the database deployment?"

Engineer: "Yes, check the database"

Claude: [Investigates database]
  - Lists postgres pods (all in Pending state)
  - Checks events (FailedScheduling: Insufficient memory)
  - Analyzes node resources

Claude: "The postgres pods can't be scheduled due to insufficient memory
on available nodes. All nodes are at >95% memory utilization. I recommend:
1. Scale down non-critical services temporarily
2. Add more nodes to the cluster
3. Or increase memory limits on existing nodes"

# Total time: 2-3 minutes

Use Case 2: Developer Onboarding

Scenario: New developer needs to understand the microservices architecture.

Query:

Developer: "Show me all services in the production namespace and explain 
what each one does"

Claude: [Uses Kubernetes MCP Server]
  - Lists all services with their endpoints
  - Retrieves deployment annotations
  - Checks pod labels and descriptions
  - Analyzes ingress rules

Claude: "Here's an overview of the 12 services in production:

1. api-gateway (3 replicas)
   - Entry point for all API requests
   - Routes to backend services based on path
   - Exposed via ingress at api.example.com

2. auth-service (2 replicas)
   - Handles user authentication and JWT tokens
   - Internal service, not publicly exposed
   - Connected to: user-database

3. user-service (5 replicas)
   - User profile management and CRUD operations
   - REST API on port 8080
   - Dependencies: user-database, cache-redis

[... continues for all services ...]

Would you like me to explain the request flow for a specific operation?"

Use Case 3: Capacity Planning

Query:

SRE: "Analyze resource usage across all namespaces and identify 
opportunities for optimization"

Claude: [Comprehensive analysis]
  - Lists all pods with resource requests/limits
  - Retrieves actual usage via metrics
  - Identifies over-provisioned resources
  - Calculates potential savings

Claude: "Resource Optimization Report:

OVER-PROVISIONED RESOURCES:
1. analytics-worker (staging): 
   - Requested: 4 CPU, 8Gi memory
   - Actual usage: 0.5 CPU (12.5%), 1.2Gi memory (15%)
   - Recommendation: Reduce to 1 CPU, 2Gi memory
   - Savings: 3 CPU, 6Gi memory

2. background-processor (production):
   - Requested: 2 CPU, 4Gi memory
   - Actual usage: 0.3 CPU (15%), 800Mi memory (20%)
   - Recommendation: Reduce to 0.5 CPU, 1Gi memory
   - Savings: 1.5 CPU, 3Gi memory

[... detailed analysis ...]

Total potential savings: 15 CPU, 30Gi memory across all namespaces
Estimated cost reduction: $450/month

Would you like me to generate the YAML for these optimizations?"

Use Case 4: Security Audit

Query:

Security Team: "Find all pods running as root or with privileged mode enabled"

Claude: [Security scan]
  - Inspects all pod security contexts
  - Checks for privileged containers
  - Identifies root users
  - Reviews capabilities

Claude: "Security Audit Results:

⚠️ CRITICAL ISSUES:
1. monitoring-agent (kube-system): Running as root with privileged mode
   - Risk: Full host access, potential for container escape
   - Recommendation: Use non-root user with specific capabilities

2. legacy-app (production): Running as UID 0
   - Risk: Unnecessary root privileges
   - Recommendation: Set securityContext.runAsUser: 1000

⚠️ WARNINGS:
3. database-backup (production): CAP_SYS_ADMIN capability
   - Risk: Elevated privileges, potential for abuse
   - Recommendation: Use more specific capabilities if needed

[... complete audit results ...]

Total: 3 critical issues, 7 warnings across 120 pods
Would you like me to generate secure configurations?"

Troubleshooting Guide {#troubleshooting}

Issue 1: “Cannot connect to Kubernetes cluster”

Symptoms:

Error: Failed to connect to Kubernetes API
Could not load kubeconfig

Diagnosis:

# Check kubeconfig exists and is valid
cat ~/.kube/config

# Test connection
kubectl cluster-info

# Verify contexts
kubectl config get-contexts

# Check current context
kubectl config current-context

Solutions:

  1. Kubeconfig not found: # Set KUBECONFIG environment variable export KUBECONFIG=/path/to/your/kubeconfig # Or in Claude Desktop config { "env": { "KUBECONFIG": "/home/user/.kube/config" } }
  2. Invalid context: # Switch to correct context kubectl config use-context correct-cluster-name
  3. Expired credentials: # Refresh credentials (for cloud providers) # AWS EKS aws eks update-kubeconfig --name cluster-name --region us-west-2 # GKE gcloud container clusters get-credentials cluster-name --zone us-central1-a # AKS az aks get-credentials --resource-group rg-name --name cluster-name

Issue 2: “Permission denied” errors

Symptoms:

Error: pods is forbidden: User "system:serviceaccount:default:mcp-reader" 
cannot list resource "pods" in API group "" in the namespace "production"

Diagnosis:

# Check what you can do
kubectl auth can-i list pods -n production
kubectl auth can-i --list

# Describe service account
kubectl describe serviceaccount mcp-reader -n default

# Check role bindings
kubectl get rolebindings,clusterrolebindings --all-namespaces | grep mcp-reader

Solutions:

  1. Grant required permissions: # Apply the RBAC configuration from earlier examples kubectl apply -f k8s-mcp-rbac.yaml
  2. Use admin credentials temporarily (not recommended for production): # Copy admin kubeconfig cp ~/.kube/config ~/.kube/mcp-admin-config # Update Claude Desktop to use it { "env": { "KUBECONFIG": "/home/user/.kube/mcp-admin-config" } }

Issue 3: MCP Server not appearing in Claude Desktop

Symptoms:

  • No πŸ”Œ icon visible
  • Server doesn’t show up in available tools

Diagnosis:

# Check Claude Desktop logs
# macOS
tail -f ~/Library/Logs/Claude/mcp*.log

# Windows
type %APPDATA%\Claude\logs\mcp*.log

# Manually test the server
npx -y kubernetes-mcp-server@latest
# Should output: "Kubernetes MCP Server running on stdio"

Solutions:

  1. Check configuration syntax: // Valid configuration { "mcpServers": { "kubernetes": { "command": "npx", "args": ["-y", "kubernetes-mcp-server@latest"] } } } // Common mistakes: // ❌ Missing comma // ❌ Trailing comma after last item // ❌ Incorrect quotes (use double quotes, not single) // ❌ Wrong path separators on Windows (use \\ or /)
  2. Restart Claude Desktop: # macOS killall Claude && open -a Claude # Windows taskkill /F /IM Claude.exe && start Claude
  3. Clear cache: # macOS rm -rf ~/Library/Application\ Support/Claude/mcp_cache # Windows rmdir /s %APPDATA%\Claude\mcp_cache

Issue 4: Slow response times

Symptoms:

  • Tools take >30 seconds to respond
  • Timeouts on large queries

Diagnosis:

# Check network latency to cluster
kubectl cluster-info | grep "Kubernetes control plane"
time kubectl get nodes

# Monitor MCP server resource usage
docker stats kubernetes-mcp-server  # If running in Docker

# Check Kubernetes API server load
kubectl top nodes
kubectl top pods -n kube-system

Solutions:

  1. Optimize queries: # Instead of: "List all pods in all namespaces with full details" # Use: "List pods in the frontend namespace" "Show me pods in CrashLoopBackOff state"
  2. Use caching (if supported): { "env": { "MCP_CACHE_ENABLED": "true", "MCP_CACHE_TTL": "300" } }
  3. Limit result size: # Most servers support limiting --max-results=50 --tail-lines=100

Performance Optimization {#performance}

Benchmarking Different Implementations

Test Setup:

# Test cluster: 3 nodes, 50 namespaces, 500 pods
# Query: "List all pods across all namespaces"

# Method 1: kubectl wrapper (baseline)
time kubectl get pods --all-namespaces

# Method 2: Native Go MCP server
time kubernetes-mcp-server list_pods --namespace=all

# Method 3: Node.js MCP server  
time npx mcp-server-kubernetes list_pods --namespace=all

Results:

ImplementationExecution TimeMemory UsageCPU Usage
kubectl wrapper2.8s45MB15%
Native Go (containers/kubernetes-mcp-server)0.9s12MB8%
Node.js (Flux159)1.7s85MB22%
Python (mcp-kubernetes-server)2.1s105MB18%

Conclusion: Native Go implementation (containers/kubernetes-mcp-server) offers the best performance.

Optimization Techniques

1. Connection Pooling:

// Reuse Kubernetes client connections
var (
    kubeConfig *rest.Config
    clientset  *kubernetes.Clientset
)

func init() {
    // Initialize once, reuse forever
    kubeConfig, _ = rest.InClusterConfig()
    clientset, _ = kubernetes.NewForConfig(kubeConfig)
}

2. Request Batching:

// Instead of multiple sequential requests
const pods = await getPods(namespace);
const deployments = await getDeployments(namespace);
const services = await getServices(namespace);

// Use Promise.all for parallel requests
const [pods, deployments, services] = await Promise.all([
  getPods(namespace),
  getDeployments(namespace),
  getServices(namespace)
]);

3. Selective Field Retrieval:

// Don't fetch unnecessary data
listOptions := metav1.ListOptions{
    FieldSelector: "status.phase=Running",
    LabelSelector: "app=frontend",
    Limit:         100,  // Pagination
}

pods, err := clientset.CoreV1().Pods(namespace).List(ctx, listOptions)

4. Caching Strategy:

# Redis-based caching
cache:
  enabled: true
  backend: redis
  redis:
    host: redis:6379
    ttl: 300  # 5 minutes
  
  # Cache keys
  keys:
    pod_list: "k8s:pods:{namespace}:list"
    pod_detail: "k8s:pods:{namespace}:{name}"
  
  # Invalidation
  invalidate_on:
    - pod.created
    - pod.deleted
    - pod.updated

Future Trends and Roadmap {#future}

Emerging Patterns

1. Multi-Model Integration:

  • Combining multiple AI models (GPT-4, Claude, Gemini) for different tasks
  • Model routing based on query complexity
  • Cost optimization through intelligent model selection

2. Proactive Monitoring:

  • AI agents continuously monitoring cluster health
  • Automatic issue detection and remediation
  • Predictive scaling based on historical patterns

3. Natural Language Infrastructure as Code:

Developer: "Create a production-ready deployment for a Node.js app 
with Redis caching, PostgreSQL database, and autoscaling from 3 to 10 replicas"

AI: [Generates complete YAML manifests]
- Deployment with resource limits
- HorizontalPodAutoscaler
- Services for each component
- PersistentVolumeClaims
- NetworkPolicies
- Ingress rules

Upcoming Features

1. GitOps Integration:

  • Direct integration with ArgoCD and Flux
  • AI-assisted PR reviews for Kubernetes manifests
  • Automated rollback suggestions

2. Cost Optimization:

  • Real-time cost analysis
  • Spot instance recommendations
  • Resource rightsizing automation

3. Security Scanning:

  • Vulnerability detection in running containers
  • Compliance checking (PCI-DSS, HIPAA, SOC2)
  • Automated security policy enforcement

4. Multi-Cloud Support:

  • Unified interface across AWS EKS, Azure AKS, Google GKE
  • Cross-cloud migration planning
  • Hybrid cloud orchestration

Conclusion

Kubernetes MCP servers represent a significant leap forward in how we interact with container orchestration platforms. By enabling natural language queries, automated troubleshooting, and AI-assisted operations, they’re democratizing Kubernetes access and making DevOps workflows more efficient.

Key Takeaways:

  1. Choose the right implementation for your needs:
    • containers/kubernetes-mcp-server for production (best performance)
    • Flux159/mcp-server-kubernetes for feature-rich development
    • Cloud-specific servers (AWS EKS, Azure AKS) for managed services
  2. Security is paramount:
    • Always use dedicated service accounts
    • Implement RBAC with least privilege
    • Enable audit logging
    • Use short-lived tokens
  3. Start small, scale gradually:
    • Begin with read-only access
    • Test in development environments
    • Implement monitoring and observability
    • Gradually expand to production
  4. Production readiness checklist:
    • [ ] RBAC configured with minimal permissions
    • [ ] Network policies implemented
    • [ ] Audit logging enabled
    • [ ] High availability setup (multiple replicas)
    • [ ] TLS encryption for external access
    • [ ] Rate limiting configured
    • [ ] Monitoring and alerting in place
    • [ ] Disaster recovery plan documented

Getting Started Today

  1. Install Claude Desktop
  2. Add Kubernetes MCP server to configuration
  3. Test with simple queries like “List all pods”
  4. Gradually explore advanced features
  5. Share your experience with the community

Resources

  • Official Documentation: https://modelcontextprotocol.io
  • containers/kubernetes-mcp-server: https://github.com/containers/kubernetes-mcp-server
  • Docker MCP Gateway: https://docs.docker.com/ai/mcp-catalog-and-toolkit/
  • MCP Catalog: Browse 200+ available servers
  • Community Discord: Join the MCP developer community

About the Author: This guide was written to help developers, DevOps engineers, and SREs leverage AI-powered Kubernetes management through MCP servers. For updates and more tutorials, visit [your blog URL].

Last Updated: December 2025

Tags: #Kubernetes #MCP #ModelContextProtocol #AI #DevOps #CloudNative #Docker #ClaudeAI #LLM #InfrastructureAsCode


Did you find this guide helpful? Share it with your team and contribute to the MCP ecosystem by building your own servers!

Questions or feedback? Open an issue on GitHub or reach out on social media.

Leave a Reply

Your email address will not be published. Required fields are marked *