Skip to main content
Glama

Dockerfile Check

CI npm downloads OpenSSF Scorecard License: MIT

Dockerfiles written by agents fail in two ways. Some never build: apt-get install without -y waits for an answer the build cannot give, COPY ../x reaches outside the context, a tag like node:18.99-alpine does not exist, COPY --from=dep names a stage called deps. Others build and ship a problem: Node.js 18 or Python 3.8 past their end of life, a secret in ENV, a container running as root, an image missing the arm64 build the servers need. Dockerfile Check finds both:

  • Syntax with the validator behind VS Code's Dockerfile support, and the rules a build and a review apply: install commands without -y, copies from outside the context, unknown or later stages, exec form in single quotes, invalid ports, legacy ENV, several CMDs.

  • Every base image against its registry: the tag exists (with the nearest real tags when it does not), its digest and a pinned FROM line, the platforms it is built for, when Docker Hub last rebuilt it. Docker Hub, GHCR, Quay, GCR, MCR, ECR Public and registry.k8s.io.

  • End of life of what the image is built on, runtime and OS alike (python:3.8-slim-buster is Python 3.8 and Debian 10), with an upgrade tag that exists (python:3.14-slim).

  • Security and size: root users, secrets in ENV and ARG, sudo, unverified ADD URLs, package caches left in layers, dependency installs placed after COPY . ..

Every finding has its line and fix. image_info answers the same questions for images named in compose files, Kubernetes manifests or CI jobs. No key needed.

Built and maintained by Arhan Canli.

Install

Install in Cursor Install in VS Code Install in Goose

Needs Node.js 20 or newer. No account or key.

Claude Code

claude mcp add dockerfile-check -- npx -y dockerfile-check-mcp

Claude Desktop: download dockerfile-check-mcp-<version>.mcpb from the latest release and open it. The bundle is signed; verify it with gh attestation verify <file> --repo arhancanli/dockerfile-check-mcp.

Any other client (Windsurf, Zed, Cline, Continue and others), in its MCP config file:

{
  "mcpServers": {
    "dockerfile-check": {
      "command": "npx",
      "args": [
        "-y",
        "dockerfile-check-mcp"
      ]
    }
  }
}

Docker

docker build -t dockerfile-check-mcp https://github.com/arhancanli/dockerfile-check-mcp.git && docker run -i --rm dockerfile-check-mcp

Hosted (Streamable HTTP): node src/server.mjs --http serves stateless MCP at POST /mcp (port from PORT, default 3000).

Related MCP server: end-of-life-mcp

Example

An agent calls check_dockerfile with:

{
  "files": [
    {
      "path": "Dockerfile",
      "content": "ARG NODE_VERSION=18\nFROM node:${NODE_VERSION}-alpine AS deps\nWORKDIR /app\nCOPY package*.json ./\nRUN npm ci\n\nFROM node:${NODE_VERSION}-alpine AS build\nWORKDIR /app\nCOPY --from=dep /app/node_modules ./node_modules\nCOPY . .\nRUN npm run build\n\nFROM python:3.8-slim-buster\nMAINTAINER ops@example.com\nARG GITHUB_TOKEN\nRUN apt-get update\nRUN apt-get install curl git\nCOPY ../shared/config.yml /etc/app/\nCOPY --from=build /app/dist /srv\nENV DATABASE_PASSWORD=hunter2\nEXPOSE 8080/http\nUSER root\nCMD ['python', '-m', 'http.server', '8080']\n"
    }
  ]
}

and gets back (recorded from the live server on 2026-09-27):

{
  "files": [
    {
      "path": "Dockerfile",
      "counts": {
        "error": 5,
        "warning": 9,
        "info": 2
      },
      "findings": [
        {
          "line": 9,
          "severity": "error",
          "rule": "unknown-stage",
          "message": "--from=dep names no earlier stage (stages: deps, build), so Docker pulls an image called dep.",
          "fix": "use a stage name defined above, or a full image reference"
        },
        {
          "line": 17,
          "severity": "error",
          "rule": "install-without-yes",
          "message": "apt-get install without -y waits for a confirmation the build cannot give, and the build fails.",
          "fix": "add -y (and --no-install-recommends)"
        },
        {
          "line": 18,
          "severity": "error",
          "rule": "outside-context",
          "message": "COPY cannot reach outside the build context (../shared/config.yml).",
          "fix": "move the file into the context, or build from a parent directory"
        },
        {
          "line": 21,
          "severity": "error",
          "rule": "invalid-port",
          "message": "EXPOSE 8080/http is not a port (1-65535, optionally /tcp or /udp)."
        },
        {
          "line": 23,
          "severity": "error",
          "rule": "exec-form-quotes",
          "message": "Exec form needs double quotes: with single quotes this is run as a shell command, brackets and all.",
          "fix": "write [\"cmd\", \"arg\"]"
        },
        {
          "line": 2,
          "severity": "warning",
          "rule": "end-of-life",
          "message": "node:18-alpine is built on Node.js 18, past its end of life (2025-04-30): no more security fixes.",
          "fix": "use node:24-alpine"
        },
        {
          "line": 7,
          "severity": "warning",
          "rule": "end-of-life",
          "message": "node:18-alpine is built on Node.js 18, past its end of life (2025-04-30): no more security fixes.",
          "fix": "use node:24-alpine"
        },
        {
          "line": 13,
... (125 more lines)

Tools

Tool

What it does

check_dockerfile

Checks Dockerfiles: syntax, what breaks the build (apt-get install without -y, copies outside the context, unknown stages), root users, secrets in ENV/ARG, cache order, and each base image against its registry (tag exists, digest to pin, platforms, last rebuild) and end-of-life dates. Findings have line and fix.

image_info

For container image references (node:20-alpine, ghcr.io/org/app:1.2): whether the tag exists (nearest real tags if not), its digest and a pinned reference, platforms, last rebuild (Docker Hub), and end-of-life status of its runtime and OS with an upgrade tag. Docker Hub, GHCR, Quay, GCR, MCR, ECR Public, registry.k8s.io.

How it behaves

  • Read-only: no tool changes anything outside this process. Dockerfiles never leave it; only image names are looked up.

  • Network: HTTPS only, to the hosts in package.json under factory.allowHosts, with a deadline, a size cap and bounded retries. Docker Hub is read through its tag API, which does not spend the anonymous pull allowance; the other registries through the OCI distribution API with anonymous tokens (registry.k8s.io through the regional Artifact Registry it redirects to). Private registries and private images are named as such and not contacted further. End-of-life dates come from endoflife.date. Registry answers are kept for 30 minutes, since tags move. Nothing is logged except unexpected failures (to stderr, without your inputs).

  • FROM lines are read as Docker reads them: ARG defaults declared before the first FROM are filled in, scratch and earlier stages are not images, and --platform on a FROM wins over the platform you pass.

  • A digest is the registry's Docker-Content-Digest, or the SHA-256 of the manifest when a registry does not send one (ECR Public).

  • Results are compact JSON with a matching output schema: errors first, then warnings, then notes.

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_dockerfile: a three-stage Dockerfile with twelve problems

1983 ms

1.3 ms

4,787 chars

check_dockerfile: a clean two-stage Node.js build

836 ms

1.6 ms

443 chars

check_dockerfile: an amd64-only base image built for linux/arm64

777 ms

0.8 ms

873 chars

image_info: nine references across seven registries

2286 ms

1.5 ms

3,174 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): 1,429 characters. The full tool list, with the output schemas and annotations clients use to validate results, is 2,364 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.

  • Kube Check: Checks Kubernetes manifests for your version: removed APIs, unknown fields, Pod Security, risks.

  • License Check: Open source license answers: SPDX ids, copyleft, and whether a dependency's license fits yours.

  • The whole collection, 12 more

License

MIT, Copyright (c) 2026 Arhan Canli.

Available Tools

2 tools
check_dockerfileCheck DockerfilesA
Read-onlyIdempotent

Checks Dockerfiles: syntax, what breaks the build (apt-get install without -y, copies outside the context, unknown stages), root users, secrets in ENV/ARG, cache order, and each base image against its registry (tag exists, digest to pin, platforms, last rebuild) and end-of-life dates. Findings have line and fix.

Inputs: files (required), platform. Returns: files

image_infoDoes this image tag exist, and is it supported?A
Read-onlyIdempotent

For container image references (node:20-alpine, ghcr.io/org/app:1.2): whether the tag exists (nearest real tags if not), its digest and a pinned reference, platforms, last rebuild (Docker Hub), and end-of-life status of its runtime and OS with an upgrade tag. Docker Hub, GHCR, Quay, GCR, MCR, ECR Public, registry.k8s.io.

Inputs: images (required), platform. Returns: images

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A3.7/5.0

    Scored across 2 tools

    Disambiguation4/5

    check_dockerfile is clearly the Dockerfile linter while image_info is the image-reference inspector, so the core purposes are distinct. However, check_dockerfile also validates each base image against its registry (tag existence, digests, platforms, EOL), which overlaps with what image_info does, creating some potential for misselection on image-related queries.

    Naming Consistency4/5

    Both names use snake_case consistently, which is readable and predictable. The pattern is slightly uneven (verb_noun 'check_dockerfile' vs noun_noun 'image_info'), a minor deviation rather than a real inconsistency.

    Tool Count3/5

    Two tools is defensible for this narrow, focused domain (linting Dockerfiles plus inspecting image references). Still, it sits at the thin end and leaves little redundancy or granularity for users who only want one aspect checked.

    Completeness4/5

    The pair covers the stated purpose well: Dockerfile lint findings with lines and fixes, plus image tag/digest/platform/EOL data across major registries. Minor gaps remain, such as no autofix output or broader compose-file/context checks, but core workflows are covered.

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      B
      maintenance
      Audits 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.
      1
      MIT
    • A
      license
      A
      quality
      B
      maintenance
      Enables checking project files like Dockerfile, .nvmrc, and CI workflows to determine whether pinned runtime, database, and OS versions are still supported, providing end-of-life dates, latest patches, and upgrade targets for 470+ products.
      3
      1
      MIT
    • A
      license
      Not graded
      quality
      C
      maintenance
      Enables users to audit Dockerfiles for container-security anti-patterns, including missing USER, baked-in secrets, curl | sh / wget | bash, unpinned base images, and ADD with remote URLs. It parses Dockerfile structure to return risk levels and actionable fixes.
      MIT
    • A
      license
      Not graded
      quality
      C
      maintenance
      Exposes a Dockerfile auditing engine to AI assistants, letting them scan a Dockerfile for the 32 deterministic layer-aware rules, print a stage/layer map showing what each layer adds or deletes, explain any rule's rationale and fix, and list available rules. Findings include file:line evidence so agents can surface and triage image-safety issues directly in Claude Code, Cursor, or Cline.
      MIT