How to Deploy the GitHub MCP Server Using Docker: Complete Setup Guide
Deploy the GitHub MCP server by running docker run -i --rm -e GITHUB_PERSONAL_ACCESS_TOKEN=YOUR_PAT -p 8082:8082 ghcr.io/github/github-mcp-server http --port 8082, which pulls the distroless image and starts the HTTP server on port 8082.
The GitHub MCP (Model Context Protocol) server enables AI assistants to interact with GitHub repositories through a standardized interface. Deploying via Docker provides an isolated, reproducible environment using the official multi-stage image hosted at ghcr.io/github/github-mcp-server. This guide covers the complete deployment process based on the actual source code structure from the github/github-mcp-server repository.
Docker Architecture and Build Process
The official Dockerfile implements a three-stage build that compiles both UI assets and the Go binary before deploying to a minimal runtime. Understanding this architecture helps troubleshoot deployment issues and optimize your configuration.
Multi-Stage Build Stages
ui-buildstage: Usesnode:20-alpineto build frontend assets with Vite, outputting topkg/github/ui_dist/buildstage: Usesgolang:1.25.7-alpineto compile the server binary with embedded version metadata vialdflags- Runtime stage: Deploys to
gcr.io/distroless/base-debian12, containing only the compiled binary at/server/github-mcp-server
The build process embeds version information directly into the binary:
CGO_ENABLED=0 go build \
-ldflags="-s -w -X main.version=${VERSION} \
-X main.commit=$(git rev-parse HEAD) \
-X main.date=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
-o /bin/github-mcp-server ./cmd/github-mcp-server
Key source files governing Docker behavior include:
cmd/github-mcp-server/main.go: Parses environment variables via Viper and routes tostdioorhttpsubcommandspkg/http/server.go: Implements the HTTP listener on0.0.0.0:8082Dockerfile: Defines the distroless runtime and exposes port 8082
Prerequisites
Before deploying the GitHub MCP server using Docker, ensure you have:
- Docker installed and running on your host system
- A GitHub Personal Access Token with at least the
reposcope (additional scopes required for specific toolsets like security or actions) - (Optional) Familiarity with MCP toolsets to customize which GitHub features are exposed
Deployment Methods
The container supports two primary execution modes controlled by subcommands in cmd/github-mcp-server/main.go.
HTTP Mode (Production)
For network-accessible deployments, use the http subcommand to expose the server on port 8082:
docker run -i --rm \
-e GITHUB_PERSONAL_ACCESS_TOKEN=YOUR_PAT \
-p 8082:8082 \
ghcr.io/github/github-mcp-server http \
--port 8082
Command breakdown:
-ikeeps STDIN open for JSON-RPC communication--rmremoves the container after stopping-e GITHUB_PERSONAL_ACCESS_TOKENpasses authentication to the server (read viaviper.GetString("personal_access_token"))-p 8082:8082maps the internal port to your hosthttpinvokes the HTTP server defined inpkg/http/server.go
stdio Mode (Local Development)
For local testing or integration with hosts expecting standard I/O communication:
docker run -i --rm \
-e GITHUB_PERSONAL_ACCESS_TOKEN=YOUR_PAT \
ghcr.io/github/github-mcp-server stdio
Since CMD ["stdio"] is the default entrypoint in the Dockerfile, you can omit the subcommand:
docker run -i --rm \
-e GITHUB_PERSONAL_ACCESS_TOKEN=YOUR_PAT \
ghcr.io/github/github-mcp-server
Configuration and Environment Variables
The server uses Viper for configuration management, mapping environment variables to command flags. Set these via -e flags in your docker run commands:
| Environment Variable | Purpose | Source Reference |
|---|---|---|
GITHUB_PERSONAL_ACCESS_TOKEN |
Authentication for GitHub API calls | main.go (initConfig) |
GITHUB_TOOLSETS |
Comma-separated list of enabled tools (default: context,repos,issues,pull_requests,users) |
main.go |
GITHUB_READ_ONLY |
Boolean to disable write operations | Flag parsing in main.go |
GITHUB_DYNAMIC_TOOLSETS |
Enables runtime toolset discovery tools | Tool configuration |
Example with custom toolsets and read-only mode:
docker run -i --rm \
-e GITHUB_PERSONAL_ACCESS_TOKEN=YOUR_PAT \
-e GITHUB_TOOLSETS="repos,issues,actions,code_security" \
-e GITHUB_READ_ONLY=true \
ghcr.io/github/github-mcp-server http
Docker Compose Configuration
For persistent deployments, use this docker-compose.yml structure:
version: "3.9"
services:
github-mcp-server:
image: ghcr.io/github/github-mcp-server
container_name: github-mcp-server
restart: unless-stopped
environment:
GITHUB_PERSONAL_ACCESS_TOKEN: ${GITHUB_PAT}
GITHUB_TOOLSETS: "repos,issues,pull_requests"
GITHUB_DYNAMIC_TOOLSETS: "true"
ports:
- "8082:8082"
command: http --port 8082
Start with: docker-compose up -d
Verifying Your Deployment
Confirm the server is running correctly by checking the embedded version metadata:
docker run -i --rm \
-e GITHUB_PERSONAL_ACCESS_TOKEN=YOUR_PAT \
ghcr.io/github/github-mcp-server --version
Expected output includes the version, commit SHA, and build date injected during the Docker build process:
Version: dev
Commit: a1b2c3d4...
Build Date: 2024-07-30T12:34:56Z
For HTTP mode, verify connectivity by checking port 8082 responds to MCP protocol requests.
Summary
- The GitHub MCP server is distributed as a multi-stage Docker image at
ghcr.io/github/github-mcp-serverusing a distroless runtime for security - Authentication requires setting the
GITHUB_PERSONAL_ACCESS_TOKENenvironment variable parsed by Viper incmd/github-mcp-server/main.go - Two execution modes exist:
stdiofor local JSON-RPC over standard I/O (default), andhttpfor network-accessible deployments on port 8082 - Configuration happens via environment variables that map to Cobra flags, including toolset selection and read-only restrictions
- The Dockerfile embeds build metadata via Go ldflags and deploys to
gcr.io/distroless/base-debian12to minimize attack surface
Frequently Asked Questions
What is the difference between stdio and http modes in the GitHub MCP server?
stdio mode runs the server over standard input/output using JSON-RPC, which is ideal for local development and integration with VS Code or other editors that spawn the container as a subprocess. http mode exposes the server as a web service on port 8082 (defined in pkg/http/server.go), making it suitable for remote deployments or microservice architectures where the MCP client connects over TCP/IP.
How do I securely handle the GitHub Personal Access Token in Docker?
Never hardcode your PAT in docker run commands stored in shell history. Instead, use Docker secrets, environment files, or your shell's variable substitution (e.g., -e GITHUB_PERSONAL_ACCESS_TOKEN=$GITHUB_PAT). For Docker Compose, reference the variable in your .env file and ensure the file has restricted permissions (0600). The token is read by the Viper configuration in cmd/github-mcp-server/main.go and passed to the GitHub API client.
Can I customize which GitHub tools are available in the container?
Yes. Set the GITHUB_TOOLSETS environment variable to a comma-separated list of enabled categories. Available toolsets include context, repos, issues, pull_requests, users, actions, and code_security. This configuration is parsed in the initConfig function of main.go and controls which handlers are registered in the server. You can also enable GITHUB_DYNAMIC_TOOLSETS=true to expose helper tools that list available capabilities at runtime.
Why does the Docker image use a distroless base?
The distroless image (gcr.io/distroless/base-debian12) contains only the Go runtime and the compiled github-mcp-server binary, removing package managers, shells, and unnecessary system libraries. This significantly reduces the attack surface and image size compared to Alpine or Debian bases. As defined in the Dockerfile, the final stage copies only the binary to /server/github-mcp-server and sets it as the entrypoint, ensuring the container runs with minimal privileges.
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 →