dockerlint-mcp
Statically lints and explains Dockerfiles, docker-compose files and .dockerignore files, returning rule IDs, severities, line numbers and concrete fixes. Provides a Dockerfile overview (stages, base image tags/digests, exposed ports, entrypoint/cmd), layer and build-cache analysis with size hints, compose security checks (privileged containers, docker.sock mounts, host network, broad bind mounts, secrets in environment), .dockerignore coverage checks against COPY requirements, multi-stage rewrite proposals for Python/Node/Go/Rust patterns, and a unified-diff preview of safe automatic fixes. Nothing is built or run and no Docker daemon is required.
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., "@dockerlint-mcpLint the Dockerfile, preview safe fixes, and explain what still needs manual changes."
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.
dockerlint-mcp
An MCP server that lets an AI lint and explain Dockerfiles and docker-compose files statically: rule IDs, severities, line numbers and a concrete fix for every finding. It never builds or runs anything, needs no Docker daemon and no external binary.
How it differs from what exists. The Dockerfile-lint MCP servers I could find
(Docker CI Lint MCP, and hosted linters on
Apify) wrap a single linter or a
hosted service, and Hadolint-based setups need the hadolint binary. This server is pure Python (mcp +
pyyaml), runs fully offline, and covers the whole build context in one place: Dockerfile rules,
compose rules, .dockerignore matching that follows Docker's real rules (and checks it against what your
COPY lines need), layer/cache-order analysis, multi-stage rewrite proposals, and a unified-diff
preview of the safe automatic fixes. Secret values are never echoed back to the model, and file access
is sandboxed to one directory.
Install
Claude Code:
claude mcp add dockerlint -- uvx dockerlint-mcp --dir .Claude Desktop (claude_desktop_config.json):
{
"mcpServers": {
"dockerlint": {
"command": "uvx",
"args": ["dockerlint-mcp", "--dir", "C:\\path\\to\\your\\project"]
}
}
}Without uv: pip install dockerlint-mcp, then run dockerlint-mcp --dir /path/to/project.
Flag | Meaning |
| Only files inside this directory can be read (default: the current directory). |
| Comma-separated rule ids to turn off, e.g. |
You can also silence a single finding in the file itself with a comment on the line above:
# dockerlint-ignore: DL1003, DL1005
RUN apt-get updateIn compose files, put the comment above a line, or above a service name to cover the whole service.
In a .dockerignore, # dockerlint-ignore: DI3002 anywhere turns that rule off for the file.
Related MCP server: mcp-zen-of-languages
Tools
Tool | What it does |
| Stages with base image tag/digest, layer count, exposed ports, final user, workdir, ENTRYPOINT/CMD (exec vs shell form), COPY --from edges. |
| 28 rules (DL1001-DL1028). Each finding: rule id, severity, instruction line, explanation, concrete fix. |
| Which instructions create layers, heuristic size hints, and ORDER problems that bust the cache or bloat the image. |
| 13 compose rules (DC2001-DC2014) with line numbers. |
| Missing file, patterns that do not exclude |
| A multi-stage rewrite as text for common Python, Node, Go and Rust patterns. Never writes a file. |
| Unified diff of the safe automatic fixes. Never writes a file; lists what needs a manual change. |
path is a file (or a directory containing a Dockerfile), relative to --dir or absolute inside it.
The line number of a Dockerfile finding is the first line of the instruction.
Try asking
"Lint the Dockerfile and fix everything that is safe, then show me what is left."
"Why does my Docker build re-install dependencies on every code change?" (explain_layers)
"Is my .dockerignore protecting me? Does it exclude anything my COPY lines need?"
"Review docker-compose.yml for anything dangerous before I deploy it."
"Turn this single-stage Python Dockerfile into a multi-stage one."
"Which layers make my image big?"
Rules
ID | Severity | Rule |
DL1001 | warning | base image has no version tag or digest |
DL1002 | warning | base image uses the :latest tag |
DL1003 | warning | apt-get update without install in the same RUN |
DL1004 | warning | apt-get install without --no-install-recommends |
DL1005 | warning | apt package lists are left in the layer |
DL1006 | warning | pip install without --no-cache-dir |
DL1007 | warning | container runs as root |
DL1008 | warning | ADD used where COPY would do |
DL1009 | warning | COPY . before installing dependencies busts the build cache |
DL1010 | error | secret stored in ENV or ARG |
DL1011 | error | secret in a RUN / COPY / other instruction |
DL1012 | warning | piping curl/wget into a shell |
DL1013 | info | no HEALTHCHECK |
DL1014 | warning | shell-form ENTRYPOINT/CMD (signals are not forwarded) |
DL1015 | warning | multiple CMD / ENTRYPOINT / HEALTHCHECK in one stage |
DL1016 | warning | WORKDIR is not an absolute path |
DL1017 | warning | cd inside RUN |
DL1018 | warning | sudo inside a Dockerfile |
DL1019 | warning | world-writable permissions (chmod 777) |
DL1020 | warning | package manager cache is left in the layer (apk, yum, dnf) |
DL1021 | warning | COPY would send node_modules or .git into the image |
DL1022 | error | COPY --from refers to an unknown or later stage |
DL1023 | error | duplicate stage name |
DL1024 | error | package install without a non-interactive flag (-y) |
DL1025 | warning | apt-get upgrade makes the build non-reproducible |
DL1026 | warning | apt CLI used in a script; use apt-get |
DL1027 | info | MAINTAINER is deprecated |
DL1028 | error | Dockerfile syntax problem |
DC2001 | warning | compose image has no version tag |
DC2002 | warning | compose image uses :latest |
DC2003 | error | privileged container |
DC2004 | warning | host network mode |
DC2005 | error | docker.sock mounted into a container |
DC2006 | error | secret in environment |
DC2007 | info / warning | published port binds all interfaces (warning for databases and caches) |
DC2008 | info | no restart policy |
DC2009 | info | no healthcheck |
DC2010 | info | depends_on without a health condition |
DC2012 | warning / error | broad host directory bind mount ( |
DC2013 | info | obsolete top-level |
DC2014 | error | env_file does not exist |
DI3001 | warning | no .dockerignore |
DI3002 | warning | .dockerignore does not exclude .git |
DI3003 | warning | .dockerignore does not exclude node_modules |
DI3004 | warning | .dockerignore does not exclude .env files |
DI3005 | error | .dockerignore excludes a file the Dockerfile copies |
DI3006 | info | node_modules/.git in a subdirectory is not excluded |
How it works and what it cannot know
The Dockerfile parser is hand-written: parser directives, line continuations (with comments and blank lines inside), heredocs, JSON vs shell form,
--mount/--chown/--fromflags,ONBUILD, multi-stage names, andARG/ENVexpansion inFROM/WORKDIR.Rules look at parsed commands, not raw text, so
echo "apt-get update"is not a finding.The build context is assumed to be the Dockerfile's directory. If you build with a different context (
docker build -f docker/Dockerfile .) the context-dependent checks (DL1021,check_dockerignore) are looking at the wrong directory.Sizes in
explain_layersare heuristics from the commands, not measurements.A base image that already runs unprivileged (for example a custom image) looks like root to DL1007; silence it with
# dockerlint-ignore: DL1007.Compose findings are located by scanning the YAML text; if a key cannot be found the finding points at the service line. Only a single file is read (no
extends,include, or-fmerging, no.envinterpolation).
Security
Read-only and static. Nothing is built, run, pulled or written.
suggest_multistageandfix_previewreturn text; applying it is up to you.Directory sandbox. Every path is resolved (symlinks included) and must stay inside
--dir;..traversal, absolute paths outside it and symlink escapes are refused.env_filepaths that point outside it are reported without being probed.Secrets are never echoed. Findings name the variable (
DB_PASSWORD) or the kind of secret ("GitHub token"), not its value. Instruction text shown bydockerfile_overview,explain_layersandfix_previewis redacted the same way. (The file on disk is of course unchanged.)Safe parsing. Compose files are loaded with
yaml.safe_loadonly; files over 2 MB are refused; nested or alias-heavy YAML cannot make the server expand data without bound.The server makes no network requests.
Development
uv sync --extra test
uv run --python 3.12 pytest
uv run ruff check src tests
uv run mypy --strict srcThe tests use real files in temporary directories and launch the installed server over stdio. The
corpus in tests/corpus/good holds 16 realistic Dockerfiles that must produce zero findings.
There is a build-it-yourself tutorial in dockerlint-mcp-the-hard-way.
MIT licensed.
Available Tools
7 toolscheck_dockerignoreA
Check the .dockerignore for a Dockerfile (or a directory): missing file, patterns that do not exclude .git, node_modules or .env files, nested node_modules the root-anchored patterns miss, and patterns that exclude files the Dockerfile COPYs (the build would fail or silently omit them). Uses Docker's matching rules (root-anchored, last match wins, ** crosses dirs).
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations supplied, the description carries the full burden and largely succeeds: it names the matching semantics used (root-anchored, last match wins, ** crosses dirs) and explains the real consequence of a bad ignore file ("the build would fail or silently omit them"). What it does not state is whether the tool is purely read-only and whether a missing path is reported as a finding or an error.
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?
One dense sentence front-loads the resource and the failure modes, then a second sentence supplies the matching rules. Every clause carries information, though the parenthetical list is long enough that a reader must parse carefully; a short bulleted breakdown would scan faster.
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 explanation, and the description covers the check surface, the matching semantics, and the stakes of a bad result. For a single-parameter read-check tool this is effectively complete.
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 coverage is 0% — the only parameter is titled "Path" with no description. The description partly compensates by clarifying that the path may be a Dockerfile or a directory, which is genuinely useful disambiguation, but it does not say whether relative paths are resolved from cwd or how a directory is located/disambiguated.
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 and resource ("Check the .dockerignore") and enumerates exactly the four classes of problem it detects: missing file, missing .git/node_modules/.env exclusions, nested node_modules missed by root-anchored patterns, and patterns that exclude COPY'd files. This is clearly distinct from siblings like lint_dockerfile or dockerfile_overview, which operate on the Dockerfile itself.
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?
The description implies the context of use ("for a Dockerfile (or a directory)") and hints at the build-failure consequence that motivates running it, but it never states when to prefer this tool over lint_dockerfile or fix_preview, nor any prerequisites. Usage is inferable rather than directed.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
dockerfile_overviewA
Summarize a Dockerfile: stages with base images (tag/digest), layer count, exposed ports,
final user, workdir, and ENTRYPOINT/CMD (exec vs shell form). Start here to understand a file
before linting it. path is a Dockerfile or a directory containing one.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are supplied, so the description carries the full burden; it discloses that the operation is a read-only summarization over a local file and lists the specific artifacts returned, including the exec-vs-shell-form distinction. It does not discuss failure modes (e.g., path not found, file that is not a Dockerfile) or permission expectations, which is a modest gap for an inspection tool.
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?
Three sentences with a clean progression: what is produced, when to reach for it, then how to call it. The field enumeration is dense but every item listed is a distinct output the agent would otherwise have to discover, and nothing is redundant with the schema or annotations.
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 the description is not required to document return values, yet it usefully summarizes them anyway; the sole parameter is fully explained. The remaining gap is that it does not clarify how this differs from explain_layers, the closest sibling, which an agent would have to infer.
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 coverage is 0% — the schema only declares `path` as a string with no description — so the sentence "`path` is a Dockerfile or a directory containing one" is genuinely load-bearing, telling the agent that a directory is acceptable and that discovery happens internally. It does not cover relative-vs-absolute resolution or symlink behavior, so not a perfect 5.
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 opens with a specific verb and resource ("Summarize a Dockerfile") and then enumerates exactly what is extracted: stages with base images, layer count, exposed ports, final user, workdir, and ENTRYPOINT/CMD with exec vs shell form. This is enough to distinguish it from lint_dockerfile, explain_layers, and suggest_multistage without opening any 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?
It gives explicit sequencing guidance: "Start here to understand a file before linting it," which positions it relative to lint_dockerfile as a prerequisite step. It does not explicitly say when to prefer explain_layers or suggest_multistage instead, so sibling differentiation is only partially covered.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
explain_layersA
Explain which Dockerfile instructions create image layers, with heuristic size hints (small/large and why), and list ORDER problems that invalidate the build cache or bloat the image (COPY . before dependency install, cleanup in a later layer, recursive chown after COPY, volatile build args before expensive steps). Sizes are estimates; nothing is built.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does meaningful work: 'Sizes are estimates' sets accuracy expectations and 'nothing is built' discloses that the tool is a safe, side-effect-free static analysis. It also enumerates the specific defect classes it reports, so the agent knows what the output covers; it does not discuss error behavior for a missing/invalid 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?
One dense sentence, front-loaded with the core purpose before the heuristic and order-problem details. The four-item parenthetical is long but each example earns its place by concretizing what 'ORDER problems' means; a brief split into two sentences would read slightly better.
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 described, and the description adequately covers scope, accuracy caveats, and defect classes for a single-input analysis tool. The remaining gap is practical: no indication of what 'path' should contain or what happens when it does not resolve to a Dockerfile.
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% for the single required parameter 'path', and the description never mentions it or says whether it points to a Dockerfile, a directory, or a build context. The one parameter the agent must supply is left entirely to inference, which is the opposite of compensating for the schema gap.
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 opens with a specific verb and resource: 'Explain which Dockerfile instructions create image layers,' and adds two concrete outputs (heuristic size hints and ORDER problems). That is clearly distinct from dockerfile_overview or lint_dockerfile in framing, but it never explicitly names an alternative, and 'list ORDER problems' overlaps enough with lint_dockerfile that an agent might hesitate between the two.
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 only implied: the listed pathologies (COPY . before dependency install, cleanup in a later layer, recursive chown after COPY, volatile build args) suggest when the tool is valuable, and 'nothing is built' signals a static-analysis context. There is no explicit when-to-use/when-not statement and no routing away from lint_dockerfile or fix_preview, so the agent must infer the choice.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
fix_previewA
Show a unified diff of the safe automatic fixes for a Dockerfile (add -y and --no-install-recommends to apt-get install, --no-cache-dir to pip, --no-cache to apk, apt -> apt-get, ADD -> COPY, shell-form CMD -> exec form, MAINTAINER -> LABEL, apt lists cleanup). Never writes the file: apply the diff yourself. Lists the findings that need manual changes.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations supplied, the description carries the full burden and mostly succeeds: it explicitly declares the tool is non-mutating ('Never writes the file') and describes exactly which transformations will appear in the diff. It also discloses a secondary output (findings that need manual changes), though it does not cover failure behavior, e.g. what happens if path does not exist or is not a Dockerfile.
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?
The non-mutation guarantee is stated up front and the fix list is compactly parenthesized. The enumeration is long but each item earns its place by telling the agent what the diff will contain; only slight tightening would improve it.
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?
For a single-argument tool with an output schema, the description covers purpose, mutation safety, and output nature (diff plus manual findings) adequately. The one material hole is the ambiguity of 'path', which is unaddressed in both schema and description.
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?
Only one parameter exists, 'path', and the schema gives it zero description coverage. The description never clarifies whether it is a path to a Dockerfile, to a directory, or to a compose/Dockerfile pair, so it adds no meaning beyond the bare schema field.
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 and resource: it shows a unified diff of safe automatic fixes for a Dockerfile, and enumerates the exact fix categories (apt-get flags, ADD->COPY, MAINTAINER->LABEL, etc.). The scope is unmistakable, but it never names or contrasts itself with the closest sibling, lint_dockerfile, which also reports Dockerfile problems.
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?
The description implies the workflow ('Never writes the file: apply the diff yourself') and hints at a two-stage process by saying it also lists findings needing manual changes. However, it gives no explicit when-to-use versus lint_dockerfile or when-not guidance, leaving the agent to infer that lint_dockerfile diagnoses and fix_preview produces a patch.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
lint_composeA
Lint a docker-compose / compose.yaml file (rule IDs DC2001-DC2014): unpinned or :latest
images, privileged, host network, docker.sock mounts, secrets in environment (values never
echoed), ports published on all interfaces, missing restart/healthcheck, depends_on without a
condition, broad bind mounts (/, home), obsolete version: key, and env_file paths that do not
exist. Uses yaml.safe_load only. Suppress with # dockerlint-ignore: DC2008 above a line or service.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does meaningful work: it states that secret values are never echoed, that parsing uses yaml.safe_load only (no execution risk), and that findings can be suppressed via a '# dockerlint-ignore: DCxxxx' comment. It does not describe failure behavior for a missing or unreadable path, which is the remaining gap.
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?
The verb and resource are front-loaded, and the long rule enumeration is genuinely scoping information rather than filler, followed by a compact suppression hint. It is dense but every clause carries content; only the rule list could arguably be trimmed.
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 explained, and the description covers safety posture, rule coverage, and suppression. What is missing is the meaning of the required 'path' argument and any error-handling note, which matters for a single-required-param tool.
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% — the single 'path' parameter has no description in the schema — and the tool description never clarifies it either. An agent cannot tell whether 'path' means the compose file itself or a directory to scan, nor whether relative or absolute paths are accepted, so the description fails to compensate for the coverage gap.
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 opens with a specific verb and resource ('Lint a docker-compose / compose.yaml file') and then enumerates the exact rule set (DC2001-DC2014) it applies. This makes it immediately distinguishable from the sibling 'lint_dockerfile', which targets a different artifact.
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?
The scope is clearly bounded to compose.yaml files and the enumerated checks tell an agent what situations the tool covers, so the choice versus lint_dockerfile is inferable from the resource named. It stops short of explicitly stating when not to use it or naming alternatives, which keeps it out of 5 territory.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
lint_dockerfileA
Lint a Dockerfile with 28 rules (IDs DL1001-DL1028). Each finding has a rule ID, severity
(error/warning/info), the line of the instruction, an explanation, and a concrete fix.
Covers unpinned/latest tags, apt/pip/apk/yum hygiene, root user, ADD vs COPY, COPY-before-install
cache busting, secrets in ENV/ARG/RUN (values are never echoed), curl|sh, HEALTHCHECK,
shell-form CMD/ENTRYPOINT, WORKDIR, sudo, chmod 777 and COPY of node_modules/.git.
Suppress with # dockerlint-ignore: DL1003 above an instruction. Never builds anything.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations supplied, the description carries the full burden and does well: it discloses 'Never builds anything' (a clear safety/read-only signal), that secret values are never echoed, and that findings include severity and a concrete fix. It stops short of stating failure modes, e.g. behavior on a missing/non-Dockerfile 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 purpose and scale, then a dense rule summary and the suppression mechanism. The long rule enumeration earns its place by telling the agent exactly what classes of findings to expect, though it could be trimmed slightly.
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 re-explained, and the description still summarizes finding structure (rule ID, severity, line, explanation, fix). Combined with the safety note and suppression syntax, an agent has everything needed except explicit `path` semantics.
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 coverage is 0% and the single `path` parameter is never described — it is ambiguous whether it expects a Dockerfile file path or a directory containing one. The verb 'Lint a Dockerfile' weakly implies a file path, so some meaning leaks through but not enough to compensate for the coverage gap.
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 and resource ('Lint a Dockerfile') plus concrete scope ('28 rules, DL1001-DL1028'), which cleanly separates it from the sibling lint_compose. An agent can identify this as the Dockerfile-specific linter without opening the 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?
Usage is implied by the resource name, and the description usefully documents the in-file suppression syntax (`# dockerlint-ignore: DL1003`). However, it never states when to prefer this over siblings like fix_preview or suggest_multistage, nor any prerequisites or exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
suggest_multistageA
Propose a multi-stage rewrite of a single-stage Dockerfile as TEXT (never writes a file). Recognizes common Python, Node, Go and Rust patterns and reuses your base image version, workdir, ports and CMD/ENTRYPOINT. Explains what moves to the build stage and why the final image shrinks.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full load and does well: it declares a non-mutating contract ('never writes a file'), describes what is preserved from the original (base image version, workdir, ports, CMD/ENTRYPOINT), and says it explains what moves to the build stage. It omits failure behavior for already-multi-stage or unrecognized files.
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?
Three sentences, front-loaded with the output contract, then capability, then value. Every sentence carries information; the ecosystem list is slightly padded but genuinely useful for deciding applicability.
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 explanation. For a one-parameter read-only tool the description covers scope, output form, and preserved settings; only edge-case behavior and the exact meaning of 'path' are missing.
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?
The single 'path' parameter has 0% schema description coverage, so the description should say it points to the Dockerfile to analyze. 'A single-stage Dockerfile' only weakly implies that; an agent could plausibly pass a directory path instead.
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 and resource ('Propose a multi-stage rewrite of a single-stage Dockerfile') and pins down the output form ('as TEXT, never writes a file'). It does not name a sibling to contrast with, so the agent must infer the boundary against fix_preview or lint_dockerfile on its own.
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?
The input constraint ('single-stage Dockerfile') implies when the tool applies, but there is no explicit when-not guidance, no prerequisite statement (e.g. file must exist and be readable), and no named alternative for already-multi-stage or non-Python/Node/Go/Rust files.
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.
7 tool updates
v0.1.0- First observed
check_dockerignore - First observed
dockerfile_overview - First observed
explain_layers - First observed
fix_preview - First observed
lint_compose - First observed
lint_dockerfile - First observed
suggest_multistage
TDQS
Scored across 7 tools
Each tool has a fairly distinct role: overview summarizes, lint_dockerfile reports rule findings, explain_layers focuses on layer/cache heuristics, fix_preview shows diffs. There is minor overlap between explain_layers' order/cache problems and lint_dockerfile's cache-busting rule, but descriptions clarify the split.
All tools use snake_case, which is consistent, but the ordering is mostly verb_noun (lint_dockerfile, check_dockerignore, fix_preview) with one noun_verb outlier (dockerfile_overview). Readable and predictable overall with a single minor deviation.
Seven tools is well-scoped for a Dockerfile/compose linting server, each covering a distinct artifact (Dockerfile, compose, dockerignore) or function (summarize, lint, explain, suggest, fix). No tool feels redundant or like padding.
The surface covers the full lint lifecycle for Dockerfiles plus compose and .dockerignore, with suggestions and fix previews but no write/apply by design. Minor gaps exist, such as no automatic fix suggestions for compose or dockerignore, but core workflows are covered.
Maintenance
Related MCP Connectors
Hadolint-grade Dockerfile audit — 19 checks: secrets, privileges, supply chain, hygiene.
Audit Dockerfiles for root users, baked-in secrets, curl-pipe-shell and unpinned base images.
Four IaC audits in one call: Compose, Dockerfile, GitHub Actions, Kubernetes. 131 checks.
30+ deterministic dev and delivery tools: linting, metrics, diagrams, model advice, AI-text checks.
Related MCP Servers
- AlicenseNot gradedqualityNot gradedmaintenanceEnables AI assistants to interact with Docker containers through safe, permission-controlled access to inspect, manage, and diagnose containers, images, and compose services with built-in timeouts and AI-powered analysis.-
- AlicenseAqualityAmaintenanceEnables AI assistants and developers to analyze code for language-specific best practices and idiomatic patterns across programming languages, CI automation, and configuration formats.162MIT
- AlicenseAqualityCmaintenanceEnables agents to validate Dockerfiles for build-breaking syntax errors, risky patterns like root users and secrets in ENV/ARG, and cache-order problems, returning every finding with its line and a fix. It also verifies referenced container images against public registries, reporting tag existence, digests to pin, supported platforms, last rebuild time, and end-of-life status with an upgrade tag.21MIT
- AlicenseNot gradedqualityCmaintenanceExposes 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