An example MCP (Model Context Protocol) server demonstrating GitHub OAuth authentication using the FastMCP framework. This project showcases how to build, package, and containerize an authenticated MCP server using modern Python tooling with uv and GoReleaser's wheel-based Docker builds.
- GitHub OAuth 2.0 authentication
- HTTP-streamable MCP server
- Protected tools that use GitHub user data
- Modern Python packaging with uv
- Docker containerization with multi-arch support
- Automated releases with GoReleaser using pre-built wheels
- Health monitoring and logging
- Development and production ready
┌─────────────────┐ ┌──────────────────────┐ ┌─────────────────┐
│ MCP Client │◄──►│ FastMCP Server │◄──►│ GitHub OAuth │
│ │ │ (Containerized) │ │ │
└─────────────────┘ └──────────────────────┘ └─────────────────┘
│
┌─────▼─────┐
│ Docker │
│ Runtime │
│ │
│ Built by │
│GoReleaser │
│+ uv wheel │
└───────────┘
This project uses a modern build pipeline:
- uv builds Python wheel from source
- GoReleaser uses the wheel in Docker build context
- Dockerfile installs the pre-built wheel (no compilation in container)
- Multi-arch images built automatically for AMD64 and ARM64
- Python 3.11+
- uv (Python package manager)
- Docker (for containerization)
- GitHub account for OAuth app registration
- Go to GitHub Settings > Developer settings > OAuth Apps
- Create a new OAuth App with:
- Application name:
FastMCP OAuth Example - Homepage URL:
http://localhost:8000 - Authorization callback URL:
http://localhost:8000/auth/callback
- Application name:
- Note your Client ID and Client Secret
# Clone the repository
git clone <repository-url>
cd fastmcp-github-oauth-example
# Install dependencies
uv sync
# Configure environment
cp .env.example .env
# Edit .env with your GitHub OAuth credentials
# Run the server (loads environment from .env)
uv run --env-file .env github-oauth-server# Pull and run the published image
docker run -d \
-p 8000:8000 \
-e GITHUB_CLIENT_ID=your_client_id \
-e GITHUB_CLIENT_SECRET=your_client_secret \
-e BASE_URL=http://localhost:8000 \
--name fastmcp-server \
ghcr.io/YOUR_ORG/fastmcp-github-oauth-example:<architecture-tag># Check health
curl http://localhost:8000/health
# Check MCP endpoint
curl http://localhost:8000/mcp/
# View server logs
docker logs fastmcp-serverThe server exposes these protected tools (require GitHub authentication):
get_user_info: Returns authenticated user's GitHub profile informationget_server_info: Returns information about the MCP server and buildget_oauth_status: Returns OAuth authentication status and configurationping: Simple connectivity test
- Client connects to MCP server at
http://localhost:8000/mcp/ - Server responds with 401 and OAuth discovery information
- Client opens browser for GitHub authentication
- User grants permissions to the OAuth app
- GitHub redirects to server callback with authorization code
- Server exchanges code for access token
- Client uses token for subsequent MCP requests
The easiest way to test the server is using the MCP Inspector:
# Start the MCP server (in one terminal)
uv run --env-file .env github-oauth-server
# Test with MCP Inspector (in another terminal)
npx @modelcontextprotocol/inspector@latest http://localhost:8000/mcp/The MCP Inspector will:
- Open a web interface for testing MCP servers
- Handle the GitHub OAuth flow automatically
- Allow you to test all available tools interactively
- Show request/response details for debugging
Using the MCP Inspector, you can test each tool:
- get_user_info: View your GitHub profile data
- get_server_info: Check server configuration and build info
- get_oauth_status: Verify authentication status
- ping: Test basic connectivity
fastmcp-github-oauth-example/
├── src/fastmcp_github_oauth_example/
│ ├── __init__.py # Package initialization
│ └── server.py # Main server implementation
├── .github/workflows/ # CI/CD workflows
├── Dockerfile # Container definition (uses pre-built wheel)
├── .goreleaser.yaml # Release configuration (builds wheel)
├── docker-compose.yml # Development setup
├── pyproject.toml # Python project config
└── README.md # This file
- Python Wheel Build: GoReleaser uses
uvto build the wheel - Docker Context: GoReleaser provides the wheel in the Docker build context
- Container Build: Dockerfile copies and installs the pre-built wheel
- No Compilation: No source compilation happens inside the container
# Install development dependencies
uv sync --group dev
# Run with auto-reload (development)
uv run --env-file .env python -m fastmcp_github_oauth_example.server
# Format code
uv run black src/
# Lint code
uv run ruff check src/
# Build package
uv build
# Test GoReleaser build (no Docker push)
GITHUB_REPOSITORY_OWNER=YOUR_ORG goreleaser build --snapshot --clean# Run linting and formatting checks
uv run ruff check src/
uv run black --check src/
# Test server import
uv run python -c "from fastmcp_github_oauth_example import create_server"
# Test GoReleaser snapshot build
GITHUB_REPOSITORY_OWNER=YOUR_ORG goreleaser release --snapshot --cleanPre-built multi-architecture images are available:
# Latest release
docker pull ghcr.io/YOUR_ORG/fastmcp-github-oauth-example:latest
# Specific version
docker pull ghcr.io/YOUR_ORG/fastmcp-github-oauth-example:v1.0.0
# Architecture-specific
docker pull ghcr.io/YOUR_ORG/fastmcp-github-oauth-example:v1.0.0-amd64
docker pull ghcr.io/YOUR_ORG/fastmcp-github-oauth-example:v1.0.0-arm64| Variable | Required | Description |
|---|---|---|
GITHUB_CLIENT_ID |
Yes | GitHub OAuth App Client ID |
GITHUB_CLIENT_SECRET |
Yes | GitHub OAuth App Client Secret |
BASE_URL |
No | Server base URL (default: http://localhost:8000) |
PORT |
No | Server port (default: 8000) |
HOST |
No | Server host (default: 0.0.0.0) |
FASTMCP_DEBUG |
No | Enable debug logging (default: false) |
# Using Docker with environment file
docker run -d \
--name fastmcp-server \
-p 8000:8000 \
--env-file .env \
--restart unless-stopped \
ghcr.io/YOUR_ORG/fastmcp-github-oauth-example:latest
# Using Docker Compose
docker-compose -f docker-compose.prod.yml up -d-
"OAuth app not found"
- Verify GitHub Client ID and Secret in environment variables
- Ensure OAuth app is created in GitHub settings
-
"Callback URL mismatch"
- Check that callback URL in GitHub app matches
BASE_URL/auth/callback - Verify
BASE_URLenvironment variable is correct
- Check that callback URL in GitHub app matches
-
"Container won't start"
- Check Docker logs:
docker logs container_name - Verify all required environment variables are set
- Ensure port 8000 is not already in use
- Check Docker logs:
-
"Wheel not found during Docker build"
- Ensure GoReleaser builds wheel before Docker step
- Check that
ids: [wheel]references correct build ID - Verify GoReleaser configuration syntax
-
"Authentication fails"
- Clear browser cookies and try again
- Check GitHub OAuth app permissions and scopes
- Verify server is accessible at the configured BASE_URL
Enable detailed logging:
# Local development
FASTMCP_DEBUG=true uv run --env-file .env github-oauth-server
# Docker
docker run -e FASTMCP_DEBUG=true -p 8000:8000 fastmcp-github-oauth-exampleThe server includes a comprehensive health check endpoint:
# Check server health
curl http://localhost:8000/health
# Expected response
{
"status": "healthy",
"service": "fastmcp-github-oauth",
"version": "0.1.0"
}
# Docker health check
docker inspect --format='{{.State.Health.Status}}' container_name# Test GoReleaser configuration
goreleaser check
# Build snapshot without Docker
goreleaser build --snapshot --clean --skip-docker
# Build with verbose output
goreleaser release --snapshot --clean --debugThis is an example project for demonstration purposes. For contributions to FastMCP itself, see the main FastMCP repository.
This example is provided under the MIT License.