mcp-server-kubernetes 0.4.0 → 1.0.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.
@@ -0,0 +1,162 @@
1
+ import { McpError, ErrorCode } from "@modelcontextprotocol/sdk/types.js";
2
+ import { ContainerTemplate, containerTemplates, CustomContainerConfig, } from "../config/container-templates.js";
3
+ export const createDeploymentSchema = {
4
+ name: "create_deployment",
5
+ description: "Create a new Kubernetes deployment",
6
+ inputSchema: {
7
+ type: "object",
8
+ properties: {
9
+ name: { type: "string" },
10
+ namespace: { type: "string" },
11
+ template: {
12
+ type: "string",
13
+ enum: ContainerTemplate.options,
14
+ },
15
+ replicas: { type: "number", default: 1 },
16
+ ports: {
17
+ type: "array",
18
+ items: { type: "number" },
19
+ optional: true,
20
+ },
21
+ customConfig: {
22
+ type: "object",
23
+ optional: true,
24
+ properties: {
25
+ image: { type: "string" },
26
+ command: { type: "array", items: { type: "string" } },
27
+ args: { type: "array", items: { type: "string" } },
28
+ ports: {
29
+ type: "array",
30
+ items: {
31
+ type: "object",
32
+ properties: {
33
+ containerPort: { type: "number" },
34
+ name: { type: "string" },
35
+ protocol: { type: "string" },
36
+ },
37
+ },
38
+ },
39
+ resources: {
40
+ type: "object",
41
+ properties: {
42
+ limits: {
43
+ type: "object",
44
+ additionalProperties: { type: "string" },
45
+ },
46
+ requests: {
47
+ type: "object",
48
+ additionalProperties: { type: "string" },
49
+ },
50
+ },
51
+ },
52
+ env: {
53
+ type: "array",
54
+ items: {
55
+ type: "object",
56
+ properties: {
57
+ name: { type: "string" },
58
+ value: { type: "string" },
59
+ valueFrom: { type: "object" },
60
+ },
61
+ },
62
+ },
63
+ volumeMounts: {
64
+ type: "array",
65
+ items: {
66
+ type: "object",
67
+ properties: {
68
+ name: { type: "string" },
69
+ mountPath: { type: "string" },
70
+ readOnly: { type: "boolean" },
71
+ },
72
+ },
73
+ },
74
+ },
75
+ },
76
+ },
77
+ required: ["name", "namespace", "template"],
78
+ },
79
+ };
80
+ export async function createDeployment(k8sManager, input) {
81
+ const templateConfig = containerTemplates[input.template];
82
+ // If using custom template, validate and merge custom config
83
+ let containerConfig;
84
+ if (input.template === "custom") {
85
+ if (!input.customConfig) {
86
+ throw new McpError(ErrorCode.InvalidRequest, "Custom container configuration is required when using 'custom' template");
87
+ }
88
+ // Validate custom config against schema
89
+ const validatedConfig = CustomContainerConfig.parse(input.customConfig);
90
+ // Merge base template with custom config
91
+ containerConfig = {
92
+ ...templateConfig,
93
+ image: validatedConfig.image,
94
+ command: validatedConfig.command,
95
+ args: validatedConfig.args,
96
+ ports: validatedConfig.ports,
97
+ resources: validatedConfig.resources,
98
+ env: validatedConfig.env,
99
+ volumeMounts: validatedConfig.volumeMounts,
100
+ };
101
+ }
102
+ else {
103
+ containerConfig = {
104
+ ...templateConfig,
105
+ ports: input.ports?.map((port) => ({ containerPort: port })) ||
106
+ templateConfig.ports,
107
+ };
108
+ }
109
+ const deployment = {
110
+ apiVersion: "apps/v1",
111
+ kind: "Deployment",
112
+ metadata: {
113
+ name: input.name,
114
+ namespace: input.namespace,
115
+ labels: {
116
+ "mcp-managed": "true",
117
+ app: input.name,
118
+ },
119
+ },
120
+ spec: {
121
+ replicas: input.replicas || 1,
122
+ selector: {
123
+ matchLabels: {
124
+ app: input.name,
125
+ },
126
+ },
127
+ template: {
128
+ metadata: {
129
+ labels: {
130
+ app: input.name,
131
+ },
132
+ },
133
+ spec: {
134
+ containers: [containerConfig],
135
+ },
136
+ },
137
+ },
138
+ };
139
+ const response = await k8sManager
140
+ .getAppsApi()
141
+ .createNamespacedDeployment(input.namespace, deployment)
142
+ .catch((error) => {
143
+ console.error("Deployment creation error:", {
144
+ status: error.response?.statusCode,
145
+ message: error.response?.body?.message || error.message,
146
+ details: error.response?.body,
147
+ });
148
+ throw error;
149
+ });
150
+ k8sManager.trackResource("Deployment", input.name, input.namespace);
151
+ return {
152
+ content: [
153
+ {
154
+ type: "text",
155
+ text: JSON.stringify({
156
+ deploymentName: response.body.metadata.name,
157
+ status: "created",
158
+ }, null, 2),
159
+ },
160
+ ],
161
+ };
162
+ }
@@ -0,0 +1,22 @@
1
+ import { KubernetesManager } from "../types.js";
2
+ export declare const createNamespaceSchema: {
3
+ readonly name: "create_namespace";
4
+ readonly description: "Create a new Kubernetes namespace";
5
+ readonly inputSchema: {
6
+ readonly type: "object";
7
+ readonly properties: {
8
+ readonly name: {
9
+ readonly type: "string";
10
+ };
11
+ };
12
+ readonly required: readonly ["name"];
13
+ };
14
+ };
15
+ export declare function createNamespace(k8sManager: KubernetesManager, input: {
16
+ name: string;
17
+ }): Promise<{
18
+ content: {
19
+ type: string;
20
+ text: string;
21
+ }[];
22
+ }>;
@@ -0,0 +1,48 @@
1
+ export const createNamespaceSchema = {
2
+ name: "create_namespace",
3
+ description: "Create a new Kubernetes namespace",
4
+ inputSchema: {
5
+ type: "object",
6
+ properties: {
7
+ name: { type: "string" },
8
+ },
9
+ required: ["name"],
10
+ },
11
+ };
12
+ export async function createNamespace(k8sManager, input) {
13
+ const namespace = {
14
+ apiVersion: "v1",
15
+ kind: "Namespace",
16
+ metadata: {
17
+ name: input.name,
18
+ labels: {
19
+ "mcp-managed": "true",
20
+ app: input.name,
21
+ },
22
+ },
23
+ spec: {},
24
+ };
25
+ try {
26
+ const response = await k8sManager.getCoreApi().createNamespace(namespace);
27
+ k8sManager.trackResource("Namespace", input.name, input.name);
28
+ return {
29
+ content: [
30
+ {
31
+ type: "text",
32
+ text: JSON.stringify({
33
+ podName: response.body.metadata.name,
34
+ status: "created",
35
+ }, null, 2),
36
+ },
37
+ ],
38
+ };
39
+ }
40
+ catch (error) {
41
+ console.error("Namespace creation error:", {
42
+ status: error.response?.statusCode,
43
+ message: error.response?.body?.message || error.message,
44
+ details: error.response?.body,
45
+ });
46
+ throw error;
47
+ }
48
+ }
@@ -1,4 +1,5 @@
1
1
  import { KubernetesManager } from "../types.js";
