mcp-server-kubernetes 2.4.9 → 2.5.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/dist/config/max-buffer.d.ts +1 -0
- package/dist/config/max-buffer.js +3 -0
- package/dist/index.js +27 -5
- package/dist/tools/exec_in_pod.d.ts +0 -3
- package/dist/tools/exec_in_pod.js +0 -3
- package/dist/tools/helm-operations.js +39 -17
- package/dist/tools/kubectl-apply.js +20 -14
- package/dist/tools/kubectl-context.js +53 -24
- package/dist/tools/kubectl-create.js +78 -59
- package/dist/tools/kubectl-delete.js +44 -28
- package/dist/tools/kubectl-describe.js +29 -19
- package/dist/tools/kubectl-generic.js +22 -17
- package/dist/tools/kubectl-get.js +22 -21
- package/dist/tools/kubectl-logs.js +99 -43
- package/dist/tools/kubectl-operations.js +22 -15
- package/dist/tools/kubectl-patch.js +25 -20
- package/dist/tools/kubectl-rollout.js +35 -22
- package/dist/tools/kubectl-scale.js +31 -20
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function getSpawnMaxBuffer(): number;
|
package/dist/index.js
CHANGED
|
@@ -24,8 +24,20 @@ import { kubectlPatch, kubectlPatchSchema } from "./tools/kubectl-patch.js";
|
|
|
24
24
|
import { kubectlRollout, kubectlRolloutSchema, } from "./tools/kubectl-rollout.js";
|
|
25
25
|
import { registerPromptHandlers } from "./prompts/index.js";
|
|
26
26
|
import { ping, pingSchema } from "./tools/ping.js";
|
|
27
|
-
// Check
|
|
27
|
+
// Check environment variables for tool filtering
|
|
28
|
+
const allowOnlyReadonlyTools = process.env.ALLOW_ONLY_READONLY_TOOLS === "true";
|
|
29
|
+
const allowedToolsEnv = process.env.ALLOWED_TOOLS;
|
|
28
30
|
const nonDestructiveTools = process.env.ALLOW_ONLY_NON_DESTRUCTIVE_TOOLS === "true";
|
|
31
|
+
// Define readonly tools
|
|
32
|
+
const readonlyTools = [
|
|
33
|
+
kubectlGetSchema,
|
|
34
|
+
kubectlDescribeSchema,
|
|
35
|
+
kubectlLogsSchema,
|
|
36
|
+
kubectlContextSchema,
|
|
37
|
+
explainResourceSchema,
|
|
38
|
+
listApiResourcesSchema,
|
|
39
|
+
pingSchema,
|
|
40
|
+
];
|
|
29
41
|
// Define destructive tools (delete and uninstall operations)
|
|
30
42
|
const destructiveTools = [
|
|
31
43
|
kubectlDeleteSchema, // This replaces all individual delete operations
|
|
@@ -85,10 +97,20 @@ server.setRequestHandler(ReadResourceRequestSchema, resourceHandlers.readResourc
|
|
|
85
97
|
registerPromptHandlers(server, k8sManager);
|
|
86
98
|
// Tools handlers
|
|
87
99
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
100
|
+
let tools;
|
|
101
|
+
if (allowedToolsEnv) {
|
|
102
|
+
const allowedToolNames = allowedToolsEnv.split(",").map((t) => t.trim());
|
|
103
|
+
tools = allTools.filter((tool) => allowedToolNames.includes(tool.name));
|
|
104
|
+
}
|
|
105
|
+
else if (allowOnlyReadonlyTools) {
|
|
106
|
+
tools = readonlyTools;
|
|
107
|
+
}
|
|
108
|
+
else if (nonDestructiveTools) {
|
|
109
|
+
tools = allTools.filter((tool) => !destructiveTools.some((dt) => dt.name === tool.name));
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
tools = allTools;
|
|
113
|
+
}
|
|
92
114
|
return { tools };
|
|
93
115
|
});
|
|
94
116
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
@@ -42,17 +42,14 @@ export declare const execInPodSchema: {
|
|
|
42
42
|
container: {
|
|
43
43
|
type: string;
|
|
44
44
|
description: string;
|
|
45
|
-
optional: boolean;
|
|
46
45
|
};
|
|
47
46
|
shell: {
|
|
48
47
|
type: string;
|
|
49
48
|
description: string;
|
|
50
|
-
optional: boolean;
|
|
51
49
|
};
|
|
52
50
|
timeout: {
|
|
53
51
|
type: string;
|
|
54
52
|
description: string;
|
|
55
|
-
optional: boolean;
|
|
56
53
|
};
|
|
57
54
|
};
|
|
58
55
|
required: string[];
|
|
@@ -39,17 +39,14 @@ export const execInPodSchema = {
|
|
|
39
39
|
container: {
|
|
40
40
|
type: "string",
|
|
41
41
|
description: "Container name (required when pod has multiple containers)",
|
|
42
|
-
optional: true,
|
|
43
42
|
},
|
|
44
43
|
shell: {
|
|
45
44
|
type: "string",
|
|
46
45
|
description: "Shell to use for command execution (e.g. '/bin/sh', '/bin/bash'). If not provided, will use command as-is.",
|
|
47
|
-
optional: true,
|
|
48
46
|
},
|
|
49
47
|
timeout: {
|
|
50
48
|
type: "number",
|
|
51
49
|
description: "Timeout for command - 60000 milliseconds if not specified",
|
|
52
|
-
optional: true,
|
|
53
50
|
},
|
|
54
51
|
},
|
|
55
52
|
required: ["name", "command"],
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { execFileSync } from "child_process";
|
|
2
2
|
import { writeFileSync, unlinkSync } from "fs";
|
|
3
3
|
import yaml from "yaml";
|
|
4
|
+
import { getSpawnMaxBuffer } from "../config/max-buffer.js";
|
|
4
5
|
export const installHelmChartSchema = {
|
|
5
6
|
name: "install_helm_chart",
|
|
6
7
|
description: "Install a Helm chart",
|
|
@@ -83,13 +84,14 @@ export const uninstallHelmChartSchema = {
|
|
|
83
84
|
required: ["name", "namespace"],
|
|
84
85
|
},
|
|
85
86
|
};
|
|
86
|
-
const executeHelmCommand = (command) => {
|
|
87
|
+
const executeHelmCommand = (command, args) => {
|
|
87
88
|
try {
|
|
88
89
|
// Add a generous timeout of 60 seconds for Helm operations
|
|
89
|
-
return
|
|
90
|
+
return execFileSync(command, args, {
|
|
90
91
|
encoding: "utf8",
|
|
91
92
|
timeout: 60000, // 60 seconds timeout
|
|
92
|
-
|
|
93
|
+
maxBuffer: getSpawnMaxBuffer(),
|
|
94
|
+
env: { ...process.env, KUBECONFIG: process.env.KUBECONFIG },
|
|
93
95
|
});
|
|
94
96
|
}
|
|
95
97
|
catch (error) {
|
|
@@ -106,16 +108,24 @@ export async function installHelmChart(params) {
|
|
|
106
108
|
// Add helm repository if provided
|
|
107
109
|
if (params.repo) {
|
|
108
110
|
const repoName = params.chart.split("/")[0];
|
|
109
|
-
executeHelmCommand(
|
|
110
|
-
executeHelmCommand("helm repo update");
|
|
111
|
+
executeHelmCommand("helm", ["repo", "add", repoName, params.repo]);
|
|
112
|
+
executeHelmCommand("helm", ["repo", "update"]);
|
|
111
113
|
}
|
|
112
|
-
let command =
|
|
114
|
+
let command = "helm";
|
|
115
|
+
let args = [
|
|
116
|
+
"install",
|
|
117
|
+
params.name,
|
|
118
|
+
params.chart,
|
|
119
|
+
"--namespace",
|
|
120
|
+
params.namespace,
|
|
121
|
+
"--create-namespace",
|
|
122
|
+
];
|
|
113
123
|
// Handle values if provided
|
|
114
124
|
if (params.values) {
|
|
115
125
|
const valuesFile = writeValuesFile(params.name, params.values);
|
|
116
|
-
|
|
126
|
+
args.push("-f", valuesFile);
|
|
117
127
|
try {
|
|
118
|
-
executeHelmCommand(command);
|
|
128
|
+
executeHelmCommand(command, args);
|
|
119
129
|
}
|
|
120
130
|
finally {
|
|
121
131
|
// Cleanup values file
|
|
@@ -123,7 +133,7 @@ export async function installHelmChart(params) {
|
|
|
123
133
|
}
|
|
124
134
|
}
|
|
125
135
|
else {
|
|
126
|
-
executeHelmCommand(command);
|
|
136
|
+
executeHelmCommand(command, args);
|
|
127
137
|
}
|
|
128
138
|
const response = {
|
|
129
139
|
status: "installed",
|
|
@@ -147,16 +157,23 @@ export async function upgradeHelmChart(params) {
|
|
|
147
157
|
// Add helm repository if provided
|
|
148
158
|
if (params.repo) {
|
|
149
159
|
const repoName = params.chart.split("/")[0];
|
|
150
|
-
executeHelmCommand(
|
|
151
|
-
executeHelmCommand("helm repo update");
|
|
160
|
+
executeHelmCommand("helm", ["repo", "add", repoName, params.repo]);
|
|
161
|
+
executeHelmCommand("helm", ["repo", "update"]);
|
|
152
162
|
}
|
|
153
|
-
let command =
|
|
163
|
+
let command = "helm";
|
|
164
|
+
let args = [
|
|
165
|
+
"upgrade",
|
|
166
|
+
params.name,
|
|
167
|
+
params.chart,
|
|
168
|
+
"--namespace",
|
|
169
|
+
params.namespace,
|
|
170
|
+
];
|
|
154
171
|
// Handle values if provided
|
|
155
172
|
if (params.values) {
|
|
156
173
|
const valuesFile = writeValuesFile(params.name, params.values);
|
|
157
|
-
|
|
174
|
+
args.push("-f", valuesFile);
|
|
158
175
|
try {
|
|
159
|
-
executeHelmCommand(command);
|
|
176
|
+
executeHelmCommand(command, args);
|
|
160
177
|
}
|
|
161
178
|
finally {
|
|
162
179
|
// Cleanup values file
|
|
@@ -164,7 +181,7 @@ export async function upgradeHelmChart(params) {
|
|
|
164
181
|
}
|
|
165
182
|
}
|
|
166
183
|
else {
|
|
167
|
-
executeHelmCommand(command);
|
|
184
|
+
executeHelmCommand(command, args);
|
|
168
185
|
}
|
|
169
186
|
const response = {
|
|
170
187
|
status: "upgraded",
|
|
@@ -185,7 +202,12 @@ export async function upgradeHelmChart(params) {
|
|
|
185
202
|
}
|
|
186
203
|
export async function uninstallHelmChart(params) {
|
|
187
204
|
try {
|
|
188
|
-
executeHelmCommand(
|
|
205
|
+
executeHelmCommand("helm", [
|
|
206
|
+
"uninstall",
|
|
207
|
+
params.name,
|
|
208
|
+
"--namespace",
|
|
209
|
+
params.namespace,
|
|
210
|
+
]);
|
|
189
211
|
const response = {
|
|
190
212
|
status: "uninstalled",
|
|
191
213
|
message: `Successfully uninstalled ${params.name}`,
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { execFileSync } from "child_process";
|
|
2
2
|
import { McpError, ErrorCode } from "@modelcontextprotocol/sdk/types.js";
|
|
3
3
|
import * as fs from "fs";
|
|
4
4
|
import * as path from "path";
|
|
5
5
|
import * as os from "os";
|
|
6
|
+
import { getSpawnMaxBuffer } from "../config/max-buffer.js";
|
|
6
7
|
export const kubectlApplySchema = {
|
|
7
8
|
name: "kubectl_apply",
|
|
8
9
|
description: "Apply a Kubernetes YAML manifest from a string or file",
|
|
@@ -11,27 +12,27 @@ export const kubectlApplySchema = {
|
|
|
11
12
|
properties: {
|
|
12
13
|
manifest: {
|
|
13
14
|
type: "string",
|
|
14
|
-
description: "YAML manifest to apply"
|
|
15
|
+
description: "YAML manifest to apply",
|
|
15
16
|
},
|
|
16
17
|
filename: {
|
|
17
18
|
type: "string",
|
|
18
|
-
description: "Path to a YAML file to apply (optional - use either manifest or filename)"
|
|
19
|
+
description: "Path to a YAML file to apply (optional - use either manifest or filename)",
|
|
19
20
|
},
|
|
20
21
|
namespace: {
|
|
21
22
|
type: "string",
|
|
22
23
|
description: "Namespace to apply the resource to (optional)",
|
|
23
|
-
default: "default"
|
|
24
|
+
default: "default",
|
|
24
25
|
},
|
|
25
26
|
dryRun: {
|
|
26
27
|
type: "boolean",
|
|
27
28
|
description: "If true, only validate the resource, don't apply it",
|
|
28
|
-
default: false
|
|
29
|
+
default: false,
|
|
29
30
|
},
|
|
30
31
|
force: {
|
|
31
32
|
type: "boolean",
|
|
32
33
|
description: "If true, immediately remove resources from API and bypass graceful deletion",
|
|
33
|
-
default: false
|
|
34
|
-
}
|
|
34
|
+
default: false,
|
|
35
|
+
},
|
|
35
36
|
},
|
|
36
37
|
required: [],
|
|
37
38
|
},
|
|
@@ -44,7 +45,8 @@ export async function kubectlApply(k8sManager, input) {
|
|
|
44
45
|
const namespace = input.namespace || "default";
|
|
45
46
|
const dryRun = input.dryRun || false;
|
|
46
47
|
const force = input.force || false;
|
|
47
|
-
let command = "kubectl
|
|
48
|
+
let command = "kubectl";
|
|
49
|
+
let args = ["apply"];
|
|
48
50
|
let tempFile = null;
|
|
49
51
|
// Process manifest content if provided
|
|
50
52
|
if (input.manifest) {
|
|
@@ -52,24 +54,28 @@ export async function kubectlApply(k8sManager, input) {
|
|
|
52
54
|
const tmpDir = os.tmpdir();
|
|
53
55
|
tempFile = path.join(tmpDir, `manifest-${Date.now()}.yaml`);
|
|
54
56
|
fs.writeFileSync(tempFile, input.manifest);
|
|
55
|
-
|
|
57
|
+
args.push("-f", tempFile);
|
|
56
58
|
}
|
|
57
59
|
else if (input.filename) {
|
|
58
|
-
|
|
60
|
+
args.push("-f", input.filename);
|
|
59
61
|
}
|
|
60
62
|
// Add namespace
|
|
61
|
-
|
|
63
|
+
args.push("-n", namespace);
|
|
62
64
|
// Add dry-run flag if requested
|
|
63
65
|
if (dryRun) {
|
|
64
|
-
|
|
66
|
+
args.push("--dry-run=client");
|
|
65
67
|
}
|
|
66
68
|
// Add force flag if requested
|
|
67
69
|
if (force) {
|
|
68
|
-
|
|
70
|
+
args.push("--force");
|
|
69
71
|
}
|
|
70
72
|
// Execute the command
|
|
71
73
|
try {
|
|
72
|
-
const result =
|
|
74
|
+
const result = execFileSync(command, args, {
|
|
75
|
+
encoding: "utf8",
|
|
76
|
+
maxBuffer: getSpawnMaxBuffer(),
|
|
77
|
+
env: { ...process.env, KUBECONFIG: process.env.KUBECONFIG },
|
|
78
|
+
});
|
|
73
79
|
// Clean up temp file if created
|
|
74
80
|
if (tempFile) {
|
|
75
81
|
try {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { execFileSync } from "child_process";
|
|
2
2
|
import { McpError, ErrorCode } from "@modelcontextprotocol/sdk/types.js";
|
|
3
|
+
import { getSpawnMaxBuffer } from "../config/max-buffer.js";
|
|
3
4
|
export const kubectlContextSchema = {
|
|
4
5
|
name: "kubectl_context",
|
|
5
6
|
description: "Manage Kubernetes contexts - list, get, or set the current context",
|
|
@@ -10,28 +11,28 @@ export const kubectlContextSchema = {
|
|
|
10
11
|
type: "string",
|
|
11
12
|
enum: ["list", "get", "set"],
|
|
12
13
|
description: "Operation to perform: list contexts, get current context, or set current context",
|
|
13
|
-
default: "list"
|
|
14
|
+
default: "list",
|
|
14
15
|
},
|
|
15
16
|
name: {
|
|
16
17
|
type: "string",
|
|
17
|
-
description: "Name of the context to set as current (required for set operation)"
|
|
18
|
+
description: "Name of the context to set as current (required for set operation)",
|
|
18
19
|
},
|
|
19
20
|
showCurrent: {
|
|
20
21
|
type: "boolean",
|
|
21
22
|
description: "When listing contexts, highlight which one is currently active",
|
|
22
|
-
default: true
|
|
23
|
+
default: true,
|
|
23
24
|
},
|
|
24
25
|
detailed: {
|
|
25
26
|
type: "boolean",
|
|
26
27
|
description: "Include detailed information about the context",
|
|
27
|
-
default: false
|
|
28
|
+
default: false,
|
|
28
29
|
},
|
|
29
30
|
output: {
|
|
30
31
|
type: "string",
|
|
31
32
|
enum: ["json", "yaml", "name", "custom"],
|
|
32
33
|
description: "Output format",
|
|
33
|
-
default: "json"
|
|
34
|
-
}
|
|
34
|
+
default: "json",
|
|
35
|
+
},
|
|
35
36
|
},
|
|
36
37
|
required: ["operation"],
|
|
37
38
|
},
|
|
@@ -41,18 +42,22 @@ export async function kubectlContext(k8sManager, input) {
|
|
|
41
42
|
const { operation, name, output = "json" } = input;
|
|
42
43
|
const showCurrent = input.showCurrent !== false; // Default to true if not specified
|
|
43
44
|
const detailed = input.detailed === true; // Default to false if not specified
|
|
44
|
-
|
|
45
|
+
const command = "kubectl";
|
|
45
46
|
let result = "";
|
|
46
47
|
switch (operation) {
|
|
47
48
|
case "list":
|
|
48
49
|
// Build command to list contexts
|
|
49
|
-
|
|
50
|
+
let listArgs = ["config", "get-contexts"];
|
|
50
51
|
if (output === "name") {
|
|
51
|
-
|
|
52
|
+
listArgs.push("-o", "name");
|
|
52
53
|
}
|
|
53
54
|
else if (output === "custom" || output === "json") {
|
|
54
55
|
// For custom or JSON output, we'll format it ourselves
|
|
55
|
-
const rawResult =
|
|
56
|
+
const rawResult = execFileSync(command, listArgs, {
|
|
57
|
+
encoding: "utf8",
|
|
58
|
+
maxBuffer: getSpawnMaxBuffer(),
|
|
59
|
+
env: { ...process.env, KUBECONFIG: process.env.KUBECONFIG },
|
|
60
|
+
});
|
|
56
61
|
// Parse the tabular output from kubectl
|
|
57
62
|
const lines = rawResult.trim().split("\n");
|
|
58
63
|
const headers = lines[0].trim().split(/\s+/);
|
|
@@ -70,7 +75,7 @@ export async function kubectlContext(k8sManager, input) {
|
|
|
70
75
|
cluster: columns[clusterIndex]?.trim(),
|
|
71
76
|
user: columns[authInfoIndex]?.trim(),
|
|
72
77
|
namespace: columns[namespaceIndex]?.trim() || "default",
|
|
73
|
-
isCurrent: isCurrent
|
|
78
|
+
isCurrent: isCurrent,
|
|
74
79
|
});
|
|
75
80
|
}
|
|
76
81
|
return {
|
|
@@ -83,17 +88,29 @@ export async function kubectlContext(k8sManager, input) {
|
|
|
83
88
|
};
|
|
84
89
|
}
|
|
85
90
|
// Execute the command for non-json outputs
|
|
86
|
-
result =
|
|
91
|
+
result = execFileSync(command, listArgs, {
|
|
92
|
+
encoding: "utf8",
|
|
93
|
+
maxBuffer: getSpawnMaxBuffer(),
|
|
94
|
+
env: { ...process.env, KUBECONFIG: process.env.KUBECONFIG },
|
|
95
|
+
});
|
|
87
96
|
break;
|
|
88
97
|
case "get":
|
|
89
98
|
// Build command to get current context
|
|
90
|
-
|
|
99
|
+
const getArgs = ["config", "current-context"];
|
|
91
100
|
// Execute the command
|
|
92
101
|
try {
|
|
93
|
-
const currentContext =
|
|
102
|
+
const currentContext = execFileSync(command, getArgs, {
|
|
103
|
+
encoding: "utf8",
|
|
104
|
+
maxBuffer: getSpawnMaxBuffer(),
|
|
105
|
+
env: { ...process.env, KUBECONFIG: process.env.KUBECONFIG },
|
|
106
|
+
}).trim();
|
|
94
107
|
if (detailed) {
|
|
95
108
|
// For detailed context info, we need to use get-contexts and filter
|
|
96
|
-
const allContextsOutput =
|
|
109
|
+
const allContextsOutput = execFileSync(command, ["config", "get-contexts"], {
|
|
110
|
+
encoding: "utf8",
|
|
111
|
+
maxBuffer: getSpawnMaxBuffer(),
|
|
112
|
+
env: { ...process.env, KUBECONFIG: process.env.KUBECONFIG },
|
|
113
|
+
});
|
|
97
114
|
// Parse the tabular output from kubectl
|
|
98
115
|
const lines = allContextsOutput.trim().split("\n");
|
|
99
116
|
const headers = lines[0].trim().split(/\s+/);
|
|
@@ -105,7 +122,7 @@ export async function kubectlContext(k8sManager, input) {
|
|
|
105
122
|
name: currentContext,
|
|
106
123
|
cluster: "",
|
|
107
124
|
user: "",
|
|
108
|
-
namespace: "default"
|
|
125
|
+
namespace: "default",
|
|
109
126
|
};
|
|
110
127
|
// Find the current context in the output
|
|
111
128
|
for (let i = 1; i < lines.length; i++) {
|
|
@@ -117,7 +134,7 @@ export async function kubectlContext(k8sManager, input) {
|
|
|
117
134
|
name: currentContext,
|
|
118
135
|
cluster: columns[clusterIndex]?.trim() || "",
|
|
119
136
|
user: columns[authInfoIndex]?.trim() || "",
|
|
120
|
-
namespace: columns[namespaceIndex]?.trim() || "default"
|
|
137
|
+
namespace: columns[namespaceIndex]?.trim() || "default",
|
|
121
138
|
};
|
|
122
139
|
break;
|
|
123
140
|
}
|
|
@@ -155,7 +172,10 @@ export async function kubectlContext(k8sManager, input) {
|
|
|
155
172
|
content: [
|
|
156
173
|
{
|
|
157
174
|
type: "text",
|
|
158
|
-
text: JSON.stringify({
|
|
175
|
+
text: JSON.stringify({
|
|
176
|
+
currentContext: null,
|
|
177
|
+
error: "No current context is set",
|
|
178
|
+
}, null, 2),
|
|
159
179
|
},
|
|
160
180
|
],
|
|
161
181
|
};
|
|
@@ -169,7 +189,11 @@ export async function kubectlContext(k8sManager, input) {
|
|
|
169
189
|
}
|
|
170
190
|
// First check if the context exists
|
|
171
191
|
try {
|
|
172
|
-
const allContextsOutput =
|
|
192
|
+
const allContextsOutput = execFileSync(command, ["config", "get-contexts", "-o", "name"], {
|
|
193
|
+
encoding: "utf8",
|
|
194
|
+
maxBuffer: getSpawnMaxBuffer(),
|
|
195
|
+
env: { ...process.env, KUBECONFIG: process.env.KUBECONFIG },
|
|
196
|
+
});
|
|
173
197
|
const availableContexts = allContextsOutput.trim().split("\n");
|
|
174
198
|
// Extract the short name from the ARN if needed
|
|
175
199
|
let contextName = name;
|
|
@@ -180,13 +204,18 @@ export async function kubectlContext(k8sManager, input) {
|
|
|
180
204
|
}
|
|
181
205
|
}
|
|
182
206
|
// Check if the context exists
|
|
183
|
-
if (!availableContexts.includes(contextName) &&
|
|
207
|
+
if (!availableContexts.includes(contextName) &&
|
|
208
|
+
!availableContexts.includes(name)) {
|
|
184
209
|
throw new McpError(ErrorCode.InvalidParams, `Context '${name}' not found`);
|
|
185
210
|
}
|
|
186
211
|
// Build command to set context
|
|
187
|
-
|
|
212
|
+
const setArgs = ["config", "use-context", contextName];
|
|
188
213
|
// Execute the command
|
|
189
|
-
result =
|
|
214
|
+
result = execFileSync(command, setArgs, {
|
|
215
|
+
encoding: "utf8",
|
|
216
|
+
maxBuffer: getSpawnMaxBuffer(),
|
|
217
|
+
env: { ...process.env, KUBECONFIG: process.env.KUBECONFIG },
|
|
218
|
+
});
|
|
190
219
|
// For tests to pass, we need to return the original name format that was passed in
|
|
191
220
|
return {
|
|
192
221
|
content: [
|
|
@@ -195,7 +224,7 @@ export async function kubectlContext(k8sManager, input) {
|
|
|
195
224
|
text: JSON.stringify({
|
|
196
225
|
success: true,
|
|
197
226
|
message: `Current context set to '${name}'`,
|
|
198
|
-
context: name
|
|
227
|
+
context: name,
|
|
199
228
|
}, null, 2),
|
|
200
229
|
},
|
|
201
230
|
],
|