# MCP Registry Kubernetes Deployment This directory contains Pulumi infrastructure code to deploy the MCP Registry service to a Kubernetes cluster. It supports deploying the infrastructure locally (using an existing kubeconfig, e.g. with minikube) or to Google Cloud Platform (GCP). ## Quick Start ### Local Development Pre-requisites: - [Pulumi CLI installed](https://www.pulumi.com/docs/iac/download-install/) - Access to a Kubernetes cluster via kubeconfig. You can run a cluster locally with [minikube](https://minikube.sigs.k8s.io/docs/start/). 1. Ensure your kubeconfig is configured at the cluster you want to use. For minikube, run `minikube start && minikube tunnel`. 2. Run `make local-up` to deploy the stack. Run this again if the first attempt fails. 3. Access the repository via the ingress load balancer. You can find its external IP with `kubectl get svc ingress-nginx-controller -n ingress-nginx`. Then run `curl -H "Host: local.registry.modelcontextprotocol.io" -k https:///v0/ping` to check that the service is up. #### To change config The stack is configured out of the box for local development. But if you want to make changes, run commands like: ```bash PULUMI_CONFIG_PASSPHRASE="" pulumi config set mcp-registry:environment local PULUMI_CONFIG_PASSPHRASE="" pulumi config set mcp-registry:githubClientSecret --secret ``` #### To delete the stack `make local-destroy` and deleting the cluster (with minikube: `minikube delete`) will reset you back to a clean state. ### Production Deployment (GCP) **Note:** The production deployment is automatically handled by GitHub Actions. All merges to the `main` branch trigger an automatic deployment to GCP via [the configured GitHub Actions workflow](../.github/workflows/deploy.yml). The steps below are preserved as a log of what we did, or if a manual override is needed. Pre-requisites: - [Pulumi CLI installed](https://www.pulumi.com/docs/iac/download-install/) - A Google Cloud Platform (GCP) account - A GCP Service Account with appropriate permissions 1. Create a project: `gcloud projects create mcp-registry-prod` 2. Set the project: `gcloud config set project mcp-registry-prod` 3. Enable required APIs: `gcloud services enable storage.googleapis.com && gcloud services enable container.googleapis.com` 4. Create a service account with necessary permissions, and get the key: ```bash gcloud iam service-accounts create pulumi-svc sleep 10 gcloud projects add-iam-policy-binding mcp-registry-prod --member="serviceAccount:pulumi-svc@mcp-registry-prod.iam.gserviceaccount.com" --role="roles/container.admin" gcloud projects add-iam-policy-binding mcp-registry-prod --member="serviceAccount:pulumi-svc@mcp-registry-prod.iam.gserviceaccount.com" --role="roles/compute.admin" gcloud projects add-iam-policy-binding mcp-registry-prod --member="serviceAccount:pulumi-svc@mcp-registry-prod.iam.gserviceaccount.com" --role="roles/storage.admin" gcloud iam service-accounts add-iam-policy-binding $(gcloud projects describe mcp-registry-prod --format="value(projectNumber)")-compute@developer.gserviceaccount.com --member="serviceAccount:pulumi-svc@mcp-registry-prod.iam.gserviceaccount.com" --role="roles/iam.serviceAccountUser" gcloud iam service-accounts keys create sa-key.json --iam-account=pulumi-svc@mcp-registry-prod.iam.gserviceaccount.com ``` 5. Create a GCS bucket for Pulumi state: `gsutil mb gs://mcp-registry-prod-pulumi-state` 6. Set Pulumi's backend to GCS: `pulumi login gs://mcp-registry-prod-pulumi-state` 7. Get the passphrase file `passphrase.prod.txt` from the registry maintainers 8. Init the GCP stack: `PULUMI_CONFIG_PASSPHRASE_FILE=passphrase.prod.txt pulumi stack init gcpProd` 9. Set the GCP credentials in Pulumi config: ```bash # Base64 encode the service account key and set it pulumi config set --secret gcp:credentials "$(base64 < sa-key.json)" ``` 10. Deploy: `make prod-up` 11. Access the repository via the ingress load balancer. You can find its external IP with: `kubectl get svc ingress-nginx-controller -n ingress-nginx`. Then run `curl -H "Host: prod.registry.modelcontextprotocol.io" -k https:///v0/ping` to check that the service is up. ## Structure ``` ├── main.go # Pulumi program entry point ├── Pulumi.yaml # Project configuration ├── Pulumi.local.yaml # Local stack configuration ├── Pulumi.prod.yaml # Production stack configuration (Azure) ├── Pulumi.gcp.yaml # Production stack configuration (GCP) ├── Makefile # Build and deployment targets ├── go.mod # Go module dependencies ├── go.sum # Go module checksums └── pkg/ # Infrastructure packages ├── k8s/ # Kubernetes deployment components │ ├── cert_manager.go # SSL certificate management │ ├── deploy.go # Deployment orchestration │ ├── ingress.go # Ingress controller setup │ ├── mongodb.go # MongoDB deployment │ └── registry.go # MCP Registry deployment └── providers/ # Kubernetes cluster providers ├── types.go # Provider interface definitions ├── aks/ # Azure Kubernetes Service provider ├── gcp/ # Google Kubernetes Engine provider └── local/ # Local kubeconfig provider ``` ### Architecture Overview #### Deployment Flow 1. Pulumi program starts in `main.go` 2. Configuration is loaded from Pulumi config files 3. Provider factory creates appropriate cluster provider (AKS or local) 4. Cluster provider sets up Kubernetes access 5. `k8s.DeployAll()` orchestrates complete deployment: - Certificate manager for SSL/TLS - Ingress controller for external access - MongoDB for data persistence - MCP Registry application ## Configuration | Parameter | Description | Required | |-----------|-------------|----------| | `environment` | Deployment environment (dev/prod) | Yes | | `provider` | Kubernetes provider (local/aks/gcp) | No (default: local) | | `githubClientId` | GitHub OAuth Client ID | Yes | | `githubClientSecret` | GitHub OAuth Client Secret | Yes | | `gcpProjectId` | GCP Project ID (required when provider=gcp) | No | | `gcpRegion` | GCP Region (default: us-central1) | No | ## Troubleshooting ### Check Status ```bash kubectl get pods kubectl get deployment kubectl get svc kubectl get ingress kubectl get svc -n ingress-nginx ``` ### View Logs ```bash kubectl logs -l app=mcp-registry kubectl logs -l app=mongodb ```