2
+ import { CustomContainerConfigType } from "../config/container-templates.js";
2
3
  export declare const createPodSchema: {
3
4
  readonly name: "create_pod";
4
5
  readonly description: "Create a new Kubernetes pod";
@@ -13,7 +14,7 @@ export declare const createPodSchema: {
13
14
  };
14
15
  readonly template: {
15
16
  readonly type: "string";
16
- readonly enum: ["ubuntu", "nginx", "busybox", "alpine"];
17
+ readonly enum: ["ubuntu", "nginx", "busybox", "alpine", "custom"];
17
18
  };
18
19
  readonly command: {
19
20
  readonly type: "array";
@@ -22,6 +23,95 @@ export declare const createPodSchema: {
22
23
  };
23
24
  readonly optional: true;
24
25
  };
26
+ readonly customConfig: {
27
+ readonly type: "object";
28
+ readonly optional: true;
29
+ readonly properties: {
30
+ readonly image: {
31
+ readonly type: "string";
32
+ };
33
+ readonly command: {
34
+ readonly type: "array";
35
+ readonly items: {
36
+ readonly type: "string";
37
+ };
38
+ };
39
+ readonly args: {
40
+ readonly type: "array";
41
+ readonly items: {
42
+ readonly type: "string";
43
+ };
44
+ };
45
+ readonly ports: {
46
+ readonly type: "array";
47
+ readonly items: {
48
+ readonly type: "object";
49
+ readonly properties: {
50
+ readonly containerPort: {
51
+ readonly type: "number";
52
+ };
53
+ readonly name: {
54
+ readonly type: "string";
55
+ };
56
+ readonly protocol: {
57
+ readonly type: "string";
58
+ };
59
+ };
60
+ };
61
+ };
62
+ readonly resources: {
63
+ readonly type: "object";
64
+ readonly properties: {
65
+ readonly limits: {
66
+ readonly type: "object";
67
+ readonly additionalProperties: {
68
+ readonly type: "string";
69
+ };
70
+ };
71
+ readonly requests: {
72
+ readonly type: "object";
73
+ readonly additionalProperties: {
74
+ readonly type: "string";
75
+ };
76
+ };
77
+ };
78
+ };
79
+ readonly env: {
80
+ readonly type: "array";
81
+ readonly items: {
82
+ readonly type: "object";
83
+ readonly properties: {
84
+ readonly name: {
85
+ readonly type: "string";
86
+ };
87
+ readonly value: {
88
+ readonly type: "string";
89
+ };
90
+ readonly valueFrom: {
91
+ readonly type: "object";
92
+ };
93
+ };
94
+ };
95
+ };
96
+ readonly volumeMounts: {
97
+ readonly type: "array";
98
+ readonly items: {
99
+ readonly type: "object";
100
+ readonly properties: {
101
+ readonly name: {
102
+ readonly type: "string";
103
+ };
104
+ readonly mountPath: {
105
+ readonly type: "string";
106
+ };
107
+ readonly readOnly: {
108
+ readonly type: "boolean";
109
+ };
110
+ };
111
+ };
112
+ };
113
+ };
114
+ };
25
115
  };
