mcp-server-kubernetes 4.2.1 → 4.2.3
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.
|
@@ -25,6 +25,7 @@ export declare const HelmValuesSchema: z.ZodRecord<z.ZodString, z.ZodAny>;
|
|
|
25
25
|
export interface HelmUninstallOperation {
|
|
26
26
|
name: string;
|
|
27
27
|
namespace: string;
|
|
28
|
+
context?: string;
|
|
28
29
|
}
|
|
29
30
|
export interface HelmInstallOperation {
|
|
30
31
|
name: string;
|
|
@@ -35,6 +36,7 @@ export interface HelmInstallOperation {
|
|
|
35
36
|
valuesFile?: string;
|
|
36
37
|
createNamespace?: boolean;
|
|
37
38
|
useTemplate?: boolean;
|
|
39
|
+
context?: string;
|
|
38
40
|
}
|
|
39
41
|
export interface HelmUpgradeOperation {
|
|
40
42
|
name: string;
|
|
@@ -43,6 +45,7 @@ export interface HelmUpgradeOperation {
|
|
|
43
45
|
repo?: string;
|
|
44
46
|
values?: Record<string, any>;
|
|
45
47
|
valuesFile?: string;
|
|
48
|
+
context?: string;
|
|
46
49
|
}
|
|
47
50
|
export type HelmResponse = {
|
|
48
51
|
status: "installed" | "upgraded" | "uninstalled" | "failed";
|
|
@@ -178,7 +178,13 @@ const assertOperandsNotFlagLike = (params) => {
|
|
|
178
178
|
assertNotFlagLike(params.chart, "chart");
|
|
179
179
|
assertNotFlagLike(params.namespace, "namespace");
|
|
180
180
|
assertNotFlagLike(params.repo, "repo");
|
|
181
|
+
assertNotFlagLike(params.context, "context");
|
|
181
182
|
};
|
|
183
|
+
// helm selects the kubeconfig context with --kube-context, kubectl with
|
|
184
|
+
// --context. Without them the command runs against the current context, not
|
|
185
|
+
// the one the caller asked for.
|
|
186
|
+
const helmContextArgs = (context) => context ? ["--kube-context", context] : [];
|
|
187
|
+
const kubectlContextArgs = (context) => context ? ["--context", context] : [];
|
|
182
188
|
/**
|
|
183
189
|
* Install a Helm chart using template mode (helm template + kubectl apply).
|
|
184
190
|
* This mode bypasses authentication issues and kubeconfig API version mismatches.
|
|
@@ -197,7 +203,12 @@ async function installHelmChartTemplate(params) {
|
|
|
197
203
|
// Step 2: Create namespace
|
|
198
204
|
steps.push(`Creating namespace: ${params.namespace}`);
|
|
199
205
|
try {
|
|
200
|
-
executeCommand("kubectl", [
|
|
206
|
+
executeCommand("kubectl", [
|
|
207
|
+
"create",
|
|
208
|
+
"namespace",
|
|
209
|
+
params.namespace,
|
|
210
|
+
...kubectlContextArgs(params.context),
|
|
211
|
+
]);
|
|
201
212
|
}
|
|
202
213
|
catch (error) {
|
|
203
214
|
if (!error.message.includes("already exists")) {
|
|
@@ -213,6 +224,7 @@ async function installHelmChartTemplate(params) {
|
|
|
213
224
|
params.chart,
|
|
214
225
|
"--namespace",
|
|
215
226
|
params.namespace,
|
|
227
|
+
...helmContextArgs(params.context),
|
|
216
228
|
];
|
|
217
229
|
if (params.repo) {
|
|
218
230
|
templateArgs.push("--repo", params.repo);
|
|
@@ -243,7 +255,12 @@ async function installHelmChartTemplate(params) {
|
|
|
243
255
|
steps.push("Applying YAML using kubectl");
|
|
244
256
|
const tempYamlFile = writeTempFile("template.yaml", yamlOutput);
|
|
245
257
|
try {
|
|
246
|
-
executeCommand("kubectl", [
|
|
258
|
+
executeCommand("kubectl", [
|
|
259
|
+
"apply",
|
|
260
|
+
"-f",
|
|
261
|
+
tempYamlFile,
|
|
262
|
+
...kubectlContextArgs(params.context),
|
|
263
|
+
]);
|
|
247
264
|
steps.push("Helm chart installed successfully using template mode");
|
|
248
265
|
}
|
|
249
266
|
finally {
|
|
@@ -303,6 +320,7 @@ export async function installHelmChart(params) {
|
|
|
303
320
|
params.chart,
|
|
304
321
|
"--namespace",
|
|
305
322
|
params.namespace,
|
|
323
|
+
...helmContextArgs(params.context),
|
|
306
324
|
];
|
|
307
325
|
// Add create namespace flag if requested
|
|
308
326
|
if (params.createNamespace !== false) {
|
|
@@ -374,6 +392,7 @@ export async function upgradeHelmChart(params) {
|
|
|
374
392
|
params.chart,
|
|
375
393
|
"--namespace",
|
|
376
394
|
params.namespace,
|
|
395
|
+
...helmContextArgs(params.context),
|
|
377
396
|
];
|
|
378
397
|
// Add values file if provided
|
|
379
398
|
if (params.valuesFile) {
|
|
@@ -433,6 +452,7 @@ export async function uninstallHelmChart(params) {
|
|
|
433
452
|
params.name,
|
|
434
453
|
"--namespace",
|
|
435
454
|
params.namespace,
|
|
455
|
+
...helmContextArgs(params.context),
|
|
436
456
|
]);
|
|
437
457
|
return {
|
|
438
458
|
content: [
|
|
@@ -58,6 +58,12 @@ export declare class KubernetesManager {
|
|
|
58
58
|
*/
|
|
59
59
|
private hasEnvKubeconfigPath;
|
|
60
60
|
private hasEnvKubeconfig;
|
|
61
|
+
/**
|
|
62
|
+
* Load every file listed in KUBECONFIG and merge them the way kubectl does:
|
|
63
|
+
* files that do not exist are skipped, the first file to define a cluster,
|
|
64
|
+
* user or context by name wins, and the first current-context set wins.
|
|
65
|
+
*/
|
|
66
|
+
private loadEnvKubeconfigList;
|
|
61
67
|
/**
|
|
62
68
|
* Set the current context to the desired context name.
|
|
63
69
|
*
|
|
@@ -64,8 +64,9 @@ export class KubernetesManager {
|
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
66
|
else if (this.hasEnvKubeconfig()) {
|
|
67
|
-
//
|
|
68
|
-
|
|
67
|
+
// Priority 6: KUBECONFIG, which can list several files like kubectl
|
|
68
|
+
// accepts
|
|
69
|
+
this.loadEnvKubeconfigList();
|
|
69
70
|
}
|
|
70
71
|
else {
|
|
71
72
|
// Priority 7: Default file-based configuration (existing fallback)
|
|
@@ -218,6 +219,44 @@ export class KubernetesManager {
|
|
|
218
219
|
hasEnvKubeconfig() {
|
|
219
220
|
return !!(process.env.KUBECONFIG && process.env.KUBECONFIG.trim());
|
|
220
221
|
}
|
|
222
|
+
/**
|
|
223
|
+
* Load every file listed in KUBECONFIG and merge them the way kubectl does:
|
|
224
|
+
* files that do not exist are skipped, the first file to define a cluster,
|
|
225
|
+
* user or context by name wins, and the first current-context set wins.
|
|
226
|
+
*/
|
|
227
|
+
loadEnvKubeconfigList() {
|
|
228
|
+
const listed = process.env
|
|
229
|
+
.KUBECONFIG.split(path.delimiter)
|
|
230
|
+
.filter((file) => file.trim());
|
|
231
|
+
const files = listed.filter((file) => fs.existsSync(file));
|
|
232
|
+
if (files.length === 0) {
|
|
233
|
+
throw new Error(`None of the files listed in KUBECONFIG exist: ${listed.join(", ")}`);
|
|
234
|
+
}
|
|
235
|
+
this.kc.loadFromFile(files[0]);
|
|
236
|
+
for (const file of files.slice(1)) {
|
|
237
|
+
const next = new k8s.KubeConfig();
|
|
238
|
+
next.loadFromFile(file);
|
|
239
|
+
const has = (items, name) => items.some((item) => item.name === name);
|
|
240
|
+
for (const cluster of next.getClusters()) {
|
|
241
|
+
if (!has(this.kc.getClusters(), cluster.name)) {
|
|
242
|
+
this.kc.addCluster(cluster);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
for (const user of next.getUsers()) {
|
|
246
|
+
if (!has(this.kc.getUsers(), user.name)) {
|
|
247
|
+
this.kc.addUser(user);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
for (const context of next.getContexts()) {
|
|
251
|
+
if (!has(this.kc.getContexts(), context.name)) {
|
|
252
|
+
this.kc.addContext(context);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
if (!this.kc.getCurrentContext() && next.getCurrentContext()) {
|
|
256
|
+
this.kc.setCurrentContext(next.getCurrentContext());
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
221
260
|
/**
|
|
222
261
|
* Set the current context to the desired context name.
|
|
223
262
|
*
|