mcp-server-kubernetes 4.1.0 → 4.1.2
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
CHANGED
|
@@ -810,4 +810,10 @@ declare const allTools: ({
|
|
|
810
810
|
readOnlyHint: boolean;
|
|
811
811
|
};
|
|
812
812
|
})[];
|
|
813
|
+
/**
|
|
814
|
+
* Returns the names in `allowedToolNames` that no tool actually provides.
|
|
815
|
+
*
|
|
816
|
+
* Exported for testing.
|
|
817
|
+
*/
|
|
818
|
+
export declare function findUnknownToolNames(allowedToolNames: Iterable<string>, knownToolNames: Iterable<string>): string[];
|
|
813
819
|
export { allTools, destructiveTools };
|
package/dist/index.js
CHANGED
|
@@ -105,6 +105,28 @@ const allTools = [
|
|
|
105
105
|
// Ping utility
|
|
106
106
|
pingSchema,
|
|
107
107
|
];
|
|
108
|
+
/**
|
|
109
|
+
* Returns the names in `allowedToolNames` that no tool actually provides.
|
|
110
|
+
*
|
|
111
|
+
* Exported for testing.
|
|
112
|
+
*/
|
|
113
|
+
export function findUnknownToolNames(allowedToolNames, knownToolNames) {
|
|
114
|
+
const known = new Set(knownToolNames);
|
|
115
|
+
return [...allowedToolNames].filter((name) => !known.has(name)).sort();
|
|
116
|
+
}
|
|
117
|
+
// A misspelled name in ALLOWED_TOOLS would otherwise be dropped silently,
|
|
118
|
+
// leaving a narrower tool surface than was configured. Refuse to start instead.
|
|
119
|
+
if (explicitlyAllowedToolNames) {
|
|
120
|
+
const unknownToolNames = findUnknownToolNames(explicitlyAllowedToolNames, allTools.map((tool) => tool.name));
|
|
121
|
+
if (unknownToolNames.length > 0) {
|
|
122
|
+
console.error(`ALLOWED_TOOLS contains unknown tool ${unknownToolNames.length === 1 ? "name" : "names"}: ${unknownToolNames.join(", ")}`);
|
|
123
|
+
console.error(`Available tools: ${allTools
|
|
124
|
+
.map((tool) => tool.name)
|
|
125
|
+
.sort()
|
|
126
|
+
.join(", ")}`);
|
|
127
|
+
process.exit(1);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
108
130
|
const k8sManager = new KubernetesManager();
|
|
109
131
|
const server = new Server({
|
|
110
132
|
name: serverConfig.name,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { execFileSyncSafe } from "../security/kubectl-flags.js";
|
|
2
|
+
import { isRemoteTransport } from "../security/transport.js";
|
|
2
3
|
import { McpError, ErrorCode } from "@modelcontextprotocol/sdk/types.js";
|
|
3
4
|
import * as fs from "fs";
|
|
4
5
|
import * as path from "path";
|
|
@@ -35,7 +36,7 @@ export const kubectlPatchSchema = {
|
|
|
35
36
|
},
|
|
36
37
|
patchFile: {
|
|
37
38
|
type: "string",
|
|
38
|
-
description: "Path to a file containing the patch data (alternative to patchData)",
|
|
39
|
+
description: "Path to a file containing the patch data (alternative to patchData). The path is read on the machine running the MCP server, so it is rejected when the server runs over a remote (SSE/Streamable HTTP) transport; use 'patchData' to pass the patch contents instead.",
|
|
39
40
|
},
|
|
40
41
|
dryRun: dryRunParameter,
|
|
41
42
|
context: contextParameter,
|
|
@@ -48,6 +49,17 @@ export async function kubectlPatch(k8sManager, input) {
|
|
|
48
49
|
if (!input.patchData && !input.patchFile) {
|
|
49
50
|
throw new McpError(ErrorCode.InvalidRequest, "Either patchData or patchFile must be provided");
|
|
50
51
|
}
|
|
52
|
+
// Reject server-side filesystem reads on remote transports. Over SSE /
|
|
53
|
+
// Streamable HTTP the path resolves on the MCP server host, not the
|
|
54
|
+
// client, so `patchFile` (--patch-file) would let any client that can
|
|
55
|
+
// reach the endpoint read arbitrary server files (kubeconfig,
|
|
56
|
+
// service-account token, /proc/self/environ, etc.) via kubectl's parse
|
|
57
|
+
// errors, or merge their contents into a resource that is then readable
|
|
58
|
+
// through kubectl_get. Clients on these transports must pass the patch
|
|
59
|
+
// inline via `patchData` instead.
|
|
60
|
+
if (isRemoteTransport() && input.patchFile) {
|
|
61
|
+
throw new McpError(ErrorCode.InvalidRequest, "The 'patchFile' parameter reads a file from the MCP server's filesystem and is disabled on remote (SSE/Streamable HTTP) transports. Pass the patch contents via 'patchData' instead.");
|
|
62
|
+
}
|
|
51
63
|
const namespace = input.namespace || "default";
|
|
52
64
|
const patchType = input.patchType || "strategic";
|
|
53
65
|
const dryRun = input.dryRun || false;
|