26
116
  readonly required: readonly ["name", "namespace", "template"];
27
117
  };
@@ -31,6 +121,7 @@ export declare function createPod(k8sManager: KubernetesManager, input: {
31
121
  namespace: string;
32
122
  template: string;
33
123
  command?: string[];
124
+ customConfig?: CustomContainerConfigType;
34
125
  }): Promise<{
35
126
  content: {
36
127
  type: string;
@@ -1,4 +1,5 @@
1
- import { ContainerTemplate, containerTemplates } from "../config/container-templates.js";
1
+ import { McpError, ErrorCode } from "@modelcontextprotocol/sdk/types.js";
2
+ import { ContainerTemplate, containerTemplates, CustomContainerConfig, } from "../config/container-templates.js";
2
3
  export const createPodSchema = {
3
4
  name: "create_pod",
4
5
  description: "Create a new Kubernetes pod",
@@ -16,12 +17,101 @@ export const createPodSchema = {
16
17
  items: { type: "string" },
17
18
  optional: true,
18
19
  },
20
+ customConfig: {
21
+ type: "object",
22
+ optional: true,
23
+ properties: {
24
+ image: { type: "string" },
25
+ command: { type: "array", items: { type: "string" } },
26
+ args: { type: "array", items: { type: "string" } },
27
+ ports: {
28
+ type: "array",
29
+ items: {
30
+ type: "object",
31
+ properties: {
32
+ containerPort: { type: "number" },
33
+ name: { type: "string" },
34
+ protocol: { type: "string" },
35
+ },
36
+ },
37
+ },
38
+ resources: {
39
+ type: "object",
40
+ properties: {
41
+ limits: {
42
+ type: "object",
43
+ additionalProperties: { type: "string" },
44
+ },
45
+ requests: {
46
+ type: "object",
47
+ additionalProperties: { type: "string" },
48
+ },
49
+ },
50
+ },
51
+ env: {
52
+ type: "array",
53
+ items: {
54
+ type: "object",
55
+ properties: {
56
+ name: { type: "string" },
57
+ value: { type: "string" },
58
+ valueFrom: { type: "object" },
59
+ },
60
+ },
61
+ },
62
+ volumeMounts: {
63
+ type: "array",
64
+ items: {
65
+ type: "object",
66
+ properties: {
67
+ name: { type: "string" },
68
+ mountPath: { type: "string" },
69
+ readOnly: { type: "boolean" },
70
+ },
71
+ },
72
+ },
73
+ },
74
+ },
19
75
  },
20
76
  required: ["name", "namespace", "template"],
21
77
  },
22
78
  };
