mcp-server-kubernetes 0.3.0 → 0.3.1

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
@@ -6,6 +6,8 @@ https://github.com/user-attachments/assets/f25f8f4e-4d04-479b-9ae0-5dac452dd2ed
6
6
 
7
7
  <a href="https://glama.ai/mcp/servers/w71ieamqrt"><img width="380" height="200" src="https://glama.ai/mcp/servers/w71ieamqrt/badge" /></a>
8
8
 
9
+ [![smithery badge](https://smithery.ai/badge/mcp-server-kubernetes)](https://smithery.ai/server/mcp-server-kubernetes)
10
+
9
11
  ## Usage with Claude Desktop
10
12
 
11
13
  ```json
@@ -30,6 +32,28 @@ You can verify your connection by asking Claude to list your pods or create a te
30
32
 
31
33
  If you have errors open up a standard terminal and run `kubectl get pods` to see if you can connect to your cluster without credentials issues.
32
34
 
35
+ ## Usage with mcp-chat
36
+
37
+ [mcp-chat](https://github.com/Flux159/mcp-chat) is a CLI chat client for MCP servers. You can use it to interact with the Kubernetes server.
38
+
39
+ ```shell
40
+ npx mcp-chat --server "npx mcp-server-kubernetes"
41
+ ```
42
+
43
+ Alternatively, pass it your existing Claude Desktop configuration file from above (Linux should pass the correct path to config):
44
+
45
+ Mac:
46
+
47
+ ```shell
48
+ npx mcp-chat --config "~/Library/Application Support/Claude/claude_desktop_config.json"
49
+ ```
50
+
51
+ Windows:
52
+
53
+ ```shell
54
+ npx mcp-chat --config "%APPDATA%\Claude\claude_desktop_config.json"
55
+ ```
56
+
33
57
  ## Features
34
58
 
35
59
  - [x] Connect to a Kubernetes cluster
@@ -50,6 +74,7 @@ If you have errors open up a standard terminal and run `kubectl get pods` to see
50
74
  - Support for version specification
51
75
  - Support for custom repositories
52
76
  - [x] kubectl explain and kubectl api-resources support
77
+ - [x] Get Kubernetes events from the cluster
53
78
  - [ ] Port forward to a pod
54
79
  - [ ] Choose namespace for next commands (memory)
55
80
 
@@ -88,6 +113,12 @@ npx @modelcontextprotocol/inspector node build/index.js
88
113
  # Follow further instructions on terminal for Inspector link
89
114
  ```
90
115
 
116
+ 5. Local testing with [mcp-chat](https://github.com/Flux159/mcp-chat)
117
+
118
+ ```bash
119
+ npm run chat
120
+ ```
121
+
91
122
  ### Project Structure
92
123
 
93
124
  ```
package/dist/index.js CHANGED
@@ -11,6 +11,7 @@ import { createPod, createPodSchema } from "./tools/create_pod.js";
11
11
  import { deletePod, deletePodSchema } from "./tools/delete_pod.js";
12
12
  import { describePod, describePodSchema } from "./tools/describe_pod.js";
13
13
  import { getLogs, getLogsSchema } from "./tools/get_logs.js";
14
+ import { getEvents, getEventsSchema } from "./tools/get_events.js";
14
15
  import { getResourceHandlers } from "./resources/handlers.js";
15
16
  import { ListResourcesRequestSchema, ReadResourceRequestSchema, ListToolsRequestSchema, CallToolRequestSchema, ErrorCode, McpError, } from "@modelcontextprotocol/sdk/types.js";
16
17
  import { KubernetesManager } from "./types.js";
@@ -27,22 +28,23 @@ const server = new Server({
27
28
  server.setRequestHandler(ListToolsRequestSchema, async () => {
28
29
  return {
29
30
  tools: [
30
- listPodsSchema,
31
- listDeploymentsSchema,
32
- listServicesSchema,
33
- listNamespacesSchema,
34
- createPodSchema,
31
+ cleanupSchema,
35
32
  createDeploymentSchema,
33
+ createPodSchema,
36
34
  deletePodSchema,
37
35
  describePodSchema,
38
- cleanupSchema,
39
- listNodesSchema,
36
+ explainResourceSchema,
37
+ getEventsSchema,
40
38
  getLogsSchema,
41
39
  installHelmChartSchema,
42
- upgradeHelmChartSchema,
43
- uninstallHelmChartSchema,
44
- explainResourceSchema,
45
40
  listApiResourcesSchema,
41
+ listDeploymentsSchema,
42
+ listNamespacesSchema,
43
+ listNodesSchema,
44
+ listPodsSchema,
45
+ listServicesSchema,
46
+ uninstallHelmChartSchema,
47
+ upgradeHelmChartSchema,
46
48
  ],
47
49
  };
48
50
  });
@@ -50,27 +52,15 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
50
52
  try {
51
53
  const { name, arguments: input = {} } = request.params;
52
54
  switch (name) {
53
- case "list_pods": {
54
- return await listPods(k8sManager, input);
55
- }
56
- case "list_deployments": {
57
- return await listDeployments(k8sManager, input);
58
- }
59
- case "list_services": {
60
- return await listServices(k8sManager, input);
61
- }
62
- case "list_namespaces": {
63
- const { body } = await k8sManager.getCoreApi().listNamespace();
64
- const namespaces = body.items.map((ns) => ({
65
- name: ns.metadata?.name || "",
66
- status: ns.status?.phase || "",
67
- createdAt: ns.metadata?.creationTimestamp,
68
- }));
55
+ case "cleanup": {
56
+ await k8sManager.cleanup();
69
57
  return {
70
58
  content: [
71
59
  {
72
60
  type: "text",
73
- text: JSON.stringify({ namespaces }, null, 2),
61
+ text: JSON.stringify({
62
+ success: true,
63
+ }, null, 2),
74
64
  },
75
65
  ],
76
66
  };
@@ -84,15 +74,36 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
84
74
  case "describe_pod": {
85
75
  return await describePod(k8sManager, input);
86
76
  }
87
- case "cleanup": {
88
- await k8sManager.cleanup();
77
+ case "explain_resource": {
78
+ return await explainResource(input);
79
+ }
80
+ case "get_events": {
81
+ return await getEvents(k8sManager, input);
82
+ }
83
+ case "get_logs": {
84
+ return await getLogs(k8sManager, input);
85
+ }
86
+ case "install_helm_chart": {
87
+ return await installHelmChart(input);
88
+ }
89
+ case "list_api_resources": {
90
+ return await listApiResources(input);
91
+ }
92
+ case "list_deployments": {
93
+ return await listDeployments(k8sManager, input);
94
+ }
95
+ case "list_namespaces": {
96
+ const { body } = await k8sManager.getCoreApi().listNamespace();
97
+ const namespaces = body.items.map((ns) => ({
98
+ name: ns.metadata?.name || "",
99
+ status: ns.status?.phase || "",
100
+ createdAt: ns.metadata?.creationTimestamp,
101
+ }));
89
102
  return {
90
103
  content: [
91
104
  {
92
105
  type: "text",
93
- text: JSON.stringify({
94
- success: true,
95
- }, null, 2),
106
+ text: JSON.stringify({ namespaces }, null, 2),
96
107
  },
97
108
  ],
98
109
  };
@@ -100,23 +111,17 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
100
111
  case "list_nodes": {
101
112
  return await listNodes(k8sManager);
102
113
  }
103
- case "get_logs": {
104
- return await getLogs(k8sManager, input);
105
- }
106
- case "install_helm_chart": {
107
- return await installHelmChart(input);
114
+ case "list_pods": {
115
+ return await listPods(k8sManager, input);
108
116
  }
109
- case "upgrade_helm_chart": {
110
- return await upgradeHelmChart(input);
117
+ case "list_services": {
118
+ return await listServices(k8sManager, input);
111
119
  }
112
120
  case "uninstall_helm_chart": {
113
121
  return await uninstallHelmChart(input);
114
122
  }
115
- case "explain_resource": {
116
- return await explainResource(input);
117
- }
118
- case "list_api_resources": {
119
- return await listApiResources(input);
123
+ case "upgrade_helm_chart": {
124
+ return await upgradeHelmChart(input);
120
125
  }
121
126
  default:
122
127
  throw new McpError(ErrorCode.InvalidRequest, `Unknown tool: ${name}`);
@@ -219,3 +219,25 @@ export declare const GetLogsResponseSchema: z.ZodObject<{
219
219
  text: string;
220
220
  }[];
221
221
  }>;
222
+ export declare const GetEventsResponseSchema: z.ZodObject<{
223
+ content: z.ZodArray<z.ZodObject<{
224
+ type: z.ZodLiteral<"text">;
225
+ text: z.ZodString;
226
+ }, "strip", z.ZodTypeAny, {
227
+ type: "text";
228
+ text: string;
229
+ }, {
230
+ type: "text";
231
+ text: string;
232
+ }>, "many">;
233
+ }, "strip", z.ZodTypeAny, {
234
+ content: {
235
+ type: "text";
236
+ text: string;
237
+ }[];
238
+ }, {
239
+ content: {
240
+ type: "text";
241
+ text: string;
242
+ }[];
243
+ }>;
@@ -34,3 +34,6 @@ export const ListNodesResponseSchema = z.object({
34
34
  export const GetLogsResponseSchema = z.object({
35
35
  content: z.array(ToolResponseContent),
36
36
  });
37
+ export const GetEventsResponseSchema = z.object({
38
+ content: z.array(ToolResponseContent),
39
+ });
@@ -0,0 +1,28 @@
1
+ import { KubernetesManager } from "../types.js";
2
+ export declare const getEventsSchema: {
3
+ name: string;
4
+ description: string;
5
+ inputSchema: {
6
+ type: string;
7
+ properties: {
8
+ namespace: {
9
+ type: string;
10
+ description: string;
11
+ };
12
+ fieldSelector: {
13
+ type: string;
14
+ description: string;
15
+ };
16
+ };
17
+ required: never[];
18
+ };
19
+ };
20
+ export declare function getEvents(k8sManager: KubernetesManager, params: {
21
+ namespace?: string;
22
+ fieldSelector?: string;
23
+ }): Promise<{
24
+ content: {
25
+ type: string;
26
+ text: string;
27
+ }[];
28
+ }>;
@@ -0,0 +1,66 @@
1
+ export const getEventsSchema = {
2
+ name: "get_events",
3
+ description: "Get Kubernetes events from the cluster",
4
+ inputSchema: {
5
+ type: "object",
6
+ properties: {
7
+ namespace: {
8
+ type: "string",
9
+ description: "Namespace to get events from. If not specified, gets events from all namespaces",
10
+ },
11
+ fieldSelector: {
12
+ type: "string",
13
+ description: "Field selector to filter events",
14
+ },
15
+ },
16
+ required: [],
17
+ },
18
+ };
19
+ export async function getEvents(k8sManager, params) {
20
+ const { namespace, fieldSelector } = params;
21
+ const api = k8sManager.getCoreApi();
22
+ let events;
23
+ if (namespace) {
24
+ const { body } = await api.listNamespacedEvent(namespace, undefined, // pretty
25
+ undefined, // allowWatchBookmarks
26
+ undefined, // _continue
27
+ undefined, // fieldSelector
28
+ fieldSelector // fieldSelector
29
+ );
30
+ events = body;
31
+ }
32
+ else {
33
+ const { body } = await api.listEventForAllNamespaces(undefined, // allowWatchBookmarks
34
+ undefined, // _continue
35
+ fieldSelector, // fieldSelector
36
+ undefined, // labelSelector
37
+ undefined, // limit
38
+ undefined, // pretty
39
+ undefined, // resourceVersion
40
+ undefined, // resourceVersionMatch
41
+ undefined // timeoutSeconds
42
+ );
43
+ events = body;
44
+ }
45
+ const formattedEvents = events.items.map((event) => ({
46
+ type: event.type || "",
47
+ reason: event.reason || "",
48
+ message: event.message || "",
49
+ involvedObject: {
50
+ kind: event.involvedObject.kind || "",
51
+ name: event.involvedObject.name || "",
52
+ namespace: event.involvedObject.namespace || "",
53
+ },
54
+ firstTimestamp: event.firstTimestamp || "",
55
+ lastTimestamp: event.lastTimestamp || "",
56
+ count: event.count || 0,
57
+ }));
58
+ return {
59
+ content: [
60
+ {
61
+ type: "text",
62
+ text: JSON.stringify({ events: formattedEvents }, null, 2),
63
+ },
64
+ ],
65
+ };
66
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcp-server-kubernetes",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "MCP server for interacting with Kubernetes clusters via kubectl",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -21,7 +21,8 @@
21
21
  "start": "node dist/index.js",
22
22
  "test": "vitest run",
23
23
  "prepublishOnly": "npm run build",
24
- "dockerbuild": "docker buildx build -t flux159/mcp-server-kubernetes --platform linux/amd64,linux/arm64 --push ."
24
+ "dockerbuild": "docker buildx build -t flux159/mcp-server-kubernetes --platform linux/amd64,linux/arm64 --push .",
25
+ "chat": "npx mcp-chat --server \"./dist/index.js\""
25
26
  },
26
27
  "keywords": [
27
28
  "mcp",