mcp-server-kubernetes 2.8.0 → 2.9.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.
@@ -1,77 +1,122 @@
1
+ /**
2
+ * Tool: install_helm_chart
3
+ * Install a Helm chart with support for both standard Helm install and template-based installation.
4
+ * Template mode bypasses authentication issues and kubeconfig API version mismatches.
5
+ * Supports local chart paths, remote repositories, and custom values.
6
+ */
1
7
  import { execFileSync } from "child_process";
2
8
  import { writeFileSync, unlinkSync } from "fs";
3
- import yaml from "yaml";
9
+ import { dump } from "js-yaml";
4
10
  import { getSpawnMaxBuffer } from "../config/max-buffer.js";
5
11
  import { contextParameter, namespaceParameter } from "../models/common-parameters.js";
12
+ /**
13
+ * Schema for install_helm_chart tool.
14
+ * - name: Release name
15
+ * - chart: Chart name or path to chart directory
16
+ * - namespace: Target namespace
17
+ * - repo: (Optional) Helm repository URL
18
+ * - values: (Optional) Custom values object
19
+ * - valuesFile: (Optional) Path to values file
20
+ * - useTemplate: (Optional) Use template mode instead of helm install
21
+ * - createNamespace: (Optional) Create namespace if it doesn't exist
22
+ */
6
23
  export const installHelmChartSchema = {
7
24
  name: "install_helm_chart",
8
- description: "Install a Helm chart",
25
+ description: "Install a Helm chart with support for both standard and template-based installation",
9
26
  inputSchema: {
10
27
  type: "object",
11
28
  properties: {
12
29
  name: {
13
30
  type: "string",
14
- description: "Release name",
31
+ description: "Name of the Helm release",
15
32
  },
16
33
  chart: {
17
34
  type: "string",
18
- description: "Chart name",
35
+ description: "Chart name (e.g., 'nginx') or path to chart directory",
19
36
  },
37
+ namespace: namespaceParameter,
38
+ context: contextParameter,
20
39
  repo: {
21
40
  type: "string",
22
- description: "Chart repository URL",
41
+ description: "Helm repository URL (optional if using local chart path)",
23
42
  },
24
- namespace: namespaceParameter,
25
- context: contextParameter,
26
43
  values: {
27
44
  type: "object",
28
- description: "Chart values",
29
- properties: {},
30
- additionalProperties: true,
45
+ description: "Custom values to override chart defaults",
46
+ },
47
+ valuesFile: {
48
+ type: "string",
49
+ description: "Path to values file (alternative to values object)",
50
+ },
51
+ useTemplate: {
52
+ type: "boolean",
53
+ description: "Use helm template + kubectl apply instead of helm install (bypasses auth issues)",
54
+ default: false,
55
+ },
56
+ createNamespace: {
57
+ type: "boolean",
58
+ description: "Create namespace if it doesn't exist",
59
+ default: true,
31
60
  },
32
61
  },
33
- required: ["name", "chart", "repo", "namespace"],
62
+ required: ["name", "chart", "namespace"],
34
63
  },
35
64
  };
65
+ /**
66
+ * Schema for upgrade_helm_chart tool.
67
+ * - name: Release name
68
+ * - chart: Chart name or path
69
+ * - namespace: Target namespace
70
+ * - repo: (Optional) Helm repository URL
71
+ * - values: (Optional) Custom values object
72
+ * - valuesFile: (Optional) Path to values file
73
+ */
36
74
  export const upgradeHelmChartSchema = {
37
75
  name: "upgrade_helm_chart",
38
- description: "Upgrade a Helm release",
76
+ description: "Upgrade an existing Helm chart release",
39
77
  inputSchema: {
40
78
  type: "object",
41
79
  properties: {
42
80
  name: {
43
81
  type: "string",
44
- description: "Release name",
82
+ description: "Name of the Helm release to upgrade",
45
83
  },
46
84
  chart: {
47
85
  type: "string",
48
- description: "Chart name",
86
+ description: "Chart name or path to chart directory",
49
87
  },
88
+ namespace: namespaceParameter,
89
+ context: contextParameter,
50
90
  repo: {
51
91
  type: "string",
52
- description: "Chart repository URL",
92
+ description: "Helm repository URL (optional if using local chart path)",
53
93
  },
54
- namespace: namespaceParameter,
55
- context: contextParameter,
56
94
  values: {
57
95
  type: "object",
58
- description: "Chart values",
59
- properties: {},
60
- additionalProperties: true,
96
+ description: "Custom values to override chart defaults",
97
+ },
98
+ valuesFile: {
99
+ type: "string",
100
+ description: "Path to values file (alternative to values object)",
61
101
  },
62
102
  },
63
- required: ["name", "chart", "repo", "namespace"],
103
+ required: ["name", "chart", "namespace"],
64
104
  },
65
105
  };
