Kube Check
Checks Argo custom resources against their CRDs, either from the supplied manifests or from a built-in CRD catalog, validating apiVersion/kind, fields, types, and schema for Argo resources.
Checks Istio custom resources against their CRDs, either from the supplied manifests or from a built-in CRD catalog, validating apiVersion/kind, fields, types, and schema for Istio resources.
Validates Kubernetes manifests (YAML or JSON, multi-document) against a chosen Kubernetes version from 1.19 to newest, checking removed/deprecated APIs and replacements, unknown or misspelt fields, schema and type errors, API server admission rules such as name/label/selector validity, Pod Security Standards, and common risks without needing a cluster.
Checks Prometheus custom resources against their CRDs, either from the supplied manifests or from a built-in CRD catalog, validating apiVersion/kind, fields, types, and schema for Prometheus resources.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Kube Checkcheck k8s/deploy.yaml against Kubernetes 1.29 for deprecated APIs"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Kube Check
Agents write Kubernetes manifests from memory, and memory is several versions old: extensions/v1beta1
Ingresses (gone since 1.22), batch/v1beta1 CronJobs (gone since 1.25), imagePullPolicy: always,
memory: 512mb, a selector that does not match the pod labels. The cluster refuses them at deploy
time, or worse, accepts them and runs something else. Kube Check checks manifests against the API of
the Kubernetes version you run or are upgrading to, without a cluster:
APIs: what that version serves, what was removed (with the replacement, and the other fields that must change: an Ingress moving to
networking.k8s.io/v1also needspathTypeandbackend.service), and what is deprecated there, for 1.19 to the newest release.Fields: unknown or misspelt fields with the one meant, wrong types, enumerated values the OpenAPI document leaves out (
Always, notalways), quantities (512Mi, not512mb), and what the API server refuses beyond the schema: names, labels, selectors that match no pods, requests above limits, probes with two handlers, mounts of volumes that do not exist.Custom resources: checked against their CRD when it is in the files, else the CRDs catalog (cert-manager, Argo, Istio, Prometheus and hundreds more).
Pod Security Standards: baseline by default, restricted on request, check by check as Pod Security admission applies them; plus risks such as unpinned images, missing requests and secrets written into env.
Every finding has its file, line, rule and fix. Look up any field's meaning, or which apiVersion a kind needs, in the same version. No cluster or key needed.
Built and maintained by Arhan Canli.
Install
Needs Node.js 20 or newer. No account or key.
Claude Code
claude mcp add kube-check -- npx -y kube-check-mcpClaude Desktop: download kube-check-mcp-<version>.mcpb from the latest release and open it. The bundle is signed; verify it with gh attestation verify <file> --repo arhancanli/kube-check-mcp.
Any other client (Windsurf, Zed, Cline, Continue and others), in its MCP config file:
{
"mcpServers": {
"kube-check": {
"command": "npx",
"args": [
"-y",
"kube-check-mcp"
]
}
}
}Docker
docker build -t kube-check-mcp https://github.com/arhancanli/kube-check-mcp.git && docker run -i --rm kube-check-mcpHosted (Streamable HTTP): node src/server.mjs --http serves stateless MCP at POST /mcp (port from PORT, default 3000).
Related MCP server: API Doctor MCP
Example
An agent calls check_manifests with:
{
"files": [
{
"path": "k8s/app.yaml",
"content": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: Web_App\n labels:\n app: web\nspec:\n replicas: 2\n selector:\n matchLabels:\n app: web\n template:\n metadata:\n labels:\n app: website\n spec:\n containers:\n - name: web\n image: nginx\n imagePullPolicy: always\n port:\n - containerPort: 80\n resources:\n requests:\n memory: 512mb\n cpu: \"2\"\n limits:\n cpu: \"1\"\n env:\n - name: DB_PASSWORD\n value: hunter2\n - name: DEBUG\n value: yes\n securityContext:\n privileged: true\n---\napiVersion: extensions/v1beta1\nkind: Ingress\nmetadata:\n name: web\nspec:\n rules:\n - host: example.com\n http:\n paths:\n - path: /\n backend:\n serviceName: web\n servicePort: 80\n---\napiVersion: v1\nkind: Service\nmetadata:\n name: web\nspec:\n selector:\n app: web\n ports:\n - port: 80\n targetPort: http\n---\napiVersion: batch/v1beta1\nkind: CronJob\nmetadata:\n name: cleanup\nspec:\n schedule: \"0 3 * *\"\n jobTemplate:\n spec:\n template:\n spec:\n containers:\n - name: c\n image: busybox:1.36\n---\napiVersion: policy/v1beta1\nkind: PodSecurityPolicy\nmetadata:\n name: restricted\nspec: {}\n"
}
]
}and gets back (recorded from the live server on 2026-09-27):
{
"kubernetes_version": "1.37",
"objects": 5,
"counts": {
"error": 12,
"warning": 5
},
"findings": [
{
"file": "k8s/app.yaml",
"line": 4,
"object": "Deployment/Web_App",
"severity": "error",
"rule": "invalid-name",
"path": "metadata.name",
"message": "The Deployment name \"Web_App\" is invalid: lowercase letters, digits, '-' and '.', starting and ending with a letter or digit."
},
{
"file": "k8s/app.yaml",
"line": 9,
"object": "Deployment/Web_App",
"severity": "error",
"rule": "selector-mismatch",
"path": "spec.selector",
"message": "The selector does not match the pod template's labels (app=website): the API server refuses it.",
"fix": "make spec.template.metadata.labels contain every selector label"
},
{
"file": "k8s/app.yaml",
"line": 20,
"object": "Deployment/Web_App",
"severity": "error",
"rule": "schema",
"path": "spec.template.spec.containers[0].imagePullPolicy",
"message": "\"always\" is not an allowed value",
"did_you_mean": "Always",
"allowed": [
"Always",
"IfNotPresent",
"Never"
]
},
{
"file": "k8s/app.yaml",
"line": 21,
"object": "Deployment/Web_App",
"severity": "error",
"rule": "schema",
"path": "spec.template.spec.containers[0].port",
"message": "unknown property \"port\"",
"did_you_mean": "ports"
},
{
"file": "k8s/app.yaml",
"line": 25,
"object": "Deployment/Web_App",
"severity": "error",
"rule": "schema",
"path": "spec.template.spec.containers[0].resources.requests.memory",
"message": "\"512mb\" is not a quantity: write 512Mi (powers of 1024) or 512M (powers of 1000); units are Ki Mi Gi Ti Pi Ei or k M G T P E, and m means thousandths",
... (127 more lines)Tools
Tool | What it does |
| For Kubernetes kinds (Ingress) or apiVersion/kind pairs (batch/v1beta1/CronJob): the apiVersions a version serves (default: newest), the one to use, and when older ones were deprecated and removed. A named apiVersion gets its status there: served, deprecated or removed, with the replacement. |
| Checks Kubernetes manifests (YAML/JSON, multi-document) against a Kubernetes version (default: newest): removed or deprecated APIs with replacements, unknown or wrong fields, what the API server refuses, Pod Security (baseline; restricted on request), risks. Custom resources via their CRD. Findings have file, line, fix. Render Helm/Kustomize first. |
| What a field of a Kubernetes kind means and accepts, from the version's API (default: newest): description, type, allowed values, required sub-fields and the fields under it. field is a dotted path (spec.template.spec.containers[].resources); omit it for the kind's top level. search finds fields by words instead (search: 'rolling update surge'). |
How it behaves
Read-only: no tool changes anything outside this process. Manifests never leave it; only schemas and version data are downloaded.
Network: HTTPS only, to
raw.githubusercontent.comandendoflife.date, with a deadline, a size cap and bounded retries. Sources: each version's API definitions from kubernetes-json-schema (generated from Kubernetes' own OpenAPI document; one 1.5 MB file per version, fetched once and kept), removal and deprecation history from Pluto (Apache-2.0), custom resource schemas from the CRDs catalog (MIT), and the release list from endoflife.date. Nothing is logged except unexpected failures (to stderr, without your inputs).Read as kubectl reads: YAML 1.1 (
yesis a boolean, sovalue: yesin env is refused, as the API server refuses it), every document of a file, List objects split, comment-only documents (Helm's disabled templates) skipped,nullfields treated as unset.Whether an apiVersion is served comes from that version's own definitions; Pluto's table only adds when it was deprecated and removed, and a deprecation is reported only when the version also serves a newer API to move to. A field the CRDs catalog's schema does not know is a warning, not an error, unless it is a near miss of a known field: the installed CRD may be newer.
Patterns written for Go's regular expressions (
(?i),\z,[[:alpha:]]) are translated; one that still cannot run in JavaScript is not checked rather than failing the whole schema.Results are compact JSON with a matching output schema: errors first, then warnings, then notes; at most 200 findings are listed and the rest counted.
Benchmark
Not yet measured.
Performance
Measured 2026-09-27 from Dubai, home connection against the live upstream, Node 24.19.0 (bench/perf.json, scripts/perf.mjs in the factory).
Call | First call | Repeat | Result size |
check_manifests: a Deployment with eight mistakes, a removed Ingress, CronJob and PodSecurityPolicy | 906 ms | 2.7 ms | 5,625 chars |
check_manifests: a clean Deployment, Service and Ingress under the restricted Pod Security level | 907 ms | 2.6 ms | 67 chars |
check_manifests: a CRD with its resource, a cert-manager Certificate and a pod, restricted | 867 ms | 2.9 ms | 3,186 chars |
check_manifests: manifests written for 1.24, checked for the upgrade to 1.25 | 748 ms | 1.9 ms | 663 chars |
check_manifests: the same manifests on 1.24, where they are only deprecated | 578 ms | 2.4 ms | 696 chars |
api_versions: six kinds and apiVersions | 696 ms | 0.7 ms | 2,010 chars |
field_help: a Deployment's rolling update surge | 1088 ms | 0.9 ms | 826 chars |
field_help: search a Pod's fields for 'termination grace' | 1015 ms | 1.9 ms | 1,085 chars |
First call: a fresh server process, including the TLS connection and the upstream's own time. Repeat: the same call again, answered from the in-process cache, so it shows this server's own overhead.
Tool definitions the model reads on every turn (name, description, input schema): 2,212 characters. The full tool list, with the output schemas and annotations clients use to validate results, is 3,614 characters.
More MCP servers by Arhan Canli
Actions Check: Checks GitHub Actions workflows: outdated actions, old Node runtimes, retired runners, injection.
Config Check: Validates config files against their official schemas: tsconfig, compose, workflows, 1,400+ more.
Cron Check: Explains cron expressions, lists next run times in any time zone, converts between cron dialects.
Domain Health: Email and domain checks: SPF lookup limits, DKIM keys, DMARC, DNS records, registration expiry.
End of Life: Is this version still supported? EOL dates, latest patch and upgrade target for 470+ products.
Internet Standards: RFC sections, status, obsoleted-by chains, errata and IANA registries for coding agents.
License Check: Open source license answers: SPDX ids, copyleft, and whether a dependency's license fits yours.
Package Truth: Checks packages exist before install: version, deprecation, vulnerabilities, licence. 7 ecosystems.
The whole collection, 9 more
License
MIT, Copyright (c) 2026 Arhan Canli.
Available Tools
3 toolsapi_versionsWhich apiVersion does a kind need?ARead-onlyIdempotent
For Kubernetes kinds (Ingress) or apiVersion/kind pairs (batch/v1beta1/CronJob): the apiVersions a version serves (default: newest), the one to use, and when older ones were deprecated and removed. A named apiVersion gets its status there: served, deprecated or removed, with the replacement.
| Name | Required | Description | Default |
|---|---|---|---|
| kinds | Yes | ||
| kubernetes_version | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| results | Yes | |
| kubernetes_version | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare a safe, idempotent, read-only, open-world lookup, so the bar is lower. The description goes beyond them by disclosing the response semantics: newest is the default, older versions carry deprecation and removal dates, and a named version yields a status of served/deprecated/removed plus a replacement.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two dense sentences with no filler; the input forms and the default-to-newest behavior are front-loaded. It reads as a compressed spec rather than prose, which suits an agent consumer.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need no exhaustive explanation, yet the description still characterizes the shape of the answer. The only real hole is the unexplained 'kubernetes_version' parameter; otherwise an agent has enough to call this correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate. It usefully documents the accepted format of the required 'kinds' entries (bare kind or apiVersion/kind pair), but says nothing about the optional 'kubernetes_version' parameter (e.g., whether it defaults to newest or filters against a specific release).
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb+resource: it resolves which apiVersions a kind (or apiVersion/kind pair) is served by, which one to use, and deprecation/removal history. It is clearly distinguishable from check_manifests and field_help, but it never names those siblings to reinforce the boundary.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by the input forms (a bare kind like 'Ingress' or a full 'batch/v1beta1/CronJob' pair) and by the goal of finding a usable apiVersion. There is no explicit statement of when to reach for this tool versus check_manifests or field_help, and no exclusions or prerequisites.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
check_manifestsCheck Kubernetes manifestsARead-onlyIdempotent
Checks Kubernetes manifests (YAML/JSON, multi-document) against a Kubernetes version (default: newest): removed or deprecated APIs with replacements, unknown or wrong fields, what the API server refuses, Pod Security (baseline; restricted on request), risks. Custom resources via their CRD. Findings have file, line, fix. Render Helm/Kustomize first.
| Name | Required | Description | Default |
|---|---|---|---|
| files | Yes | ||
| pod_security | No | the level the namespace enforces; its violations become errors | |
| kubernetes_version | No | e.g. 1.30; default the newest release |
Output Schema
| Name | Required | Description |
|---|---|---|
| counts | Yes | |
| objects | Yes | |
| findings | Yes | |
| kubernetes_version | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive, openWorld), so the bar is lower. The description adds genuinely useful behavior: custom resources resolved via their CRD, multi-document support, and that findings carry file, line, and fix. It stops short of stating whether results are exhaustive or how severity is ordered, but the added context is substantial.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Dense but front-loaded, leading with what is checked before the qualifications. It's a single long sentence fragment chain with no wasted preamble, though the list-like packing is slightly denser than needed.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be spelled out, yet the description still notes the shape of findings. Coverage of inputs, defaults, validation scope, and the Helm/Kustomize prerequisite makes this complete for a read-only checker.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With 67% schema coverage, the description compensates well: it explains kubernetes_version defaults to the newest release, describes the pod_security levels and that their violations become errors, and clarifies that files must be rendered (Helm/Kustomize) before passing. This adds meaning beyond the raw schema fields.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (checks) and resource (Kubernetes manifests) plus the scope of what is validated: removed/deprecated APIs, unknown fields, API server refusals, Pod Security, and risks. The sibling tools (api_versions, field_help) are clearly different in function, so an agent can route correctly without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives concrete operating conditions: multi-document YAML/JSON, Kubernetes version defaults to newest, Pod Security baseline by default and restricted on request, and a prerequisite to render Helm/Kustomize first. It doesn't name alternatives or explicit when-not cases, but the context is clear enough to invoke confidently.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
field_helpWhat does this Kubernetes field do?ARead-onlyIdempotent
What a field of a Kubernetes kind means and accepts, from the version's API (default: newest): description, type, allowed values, required sub-fields and the fields under it. field is a dotted path (spec.template.spec.containers[].resources); omit it for the kind's top level. search finds fields by words instead (search: 'rolling update surge').
| Name | Required | Description | Default |
|---|---|---|---|
| kind | Yes | Deployment, or apps/v1/Deployment | |
| field | No | ||
| search | No | ||
| kubernetes_version | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| kind | Yes | |
| apiVersion | Yes | |
| kubernetes_version | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive, open-world). The description adds genuine behavioral context beyond them: content is sourced from the versioned API and defaults to the newest version. It stops short of stating failure modes (e.g., unknown kind or unresolvable path).
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core purpose, then parameter mechanics, all in a single dense sentence-group with zero filler. Examples are embedded inline rather than padding the text.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return values need no explanation, and the description covers addressing modes, defaults, and fallbacks adequately for a read-only lookup tool. It is only marginally incomplete in not hinting at unsupported kinds or lookup failure behavior.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is only 25% (just `kind`), but the description compensates thoroughly: it defines `field` as a dotted path with a concrete example, explains omitting it for top-level, defines `search` as word-based with an example query, and notes `kubernetes_version` defaults to newest. All four parameters gain meaning beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource: it explains what a field of a Kubernetes kind 'means and accepts' from the versioned API. The scope (per-field documentation lookup, with dotted-path addressing) is unmistakably distinct from the sibling manifest-checking and API-version tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear in-tool routing: use `field` for a dotted path, 'omit it for the kind's top level', and use `search` for word-based discovery with a worked example. It does not, however, state when to reach for this tool over api_versions or check_manifests, nor any preconditions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
3 tool updates
v0.1.0- First observed
api_versions - First observed
check_manifests - First observed
field_help
TDQS
Scored across 3 tools
The three tools target distinct activities: API version lifecycle lookup (api_versions), manifest validation (check_manifests), and field schema documentation (field_help). There is mild overlap between api_versions and check_manifests since both surface deprecated/removed APIs, but the descriptions make the boundary clear (lookup vs. file-level validation).
All names are snake_case, which is good, but the patterns differ: api_versions is a noun phrase, check_manifests is verb_noun, and field_help is noun_noun. Readable but no single predictable convention.
Three focused tools is on the lean side but each covers a distinct, well-motivated capability for Kubernetes manifest checking. No filler tools and no obvious redundancy.
The surface covers the key lifecycle needs: API version/deprecation status, manifest validation with fixes, and field documentation including CRDs and Helm/Kustomize-aware behavior. Minor gaps like live-cluster validation or explicit schema browsing are acceptable for the stated scope.
Maintenance
Related MCP Connectors
kube-linter audit for Kubernetes manifests — 63 checks: security, availability, RBAC, network.
Fail-closed policy guardrails for AI agents running kubectl, terraform, helm, and argocd.
Four IaC audits in one call: Compose, Dockerfile, GitHub Actions, Kubernetes. 131 checks.
Multi-CI security scanner with a live threat-intel feed of compromised CI components
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceMCP server to lint and validate Kubernetes-related manifests(Helm, FluxCD, ArgoCD, Kustomize, etc.)27 PyPIMIT
- FlicenseNot gradedqualityBmaintenanceValidates OpenAPI documents, JSON Schemas, and JSON payloads. Also compares OpenAPI specs and displays breaking changes.-
- FlicenseNot gradedqualityDmaintenanceStatic audit of Kubernetes manifests via MCP, powered by kube-linter. Returns structured reports with severity, check ID, category, message, and remediation hints.-

EVIDIQ Bastionofficial
AlicenseNot gradedqualityBmaintenanceAudits infrastructure configurations (Dockerfiles, GitHub Actions, Kubernetes, Terraform/Compose) against 14 deterministic security rules, returning BLOCK/REVIEW/PASS verdicts and signing attestations. Helps agents verify deployment configs before applying them.1MIT