mcp-server-kubernetes 2.4.2 → 2.4.4

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.
package/README.md CHANGED
@@ -71,7 +71,7 @@ npx mcp-chat --config "%APPDATA%\Claude\claude_desktop_config.json"
71
71
  - [x] Unified kubectl API for managing resources
72
72
  - Get or list resources with `kubectl_get`
73
73
  - Describe resources with `kubectl_describe`
74
- - List resources with `kubectl_list`
74
+ - List resources with `kubectl_get`
75
75
  - Create resources with `kubectl_create`
76
76
  - Apply YAML manifests with `kubectl_apply`
77
77
  - Delete resources with `kubectl_delete`
@@ -83,21 +83,22 @@ npx mcp-chat --config "%APPDATA%\Claude\claude_desktop_config.json"
83
83
  - Update field(s) of a resource with `kubectl_patch`
84
84
  - Manage deployment rollouts with `kubectl_rollout`
85
85
  - Execute any kubectl command with `kubectl_generic`
86
+ - Verify connection with `ping`
86
87
  - [x] Advanced operations
87
88
  - Scale deployments with `kubectl_scale` (replaces legacy `scale_deployment`)
88
89
  - Port forward to pods and services with `port_forward`
89
90
  - Run Helm operations
90
91
  - Install, upgrade, and uninstall charts
91
92
  - Support for custom values, repositories, and versions
92
- - [x] Troubleshooting Prompt (`k8s-troubleshoot`)
93
+ - [x] Troubleshooting Prompt (`k8s-diagnose`)
93
94
  - Guides through a systematic Kubernetes troubleshooting flow for pods based on a keyword and optional namespace.
94
95
  - [x] Non-destructive mode for read and create/update-only access to clusters
95
96
 
96
97
  ## Prompts
97
98
 
98
- The MCP Kubernetes server includes specialized prompts to assist with common operations.
99
+ The MCP Kubernetes server includes specialized prompts to assist with common diagnostic operations.
99
100
 
100
- ### k8s-troubleshoot Prompt
101
+ ### k8s-diagnose Prompt
101
102
 
102
103
  This prompt provides a systematic troubleshooting flow for Kubernetes pods. It accepts a `keyword` to identify relevant pods and an optional `namespace` to narrow the search.
103
104
  The prompt's output will guide you through an autonomous troubleshooting flow, providing instructions for identifying issues, collecting evidence, and suggesting remediation steps.
@@ -192,7 +193,7 @@ For Claude Desktop configuration with non-destructive mode:
192
193
 
193
194
  All read-only and resource creation/update operations remain available:
194
195
 
195
- - Resource Information: `kubectl_get`, `kubectl_describe`, `kubectl_list`, `kubectl_logs`, `explain_resource`, `list_api_resources`
196
+ - Resource Information: `kubectl_get`, `kubectl_describe`, `kubectl_logs`, `explain_resource`, `list_api_resources`
196
197
  - Resource Creation/Modification: `kubectl_apply`, `kubectl_create`, `kubectl_scale`, `kubectl_patch`, `kubectl_rollout`
197
198
  - Helm Operations: `install_helm_chart`, `upgrade_helm_chart`
198
199
  - Connectivity: `port_forward`, `stop_port_forward`
@@ -61,8 +61,8 @@ export declare const CustomContainerConfig: z.ZodObject<{
61
61
  limits?: Record<string, string> | undefined;
62
62
  requests?: Record<string, string> | undefined;
63
63
  } | undefined;
64
- args?: string[] | undefined;
65
64
  command?: string[] | undefined;
