Skip to content

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

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 request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions