mcp-server-kubernetes 4.1.7 → 4.1.8

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.
@@ -1,6 +1,6 @@
1
1
  export declare const serverConfig: {
2
2
  readonly name: "kubernetes";
3
- readonly version: "4.1.7";
3
+ readonly version: "4.1.8";
4
4
  readonly capabilities: {
5
5
  readonly resources: {};
6
6
  readonly tools: {};
@@ -1,6 +1,6 @@
1
1
  export const serverConfig = {
2
2
  name: "kubernetes",
3
- version: "4.1.7",
3
+ version: "4.1.8",
4
4
  capabilities: {
5
5
  resources: {},
6
6
  tools: {},
@@ -8,7 +8,19 @@ export declare class KubernetesManager {
8
8
  private k8sApi;
9
9
  private k8sAppsApi;
10
10
  private k8sBatchApi;
11
+ /** Set when API client construction fails (e.g. no active cluster/context). */
12
+ private clientInitError;
11
13
  constructor();
14
+ /**
15
+ * Attempt to build Kubernetes API clients. On failure, keep the process
16
+ * alive in a degraded state; getters and refresh will surface the error.
17
+ */
18
+ private tryInitApiClients;
19
+ /**
20
+ * Ensure API clients exist, retrying construction if we started degraded.
21
+ * Throws a clear configuration error if the kubeconfig still has no active cluster.
22
+ */
23
+ private ensureApiClients;
12
24
  /**
13
25
  * A very simple test to check if the application is running inside a Kubernetes cluster
14
26
  */
@@ -64,6 +76,11 @@ export declare class KubernetesManager {
64
76
  getCoreApi(): k8s.CoreV1Api;
65
77
  getAppsApi(): k8s.AppsV1Api;
66
78
  getBatchApi(): k8s.BatchV1Api;
79
+ /**
80
+ * True when API clients failed to initialize (e.g. empty current-context).
81
+ */
82
+ hasClientInitError(): boolean;
83
+ getClientInitError(): Error | undefined;
67
84
  /**
68
85
  * Get the default namespace for operations
69
86
  * Uses K8S_NAMESPACE environment variable if set, otherwise defaults to "default"
@@ -10,6 +10,8 @@ export class KubernetesManager {
10
10
  k8sApi;
11
11
  k8sAppsApi;
12
12
  k8sBatchApi;
13
+ /** Set when API client construction fails (e.g. no active cluster/context). */
14
+ clientInitError;
13
15
  constructor() {
14
16
  this.kc = new k8s.KubeConfig();
15
17
  if (this.hasEnvKubeconfigYaml()) {
@@ -78,10 +80,45 @@ export class KubernetesManager {
78
80
  console.warn(`Warning: Could not set context to ${process.env.K8S_CONTEXT}: ${error instanceof Error ? error.message : "Unknown error"}`);
79
81
  }
80
82
  }
81
- // Initialize API clients
82
- this.k8sApi = this.kc.makeApiClient(k8s.CoreV1Api);
83
- this.k8sAppsApi = this.kc.makeApiClient(k8s.AppsV1Api);
84
- this.k8sBatchApi = this.kc.makeApiClient(k8s.BatchV1Api);
83
+ // Initialize API clients in degraded mode on failure so MCP initialize
84
+ // can still succeed when kubeconfig has no usable current-context.
85
+ this.tryInitApiClients();
86
+ }
87
+ /**
88
+ * Attempt to build Kubernetes API clients. On failure, keep the process
89
+ * alive in a degraded state; getters and refresh will surface the error.
90
+ */
91
+ tryInitApiClients() {
92
+ try {
93
+ this.refreshApiClients();
94
+ }
95
+ catch (error) {
96
+ this.clientInitError =
97
+ error instanceof Error ? error : new Error(String(error));
98
+ this.k8sApi = undefined;
99
+ this.k8sAppsApi = undefined;
100
+ this.k8sBatchApi = undefined;
101
+ console.error(`Warning: Kubernetes API clients not initialized: ${this.clientInitError.message}`);
102
+ }
103
+ }
104
+ /**
105
+ * Ensure API clients exist, retrying construction if we started degraded.
106
+ * Throws a clear configuration error if the kubeconfig still has no active cluster.
107
+ */
108
+ ensureApiClients() {
109
+ if (this.k8sApi && this.k8sAppsApi && this.k8sBatchApi) {
110
+ return;
111
+ }
112
+ try {
113
+ this.refreshApiClients();
114
+ }
115
+ catch (error) {
116
+ const message = error instanceof Error
117
+ ? error.message
118
+ : this.clientInitError?.message || String(error);
119
+ throw new Error(`Kubernetes configuration error: ${message}. ` +
120
+ "Set a valid current-context in your kubeconfig (or via K8S_CONTEXT) and restart the server.");
121
+ }
85
122
  }
86
123
  /**
87
124
  * A very simple test to check if the application is running inside a Kubernetes cluster
@@ -190,6 +227,7 @@ export class KubernetesManager {
190
227
  this.k8sApi = this.kc.makeApiClient(k8s.CoreV1Api);
191
228
  this.k8sAppsApi = this.kc.makeApiClient(k8s.AppsV1Api);
192
229
  this.k8sBatchApi = this.kc.makeApiClient(k8s.BatchV1Api);
230
+ this.clientInitError = undefined;
193
231
  }
194
232
  setCurrentContext(contextName) {
195
233
  // Get all available contexts
@@ -199,11 +237,9 @@ export class KubernetesManager {
199
237
  if (!contextNames.includes(contextName)) {
200
238
  throw new Error(`Context '${contextName}' not found. Available contexts: ${contextNames.join(", ")}`);
201
239
  }
202
- // Set the current context
240
+ // Set the current context and rebuild clients (recovers from degraded mode)
203
241
  this.kc.setCurrentContext(contextName);
204
- this.k8sApi = this.kc.makeApiClient(k8s.CoreV1Api);
205
- this.k8sAppsApi = this.kc.makeApiClient(k8s.AppsV1Api);
206
- this.k8sBatchApi = this.kc.makeApiClient(k8s.BatchV1Api);
242
+ this.refreshApiClients();
207
243
  }
208
244
  async cleanup() {
209
245
  // Stop watches
@@ -224,18 +260,21 @@ export class KubernetesManager {
224
260
  this.resources.push({ kind, name, namespace, createdAt: new Date() });
225
261
  }
226
262
  async deleteResource(kind, name, namespace) {
263
+ const coreApi = this.getCoreApi();
264
+ const appsApi = this.getAppsApi();
265
+ const batchApi = this.getBatchApi();
227
266
  switch (kind.toLowerCase()) {
228
267
  case "pod":
229
- await this.k8sApi.deleteNamespacedPod({ name, namespace });
268
+ await coreApi.deleteNamespacedPod({ name, namespace });
230
269
  break;
231
270
  case "deployment":
232
- await this.k8sAppsApi.deleteNamespacedDeployment({ name, namespace });
271
+ await appsApi.deleteNamespacedDeployment({ name, namespace });
233
272
  break;
234
273
  case "service":
235
- await this.k8sApi.deleteNamespacedService({ name, namespace });
274
+ await coreApi.deleteNamespacedService({ name, namespace });
236
275
  break;
237
276
  case "cronjob":
238
- await this.k8sBatchApi.deleteNamespacedCronJob({ name, namespace });
277
+ await batchApi.deleteNamespacedCronJob({ name, namespace });
239
278
  break;
240
279
  }
241
280
  this.resources = this.resources.filter((r) => !(r.kind === kind && r.name === name && r.namespace === namespace));
@@ -256,14 +295,26 @@ export class KubernetesManager {
256
295
  return this.kc;
257
296
  }
258
297
  getCoreApi() {
298
+ this.ensureApiClients();
259
299
  return this.k8sApi;
260
300
  }
261
301
  getAppsApi() {
302
+ this.ensureApiClients();
262
303
  return this.k8sAppsApi;
263
304
  }
264
305
  getBatchApi() {
306
+ this.ensureApiClients();
265
307
  return this.k8sBatchApi;
266
308
  }
309
+ /**
310
+ * True when API clients failed to initialize (e.g. empty current-context).
311
+ */
312
+ hasClientInitError() {
313
+ return !!this.clientInitError || !this.k8sApi;
314
+ }
315
+ getClientInitError() {
316
+ return this.clientInitError;
317
+ }
267
318
  /**
268
319
  * Get the default namespace for operations
269
320
  * Uses K8S_NAMESPACE environment variable if set, otherwise defaults to "default"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcp-server-kubernetes",
3
- "version": "4.1.7",
3
+ "version": "4.1.8",
4
4
  "description": "MCP server for interacting with Kubernetes clusters via kubectl",
5
5
  "license": "MIT",
6
6
  "type": "module",