23
79
  export async function createPod(k8sManager, input) {
24
80
  const templateConfig = containerTemplates[input.template];
81
+ // If using custom template, validate and merge custom config
82
+ let containerConfig;
83
+ if (input.template === "custom") {
84
+ if (!input.customConfig) {
85
+ throw new McpError(ErrorCode.InvalidRequest, "Custom container configuration is required when using 'custom' template");
86
+ }
87
+ // Validate custom config against schema
88
+ const validatedConfig = CustomContainerConfig.parse(input.customConfig);
89
+ // Create a new container config with all fields explicitly set
90
+ containerConfig = {
91
+ name: "main",
92
+ image: validatedConfig.image,
93
+ command: validatedConfig.command,
94
+ args: validatedConfig.args,
95
+ ports: validatedConfig.ports || [],
96
+ resources: validatedConfig.resources || {
97
+ limits: {},
98
+ requests: {},
99
+ },
100
+ env: validatedConfig.env || [],
101
+ volumeMounts: validatedConfig.volumeMounts || [],
102
+ livenessProbe: templateConfig.livenessProbe,
103
+ readinessProbe: templateConfig.readinessProbe,
104
+ };
105
+ }
106
+ else {
107
+ containerConfig = {
108
+ ...templateConfig,
109
+ ...(input.command && {
110
+ command: input.command,
111
+ args: undefined, // Clear default args when command is overridden
112
+ }),
113
+ };
114
+ }
25
115
  const pod = {
26
116
  apiVersion: "v1",
27
117
  kind: "Pod",
@@ -34,15 +124,7 @@ export async function createPod(k8sManager, input) {
34
124
  },
35
125
  },
36
126
  spec: {
37
- containers: [
38
- {
39
- ...templateConfig,
40
- ...(input.command && {
41
- command: input.command,
42
- args: undefined, // Clear default args when command is overridden
43
- }),
44
- },
45
- ],
127
+ containers: [containerConfig],
46
128
  },
47
129
  };
48
130
  const response = await k8sManager
@@ -0,0 +1,31 @@
1
+ import { KubernetesManager } from "../types.js";
2
+ export declare const deleteDeploymentSchema: {
3
+ readonly name: "delete_deployment";
4
+ readonly description: "Delete a Kubernetes deployment";
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 ignoreNotFound: {
15
+ readonly type: "boolean";
16
+ readonly default: false;
17
+ };
18
+ };
19
+ readonly required: readonly ["name", "namespace"];
20
+ };
21
+ };
22
+ export declare function deleteDeployment(k8sManager: KubernetesManager, input: {
23
+ name: string;
24
+ namespace: string;
25
+ ignoreNotFound?: boolean;
26
+ }): Promise<{
27
+ content: {
28
+ type: string;
29
+ text: string;
30
+ }[];
31
+ }>;
@@ -0,0 +1,47 @@
1
+ export const deleteDeploymentSchema = {
2
+ name: "delete_deployment",
3
+ description: "Delete a Kubernetes deployment",
4
+ inputSchema: {
5
+ type: "object",
6
+ properties: {
7
+ name: { type: "string" },
8
+ namespace: { type: "string" },
9
+ ignoreNotFound: { type: "boolean", default: false },
10
+ },
11
+ required: ["name", "namespace"],
12
+ },
13
+ };
14
+ export async function deleteDeployment(k8sManager, input) {
15
+ try {
16
+ await k8sManager
17
+ .getAppsApi()
18
+ .deleteNamespacedDeployment(input.name, input.namespace);
19
+ return {
20
+ content: [
21
+ {
22
+ type: "text",
23
+ text: JSON.stringify({
24
+ success: true,
25
+ status: "deleted",
26
+ }, null, 2),
27
+ },
28
+ ],
29
+ };
30
+ }
31
+ catch (error) {
32
+ if (input.ignoreNotFound && error.response?.statusCode === 404) {
33
+ return {
34
+ content: [
35
+ {
36
+ type: "text",
37
+ text: JSON.stringify({
38
+ success: true,
39
+ status: "not_found",
40
+ }, null, 2),
41
+ },
42
+ ],
43
+ };
44
+ }
45
+ throw error;
46
+ }
47
+ }
@@ -0,0 +1,26 @@
1
+ import { KubernetesManager } from "../types.js";
2
+ export declare const describeDeploymentSchema: {
3
+ readonly name: "describe_deployment";
4
+ readonly description: "Get details about a Kubernetes deployment";
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 describeDeployment(k8sManager: KubernetesManager, input: {
19
+ name: string;
20
+ namespace: string;
21
+ }): Promise<{
22
+ content: {
23
+ type: string;
24
+ text: string;
25
+ }[];
26
+ }>;
@@ -0,0 +1,40 @@
1
+ export const describeDeploymentSchema = {
2
+ name: "describe_deployment",
3
+ description: "Get details about a Kubernetes deployment",
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 describeDeployment(k8sManager, input) {
14
+ const { body } = await k8sManager
15
+ .getAppsApi()
16
+ .readNamespacedDeployment(input.name, input.namespace)
17
+ .catch((error) => {
18
+ console.error("Deployment description error:", {
19
+ status: error.response?.statusCode,
20
+ message: error.response?.body?.message || error.message,
21
+ details: error.response?.body,
22
+ });
23
+ throw error;
24
+ });
25
+ return {
26
+ content: [
27
+ {
28
+ type: "text",
29
+ text: JSON.stringify({
30
+ name: body.metadata?.name,
31
+ namespace: body.metadata?.namespace,
32
+ replicas: body.spec?.replicas,
33
+ availableReplicas: body.status?.availableReplicas,
34
+ spec: body.spec,
35
+ status: body.status,
36
+ }, null, 2),
37
+ },
38
+ ],
39
+ };
40
+ }
@@ -0,0 +1,59 @@
1
+ import { KubernetesManager } from "../utils/kubernetes-manager.js";
2
+ export declare const PortForwardSchema: {
3
+ name: string;
4
+ description: string;
5
+ inputSchema: {
6
+ type: string;
7
+ properties: {
8
+ resourceType: {
9
+ type: string;
10
+ };
11
+ resourceName: {
12
+ type: string;
13
+ };
14
+ localPort: {
15
+ type: string;
16
+ };
17
+ targetPort: {
18
+ type: string;
19
+ };
20
+ namespace: {
21
+ type: string;
22
+ };
23
+ };
24
+ required: string[];
25
+ };
26
+ };
27
+ export declare function startPortForward(k8sManager: KubernetesManager, input: {
28
+ resourceType: string;
29
+ resourceName: string;
30
+ localPort: number;
31
+ targetPort: number;
32
+ namespace?: string;
33
+ }): Promise<{
34
+ content: {
35
+ success: boolean;
36
+ message: string;
37
+ }[];
38
+ }>;
39
+ export declare const StopPortForwardSchema: {
40
+ name: string;
41
+ description: string;
42
+ inputSchema: {
43
+ type: string;
44
+ properties: {
45
+ id: {
46
+ type: string;
47
+ };
48
+ };
49
+ required: string[];
50
+ };
51
+ };
52
+ export declare function stopPortForward(k8sManager: KubernetesManager, input: {
53
+ id: string;
54
+ }): Promise<{
55
+ content: {
56
+ success: boolean;
57
+ message: string;
58
+ }[];
59
+ }>;