mcp-server-kubernetes 2.7.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.
Files changed (38) hide show
  1. package/README.md +251 -2
  2. package/dist/index.d.ts +190 -27
  3. package/dist/index.js +7 -0
  4. package/dist/models/common-parameters.d.ts +15 -0
  5. package/dist/models/common-parameters.js +15 -0
  6. package/dist/models/helm-models.d.ts +18 -5
  7. package/dist/models/kubectl-models.d.ts +2 -0
  8. package/dist/tools/exec_in_pod.d.ts +7 -1
  9. package/dist/tools/exec_in_pod.js +7 -5
  10. package/dist/tools/helm-operations.d.ts +89 -11
  11. package/dist/tools/helm-operations.js +297 -106
  12. package/dist/tools/kubectl-apply.d.ts +12 -6
  13. package/dist/tools/kubectl-apply.js +9 -10
  14. package/dist/tools/kubectl-create.d.ts +12 -6
  15. package/dist/tools/kubectl-create.js +9 -10
  16. package/dist/tools/kubectl-delete.d.ts +9 -3
  17. package/dist/tools/kubectl-delete.js +8 -5
  18. package/dist/tools/kubectl-describe.d.ts +9 -3
  19. package/dist/tools/kubectl-describe.js +7 -5
  20. package/dist/tools/kubectl-generic.d.ts +7 -1
  21. package/dist/tools/kubectl-generic.js +7 -5
  22. package/dist/tools/kubectl-get.d.ts +9 -3
  23. package/dist/tools/kubectl-get.js +7 -5
  24. package/dist/tools/kubectl-logs.d.ts +9 -3
  25. package/dist/tools/kubectl-logs.js +11 -5
  26. package/dist/tools/kubectl-operations.d.ts +10 -0
  27. package/dist/tools/kubectl-operations.js +13 -0
  28. package/dist/tools/kubectl-patch.d.ts +8 -2
  29. package/dist/tools/kubectl-patch.js +9 -10
  30. package/dist/tools/kubectl-rollout.d.ts +7 -1
  31. package/dist/tools/kubectl-rollout.js +8 -5
  32. package/dist/tools/kubectl-scale.d.ts +7 -1
  33. package/dist/tools/kubectl-scale.js +8 -5
  34. package/dist/tools/node-management.d.ts +100 -0
  35. package/dist/tools/node-management.js +291 -0
  36. package/dist/utils/sse.js +21 -0
  37. package/dist/utils/streamable-http.js +21 -0
  38. package/package.json +1 -1
@@ -1,6 +1,7 @@
1
1
  import { execFileSync } from "child_process";
2
2
  import { McpError, ErrorCode } from "@modelcontextprotocol/sdk/types.js";
3
3
  import { getSpawnMaxBuffer } from "../config/max-buffer.js";
4
+ import { contextParameter, namespaceParameter } from "../models/common-parameters.js";
4
5
  export const kubectlRolloutSchema = {
5
6
  name: "kubectl_rollout",
6
7
  description: "Manage the rollout of a resource (e.g., deployment, daemonset, statefulset)",
@@ -23,11 +24,7 @@ export const kubectlRolloutSchema = {
23
24
  type: "string",
24
25
  description: "Name of the resource",
25
26
  },
26
- namespace: {
27
- type: "string",
28
- description: "Namespace of the resource",
29
- default: "default",
30
- },
27
+ namespace: namespaceParameter,
31
28
  revision: {
32
29
  type: "number",
33
30
  description: "Revision to rollback to (for undo subcommand)",
@@ -45,6 +42,7 @@ export const kubectlRolloutSchema = {
45
42
  description: "Watch the rollout status in real-time until completion",
46
43
  default: false,
47
44
  },
45
+ context: contextParameter,
48
46
  },
49
47
  required: ["subCommand", "resourceType", "name", "namespace"],
50
48
  },
