mcp-server-kubernetes 2.1.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -11,12 +11,13 @@
11
11
  [![Last Commit](https://img.shields.io/github/last-commit/Flux159/mcp-server-kubernetes)](https://github.com/Flux159/mcp-server-kubernetes/commits/main)
12
12
  [![smithery badge](https://smithery.ai/badge/mcp-server-kubernetes)](https://smithery.ai/protocol/mcp-server-kubernetes)
13
13
 
14
- MCP Server that can connect to a Kubernetes cluster and manage it.
14
+ MCP Server that can connect to a Kubernetes cluster and manage it. Supports loading kubeconfig from multiple sources in priority order.
15
15
 
16
16
  https://github.com/user-attachments/assets/f25f8f4e-4d04-479b-9ae0-5dac452dd2ed
17
17
 
18
18
  <a href="https://glama.ai/mcp/servers/w71ieamqrt"><img width="380" height="200" src="https://glama.ai/mcp/servers/w71ieamqrt/badge" /></a>
19
19
 
20
+
20
21
  ## Usage with Claude Desktop
21
22
 
22
23
  ```json
@@ -30,6 +31,8 @@ https://github.com/user-attachments/assets/f25f8f4e-4d04-479b-9ae0-5dac452dd2ed
30
31
  }
31
32
  ```
32
33
 
34
+ By default, the server loads kubeconfig from `~/.kube/config`. For additional authentication options (environment variables, custom paths, etc.), see [ADVANCED_README.md](ADVANCED_README.md).
35
+
33
36
  The server will automatically connect to your current kubectl context. Make sure you have:
34
37
 
35
38
  1. kubectl installed and in your PATH
@@ -175,6 +178,25 @@ For Claude Desktop configuration with non-destructive mode:
175
178
  }
176
179
  ```
177
180
 
181
+ ### Commands Available in Non-Destructive Mode
182
+
183
+ All read-only and resource creation/update operations remain available:
184
+
185
+ - Resource Information: `kubectl_get`, `kubectl_describe`, `kubectl_list`, `kubectl_logs`, `explain_resource`, `list_api_resources`
186
+ - Resource Creation/Modification: `kubectl_apply`, `kubectl_create`, `kubectl_scale`, `kubectl_patch`, `kubectl_rollout`
187
+ - Helm Operations: `install_helm_chart`, `upgrade_helm_chart`
188
+ - Connectivity: `port_forward`, `stop_port_forward`
189
+ - Context Management: `kubectl_context`
190
+
191
+ ### Commands Disabled in Non-Destructive Mode
192
+
193
+ The following destructive operations are disabled:
194
+
195
+ - `kubectl_delete`: Deleting any Kubernetes resources
196
+ - `uninstall_helm_chart`: Uninstalling Helm charts
197
+ - `cleanup`: Cleanup of managed resources
198
+ - `kubectl_generic`: General kubectl command access (may include destructive operations)
199
+
178
200
  For additional advanced features, see the [ADVANCED_README.md](ADVANCED_README.md).
179
201
 
180
202
  ## Architecture
@@ -190,19 +212,34 @@ The sequence diagram below illustrates how requests flow through the system:
190
212
  ```mermaid
191
213
  sequenceDiagram
192
214
  participant Client
193
- participant Transport as StdioTransport
215
+ participant Transport as Transport Layer
194
216
  participant Server as MCP Server
217
+ participant Filter as Tool Filter
195
218
  participant Handler as Request Handler
196
219
  participant K8sManager as KubernetesManager
197
220
  participant K8s as Kubernetes API
198
221
 
199
- Client->>Transport: Send Request via STDIO
222
+ Note over Transport: StdioTransport or<br>SSE Transport
223
+
224
+ Client->>Transport: Send Request
200
225
  Transport->>Server: Forward Request
201
226
 
202
227
  alt Tools Request
203
- Server->>Handler: Route to tools handler
204
- Handler->>K8sManager: Execute kubectl operation
205
- K8sManager->>K8s: Make API call
228
+ Server->>Filter: Filter available tools
229
+ Note over Filter: Remove destructive tools<br>if in non-destructive mode
230
+ Filter->>Handler: Route to tools handler
231
+
232
+ alt kubectl operations
233
+ Handler->>K8sManager: Execute kubectl operation
234
+ K8sManager->>K8s: Make API call
235
+ else Helm operations
236
+ Handler->>K8sManager: Execute Helm operation
237
+ K8sManager->>K8s: Make API call
238
+ else Port Forward operations
239
+ Handler->>K8sManager: Set up port forwarding
240
+ K8sManager->>K8s: Make API call
241
+ end
242
+
206
243
  K8s-->>K8sManager: Return result
207
244
  K8sManager-->>Handler: Process response
208
245
  Handler-->>Server: Return tool result
@@ -219,6 +256,8 @@ sequenceDiagram
219
256
  Transport-->>Client: Return Final Response
220
257
  ```
221
258
 
259
+ See this [DeepWiki link](https://deepwiki.com/Flux159/mcp-server-kubernetes) for a more indepth architecture overview created by Devin.
260
+
222
261
  ## Publishing new release
223
262
 
224
263
  Go to the [releases page](https://github.com/Flux159/mcp-server-kubernetes/releases), click on "Draft New Release", click "Choose a tag" and create a new tag by typing out a new version number using "v{major}.{minor}.{patch}" semver format. Then, write a release title "Release v{major}.{minor}.{patch}" and description / changelog if necessary and click "Publish Release".
@@ -227,4 +266,4 @@ This will create a new tag which will trigger a new release build via the cd.yml
227
266
 
228
267
  ## Not planned
229
268
 
230
- Authentication / adding clusters to kubectx.
269
+ Adding clusters to kubectx.
package/dist/index.js CHANGED
@@ -29,6 +29,7 @@ const destructiveTools = [
29
29
  kubectlDeleteSchema, // This replaces all individual delete operations
30
30
  uninstallHelmChartSchema,
31
31
  cleanupSchema, // Cleanup is also destructive as it deletes resources
32
+ kubectlGenericSchema, // Generic kubectl command can perform destructive operations
32
33
  ];
33
34
  // Get all available tools
34
35
  const allTools = [
@@ -181,7 +182,7 @@ if (process.env.ENABLE_UNSAFE_SSE_TRANSPORT) {
181
182
  }
182
183
  else {
183
184
  const transport = new StdioServerTransport();
184
- console.log(`Starting Kubernetes MCP server v${serverConfig.version}, handling commands...`);
185
+ console.error(`Starting Kubernetes MCP server v${serverConfig.version}, handling commands...`);
185
186
  server.connect(transport);
186
187
  }
187
188
  ["SIGINT", "SIGTERM"].forEach((signal) => {
@@ -97,7 +97,7 @@ export async function kubectlGeneric(k8sManager, input) {
97
97
  // Execute the command (join all args except the first "kubectl" which is used in execSync)
98
98
  const command = cmdArgs.slice(1).join(' ');
99
99
  try {
100
- console.log(`Executing: kubectl ${command}`);
100
+ console.error(`Executing: kubectl ${command}`);
101
101
  const result = execSync(`kubectl ${command}`, { encoding: "utf8" });
102
102
  return {
103
103
  content: [
@@ -13,6 +13,38 @@ export declare class KubernetesManager {
13
13
  * A very simple test to check if the application is running inside a Kubernetes cluster
14
14
  */
15
15
  private isRunningInCluster;
16
+ /**
17
+ * Check if KUBECONFIG_YAML environment variable is available
18
+ */
19
+ private hasEnvKubeconfigYaml;
20
+ /**
21
+ * Check if KUBECONFIG_JSON environment variable is available
22
+ */
23
+ private hasEnvKubeconfigJson;
24
+ /**
25
+ * Check if minimal K8S_SERVER and K8S_TOKEN environment variables are available
26
+ */
27
+ private hasEnvMinimalKubeconfig;
28
+ /**
29
+ * Load kubeconfig from KUBECONFIG_PATH environment variable (file path)
30
+ */
31
+ private loadEnvKubeconfigPath;
32
+ /**
33
+ * Load kubeconfig from KUBECONFIG_YAML environment variable (YAML format)
34
+ */
35
+ private loadEnvKubeconfigYaml;
36
+ /**
37
+ * Load kubeconfig from KUBECONFIG_JSON environment variable (JSON format)
38
+ */
39
+ private loadEnvKubeconfigJson;
40
+ /**
41
+ * Load kubeconfig from minimal K8S_SERVER and K8S_TOKEN environment variables
42
+ */
43
+ private loadEnvMinimalKubeconfig;
44
+ /**
45
+ * Check if KUBECONFIG_PATH environment variable is available
46
+ */
47
+ private hasEnvKubeconfigPath;
16
48
  /**
17
49
  * Set the current context to the desired context name.
18
50
  *
@@ -30,4 +62,9 @@ export declare class KubernetesManager {
30
62
  getCoreApi(): k8s.CoreV1Api;
31
63
  getAppsApi(): k8s.AppsV1Api;
32
64
  getBatchApi(): k8s.BatchV1Api;
65
+ /**
66
+ * Get the default namespace for operations
67
+ * Uses K8S_NAMESPACE environment variable if set, otherwise defaults to "default"
68
+ */
69
+ getDefaultNamespace(): string;
33
70
  }
@@ -11,11 +11,59 @@ export class KubernetesManager {
11
11
  constructor() {
12
12
  this.kc = new k8s.KubeConfig();
13
13
  if (this.isRunningInCluster()) {
14
+ // Priority 1: In-cluster configuration (existing)
14
15
  this.kc.loadFromCluster();
15
16
  }
17
+ else if (this.hasEnvKubeconfigYaml()) {
18
+ // Priority 2: Full kubeconfig as YAML string
19
+ try {
20
+ this.loadEnvKubeconfigYaml();
21
+ }
22
+ catch (error) {
23
+ throw new Error(`Failed to parse KUBECONFIG_YAML: ${error instanceof Error ? error.message : 'Unknown error'}`);
24
+ }
25
+ }
26
+ else if (this.hasEnvKubeconfigJson()) {
27
+ // Priority 3: Full kubeconfig as JSON string
28
+ try {
29
+ this.loadEnvKubeconfigJson();
30
+ }
31
+ catch (error) {
32
+ throw new Error(`Failed to parse KUBECONFIG_JSON: ${error instanceof Error ? error.message : 'Unknown error'}`);
33
+ }
34
+ }
35
+ else if (this.hasEnvMinimalKubeconfig()) {
36
+ // Priority 4: Minimal config with individual environment variables
37
+ try {
38
+ this.loadEnvMinimalKubeconfig();
39
+ }
40
+ catch (error) {
41
+ throw new Error(`Failed to create kubeconfig from K8S_SERVER and K8S_TOKEN: ${error instanceof Error ? error.message : 'Unknown error'}`);
42
+ }
43
+ }
44
+ else if (this.hasEnvKubeconfigPath()) {
45
+ // Priority 5: Custom kubeconfig file path
46
+ try {
47
+ this.loadEnvKubeconfigPath();
48
+ }
49
+ catch (error) {
50
+ throw new Error(`Failed to load kubeconfig from KUBECONFIG_PATH: ${error instanceof Error ? error.message : 'Unknown error'}`);
51
+ }
52
+ }
16
53
  else {
54
+ // Priority 6: Default file-based configuration (existing fallback)
17
55
  this.kc.loadFromDefault();
18
56
  }
57
+ // Apply context override if specified
58
+ if (process.env.K8S_CONTEXT) {
59
+ try {
60
+ this.setCurrentContext(process.env.K8S_CONTEXT);
61
+ }
62
+ catch (error) {
63
+ console.warn(`Warning: Could not set context to ${process.env.K8S_CONTEXT}: ${error instanceof Error ? error.message : 'Unknown error'}`);
64
+ }
65
+ }
66
+ // Initialize API clients
19
67
  this.k8sApi = this.kc.makeApiClient(k8s.CoreV1Api);
20
68
  this.k8sAppsApi = this.kc.makeApiClient(k8s.AppsV1Api);
21
69
  this.k8sBatchApi = this.kc.makeApiClient(k8s.BatchV1Api);
@@ -32,6 +80,80 @@ export class KubernetesManager {
32
80
  return false;
33
81
  }
34
82
  }
83
+ /**
84
+ * Check if KUBECONFIG_YAML environment variable is available
85
+ */
86
+ hasEnvKubeconfigYaml() {
87
+ return !!(process.env.KUBECONFIG_YAML && process.env.KUBECONFIG_YAML.trim());
88
+ }
89
+ /**
90
+ * Check if KUBECONFIG_JSON environment variable is available
91
+ */
92
+ hasEnvKubeconfigJson() {
93
+ return !!(process.env.KUBECONFIG_JSON && process.env.KUBECONFIG_JSON.trim());
94
+ }
95
+ /**
96
+ * Check if minimal K8S_SERVER and K8S_TOKEN environment variables are available
97
+ */
98
+ hasEnvMinimalKubeconfig() {
99
+ return !!(process.env.K8S_SERVER &&
100
+ process.env.K8S_SERVER.trim() &&
101
+ process.env.K8S_TOKEN &&
102
+ process.env.K8S_TOKEN.trim());
103
+ }
104
+ /**
105
+ * Load kubeconfig from KUBECONFIG_PATH environment variable (file path)
106
+ */
107
+ loadEnvKubeconfigPath() {
108
+ this.kc.loadFromFile(process.env.KUBECONFIG_PATH);
109
+ }
110
+ /**
111
+ * Load kubeconfig from KUBECONFIG_YAML environment variable (YAML format)
112
+ */
113
+ loadEnvKubeconfigYaml() {
114
+ this.kc.loadFromString(process.env.KUBECONFIG_YAML);
115
+ }
116
+ /**
117
+ * Load kubeconfig from KUBECONFIG_JSON environment variable (JSON format)
118
+ */
119
+ loadEnvKubeconfigJson() {
120
+ const configObj = JSON.parse(process.env.KUBECONFIG_JSON);
121
+ this.kc.loadFromOptions(configObj);
122
+ }
123
+ /**
124
+ * Load kubeconfig from minimal K8S_SERVER and K8S_TOKEN environment variables
125
+ */
126
+ loadEnvMinimalKubeconfig() {
127
+ if (!process.env.K8S_SERVER || !process.env.K8S_TOKEN) {
128
+ throw new Error('K8S_SERVER and K8S_TOKEN environment variables are required');
129
+ }
130
+ const cluster = {
131
+ name: 'env-cluster',
132
+ server: process.env.K8S_SERVER,
133
+ skipTLSVerify: process.env.K8S_SKIP_TLS_VERIFY === 'true'
134
+ };
135
+ const user = {
136
+ name: 'env-user',
137
+ token: process.env.K8S_TOKEN
138
+ };
139
+ const context = {
140
+ name: 'env-context',
141
+ user: user.name,
142
+ cluster: cluster.name
143
+ };
144
+ this.kc.loadFromOptions({
145
+ clusters: [cluster],
146
+ users: [user],
147
+ contexts: [context],
148
+ currentContext: context.name
149
+ });
150
+ }
151
+ /**
152
+ * Check if KUBECONFIG_PATH environment variable is available
153
+ */
154
+ hasEnvKubeconfigPath() {
155
+ return !!(process.env.KUBECONFIG_PATH && process.env.KUBECONFIG_PATH.trim());
156
+ }
35
157
  /**
36
158
  * Set the current context to the desired context name.
37
159
  *
@@ -110,4 +232,11 @@ export class KubernetesManager {
110
232
  getBatchApi() {
111
233
  return this.k8sBatchApi;
112
234
  }
235
+ /**
236
+ * Get the default namespace for operations
237
+ * Uses K8S_NAMESPACE environment variable if set, otherwise defaults to "default"
238
+ */
239
+ getDefaultNamespace() {
240
+ return process.env.K8S_NAMESPACE || 'default';
241
+ }
113
242
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcp-server-kubernetes",
3
- "version": "2.1.0",
3
+ "version": "2.2.0",
4
4
  "description": "MCP server for interacting with Kubernetes clusters via kubectl",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -46,6 +46,7 @@
46
46
  "@types/express": "5.0.1",
47
47
  "@types/js-yaml": "4.0.9",
48
48
  "@types/node": "22.9.3",
49
+ "esbuild": "0.21.5",
49
50
  "shx": "0.3.4",
50
51
  "typescript": "5.6.2",
51
52
  "vitest": "2.1.9"