How the kubectl_patch Tool Handles Strategic, Merge, and JSON Patches in Kubernetes
The kubectl_patch tool supports three Kubernetes patch types—strategic (default), merge, and JSON—by mapping the patchType parameter to kubectl's --type flag and managing patch data through temporary files or direct file references.
The kubectl_patch tool in the flux159/mcp-server-kubernetes repository provides MCP clients with a type-safe wrapper around kubectl patch, abstracting the complexity of RFC 6902 JSON patches, JSON Merge patches, and Strategic Merge patches while handling resource cleanup and error propagation automatically.
Overview of Patch Types in kubectl_patch
The tool implements the three standard Kubernetes patching strategies as defined by the upstream kubectl CLI. Each strategy modifies resources differently and suits specific use cases:
- Strategic merge patch (default): Uses server-side logic to merge lists based on merge keys like
nameorcontainerPort, ideal for native Kubernetes resources such as Deployments and Services. - Merge patch: Implements JSON Merge Patch (RFC 7386), which replaces entire fields rather than merging them, useful for generic or custom resources.
- JSON patch: Implements JSON Patch (RFC 6902) with explicit operations (
add,remove,replace,move,copy,test), providing surgical precision for specific field modifications.
Implementation Details in src/tools/kubectl-patch.ts
The core implementation resides in src/tools/kubectl-patch.ts, where the tool constructs shell commands, validates inputs, and manages the lifecycle of temporary patch files.
Input Validation and Defaults
The tool enforces strict input requirements at lines 70-74, throwing a McpError with ErrorCode.InvalidRequest if neither patchData nor patchFile is provided. Default values are established at lines 77-79: namespace falls back to "default", patchType defaults to "strategic", and dryRun initializes to false.
Command Assembly and Patch Type Selection
Command construction begins at line 84 with the base array ["patch", resourceType, name, "-n", namespace]. A switch statement at lines 87-99 injects the appropriate --type flag based on the patchType parameter:
"strategic"→--type strategic(line 89)"merge"→--type merge(line 92)"json"→--type json(line 95)
Payload Handling and Execution
For inline JSON payloads (patchData), the tool creates a temporary file under os.tmpdir() with a unique name at lines 111-114, passing the path via --patch-file. When patchFile is provided, the path is forwarded directly at lines 115-117. Optional flags including --dry-run=client (lines 120-122) and --context (lines 124-126) are appended before execution via execFileSync with a bounded buffer from getSpawnMaxBuffer() (lines 131-135).
Cleanup logic at lines 137-164 ensures temporary files are deleted regardless of execution success or failure. Error handling at lines 155-168 wraps execution failures in McpError instances with ErrorCode.InternalError, preserving stack traces while providing actionable error messages.
Code Examples
The following examples demonstrate how MCP clients interact with the kubectl_patch tool through the SDK. All assume an established client connection.
Strategic Merge Patch (Default)
await client.request(
{
method: "tools/call",
params: {
name: "kubectl_patch",
arguments: {
resourceType: "deployment",
name: "web-server",
namespace: "production",
patchData: {
spec: {
replicas: 3,
template: {
spec: {
containers: [{
name: "nginx",
image: "nginx:1.25"
}]
}
}
}
}
}
}
},
z.any()
);
Implementation reference: Default patchType handling at line 78 and strategic flag injection at line 89.
JSON Merge Patch
await client.request(
{
method: "tools/call",
params: {
name: "kubectl_patch",
arguments: {
resourceType: "configmap",
name: "app-config",
namespace: "default",
patchType: "merge",
patchData: {
data: {
LOG_LEVEL: "debug"
}
}
}
}
},
z.any()
);
Implementation reference: Merge type flag at line 92.
JSON Patch (RFC 6902)
await client.request(
{
method: "tools/call",
params: {
name: "kubectl_patch",
arguments: {
resourceType: "pod",
name: "worker-7d9f4",
namespace: "batch-jobs",
patchType: "json",
patchData: [
{ op: "replace", path: "/spec/containers/0/image", value: "busybox:1.36" },
{ op: "add", path: "/metadata/labels/environment", value: "staging" },
{ op: "remove", path: "/spec/terminationGracePeriodSeconds" }
]
}
}
},
z.any()
);
Implementation reference: JSON type flag at line 95.
Using External Patch Files
await client.request(
{
method: "tools/call",
params: {
name: "kubectl_patch",
arguments: {
resourceType: "service",
name: "api-gateway",
namespace: "ingress",
patchFile: "/opt/patches/service-annotations.yaml"
}
}
},
z.any()
);
Implementation reference: File path handling at lines 115-117.
Dry-Run Mode
await client.request(
{
method: "tools/call",
params: {
name: "kubectl_patch",
arguments: {
resourceType: "deployment",
name: "critical-app",
namespace: "production",
patchType: "strategic",
patchData: {
spec: { replicas: 10 }
},
dryRun: true
}
}
},
z.any()
);
Implementation reference: Dry-run flag injection at line 121.
Error Handling and Resource Cleanup
The tool implements defensive programming patterns to prevent resource leaks and provide clear failure diagnostics. As implemented in src/tools/kubectl-patch.ts, any execFileSync failure triggers the cleanup block at lines 137-164, which removes temporary JSON files created for inline patch data. Errors are wrapped at lines 155-168 with descriptive messages indicating whether the failure occurred during command execution, file system operations, or JSON serialization. Unexpected errors outside the main try-catch block are also captured and re-wrapped at lines 170-178 to ensure all exceptions conform to the MCP protocol's error structure.
Summary
- Strategic merge is the default patching strategy, activated when
patchTypeis omitted or explicitly set to"strategic", utilizing kubectl's server-side merging logic. - JSON Merge and JSON Patch require explicit
patchTypevalues of"merge"and"json"respectively, each triggering different kubectl--typeflags and accepting distinct payload structures. - Temporary file management handles inline
patchDataby writing toos.tmpdir()and automatically cleaning up after execution, whilepatchFilereferences existing server-side files directly. - Safety features include client-side dry-run support via the
dryRunparameter and comprehensive error wrapping that converts all failures into standardizedMcpErrorobjects.
Frequently Asked Questions
What happens if I provide both patchData and patchFile to kubectl_patch?
The tool validates inputs at lines 70-74 and requires at least one of these parameters, but does not explicitly reject providing both. When both are present, the implementation prioritizes patchData because the conditional logic at lines 111-114 creates a temporary file and appends --patch-file before checking patchFile at lines 115-117, effectively overwriting the file path argument.
Why does kubectl_patch create temporary files instead of passing JSON directly to kubectl?
The implementation uses temporary files (lines 111-114) because kubectl's --patch flag has strict length limitations and shell escaping requirements that can corrupt complex JSON payloads. Writing to a temporary file via --patch-file ensures large patches, special characters, and multi-line strings are handled correctly without command-line injection risks or buffer overflows.
How does the tool handle kubectl context switching?
The tool accepts an optional context parameter that appends --context to the command array at lines 124-126. This allows MCP clients to target specific clusters defined in the kubeconfig file without modifying the KUBECONFIG environment variable, which is inherited from the parent process as referenced at lines 131-135.
What patch type should I use for Custom Resource Definitions (CRDs)?
For CRDs, use JSON Merge Patch (patchType: "merge") or JSON Patch (patchType: "json"). According to the Kubernetes API conventions, Strategic Merge Patch requires server-side knowledge of resource schemas and merge keys, which native resources possess but most CRDs lack unless explicitly defined in the CRD's OpenAPI v3 schema.
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 →