65
+ args?: string[] | undefined;
66
66
  ports?: {
67
67
  containerPort: number;
68
68
  name?: string | undefined;
@@ -84,8 +84,8 @@ export declare const CustomContainerConfig: z.ZodObject<{
84
84
  limits?: Record<string, string> | undefined;
85
85
  requests?: Record<string, string> | undefined;
86
86
  } | undefined;
87
- args?: string[] | undefined;
88
87
  command?: string[] | undefined;
88
+ args?: string[] | undefined;
89
89
  ports?: {
90
90
  containerPort: number;
91
91
  name?: string | undefined;
package/dist/index.d.ts CHANGED
@@ -296,43 +296,6 @@ declare const allTools: ({
296
296
  };
297
297
  readonly required: readonly ["resourceType", "name"];
298
298
  };
299
- } | {
300
- readonly name: "kubectl_list";
301
- readonly description: "List Kubernetes resources by resource type and optionally namespace";
302
- readonly inputSchema: {
303
- readonly type: "object";
304
- readonly properties: {
305
- readonly resourceType: {
306
- readonly type: "string";
307
- readonly description: "Type of resource to list (e.g., pods, deployments, services, configmaps, etc.)";
308
- };
309
- readonly namespace: {
310
- readonly type: "string";
311
- readonly description: "Namespace of the resources (optional - defaults to 'default' for namespaced resources)";
312
- readonly default: "default";
313
- };
314
- readonly output: {
315
- readonly type: "string";
316
- readonly enum: readonly ["json", "yaml", "wide", "name", "custom", "formatted"];
317
- readonly description: "Output format - 'formatted' uses a resource-specific format with key information";
318
- readonly default: "formatted";
319
- };
320
- readonly allNamespaces: {
321
- readonly type: "boolean";
322
- readonly description: "If true, list resources across all namespaces";
323
- readonly default: false;
324
- };
325
- readonly labelSelector: {
326
- readonly type: "string";
327
- readonly description: "Filter resources by label selector (e.g. 'app=nginx')";
328
- };
329
- readonly fieldSelector: {
330
- readonly type: "string";
331
- readonly description: "Filter resources by field selector (e.g. 'metadata.name=my-pod')";
332
- };
333
- };
334
- readonly required: readonly ["resourceType", "namespace"];
335
- };
336
299
  } | {
337
300
  readonly name: "kubectl_apply";
338
301
  readonly description: "Apply a Kubernetes YAML manifest from a string or file";
@@ -591,5 +554,13 @@ declare const allTools: ({
591
554
  };
592
555
  readonly required: readonly ["resourceType", "name", "namespace"];
593
556
  };
557
+ } | {
558
+ name: string;
559
+ description: string;
560
+ inputSchema: {
561
+ type: string;
562
+ properties: {};
563
+ required: never[];
564
+ };
594
565
  })[];
595
566
  export { allTools, destructiveTools };
package/dist/index.js CHANGED
@@ -3,6 +3,7 @@ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
3
3
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
4
  import { installHelmChart, installHelmChartSchema, upgradeHelmChart, upgradeHelmChartSchema, uninstallHelmChart, uninstallHelmChartSchema, } from "./tools/helm-operations.js";
5
5
  import { explainResource, explainResourceSchema, listApiResources, listApiResourcesSchema, } from "./tools/kubectl-operations.js";
6
+ import { execInPod, execInPodSchema } from "./tools/exec_in_pod.js";
6
7
  import { getResourceHandlers } from "./resources/handlers.js";
7
8
  import { ListResourcesRequestSchema, ReadResourceRequestSchema, ListToolsRequestSchema, CallToolRequestSchema, ErrorCode, McpError, } from "@modelcontextprotocol/sdk/types.js";
8
9
  import { KubernetesManager } from "./types.js";
@@ -14,7 +15,6 @@ import { kubectlScale, kubectlScaleSchema } from "./tools/kubectl-scale.js";
14
15
  import { kubectlContext, kubectlContextSchema, } from "./tools/kubectl-context.js";
15
16
  import { kubectlGet, kubectlGetSchema } from "./tools/kubectl-get.js";
16
17
  import { kubectlDescribe, kubectlDescribeSchema, } from "./tools/kubectl-describe.js";
17
- import { kubectlList, kubectlListSchema } from "./tools/kubectl-list.js";
18
18
  import { kubectlApply, kubectlApplySchema } from "./tools/kubectl-apply.js";
19
19
  import { kubectlDelete, kubectlDeleteSchema } from "./tools/kubectl-delete.js";
20
20
  import { kubectlCreate, kubectlCreateSchema } from "./tools/kubectl-create.js";
@@ -23,6 +23,7 @@ import { kubectlGeneric, kubectlGenericSchema, } from "./tools/kubectl-generic.j
23
23
  import { kubectlPatch, kubectlPatchSchema } from "./tools/kubectl-patch.js";
24
24
  import { kubectlRollout, kubectlRolloutSchema, } from "./tools/kubectl-rollout.js";
25
25
  import { registerPromptHandlers } from "./prompts/index.js";
26
+ import { ping, pingSchema } from "./tools/ping.js";
26
27
  // Check if non-destructive tools only mode is enabled
27
28
  const nonDestructiveTools = process.env.ALLOW_ONLY_NON_DESTRUCTIVE_TOOLS === "true";
28
29
  // Define destructive tools (delete and uninstall operations)
