mcp-server-kubernetes 3.2.0 → 3.2.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.
- package/dist/tools/kubectl-get.js +86 -5
- package/package.json +2 -2
|
@@ -168,7 +168,7 @@ export async function kubectlGet(k8sManager, input) {
|
|
|
168
168
|
name: item.metadata?.name || "",
|
|
169
169
|
namespace: item.metadata?.namespace || "",
|
|
170
170
|
kind: item.kind || resourceType,
|
|
171
|
-
status: getResourceStatus(item),
|
|
171
|
+
status: getResourceStatus(item, resourceType),
|
|
172
172
|
createdAt: item.metadata?.creationTimestamp,
|
|
173
173
|
}));
|
|
174
174
|
return {
|
|
@@ -218,13 +218,94 @@ export async function kubectlGet(k8sManager, input) {
|
|
|
218
218
|
throw new McpError(ErrorCode.InternalError, `Failed to execute kubectl get command: ${error.message}`);
|
|
219
219
|
}
|
|
220
220
|
}
|
|
221
|
+
// Compute pod status the same way kubectl does, by inspecting container statuses
|
|
222
|
+
// Based on kubernetes/pkg/printers/internalversion/printers.go printPod()
|
|
223
|
+
function getPodStatus(pod) {
|
|
224
|
+
let reason = pod.status?.phase || "Unknown";
|
|
225
|
+
if (pod.status?.reason) {
|
|
226
|
+
reason = pod.status.reason;
|
|
227
|
+
}
|
|
228
|
+
// Check init container statuses
|
|
229
|
+
const initContainerStatuses = pod.status?.initContainerStatuses || [];
|
|
230
|
+
for (let i = 0; i < initContainerStatuses.length; i++) {
|
|
231
|
+
const container = initContainerStatuses[i];
|
|
232
|
+
const terminated = container.state?.terminated;
|
|
233
|
+
const waiting = container.state?.waiting;
|
|
234
|
+
if (terminated && terminated.exitCode === 0) {
|
|
235
|
+
// Init container completed successfully, continue
|
|
236
|
+
continue;
|
|
237
|
+
}
|
|
238
|
+
if (terminated) {
|
|
239
|
+
if (terminated.reason) {
|
|
240
|
+
reason = `Init:${terminated.reason}`;
|
|
241
|
+
}
|
|
242
|
+
else if (terminated.signal) {
|
|
243
|
+
reason = `Init:Signal:${terminated.signal}`;
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
reason = `Init:ExitCode:${terminated.exitCode}`;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
else if (waiting && waiting.reason && waiting.reason !== "PodInitializing") {
|
|
250
|
+
reason = `Init:${waiting.reason}`;
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
const totalInit = initContainerStatuses.length;
|
|
254
|
+
reason = `Init:${i}/${totalInit}`;
|
|
255
|
+
}
|
|
256
|
+
break;
|
|
257
|
+
}
|
|
258
|
+
// If all init containers are done, check regular container statuses
|
|
259
|
+
if (initContainerStatuses.length === 0 ||
|
|
260
|
+
!reason.startsWith("Init:")) {
|
|
261
|
+
const containerStatuses = pod.status?.containerStatuses || [];
|
|
262
|
+
let hasRunning = false;
|
|
263
|
+
for (let i = containerStatuses.length - 1; i >= 0; i--) {
|
|
264
|
+
const container = containerStatuses[i];
|
|
265
|
+
const waiting = container.state?.waiting;
|
|
266
|
+
const terminated = container.state?.terminated;
|
|
267
|
+
if (waiting && waiting.reason) {
|
|
268
|
+
reason = waiting.reason;
|
|
269
|
+
}
|
|
270
|
+
else if (terminated) {
|
|
271
|
+
if (terminated.reason) {
|
|
272
|
+
reason = terminated.reason;
|
|
273
|
+
}
|
|
274
|
+
else if (terminated.signal) {
|
|
275
|
+
reason = `Signal:${terminated.signal}`;
|
|
276
|
+
}
|
|
277
|
+
else {
|
|
278
|
+
reason = `ExitCode:${terminated.exitCode}`;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
else if (container.ready && container.state?.running) {
|
|
282
|
+
hasRunning = true;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
// If all containers are ready and running, use the phase
|
|
286
|
+
if (hasRunning && reason === (pod.status?.phase || "Unknown")) {
|
|
287
|
+
reason = pod.status?.phase || "Running";
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
// Handle pod deletion
|
|
291
|
+
if (pod.metadata?.deletionTimestamp) {
|
|
292
|
+
reason = "Terminating";
|
|
293
|
+
}
|
|
294
|
+
return reason;
|
|
295
|
+
}
|
|
221
296
|
// Extract status from various resource types
|
|
222
|
-
function getResourceStatus(resource) {
|
|
297
|
+
function getResourceStatus(resource, resourceType) {
|
|
223
298
|
if (!resource)
|
|
224
299
|
return "Unknown";
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
300
|
+
const isPod = resource.kind === "Pod" ||
|
|
301
|
+
resourceType === "pods" ||
|
|
302
|
+
resourceType === "pod" ||
|
|
303
|
+
resourceType === "po" ||
|
|
304
|
+
(resource.status?.phase !== undefined &&
|
|
305
|
+
resource.status?.containerStatuses !== undefined);
|
|
306
|
+
// Pod status - use kubectl-equivalent logic
|
|
307
|
+
if (isPod) {
|
|
308
|
+
return getPodStatus(resource);
|
|
228
309
|
}
|
|
229
310
|
// Deployment, ReplicaSet, StatefulSet status
|
|
230
311
|
if (resource.status?.readyReplicas !== undefined) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-server-kubernetes",
|
|
3
|
-
"version": "3.2.
|
|
3
|
+
"version": "3.2.1",
|
|
4
4
|
"description": "MCP server for interacting with Kubernetes clusters via kubectl",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@kubernetes/client-node": "1.3.0",
|
|
41
|
-
"@modelcontextprotocol/sdk": "1.
|
|
41
|
+
"@modelcontextprotocol/sdk": "1.26.0",
|
|
42
42
|
"express": "4.21.2",
|
|
43
43
|
"js-yaml": "4.1.1",
|
|
44
44
|
"yaml": "2.7.0",
|