How Zod Schemas Are Validated for Tool Inputs and Request Payloads in MCP Kubernetes
The MCP Kubernetes server performs declarative validation of all tool inputs and request payloads using Zod at the protocol layer, ensuring only type-safe data reaches tool implementations.
The flux159/mcp-server-kubernetes repository implements the Model Context Protocol (MCP) to expose Kubernetes operations via structured tools. By leveraging Zod schemas to validate every incoming JSON-RPC request, the server enforces strict type contracts before any kubectl or Helm command executes. This approach centralizes validation logic within the MCP SDK integration, eliminating defensive coding inside individual tool handlers.
Schema Definitions for Tool Metadata and Inputs
The repository defines validation rules at two levels: a generic metadata wrapper that describes the tool itself, and concrete input schemas that specify the shape of acceptable arguments. Both follow Zod's JSON Schema conventions to maintain compatibility with the MCP SDK.
Generic Tool Schema Structure
In src/models/tool-models.ts, the server declares a reusable ToolSchema that captures the metadata required by the MCP specification. This schema validates the tool's name, description, and the shape of its input schema.
// src/models/tool-models.ts
import { z } from "zod";
export const ToolSchema = z.object({
name: z.string(),
description: z.string(),
inputSchema: z.record(z.any()),
});
export const ListToolsResponseSchema = z.object({
tools: z.array(ToolSchema),
});
export type K8sTool = z.infer<typeof ToolSchema>;
Concrete Tool Input Schemas
Individual tools export their own schema constants that enumerate required and optional fields. For example, src/tools/kubectl-get.ts defines kubectlGetSchema with detailed properties including references to shared parameter definitions like namespaceParameter from src/models/common-parameters.ts.
// src/tools/kubectl-get.ts
export const kubectlGetSchema = {
name: "kubectl_get",
description:
"Get or list Kubernetes resources by resource type, name, and optionally namespace",
annotations: { readOnlyHint: true },
inputSchema: {
type: "object",
properties: {
resourceType: { type: "string", description: "Type of resource to get" },
name: { type: "string", description: "Resource name (optional)" },
namespace: { $ref: "#/components/schemas/namespaceParameter" },
output: {
type: "string",
enum: ["json", "yaml", "wide", "name", "custom"],
default: "json",
},
},
required: ["resourceType"],
},
} as const;
Protocol-Layer Validation via MCP SDK
Validation is not performed by the tools themselves, but rather by the MCP SDK when requests arrive. In src/index.ts, the server registers handlers for specific request types—such as CallToolRequestSchema and ListToolsRequestSchema—which the SDK automatically validates against their attached Zod definitions.
Request Handler Registration
The server uses setRequestHandler to bind incoming requests to business logic. When a client invokes a tool, the SDK first validates the payload against CallToolRequestSchema. Only after passing this check does the execution reach the handler function.
// src/index.ts
server.setRequestHandler(
CallToolRequestSchema,
withTelemetry(async (request) => {
const { name, arguments: input = {} } = request.params;
// At this point `input` conforms to the tool's `inputSchema`
if (name === "kubectl_get") {
return await kubectlGet(k8sManager, input as KubectlGetArgs);
}
// ... other tool dispatch logic
})
);
Structured Error Responses
If validation fails at the protocol layer, the MCP SDK throws an McpError with ErrorCode.InvalidRequest before the tool handler executes. The client receives a structured JSON-RPC error response indicating which fields violated the schema constraints.
Runtime Validation Flow
The validation sequence follows a strict pipeline that separates protocol concerns from business logic:
- Request Reception: The MCP server receives a JSON-RPC request containing a tool name and arguments.
- Schema Validation: The SDK validates the request body against
CallToolRequestSchema, ensuring the tool name exists and the arguments match the tool's declaredinputSchema. - Safe Execution: The server extracts
request.params.argumentsand passes it directly to the tool implementation. Because validation already occurred, the tool can safely cast the input to its expected TypeScript interface without callingz.parse. - Error Propagation: Any schema violations trigger an immediate error response, preventing invalid data from reaching Kubernetes API calls.
This architecture means tool implementations never import Zod or perform runtime parsing; they rely entirely on the pre-validated inputs provided by the protocol layer.
Testing Schema Enforcement
The repository includes unit tests that verify Zod schemas behave as expected. In tests/kubectl.test.ts, tests instantiate Zod objects directly to confirm that both valid and invalid payloads are handled correctly.
// tests/kubectl.test.ts
import { z } from "zod";
import { kubectlGetSchema } from "../src/tools/kubectl-get.js";
test("kubectl_get schema rejects missing resourceType", () => {
const payload = { name: "my-pod" }; // missing required resourceType
expect(() =>
z.object(kubectlGetSchema.inputSchema).parse(payload)
).toThrow();
});
These tests ensure that schema changes do not inadvertently loosen validation requirements or break the contract between the server and its clients.
Summary
- Declarative Validation: Zod schemas are defined once in tool metadata and validated automatically by the MCP SDK request handlers.
- Protocol-Layer Enforcement: Validation occurs in
src/index.tsviaCallToolRequestSchemabefore any tool code executes. - Zero Tool Overhead: Tool implementations receive pre-validated arguments and do not perform additional Zod parsing.
- Comprehensive Testing: Unit tests in
tests/kubectl.test.tsverify schema behavior by directly importing and testing Zod objects.
Frequently Asked Questions
Where are Zod schemas defined in the MCP Kubernetes server?
Generic schemas reside in src/models/tool-models.ts, while concrete tool-specific input schemas are located in individual files under src/tools/ (e.g., src/tools/kubectl-get.ts). Shared parameter fragments—such as namespaceParameter—are maintained in src/models/common-parameters.ts for reuse across multiple tool definitions.
When does validation occur during a tool call?
Validation happens immediately upon receipt of the request, when the MCP SDK checks the incoming payload against CallToolRequestSchema. If the arguments do not conform to the tool's declared inputSchema, the SDK throws an McpError with ErrorCode.InvalidRequest and returns a structured error to the client before the tool handler executes.
Do tool implementations handle their own validation?
No. Tool implementations assume that request.params.arguments has already been validated against the tool's Zod schema. The tools never call z.parse or perform defensive validation; they rely entirely on the protocol-layer validation performed during request handler registration in src/index.ts.
How are schemas tested for correctness?
Unit tests import Zod directly (import { z } from "zod") and instantiate schema objects to verify enforcement. For example, tests/kubectl.test.ts confirms that missing required fields like resourceType trigger validation errors, ensuring that schema definitions remain accurate as the codebase evolves.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →