Build MCP containers
This guide explains how to use the thv build
command to build MCP server containers from protocol schemes without running
them. This is useful for pre-building containers for Kubernetes deployments,
CI/CD pipelines, and container registry workflows.
Overview
The thv build command allows you to build containers from protocol schemes
(uvx://, npx://, go://) without immediately running them. This provides
several benefits:
- Pre-build containers for faster deployment in Kubernetes environments
- Separate build and run phases in CI/CD pipelines
- Custom image tagging for container registry workflows
- Dockerfile generation for inspection and customization
- Build validation before deployment
Basic usage
To build a container from a protocol scheme:
thv build <PROTOCOL_SCHEME>
For example:
# Build a Python MCP server using uvx
thv build uvx://mcp-server-git
# Build a Node.js MCP server using npx with a pinned version
thv build npx://@upstash/context7-mcp@1.0.26
# Build a Go MCP server
thv build go://github.com/example/my-mcp-server@latest
When you run thv build, ToolHive:
- Detects the protocol scheme and extracts the package reference
- Generates a Dockerfile based on the appropriate template
- Builds a Docker image with the package installed
- Tags the image with an auto-generated name or your custom tag
- Displays the built image name for use with other tools
Custom image tagging
Use the --tag (or -t) flag to specify a custom name and tag for the built
image:
thv build --tag my-custom-name:latest npx://@modelcontextprotocol/server-filesystem
This is particularly useful for:
- Container registries: Tag images for pushing to registries
- Kubernetes deployments: Use predictable image names in manifests
- Version management: Tag images with specific versions
Tagging examples
- Container registry
- Kubernetes
- Version management
Build and tag for pushing to a container registry:
# Build and tag for Docker Hub
thv build --tag myusername/mcp-git-server:v1.0.0 uvx://mcp-server-git
# Build and tag for GitHub Container Registry
thv build --tag ghcr.io/myorg/mcp-filesystem:latest npx://@modelcontextprotocol/server-filesystem
# Push to registry
docker push ghcr.io/myorg/mcp-filesystem:latest
Build images with predictable names for Kubernetes manifests:
# Build with a consistent tag
thv build --tag mcp-servers/git-server:stable uvx://mcp-server-git
Use the built image in your Kubernetes manifests:
apiVersion: toolhive.stacklok.dev/v1alpha1
kind: MCPServer
metadata:
name: git-server
namespace: production
spec:
image: mcp-servers/git-server:stable
# ... other spec fields ...
Build multiple versions of the same server:
# Build different versions
thv build --tag mcp-git:v1.0.0 uvx://mcp-server-git@1.0.0
thv build --tag mcp-git:v1.1.0 uvx://mcp-server-git@1.1.0
thv build --tag mcp-git:latest uvx://mcp-server-git@latest
Protocol schemes
The thv build command supports the same protocol schemes as
thv run:
Python (uvx)
Build Python-based MCP servers using the uv package manager:
# Build with auto-generated name
thv build uvx://mcp-server-git
# Build with custom tag
thv build --tag my-git-server:latest uvx://mcp-server-git@1.2.0
Node.js (npx)
Build Node.js-based MCP servers using npm:
# Build with auto-generated name
thv build npx://@modelcontextprotocol/server-filesystem
# Build with custom tag
thv build --tag filesystem-server:v2.0 npx://@modelcontextprotocol/server-filesystem@2.0.0
Go
Build Go-based MCP servers:
# Build from remote Go module
thv build --tag grafana-mcp:latest go://github.com/grafana/mcp-grafana/cmd/mcp-grafana@latest
# Build from local Go project
thv build --tag my-local-server:dev go://./cmd/my-mcp-server
Build-time arguments
Some MCP servers require specific subcommands or arguments that must always be
present. You can bake these required arguments directly into the container image
at build time using the -- separator at the end of the thv build command:
thv build <PROTOCOL_SCHEME> -- <BUILD_ARGS>
- Build-time arguments: Baked into the container image and always present. These are typically required subcommands or essential configuration flags.
- Runtime arguments: Passed when running the container and appended after build-time arguments. These are typically optional flags or dynamic configuration.
Build-time arguments are embedded in the container's ENTRYPOINT and always
execute before any runtime arguments. For example, the LaunchDarkly MCP server
requires a start subcommand:
# Bake "start" subcommand into container
thv build --tag launchdarkly-mcp:latest npx://@launchdarkly/mcp-server -- start
# Runtime args still append after baked-in args
thv run launchdarkly-mcp:latest -- --verbose
# Executes: npx @launchdarkly/mcp-server start --verbose
You can include multiple build-time arguments as needed:
thv build uvx://my-package -- --transport stdio --log-level info
Dockerfile generation
Use the --dry-run flag to generate the Dockerfile without building the image:
# Output Dockerfile to stdout
thv build --dry-run uvx://mcp-server-git
# Save Dockerfile to a file
thv build --dry-run --output Dockerfile.mcp-git uvx://mcp-server-git
This is useful for:
- Inspecting the build process before building
- Customizing Dockerfiles for specific requirements
- Understanding dependencies and build steps
- Debugging build issues
Example Dockerfile output
# Generated by: thv build --dry-run uvx://mcp-server-git
FROM python:3.12-slim
# Install uv
RUN pip install uv
# Install the package
RUN uv tool install mcp-server-git
# Set the entrypoint
ENTRYPOINT ["uv", "tool", "run", "mcp-server-git"]
Kubernetes workflows
The thv build command is especially useful for Kubernetes deployments where
you need to pre-build containers before deploying them.
Pre-build workflow
-
Build the container with a specific tag:
thv build --tag ghcr.io/myorg/mcp-git:v1.0.0 uvx://mcp-server-git@1.0.0 -
Push to container registry:
docker push ghcr.io/myorg/mcp-git:v1.0.0 -
Deploy to Kubernetes using the pre-built image:
apiVersion: toolhive.stacklok.dev/v1alpha1
kind: MCPServer
metadata:
name: git-server
namespace: production
spec:
image: ghcr.io/myorg/mcp-git:v1.0.0
transport: stdio
CI/CD integration
Integrate thv build into your CI/CD pipeline for automated container building:
# Example GitHub Actions workflow
name: Build and Deploy MCP Server
on:
push:
tags: ['v*']
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install ToolHive
uses: StacklokLabs/toolhive-actions/install@v0
with:
version: latest
- name: Log in to Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build MCP server
run: |
thv build --tag ghcr.io/${{ github.repository }}/mcp-server:${{ github.ref_name }} \
uvx://mcp-server-git@${{ github.ref_name }}
- name: Push to registry
run: |
docker push ghcr.io/${{ github.repository }}/mcp-server:${{ github.ref_name }}
For more advanced CI/CD patterns including multi-architecture builds, supply chain security, and change detection, see the Advanced CI/CD patterns guide.
Advanced usage
Build with custom CA certificates
For corporate environments with custom certificate authorities:
# Use global CA certificate configuration
thv config set-ca-cert /path/to/corporate-ca.crt
thv build uvx://internal-mcp-server
# Override CA certificate for specific build
thv build --ca-cert /path/to/special-ca.crt uvx://special-server
Build local Go projects
Build MCP servers from local Go projects:
# Build from current directory
cd my-go-mcp-project
thv build --tag my-server:dev go://.
# Build from relative path
thv build --tag my-server:dev go://./cmd/server
# Build from absolute path
thv build --tag my-server:dev go:///path/to/my-project
Comparison with thv run
| Feature | thv build | thv run |
|---|---|---|
| Purpose | Build containers only | Build and run containers |
| Output | Container image | Running MCP server |
| Use case | Pre-building, CI/CD | Development, testing |
| Kubernetes | Pre-build for deployment | Direct development |
| Custom tagging | ✅ --tag flag | ❌ Auto-generated names |
| Dockerfile generation | ✅ --dry-run flag | ❌ Not available |
Next steps
- Use built containers with
thv runfor local development - Deploy pre-built containers to Kubernetes
- Set up CI/CD pipelines for automated building
- Learn about container registry workflows
Related information
Troubleshooting
Build fails with network errors
If builds fail with network connectivity issues:
- Check internet connectivity for downloading packages
- Configure CA certificates for corporate environments:
thv config set-ca-cert /path/to/corporate-ca.crt - Use proxy settings if required by your network
- Verify package names and versions exist in the respective registries
Invalid image tag format
If you get image tag validation errors:
- Use valid Docker image tag format:
name:tagorregistry/name:tag - Avoid special characters except hyphens, underscores, and dots
- Use lowercase names for compatibility
- Check tag length limits (typically 128 characters)
Example valid tags:
thv build --tag my-server:latest uvx://package
thv build --tag ghcr.io/org/server:v1.0.0 npx://package
Package not found errors
If the build fails because a package cannot be found:
-
Verify package exists in the respective registry:
-
Check version specifiers:
# Correct version formats
thv build uvx://package@1.0.0
thv build npx://package@latest
thv build go://github.com/user/repo@v1.0.0 -
For Go modules, ensure the path includes the correct import path