Build MCP server 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
thv build npx://@modelcontextprotocol/server-filesystem
# 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 in Kubernetes manifest
# spec:
#   image: mcp-servers/git-server:stable
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
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 want 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
permissionProfile:
type: builtin
name: network 
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 with ToolHive 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