mcp-server-kubernetes 0.4.0 → 1.0.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 -4
- package/dist/config/container-templates.d.ts +102 -1
- package/dist/config/container-templates.js +56 -0
- package/dist/config/deployment-config.d.ts +90 -1
- package/dist/config/deployment-config.js +56 -1
- package/dist/index.js +27 -0
- package/dist/models/response-schemas.d.ts +66 -0
- package/dist/models/response-schemas.js +12 -0
- package/dist/tools/create_deployment.d.ts +135 -0
- package/dist/tools/create_deployment.js +162 -0
- package/dist/tools/create_namespace.d.ts +22 -0
- package/dist/tools/create_namespace.js +48 -0
- package/dist/tools/create_pod.d.ts +92 -1
- package/dist/tools/create_pod.js +92 -10
- package/dist/tools/delete_deployment.d.ts +31 -0
- package/dist/tools/delete_deployment.js +47 -0
- package/dist/tools/describe_deployment.d.ts +26 -0
- package/dist/tools/describe_deployment.js +40 -0
- package/dist/tools/port_forward.d.ts +55 -0
- package/dist/tools/port_forward.js +110 -0
- package/package.json +11 -11
|
@@ -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,55 @@
|
|
|
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
|
+
};
|
|
21
|
+
required: string[];
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
export declare function startPortForward(k8sManager: KubernetesManager, input: {
|
|
25
|
+
resourceType: string;
|
|
26
|
+
resourceName: string;
|
|
27
|
+
localPort: number;
|
|
28
|
+
targetPort: number;
|
|
29
|
+
}): Promise<{
|
|
30
|
+
content: {
|
|
31
|
+
success: boolean;
|
|
32
|
+
message: string;
|
|
33
|
+
}[];
|
|
34
|
+
}>;
|
|
35
|
+
export declare const StopPortForwardSchema: {
|
|
36
|
+
name: string;
|
|
37
|
+
description: string;
|
|
38
|
+
inputSchema: {
|
|
39
|
+
type: string;
|
|
40
|
+
properties: {
|
|
41
|
+
id: {
|
|
42
|
+
type: string;
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
required: string[];
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
export declare function stopPortForward(k8sManager: KubernetesManager, input: {
|
|
49
|
+
id: string;
|
|
50
|
+
}): Promise<{
|
|
51
|
+
content: {
|
|
52
|
+
success: boolean;
|
|
53
|
+
message: string;
|
|
54
|
+
}[];
|
|
55
|
+
}>;
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { spawn } from "child_process";
|
|
2
|
+
// Use spawn instead of exec because port-forward is a long-running process
|
|
3
|
+
async function executeKubectlCommandAsync(command) {
|
|
4
|
+
return new Promise((resolve, reject) => {
|
|
5
|
+
const [cmd, ...args] = command.split(" ");
|
|
6
|
+
const process = spawn(cmd, args);
|
|
7
|
+
let output = "";
|
|
8
|
+
let errorOutput = "";
|
|
9
|
+
process.stdout.on("data", (data) => {
|
|
10
|
+
output += data.toString();
|
|
11
|
+
if (output.includes("Forwarding from")) {
|
|
12
|
+
resolve({
|
|
13
|
+
success: true,
|
|
14
|
+
message: "port-forwarding was successful",
|
|
15
|
+
pid: process.pid,
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
process.stderr.on("data", (data) => {
|
|
20
|
+
errorOutput += data.toString();
|
|
21
|
+
});
|
|
22
|
+
process.on("error", (error) => {
|
|
23
|
+
reject(new Error(`Failed to execute port-forward: ${error.message}`));
|
|
24
|
+
});
|
|
25
|
+
process.on("close", (code) => {
|
|
26
|
+
if (code !== 0) {
|
|
27
|
+
reject(new Error(`Port-forward process exited with code ${code}. Error: ${errorOutput}`));
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
// Set a timeout to reject if we don't see the success message
|
|
31
|
+
setTimeout(() => {
|
|
32
|
+
if (!output.includes("Forwarding from")) {
|
|
33
|
+
reject(new Error("port-forwarding failed - no success message received"));
|
|
34
|
+
}
|
|
35
|
+
}, 5000);
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
export const PortForwardSchema = {
|
|
39
|
+
name: "port_forward",
|
|
40
|
+
description: "Forward a local port to a port on a Kubernetes resource",
|
|
41
|
+
inputSchema: {
|
|
42
|
+
type: "object",
|
|
43
|
+
properties: {
|
|
44
|
+
resourceType: { type: "string" },
|
|
45
|
+
resourceName: { type: "string" },
|
|
46
|
+
localPort: { type: "number" },
|
|
47
|
+
targetPort: { type: "number" },
|
|
48
|
+
},
|
|
49
|
+
required: ["resourceType", "resourceName", "localPort", "targetPort"],
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
export async function startPortForward(k8sManager, input) {
|
|
53
|
+
let command = `kubectl port-forward ${input.resourceType}/${input.resourceName} ${input.localPort}:${input.targetPort}`;
|
|
54
|
+
try {
|
|
55
|
+
const result = await executeKubectlCommandAsync(command);
|
|
56
|
+
// Track the port-forward process
|
|
57
|
+
k8sManager.trackPortForward({
|
|
58
|
+
id: `${input.resourceType}-${input.resourceName}-${input.localPort}`,
|
|
59
|
+
server: {
|
|
60
|
+
stop: async () => {
|
|
61
|
+
try {
|
|
62
|
+
process.kill(result.pid);
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
console.error(`Failed to stop port-forward process ${result.pid}:`, error);
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
resourceType: input.resourceType,
|
|
70
|
+
name: input.resourceName,
|
|
71
|
+
namespace: "default", // TODO: Make namespace configurable
|
|
72
|
+
ports: [{ local: input.localPort, remote: input.targetPort }],
|
|
73
|
+
});
|
|
74
|
+
return {
|
|
75
|
+
content: [{ success: result.success, message: result.message }],
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
throw new Error(`Failed to execute port-forward: ${error.message}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
export const StopPortForwardSchema = {
|
|
83
|
+
name: "stop_port_forward",
|
|
84
|
+
description: "Stop a port-forward process",
|
|
85
|
+
inputSchema: {
|
|
86
|
+
type: "object",
|
|
87
|
+
properties: {
|
|
88
|
+
id: { type: "string" },
|
|
89
|
+
},
|
|
90
|
+
required: ["id"],
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
export async function stopPortForward(k8sManager, input) {
|
|
94
|
+
const portForward = k8sManager.getPortForward(input.id);
|
|
95
|
+
if (!portForward) {
|
|
96
|
+
throw new Error(`Port-forward with id ${input.id} not found`);
|
|
97
|
+
}
|
|
98
|
+
try {
|
|
99
|
+
await portForward.server.stop();
|
|
100
|
+
k8sManager.removePortForward(input.id);
|
|
101
|
+
return {
|
|
102
|
+
content: [
|
|
103
|
+
{ success: true, message: "port-forward stopped successfully" },
|
|
104
|
+
],
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
throw new Error(`Failed to stop port-forward: ${error.message}`);
|
|
109
|
+
}
|
|
110
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-server-kubernetes",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "MCP server for interacting with Kubernetes clusters via kubectl",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -35,19 +35,19 @@
|
|
|
35
35
|
"node": ">=18"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@kubernetes/client-node": "
|
|
39
|
-
"@modelcontextprotocol/sdk": "1.0
|
|
40
|
-
"js-yaml": "
|
|
41
|
-
"yaml": "
|
|
42
|
-
"zod": "
|
|
38
|
+
"@kubernetes/client-node": "0.20.0",
|
|
39
|
+
"@modelcontextprotocol/sdk": "1.7.0",
|
|
40
|
+
"js-yaml": "4.1.0",
|
|
41
|
+
"yaml": "2.7.0",
|
|
42
|
+
"zod": "3.23.8",
|
|
43
43
|
"express": "4.21.2"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
|
-
"@types/express": "
|
|
47
|
-
"@types/js-yaml": "
|
|
48
|
-
"@types/node": "
|
|
49
|
-
"shx": "
|
|
50
|
-
"typescript": "
|
|
46
|
+
"@types/express": "5.0.1",
|
|
47
|
+
"@types/js-yaml": "4.0.9",
|
|
48
|
+
"@types/node": "22.9.3",
|
|
49
|
+
"shx": "0.3.4",
|
|
50
|
+
"typescript": "5.6.2",
|
|
51
51
|
"vitest": "2.1.9"
|
|
52
52
|
}
|
|
53
53
|
}
|