mcp-server-kubernetes 3.3.0 → 3.4.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/index.d.ts +11 -0
- package/dist/index.js +6 -0
- package/dist/tools/kubectl-reconnect.d.ts +19 -0
- package/dist/tools/kubectl-reconnect.js +32 -0
- package/dist/utils/auth.js +25 -1
- package/dist/utils/kubernetes-manager.d.ts +1 -0
- package/dist/utils/kubernetes-manager.js +5 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -393,6 +393,17 @@ declare const allTools: ({
|
|
|
393
393
|
};
|
|
394
394
|
readonly required: readonly ["operation"];
|
|
395
395
|
};
|
|
396
|
+
} | {
|
|
397
|
+
readonly name: "kubectl_reconnect";
|
|
398
|
+
readonly description: "Reconnect to the Kubernetes API server by recreating all API clients. Use this after cluster upgrades (e.g., EKS control plane upgrades that rotate ENIs/IPs) to force fresh DNS resolution and new TCP connections.";
|
|
399
|
+
readonly annotations: {
|
|
400
|
+
readonly readOnlyHint: false;
|
|
401
|
+
};
|
|
402
|
+
readonly inputSchema: {
|
|
403
|
+
readonly type: "object";
|
|
404
|
+
readonly properties: {};
|
|
405
|
+
readonly required: readonly [];
|
|
406
|
+
};
|
|
396
407
|
} | {
|
|
397
408
|
readonly name: "kubectl_get";
|
|
398
409
|
readonly description: "Get or list Kubernetes resources by resource type, name, and optionally namespace";
|
package/dist/index.js
CHANGED
|
@@ -18,6 +18,7 @@ import { startSSEServer } from "./utils/sse.js";
|
|
|
18
18
|
import { startPortForward, PortForwardSchema, stopPortForward, StopPortForwardSchema, } from "./tools/port_forward.js";
|
|
19
19
|
import { kubectlScale, kubectlScaleSchema } from "./tools/kubectl-scale.js";
|
|
20
20
|
import { kubectlContext, kubectlContextSchema, } from "./tools/kubectl-context.js";
|
|
21
|
+
import { kubectlReconnect, kubectlReconnectSchema, } from "./tools/kubectl-reconnect.js";
|
|
21
22
|
import { kubectlGet, kubectlGetSchema } from "./tools/kubectl-get.js";
|
|
22
23
|
import { kubectlDescribe, kubectlDescribeSchema, } from "./tools/kubectl-describe.js";
|
|
23
24
|
import { kubectlApply, kubectlApplySchema } from "./tools/kubectl-apply.js";
|
|
@@ -41,6 +42,7 @@ const readonlyTools = [
|
|
|
41
42
|
kubectlDescribeSchema,
|
|
42
43
|
kubectlLogsSchema,
|
|
43
44
|
kubectlContextSchema,
|
|
45
|
+
kubectlReconnectSchema,
|
|
44
46
|
explainResourceSchema,
|
|
45
47
|
listApiResourcesSchema,
|
|
46
48
|
pingSchema,
|
|
@@ -69,6 +71,7 @@ const allTools = [
|
|
|
69
71
|
kubectlRolloutSchema,
|
|
70
72
|
// Kubernetes context management
|
|
71
73
|
kubectlContextSchema,
|
|
74
|
+
kubectlReconnectSchema,
|
|
72
75
|
// Special operations that aren't covered by simple kubectl commands
|
|
73
76
|
explainResourceSchema,
|
|
74
77
|
// Helm operations
|
|
@@ -129,6 +132,9 @@ server.setRequestHandler(CallToolRequestSchema, withTelemetry(async (request) =>
|
|
|
129
132
|
if (name === "kubectl_context") {
|
|
130
133
|
return await kubectlContext(k8sManager, input);
|
|
131
134
|
}
|
|
135
|
+
if (name === "kubectl_reconnect") {
|
|
136
|
+
return await kubectlReconnect(k8sManager);
|
|
137
|
+
}
|
|
132
138
|
if (name === "kubectl_get") {
|
|
133
139
|
return await kubectlGet(k8sManager, input);
|
|
134
140
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { KubernetesManager } from "../types.js";
|
|
2
|
+
export declare const kubectlReconnectSchema: {
|
|
3
|
+
readonly name: "kubectl_reconnect";
|
|
4
|
+
readonly description: "Reconnect to the Kubernetes API server by recreating all API clients. Use this after cluster upgrades (e.g., EKS control plane upgrades that rotate ENIs/IPs) to force fresh DNS resolution and new TCP connections.";
|
|
5
|
+
readonly annotations: {
|
|
6
|
+
readonly readOnlyHint: false;
|
|
7
|
+
};
|
|
8
|
+
readonly inputSchema: {
|
|
9
|
+
readonly type: "object";
|
|
10
|
+
readonly properties: {};
|
|
11
|
+
readonly required: readonly [];
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
export declare function kubectlReconnect(k8sManager: KubernetesManager): Promise<{
|
|
15
|
+
content: {
|
|
16
|
+
type: string;
|
|
17
|
+
text: string;
|
|
18
|
+
}[];
|
|
19
|
+
}>;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { McpError, ErrorCode } from "@modelcontextprotocol/sdk/types.js";
|
|
2
|
+
export const kubectlReconnectSchema = {
|
|
3
|
+
name: "kubectl_reconnect",
|
|
4
|
+
description: "Reconnect to the Kubernetes API server by recreating all API clients. Use this after cluster upgrades (e.g., EKS control plane upgrades that rotate ENIs/IPs) to force fresh DNS resolution and new TCP connections.",
|
|
5
|
+
annotations: {
|
|
6
|
+
readOnlyHint: false,
|
|
7
|
+
},
|
|
8
|
+
inputSchema: {
|
|
9
|
+
type: "object",
|
|
10
|
+
properties: {},
|
|
11
|
+
required: [],
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
export async function kubectlReconnect(k8sManager) {
|
|
15
|
+
try {
|
|
16
|
+
k8sManager.refreshApiClients();
|
|
17
|
+
return {
|
|
18
|
+
content: [
|
|
19
|
+
{
|
|
20
|
+
type: "text",
|
|
21
|
+
text: JSON.stringify({
|
|
22
|
+
success: true,
|
|
23
|
+
message: "API clients refreshed. DNS will be re-resolved on the next request.",
|
|
24
|
+
}, null, 2),
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
throw new McpError(ErrorCode.InternalError, `Failed to reconnect: ${error.message}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
package/dist/utils/auth.js
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
import { timingSafeEqual } from "crypto";
|
|
2
|
+
/** Constant-time string comparison that prevents timing attacks (CWE-208). */
|
|
3
|
+
function timingSafeCompare(a, b) {
|
|
4
|
+
const bufA = Buffer.from(a);
|
|
5
|
+
const bufB = Buffer.from(b);
|
|
6
|
+
if (bufA.length !== bufB.length) {
|
|
7
|
+
// Compare against itself to keep constant time, then return false
|
|
8
|
+
timingSafeEqual(bufA, bufA);
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
return timingSafeEqual(bufA, bufB);
|
|
12
|
+
}
|
|
1
13
|
/**
|
|
2
14
|
* Authentication middleware for MCP HTTP transports.
|
|
3
15
|
*
|
|
@@ -31,7 +43,19 @@ export function createAuthMiddleware() {
|
|
|
31
43
|
});
|
|
32
44
|
return;
|
|
33
45
|
}
|
|
34
|
-
|
|
46
|
+
// Reject array-valued headers (e.g. duplicate X-MCP-AUTH)
|
|
47
|
+
if (Array.isArray(providedToken)) {
|
|
48
|
+
res.status(401).json({
|
|
49
|
+
jsonrpc: "2.0",
|
|
50
|
+
error: {
|
|
51
|
+
code: -32001,
|
|
52
|
+
message: "Unauthorized: Only single X-MCP-AUTH header is allowed",
|
|
53
|
+
},
|
|
54
|
+
id: null,
|
|
55
|
+
});
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (!timingSafeCompare(providedToken, authToken)) {
|
|
35
59
|
res.status(403).json({
|
|
36
60
|
jsonrpc: "2.0",
|
|
37
61
|
error: {
|
|
@@ -186,6 +186,11 @@ export class KubernetesManager {
|
|
|
186
186
|
*
|
|
187
187
|
* @param contextName
|
|
188
188
|
*/
|
|
189
|
+
refreshApiClients() {
|
|
190
|
+
this.k8sApi = this.kc.makeApiClient(k8s.CoreV1Api);
|
|
191
|
+
this.k8sAppsApi = this.kc.makeApiClient(k8s.AppsV1Api);
|
|
192
|
+
this.k8sBatchApi = this.kc.makeApiClient(k8s.BatchV1Api);
|
|
193
|
+
}
|
|
189
194
|
setCurrentContext(contextName) {
|
|
190
195
|
// Get all available contexts
|
|
191
196
|
const contexts = this.kc.getContexts();
|