Skip to content

Conversation

@danbarr
Copy link
Collaborator

@danbarr danbarr commented Nov 18, 2025

Summary

Adds support for baking required CLI arguments into container ENTRYPOINTs at build time, addressing Dockyard issue #189.

Some MCP servers (like LaunchDarkly) require specific subcommands that must always be present. This feature allows those arguments to be embedded in the container image, preventing users from accidentally overwriting them.

Note: This PR implements the ToolHive side of the feature. Once released, Dockyard will need to be updated to pass spec.args to BuildFromProtocolSchemeWithName (see stacklok/dockyard#189).

Changes

  • Added buildArgs []string parameter to BuildFromProtocolSchemeWithName and createTemplateData
  • Updated all three transport templates (NPX, UVX, GO) to include buildArgs before "$@"
  • Enhanced thv build CLI to accept -- <args> syntax for baking arguments
  • Added comprehensive test coverage at both template and protocol levels

Examples

# Bake "start" subcommand into container
thv build npx://@launchdarkly/mcp-server -- start

# Multiple build arguments
thv build uvx://package -- --transport stdio

# Runtime args still append after baked-in args
thv run my-image -- --verbose
# Executes: npx @launchdarkly/mcp-server start --verbose

Implementation Details

  • BuildArgs are semantically distinct from runtime args (required subcommands vs optional flags)
  • All existing callers pass nil for backward compatibility
  • Templates insert buildArgs before "$@" so runtime args append naturally
  • Works consistently across all three transport types (NPX, UVX, GO)

Testing

  • ✅ All unit tests passing
  • ✅ All linting passing
  • ✅ Comprehensive test coverage added for new functionality

Next Steps

This enables Dockyard to pass spec.args to the build system for servers requiring specific subcommands.

- Add BuildArgs field to TemplateData struct for baking required CLI
  arguments into container ENTRYPOINT at build time
- Update npx.tmpl to insert BuildArgs before "$@"
- Update uvx.tmpl to insert BuildArgs before "$@"
- Update go.tmpl to insert BuildArgs in JSON array format

BuildArgs are for required subcommands (e.g., 'start') while runtime
args passed via '-- <args>' append after. This prevents duplication
issues that led to MCPArgs removal in PR #2630.

Related to: stacklok/dockyard#189
- Add buildArgs []string parameter to BuildFromProtocolSchemeWithName
- Update createTemplateData to accept and use buildArgs
- Update HandleProtocolScheme to pass nil for buildArgs
- Update thv build command callers to pass nil for buildArgs

Existing callers pass nil to maintain backward compatibility.
Fixed extra quote in ENTRYPOINT template that was causing test failures.
The template now correctly generates:
- Empty buildArgs: ENTRYPOINT ["/app/mcp-server"]
- With buildArgs: ENTRYPOINT ["/app/mcp-server", "arg1", "arg2"]
Added test cases for all three transport types (NPX, UVX, GO) that
exercise the BuildArgs feature:
- NPX with single arg (start)
- UVX with multiple args (--transport stdio)
- GO with multiple args (serve --verbose)

All tests verify that BuildArgs are correctly baked into the ENTRYPOINT.
Users can now bake required arguments into containers at build time:
  $ thv build npx://@launchdarkly/mcp-server -- start
  $ thv build uvx://package -- --transport stdio

This provides:
- Consistency with 'thv run -- <args>' syntax
- Easy local testing of build args before using in Dockyard
- Arguments are baked into ENTRYPOINT, not overridable at runtime

Examples:
- NPX: exec npx package start "$@"
- UVX: exec package "--transport" "stdio"
- GO: ENTRYPOINT ["/app/mcp-server", "serve", "--verbose"]

Related to: stacklok/dockyard#189
- Updated TestTemplateDataWithLocalPath to include BuildArgs field
- Added TestCreateTemplateData with 5 test cases covering:
  * NPX with single buildArg
  * UVX with multiple buildArgs
  * GO with buildArgs
  * GO local path with buildArgs
  * NPX without buildArgs (backward compatibility)

All tests verify that buildArgs flow correctly through the
createTemplateData function and are properly set in TemplateData.
- Broke up long line in build.go (BuildFromProtocolSchemeWithName call)
- Broke up long function signature in protocol.go (createTemplateData)

Both lines now conform to 130 character limit.
Signed-off-by: Dan Barr <[email protected]>
@codecov
Copy link

codecov bot commented Nov 18, 2025

Codecov Report

❌ Patch coverage is 75.00000% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 55.57%. Comparing base (832c968) to head (f4f7c6c).

Files with missing lines Patch % Lines
pkg/runner/protocol.go 75.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2631      +/-   ##
==========================================
+ Coverage   55.47%   55.57%   +0.10%     
==========================================
  Files         312      312              
  Lines       29714    29715       +1     
==========================================
+ Hits        16483    16515      +32     
+ Misses      11791    11758      -33     
- Partials     1440     1442       +2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@JAORMX
Copy link
Collaborator

JAORMX commented Nov 19, 2025

@claude do a thorough review of this

@claude
Copy link
Contributor

claude bot commented Nov 19, 2025

Claude encountered an error —— View job


I'll analyze this and get back to you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants