stacklok / stacklok/toolhive

Support forcing transitive dependency versions in protocol-scheme builds

Open
#6,209 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

enhancement needs-triage
Dominant language
Go
Stars
2.2k
Forks
300
Avg merge
1d 15h
Merged PRs (30d)
184

Description

Problem

--build-with (#6116) constrains a transitive dependency that upstream leaves unbounded. That is its design: it maps to uv tool install --with '<spec>', an additive requirement the resolver must satisfy alongside what upstream declared.

It structurally cannot help when upstream pins or caps the vulnerable dependency, because no satisfiable version is left to ask for. fastmcp>=3.2.0 alongside upstream's fastmcp<3.0.0 is an unsatisfiable set, so the resolver errors instead of resolving our way. Beating a pin or a cap needs a force override, a different mechanism.

Real examples of the shape, from dockyard#668: @brightdata/mcp 2.9.5 hard-pins @modelcontextprotocol/sdk at 1.21.2 (fixes are >=1.24); mcp-clickhouse 0.3.0 caps fastmcp<3.0.0 (the CRITICAL fix is 3.2.0); mcp-neo4j-cypher 0.6.0 caps fastmcp<2.14 (all fixes excluded).

This is also why npx:// has no build-time dependency support at all. npm resolves each parent's range independently and nests a private copy, so there is no additive analogue of --with to add: installing @modelcontextprotocol/sdk@1.26.0 at the top level of the generated package.json leaves @brightdata/mcp's pinned 1.21.2 in node_modules/@brightdata/mcp/node_modules/. Overrides is npm's only lever, and it happens to cover both the pin and the cap case.

Sketch

A RuntimeConfig.BuildOverrides []string field with a --build-override flag on thv build and thv run, meaning "force this version wherever it appears in the tree". --build-with unchanged. Entries in each ecosystem's native syntax, matching the existing "interpreted per package ecosystem" convention:

  • npx: @modelcontextprotocol/sdk@1.26.0, split into name + range to become an overrides object in the package.json generated at npx.tmpl:56. npm honors overrides only from the root manifest and only if present before npm install, so that RUN echo ... > package.json line is the injection point, not the install line.
  • uvx: fastmcp>=3.2.0, written as lines of a requirements file passed to uv tool install --overrides <file> (verified present, and composable with the existing --with).
  • go: reject, as --build-with does today.

Validation needs a wider allowlist than buildWithPattern to cover npm syntax (@, /, ^, |) while still excluding anything that could escape a single-quoted shell word or a JSON string literal.

Status

Not scheduled, and there is no current consumer: dockyard is implementing native override support on its own side (dockyard#669), which supersedes its use of --build-with as well. Filing to record the finding so the next person hitting a pinned or capped transitive dep does not rediscover why --build-with will not fix it. Revisit if demand appears outside dockyard.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with RuntimeConfig, the --build-with flag handling for thv build and thv run, npx.tmpl:56, and buildWithPattern. Trace how each ecosystem's build dependencies are generated, then define the override injection and validation points described for npx and uvx while preserving Go's rejection behavior. Done means the flags, generated manifests or requirements, and safety validation support the stated override syntax.

Written by the indexing model from the issue text.

Assessment

Tech stack
go, node.js
Domain
build-system, cli
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.