Skip to content

feat(dockhand): support transitive dependency overrides/constraints in spec.yaml #668

@JAORMX

Description

@JAORMX

Problem

Renovate version bumps for MCP servers fail the build-containers Grype gate (--fail-on high --only-fixed) when the bumped package pins or caps a transitive dependency to a vulnerable version, and we have no way to override that pin from within dockyard. Three open PRs are blocked on exactly this:

PR Package Vulnerable transitive dep Why we can't fix it Worst
#469 @brightdata/mcp 2.9.5 @modelcontextprotocol/sdk hard-pinned 1.21.2 package pins exact version; fixes are ≥1.24 3× HIGH
#527 mcp-clickhouse 0.3.0 fastmcp capped <3.0.0 CRITICAL fix is fastmcp 3.2.0, excluded by cap CVE-2026-32871 (Critical)
#528 mcp-neo4j-cypher 0.6.0 fastmcp capped <2.14 all fixes (2.14.x / 3.2.0) excluded by cap Critical + 3 HIGH

(Note #527 and #528 are also regressions vs. what main currently ships — see those PRs.)

Proposal

Add an optional dependency-override mechanism to the spec.yaml schema, plumbed into the generated Dockerfile:

spec:
  package: "@brightdata/mcp"
  version: "2.9.5"
  overrides:                                  # npx → npm "overrides"
    "@modelcontextprotocol/sdk": "1.26.0"
spec:
  package: "mcp-clickhouse"
  version: "0.3.0"
  constraints:                                # uvx → uv "--override" / constraints file
    - "fastmcp>=3.2.0"

Implementation sketch

  • Extend MCPServerPackageSpec (cmd/dockhand/main.go:43) with Overrides map[string]string (npx) and/or Constraints []string (uvx).
  • generateDockerfile (cmd/dockhand/main.go:354) already receives the Dockerfile as a string from toolhive's BuildFromProtocolSchemeWithName(..., dryRun=true). Post-process that string to inject the override:
    • npx: emit a package.json containing an overrides block before the npm install --save <pkg> step (npm honors overrides only from package.json).
    • uvx: add --override <constraints-file> (or per-spec --override pkg>=ver) to the uv tool install step.
  • Require every override entry to carry a short justification (mirroring security.allowed_issues) so the why is auditable in-repo.

Verification (already done manually)

A throwaway test of each override was run against the exact build recipe + the same Grype gate:

Acceptance

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestneeds-triageIssue needs initial triage by a maintainer

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions