mcp-server-kubernetes 1.0.1 → 1.2.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.
- package/README.md +5 -10
- package/dist/index.js +42 -1
- package/dist/models/response-schemas.d.ts +176 -0
- package/dist/models/response-schemas.js +30 -0
- package/dist/tools/create_cronjob.d.ts +47 -0
- package/dist/tools/create_cronjob.js +93 -0
- package/dist/tools/delete_cronjob.d.ts +26 -0
- package/dist/tools/delete_cronjob.js +48 -0
- package/dist/tools/delete_namespace.d.ts +27 -0
- package/dist/tools/delete_namespace.js +44 -0
- package/dist/tools/describe_cronjob.d.ts +27 -0
- package/dist/tools/describe_cronjob.js +83 -0
- package/dist/tools/get_job_logs.d.ts +40 -0
- package/dist/tools/get_job_logs.js +104 -0
- package/dist/tools/list_cronjobs.d.ts +23 -0
- package/dist/tools/list_cronjobs.js +35 -0
- package/dist/tools/list_jobs.d.ts +29 -0
- package/dist/tools/list_jobs.js +77 -0
- package/dist/tools/scale_deployment.d.ts +30 -0
- package/dist/tools/scale_deployment.js +50 -0
- package/dist/utils/kubernetes-manager.d.ts +2 -0
- package/dist/utils/kubernetes-manager.js +8 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -66,16 +66,10 @@ npx mcp-chat --config "%APPDATA%\Claude\claude_desktop_config.json"
|
|
|
66
66
|
## Features
|
|
67
67
|
|
|
68
68
|
- [x] Connect to a Kubernetes cluster
|
|
69
|
-
- [x] List all pods
|
|
70
|
-
- [x]
|
|
71
|
-
- [x] List all
|
|
72
|
-
- [x]
|
|
73
|
-
- [x] Create a pod
|
|
74
|
-
- [x] Delete a pod
|
|
75
|
-
- [x] Describe a pod
|
|
76
|
-
- [x] List all namespaces
|
|
77
|
-
- [x] Create a namespace
|
|
78
|
-
- [x] Create custom pod & deployment configs
|
|
69
|
+
- [x] List all pods, services, deployments, nodes
|
|
70
|
+
- [x] Create, describe, delete a pod
|
|
71
|
+
- [x] List all namespaces, create a namespace
|
|
72
|
+
- [x] Create custom pod & deployment configs, update deployment replicas
|
|
79
73
|
- [x] Get logs from a pod for debugging (supports pods, deployments, jobs, and label selectors)
|
|
80
74
|
- [x] Support Helm v3 for installing charts
|
|
81
75
|
- Install charts with custom values
|
|
@@ -87,6 +81,7 @@ npx mcp-chat --config "%APPDATA%\Claude\claude_desktop_config.json"
|
|
|
87
81
|
- [x] kubectl explain and kubectl api-resources support
|
|
88
82
|
- [x] Get Kubernetes events from the cluster
|
|
89
83
|
- [x] Port forward to a pod or service
|
|
84
|
+
- [x] Create, list, and decribe cronjobs
|
|
90
85
|
|
|
91
86
|
## Local Development
|
|
92
87
|
|
package/dist/index.js
CHANGED
|
@@ -5,10 +5,16 @@ import { listPods, listPodsSchema } from "./tools/list_pods.js";
|
|
|
5
5
|
import { listNodes, listNodesSchema } from "./tools/list_nodes.js";
|
|
6
6
|
import { listServices, listServicesSchema } from "./tools/list_services.js";
|
|
7
7
|
import { listDeployments, listDeploymentsSchema, } from "./tools/list_deployments.js";
|
|
8
|
+
import { listCronJobs, listCronJobsSchema } from "./tools/list_cronjobs.js";
|
|
9
|
+
import { describeCronJob, describeCronJobSchema } from "./tools/describe_cronjob.js";
|
|
10
|
+
import { listJobs, listJobsSchema } from "./tools/list_jobs.js";
|
|
11
|
+
import { getJobLogs, getJobLogsSchema } from "./tools/get_job_logs.js";
|
|
8
12
|
import { installHelmChart, installHelmChartSchema, upgradeHelmChart, upgradeHelmChartSchema, uninstallHelmChart, uninstallHelmChartSchema, } from "./tools/helm-operations.js";
|
|
9
13
|
import { explainResource, explainResourceSchema, listApiResources, listApiResourcesSchema, } from "./tools/kubectl-operations.js";
|
|
10
14
|
import { createNamespace, createNamespaceSchema, } from "./tools/create_namespace.js";
|
|
11
15
|
import { createPod, createPodSchema } from "./tools/create_pod.js";
|
|
16
|
+
import { createCronJob, createCronJobSchema } from "./tools/create_cronjob.js";
|
|
17
|
+
import { DeleteCronJob, DeleteCronJobSchema } from "./tools/delete_cronjob.js";
|
|
12
18
|
import { deletePod, deletePodSchema } from "./tools/delete_pod.js";
|
|
13
19
|
import { describePod, describePodSchema } from "./tools/describe_pod.js";
|
|
14
20
|
import { getLogs, getLogsSchema } from "./tools/get_logs.js";
|
|
@@ -19,11 +25,13 @@ import { KubernetesManager } from "./types.js";
|
|
|
19
25
|
import { serverConfig } from "./config/server-config.js";
|
|
20
26
|
import { createDeploymentSchema } from "./config/deployment-config.js";
|
|
21
27
|
import { listNamespacesSchema } from "./config/namespace-config.js";
|
|
28
|
+
import { deleteNamespace, deleteNamespaceSchema } from "./tools/delete_namespace.js";
|
|
22
29
|
import { cleanupSchema } from "./config/cleanup-config.js";
|
|
23
30
|
import { startSSEServer } from "./utils/sse.js";
|
|
24
31
|
import { startPortForward, PortForwardSchema, stopPortForward, StopPortForwardSchema, } from "./tools/port_forward.js";
|
|
25
|
-
import { deleteDeployment } from "./tools/delete_deployment.js";
|
|
32
|
+
import { deleteDeployment, deleteDeploymentSchema } from "./tools/delete_deployment.js";
|
|
26
33
|
import { createDeployment } from "./tools/create_deployment.js";
|
|
34
|
+
import { scaleDeployment, scaleDeploymentSchema } from "./tools/scale_deployment.js";
|
|
27
35
|
import { describeDeployment, describeDeploymentSchema, } from "./tools/describe_deployment.js";
|
|
28
36
|
const k8sManager = new KubernetesManager();
|
|
29
37
|
const server = new Server({
|
|
@@ -38,15 +46,22 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
38
46
|
createDeploymentSchema,
|
|
39
47
|
createNamespaceSchema,
|
|
40
48
|
createPodSchema,
|
|
49
|
+
createCronJobSchema,
|
|
41
50
|
deletePodSchema,
|
|
51
|
+
deleteDeploymentSchema,
|
|
52
|
+
deleteNamespaceSchema,
|
|
53
|
+
describeCronJobSchema,
|
|
42
54
|
describePodSchema,
|
|
43
55
|
describeDeploymentSchema,
|
|
44
56
|
explainResourceSchema,
|
|
45
57
|
getEventsSchema,
|
|
58
|
+
getJobLogsSchema,
|
|
46
59
|
getLogsSchema,
|
|
47
60
|
installHelmChartSchema,
|
|
48
61
|
listApiResourcesSchema,
|
|
62
|
+
listCronJobsSchema,
|
|
49
63
|
listDeploymentsSchema,
|
|
64
|
+
listJobsSchema,
|
|
50
65
|
listNamespacesSchema,
|
|
51
66
|
listNodesSchema,
|
|
52
67
|
listPodsSchema,
|
|
@@ -55,6 +70,8 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
55
70
|
upgradeHelmChartSchema,
|
|
56
71
|
PortForwardSchema,
|
|
57
72
|
StopPortForwardSchema,
|
|
73
|
+
scaleDeploymentSchema,
|
|
74
|
+
DeleteCronJobSchema,
|
|
58
75
|
],
|
|
59
76
|
};
|
|
60
77
|
});
|
|
@@ -81,6 +98,12 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
81
98
|
case "create_pod": {
|
|
82
99
|
return await createPod(k8sManager, input);
|
|
83
100
|
}
|
|
101
|
+
case "create_cronjob": {
|
|
102
|
+
return await createCronJob(k8sManager, input);
|
|
103
|
+
}
|
|
104
|
+
case "delete_cronjob": {
|
|
105
|
+
return await DeleteCronJob(k8sManager, input);
|
|
106
|
+
}
|
|
84
107
|
case "delete_pod": {
|
|
85
108
|
return await deletePod(k8sManager, input);
|
|
86
109
|
}
|
|
@@ -130,6 +153,18 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
130
153
|
case "list_services": {
|
|
131
154
|
return await listServices(k8sManager, input);
|
|
132
155
|
}
|
|
156
|
+
case "list_cronjobs": {
|
|
157
|
+
return await listCronJobs(k8sManager, input);
|
|
158
|
+
}
|
|
159
|
+
case "describe_cronjob": {
|
|
160
|
+
return await describeCronJob(k8sManager, input);
|
|
161
|
+
}
|
|
162
|
+
case "list_jobs": {
|
|
163
|
+
return await listJobs(k8sManager, input);
|
|
164
|
+
}
|
|
165
|
+
case "get_job_logs": {
|
|
166
|
+
return await getJobLogs(k8sManager, input);
|
|
167
|
+
}
|
|
133
168
|
case "uninstall_helm_chart": {
|
|
134
169
|
return await uninstallHelmChart(input);
|
|
135
170
|
}
|
|
@@ -142,6 +177,9 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
142
177
|
case "stop_port_forward": {
|
|
143
178
|
return await stopPortForward(k8sManager, input);
|
|
144
179
|
}
|
|
180
|
+
case "delete_namespace": {
|
|
181
|
+
return await deleteNamespace(k8sManager, input);
|
|
182
|
+
}
|
|
145
183
|
case "delete_deployment": {
|
|
146
184
|
return await deleteDeployment(k8sManager, input);
|
|
147
185
|
}
|
|
@@ -151,6 +189,9 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
151
189
|
case "describe_deployment": {
|
|
152
190
|
return await describeDeployment(k8sManager, input);
|
|
153
191
|
}
|
|
192
|
+
case "scale_deployment": {
|
|
193
|
+
return await scaleDeployment(k8sManager, input);
|
|
194
|
+
}
|
|
154
195
|
default:
|
|
155
196
|
throw new McpError(ErrorCode.InvalidRequest, `Unknown tool: ${name}`);
|
|
156
197
|
}
|
|
@@ -21,6 +21,28 @@ export declare const CreateNamespaceResponseSchema: z.ZodObject<{
|
|
|
21
21
|
text: string;
|
|
22
22
|
}[];
|
|
23
23
|
}>;
|
|
24
|
+
export declare const DeleteNamespaceResponseSchema: z.ZodObject<{
|
|
25
|
+
content: z.ZodArray<z.ZodObject<{
|
|
26
|
+
type: z.ZodLiteral<"text">;
|
|
27
|
+
text: z.ZodString;
|
|
28
|
+
}, "strip", z.ZodTypeAny, {
|
|
29
|
+
type: "text";
|
|
30
|
+
text: string;
|
|
31
|
+
}, {
|
|
32
|
+
type: "text";
|
|
33
|
+
text: string;
|
|
34
|
+
}>, "many">;
|
|
35
|
+
}, "strip", z.ZodTypeAny, {
|
|
36
|
+
content: {
|
|
37
|
+
type: "text";
|
|
38
|
+
text: string;
|
|
39
|
+
}[];
|
|
40
|
+
}, {
|
|
41
|
+
content: {
|
|
42
|
+
type: "text";
|
|
43
|
+
text: string;
|
|
44
|
+
}[];
|
|
45
|
+
}>;
|
|
24
46
|
export declare const CreatePodResponseSchema: z.ZodObject<{
|
|
25
47
|
content: z.ZodArray<z.ZodObject<{
|
|
26
48
|
type: z.ZodLiteral<"text">;
|
|
@@ -285,6 +307,116 @@ export declare const GetEventsResponseSchema: z.ZodObject<{
|
|
|
285
307
|
text: string;
|
|
286
308
|
}[];
|
|
287
309
|
}>;
|
|
310
|
+
export declare const ListCronJobsResponseSchema: z.ZodObject<{
|
|
311
|
+
content: z.ZodArray<z.ZodObject<{
|
|
312
|
+
type: z.ZodLiteral<"text">;
|
|
313
|
+
text: z.ZodString;
|
|
314
|
+
}, "strip", z.ZodTypeAny, {
|
|
315
|
+
type: "text";
|
|
316
|
+
text: string;
|
|
317
|
+
}, {
|
|
318
|
+
type: "text";
|
|
319
|
+
text: string;
|
|
320
|
+
}>, "many">;
|
|
321
|
+
}, "strip", z.ZodTypeAny, {
|
|
322
|
+
content: {
|
|
323
|
+
type: "text";
|
|
324
|
+
text: string;
|
|
325
|
+
}[];
|
|
326
|
+
}, {
|
|
327
|
+
content: {
|
|
328
|
+
type: "text";
|
|
329
|
+
text: string;
|
|
330
|
+
}[];
|
|
331
|
+
}>;
|
|
332
|
+
export declare const CreateCronJobResponseSchema: z.ZodObject<{
|
|
333
|
+
content: z.ZodArray<z.ZodObject<{
|
|
334
|
+
type: z.ZodLiteral<"text">;
|
|
335
|
+
text: z.ZodString;
|
|
336
|
+
}, "strip", z.ZodTypeAny, {
|
|
337
|
+
type: "text";
|
|
338
|
+
text: string;
|
|
339
|
+
}, {
|
|
340
|
+
type: "text";
|
|
341
|
+
text: string;
|
|
342
|
+
}>, "many">;
|
|
343
|
+
}, "strip", z.ZodTypeAny, {
|
|
344
|
+
content: {
|
|
345
|
+
type: "text";
|
|
346
|
+
text: string;
|
|
347
|
+
}[];
|
|
348
|
+
}, {
|
|
349
|
+
content: {
|
|
350
|
+
type: "text";
|
|
351
|
+
text: string;
|
|
352
|
+
}[];
|
|
353
|
+
}>;
|
|
354
|
+
export declare const DescribeCronJobResponseSchema: z.ZodObject<{
|
|
355
|
+
content: z.ZodArray<z.ZodObject<{
|
|
356
|
+
type: z.ZodLiteral<"text">;
|
|
357
|
+
text: z.ZodString;
|
|
358
|
+
}, "strip", z.ZodTypeAny, {
|
|
359
|
+
type: "text";
|
|
360
|
+
text: string;
|
|
361
|
+
}, {
|
|
362
|
+
type: "text";
|
|
363
|
+
text: string;
|
|
364
|
+
}>, "many">;
|
|
365
|
+
}, "strip", z.ZodTypeAny, {
|
|
366
|
+
content: {
|
|
367
|
+
type: "text";
|
|
368
|
+
text: string;
|
|
369
|
+
}[];
|
|
370
|
+
}, {
|
|
371
|
+
content: {
|
|
372
|
+
type: "text";
|
|
373
|
+
text: string;
|
|
374
|
+
}[];
|
|
375
|
+
}>;
|
|
376
|
+
export declare const ListJobsResponseSchema: z.ZodObject<{
|
|
377
|
+
content: z.ZodArray<z.ZodObject<{
|
|
378
|
+
type: z.ZodLiteral<"text">;
|
|
379
|
+
text: z.ZodString;
|
|
380
|
+
}, "strip", z.ZodTypeAny, {
|
|
381
|
+
type: "text";
|
|
382
|
+
text: string;
|
|
383
|
+
}, {
|
|
384
|
+
type: "text";
|
|
385
|
+
text: string;
|
|
386
|
+
}>, "many">;
|
|
387
|
+
}, "strip", z.ZodTypeAny, {
|
|
388
|
+
content: {
|
|
389
|
+
type: "text";
|
|
390
|
+
text: string;
|
|
391
|
+
}[];
|
|
392
|
+
}, {
|
|
393
|
+
content: {
|
|
394
|
+
type: "text";
|
|
395
|
+
text: string;
|
|
396
|
+
}[];
|
|
397
|
+
}>;
|
|
398
|
+
export declare const GetJobLogsResponseSchema: z.ZodObject<{
|
|
399
|
+
content: z.ZodArray<z.ZodObject<{
|
|
400
|
+
type: z.ZodLiteral<"text">;
|
|
401
|
+
text: z.ZodString;
|
|
402
|
+
}, "strip", z.ZodTypeAny, {
|
|
403
|
+
type: "text";
|
|
404
|
+
text: string;
|
|
405
|
+
}, {
|
|
406
|
+
type: "text";
|
|
407
|
+
text: string;
|
|
408
|
+
}>, "many">;
|
|
409
|
+
}, "strip", z.ZodTypeAny, {
|
|
410
|
+
content: {
|
|
411
|
+
type: "text";
|
|
412
|
+
text: string;
|
|
413
|
+
}[];
|
|
414
|
+
}, {
|
|
415
|
+
content: {
|
|
416
|
+
type: "text";
|
|
417
|
+
text: string;
|
|
418
|
+
}[];
|
|
419
|
+
}>;
|
|
288
420
|
export declare const PortForwardResponseSchema: z.ZodObject<{
|
|
289
421
|
content: z.ZodArray<z.ZodObject<{
|
|
290
422
|
success: z.ZodBoolean;
|
|
@@ -307,3 +439,47 @@ export declare const PortForwardResponseSchema: z.ZodObject<{
|
|
|
307
439
|
success: boolean;
|
|
308
440
|
}[];
|
|
309
441
|
}>;
|
|
442
|
+
export declare const ScaleDeploymentResponseSchema: z.ZodObject<{
|
|
443
|
+
content: z.ZodArray<z.ZodObject<{
|
|
444
|
+
success: z.ZodBoolean;
|
|
445
|
+
message: z.ZodString;
|
|
446
|
+
}, "strip", z.ZodTypeAny, {
|
|
447
|
+
message: string;
|
|
448
|
+
success: boolean;
|
|
449
|
+
}, {
|
|
450
|
+
message: string;
|
|
451
|
+
success: boolean;
|
|
452
|
+
}>, "many">;
|
|
453
|
+
}, "strip", z.ZodTypeAny, {
|
|
454
|
+
content: {
|
|
455
|
+
message: string;
|
|
456
|
+
success: boolean;
|
|
457
|
+
}[];
|
|
458
|
+
}, {
|
|
459
|
+
content: {
|
|
460
|
+
message: string;
|
|
461
|
+
success: boolean;
|
|
462
|
+
}[];
|
|
463
|
+
}>;
|
|
464
|
+
export declare const DeleteCronJobResponseSchema: z.ZodObject<{
|
|
465
|
+
content: z.ZodArray<z.ZodObject<{
|
|
466
|
+
success: z.ZodBoolean;
|
|
467
|
+
message: z.ZodString;
|
|
468
|
+
}, "strip", z.ZodTypeAny, {
|
|
469
|
+
message: string;
|
|
470
|
+
success: boolean;
|
|
471
|
+
}, {
|
|
472
|
+
message: string;
|
|
473
|
+
success: boolean;
|
|
474
|
+
}>, "many">;
|
|
475
|
+
}, "strip", z.ZodTypeAny, {
|
|
476
|
+
content: {
|
|
477
|
+
message: string;
|
|
478
|
+
success: boolean;
|
|
479
|
+
}[];
|
|
480
|
+
}, {
|
|
481
|
+
content: {
|
|
482
|
+
message: string;
|
|
483
|
+
success: boolean;
|
|
484
|
+
}[];
|
|
485
|
+
}>;
|
|
@@ -7,6 +7,9 @@ const ToolResponseContent = z.object({
|
|
|
7
7
|
export const CreateNamespaceResponseSchema = z.object({
|
|
8
8
|
content: z.array(ToolResponseContent),
|
|
9
9
|
});
|
|
10
|
+
export const DeleteNamespaceResponseSchema = z.object({
|
|
11
|
+
content: z.array(ToolResponseContent),
|
|
12
|
+
});
|
|
10
13
|
export const CreatePodResponseSchema = z.object({
|
|
11
14
|
content: z.array(ToolResponseContent),
|
|
12
15
|
});
|
|
@@ -43,9 +46,36 @@ export const GetLogsResponseSchema = z.object({
|
|
|
43
46
|
export const GetEventsResponseSchema = z.object({
|
|
44
47
|
content: z.array(ToolResponseContent),
|
|
45
48
|
});
|
|
49
|
+
export const ListCronJobsResponseSchema = z.object({
|
|
50
|
+
content: z.array(ToolResponseContent),
|
|
51
|
+
});
|
|
52
|
+
export const CreateCronJobResponseSchema = z.object({
|
|
53
|
+
content: z.array(ToolResponseContent),
|
|
54
|
+
});
|
|
55
|
+
export const DescribeCronJobResponseSchema = z.object({
|
|
56
|
+
content: z.array(ToolResponseContent),
|
|
57
|
+
});
|
|
58
|
+
export const ListJobsResponseSchema = z.object({
|
|
59
|
+
content: z.array(ToolResponseContent),
|
|
60
|
+
});
|
|
61
|
+
export const GetJobLogsResponseSchema = z.object({
|
|
62
|
+
content: z.array(ToolResponseContent),
|
|
63
|
+
});
|
|
46
64
|
export const PortForwardResponseSchema = z.object({
|
|
47
65
|
content: z.array(z.object({
|
|
48
66
|
success: z.boolean(),
|
|
49
67
|
message: z.string(),
|
|
50
68
|
})),
|
|
51
69
|
});
|
|
70
|
+
export const ScaleDeploymentResponseSchema = z.object({
|
|
71
|
+
content: z.array(z.object({
|
|
72
|
+
success: z.boolean(),
|
|
73
|
+
message: z.string(),
|
|
74
|
+
})),
|
|
75
|
+
});
|
|
76
|
+
export const DeleteCronJobResponseSchema = z.object({
|
|
77
|
+
content: z.array(z.object({
|
|
78
|
+
success: z.boolean(),
|
|
79
|
+
message: z.string(),
|
|
80
|
+
})),
|
|
81
|
+
});
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { KubernetesManager } from "../types.js";
|
|
2
|
+
export declare const createCronJobSchema: {
|
|
3
|
+
readonly name: "create_cronjob";
|
|
4
|
+
readonly description: "Create a new Kubernetes CronJob";
|
|
5
|
+
readonly inputSchema: {
|
|
6
|
+
readonly type: "object";
|
|
7
|
+
readonly properties: {
|
|
8
|
+
readonly name: {
|
|
9
|
+
readonly type: "string";
|
|
10
|
+
};
|
|
11
|
+
readonly namespace: {
|
|
12
|
+
readonly type: "string";
|
|
13
|
+
};
|
|
14
|
+
readonly schedule: {
|
|
15
|
+
readonly type: "string";
|
|
16
|
+
};
|
|
17
|
+
readonly image: {
|
|
18
|
+
readonly type: "string";
|
|
19
|
+
};
|
|
20
|
+
readonly command: {
|
|
21
|
+
readonly type: "array";
|
|
22
|
+
readonly items: {
|
|
23
|
+
readonly type: "string";
|
|
24
|
+
};
|
|
25
|
+
readonly optional: true;
|
|
26
|
+
};
|
|
27
|
+
readonly suspend: {
|
|
28
|
+
readonly type: "boolean";
|
|
29
|
+
readonly optional: true;
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
readonly required: readonly ["name", "namespace", "schedule", "image"];
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
export declare function createCronJob(k8sManager: KubernetesManager, input: {
|
|
36
|
+
name: string;
|
|
37
|
+
namespace: string;
|
|
38
|
+
schedule: string;
|
|
39
|
+
image: string;
|
|
40
|
+
command?: string[];
|
|
41
|
+
suspend?: boolean;
|
|
42
|
+
}): Promise<{
|
|
43
|
+
content: {
|
|
44
|
+
type: string;
|
|
45
|
+
text: string;
|
|
46
|
+
}[];
|
|
47
|
+
}>;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
export const createCronJobSchema = {
|
|
2
|
+
name: "create_cronjob",
|
|
3
|
+
description: "Create a new Kubernetes CronJob",
|
|
4
|
+
inputSchema: {
|
|
5
|
+
type: "object",
|
|
6
|
+
properties: {
|
|
7
|
+
name: { type: "string" },
|
|
8
|
+
namespace: { type: "string" },
|
|
9
|
+
schedule: { type: "string" },
|
|
10
|
+
image: { type: "string" },
|
|
11
|
+
command: {
|
|
12
|
+
type: "array",
|
|
13
|
+
items: { type: "string" },
|
|
14
|
+
optional: true,
|
|
15
|
+
},
|
|
16
|
+
suspend: {
|
|
17
|
+
type: "boolean",
|
|
18
|
+
optional: true,
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
required: ["name", "namespace", "schedule", "image"],
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
export async function createCronJob(k8sManager, input) {
|
|
25
|
+
try {
|
|
26
|
+
const cronJob = {
|
|
27
|
+
apiVersion: "batch/v1",
|
|
28
|
+
kind: "CronJob",
|
|
29
|
+
metadata: {
|
|
30
|
+
name: input.name,
|
|
31
|
+
namespace: input.namespace,
|
|
32
|
+
labels: {
|
|
33
|
+
"mcp-managed": "true",
|
|
34
|
+
app: input.name,
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
spec: {
|
|
38
|
+
schedule: input.schedule,
|
|
39
|
+
suspend: input.suspend || false,
|
|
40
|
+
jobTemplate: {
|
|
41
|
+
spec: {
|
|
42
|
+
template: {
|
|
43
|
+
spec: {
|
|
44
|
+
containers: [
|
|
45
|
+
{
|
|
46
|
+
name: input.name,
|
|
47
|
+
image: input.image,
|
|
48
|
+
...(input.command && {
|
|
49
|
+
command: input.command,
|
|
50
|
+
}),
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
restartPolicy: "OnFailure",
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
const response = await k8sManager
|
|
61
|
+
.getBatchApi()
|
|
62
|
+
.createNamespacedCronJob(input.namespace, cronJob)
|
|
63
|
+
.catch((error) => {
|
|
64
|
+
console.error("CronJob creation error:", {
|
|
65
|
+
status: error.response?.statusCode,
|
|
66
|
+
message: error.response?.body?.message || error.message,
|
|
67
|
+
details: error.response?.body,
|
|
68
|
+
});
|
|
69
|
+
throw error;
|
|
70
|
+
});
|
|
71
|
+
k8sManager.trackResource("CronJob", input.name, input.namespace);
|
|
72
|
+
return {
|
|
73
|
+
content: [
|
|
74
|
+
{
|
|
75
|
+
type: "text",
|
|
76
|
+
text: JSON.stringify({
|
|
77
|
+
cronJobName: response.body.metadata.name,
|
|
78
|
+
schedule: response.body.spec.schedule,
|
|
79
|
+
status: "created",
|
|
80
|
+
}, null, 2),
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
console.error("CronJob creation error:", {
|
|
87
|
+
status: error.response?.statusCode,
|
|
88
|
+
message: error.response?.body?.message || error.message,
|
|
89
|
+
details: error.response?.body,
|
|
90
|
+
});
|
|
91
|
+
throw error;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { KubernetesManager } from "../types.js";
|
|
2
|
+
export declare const DeleteCronJobSchema: {
|
|
3
|
+
readonly name: "delete_cronjob";
|
|
4
|
+
readonly description: "Delete a Kubernetes CronJob";
|
|
5
|
+
readonly inputSchema: {
|
|
6
|
+
readonly type: "object";
|
|
7
|
+
readonly properties: {
|
|
8
|
+
readonly name: {
|
|
9
|
+
readonly type: "string";
|
|
10
|
+
};
|
|
11
|
+
readonly namespace: {
|
|
12
|
+
readonly type: "string";
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
readonly required: readonly ["name", "namespace"];
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
export declare function DeleteCronJob(k8sManager: KubernetesManager, input: {
|
|
19
|
+
name: string;
|
|
20
|
+
namespace: string;
|
|
21
|
+
}): Promise<{
|
|
22
|
+
content: {
|
|
23
|
+
success: boolean;
|
|
24
|
+
message: string;
|
|
25
|
+
}[];
|
|
26
|
+
}>;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export const DeleteCronJobSchema = {
|
|
2
|
+
name: "delete_cronjob",
|
|
3
|
+
description: "Delete a Kubernetes CronJob",
|
|
4
|
+
inputSchema: {
|
|
5
|
+
type: "object",
|
|
6
|
+
properties: {
|
|
7
|
+
name: { type: "string" },
|
|
8
|
+
namespace: { type: "string" }
|
|
9
|
+
},
|
|
10
|
+
required: ["name", "namespace"]
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
export async function DeleteCronJob(k8sManager, input) {
|
|
14
|
+
try {
|
|
15
|
+
const response = await k8sManager.getBatchApi().deleteNamespacedCronJob(input.name, input.namespace);
|
|
16
|
+
if (response.response?.statusCode !== undefined && (response.response.statusCode === 200 || response.response.statusCode === 202)) {
|
|
17
|
+
return {
|
|
18
|
+
content: [
|
|
19
|
+
{
|
|
20
|
+
success: true,
|
|
21
|
+
message: `Deleted cronjob ${input.name} in namespace ${input.namespace}.` +
|
|
22
|
+
(response.body?.details ? ` Details: ${response.body.details}` : "")
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
return {
|
|
29
|
+
content: [
|
|
30
|
+
{
|
|
31
|
+
success: false,
|
|
32
|
+
message: `Failed to delete cronjob ${input.name} in namespace ${input.namespace}.` + (response.body?.details ? ` Details: ${response.body.details}` : "")
|
|
33
|
+
}
|
|
34
|
+
]
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
return {
|
|
40
|
+
content: [
|
|
41
|
+
{
|
|
42
|
+
success: false,
|
|
43
|
+
message: `Failed to delete cronjob: ${error.message}`
|
|
44
|
+
}
|
|
45
|
+
]
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { KubernetesManager } from "../types.js";
|
|
2
|
+
export declare const deleteNamespaceSchema: {
|
|
3
|
+
readonly name: "delete_namespace";
|
|
4
|
+
readonly description: "Delete a Kubernetes namespace";
|
|
5
|
+
readonly inputSchema: {
|
|
6
|
+
readonly type: "object";
|
|
7
|
+
readonly properties: {
|
|
8
|
+
readonly name: {
|
|
9
|
+
readonly type: "string";
|
|
10
|
+
};
|
|
11
|
+
readonly ignoreNotFound: {
|
|
12
|
+
readonly type: "boolean";
|
|
13
|
+
readonly default: false;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
readonly required: readonly ["name"];
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
export declare function deleteNamespace(k8sManager: KubernetesManager, input: {
|
|
20
|
+
name: string;
|
|
21
|
+
ignoreNotFound?: boolean;
|
|
22
|
+
}): Promise<{
|
|
23
|
+
content: {
|
|
24
|
+
type: string;
|
|
25
|
+
text: string;
|
|
26
|
+
}[];
|
|
27
|
+
}>;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export const deleteNamespaceSchema = {
|
|
2
|
+
name: "delete_namespace",
|
|
3
|
+
description: "Delete a Kubernetes namespace",
|
|
4
|
+
inputSchema: {
|
|
5
|
+
type: "object",
|
|
6
|
+
properties: {
|
|
7
|
+
name: { type: "string" },
|
|
8
|
+
ignoreNotFound: { type: "boolean", default: false },
|
|
9
|
+
},
|
|
10
|
+
required: ["name"],
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
export async function deleteNamespace(k8sManager, input) {
|
|
14
|
+
try {
|
|
15
|
+
await k8sManager.getCoreApi().deleteNamespace(input.name);
|
|
16
|
+
return {
|
|
17
|
+
content: [
|
|
18
|
+
{
|
|
19
|
+
type: "text",
|
|
20
|
+
text: JSON.stringify({
|
|
21
|
+
success: true,
|
|
22
|
+
status: "deleted",
|
|
23
|
+
}, null, 2),
|
|
24
|
+
},
|
|
25
|
+
],
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
if (input.ignoreNotFound && error.response?.statusCode === 404) {
|
|
30
|
+
return {
|
|
31
|
+
content: [
|
|
32
|
+
{
|
|
33
|
+
type: "text",
|
|
34
|
+
text: JSON.stringify({
|
|
35
|
+
success: true,
|
|
36
|
+
status: "not_found",
|
|
37
|
+
}, null, 2),
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
throw error;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { KubernetesManager } from "../types.js";
|
|
2
|
+
export declare const describeCronJobSchema: {
|
|
3
|
+
readonly name: "describe_cronjob";
|
|
4
|
+
readonly description: "Get detailed information about a Kubernetes CronJob including recent job history";
|
|
5
|
+
readonly inputSchema: {
|
|
6
|
+
readonly type: "object";
|
|
7
|
+
readonly properties: {
|
|
8
|
+
readonly name: {
|
|
9
|
+
readonly type: "string";
|
|
10
|
+
};
|
|
11
|
+
readonly namespace: {
|
|
12
|
+
readonly type: "string";
|
|
13
|
+
readonly default: "default";
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
readonly required: readonly ["name", "namespace"];
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
export declare function describeCronJob(k8sManager: KubernetesManager, input: {
|
|
20
|
+
name: string;
|
|
21
|
+
namespace: string;
|
|
22
|
+
}): Promise<{
|
|
23
|
+
content: {
|
|
24
|
+
type: string;
|
|
25
|
+
text: string;
|
|
26
|
+
}[];
|
|
27
|
+
}>;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
export const describeCronJobSchema = {
|
|
2
|
+
name: "describe_cronjob",
|
|
3
|
+
description: "Get detailed information about a Kubernetes CronJob including recent job history",
|
|
4
|
+
inputSchema: {
|
|
5
|
+
type: "object",
|
|
6
|
+
properties: {
|
|
7
|
+
name: { type: "string" },
|
|
8
|
+
namespace: { type: "string", default: "default" },
|
|
9
|
+
},
|
|
10
|
+
required: ["name", "namespace"],
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
export async function describeCronJob(k8sManager, input) {
|
|
14
|
+
try {
|
|
15
|
+
// Get the CronJob details
|
|
16
|
+
const batchV1Api = k8sManager.getBatchApi();
|
|
17
|
+
const cronJobResponse = await batchV1Api.readNamespacedCronJob(input.name, input.namespace);
|
|
18
|
+
const cronJob = cronJobResponse.body;
|
|
19
|
+
// Get recent Jobs associated with this CronJob
|
|
20
|
+
const labelSelector = `app=${input.name},cronjob-name=${input.name}`;
|
|
21
|
+
const jobsResponse = await batchV1Api.listNamespacedJob(input.namespace, undefined, // pretty
|
|
22
|
+
undefined, // allowWatchBookmarks
|
|
23
|
+
undefined, // _continue
|
|
24
|
+
undefined, // fieldSelector
|
|
25
|
+
labelSelector);
|
|
26
|
+
// Sort jobs by creation time (newest first)
|
|
27
|
+
const jobs = jobsResponse.body.items.sort((a, b) => {
|
|
28
|
+
const aTime = a.metadata?.creationTimestamp
|
|
29
|
+
? new Date(a.metadata.creationTimestamp)
|
|
30
|
+
: new Date(0);
|
|
31
|
+
const bTime = b.metadata?.creationTimestamp
|
|
32
|
+
? new Date(b.metadata.creationTimestamp)
|
|
33
|
+
: new Date(0);
|
|
34
|
+
return bTime.getTime() - aTime.getTime();
|
|
35
|
+
});
|
|
36
|
+
// Limit to 5 most recent jobs
|
|
37
|
+
const recentJobs = jobs.slice(0, 5).map((job) => ({
|
|
38
|
+
name: job.metadata?.name || "",
|
|
39
|
+
creationTime: job.metadata?.creationTimestamp || "",
|
|
40
|
+
status: {
|
|
41
|
+
active: job.status?.active || 0,
|
|
42
|
+
succeeded: job.status?.succeeded || 0,
|
|
43
|
+
failed: job.status?.failed || 0,
|
|
44
|
+
completionTime: job.status?.completionTime || null,
|
|
45
|
+
},
|
|
46
|
+
}));
|
|
47
|
+
// Format the response with CronJob details and recent jobs
|
|
48
|
+
const cronJobDetails = {
|
|
49
|
+
name: cronJob.metadata?.name || "",
|
|
50
|
+
namespace: cronJob.metadata?.namespace || "",
|
|
51
|
+
schedule: cronJob.spec?.schedule || "",
|
|
52
|
+
suspend: cronJob.spec?.suspend || false,
|
|
53
|
+
concurrencyPolicy: cronJob.spec?.concurrencyPolicy || "Allow",
|
|
54
|
+
lastScheduleTime: cronJob.status?.lastScheduleTime || null,
|
|
55
|
+
lastSuccessfulTime: cronJob.status?.lastSuccessfulTime || null,
|
|
56
|
+
creationTimestamp: cronJob.metadata?.creationTimestamp || "",
|
|
57
|
+
recentJobs: recentJobs,
|
|
58
|
+
jobTemplate: {
|
|
59
|
+
image: cronJob.spec?.jobTemplate?.spec?.template?.spec?.containers?.[0]
|
|
60
|
+
?.image || "",
|
|
61
|
+
command: cronJob.spec?.jobTemplate?.spec?.template?.spec?.containers?.[0]
|
|
62
|
+
?.command || [],
|
|
63
|
+
restartPolicy: cronJob.spec?.jobTemplate?.spec?.template?.spec?.restartPolicy || "",
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
return {
|
|
67
|
+
content: [
|
|
68
|
+
{
|
|
69
|
+
type: "text",
|
|
70
|
+
text: JSON.stringify(cronJobDetails, null, 2),
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
console.error("Error describing CronJob:", {
|
|
77
|
+
status: error.response?.statusCode,
|
|
78
|
+
message: error.response?.body?.message || error.message,
|
|
79
|
+
details: error.response?.body,
|
|
80
|
+
});
|
|
81
|
+
throw error;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { KubernetesManager } from "../types.js";
|
|
2
|
+
export declare const getJobLogsSchema: {
|
|
3
|
+
readonly name: "get_job_logs";
|
|
4
|
+
readonly description: "Get logs from Pods created by a specific Job";
|
|
5
|
+
readonly inputSchema: {
|
|
6
|
+
readonly type: "object";
|
|
7
|
+
readonly properties: {
|
|
8
|
+
readonly name: {
|
|
9
|
+
readonly type: "string";
|
|
10
|
+
readonly description: "Name of the Job to get logs from";
|
|
11
|
+
};
|
|
12
|
+
readonly namespace: {
|
|
13
|
+
readonly type: "string";
|
|
14
|
+
readonly default: "default";
|
|
15
|
+
};
|
|
16
|
+
readonly tail: {
|
|
17
|
+
readonly type: "number";
|
|
18
|
+
readonly description: "Number of lines to return from the end of the logs";
|
|
19
|
+
readonly optional: true;
|
|
20
|
+
};
|
|
21
|
+
readonly timestamps: {
|
|
22
|
+
readonly type: "boolean";
|
|
23
|
+
readonly description: "Include timestamps in the logs";
|
|
24
|
+
readonly optional: true;
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
readonly required: readonly ["name", "namespace"];
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
export declare function getJobLogs(k8sManager: KubernetesManager, input: {
|
|
31
|
+
name: string;
|
|
32
|
+
namespace: string;
|
|
33
|
+
tail?: number;
|
|
34
|
+
timestamps?: boolean;
|
|
35
|
+
}): Promise<{
|
|
36
|
+
content: {
|
|
37
|
+
type: string;
|
|
38
|
+
text: string;
|
|
39
|
+
}[];
|
|
40
|
+
}>;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
export const getJobLogsSchema = {
|
|
2
|
+
name: "get_job_logs",
|
|
3
|
+
description: "Get logs from Pods created by a specific Job",
|
|
4
|
+
inputSchema: {
|
|
5
|
+
type: "object",
|
|
6
|
+
properties: {
|
|
7
|
+
name: {
|
|
8
|
+
type: "string",
|
|
9
|
+
description: "Name of the Job to get logs from",
|
|
10
|
+
},
|
|
11
|
+
namespace: {
|
|
12
|
+
type: "string",
|
|
13
|
+
default: "default",
|
|
14
|
+
},
|
|
15
|
+
tail: {
|
|
16
|
+
type: "number",
|
|
17
|
+
description: "Number of lines to return from the end of the logs",
|
|
18
|
+
optional: true,
|
|
19
|
+
},
|
|
20
|
+
timestamps: {
|
|
21
|
+
type: "boolean",
|
|
22
|
+
description: "Include timestamps in the logs",
|
|
23
|
+
optional: true,
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
required: ["name", "namespace"],
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
export async function getJobLogs(k8sManager, input) {
|
|
30
|
+
try {
|
|
31
|
+
const coreApi = k8sManager.getCoreApi();
|
|
32
|
+
// First, get the job to check if it exists
|
|
33
|
+
const batchApi = k8sManager.getBatchApi();
|
|
34
|
+
await batchApi.readNamespacedJob(input.name, input.namespace);
|
|
35
|
+
// Find pods associated with this job
|
|
36
|
+
const labelSelector = `job-name=${input.name}`;
|
|
37
|
+
const { body: podList } = await coreApi.listNamespacedPod(input.namespace, undefined, // pretty
|
|
38
|
+
undefined, // allowWatchBookmarks
|
|
39
|
+
undefined, // _continue
|
|
40
|
+
undefined, // fieldSelector
|
|
41
|
+
labelSelector // labelSelector
|
|
42
|
+
);
|
|
43
|
+
if (podList.items.length === 0) {
|
|
44
|
+
return {
|
|
45
|
+
content: [
|
|
46
|
+
{
|
|
47
|
+
type: "text",
|
|
48
|
+
text: JSON.stringify({
|
|
49
|
+
message: `No pods found for job ${input.name}`,
|
|
50
|
+
}, null, 2),
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
// Get logs from all pods belonging to this job
|
|
56
|
+
const podLogs = await Promise.all(podList.items.map(async (pod) => {
|
|
57
|
+
const podName = pod.metadata?.name || "";
|
|
58
|
+
try {
|
|
59
|
+
const logResponse = await coreApi.readNamespacedPodLog(podName, input.namespace, undefined, // container
|
|
60
|
+
undefined, // follow
|
|
61
|
+
input.timestamps || false, // timestamps
|
|
62
|
+
undefined, // sinceSeconds
|
|
63
|
+
undefined, // sinceTime
|
|
64
|
+
(input.tail != undefined ? true : true) || undefined, // tailLines
|
|
65
|
+
undefined // pretty
|
|
66
|
+
);
|
|
67
|
+
return {
|
|
68
|
+
podName,
|
|
69
|
+
logs: logResponse.body,
|
|
70
|
+
status: pod.status?.phase || "Unknown",
|
|
71
|
+
startTime: pod.status?.startTime || null,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
return {
|
|
76
|
+
podName,
|
|
77
|
+
logs: `Error retrieving logs: ${error.message || "Unknown error"}`,
|
|
78
|
+
status: pod.status?.phase || "Unknown",
|
|
79
|
+
startTime: pod.status?.startTime || null,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
}));
|
|
83
|
+
return {
|
|
84
|
+
content: [
|
|
85
|
+
{
|
|
86
|
+
type: "text",
|
|
87
|
+
text: JSON.stringify({
|
|
88
|
+
job: input.name,
|
|
89
|
+
namespace: input.namespace,
|
|
90
|
+
pods: podLogs,
|
|
91
|
+
}, null, 2),
|
|
92
|
+
},
|
|
93
|
+
],
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
console.error("Error getting Job logs:", {
|
|
98
|
+
status: error.response?.statusCode,
|
|
99
|
+
message: error.response?.body?.message || error.message,
|
|
100
|
+
details: error.response?.body,
|
|
101
|
+
});
|
|
102
|
+
throw error;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { KubernetesManager } from "../types.js";
|
|
2
|
+
export declare const listCronJobsSchema: {
|
|
3
|
+
readonly name: "list_cronjobs";
|
|
4
|
+
readonly description: "List CronJobs in a namespace";
|
|
5
|
+
readonly inputSchema: {
|
|
6
|
+
readonly type: "object";
|
|
7
|
+
readonly properties: {
|
|
8
|
+
readonly namespace: {
|
|
9
|
+
readonly type: "string";
|
|
10
|
+
readonly default: "default";
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
readonly required: readonly ["namespace"];
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
export declare function listCronJobs(k8sManager: KubernetesManager, input: {
|
|
17
|
+
namespace?: string;
|
|
18
|
+
}): Promise<{
|
|
19
|
+
content: {
|
|
20
|
+
type: string;
|
|
21
|
+
text: string;
|
|
22
|
+
}[];
|
|
23
|
+
}>;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export const listCronJobsSchema = {
|
|
2
|
+
name: "list_cronjobs",
|
|
3
|
+
description: "List CronJobs in a namespace",
|
|
4
|
+
inputSchema: {
|
|
5
|
+
type: "object",
|
|
6
|
+
properties: {
|
|
7
|
+
namespace: { type: "string", default: "default" },
|
|
8
|
+
},
|
|
9
|
+
required: ["namespace"],
|
|
10
|
+
},
|
|
11
|
+
};
|
|
12
|
+
export async function listCronJobs(k8sManager, input) {
|
|
13
|
+
const namespace = input.namespace || "default";
|
|
14
|
+
// Get BatchV1Api from KubernetesManager
|
|
15
|
+
const batchV1Api = k8sManager.getBatchApi();
|
|
16
|
+
// List cronjobs in the specified namespace
|
|
17
|
+
const { body } = await batchV1Api.listNamespacedCronJob(namespace);
|
|
18
|
+
// Transform cronjob data to a more readable format
|
|
19
|
+
const cronjobs = body.items.map((cronjob) => ({
|
|
20
|
+
name: cronjob.metadata?.name || "",
|
|
21
|
+
namespace: cronjob.metadata?.namespace || "",
|
|
22
|
+
schedule: cronjob.spec?.schedule || "",
|
|
23
|
+
suspend: cronjob.spec?.suspend || false,
|
|
24
|
+
lastScheduleTime: cronjob.status?.lastScheduleTime || null,
|
|
25
|
+
createdAt: cronjob.metadata?.creationTimestamp,
|
|
26
|
+
}));
|
|
27
|
+
return {
|
|
28
|
+
content: [
|
|
29
|
+
{
|
|
30
|
+
type: "text",
|
|
31
|
+
text: JSON.stringify({ cronjobs }, null, 2),
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
};
|
|
35
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { KubernetesManager } from "../types.js";
|
|
2
|
+
export declare const listJobsSchema: {
|
|
3
|
+
readonly name: "list_jobs";
|
|
4
|
+
readonly description: "List Jobs in a namespace, optionally filtered by a CronJob parent";
|
|
5
|
+
readonly inputSchema: {
|
|
6
|
+
readonly type: "object";
|
|
7
|
+
readonly properties: {
|
|
8
|
+
readonly namespace: {
|
|
9
|
+
readonly type: "string";
|
|
10
|
+
readonly default: "default";
|
|
11
|
+
};
|
|
12
|
+
readonly cronJobName: {
|
|
13
|
+
readonly type: "string";
|
|
14
|
+
readonly description: "Optional: Filter jobs created by a specific CronJob";
|
|
15
|
+
readonly optional: true;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
readonly required: readonly ["namespace"];
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
export declare function listJobs(k8sManager: KubernetesManager, input: {
|
|
22
|
+
namespace: string;
|
|
23
|
+
cronJobName?: string;
|
|
24
|
+
}): Promise<{
|
|
25
|
+
content: {
|
|
26
|
+
type: string;
|
|
27
|
+
text: string;
|
|
28
|
+
}[];
|
|
29
|
+
}>;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
export const listJobsSchema = {
|
|
2
|
+
name: "list_jobs",
|
|
3
|
+
description: "List Jobs in a namespace, optionally filtered by a CronJob parent",
|
|
4
|
+
inputSchema: {
|
|
5
|
+
type: "object",
|
|
6
|
+
properties: {
|
|
7
|
+
namespace: { type: "string", default: "default" },
|
|
8
|
+
cronJobName: {
|
|
9
|
+
type: "string",
|
|
10
|
+
description: "Optional: Filter jobs created by a specific CronJob",
|
|
11
|
+
optional: true,
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
required: ["namespace"],
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
export async function listJobs(k8sManager, input) {
|
|
18
|
+
try {
|
|
19
|
+
const namespace = input.namespace;
|
|
20
|
+
const batchV1Api = k8sManager.getBatchApi();
|
|
21
|
+
// Set up label selector if cronJobName is provided
|
|
22
|
+
let labelSelector;
|
|
23
|
+
if (input.cronJobName) {
|
|
24
|
+
labelSelector = `cronjob-name=${input.cronJobName}`;
|
|
25
|
+
}
|
|
26
|
+
// Get jobs with optional filtering
|
|
27
|
+
const { body } = await batchV1Api.listNamespacedJob(namespace, undefined, // pretty
|
|
28
|
+
undefined, // allowWatchBookmarks
|
|
29
|
+
undefined, // _continue
|
|
30
|
+
undefined, // fieldSelector
|
|
31
|
+
labelSelector // labelSelector
|
|
32
|
+
);
|
|
33
|
+
// Sort jobs by creation time (newest first)
|
|
34
|
+
const jobs = body.items.sort((a, b) => {
|
|
35
|
+
const aTime = a.metadata?.creationTimestamp
|
|
36
|
+
? new Date(a.metadata.creationTimestamp)
|
|
37
|
+
: new Date(0);
|
|
38
|
+
const bTime = b.metadata?.creationTimestamp
|
|
39
|
+
? new Date(b.metadata.creationTimestamp)
|
|
40
|
+
: new Date(0);
|
|
41
|
+
return bTime.getTime() - aTime.getTime();
|
|
42
|
+
});
|
|
43
|
+
// Transform job data to a more readable format
|
|
44
|
+
const formattedJobs = jobs.map((job) => ({
|
|
45
|
+
name: job.metadata?.name || "",
|
|
46
|
+
namespace: job.metadata?.namespace || "",
|
|
47
|
+
creationTime: job.metadata?.creationTimestamp || "",
|
|
48
|
+
labels: job.metadata?.labels || {},
|
|
49
|
+
completions: job.spec?.completions || 1,
|
|
50
|
+
parallelism: job.spec?.parallelism || 1,
|
|
51
|
+
status: {
|
|
52
|
+
active: job.status?.active || 0,
|
|
53
|
+
succeeded: job.status?.succeeded || 0,
|
|
54
|
+
failed: job.status?.failed || 0,
|
|
55
|
+
completionTime: job.status?.completionTime || null,
|
|
56
|
+
startTime: job.status?.startTime || null,
|
|
57
|
+
conditions: job.status?.conditions || [],
|
|
58
|
+
},
|
|
59
|
+
}));
|
|
60
|
+
return {
|
|
61
|
+
content: [
|
|
62
|
+
{
|
|
63
|
+
type: "text",
|
|
64
|
+
text: JSON.stringify({ jobs: formattedJobs }, null, 2),
|
|
65
|
+
},
|
|
66
|
+
],
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
console.error("Error listing Jobs:", {
|
|
71
|
+
status: error.response?.statusCode,
|
|
72
|
+
message: error.response?.body?.message || error.message,
|
|
73
|
+
details: error.response?.body,
|
|
74
|
+
});
|
|
75
|
+
throw error;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { KubernetesManager } from "../types.js";
|
|
2
|
+
export declare const scaleDeploymentSchema: {
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
inputSchema: {
|
|
6
|
+
type: string;
|
|
7
|
+
properties: {
|
|
8
|
+
name: {
|
|
9
|
+
type: string;
|
|
10
|
+
};
|
|
11
|
+
namespace: {
|
|
12
|
+
type: string;
|
|
13
|
+
};
|
|
14
|
+
replicas: {
|
|
15
|
+
type: string;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
required: string[];
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
export declare function scaleDeployment(k8sManager: KubernetesManager, input: {
|
|
22
|
+
name: string;
|
|
23
|
+
namespace: string;
|
|
24
|
+
replicas: number;
|
|
25
|
+
}): Promise<{
|
|
26
|
+
content: {
|
|
27
|
+
success: boolean;
|
|
28
|
+
message: string;
|
|
29
|
+
}[];
|
|
30
|
+
}>;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export const scaleDeploymentSchema = {
|
|
2
|
+
name: "scale_deployment",
|
|
3
|
+
description: "Scale a Kubernetes deployment",
|
|
4
|
+
inputSchema: {
|
|
5
|
+
type: "object",
|
|
6
|
+
properties: {
|
|
7
|
+
name: { type: "string" },
|
|
8
|
+
namespace: { type: "string" },
|
|
9
|
+
replicas: { type: "number" }
|
|
10
|
+
},
|
|
11
|
+
required: ["name", "namespace", "replicas"]
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
export async function scaleDeployment(k8sManager, input) {
|
|
15
|
+
try {
|
|
16
|
+
const scale = k8sManager.getAppsApi().readNamespacedDeploymentScale(input.name, input.namespace);
|
|
17
|
+
(await scale).body.spec.replicas = input.replicas;
|
|
18
|
+
const result = await k8sManager.getAppsApi().replaceNamespacedDeploymentScale(input.name, input.namespace, (await scale).body);
|
|
19
|
+
if (result.response?.statusCode !== undefined && result.response.statusCode >= 200 && result.response.statusCode < 300) {
|
|
20
|
+
return {
|
|
21
|
+
content: [
|
|
22
|
+
{
|
|
23
|
+
success: true,
|
|
24
|
+
message: `Scaled deployment ${input.name} to ${input.replicas} replicas`
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
return {
|
|
31
|
+
content: [
|
|
32
|
+
{
|
|
33
|
+
success: false,
|
|
34
|
+
message: `Failed to scale deployment ${input.name} to ${input.replicas} replicas`
|
|
35
|
+
}
|
|
36
|
+
]
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
return {
|
|
42
|
+
content: [
|
|
43
|
+
{
|
|
44
|
+
success: false,
|
|
45
|
+
message: `Failed to scale deployment ${error.message}`
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -7,6 +7,7 @@ export declare class KubernetesManager {
|
|
|
7
7
|
private kc;
|
|
8
8
|
private k8sApi;
|
|
9
9
|
private k8sAppsApi;
|
|
10
|
+
private k8sBatchApi;
|
|
10
11
|
constructor();
|
|
11
12
|
cleanup(): Promise<void>;
|
|
12
13
|
trackResource(kind: string, name: string, namespace: string): void;
|
|
@@ -18,4 +19,5 @@ export declare class KubernetesManager {
|
|
|
18
19
|
getKubeConfig(): k8s.KubeConfig;
|
|
19
20
|
getCoreApi(): k8s.CoreV1Api;
|
|
20
21
|
getAppsApi(): k8s.AppsV1Api;
|
|
22
|
+
getBatchApi(): k8s.BatchV1Api;
|
|
21
23
|
}
|
|
@@ -6,11 +6,13 @@ export class KubernetesManager {
|
|
|
6
6
|
kc;
|
|
7
7
|
k8sApi;
|
|
8
8
|
k8sAppsApi;
|
|
9
|
+
k8sBatchApi;
|
|
9
10
|
constructor() {
|
|
10
11
|
this.kc = new k8s.KubeConfig();
|
|
11
12
|
this.kc.loadFromDefault();
|
|
12
13
|
this.k8sApi = this.kc.makeApiClient(k8s.CoreV1Api);
|
|
13
14
|
this.k8sAppsApi = this.kc.makeApiClient(k8s.AppsV1Api);
|
|
15
|
+
this.k8sBatchApi = this.kc.makeApiClient(k8s.BatchV1Api);
|
|
14
16
|
}
|
|
15
17
|
async cleanup() {
|
|
16
18
|
// Stop watches
|
|
@@ -41,6 +43,9 @@ export class KubernetesManager {
|
|
|
41
43
|
case "service":
|
|
42
44
|
await this.k8sApi.deleteNamespacedService(name, namespace);
|
|
43
45
|
break;
|
|
46
|
+
case "cronjob":
|
|
47
|
+
await this.k8sBatchApi.deleteNamespacedCronJob(name, namespace);
|
|
48
|
+
break;
|
|
44
49
|
}
|
|
45
50
|
this.resources = this.resources.filter((r) => !(r.kind === kind && r.name === name && r.namespace === namespace));
|
|
46
51
|
}
|
|
@@ -65,4 +70,7 @@ export class KubernetesManager {
|
|
|
65
70
|
getAppsApi() {
|
|
66
71
|
return this.k8sAppsApi;
|
|
67
72
|
}
|
|
73
|
+
getBatchApi() {
|
|
74
|
+
return this.k8sBatchApi;
|
|
75
|
+
}
|
|
68
76
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-server-kubernetes",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "MCP server for interacting with Kubernetes clusters via kubectl",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -37,10 +37,10 @@
|
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@kubernetes/client-node": "0.20.0",
|
|
39
39
|
"@modelcontextprotocol/sdk": "1.7.0",
|
|
40
|
+
"express": "4.21.2",
|
|
40
41
|
"js-yaml": "4.1.0",
|
|
41
42
|
"yaml": "2.7.0",
|
|
42
|
-
"zod": "3.23.8"
|
|
43
|
-
"express": "4.21.2"
|
|
43
|
+
"zod": "3.23.8"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@types/express": "5.0.1",
|