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.
|
@@ -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
|
-
|
|
83
|
-
this.
|
|
84
|
-
|
|
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.
|
|
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
|
|
268
|
+
await coreApi.deleteNamespacedPod({ name, namespace });
|
|
230
269
|
break;
|
|
231
270
|
case "deployment":
|
|
232
|
-
await
|
|
271
|
+
await appsApi.deleteNamespacedDeployment({ name, namespace });
|
|
233
272
|
break;
|
|
234
273
|
case "service":
|
|
235
|
-
await
|
|
274
|
+
await coreApi.deleteNamespacedService({ name, namespace });
|
|
236
275
|
break;
|
|
237
276
|
case "cronjob":
|
|
238
|
-
await
|
|
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"
|