Skip to main content
Glama

mcp-server-kubernetes

by Flux159
// Import necessary modules and dependencies import { expect, test, describe, beforeEach, afterEach } from "vitest"; import { Client } from "@modelcontextprotocol/sdk/client/index.js"; import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js"; import { z } from "zod"; // Define the response type for easier use in tests type KubectlResponse = { content: Array<{ type: "text"; text: string; }>; }; // Utility function to introduce a delay async function sleep(ms: number): Promise<void> { return new Promise((resolve) => setTimeout(resolve, ms)); } // Utility function to generate a random ID function generateRandomId(): string { return Math.random().toString(36).substring(2, 10); } // Utility function to generate a random SHA-like string function generateRandomSHA(): string { return Math.random().toString(36).substring(2, 15); } // Test suite for Kubernetes ConfigMap operations using kubectl commands describe("test kubernetes configmap with kubectl commands", () => { let transport: StdioClientTransport; let client: Client; const NAMESPACE_PREFIX = "test-configmap"; // Prefix for test namespaces let testNamespace: string; const testName = `test-configmap-${generateRandomSHA()}`; // Unique name for the ConfigMap // Setup before each test beforeEach(async () => { try { transport = new StdioClientTransport({ command: "bun", args: ["src/index.ts"], stderr: "pipe", }); client = new Client( { name: "test-client", version: "1.0.0", }, { capabilities: {}, } ); await client.connect(transport); await sleep(5000); // Wait longer for the client to connect testNamespace = `${NAMESPACE_PREFIX}-${generateRandomId()}`; console.log(`Creating test namespace: ${testNamespace}`); console.log("About to create namespace:", testNamespace); try { // Create a test namespace using kubectl_create const namespaceResponse = await client.request({ method: "tools/call", params: { name: "kubectl_create", arguments: { resourceType: "namespace", name: testNamespace }, }, }, // @ts-ignore - Ignoring type error for now z.any()) as KubectlResponse; console.log("Namespace creation response:", JSON.stringify(namespaceResponse)); } catch (error) { console.error("Error creating namespace:", error); throw error; } await sleep(5000); // Wait longer for the namespace to be created } catch (error: any) { console.error("Error in beforeEach:", error); throw error; } }); // Cleanup after each test afterEach(async () => { try { console.log(`Cleaning up test namespace: ${testNamespace}`); // Delete the test namespace using kubectl_delete await client.request({ method: "tools/call", params: { name: "kubectl_delete", arguments: { resourceType: "namespace", name: testNamespace }, }, }, // @ts-ignore - Ignoring type error for now z.any()); await transport.close(); // Close the transport await sleep(5000); // Wait longer for cleanup to complete } catch (e) { console.error("Error during cleanup:", e); } }); // Test case: Verify creation of a ConfigMap test("verify creation of configmap", async () => { const testData = { key1: "hello", key2: "world", }; // Create ConfigMap using kubectl_create with resourceType and fromLiteral const fromLiteralArgs = Object.entries(testData).map(([key, value]) => `${key}=${value}`); const createResponse = await client.request({ method: "tools/call", params: { name: "kubectl_create", arguments: { resourceType: "configmap", name: testName, namespace: testNamespace, fromLiteral: fromLiteralArgs }, }, }, // @ts-ignore - Ignoring type error for now z.any()) as KubectlResponse; console.log("ConfigMap creation response:", JSON.stringify(createResponse)); expect(createResponse.content[0].type).toBe("text"); expect(createResponse.content[0].text).toContain(`kind: ConfigMap`); expect(createResponse.content[0].text).toContain(`name: ${testName}`); // Wait longer for the ConfigMap to be fully created await sleep(5000); }, 60000); // 60 second timeout // Test case: Verify retrieval of a ConfigMap test("verify get of configmap", async () => { const testData = { key1: "foo", key2: "bar", }; // Create ConfigMap using kubectl_create with resourceType and fromLiteral const fromLiteralArgs = Object.entries(testData).map(([key, value]) => `${key}=${value}`); await client.request({ method: "tools/call", params: { name: "kubectl_create", arguments: { resourceType: "configmap", name: testName, namespace: testNamespace, fromLiteral: fromLiteralArgs }, }, }, // @ts-ignore - Ignoring type error for now z.any()) as KubectlResponse; await sleep(5000); // Wait longer for the ConfigMap to be created // Retrieve the ConfigMap using kubectl_get const getResponse = await client.request({ method: "tools/call", params: { name: "kubectl_get", arguments: { resourceType: "configmap", name: testName, namespace: testNamespace, output: "json" }, }, }, // @ts-ignore - Ignoring type error for now z.any()) as KubectlResponse; console.log("Get configmap response:", JSON.stringify(getResponse)); // Validate the content expect(getResponse.content[0].type).toBe("text"); // Parse the JSON response const configMapData = JSON.parse(getResponse.content[0].text); expect(configMapData.metadata.name).toBe(testName); expect(configMapData.metadata.namespace).toBe(testNamespace); expect(configMapData.data).toEqual(testData); }, 60000); // 60 second timeout // Test case: Verify update of a ConfigMap test("verify update of configmap", async () => { const initialData = { key1: "init", key2: "val", }; // Create ConfigMap using kubectl_create with resourceType and fromLiteral const fromLiteralArgs = Object.entries(initialData).map(([key, value]) => `${key}=${value}`); await client.request({ method: "tools/call", params: { name: "kubectl_create", arguments: { resourceType: "configmap", name: testName, namespace: testNamespace, fromLiteral: fromLiteralArgs }, }, }, // @ts-ignore - Ignoring type error for now z.any()) as KubectlResponse; await sleep(5000); // Wait longer for the ConfigMap to be created // Now update the ConfigMap with new data const updatedData = { key1: "updated", key2: "val", key3: "new", }; // Convert the updated data to YAML string for the manifest const updatedDataYaml = Object.entries(updatedData) .map(([key, value]) => ` ${key}: ${value}`) .join('\n'); // Update ConfigMap using kubectl_apply again const updateManifest = ` apiVersion: v1 kind: ConfigMap metadata: name: ${testName} namespace: ${testNamespace} data: ${updatedDataYaml} `; const updateResponse = await client.request({ method: "tools/call", params: { name: "kubectl_apply", arguments: { manifest: updateManifest, namespace: testNamespace }, }, }, // @ts-ignore - Ignoring type error for now z.any()) as KubectlResponse; console.log("ConfigMap update response:", JSON.stringify(updateResponse)); expect(updateResponse.content[0].type).toBe("text"); expect(updateResponse.content[0].text).toContain(`configmap/${testName} configured`); // Wait longer for update to be applied await sleep(5000); // Verify the update using kubectl_get const getResponse = await client.request({ method: "tools/call", params: { name: "kubectl_get", arguments: { resourceType: "configmap", name: testName, namespace: testNamespace, output: "json" }, }, }, // @ts-ignore - Ignoring type error for now z.any()) as KubectlResponse; // Parse the JSON response const configMapData = JSON.parse(getResponse.content[0].text); expect(configMapData.data).toEqual(updatedData); expect(configMapData.data.key3).toBe("new"); }, 120000); // 120 second timeout for update test // Test case: Verify deletion of a ConfigMap test("verify delete of configmap", async () => { const testData = { key1: "to-be-deleted", }; // Create ConfigMap using kubectl_create with resourceType and fromLiteral const fromLiteralArgs = Object.entries(testData).map(([key, value]) => `${key}=${value}`); await client.request({ method: "tools/call", params: { name: "kubectl_create", arguments: { resourceType: "configmap", name: testName, namespace: testNamespace, fromLiteral: fromLiteralArgs }, }, }, // @ts-ignore - Ignoring type error for now z.any()) as KubectlResponse; await sleep(5000); // Wait longer for the ConfigMap to be created // Delete the ConfigMap using kubectl_delete const deleteResponse = await client.request({ method: "tools/call", params: { name: "kubectl_delete", arguments: { resourceType: "configmap", name: testName, namespace: testNamespace }, }, }, // @ts-ignore - Ignoring type error for now z.any()) as KubectlResponse; expect(deleteResponse.content[0].type).toBe("text"); expect(deleteResponse.content[0].text).toContain(`configmap "${testName}" deleted`); // Verify the ConfigMap is deleted by trying to get it await sleep(5000); // Wait longer for deletion to complete const getResponse = await client.request({ method: "tools/call", params: { name: "kubectl_get", arguments: { resourceType: "configmap", name: testName, namespace: testNamespace, output: "json" }, }, }, // @ts-ignore - Ignoring type error for now z.any()) as KubectlResponse; // Should indicate the resource is not found expect(getResponse.content[0].type).toBe("text"); expect(getResponse.content[0].text).toContain("not found"); }, 60000); // 60 second timeout });

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Flux159/mcp-server-kubernetes'

If you have feedback or need assistance with the MCP directory API, please join our Discord server