A complete platform for deploying and managing MCP (Model Context Protocol) servers.
When working with large language models, context window limitations often require breaking monolithic services into multiple specialized MCP servers. Rather than paying for third-party gateway services that only provide basic routing, this platform offers a self-hosted solution that gives you full control.
The platform targets organizations that need to ship many MCP servers internally, maintaining a centralized registry where any team can discover and use available MCP servers across the company.
MCP Runtime Platform provides a streamlined workflow for teams to deploy a suite of MCP servers:
- Define server metadata in simple YAML files
- Build Docker images automatically from Dockerfiles
- Deploy via CLI or CI/CD - Kubernetes operator handles everything
- Access via unified URLs:
/{server-name}/mcp
- Complete Platform - Internal registry deployment plus cluster setup helpers
- CLI Tool - Manage platform, registry, cluster, and servers
- Automated Setup - One-command platform deployment
- CI/CD Integration - Automated build and deployment pipeline
- Kubernetes Operator - Automatically creates Deployment, Service, and Ingress
- Metadata-Driven - Simple YAML files, no Kubernetes knowledge needed
- Unified URLs - All servers get consistent
/{server-name}/mcproutes - Auto Image Building - Builds from Dockerfiles and updates metadata automatically
├── cmd/ # Application entry points
│ ├── mcp-runtime/ # Platform management CLI
│ └── operator/ # Kubernetes operator
├── internal/ # Private application code
│ ├── operator/ # Kubernetes operator controller
│ └── cli/ # CLI command implementations
├── api/ # Kubernetes API definitions (CRDs)
├── config/ # Kubernetes manifests
│ ├── crd/ # Custom Resource Definitions
│ ├── registry/ # Registry deployment
│ ├── rbac/ # RBAC configurations
│ └── manager/ # Operator deployment
├── docs/ # Internal notes (README is primary; no separate docs published)
└── examples/ # Example configurations
This README is the primary source of truth; no additional external docs are published.
- Go 1.21 or higher (needed to build the CLI and operator tools)
- Make (used by the provided Makefiles)
- kubectl configured for your cluster
- Docker (to build/push images and interact with the registry)
- Kubernetes cluster (1.21+) with a default StorageClass (registry PVC)
- Ingress controller: setup installs Traefik by default; install/configure another controller first if you prefer a different one
- Operator image handling: setup builds the operator image and auto-loads it into minikube/kind/k3d; for other clusters, ensure the image is in a pullable registry (use
OPERATOR_IMGto override) - Network access to fetch Go modules (for controller-gen/kustomize downloads)
- Default (internal):
mcp-runtime setupdeploys an in-cluster registry in namespaceregistry(PVC-backed) and loads the operator image into the cluster. - Bring your own registry: run
mcp-runtime registry provision --url <registry> [--username ... --password ...] [--operator-image <registry>/mcp-runtime-operator:latest]beforemcp-runtime setup. When a provisioned registry is configured, setup does not create the internal registry; it uses your registry instead and tags/pushes the operator image there. Make sure your cluster nodes can pull from it (configure imagePullSecrets if needed).
- Pushing images: use
mcp-runtime registry push --image <src> [--mode in-cluster|direct] [--registry ...] [--name ...]. Default mode (in-cluster) spins up a helper pod with skopeo to push from inside the cluster; requires kubectl access to create pods inregistrynamespace.directmode usesdocker pushfrom the runner/host and needs a reachable, trusted registry endpoint (Ingress/TLS or NodePort plus insecure-registry config). - Pulling images (pods): nodes must reach the registry. Prefer ClusterIP or a trusted ingress/TLS hostname. Service DNS (
*.svc) is not used by the node runtime for image pulls. NodePort without TLS requires marking the registry as insecure on the node runtime. - MCPServer images: set
spec.imageto the address nodes can reach (ClusterIP or trusted ingress).spec.useProvisionedRegistry/spec.registryOverridecan rewrite to a provisioned registry, and the controller can auto-create a pull secret if provisioned creds are set andimagePullSecretsis empty. - Registry selection decisions:
- Per-server override (
spec.registryOverride) is kept to let teams pull public images, migrate gradually, or target partner registries without mirroring everything. - Global/provisioned registry (
spec.useProvisionedRegistry+ operator envPROVISIONED_REGISTRY_*) is the “platform default” path; enables auto pull-secret creation. - If you want tighter control, layer policy (allowlist/denylist/webhook) rather than removing per-server override.
- Per-server override (
- Image pull secrets: Kubernetes stores registry creds in a
kubernetes.io/dockerconfigjsonSecret. The operator will auto-create/update one per namespace (default namemcp-runtime-registry-creds) and attach it to Deployments whenPROVISIONED_REGISTRY_URL/USERNAME/PASSWORDare set andspec.imagePullSecretsis empty. If you need custom creds, setspec.imagePullSecretson the MCPServer.
- The operator creates one Ingress per MCPServer with a default path of
/<name>/mcp; setspec.ingressPathto override. - Set a shared host once via operator env
MCP_DEFAULT_INGRESS_HOST(e.g.,mcp.example.com); any MCPServer withoutspec.ingressHostwill inherit it. Per-CR values override the default. - Traefik merges all matching Host/Path rules onto its single listener (80/443), so multiple MCPServers can share the same host with different paths.
- Make your hostname resolve to the ingress entrypoint (LB IP, node IP+NodePort, or your chosen exposure) so
http(s)://<host>/<name>/mcpworks from clients. mcp-runtime setup --ingress traefikinstalls the bundled Traefik controller by default using the secure overlay atconfig/ingress/overlays/prod(dashboard/API disabled). It skips install if an IngressClass already exists unless you add--force-ingress-install. Use--ingress noneto skip installing a controller. For a dev-friendly dashboard, point--ingress-manifesttoconfig/ingress/overlays/devto enable--api.insecure=true.- On-prem/no-cloud exposure options:
- Install MetalLB and keep Traefik as
LoadBalancer; MetalLB assigns a LAN IP—point DNS/hosts to it. - Switch Traefik Service to
NodePortand usehttp://<node-ip>:<nodePort>; update DNS/hosts to the node IP. - Dev-only:
kubectl port-forward -n traefik svc/traefik 18080:80and curlhttp://127.0.0.1:18080/...with the correct Host header.
- Install MetalLB and keep Traefik as
# Clone repository
git clone https://github.com/Agent-Hellboy/mcp-runtime.git
cd mcp-runtime
# Install dependencies
make install
# Build runtime CLI
make build-runtime
# (Optional) Install globally
make install-runtimeRun these in order:
- Build the CLI
make build-runtimeBuilds the mcp-runtime binary into ./bin.
- (Optional) Install the CLI globally
make install-runtimeCopies bin/mcp-runtime to /usr/local/bin so it’s on your PATH.
- Setup the platform (uses internal registry by default; skips it if you provision an external one)
mcp-runtime setupInstalls the CRD, creates the mcp-runtime namespace, deploys the registry, and deploys the operator if its image is present.
The registry uses a PersistentVolumeClaim by default; make sure your cluster has a default storage class or update config/registry/pvc.yaml with a specific storageClassName.
- Check status
mcp-runtime statusVerifies cluster, registry, and operator readiness.
# 1. Create metadata file (.mcp/metadata.yaml)
cat > .mcp/metadata.yaml <<EOF
version: v1
servers:
- name: my-server
route: /my-server/mcp
port: 8088
EOF
# 2. Build image locally
docker build -t my-server:latest .
# 3. Push image to the platform/provisioned registry (retags automatically)
mcp-runtime registry push --image my-server:latest
# 4. Generate CRDs and deploy
mcp-runtime pipeline generate --dir .mcp --output manifests/
mcp-runtime pipeline deploy --dir manifests/Your server will be available at: http://<ingress-host>/my-server/mcp
Use this README as the primary walkthrough.
# Setup complete platform
mcp-runtime setup
# Check platform status
mcp-runtime status# Initialize cluster
mcp-runtime cluster init
# Check cluster status
mcp-runtime cluster status
# Provision cluster (Kind, GKE, EKS, AKS)
mcp-runtime cluster provision --provider kind --nodes 3
# Cloud providers are not automated yet; use gcloud/eksctl/az to create a cluster and then point kubectl at it# Check registry status
mcp-runtime registry status
# Show registry info
mcp-runtime registry info
# (Optional) Configure an external registry
mcp-runtime registry provision --url <registry> [--username ... --password ...]# Build image from Dockerfile
mcp-runtime server build my-server
# Build and push image (updates metadata)
mcp-runtime server build --push my-server
# Generate CRDs from metadata
mcp-runtime pipeline generate --dir .mcp --output manifests/
# Deploy CRDs to cluster
mcp-runtime pipeline deploy --dir manifests/# List all servers
mcp-runtime server list
# Get server details
mcp-runtime server get my-server
# View server logs
mcp-runtime server logs my-server --follow
# Delete server
mcp-runtime server delete my-serverThis README is the main reference; there is no separate published doc set.
The operator uses kubebuilder/controller-gen to generate code. Before building, you need to generate:
make -f Makefile.operator manifestsThis generates:
config/crd/bases/mcp.agent-hellboy.io_mcpservers.yaml- CRD definition
make -f Makefile.operator generateThis generates:
api/v1alpha1/zz_generated.deepcopy.go- Deep copy methods for Kubernetes runtime.Object
make -f Makefile.operator manifests generateNote: Generated files (api/v1alpha1/zz_generated.deepcopy.go and CRD manifests) are committed to the repository. Regenerate them after modifying types in api/v1alpha1/.
For developers working on the operator itself:
# Build operator image
make -f Makefile.operator docker-build-operator IMG=your-registry/mcp-runtime-operator:latest
# Deploy operator manually (usually handled by mcp-runtime setup)
make -f Makefile.operator deploy IMG=your-registry/mcp-runtime-operator:latestNote: End users should use mcp-runtime setup which handles operator deployment automatically. These commands are for developers modifying the operator code.
# Run tests
make test
# Format code
make fmt
# Lint code (requires golangci-lint)
make lint
# Generate operator code
make -f Makefile.operator generate- Fork the repository
- Create a feature branch
- Make your changes
- Add tests if applicable
- Run
make fmt && make lint && make test - Submit a pull request
┌─────────────────────────────────────────────────────────────┐
│ CI/CD Runner (GitHub Actions, GitLab CI, etc.) │
│ │
│ 1. Checkout code │
│ 2. Build Docker image │
│ 3. Push to registry │
│ 4. Generate CRDs from metadata │
│ 5. Apply CRDs to cluster via kubectl │
│ (uses kubeconfig from secrets) │
└──────────────────────┬──────────────────────────────────────┘
│ HTTPS API calls
│ (kubectl → Kubernetes API Server)
▼
┌─────────────────────────────────────────────────────────────┐
│ Kubernetes Cluster (Remote - Cloud/On-Prem) │
│ │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ API Server │ │
│ │ • Receives CRD manifests from CI/CD │ │
│ │ • Stores CRDs in etcd │ │
│ └──────────────────┬──────────────────────────────────┘ │
│ │ │
│ │ Operator watches for changes │
│ ▼ │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ Operator (in cluster) │ │
│ │ • Watches MCPServer CRDs │ │
│ │ • Creates Deployment, Service, Ingress │ │
│ └───────────────────────────────────────────────────────┘ │
│ │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ Resources Created by Operator │ │
│ │ ├─ Deployment (runs pods) │ │
│ │ ├─ Service (ClusterIP) │ │
│ │ └─ Ingress (external routes) │ │
│ └───────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
- Teams define metadata - Simple YAML file with server configuration
- CLI builds images - From Dockerfiles, pushes to registry, updates metadata
- CLI generates CRDs - Converts metadata to Kubernetes Custom Resources
- Operator watches CRDs - Automatically creates Deployment, Service, and Ingress
- Servers accessible - Via unified URLs:
/{server-name}/mcp
The operator automatically manages MCP server deployments:
- Watches for
MCPServerCRD instances - Creates Deployment with specified replicas and resources
- Creates ClusterIP Service for internal communication
- Creates Ingress with unified route pattern
The platform integrates seamlessly with CI/CD pipelines:
# Example GitHub Actions workflow
- name: Build and push
run: mcp-runtime build push my-server --tag ${{ github.sha }}
- name: Deploy
run: |
mcp-runtime pipeline generate --dir .mcp --output manifests/
mcp-runtime pipeline deploy --dir manifests/Use these snippets in your pipeline of choice. A sample pre-check workflow exists at .github/workflows/pre-check.yaml.
- Kubernetes operator for automatic deployment
- CI/CD pipeline integration
- Custom Resource Definition (CRD)
- Platform CLI with full feature set
- Container registry deployment
- Metadata-driven workflow
- Automatic image building and metadata updates
- Unified URL routing pattern
- API server for centralized control (optional)
- Multi-cluster support
- Advanced monitoring and observability
- Webhook validation
- Approval workflows
This project is licensed under the MIT License - see the LICENSE file for details.
Officially supported on: under dev
Tested on:
- macOS Sonoma (M1/M4 chips)
- Ubuntu 20.04+ LTS