106
+ /**
107
+ * Schema for uninstall_helm_chart tool.
108
+ * - name: Release name
109
+ * - namespace: Target namespace
110
+ */
66
111
  export const uninstallHelmChartSchema = {
67
112
  name: "uninstall_helm_chart",
68
- description: "Uninstall a Helm release",
113
+ description: "Uninstall a Helm chart release",
69
114
  inputSchema: {
70
115
  type: "object",
71
116
  properties: {
72
117
  name: {
73
118
  type: "string",
74
- description: "Release name",
119
+ description: "Name of the Helm release to uninstall",
75
120
  },
76
121
  namespace: namespaceParameter,
77
122
  context: contextParameter,
@@ -79,144 +124,295 @@ export const uninstallHelmChartSchema = {
79
124
  required: ["name", "namespace"],
80
125
  },
81
126
  };
82
- const executeHelmCommand = (command, args) => {
127
+ /**
128
+ * Execute a command using child_process.execFileSync with proper error handling.
129
+ * @param command - The command to execute
130
+ * @param args - Array of command arguments
131
+ * @returns The command output as a string
132
+ * @throws Error if command execution fails
133
+ */
134
+ const executeCommand = (command, args) => {
83
135
  try {
84
- // Add a generous timeout of 60 seconds for Helm operations
85
136
  return execFileSync(command, args, {
86
137
  encoding: "utf8",
87
- timeout: 60000, // 60 seconds timeout
138
+ timeout: 300000, // 5 minutes timeout
88
139
  maxBuffer: getSpawnMaxBuffer(),
89
140
  env: { ...process.env, KUBECONFIG: process.env.KUBECONFIG },
90
141
  });
91
142
  }
92
143
  catch (error) {
93
- throw new Error(`Helm command failed: ${error.message}`);
144
+ throw new Error(`${command} command failed: ${error.message}`);
94
145
  }
95
146
  };
96
- const writeValuesFile = (name, values) => {
97
- const filename = `${name}-values.yaml`;
98
- writeFileSync(filename, yaml.stringify(values));
99
- return filename;
100
- };
101
- export async function installHelmChart(params) {
147
+ /**
148
+ * Install a Helm chart using template mode (helm template + kubectl apply).
149
+ * This mode bypasses authentication issues and kubeconfig API version mismatches.
150
+ * @param params - Installation parameters
151
+ * @returns Promise with installation result
152
+ */
153
+ async function installHelmChartTemplate(params) {
154
+ const steps = [];
102
155
  try {
103
- // Add helm repository if provided
156
+ // Step 1: Add helm repository if provided
104
157
  if (params.repo) {
105
- const repoName = params.chart.split("/")[0];
106
- executeHelmCommand("helm", ["repo", "add", repoName, params.repo]);
107
- executeHelmCommand("helm", ["repo", "update"]);
158
+ steps.push(`Adding helm repository: ${params.repo}`);
159
+ executeCommand("helm", ["repo", "add", "temp-repo", params.repo]);
160
+ executeCommand("helm", ["repo", "update"]);
161
+ }
162
+ // Step 2: Create namespace
163
+ steps.push(`Creating namespace: ${params.namespace}`);
164
+ try {
165
+ executeCommand("kubectl", ["create", "namespace", params.namespace]);
166
+ }
167
+ catch (error) {
168
+ if (!error.message.includes("already exists")) {
169
+ throw error;
170
+ }
171
+ steps.push(`Namespace ${params.namespace} already exists`);
108
172
  }
109
- let command = "helm";
110
- let args = [
111
- "install",
173
+ // Step 3: Prepare values
174
+ let valuesContent = "";
175
+ if (params.valuesFile) {
176
+ steps.push(`Using values file: ${params.valuesFile}`);
177
+ valuesContent = executeCommand("cat", [params.valuesFile]);
178
+ }
179
+ else if (params.values) {
180
+ steps.push("Using provided values object");
181
+ valuesContent = dump(params.values);
182
+ }
183
+ // Step 4: Generate YAML using helm template
184
+ steps.push("Generating YAML using helm template");
185
+ const templateArgs = [
186
+ "template",
112
187
  params.name,
113
188
  params.chart,
114
- "--namespace",
115
- params.namespace,
116
- "--create-namespace",
189
+ "--namespace", params.namespace
117
190
  ];
118
- // Handle values if provided
119
- if (params.values) {
120
- const valuesFile = writeValuesFile(params.name, params.values);
121
- args.push("-f", valuesFile);
191
+ if (params.repo) {
192
+ templateArgs.push("--repo", params.repo);
193
+ }
194
+ if (valuesContent) {
195
+ const tempValuesFile = `/tmp/values-${Date.now()}.yaml`;
196
+ writeFileSync(tempValuesFile, valuesContent);
197
+ templateArgs.push("-f", tempValuesFile);
198
+ const yamlOutput = executeCommand("helm", templateArgs);
199
+ // Clean up temp file
200
+ unlinkSync(tempValuesFile);
201
+ // Step 5: Apply YAML using kubectl
202
+ steps.push("Applying YAML using kubectl");
203
+ const tempYamlFile = `/tmp/helm-template-${Date.now()}.yaml`;
204
+ writeFileSync(tempYamlFile, yamlOutput);
122
205
  try {
123
- executeHelmCommand(command, args);
206
+ executeCommand("kubectl", ["apply", "-f", tempYamlFile]);
207
+ steps.push("Helm chart installed successfully using template mode");
124
208
  }
125
209
  finally {
126
- // Cleanup values file
127
- unlinkSync(valuesFile);
210
+ // Clean up temp file
211
+ unlinkSync(tempYamlFile);
128
212
  }
129
213
  }
130
214
  else {
131
- executeHelmCommand(command, args);
215
+ const yamlOutput = executeCommand("helm", templateArgs);
216
+ // Step 5: Apply YAML using kubectl
217
+ steps.push("Applying YAML using kubectl");
218
+ const tempYamlFile = `/tmp/helm-template-${Date.now()}.yaml`;
219
+ writeFileSync(tempYamlFile, yamlOutput);
220
+ try {
221
+ executeCommand("kubectl", ["apply", "-f", tempYamlFile]);
222
+ steps.push("Helm chart installed successfully using template mode");
223
+ }
224
+ finally {
225
+ // Clean up temp file
226
+ unlinkSync(tempYamlFile);
227
+ }
132
228
  }
133
- const response = {
134
- status: "installed",
135
- message: `Successfully installed ${params.name}`,
229
+ return {
230
+ content: [
231
+ {
232
+ type: "text",
233
+ text: JSON.stringify({
234
+ status: "installed",
235
+ message: `Helm chart '${params.name}' installed successfully using template mode`,
236
+ steps: steps
237
+ })
238
+ }
239
+ ]
240
+ };
241
+ }
242
+ catch (error) {
243
+ return {
244
+ content: [
245
+ {
246
+ type: "text",
247
+ text: JSON.stringify({
248
+ status: "failed",
249
+ error: `Failed to install Helm chart using template mode: ${error.message}`,
250
+ steps: steps
251
+ })
252
+ }
253
+ ]
136
254
  };
255
+ }
256
+ }
257
+ /**
258
+ * Install a Helm chart using standard helm install command.
259
+ * @param params - Installation parameters
260
+ * @returns Promise with installation result
261
+ */
262
+ export async function installHelmChart(params) {
263
+ // Use template mode if requested
264
+ if (params.useTemplate) {
265
+ return installHelmChartTemplate(params);
266
+ }
267
+ try {
268
+ // Add repository if provided
269
+ if (params.repo) {
270
+ const repoName = params.chart.split("/")[0];
271
+ executeCommand("helm", ["repo", "add", repoName, params.repo]);
272
+ executeCommand("helm", ["repo", "update"]);
273
+ }
274
+ const args = ["install", params.name, params.chart, "--namespace", params.namespace];
275
+ // Add create namespace flag if requested
276
+ if (params.createNamespace !== false) {
277
+ args.push("--create-namespace");
278
+ }
279
+ // Add values file if provided
280
+ if (params.valuesFile) {
281
+ args.push("-f", params.valuesFile);
282
+ }
283
+ // Add values object if provided
284
+ if (params.values) {
285
+ const valuesContent = dump(params.values);
286
+ const tempFile = `/tmp/values-${Date.now()}.yaml`;
287
+ writeFileSync(tempFile, valuesContent);
288
+ try {
289
+ args.push("-f", tempFile);
290
+ executeCommand("helm", args);
291
+ }
292
+ finally {
293
+ unlinkSync(tempFile);
294
+ }
295
+ }
296
+ else {
297
+ executeCommand("helm", args);
298
+ }
137
299
  return {
138
300
  content: [
139
301
  {
140
302
  type: "text",
141
- text: JSON.stringify(response, null, 2),
142
- },
143
- ],
303
+ text: JSON.stringify({
304
+ status: "installed",
305
+ message: `Helm chart '${params.name}' installed successfully in namespace '${params.namespace}'`
306
+ })
307
+ }
308
+ ]
144
309
  };
145
310
  }
146
311
  catch (error) {
147
- throw new Error(`Failed to install Helm chart: ${error.message}`);
312
+ return {
313
+ content: [
314
+ {
315
+ type: "text",
316
+ text: JSON.stringify({
317
+ status: "failed",
318
+ error: `Failed to install Helm chart: ${error.message}`
319
+ })
320
+ }
321
+ ]
322
+ };
148
323
  }
149
324
  }
325
+ /**
326
+ * Upgrade an existing Helm chart release.
327
+ * @param params - Upgrade parameters
328
+ * @returns Promise with upgrade result
329
+ */
150
330
  export async function upgradeHelmChart(params) {
151
331
  try {
152
- // Add helm repository if provided
332
+ // Add repository if provided
153
333
  if (params.repo) {
154
334
  const repoName = params.chart.split("/")[0];
155
- executeHelmCommand("helm", ["repo", "add", repoName, params.repo]);
156
- executeHelmCommand("helm", ["repo", "update"]);
335
+ executeCommand("helm", ["repo", "add", repoName, params.repo]);
336
+ executeCommand("helm", ["repo", "update"]);
157
337
  }
158
- let command = "helm";
159
- let args = [
160
- "upgrade",
161
- params.name,
162
- params.chart,
163
- "--namespace",
164
- params.namespace,
165
- ];
166
- // Handle values if provided
338
+ const args = ["upgrade", params.name, params.chart, "--namespace", params.namespace];
339
+ // Add values file if provided
340
+ if (params.valuesFile) {
341
+ args.push("-f", params.valuesFile);
342
+ }
343
+ // Add values object if provided
167
344
  if (params.values) {
168
- const valuesFile = writeValuesFile(params.name, params.values);
169
- args.push("-f", valuesFile);
345
+ const valuesContent = dump(params.values);
346
+ const tempFile = `/tmp/values-${Date.now()}.yaml`;
347
+ writeFileSync(tempFile, valuesContent);
170
348
  try {
171
- executeHelmCommand(command, args);
349
+ args.push("-f", tempFile);
350
+ executeCommand("helm", args);
172
351
  }
173
352
  finally {
174
- // Cleanup values file
175
- unlinkSync(valuesFile);
353
+ unlinkSync(tempFile);
176
354
  }
177
355
  }
178
356
  else {
179
- executeHelmCommand(command, args);
357
+ executeCommand("helm", args);
180
358
  }
181
- const response = {
182
- status: "upgraded",
183
- message: `Successfully upgraded ${params.name}`,
184
- };
185
359
  return {
186
360
  content: [
187
361
  {
188
362
  type: "text",
189
- text: JSON.stringify(response, null, 2),
190
- },
191
- ],
363
+ text: JSON.stringify({
364
+ status: "upgraded",
365
+ message: `Helm chart '${params.name}' upgraded successfully in namespace '${params.namespace}'`
366
+ })
367
+ }
368
+ ]
192
369
  };
193
370
  }
194
371
  catch (error) {
195
- throw new Error(`Failed to upgrade Helm chart: ${error.message}`);
372
+ return {
373
+ content: [
374
+ {
375
+ type: "text",
376
+ text: JSON.stringify({
377
+ status: "failed",
378
+ error: `Failed to upgrade Helm chart: ${error.message}`
379
+ })
380
+ }
381
+ ]
382
+ };
196
383
  }
197
384
  }
385
+ /**
386
+ * Uninstall a Helm chart release.
387
+ * @param params - Uninstall parameters
388
+ * @returns Promise with uninstall result
389
+ */
198
390
  export async function uninstallHelmChart(params) {
199
391
  try {
200
- executeHelmCommand("helm", [
201
- "uninstall",
202
- params.name,
203
- "--namespace",
204
- params.namespace,
205
- ]);
206
- const response = {
207
- status: "uninstalled",
208
- message: `Successfully uninstalled ${params.name}`,
209
- };
392
+ executeCommand("helm", ["uninstall", params.name, "--namespace", params.namespace]);
210
393
  return {
211
394
  content: [
212
395
  {
213
396
  type: "text",
214
- text: JSON.stringify(response, null, 2),
215
- },
216
- ],
397
+ text: JSON.stringify({
398
+ status: "uninstalled",
399
+ message: `Helm chart '${params.name}' uninstalled successfully from namespace '${params.namespace}'`
400
+ })
401
+ }
402
+ ]
217
403
  };
218
404
  }
219
405
  catch (error) {
220
- throw new Error(`Failed to uninstall Helm chart: ${error.message}`);
406
+ return {
407
+ content: [
408
+ {
409
+ type: "text",
410
+ text: JSON.stringify({
411
+ status: "failed",
412
+ error: `Failed to uninstall Helm chart: ${error.message}`
413
+ })
414
+ }
415
+ ]
416
+ };
221
417
  }
222
418
  }
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Tool: node_management
3
+ * Manage Kubernetes nodes with cordon, drain, and uncordon operations.
4
+ * Provides safety features for node operations and implements proper error handling
5
+ * and confirmation requirements for destructive operations.
6
+ * Note: Use kubectl_get with resourceType="nodes" to list nodes.
7
+ */
8
+ /**
9
+ * Schema for node_management tool.
10
+ * - operation: Node operation to perform (cordon, drain, uncordon)
11
+ * - nodeName: Name of the node to operate on (required for cordon, drain, uncordon)
12
+ * - force: Force the operation even if there are unmanaged pods (for drain)
13
+ * - gracePeriod: Grace period for pod termination (for drain)
14
+ * - deleteLocalData: Delete local data even if emptyDir volumes are used (for drain)
15
+ * - ignoreDaemonsets: Ignore DaemonSet-managed pods (for drain)
16
+ * - timeout: Timeout for drain operation
17
+ * - dryRun: Show what would be done without actually doing it (for drain)
18
+ * - confirmDrain: Explicit confirmation to drain the node (required for drain)
19
+ */
20
+ export declare const nodeManagementSchema: {
21
+ name: string;
22
+ description: string;
23
+ inputSchema: {
24
+ type: string;
25
+ properties: {
26
+ operation: {
27
+ type: string;
28
+ description: string;
29
+ enum: string[];
30
+ };
31
+ nodeName: {
32
+ type: string;
33
+ description: string;
34
+ };
35
+ force: {
36
+ type: string;
37
+ description: string;
38
+ default: boolean;
39
+ };
40
+ gracePeriod: {
41
+ type: string;
42
+ description: string;
43
+ default: number;
44
+ };
45
+ deleteLocalData: {
46
+ type: string;
47
+ description: string;
48
+ default: boolean;
49
+ };
50
+ ignoreDaemonsets: {
51
+ type: string;
52
+ description: string;
53
+ default: boolean;
54
+ };
55
+ timeout: {
56
+ type: string;
57
+ description: string;
58
+ default: string;
59
+ };
60
+ dryRun: {
61
+ type: string;
62
+ description: string;
63
+ default: boolean;
64
+ };
65
+ confirmDrain: {
66
+ type: string;
67
+ description: string;
68
+ default: boolean;
69
+ };
70
+ };
71
+ required: string[];
72
+ };
73
+ };
74
+ /**
75
+ * Interface for node_management tool parameters.
76
+ */
77
+ interface NodeManagementParams {
78
+ operation: "cordon" | "drain" | "uncordon";
79
+ nodeName?: string;
80
+ force?: boolean;
81
+ gracePeriod?: number;
82
+ deleteLocalData?: boolean;
83
+ ignoreDaemonsets?: boolean;
84
+ timeout?: string;
85
+ dryRun?: boolean;
86
+ confirmDrain?: boolean;
87
+ }
88
+ /**
89
+ * Main node_management function that handles all node operations.
90
+ * Implements safety features and proper error handling for node management tasks.
91
+ * @param params - Node management parameters
92
+ * @returns Promise with operation results
93
+ */
94
+ export declare function nodeManagement(params: NodeManagementParams): Promise<{
95
+ content: {
96
+ type: string;
97
+ text: string;
98
+ }[];
99
+ }>;
100
+ export {};