mcp-server-kubernetes 0.3.0 → 0.3.2

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
@@ -1,4 +1,15 @@
1
- # mcp-server-kubernetes
1
+ # MCP Server Kubernetes
2
+
3
+ [![CI](https://github.com/Flux159/mcp-server-kubernetes/actions/workflows/ci.yml/badge.svg)](https://github.com/yourusername/mcp-server-kubernetes/actions/workflows/ci.yml)
4
+ [![Language](https://img.shields.io/github/languages/top/Flux159/mcp-server-kubernetes)](https://github.com/yourusername/mcp-server-kubernetes)
5
+ [![Bun](https://img.shields.io/badge/runtime-bun-orange)](https://bun.sh)
6
+ [![Kubernetes](https://img.shields.io/badge/kubernetes-%23326ce5.svg?style=flat&logo=kubernetes&logoColor=white)](https://kubernetes.io/)
7
+ [![Docker](https://img.shields.io/badge/docker-%230db7ed.svg?style=flat&logo=docker&logoColor=white)](https://www.docker.com/)
8
+ [![Stars](https://img.shields.io/github/stars/Flux159/mcp-server-kubernetes)](https://github.com/Flux159/mcp-server-kubernetes/stargazers)
9
+ [![Issues](https://img.shields.io/github/issues/Flux159/mcp-server-kubernetes)](https://github.com/Flux159/mcp-server-kubernetes/issues)
10
+ [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/Flux159/mcp-server-kubernetes/pulls)
11
+ [![Last Commit](https://img.shields.io/github/last-commit/Flux159/mcp-server-kubernetes)](https://github.com/Flux159/mcp-server-kubernetes/commits/main)
12
+ [![smithery badge](https://smithery.ai/badge/mcp-server-kubernetes)](https://smithery.ai/protocol/mcp-server-kubernetes)
2
13
 
3
14
  MCP Server that can connect to a Kubernetes cluster and manage it.
4
15
 
@@ -30,6 +41,28 @@ You can verify your connection by asking Claude to list your pods or create a te
30
41
 
31
42
  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
43
 
44
+ ## Usage with mcp-chat
45
+
46
+ [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.
47
+
48
+ ```shell
49
+ npx mcp-chat --server "npx mcp-server-kubernetes"
50
+ ```
51
+
52
+ Alternatively, pass it your existing Claude Desktop configuration file from above (Linux should pass the correct path to config):
53
+
54
+ Mac:
55
+
56
+ ```shell
57
+ npx mcp-chat --config "~/Library/Application Support/Claude/claude_desktop_config.json"
58
+ ```
59
+
60
+ Windows:
61
+
62
+ ```shell
63
+ npx mcp-chat --config "%APPDATA%\Claude\claude_desktop_config.json"
64
+ ```
65
+
33
66
  ## Features
34
67
 
35
68
  - [x] Connect to a Kubernetes cluster
@@ -50,6 +83,7 @@ If you have errors open up a standard terminal and run `kubectl get pods` to see
50
83
  - Support for version specification
51
84
  - Support for custom repositories
52
85
  - [x] kubectl explain and kubectl api-resources support
86
+ - [x] Get Kubernetes events from the cluster
53
87
  - [ ] Port forward to a pod
54
88
  - [ ] Choose namespace for next commands (memory)
55
89
 
@@ -88,34 +122,60 @@ npx @modelcontextprotocol/inspector node build/index.js
88
122
  # Follow further instructions on terminal for Inspector link
89
123
  ```
90
124
 
125
+ 5. Local testing with [mcp-chat](https://github.com/Flux159/mcp-chat)
126
+
127
+ ```bash
128
+ npm run chat
129
+ ```
130
+
91
131
  ### Project Structure
92
132
 
93
133
  ```
94
134
  ├── src/
95
135
  │ ├── index.ts # Main server implementation
96
136
  │ ├── types.ts # Type re-exports
97
- │ ├── config/ # Configuration files
137
+ │ ├── config/ # Configuration files
98
138
  │ │ ├── container-templates.ts # Container configurations
99
- │ │ ├── server-config.ts # Server settings
139
+ │ │ ├── server-config.ts # Server settings
100
140
  │ │ ├── deployment-config.ts # Deployment schemas
101
- │ │ └── ...
102
- ├── models/ # Data models and schemas
103
- ├── response-schemas.ts # API response schemas
104
- │ │ ├── resource-models.ts # Resource models
105
- │ │ └── tool-models.ts # Tool schemas
106
- │ ├── utils/ # Utility classes
107
- │ │ └── kubernetes-manager.ts # K8s management
108
- ├── resources/ # Resource handlers
109
- │ └── handlers.ts # Resource implementation
110
- │ └── tools/ # Tool implementations
111
- ├── list_pods.ts
112
- ├── list_services.ts
113
- ├── list_deployments.ts
114
- └── ...
115
- ├── tests/ # Test files
116
- └── unit.test.ts # Unit tests
117
- └── helm.test.ts # Helm tests
118
- └── ...
141
+ │ │ ├── namespace-config.ts # Namespace schemas
142
+ │ └── cleanup-config.ts # Resource cleanup configuration
143
+ │ ├── models/ # Data models and schemas
144
+ │ │ ├── response-schemas.ts # API response schemas
145
+ │ │ ├── resource-models.ts # Resource models
146
+ ├── tool-models.ts # Tool schemas
147
+ │ │ ├── helm-models.ts # Helm operation schemas
148
+ │ └── kubectl-models.ts # Kubectl operation schemas
149
+ ├── utils/ # Utility classes
150
+ └── kubernetes-manager.ts # K8s management
151
+ ├── resources/ # Resource handlers
152
+ │ └── handlers.ts # Resource implementation
153
+ └── tools/ # Tool implementations
154
+ ├── list_pods.ts # Pod listing operations
155
+ ├── list_services.ts # Service listing operations
156
+ ├── list_deployments.ts # Deployment listing operations
157
+ ├── list_nodes.ts # Node listing operations
158
+ │ ├── create_pod.ts # Pod creation operations
159
+ │ ├── delete_pod.ts # Pod deletion operations
160
+ │ ├── describe_pod.ts # Pod description operations
161
+ │ ├── get_logs.ts # Container logs operations
162
+ │ ├── get_events.ts # Kubernetes events operations
163
+ │ ├── helm-operations.ts # Helm chart operations
164
+ │ └── kubectl-operations.ts # Kubectl utility operations
165
+ ├── tests/ # Test files
166
+ │ ├── unit.test.ts # Unit tests for basic operations
167
+ │ ├── helm.test.ts # Helm-specific tests
168
+ │ └── kubectl.test.ts # Kubectl-specific tests
169
+ ├── .github/ # GitHub configuration
170
+ │ └── workflows/ # CI/CD workflows
171
+ │ ├── ci.yml # Continuous integration
172
+ │ └── cd.yml # Continuous deployment
173
+ ├── Dockerfile # Docker container definition
174
+ ├── LICENSE # MIT license
175
+ ├── README.md # Project documentation
176
+ ├── package.json # NPM package configuration
177
+ ├── tsconfig.json # TypeScript configuration
178
+ └── vitest.config.ts # Test configuration
119
179
  ```
120
180
 
121
181
  ### Contributing
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.2",
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",