Publishing MCP Servers to GitHub Container Registry: A Complete Guide
You can publish MCP servers to GitHub Container Registry (GHCR) by building a multi-stage Docker image, configuring a GitHub Actions workflow to automate the build and push process, and then referencing the resulting image in your MCP client configuration.
Publishing MCP servers to GitHub Container Registry enables seamless distribution and deployment of containerized Model Context Protocol implementations. The cr2007/mcp-wordle-python repository demonstrates this pattern by packaging a FastMCP server that exposes Wordle solutions into a lightweight Docker image hosted on GHCR. This guide walks through the architecture, manual and automated publishing workflows, and client configuration required to implement this pattern in your own MCP projects.
Understanding the MCP Server Architecture
The Wordle MCP server follows a layered architecture that separates the MCP protocol handling from business logic and external API communication.
Core Components
FastMCP Server Layer
The server initialization occurs in src/mcp_wordle/main.py where FastMCP("WordleMCP") creates the protocol handler. The get_wordle_data function is decorated with @mcp.tool() to register it as an available tool. When mcp.run() executes, FastMCP manages the stdio transport, request parsing, and response serialization.
Wordle API Client
The same file contains the API interaction logic. The function constructs a URL targeting https://www.nytimes.com/svc/wordle/v2/{target_date}.json and executes requests.get(url, timeout=300).json(). The date parameter defaults to the current ISO format date if not specified.
Dependency Management
The pyproject.toml file declares fastmcp>=2.9.2 and requests>=2.32.4 as dependencies. The project uses uv as its package manager, with uv.lock ensuring deterministic builds across environments.
Container Build Strategy
The Dockerfile implements a multi-stage build to minimize the final image size while maintaining build reproducibility.
Builder Stage
Based on ghcr.io/astral-sh/uv:0.7-python3.10-bookworm-slim, this stage:
- Copies
pyproject.tomlanduv.lock - Executes
uv sync --frozen --no-cache --compile-bytecodeto create a virtual environment with compiled Python bytecode - Copies the source code from
src/mcp_wordle/
Final Stage
Based on python:3.10-slim-bookworm, this stage:
- Copies the pre-built virtual environment from the builder
- Sets
ENTRYPOINT ["mcp-wordle"]to launch the server immediately on container start
This approach yields an image that contains only the Python runtime and the application code, excluding build tools and caches.
How to Publish MCP Servers to GitHub Container Registry
Publishing requires either manual intervention for testing or automated workflows for continuous deployment.
Prerequisites
Before publishing, ensure you have:
- A GitHub repository with a working
Dockerfileat the root - The
GITHUB_TOKENsecret available in your repository (enabled by default) - For local testing: Docker Buildx installed (
docker buildx create --use)
Manual Build and Push
For testing or one-off releases, build and push manually:
# Enable Buildx for multi-platform support
docker buildx create --use
# Build and push multi-architecture image
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t ghcr.io/USERNAME/mcp-server-name:latest \
--push .
Replace USERNAME with your GitHub username and mcp-server-name with your repository name. The --push flag uploads directly to GHCR.
Verify the upload:
docker pull ghcr.io/USERNAME/mcp-server-name:latest
docker run --rm ghcr.io/USERNAME/mcp-server-name:latest --help
Automated Publishing with GitHub Actions
The repository includes .github/workflows/publish-image.yml to automate publishing. The workflow triggers on pushes to master that modify build-related files:
on:
push:
branches: [master]
paths:
- 'uv.lock'
- 'pyproject.toml'
- 'Dockerfile'
- 'src/**'
- '.github/workflows/publish-image.yml'
The workflow steps:
- Checkout the repository
- Set up QEMU for cross-platform builds
- Set up Docker Buildx
- Login to GHCR using
${{ secrets.GITHUB_TOKEN }} - Build and push multi-platform images (
linux/amd64,linux/arm64) with thelatesttag
This ensures that any code change automatically produces an updated container image available at ghcr.io/cr2007/mcp-wordle-python:latest.
Configuring MCP Clients to Use GHCR Images
Once published, configure MCP-compatible clients to invoke the containerized server.
Docker-based Configuration
For Claude Desktop or similar clients, add this server configuration:
{
"mcpServers": {
"Wordle MCP (Python)": {
"command": "docker",
"args": [
"run",
"--rm",
"-i",
"--init",
"-e",
"DOCKER_CONTAINER=true",
"ghcr.io/cr2007/mcp-wordle-python:latest"
]
}
}
}
The flags ensure:
--rm: Container cleans up after exit-i: Interactive mode for stdio transport--init: Proper signal handling-e DOCKER_CONTAINER=true: Environment flag used by the application logic
Alternative uvx Installation
For environments where Docker is unavailable, use uvx to run directly from the repository:
{
"mcpServers": {
"Wordle MCP (Python)": {
"command": "uvx",
"args": [
"--from",
"git+https://github.com/cr2007/mcp-wordle-python",
"mcp-wordle"
]
}
}
}
uvx handles dependency resolution and virtual environment creation automatically, pulling the code from GitHub and executing the mcp-wordle entrypoint defined in pyproject.toml.
Summary
Publishing MCP servers to GitHub Container Registry streamlines distribution and ensures consistent runtime environments across different client implementations.
- Multi-stage Docker builds using
uvproduce minimal, secure images containing only the Python runtime and compiled application code - GitHub Actions automation in
.github/workflows/publish-image.ymlhandles multi-platform builds (linux/amd64,linux/arm64) and pushes to GHCR on every relevant code change - Client configuration requires only a JSON snippet specifying the
docker runcommand with the GHCR image URL, enabling immediate integration with Claude Desktop and other MCP clients - Alternative deployment via
uvxprovides a container-free option for development or resource-constrained environments
Frequently Asked Questions
How do I authenticate to GitHub Container Registry for manual pushes?
GitHub Container Registry uses the same authentication as Docker Hub but requires a GitHub Personal Access Token (PAT) with write:packages and read:packages scopes. Generate a token in your GitHub Settings under Developer settings > Personal access tokens > Tokens (classic). Then login using echo $CR_PAT | docker login ghcr.io -u USERNAME --password-stdin where $CR_PAT is your token. The GitHub Actions workflow uses the built-in GITHUB_TOKEN secret automatically, so no manual authentication is required for automated builds.
Why does the Dockerfile use a multi-stage build with uv instead of pip?
The multi-stage build strategy minimizes the final image size and attack surface by excluding build tools and caches from the runtime environment. The builder stage uses ghcr.io/astral-sh/uv:0.7-python3.10-bookworm-slim to install dependencies via uv sync --frozen --no-cache --compile-bytecode, which creates a deterministic virtual environment with pre-compiled Python bytecode. The final stage copies only this virtual environment into a slim python:3.10-slim-bookworm base image, resulting in a container that contains only the Python runtime and application code without uv, pip, or build dependencies.
How do I troubleshoot a container that exits immediately when run by an MCP client?
If the container exits immediately when invoked by an MCP client like Claude Desktop, check three common configuration issues. First, ensure the client configuration includes the -i (interactive) flag, as MCP servers communicate over stdio and require an interactive TTY to function. Second, verify that the --init flag is present to ensure proper signal handling, preventing zombie processes when the client terminates the connection. Third, check that the image tag is correct and accessible by running docker pull ghcr.io/USERNAME/IMAGE:latest manually to confirm the image exists and your Docker daemon has authentication to access GHCR.
Can I run the MCP server without Docker using the published GHCR image?
No, the GHCR image is specifically a Docker container image and requires a container runtime such as Docker, Podman, or containerd to execute. However, the repository provides an alternative installation method using uvx that achieves similar convenience without containerization. The uvx command fetches the source code directly from GitHub, creates a temporary virtual environment with all dependencies, and executes the mcp-wordle entrypoint defined in pyproject.toml. This method is ideal for development environments or systems where running Docker containers is impractical, though it requires the uv tool to be installed locally.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →