mcp-server-kubernetes 1.6.2 → 2.1.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 +46 -22
- package/dist/config/container-templates.d.ts +2 -2
- package/dist/index.d.ts +314 -736
- package/dist/index.js +93 -200
- package/dist/models/resource-models.d.ts +6 -6
- package/dist/tools/kubectl-apply.d.ts +46 -0
- package/dist/tools/kubectl-apply.js +110 -0
- package/dist/tools/kubectl-context.d.ts +49 -0
- package/dist/tools/kubectl-context.js +233 -0
- package/dist/tools/kubectl-create.d.ts +150 -0
- package/dist/tools/kubectl-create.js +321 -0
- package/dist/tools/kubectl-delete.d.ts +77 -0
- package/dist/tools/kubectl-delete.js +177 -0
- package/dist/tools/kubectl-describe.d.ts +47 -0
- package/dist/tools/kubectl-describe.js +96 -0
- package/dist/tools/kubectl-generic.d.ts +71 -0
- package/dist/tools/kubectl-generic.js +121 -0
- package/dist/tools/kubectl-get.d.ts +72 -0
- package/dist/tools/kubectl-get.js +251 -0
- package/dist/tools/kubectl-list.d.ts +61 -0
- package/dist/tools/kubectl-list.js +189 -0
- package/dist/tools/{get_logs.d.ts → kubectl-logs.d.ts} +35 -19
- package/dist/tools/kubectl-logs.js +312 -0
- package/dist/tools/kubectl-patch.d.ts +57 -0
- package/dist/tools/kubectl-patch.js +128 -0
- package/dist/tools/kubectl-rollout.d.ts +67 -0
- package/dist/tools/kubectl-rollout.js +115 -0
- package/dist/tools/{scale_deployment.d.ts → kubectl-scale.d.ts} +13 -3
- package/dist/tools/kubectl-scale.js +73 -0
- package/dist/utils/kubernetes-manager.d.ts +4 -0
- package/dist/utils/kubernetes-manager.js +21 -3
- package/package.json +1 -1
- package/dist/tools/create_configmap.d.ts +0 -33
- package/dist/tools/create_configmap.js +0 -66
- package/dist/tools/create_cronjob.d.ts +0 -47
- package/dist/tools/create_cronjob.js +0 -93
- package/dist/tools/create_deployment.d.ts +0 -135
- package/dist/tools/create_deployment.js +0 -162
- package/dist/tools/create_namespace.d.ts +0 -22
- package/dist/tools/create_namespace.js +0 -48
- package/dist/tools/create_pod.d.ts +0 -130
- package/dist/tools/create_pod.js +0 -153
- package/dist/tools/create_service.d.ts +0 -74
- package/dist/tools/create_service.js +0 -102
- package/dist/tools/delete_configmap.d.ts +0 -26
- package/dist/tools/delete_configmap.js +0 -49
- package/dist/tools/delete_cronjob.d.ts +0 -26
- package/dist/tools/delete_cronjob.js +0 -48
- package/dist/tools/delete_deployment.d.ts +0 -31
- package/dist/tools/delete_deployment.js +0 -47
- package/dist/tools/delete_namespace.d.ts +0 -27
- package/dist/tools/delete_namespace.js +0 -44
- package/dist/tools/delete_pod.d.ts +0 -31
- package/dist/tools/delete_pod.js +0 -45
- package/dist/tools/delete_service.d.ts +0 -32
- package/dist/tools/delete_service.js +0 -46
- package/dist/tools/describe_cronjob.d.ts +0 -27
- package/dist/tools/describe_cronjob.js +0 -83
- package/dist/tools/describe_deployment.d.ts +0 -26
- package/dist/tools/describe_deployment.js +0 -40
- package/dist/tools/describe_node.d.ts +0 -22
- package/dist/tools/describe_node.js +0 -84
- package/dist/tools/describe_pod.d.ts +0 -33
- package/dist/tools/describe_pod.js +0 -81
- package/dist/tools/describe_service.d.ts +0 -34
- package/dist/tools/describe_service.js +0 -85
- package/dist/tools/get_configmap.d.ts +0 -27
- package/dist/tools/get_configmap.js +0 -48
- package/dist/tools/get_current_context.d.ts +0 -23
- package/dist/tools/get_current_context.js +0 -55
- package/dist/tools/get_events.d.ts +0 -28
- package/dist/tools/get_events.js +0 -66
- package/dist/tools/get_job_logs.d.ts +0 -40
- package/dist/tools/get_job_logs.js +0 -104
- package/dist/tools/get_logs.js +0 -150
- package/dist/tools/list_contexts.d.ts +0 -23
- package/dist/tools/list_contexts.js +0 -39
- package/dist/tools/list_cronjobs.d.ts +0 -23
- package/dist/tools/list_cronjobs.js +0 -35
- package/dist/tools/list_deployments.d.ts +0 -23
- package/dist/tools/list_deployments.js +0 -30
- package/dist/tools/list_jobs.d.ts +0 -29
- package/dist/tools/list_jobs.js +0 -77
- package/dist/tools/list_nodes.d.ts +0 -15
- package/dist/tools/list_nodes.js +0 -21
- package/dist/tools/list_pods.d.ts +0 -23
- package/dist/tools/list_pods.js +0 -29
- package/dist/tools/list_services.d.ts +0 -23
- package/dist/tools/list_services.js +0 -31
- package/dist/tools/scale_deployment.js +0 -50
- package/dist/tools/set_current_context.d.ts +0 -23
- package/dist/tools/set_current_context.js +0 -35
- package/dist/tools/update_configmap.d.ts +0 -33
- package/dist/tools/update_configmap.js +0 -71
- package/dist/tools/update_deployment.d.ts +0 -113
- package/dist/tools/update_deployment.js +0 -155
- package/dist/tools/update_service.d.ts +0 -72
- package/dist/tools/update_service.js +0 -125
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { execSync } from "child_process";
|
|
2
|
+
import { McpError, ErrorCode } from "@modelcontextprotocol/sdk/types.js";
|
|
3
|
+
export const kubectlDescribeSchema = {
|
|
4
|
+
name: "kubectl_describe",
|
|
5
|
+
description: "Describe Kubernetes resources by resource type, name, and optionally namespace",
|
|
6
|
+
inputSchema: {
|
|
7
|
+
type: "object",
|
|
8
|
+
properties: {
|
|
9
|
+
resourceType: {
|
|
10
|
+
type: "string",
|
|
11
|
+
description: "Type of resource to describe (e.g., pods, deployments, services, etc.)"
|
|
12
|
+
},
|
|
13
|
+
name: {
|
|
14
|
+
type: "string",
|
|
15
|
+
description: "Name of the resource to describe"
|
|
16
|
+
},
|
|
17
|
+
namespace: {
|
|
18
|
+
type: "string",
|
|
19
|
+
description: "Namespace of the resource (optional - defaults to 'default' for namespaced resources)",
|
|
20
|
+
default: "default"
|
|
21
|
+
},
|
|
22
|
+
allNamespaces: {
|
|
23
|
+
type: "boolean",
|
|
24
|
+
description: "If true, describe resources across all namespaces",
|
|
25
|
+
default: false
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
required: ["resourceType", "name"],
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
export async function kubectlDescribe(k8sManager, input) {
|
|
32
|
+
try {
|
|
33
|
+
const resourceType = input.resourceType.toLowerCase();
|
|
34
|
+
const name = input.name;
|
|
35
|
+
const namespace = input.namespace || "default";
|
|
36
|
+
const allNamespaces = input.allNamespaces || false;
|
|
37
|
+
// Build the kubectl command
|
|
38
|
+
let command = "kubectl describe ";
|
|
39
|
+
// Add resource type
|
|
40
|
+
command += resourceType;
|
|
41
|
+
// Add name
|
|
42
|
+
command += ` ${name}`;
|
|
43
|
+
// Add namespace flag unless all namespaces is specified
|
|
44
|
+
if (allNamespaces) {
|
|
45
|
+
command += " --all-namespaces";
|
|
46
|
+
}
|
|
47
|
+
else if (namespace && !isNonNamespacedResource(resourceType)) {
|
|
48
|
+
command += ` -n ${namespace}`;
|
|
49
|
+
}
|
|
50
|
+
// Execute the command
|
|
51
|
+
try {
|
|
52
|
+
const result = execSync(command, { encoding: "utf8" });
|
|
53
|
+
return {
|
|
54
|
+
content: [
|
|
55
|
+
{
|
|
56
|
+
type: "text",
|
|
57
|
+
text: result,
|
|
58
|
+
},
|
|
59
|
+
],
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
if (error.status === 404 || error.message.includes("not found")) {
|
|
64
|
+
return {
|
|
65
|
+
content: [
|
|
66
|
+
{
|
|
67
|
+
type: "text",
|
|
68
|
+
text: JSON.stringify({
|
|
69
|
+
error: `Resource ${resourceType}/${name} not found`,
|
|
70
|
+
status: "not_found",
|
|
71
|
+
}, null, 2),
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
isError: true,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
throw new McpError(ErrorCode.InternalError, `Failed to describe resource: ${error.message}`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
throw new McpError(ErrorCode.InternalError, `Failed to execute kubectl describe command: ${error.message}`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// Helper function to determine if a resource is non-namespaced
|
|
85
|
+
function isNonNamespacedResource(resourceType) {
|
|
86
|
+
const nonNamespacedResources = [
|
|
87
|
+
"nodes", "node", "no",
|
|
88
|
+
"namespaces", "namespace", "ns",
|
|
89
|
+
"persistentvolumes", "pv",
|
|
90
|
+
"storageclasses", "sc",
|
|
91
|
+
"clusterroles",
|
|
92
|
+
"clusterrolebindings",
|
|
93
|
+
"customresourcedefinitions", "crd", "crds"
|
|
94
|
+
];
|
|
95
|
+
return nonNamespacedResources.includes(resourceType.toLowerCase());
|
|
96
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { KubernetesManager } from "../types.js";
|
|
2
|
+
export declare const kubectlGenericSchema: {
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
inputSchema: {
|
|
6
|
+
type: string;
|
|
7
|
+
properties: {
|
|
8
|
+
command: {
|
|
9
|
+
type: string;
|
|
10
|
+
description: string;
|
|
11
|
+
};
|
|
12
|
+
subCommand: {
|
|
13
|
+
type: string;
|
|
14
|
+
description: string;
|
|
15
|
+
optional: boolean;
|
|
16
|
+
};
|
|
17
|
+
resourceType: {
|
|
18
|
+
type: string;
|
|
19
|
+
description: string;
|
|
20
|
+
optional: boolean;
|
|
21
|
+
};
|
|
22
|
+
name: {
|
|
23
|
+
type: string;
|
|
24
|
+
description: string;
|
|
25
|
+
optional: boolean;
|
|
26
|
+
};
|
|
27
|
+
namespace: {
|
|
28
|
+
type: string;
|
|
29
|
+
description: string;
|
|
30
|
+
default: string;
|
|
31
|
+
optional: boolean;
|
|
32
|
+
};
|
|
33
|
+
outputFormat: {
|
|
34
|
+
type: string;
|
|
35
|
+
description: string;
|
|
36
|
+
enum: string[];
|
|
37
|
+
optional: boolean;
|
|
38
|
+
};
|
|
39
|
+
flags: {
|
|
40
|
+
type: string;
|
|
41
|
+
description: string;
|
|
42
|
+
optional: boolean;
|
|
43
|
+
additionalProperties: boolean;
|
|
44
|
+
};
|
|
45
|
+
args: {
|
|
46
|
+
type: string;
|
|
47
|
+
items: {
|
|
48
|
+
type: string;
|
|
49
|
+
};
|
|
50
|
+
description: string;
|
|
51
|
+
optional: boolean;
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
required: string[];
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
export declare function kubectlGeneric(k8sManager: KubernetesManager, input: {
|
|
58
|
+
command: string;
|
|
59
|
+
subCommand?: string;
|
|
60
|
+
resourceType?: string;
|
|
61
|
+
name?: string;
|
|
62
|
+
namespace?: string;
|
|
63
|
+
outputFormat?: string;
|
|
64
|
+
flags?: Record<string, any>;
|
|
65
|
+
args?: string[];
|
|
66
|
+
}): Promise<{
|
|
67
|
+
content: {
|
|
68
|
+
type: string;
|
|
69
|
+
text: string;
|
|
70
|
+
}[];
|
|
71
|
+
}>;
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { execSync } from "child_process";
|
|
2
|
+
import { McpError, ErrorCode } from "@modelcontextprotocol/sdk/types.js";
|
|
3
|
+
export const kubectlGenericSchema = {
|
|
4
|
+
name: "kubectl_generic",
|
|
5
|
+
description: "Execute any kubectl command with the provided arguments and flags",
|
|
6
|
+
inputSchema: {
|
|
7
|
+
type: "object",
|
|
8
|
+
properties: {
|
|
9
|
+
command: {
|
|
10
|
+
type: "string",
|
|
11
|
+
description: "The kubectl command to execute (e.g. patch, rollout, top)"
|
|
12
|
+
},
|
|
13
|
+
subCommand: {
|
|
14
|
+
type: "string",
|
|
15
|
+
description: "Subcommand if applicable (e.g. 'history' for rollout)",
|
|
16
|
+
optional: true
|
|
17
|
+
},
|
|
18
|
+
resourceType: {
|
|
19
|
+
type: "string",
|
|
20
|
+
description: "Resource type (e.g. pod, deployment)",
|
|
21
|
+
optional: true
|
|
22
|
+
},
|
|
23
|
+
name: {
|
|
24
|
+
type: "string",
|
|
25
|
+
description: "Resource name",
|
|
26
|
+
optional: true
|
|
27
|
+
},
|
|
28
|
+
namespace: {
|
|
29
|
+
type: "string",
|
|
30
|
+
description: "Namespace",
|
|
31
|
+
default: "default",
|
|
32
|
+
optional: true
|
|
33
|
+
},
|
|
34
|
+
outputFormat: {
|
|
35
|
+
type: "string",
|
|
36
|
+
description: "Output format (e.g. json, yaml, wide)",
|
|
37
|
+
enum: ["json", "yaml", "wide", "name", "custom"],
|
|
38
|
+
optional: true
|
|
39
|
+
},
|
|
40
|
+
flags: {
|
|
41
|
+
type: "object",
|
|
42
|
+
description: "Command flags as key-value pairs",
|
|
43
|
+
optional: true,
|
|
44
|
+
additionalProperties: true
|
|
45
|
+
},
|
|
46
|
+
args: {
|
|
47
|
+
type: "array",
|
|
48
|
+
items: { type: "string" },
|
|
49
|
+
description: "Additional command arguments",
|
|
50
|
+
optional: true
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
required: ["command"]
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
export async function kubectlGeneric(k8sManager, input) {
|
|
57
|
+
try {
|
|
58
|
+
// Start building the kubectl command
|
|
59
|
+
let cmdArgs = ["kubectl", input.command];
|
|
60
|
+
// Add subcommand if provided
|
|
61
|
+
if (input.subCommand) {
|
|
62
|
+
cmdArgs.push(input.subCommand);
|
|
63
|
+
}
|
|
64
|
+
// Add resource type if provided
|
|
65
|
+
if (input.resourceType) {
|
|
66
|
+
cmdArgs.push(input.resourceType);
|
|
67
|
+
}
|
|
68
|
+
// Add resource name if provided
|
|
69
|
+
if (input.name) {
|
|
70
|
+
cmdArgs.push(input.name);
|
|
71
|
+
}
|
|
72
|
+
// Add namespace if provided
|
|
73
|
+
if (input.namespace) {
|
|
74
|
+
cmdArgs.push(`--namespace=${input.namespace}`);
|
|
75
|
+
}
|
|
76
|
+
// Add output format if provided
|
|
77
|
+
if (input.outputFormat) {
|
|
78
|
+
cmdArgs.push(`-o=${input.outputFormat}`);
|
|
79
|
+
}
|
|
80
|
+
// Add any provided flags
|
|
81
|
+
if (input.flags) {
|
|
82
|
+
for (const [key, value] of Object.entries(input.flags)) {
|
|
83
|
+
if (value === true) {
|
|
84
|
+
// Handle boolean flags
|
|
85
|
+
cmdArgs.push(`--${key}`);
|
|
86
|
+
}
|
|
87
|
+
else if (value !== false && value !== null && value !== undefined) {
|
|
88
|
+
// Skip false/null/undefined values, add others as --key=value
|
|
89
|
+
cmdArgs.push(`--${key}=${value}`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
// Add any additional arguments
|
|
94
|
+
if (input.args && input.args.length > 0) {
|
|
95
|
+
cmdArgs.push(...input.args);
|
|
96
|
+
}
|
|
97
|
+
// Execute the command (join all args except the first "kubectl" which is used in execSync)
|
|
98
|
+
const command = cmdArgs.slice(1).join(' ');
|
|
99
|
+
try {
|
|
100
|
+
console.log(`Executing: kubectl ${command}`);
|
|
101
|
+
const result = execSync(`kubectl ${command}`, { encoding: "utf8" });
|
|
102
|
+
return {
|
|
103
|
+
content: [
|
|
104
|
+
{
|
|
105
|
+
type: "text",
|
|
106
|
+
text: result,
|
|
107
|
+
},
|
|
108
|
+
],
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
throw new McpError(ErrorCode.InternalError, `Failed to execute kubectl command: ${error.message}`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
if (error instanceof McpError) {
|
|
117
|
+
throw error;
|
|
118
|
+
}
|
|
119
|
+
throw new McpError(ErrorCode.InternalError, `Failed to execute kubectl command: ${error.message}`);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { KubernetesManager } from "../types.js";
|
|
2
|
+
export declare const kubectlGetSchema: {
|
|
3
|
+
readonly name: "kubectl_get";
|
|
4
|
+
readonly description: "Get or list Kubernetes resources by resource type, name, and optionally namespace";
|
|
5
|
+
readonly inputSchema: {
|
|
6
|
+
readonly type: "object";
|
|
7
|
+
readonly properties: {
|
|
8
|
+
readonly resourceType: {
|
|
9
|
+
readonly type: "string";
|
|
10
|
+
readonly description: "Type of resource to get (e.g., pods, deployments, services, configmaps, events, etc.)";
|
|
11
|
+
};
|
|
12
|
+
readonly name: {
|
|
13
|
+
readonly type: "string";
|
|
14
|
+
readonly description: "Name of the resource (optional - if not provided, lists all resources of the specified type)";
|
|
15
|
+
};
|
|
16
|
+
readonly namespace: {
|
|
17
|
+
readonly type: "string";
|
|
18
|
+
readonly description: "Namespace of the resource (optional - defaults to 'default' for namespaced resources)";
|
|
19
|
+
readonly default: "default";
|
|
20
|
+
};
|
|
21
|
+
readonly output: {
|
|
22
|
+
readonly type: "string";
|
|
23
|
+
readonly enum: readonly ["json", "yaml", "wide", "name", "custom"];
|
|
24
|
+
readonly description: "Output format";
|
|
25
|
+
readonly default: "json";
|
|
26
|
+
};
|
|
27
|
+
readonly allNamespaces: {
|
|
28
|
+
readonly type: "boolean";
|
|
29
|
+
readonly description: "If true, list resources across all namespaces";
|
|
30
|
+
readonly default: false;
|
|
31
|
+
};
|
|
32
|
+
readonly labelSelector: {
|
|
33
|
+
readonly type: "string";
|
|
34
|
+
readonly description: "Filter resources by label selector (e.g. 'app=nginx')";
|
|
35
|
+
readonly optional: true;
|
|
36
|
+
};
|
|
37
|
+
readonly fieldSelector: {
|
|
38
|
+
readonly type: "string";
|
|
39
|
+
readonly description: "Filter resources by field selector (e.g. 'metadata.name=my-pod')";
|
|
40
|
+
readonly optional: true;
|
|
41
|
+
};
|
|
42
|
+
readonly sortBy: {
|
|
43
|
+
readonly type: "string";
|
|
44
|
+
readonly description: "Sort events by a field (default: lastTimestamp). Only applicable for events.";
|
|
45
|
+
readonly optional: true;
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
readonly required: readonly ["resourceType"];
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
export declare function kubectlGet(k8sManager: KubernetesManager, input: {
|
|
52
|
+
resourceType: string;
|
|
53
|
+
name?: string;
|
|
54
|
+
namespace?: string;
|
|
55
|
+
output?: string;
|
|
56
|
+
allNamespaces?: boolean;
|
|
57
|
+
labelSelector?: string;
|
|
58
|
+
fieldSelector?: string;
|
|
59
|
+
sortBy?: string;
|
|
60
|
+
}): Promise<{
|
|
61
|
+
content: {
|
|
62
|
+
type: string;
|
|
63
|
+
text: string;
|
|
64
|
+
}[];
|
|
65
|
+
isError?: undefined;
|
|
66
|
+
} | {
|
|
67
|
+
content: {
|
|
68
|
+
type: string;
|
|
69
|
+
text: string;
|
|
70
|
+
}[];
|
|
71
|
+
isError: boolean;
|
|
72
|
+
}>;
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import { execSync } from "child_process";
|
|
2
|
+
import { McpError, ErrorCode } from "@modelcontextprotocol/sdk/types.js";
|
|
3
|
+
export const kubectlGetSchema = {
|
|
4
|
+
name: "kubectl_get",
|
|
5
|
+
description: "Get or list Kubernetes resources by resource type, name, and optionally namespace",
|
|
6
|
+
inputSchema: {
|
|
7
|
+
type: "object",
|
|
8
|
+
properties: {
|
|
9
|
+
resourceType: {
|
|
10
|
+
type: "string",
|
|
11
|
+
description: "Type of resource to get (e.g., pods, deployments, services, configmaps, events, etc.)"
|
|
12
|
+
},
|
|
13
|
+
name: {
|
|
14
|
+
type: "string",
|
|
15
|
+
description: "Name of the resource (optional - if not provided, lists all resources of the specified type)"
|
|
16
|
+
},
|
|
17
|
+
namespace: {
|
|
18
|
+
type: "string",
|
|
19
|
+
description: "Namespace of the resource (optional - defaults to 'default' for namespaced resources)",
|
|
20
|
+
default: "default"
|
|
21
|
+
},
|
|
22
|
+
output: {
|
|
23
|
+
type: "string",
|
|
24
|
+
enum: ["json", "yaml", "wide", "name", "custom"],
|
|
25
|
+
description: "Output format",
|
|
26
|
+
default: "json"
|
|
27
|
+
},
|
|
28
|
+
allNamespaces: {
|
|
29
|
+
type: "boolean",
|
|
30
|
+
description: "If true, list resources across all namespaces",
|
|
31
|
+
default: false
|
|
32
|
+
},
|
|
33
|
+
labelSelector: {
|
|
34
|
+
type: "string",
|
|
35
|
+
description: "Filter resources by label selector (e.g. 'app=nginx')",
|
|
36
|
+
optional: true
|
|
37
|
+
},
|
|
38
|
+
fieldSelector: {
|
|
39
|
+
type: "string",
|
|
40
|
+
description: "Filter resources by field selector (e.g. 'metadata.name=my-pod')",
|
|
41
|
+
optional: true
|
|
42
|
+
},
|
|
43
|
+
sortBy: {
|
|
44
|
+
type: "string",
|
|
45
|
+
description: "Sort events by a field (default: lastTimestamp). Only applicable for events.",
|
|
46
|
+
optional: true
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
required: ["resourceType"],
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
export async function kubectlGet(k8sManager, input) {
|
|
53
|
+
try {
|
|
54
|
+
const resourceType = input.resourceType.toLowerCase();
|
|
55
|
+
const name = input.name || "";
|
|
56
|
+
const namespace = input.namespace || "default";
|
|
57
|
+
const output = input.output || "json";
|
|
58
|
+
const allNamespaces = input.allNamespaces || false;
|
|
59
|
+
const labelSelector = input.labelSelector || "";
|
|
60
|
+
const fieldSelector = input.fieldSelector || "";
|
|
61
|
+
const sortBy = input.sortBy;
|
|
62
|
+
// Build the kubectl command
|
|
63
|
+
let command = "kubectl get ";
|
|
64
|
+
// Add resource type
|
|
65
|
+
command += resourceType;
|
|
66
|
+
// Add name if provided
|
|
67
|
+
if (name) {
|
|
68
|
+
command += ` ${name}`;
|
|
69
|
+
}
|
|
70
|
+
// For events, default to all namespaces unless explicitly specified
|
|
71
|
+
const shouldShowAllNamespaces = resourceType === "events" ?
|
|
72
|
+
(input.namespace ? false : true) : allNamespaces;
|
|
73
|
+
// Add namespace flag unless all namespaces is specified
|
|
74
|
+
if (shouldShowAllNamespaces) {
|
|
75
|
+
command += " --all-namespaces";
|
|
76
|
+
}
|
|
77
|
+
else if (namespace && !isNonNamespacedResource(resourceType)) {
|
|
78
|
+
command += ` -n ${namespace}`;
|
|
79
|
+
}
|
|
80
|
+
// Add label selector if provided
|
|
81
|
+
if (labelSelector) {
|
|
82
|
+
command += ` -l ${labelSelector}`;
|
|
83
|
+
}
|
|
84
|
+
// Add field selector if provided
|
|
85
|
+
if (fieldSelector) {
|
|
86
|
+
command += ` --field-selector=${fieldSelector}`;
|
|
87
|
+
}
|
|
88
|
+
// Add sort-by for events
|
|
89
|
+
if (resourceType === "events" && sortBy) {
|
|
90
|
+
command += ` --sort-by=.${sortBy}`;
|
|
91
|
+
}
|
|
92
|
+
else if (resourceType === "events") {
|
|
93
|
+
command += ` --sort-by=.lastTimestamp`;
|
|
94
|
+
}
|
|
95
|
+
// Add output format
|
|
96
|
+
if (output === "json") {
|
|
97
|
+
command += " -o json";
|
|
98
|
+
}
|
|
99
|
+
else if (output === "yaml") {
|
|
100
|
+
command += " -o yaml";
|
|
101
|
+
}
|
|
102
|
+
else if (output === "wide") {
|
|
103
|
+
command += " -o wide";
|
|
104
|
+
}
|
|
105
|
+
else if (output === "name") {
|
|
106
|
+
command += " -o name";
|
|
107
|
+
}
|
|
108
|
+
else if (output === "custom") {
|
|
109
|
+
if (resourceType === "events") {
|
|
110
|
+
command += ` -o 'custom-columns=LAST SEEN:.lastTimestamp,TYPE:.type,REASON:.reason,OBJECT:.involvedObject.kind/.involvedObject.name,MESSAGE:.message'`;
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
command += ` -o 'custom-columns=NAME:.metadata.name,NAMESPACE:.metadata.namespace,STATUS:.status.phase,AGE:.metadata.creationTimestamp'`;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// Execute the command
|
|
117
|
+
try {
|
|
118
|
+
const result = execSync(command, { encoding: "utf8" });
|
|
119
|
+
// Format the results for better readability
|
|
120
|
+
const isListOperation = !name;
|
|
121
|
+
if (isListOperation && output === "json") {
|
|
122
|
+
try {
|
|
123
|
+
// Parse JSON and extract key information
|
|
124
|
+
const parsed = JSON.parse(result);
|
|
125
|
+
if (parsed.kind && parsed.kind.endsWith("List") && parsed.items) {
|
|
126
|
+
if (resourceType === "events") {
|
|
127
|
+
const formattedEvents = parsed.items.map((event) => ({
|
|
128
|
+
type: event.type || "",
|
|
129
|
+
reason: event.reason || "",
|
|
130
|
+
message: event.message || "",
|
|
131
|
+
involvedObject: {
|
|
132
|
+
kind: event.involvedObject?.kind || "",
|
|
133
|
+
name: event.involvedObject?.name || "",
|
|
134
|
+
namespace: event.involvedObject?.namespace || "",
|
|
135
|
+
},
|
|
136
|
+
firstTimestamp: event.firstTimestamp || "",
|
|
137
|
+
lastTimestamp: event.lastTimestamp || "",
|
|
138
|
+
count: event.count || 0,
|
|
139
|
+
}));
|
|
140
|
+
return {
|
|
141
|
+
content: [
|
|
142
|
+
{
|
|
143
|
+
type: "text",
|
|
144
|
+
text: JSON.stringify({ events: formattedEvents }, null, 2),
|
|
145
|
+
},
|
|
146
|
+
],
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
const items = parsed.items.map((item) => ({
|
|
151
|
+
name: item.metadata?.name || "",
|
|
152
|
+
namespace: item.metadata?.namespace || "",
|
|
153
|
+
kind: item.kind || resourceType,
|
|
154
|
+
status: getResourceStatus(item),
|
|
155
|
+
createdAt: item.metadata?.creationTimestamp
|
|
156
|
+
}));
|
|
157
|
+
return {
|
|
158
|
+
content: [
|
|
159
|
+
{
|
|
160
|
+
type: "text",
|
|
161
|
+
text: JSON.stringify({ items }, null, 2),
|
|
162
|
+
},
|
|
163
|
+
],
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
catch (parseError) {
|
|
169
|
+
// If JSON parsing fails, return the raw output
|
|
170
|
+
console.error("Error parsing JSON:", parseError);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return {
|
|
174
|
+
content: [
|
|
175
|
+
{
|
|
176
|
+
type: "text",
|
|
177
|
+
text: result,
|
|
178
|
+
},
|
|
179
|
+
],
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
catch (error) {
|
|
183
|
+
if (error.status === 404 || error.message.includes("not found")) {
|
|
184
|
+
return {
|
|
185
|
+
content: [
|
|
186
|
+
{
|
|
187
|
+
type: "text",
|
|
188
|
+
text: JSON.stringify({
|
|
189
|
+
error: `Resource ${resourceType}${name ? `/${name}` : ""} not found`,
|
|
190
|
+
status: "not_found",
|
|
191
|
+
}, null, 2),
|
|
192
|
+
},
|
|
193
|
+
],
|
|
194
|
+
isError: true,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
throw new McpError(ErrorCode.InternalError, `Failed to get resource: ${error.message}`);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
catch (error) {
|
|
201
|
+
throw new McpError(ErrorCode.InternalError, `Failed to execute kubectl get command: ${error.message}`);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
// Extract status from various resource types
|
|
205
|
+
function getResourceStatus(resource) {
|
|
206
|
+
if (!resource)
|
|
207
|
+
return "Unknown";
|
|
208
|
+
// Pod status
|
|
209
|
+
if (resource.status?.phase) {
|
|
210
|
+
return resource.status.phase;
|
|
211
|
+
}
|
|
212
|
+
// Deployment, ReplicaSet, StatefulSet status
|
|
213
|
+
if (resource.status?.readyReplicas !== undefined) {
|
|
214
|
+
const ready = resource.status.readyReplicas || 0;
|
|
215
|
+
const total = resource.status.replicas || 0;
|
|
216
|
+
return `${ready}/${total} ready`;
|
|
217
|
+
}
|
|
218
|
+
// Service status
|
|
219
|
+
if (resource.spec?.type) {
|
|
220
|
+
return resource.spec.type;
|
|
221
|
+
}
|
|
222
|
+
// Node status
|
|
223
|
+
if (resource.status?.conditions) {
|
|
224
|
+
const readyCondition = resource.status.conditions.find((c) => c.type === "Ready");
|
|
225
|
+
if (readyCondition) {
|
|
226
|
+
return readyCondition.status === "True" ? "Ready" : "NotReady";
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
// Job/CronJob status
|
|
230
|
+
if (resource.status?.succeeded !== undefined) {
|
|
231
|
+
return resource.status.succeeded ? "Completed" : "Running";
|
|
232
|
+
}
|
|
233
|
+
// PV/PVC status
|
|
234
|
+
if (resource.status?.phase) {
|
|
235
|
+
return resource.status.phase;
|
|
236
|
+
}
|
|
237
|
+
return "Active";
|
|
238
|
+
}
|
|
239
|
+
// Helper function to determine if a resource is non-namespaced
|
|
240
|
+
function isNonNamespacedResource(resourceType) {
|
|
241
|
+
const nonNamespacedResources = [
|
|
242
|
+
"nodes", "node", "no",
|
|
243
|
+
"namespaces", "namespace", "ns",
|
|
244
|
+
"persistentvolumes", "pv",
|
|
245
|
+
"storageclasses", "sc",
|
|
246
|
+
"clusterroles",
|
|
247
|
+
"clusterrolebindings",
|
|
248
|
+
"customresourcedefinitions", "crd", "crds"
|
|
249
|
+
];
|
|
250
|
+
return nonNamespacedResources.includes(resourceType.toLowerCase());
|
|
251
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { KubernetesManager } from "../types.js";
|
|
2
|
+
export declare const kubectlListSchema: {
|
|
3
|
+
readonly name: "kubectl_list";
|
|
4
|
+
readonly description: "List Kubernetes resources by resource type and optionally namespace";
|
|
5
|
+
readonly inputSchema: {
|
|
6
|
+
readonly type: "object";
|
|
7
|
+
readonly properties: {
|
|
8
|
+
readonly resourceType: {
|
|
9
|
+
readonly type: "string";
|
|
10
|
+
readonly description: "Type of resource to list (e.g., pods, deployments, services, configmaps, etc.)";
|
|
11
|
+
};
|
|
12
|
+
readonly namespace: {
|
|
13
|
+
readonly type: "string";
|
|
14
|
+
readonly description: "Namespace of the resources (optional - defaults to 'default' for namespaced resources)";
|
|
15
|
+
readonly default: "default";
|
|
16
|
+
};
|
|
17
|
+
readonly output: {
|
|
18
|
+
readonly type: "string";
|
|
19
|
+
readonly enum: readonly ["json", "yaml", "wide", "name", "custom", "formatted"];
|
|
20
|
+
readonly description: "Output format - 'formatted' uses a resource-specific format with key information";
|
|
21
|
+
readonly default: "formatted";
|
|
22
|
+
};
|
|
23
|
+
readonly allNamespaces: {
|
|
24
|
+
readonly type: "boolean";
|
|
25
|
+
readonly description: "If true, list resources across all namespaces";
|
|
26
|
+
readonly default: false;
|
|
27
|
+
};
|
|
28
|
+
readonly labelSelector: {
|
|
29
|
+
readonly type: "string";
|
|
30
|
+
readonly description: "Filter resources by label selector (e.g. 'app=nginx')";
|
|
31
|
+
readonly optional: true;
|
|
32
|
+
};
|
|
33
|
+
readonly fieldSelector: {
|
|
34
|
+
readonly type: "string";
|
|
35
|
+
readonly description: "Filter resources by field selector (e.g. 'metadata.name=my-pod')";
|
|
36
|
+
readonly optional: true;
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
readonly required: readonly ["resourceType"];
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
export declare function kubectlList(k8sManager: KubernetesManager, input: {
|
|
43
|
+
resourceType: string;
|
|
44
|
+
namespace?: string;
|
|
45
|
+
output?: string;
|
|
46
|
+
allNamespaces?: boolean;
|
|
47
|
+
labelSelector?: string;
|
|
48
|
+
fieldSelector?: string;
|
|
49
|
+
}): Promise<{
|
|
50
|
+
content: {
|
|
51
|
+
type: string;
|
|
52
|
+
text: string;
|
|
53
|
+
}[];
|
|
54
|
+
isError?: undefined;
|
|
55
|
+
} | {
|
|
56
|
+
content: {
|
|
57
|
+
type: string;
|
|
58
|
+
text: string;
|
|
59
|
+
}[];
|
|
60
|
+
isError: boolean;
|
|
61
|
+
}>;
|