@@ -39,7 +40,6 @@ const allTools = [
39
40
  // Unified kubectl-style tools - these replace many specific tools
40
41
  kubectlGetSchema,
41
42
  kubectlDescribeSchema,
42
- kubectlListSchema,
43
43
  kubectlApplySchema,
44
44
  kubectlDeleteSchema,
45
45
  kubectlCreateSchema,
@@ -58,10 +58,13 @@ const allTools = [
58
58
  // Port forwarding
59
59
  PortForwardSchema,
60
60
  StopPortForwardSchema,
61
+ execInPodSchema,
61
62
  // API resource operations
62
63
  listApiResourcesSchema,
63
64
  // Generic kubectl command
64
65
  kubectlGenericSchema,
66
+ // Ping utility
67
+ pingSchema,
65
68
  ];
66
69
  const k8sManager = new KubernetesManager();
67
70
  const server = new Server({
@@ -101,9 +104,6 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
101
104
  if (name === "kubectl_describe") {
102
105
  return await kubectlDescribe(k8sManager, input);
103
106
  }
104
- if (name === "kubectl_list") {
105
- return await kubectlList(k8sManager, input);
106
- }
107
107
  if (name === "kubectl_apply") {
108
108
  return await kubectlApply(k8sManager, input);
109
109
  }
@@ -174,6 +174,12 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
174
174
  case "kubectl_scale": {
175
175
  return await kubectlScale(k8sManager, input);
176
176
  }
177
+ case "ping": {
178
+ return await ping();
179
+ }
180
+ case "exec_in_pod": {
181
+ return await execInPod(k8sManager, input);
182
+ }
177
183
  default:
178
184
  throw new McpError(ErrorCode.InvalidRequest, `Unknown tool: ${name}`);
179
185
  }
@@ -664,3 +664,25 @@ export declare const DescribeNodeResponseSchema: z.ZodObject<{
664
664
  text: string;
665
665
  }[];
666
666
  }>;
667
+ export declare const ExecInPodResponseSchema: z.ZodObject<{
668
+ content: z.ZodArray<z.ZodObject<{
669
+ type: z.ZodLiteral<"text">;
670
+ text: z.ZodString;
671
+ }, "strip", z.ZodTypeAny, {
672
+ type: "text";
673
+ text: string;
674
+ }, {
675
+ type: "text";
676
+ text: string;
677
+ }>, "many">;
678
+ }, "strip", z.ZodTypeAny, {
679
+ content: {
680
+ type: "text";
681
+ text: string;
682
+ }[];
683
+ }, {
684
+ content: {
685
+ type: "text";
686
+ text: string;
687
+ }[];
688
+ }>;
@@ -116,3 +116,6 @@ export const SetCurrentContextResponseSchema = z.object({
116
116
  export const DescribeNodeResponseSchema = z.object({
117
117
  content: z.array(ToolResponseContent),
118
118
  });
119
+ export const ExecInPodResponseSchema = z.object({
120
+ content: z.array(ToolResponseContent),
121
+ });
@@ -39,4 +39,5 @@ export declare const ListToolsResponseSchema: z.ZodObject<{
39
39
  inputSchema: Record<string, any>;
40
40
  }[];
41
41
  }>;
42
+ export declare const PingResponseSchema: z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>;
42
43
  export type K8sTool = z.infer<typeof ToolSchema>;
@@ -8,3 +8,4 @@ export const ToolSchema = z.object({
8
8
  export const ListToolsResponseSchema = z.object({
9
9
  tools: z.array(ToolSchema),
10
10
  });
11
+ export const PingResponseSchema = z.object({});
@@ -5,8 +5,8 @@ export function registerPromptHandlers(server, k8sManager) {
5
5
  return {
6
6
  prompts: [
7
7
  {
8
- name: "k8s-troubleshoot",
9
- description: "Troubleshoot Kubernetes Resources.",
8
+ name: "k8s-diagnose",
9
+ description: "Diagnose Kubernetes Resources.",
10
10
  arguments: [
11
11
  {
12
12
  name: "keyword",
@@ -27,16 +27,16 @@ export function registerPromptHandlers(server, k8sManager) {
27
27
  // Register prompt handler
28
28
  server.setRequestHandler(GetPromptRequestSchema, async (request) => {
29
29
  const { name, arguments: args } = request.params;
30
- if (name === "k8s-troubleshoot") {
30
+ if (name === "k8s-diagnose") {
31
31
  const keyword = args?.keyword;
32
32
  const namespace = args?.namespace;
33
33
  if (!keyword) {
34
- throw new Error("Keyword parameter is required for k8s-troubleshoot prompt");
34
+ throw new Error("Keyword parameter is required for k8s-diagnose prompt");
35
35
  }
36
36
  const actualNamespace = namespace || "all";
37
- const message = `Troubleshooting for resources (pods, nodes, etc.) containing keyword "${keyword}" in their names within namespace "${actualNamespace}" (or across all namespaces if specified) for this investigation:
37
+ const message = `Diagnose Kubernetes resources (pods, nodes, etc.) containing keyword "${keyword}" in their names within namespace "${actualNamespace}" (or across all namespaces if specified) for this investigation:
38
38
 
39
- **Autonomous Kubernetes Troubleshooting Flow**
39
+ **Autonomous Kubernetes Diagnosis Flow**
40
40
 
41
41
  0. **Perform Quick Health Checks / Golden Signals Analysis**
42
42
  - Assess latency, errors, and resource utilization. If a clear issue is identified (e.g., node not ready, network partition), streamline or deprioritize subsequent detailed steps.
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Tool: exec_in_pod
3
+ * Execute a command in a Kubernetes pod or container and return the output.
4
+ * Uses the official Kubernetes client-node Exec API for native execution.
5
+ * Supports both string and array command formats, and optional container targeting.
6
+ */
7
+ import { KubernetesManager } from "../types.js";
8
+ /**
9
+ * Schema for exec_in_pod tool.
10
+ * - name: Pod name
11
+ * - namespace: Namespace (default: "default")
12
+ * - command: Command to execute (string or array of args)
13
+ * - container: (Optional) Container name
14
+ */
15
+ export declare const execInPodSchema: {
16
+ name: string;
17
+ description: string;
18
+ inputSchema: {
19
+ type: string;
20
+ properties: {
21
+ name: {
22
+ type: string;
23
+ description: string;
24
+ };
25
+ namespace: {
26
+ type: string;
27
+ description: string;
28
+ default: string;
29
+ };
30
+ command: {
31
+ anyOf: ({
32
+ type: string;
33
+ items?: undefined;
34
+ } | {
35
+ type: string;
36
+ items: {
37
+ type: string;
38
+ };
39
+ })[];
40
+ description: string;
41
+ };
42
+ container: {
43
+ type: string;
44
+ description: string;
45
+ optional: boolean;
46
+ };
47
+ shell: {
48
+ type: string;
49
+ description: string;
50
+ optional: boolean;
51
+ };
52
+ timeout: {
53
+ type: string;
54
+ description: string;
55
+ optional: boolean;
56
+ };
57
+ };
58
+ required: string[];
59
+ };
60
+ };
61
+ /**
62
+ * Execute a command in a Kubernetes pod or container using the Kubernetes client-node Exec API.
63
+ * Returns the stdout output as a text response.
64
+ * Throws McpError on failure.
65
+ */
66
+ export declare function execInPod(k8sManager: KubernetesManager, input: {
67
+ name: string;
68
+ namespace?: string;
69
+ command: string | string[];
70
+ container?: string;
71
+ shell?: string;
72
+ timeout?: number;
73
+ }): Promise<{
74
+ content: {
75
+ type: string;
76
+ text: string;
77
+ }[];
78
+ }>;
@@ -0,0 +1,161 @@
1
+ /**
2
+ * Tool: exec_in_pod
3
+ * Execute a command in a Kubernetes pod or container and return the output.
4
+ * Uses the official Kubernetes client-node Exec API for native execution.
5
+ * Supports both string and array command formats, and optional container targeting.
6
+ */
7
+ import * as k8s from "@kubernetes/client-node";
8
+ import { McpError, ErrorCode } from "@modelcontextprotocol/sdk/types.js";
9
+ import { Writable } from "stream";
10
+ /**
11
+ * Schema for exec_in_pod tool.
12
+ * - name: Pod name
13
+ * - namespace: Namespace (default: "default")
14
+ * - command: Command to execute (string or array of args)
15
+ * - container: (Optional) Container name
16
+ */
17
+ export const execInPodSchema = {
18
+ name: "exec_in_pod",
19
+ description: "Execute a command in a Kubernetes pod or container and return the output",
20
+ inputSchema: {
21
+ type: "object",
22
+ properties: {
23
+ name: {
24
+ type: "string",
25
+ description: "Name of the pod to execute the command in",
26
+ },
27
+ namespace: {
28
+ type: "string",
29
+ description: "Kubernetes namespace where the pod is located",
30
+ default: "default",
31
+ },
32
+ command: {
33
+ anyOf: [
34
+ { type: "string" },
35
+ { type: "array", items: { type: "string" } }
36
+ ],
37
+ description: "Command to execute in the pod (string or array of args)",
38
+ },
39
+ container: {
40
+ type: "string",
41
+ description: "Container name (required when pod has multiple containers)",
42
+ optional: true,
43
+ },
44
+ shell: {
45
+ type: "string",
46
+ description: "Shell to use for command execution (e.g. '/bin/sh', '/bin/bash'). If not provided, will use command as-is.",
47
+ optional: true,
48
+ },
49
+ timeout: {
50
+ type: "number",
51
+ description: "Timeout for command - 60000 milliseconds if not specified",
52
+ optional: true,
53
+ },
54
+ },
55
+ required: ["name", "command"],
56
+ },
57
+ };
58
+ /**
59
+ * Execute a command in a Kubernetes pod or container using the Kubernetes client-node Exec API.
60
+ * Returns the stdout output as a text response.
61
+ * Throws McpError on failure.
62
+ */
63
+ export async function execInPod(k8sManager, input) {
64
+ const namespace = input.namespace || "default";
65
+ // Convert command to array of strings for the Exec API
66
+ let commandArr;
67
+ if (Array.isArray(input.command)) {
68
+ commandArr = input.command;
69
+ }
70
+ else {
71
+ // Always wrap string commands in a shell for correct parsing
72
+ const shell = input.shell || "/bin/sh";
73
+ commandArr = [shell, "-c", input.command];
74
+ console.log("[exec_in_pod] Using shell:", shell, "Command array:", commandArr);
75
+ }
76
+ // Prepare buffers to capture stdout and stderr
77
+ let stdout = "";
78
+ let stderr = "";
79
+ // Use Node.js Writable streams to collect output
80
+ const stdoutStream = new Writable({
81
+ write(chunk, _encoding, callback) {
82
+ stdout += chunk.toString();
83
+ callback();
84
+ }
85
+ });
86
+ const stderrStream = new Writable({
87
+ write(chunk, _encoding, callback) {
88
+ stderr += chunk.toString();
89
+ callback();
90
+ }
91
+ });
92
+ // Add a dummy stdin stream
93
+ const stdinStream = new Writable({
94
+ write(_chunk, _encoding, callback) {
95
+ callback();
96
+ }
97
+ });
98
+ try {
99
+ // Use the Kubernetes client-node Exec API for native exec
100
+ const kc = k8sManager.getKubeConfig();
101
+ const exec = new k8s.Exec(kc);
102
+ // Add a timeout to avoid hanging forever if exec never returns
103
+ await new Promise((resolve, reject) => {
104
+ let finished = false;
105
+ const timeoutMs = input.timeout || 60000;
106
+ const timeout = setTimeout(() => {
107
+ if (!finished) {
108
+ finished = true;
109
+ reject(new McpError(ErrorCode.InternalError, "Exec operation timed out (possible networking, RBAC, or cluster issue)"));
110
+ }
111
+ }, timeoutMs);
112
+ console.log("[exec_in_pod] Calling exec.exec with params:", {
113
+ namespace,
114
+ pod: input.name,
115
+ container: input.container ?? "",
116
+ commandArr,
117
+ stdoutStreamType: typeof stdoutStream,
118
+ stderrStreamType: typeof stderrStream,
119
+ });
120
+ exec.exec(namespace, input.name, input.container ?? "", commandArr, stdoutStream, stderrStream, stdinStream, // use dummy stdin
121
+ true, // set tty to true
122
+ (status) => {
123
+ console.log("[exec_in_pod] exec.exec callback called. Status:", status);
124
+ if (finished)
125
+ return;
126
+ finished = true;
127
+ clearTimeout(timeout);
128
+ // Always resolve; handle errors based on stderr or thrown errors
129
+ resolve();
130
+ }).catch((err) => {
131
+ console.log("[exec_in_pod] exec.exec threw error:", err);
132
+ if (!finished) {
133
+ finished = true;
134
+ clearTimeout(timeout);
135
+ reject(new McpError(ErrorCode.InternalError, `Exec threw error: ${err?.message || err}`));
136
+ }
137
+ });
138
+ });
139
+ // Return the collected stdout as the result
140
+ // If there is stderr output or no output at all, treat as error
141
+ if (stderr || (!stdout && !stderr)) {
142
+ throw new McpError(ErrorCode.InternalError, `Failed to execute command in pod: ${stderr || "No output"}`);
143
+ }
144
+ return {
145
+ content: [
146
+ {
147
+ type: "text",
148
+ text: stdout,
149
+ },
150
+ ],
151
+ };
152
+ }
153
+ catch (error) {
154
+ // Collect error message and stderr output if available
155
+ let message = error.message || "Unknown error";
156
+ if (stderr) {
157
+ message += "\n" + stderr;
158
+ }
159
+ throw new McpError(ErrorCode.InternalError, `Failed to execute command in pod: ${message}`);
160
+ }
161
+ }
@@ -0,0 +1,10 @@
1
+ export declare const pingSchema: {
2
+ name: string;
3
+ description: string;
4
+ inputSchema: {
5
+ type: string;
6
+ properties: {};
7
+ required: never[];
8
+ };
9
+ };
10
+ export declare function ping(): Promise<Record<string, never>>;
@@ -0,0 +1,12 @@
1
+ export const pingSchema = {
2
+ name: "ping",
3
+ description: "Verify that the counterpart is still responsive and the connection is alive.",
4
+ inputSchema: {
5
+ type: "object",
6
+ properties: {},
7
+ required: [],
8
+ },
9
+ };
10
+ export async function ping() {
11
+ return {};
12
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcp-server-kubernetes",
3
- "version": "2.4.2",
3
+ "version": "2.4.4",
4
4
  "description": "MCP server for interacting with Kubernetes clusters via kubectl",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -17,6 +17,7 @@
17
17
  ],
18
18
  "scripts": {
19
19
  "build": "tsc && shx chmod +x dist/*.js",
20
+ "builddxt": "node_modules/.bin/dxt pack",
20
21
  "dev": "tsc --watch",
21
22
  "start": "node dist/index.js",
22
23
  "test": "vitest run",
@@ -48,6 +49,7 @@
48
49
  "@types/node": "22.9.3",
49
50
  "shx": "0.3.4",
50
51
  "typescript": "5.6.2",
51
- "vitest": "2.1.9"
52
+ "vitest": "2.1.9",
53
+ "@anthropic-ai/dxt": "0.1.0"
52
54
  }
53
55
  }
@@ -1,59 +0,0 @@
1
- import { KubernetesManager } from "../types.js";
2
- export declare const kubectlListSchema: {
3
- readonly name: "kubectl_list";
4
- readonly description: "List Kubernetes resources by resource type and optionally namespace";
5
- readonly inputSchema: {
6
- readonly type: "object";
7
- readonly properties: {
8
- readonly resourceType: {
9
- readonly type: "string";
10
- readonly description: "Type of resource to list (e.g., pods, deployments, services, configmaps, etc.)";
11
- };
12
- readonly namespace: {
13
- readonly type: "string";
14
- readonly description: "Namespace of the resources (optional - defaults to 'default' for namespaced resources)";
15
- readonly default: "default";
16
- };
17
- readonly output: {
18
- readonly type: "string";
19
- readonly enum: readonly ["json", "yaml", "wide", "name", "custom", "formatted"];
20
- readonly description: "Output format - 'formatted' uses a resource-specific format with key information";
21
- readonly default: "formatted";
22
- };
23
- readonly allNamespaces: {
24
- readonly type: "boolean";
25
- readonly description: "If true, list resources across all namespaces";
26
- readonly default: false;
27
- };
28
- readonly labelSelector: {
29
- readonly type: "string";
30
- readonly description: "Filter resources by label selector (e.g. 'app=nginx')";
31
- };
32
- readonly fieldSelector: {
33
- readonly type: "string";
34
- readonly description: "Filter resources by field selector (e.g. 'metadata.name=my-pod')";
35
- };
36
- };
37
- readonly required: readonly ["resourceType", "namespace"];
38
- };
39
- };
40
- export declare function kubectlList(k8sManager: KubernetesManager, input: {
41
- resourceType: string;
42
- namespace?: string;
43
- output?: string;
44
- allNamespaces?: boolean;
45
- labelSelector?: string;
46
- fieldSelector?: string;
47
- }): Promise<{
48
- content: {
49
- type: string;
50
- text: string;
51
- }[];
52
- isError?: undefined;
53
- } | {
54
- content: {
55
- type: string;
56
- text: string;
57
- }[];
58
- isError: boolean;
59
- }>;
@@ -1,187 +0,0 @@
1
- import { kubectlGet } from "./kubectl-get.js";
2
- import { execSync } from "child_process";
3
- import { McpError, ErrorCode } from "@modelcontextprotocol/sdk/types.js";
4
- export const kubectlListSchema = {
5
- name: "kubectl_list",
6
- description: "List Kubernetes resources by resource type and optionally namespace",
7
- inputSchema: {
8
- type: "object",
9
- properties: {
10
- resourceType: {
11
- type: "string",
12
- description: "Type of resource to list (e.g., pods, deployments, services, configmaps, etc.)"
13
- },
14
- namespace: {
15
- type: "string",
16
- description: "Namespace of the resources (optional - defaults to 'default' for namespaced resources)",
17
- default: "default"
18
- },
19
- output: {
20
- type: "string",
21
- enum: ["json", "yaml", "wide", "name", "custom", "formatted"],
22
- description: "Output format - 'formatted' uses a resource-specific format with key information",
23
- default: "formatted"
24
- },
25
- allNamespaces: {
26
- type: "boolean",
27
- description: "If true, list resources across all namespaces",
28
- default: false
29
- },
30
- labelSelector: {
31
- type: "string",
32
- description: "Filter resources by label selector (e.g. 'app=nginx')"
33
- },
34
- fieldSelector: {
35
- type: "string",
36
- description: "Filter resources by field selector (e.g. 'metadata.name=my-pod')"
37
- }
38
- },
39
- required: ["resourceType", "namespace"],
40
- },
41
- };
42
- export async function kubectlList(k8sManager, input) {
43
- try {
44
- const resourceType = input.resourceType.toLowerCase();
45
- const namespace = input.namespace || "default";
46
- const output = input.output || "formatted";
47
- const allNamespaces = input.allNamespaces || false;
48
- const labelSelector = input.labelSelector || "";
49
- const fieldSelector = input.fieldSelector || "";
50
- // If not using formatted output, delegate to kubectl_get
51
- if (output !== "formatted") {
52
- return await kubectlGet(k8sManager, {
53
- resourceType: input.resourceType,
54
- namespace: input.namespace,
55
- output: input.output,
56
- allNamespaces: input.allNamespaces,
57
- labelSelector: input.labelSelector,
58
- fieldSelector: input.fieldSelector
59
- });
60
- }
61
- // For formatted output, we'll use resource-specific custom columns
62
- let customColumns = "";
63
- switch (resourceType) {
64
- case "pods":
65
- case "pod":
66
- case "po":
67
- customColumns = "NAME:.metadata.name,NAMESPACE:.metadata.namespace,STATUS:.status.phase,NODE:.spec.nodeName,IP:.status.podIP,AGE:.metadata.creationTimestamp";
68
- break;
69
- case "deployments":
70
- case "deployment":
71
- case "deploy":
72
- customColumns = "NAME:.metadata.name,NAMESPACE:.metadata.namespace,READY:.status.readyReplicas/.status.replicas,UP-TO-DATE:.status.updatedReplicas,AVAILABLE:.status.availableReplicas,AGE:.metadata.creationTimestamp";
73
- break;
74
- case "services":
75
- case "service":
76
- case "svc":
77
- customColumns = "NAME:.metadata.name,NAMESPACE:.metadata.namespace,TYPE:.spec.type,CLUSTER-IP:.spec.clusterIP,EXTERNAL-IP:.status.loadBalancer.ingress[0].ip,PORTS:.spec.ports[*].port,AGE:.metadata.creationTimestamp";
78
- break;
79
- case "nodes":
80
- case "node":
81
- case "no":
82
- customColumns = "NAME:.metadata.name,STATUS:.status.conditions[?(@.type==\"Ready\")].status,ROLES:.metadata.labels.kubernetes\\.io/role,VERSION:.status.nodeInfo.kubeletVersion,INTERNAL-IP:.status.addresses[?(@.type==\"InternalIP\")].address,OS-IMAGE:.status.nodeInfo.osImage,KERNEL-VERSION:.status.nodeInfo.kernelVersion,CONTAINER-RUNTIME:.status.nodeInfo.containerRuntimeVersion";
83
- break;
84
- case "namespaces":
85
- case "namespace":
86
- case "ns":
87
- customColumns = "NAME:.metadata.name,STATUS:.status.phase,AGE:.metadata.creationTimestamp";
88
- break;
89
- case "persistentvolumes":
90
- case "pv":
91
- customColumns = "NAME:.metadata.name,CAPACITY:.spec.capacity.storage,ACCESS_MODES:.spec.accessModes,RECLAIM_POLICY:.spec.persistentVolumeReclaimPolicy,STATUS:.status.phase,CLAIM:.spec.claimRef.name,STORAGECLASS:.spec.storageClassName,AGE:.metadata.creationTimestamp";
92
- break;
93
- case "persistentvolumeclaims":
94
- case "pvc":
95
- customColumns = "NAME:.metadata.name,NAMESPACE:.metadata.namespace,STATUS:.status.phase,VOLUME:.spec.volumeName,CAPACITY:.status.capacity.storage,ACCESS_MODES:.spec.accessModes,STORAGECLASS:.spec.storageClassName,AGE:.metadata.creationTimestamp";
96
- break;
97
- case "configmaps":
98
- case "configmap":
99
- case "cm":
100
- customColumns = "NAME:.metadata.name,NAMESPACE:.metadata.namespace,DATA:.data,AGE:.metadata.creationTimestamp";
101
- break;
102
- case "secrets":
103
- case "secret":
104
- customColumns = "NAME:.metadata.name,NAMESPACE:.metadata.namespace,TYPE:.type,DATA:.data,AGE:.metadata.creationTimestamp";
105
- break;
106
- case "jobs":
107
- case "job":
108
- customColumns = "NAME:.metadata.name,NAMESPACE:.metadata.namespace,COMPLETIONS:.status.succeeded/.spec.completions,DURATION:.status.completionTime-(.status.startTime),AGE:.metadata.creationTimestamp";
109
- break;
110
- case "cronjobs":
111
- case "cronjob":
112
- case "cj":
113
- customColumns = "NAME:.metadata.name,NAMESPACE:.metadata.namespace,SCHEDULE:.spec.schedule,SUSPEND:.spec.suspend,ACTIVE:.status.active,LAST_SCHEDULE:.status.lastScheduleTime,AGE:.metadata.creationTimestamp";
114
- break;
115
- default:
116
- // For unknown resource types, fall back to a generic format
117
- customColumns = "NAME:.metadata.name,NAMESPACE:.metadata.namespace,KIND:.kind,AGE:.metadata.creationTimestamp";
118
- break;
119
- }
120
- // Build the kubectl command
121
- let command = "kubectl get ";
122
- // Add resource type
123
- command += resourceType;
124
- // Add namespace flag unless all namespaces is specified
125
- if (allNamespaces) {
126
- command += " --all-namespaces";
127
- }
128
- else if (namespace && !isNonNamespacedResource(resourceType)) {
129
- command += ` -n ${namespace}`;
130
- }
131
- // Add label selector if provided
132
- if (labelSelector) {
133
- command += ` -l ${labelSelector}`;
134
- }
135
- // Add field selector if provided
136
- if (fieldSelector) {
137
- command += ` --field-selector=${fieldSelector}`;
138
- }
139
- // Add custom columns format
140
- command += ` -o custom-columns="${customColumns}"`;
141
- // Execute the command
142
- try {
143
- const result = execSync(command, { encoding: "utf8", env: { ...process.env, KUBECONFIG: process.env.KUBECONFIG } });
144
- return {
145
- content: [
146
- {
147
- type: "text",
148
- text: result,
149
- },
150
- ],
151
- };
152
- }
153
- catch (error) {
154
- if (error.status === 404 || error.message.includes("not found")) {
155
- return {
156
- content: [
157
- {
158
- type: "text",
159
- text: JSON.stringify({
160
- error: `Resource type ${resourceType} not found or no resources exist`,
161
- status: "not_found",
162
- }, null, 2),
163
- },
164
- ],
165
- isError: true,
166
- };
167
- }
168
- throw new McpError(ErrorCode.InternalError, `Failed to list resources: ${error.message}`);
169
- }
170
- }
171
- catch (error) {
172
- throw new McpError(ErrorCode.InternalError, `Failed to execute kubectl list command: ${error.message}`);
173
- }
174
- }
175
- // Helper function to determine if a resource is non-namespaced
176
- function isNonNamespacedResource(resourceType) {
177
- const nonNamespacedResources = [
178
- "nodes", "node", "no",
179
- "namespaces", "namespace", "ns",
180
- "persistentvolumes", "pv",
181
- "storageclasses", "sc",
182
- "clusterroles",
183
- "clusterrolebindings",
184
- "customresourcedefinitions", "crd", "crds"
185
- ];
186
- return nonNamespacedResources.includes(resourceType.toLowerCase());
187
- }