@@ -53,6 +51,7 @@ export async function kubectlRollout(k8sManager, input) {
53
51
  try {
54
52
  const namespace = input.namespace || "default";
55
53
  const watch = input.watch || false;
54
+ const context = input.context || "";
56
55
  const command = "kubectl";
57
56
  const args = [
58
57
  "rollout",
@@ -73,6 +72,10 @@ export async function kubectlRollout(k8sManager, input) {
73
72
  if (input.timeout) {
74
73
  args.push(`--timeout=${input.timeout}`);
75
74
  }
75
+ // Add context if provided
76
+ if (context) {
77
+ args.push("--context", context);
78
+ }
76
79
  // Execute the command
77
80
  try {
78
81
  // For status command with watch flag, we need to handle it differently
@@ -10,7 +10,7 @@ export declare const kubectlScaleSchema: {
10
10
  description: string;
11
11
  };
12
12
  namespace: {
13
- type: string;
13
+ type: "string";
14
14
  description: string;
15
15
  default: string;
16
16
  };
@@ -23,6 +23,11 @@ export declare const kubectlScaleSchema: {
23
23
  description: string;
24
24
  default: string;
25
25
  };
26
+ context: {
27
+ type: "string";
28
+ description: string;
29
+ default: string;
30
+ };
26
31
  };
27
32
  required: string[];
28
33
  };
@@ -32,6 +37,7 @@ export declare function kubectlScale(k8sManager: KubernetesManager, input: {
32
37
  namespace?: string;
33
38
  replicas: number;
34
39
  resourceType?: string;
40
+ context?: string;
35
41
  }): Promise<{
36
42
  content: {
37
43
  success: boolean;
@@ -1,6 +1,7 @@
1
1
  import { execFileSync } from "child_process";
2
2
  import { McpError, ErrorCode } from "@modelcontextprotocol/sdk/types.js";
3
3
  import { getSpawnMaxBuffer } from "../config/max-buffer.js";
4
+ import { contextParameter, namespaceParameter } from "../models/common-parameters.js";
4
5
  export const kubectlScaleSchema = {
5
6
  name: "kubectl_scale",
6
7
  description: "Scale a Kubernetes deployment",
@@ -11,11 +12,7 @@ export const kubectlScaleSchema = {
11
12
  type: "string",
12
13
  description: "Name of the deployment to scale",
13
14
  },
14
- namespace: {
15
- type: "string",
16
- description: "Namespace of the deployment",
17
- default: "default",
18
- },
15
+ namespace: namespaceParameter,
19
16
  replicas: {
20
17
  type: "number",
21
18
  description: "Number of replicas to scale to",
@@ -25,6 +22,7 @@ export const kubectlScaleSchema = {
25
22
  description: "Resource type to scale (deployment, replicaset, statefulset)",
26
23
  default: "deployment",
27
24
  },
25
+ context: contextParameter,
28
26
  },
29
27
  required: ["name", "replicas"],
30
28
  },
@@ -33,6 +31,7 @@ export async function kubectlScale(k8sManager, input) {
33
31
  try {
34
32
  const namespace = input.namespace || "default";
35
33
  const resourceType = input.resourceType || "deployment";
34
+ const context = input.context || "";
36
35
  const command = "kubectl";
37
36
  const args = [
38
37
  "scale",
@@ -41,6 +40,10 @@ export async function kubectlScale(k8sManager, input) {
41
40
  `--replicas=${input.replicas}`,
42
41
  `--namespace=${namespace}`,
43
42
  ];
43
+ // Add context if provided
44
+ if (context) {
45
+ args.push("--context", context);
46
+ }
44
47
  // Execute the command
45
48
  try {
46
49
  const result = execFileSync(command, args, {
@@ -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 {};
@@ -0,0 +1,291 @@
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
+ import { execFileSync } from "child_process";
9
+ import { getSpawnMaxBuffer } from "../config/max-buffer.js";
10
+ /**
11
+ * Schema for node_management tool.
12
+ * - operation: Node operation to perform (cordon, drain, uncordon)
13
+ * - nodeName: Name of the node to operate on (required for cordon, drain, uncordon)
14
+ * - force: Force the operation even if there are unmanaged pods (for drain)
15
+ * - gracePeriod: Grace period for pod termination (for drain)
16
+ * - deleteLocalData: Delete local data even if emptyDir volumes are used (for drain)
17
+ * - ignoreDaemonsets: Ignore DaemonSet-managed pods (for drain)
18
+ * - timeout: Timeout for drain operation
19
+ * - dryRun: Show what would be done without actually doing it (for drain)
20
+ * - confirmDrain: Explicit confirmation to drain the node (required for drain)
21
+ */
22
+ export const nodeManagementSchema = {
23
+ name: "node_management",
24
+ description: "Manage Kubernetes nodes with cordon, drain, and uncordon operations",
25
+ inputSchema: {
26
+ type: "object",
27
+ properties: {
28
+ operation: {
29
+ type: "string",
30
+ description: "Node operation to perform",
31
+ enum: ["cordon", "drain", "uncordon"],
32
+ },
33
+ nodeName: {
34
+ type: "string",
35
+ description: "Name of the node to operate on (required for cordon, drain, uncordon)",
36
+ },
37
+ force: {
38
+ type: "boolean",
39
+ description: "Force the operation even if there are pods not managed by a ReplicationController, ReplicaSet, Job, DaemonSet or StatefulSet (for drain operation)",
40
+ default: false,
41
+ },
42
+ gracePeriod: {
43
+ type: "number",
44
+ description: "Period of time in seconds given to each pod to terminate gracefully (for drain operation). If set to -1, uses the kubectl default grace period.",
45
+ default: -1,
46
+ },
47
+ deleteLocalData: {
48
+ type: "boolean",
49
+ description: "Delete local data even if emptyDir volumes are used (for drain operation)",
50
+ default: false,
51
+ },
52
+ ignoreDaemonsets: {
53
+ type: "boolean",
54
+ description: "Ignore DaemonSet-managed pods (for drain operation)",
55
+ default: true,
56
+ },
57
+ timeout: {
58
+ type: "string",
59
+ description: "The length of time to wait before giving up (for drain operation, e.g., '5m', '1h')",
60
+ default: "0",
61
+ },
62
+ dryRun: {
63
+ type: "boolean",
64
+ description: "Show what would be done without actually doing it (for drain operation)",
65
+ default: false,
66
+ },
67
+ confirmDrain: {
68
+ type: "boolean",
69
+ description: "Explicit confirmation to drain the node (required for drain operation)",
70
+ default: false,
71
+ },
72
+ },
73
+ required: ["operation"],
74
+ },
75
+ };
76
+ /**
77
+ * Execute a command using child_process.execFileSync with proper error handling.
78
+ * @param command - The command to execute
79
+ * @param args - Array of command arguments
80
+ * @returns The command output as a string
81
+ * @throws Error if command execution fails
82
+ */
83
+ const executeCommand = (command, args) => {
84
+ try {
85
+ return execFileSync(command, args, {
86
+ encoding: "utf8",
87
+ timeout: 300000, // 5 minutes timeout for node operations
88
+ maxBuffer: getSpawnMaxBuffer(),
89
+ env: { ...process.env, KUBECONFIG: process.env.KUBECONFIG },
90
+ });
91
+ }
92
+ catch (error) {
93
+ throw new Error(`${command} command failed: ${error.message}`);
94
+ }
95
+ };
96
+ /**
97
+ * Get the status of a specific node.
98
+ * @param nodeName - Name of the node to get status for
99
+ * @returns Node status as JSON object
100
+ * @throws Error if node status retrieval fails
101
+ */
102
+ const getNodeStatus = (nodeName) => {
103
+ try {
104
+ const output = executeCommand("kubectl", ["get", "node", nodeName, "-o", "json"]);
105
+ return JSON.parse(output);
106
+ }
107
+ catch (error) {
108
+ throw new Error(`Failed to get node status: ${error.message}`);
109
+ }
110
+ };
111
+ /**
112
+ * Main node_management function that handles all node operations.
113
+ * Implements safety features and proper error handling for node management tasks.
114
+ * @param params - Node management parameters
115
+ * @returns Promise with operation results
116
+ */
117
+ export async function nodeManagement(params) {
118
+ const { operation, nodeName, force = false, gracePeriod = -1, deleteLocalData = false, ignoreDaemonsets = true, timeout = "0", dryRun = false, confirmDrain = false } = params;
119
+ try {
120
+ switch (operation) {
121
+ case "cordon":
122
+ return handleCordonNode(nodeName);
123
+ case "uncordon":
124
+ return handleUncordonNode(nodeName);
125
+ case "drain":
126
+ return handleDrainNode({
127
+ nodeName: nodeName,
128
+ force,
129
+ gracePeriod,
130
+ deleteLocalData,
131
+ ignoreDaemonsets,
132
+ timeout,
133
+ dryRun,
134
+ confirmDrain
135
+ });
136
+ default:
137
+ throw new Error(`Unknown operation: ${operation}`);
138
+ }
139
+ }
140
+ catch (error) {
141
+ return {
142
+ content: [
143
+ {
144
+ type: "text",
145
+ text: `Node management operation failed: ${error.message}`
146
+ }
147
+ ]
148
+ };
149
+ }
150
+ }
151
+ /**
152
+ * Handle the cordon node operation.
153
+ * @param nodeName - Name of the node to cordon
154
+ * @returns Promise with cordon operation results
155
+ */
156
+ async function handleCordonNode(nodeName) {
157
+ try {
158
+ // Check if node exists and get current status
159
+ const nodeStatus = getNodeStatus(nodeName);
160
+ const isSchedulable = !nodeStatus.spec.unschedulable;
161
+ if (!isSchedulable) {
162
+ return {
163
+ content: [
164
+ {
165
+ type: "text",
166
+ text: `Node '${nodeName}' is already cordoned (unschedulable)`
167
+ }
168
+ ]
169
+ };
170
+ }
171
+ // Cordon the node
172
+ executeCommand("kubectl", ["cordon", nodeName]);
173
+ return {
174
+ content: [
175
+ {
176
+ type: "text",
177
+ text: `Successfully cordoned node '${nodeName}'. The node is now unschedulable.`
178
+ }
179
+ ]
180
+ };
181
+ }
182
+ catch (error) {
183
+ throw new Error(`Failed to cordon node: ${error.message}`);
184
+ }
185
+ }
186
+ /**
187
+ * Handle the uncordon node operation.
188
+ * @param nodeName - Name of the node to uncordon
189
+ * @returns Promise with uncordon operation results
190
+ */
191
+ async function handleUncordonNode(nodeName) {
192
+ try {
193
+ // Check if node exists and get current status
194
+ const nodeStatus = getNodeStatus(nodeName);
195
+ const isSchedulable = !nodeStatus.spec.unschedulable;
196
+ if (isSchedulable) {
197
+ return {
198
+ content: [
199
+ {
200
+ type: "text",
201
+ text: `Node '${nodeName}' is already uncordoned (schedulable)`
202
+ }
203
+ ]
204
+ };
205
+ }
206
+ // Uncordon the node
207
+ executeCommand("kubectl", ["uncordon", nodeName]);
208
+ return {
209
+ content: [
210
+ {
211
+ type: "text",
212
+ text: `Successfully uncordoned node '${nodeName}'. The node is now schedulable.`
213
+ }
214
+ ]
215
+ };
216
+ }
217
+ catch (error) {
218
+ throw new Error(`Failed to uncordon node: ${error.message}`);
219
+ }
220
+ }
221
+ /**
222
+ * Handle the drain node operation with safety checks and confirmation.
223
+ * @param params - Drain operation parameters
224
+ * @returns Promise with drain operation results
225
+ */
226
+ async function handleDrainNode(params) {
227
+ const { nodeName, force, gracePeriod, deleteLocalData, ignoreDaemonsets, timeout, dryRun, confirmDrain } = params;
228
+ try {
229
+ // Check if node exists and get current status
230
+ const nodeStatus = getNodeStatus(nodeName);
231
+ const isSchedulable = !nodeStatus.spec.unschedulable;
232
+ if (!isSchedulable) {
233
+ return {
234
+ content: [
235
+ {
236
+ type: "text",
237
+ text: `Node '${nodeName}' is already cordoned (unschedulable). Drain operation may not be necessary.`
238
+ }
239
+ ]
240
+ };
241
+ }
242
+ // Check for confirmation if not in dry run mode
243
+ if (!dryRun && !confirmDrain) {
244
+ return {
245
+ content: [
246
+ {
247
+ type: "text",
248
+ text: `Drain operation requires explicit confirmation. Set confirmDrain=true to proceed with draining node '${nodeName}'.`
249
+ }
250
+ ]
251
+ };
252
+ }
253
+ // Build drain command arguments
254
+ const drainArgs = ["drain", nodeName];
255
+ if (force)
256
+ drainArgs.push("--force");
257
+ if (gracePeriod >= 0)
258
+ drainArgs.push("--grace-period", gracePeriod.toString());
259
+ if (deleteLocalData)
260
+ drainArgs.push("--delete-local-data");
261
+ if (ignoreDaemonsets)
262
+ drainArgs.push("--ignore-daemonsets");
263
+ if (timeout !== "0")
264
+ drainArgs.push("--timeout", timeout);
265
+ if (dryRun)
266
+ drainArgs.push("--dry-run=client");
267
+ // Execute drain command
268
+ const drainOutput = executeCommand("kubectl", drainArgs);
269
+ if (dryRun) {
270
+ return {
271
+ content: [
272
+ {
273
+ type: "text",
274
+ text: `Dry run drain operation for node '${nodeName}':\n\n${drainOutput}\n\nTo perform the actual drain, set dryRun=false and confirmDrain=true.`
275
+ }
276
+ ]
277
+ };
278
+ }
279
+ return {
280
+ content: [
281
+ {
282
+ type: "text",
283
+ text: `Successfully drained node '${nodeName}'.\n\n${drainOutput}`
284
+ }
285
+ ]
286
+ };
287
+ }
288
+ catch (error) {
289
+ throw new Error(`Failed to drain node: ${error.message}`);
290
+ }
291
+ }
package/dist/utils/sse.js CHANGED
@@ -21,6 +21,27 @@ export function startSSEServer(server) {
21
21
  .send("Not found. Must pass valid sessionId as query param.");
22
22
  }
23
23
  });
24
+ app.get("/health", async (req, res) => {
25
+ res.json({ status: "ok" });
26
+ });
27
+ app.get("/ready", async (req, res) => {
28
+ try {
29
+ // We can add more checks if required
30
+ // For now, we'll consider the server ready if it can respond to this request
31
+ res.json({
32
+ status: "ready",
33
+ timestamp: new Date().toISOString(),
34
+ });
35
+ }
36
+ catch (error) {
37
+ console.error("Readiness check failed:", error);
38
+ res.status(503).json({
39
+ status: "not ready",
40
+ reason: "Server initialization incomplete",
41
+ timestamp: new Date().toISOString()
42
+ });
43
+ }
44
+ });
24
45
  let port = 3000;
25
46
  try {
26
47
  port = parseInt(process.env.PORT || "3000", 10);
@@ -64,6 +64,27 @@ export function startStreamableHTTPServer(server) {
64
64
  id: null,
65
65
  }));
66
66
  });
67
+ app.get("/health", async (req, res) => {
68
+ res.json({ status: "ok" });
69
+ });
70
+ app.get("/ready", async (req, res) => {
71
+ try {
72
+ // We can add more checks if required
73
+ // For now, we'll consider the server ready if it can respond to this request
74
+ res.json({
75
+ status: "ready",
76
+ timestamp: new Date().toISOString(),
77
+ });
78
+ }
79
+ catch (error) {
80
+ console.error("Readiness check failed:", error);
81
+ res.status(503).json({
82
+ status: "not ready",
83
+ reason: "Server initialization incomplete",
84
+ timestamp: new Date().toISOString()
85
+ });
86
+ }
87
+ });
67
88
  let port = 3000;
68
89
  try {
69
90
  port = parseInt(process.env.PORT || "3000", 10);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcp-server-kubernetes",
3
- "version": "2.7.0",
3
+ "version": "2.9.0",
4
4
  "description": "MCP server for interacting with Kubernetes clusters via kubectl",
5
5
  "license": "MIT",
6
6
  "type": "module",