cforge gateway - Deployment Toolยถ
Overviewยถ
The cforge gateway command is a powerful deployment tool for MCP Gateway and its external plugins. It provides a unified, declarative way to build, configure, and deploy the complete MCP stack from a single YAML configuration file.
Quick Startยถ
Installationยถ
The cforge CLI is installed with the MCP Gateway package:
Verify installation:
Basic Workflowยถ
# 1. Validate your configuration
cforge gateway validate examples/deployment-configs/deploy-compose.yaml
# 2. Build containers (if building from source)
cforge gateway build examples/deployment-configs/deploy-compose.yaml
# 3. Generate mTLS certificates (if needed)
cforge gateway certs examples/deployment-configs/deploy-compose.yaml
# 4. Deploy the stack
cforge gateway deploy examples/deployment-configs/deploy-compose.yaml
# 5. Verify deployment health
cforge gateway verify examples/deployment-configs/deploy-compose.yaml
# 6. (Optional) Tear down
cforge gateway destroy examples/deployment-configs/deploy-compose.yaml
Simple Configuration Exampleยถ
The cforge gateway tool uses custom YAML configuration files to describe your deployment. These are not standard Docker Compose or Kubernetes manifests - instead, cforge reads these configuration files and generates the actual deployment manifests for your target environment.
Here's a minimal example configuration that demonstrates the key components:
deployment:
type: compose # Target: 'compose' or 'kubernetes'
project_name: mcp-stack-test
gateway:
image: mcpgateway/mcpgateway:latest # Use pre-built image
port: 4444
host_port: 4444 # Expose on localhost:4444
env_vars:
LOG_LEVEL: DEBUG
MCPGATEWAY_UI_ENABLED: "true"
AUTH_REQUIRED: "false" # Simplified for testing
mtls_enabled: false # Disable mTLS for simple setup
plugins:
- name: OPAPluginFilter
repo: https://github.com/terylt/mcp-context-forge.git
ref: feat/use_mtls_plugins # Git branch/tag/commit
context: plugins/external/opa # Build context path
containerfile: Containerfile
expose_port: true
mtls_enabled: false
plugin_overrides:
priority: 10
mode: "enforce"
description: "OPA policy enforcement"
certificates:
auto_generate: true # Auto-generate certs if needed
Key sections explained:
- deployment: Specifies the target environment (Docker Compose or Kubernetes) and basic settings
- gateway: Defines the MCP Gateway configuration - can use a pre-built image or build from a Git repository
- plugins: Array of external plugins to deploy. Each plugin can be built from source or use pre-built images
- certificates: mTLS certificate configuration (auto-generated by default)
How it works:
When you run cforge gateway deploy <config-file>, the tool: 1. Reads your custom configuration YAML 2. Builds container images (if building from source) 3. Generates mTLS certificates (if needed) 4. Generates actual deployment files: - For type: compose โ deploy/docker-compose.yaml - For type: kubernetes โ deploy/manifests/*.yaml (Deployment, Service, ConfigMap, etc.) 5. Deploys the generated manifests to your target environment
Additional example configurations are available in examples/deployment-configs/: - deploy-compose.yaml - Docker Compose without mTLS - deploy-compose.mtls.yaml - Docker Compose with mTLS - deploy-k8s.yaml - Kubernetes with pre-built images - deploy-k8s-cert-manager.yaml - Kubernetes with cert-manager integration - More examples for OpenShift, registry integration, and advanced scenarios
See the Example Configurations section below for detailed examples with full explanations.
Commandsยถ
cforge gateway validateยถ
Validates the deployment configuration file without making any changes.
Example:
Output: - โ Configuration syntax validation - โ Plugin name uniqueness check - โ Required field verification - โ Build configuration validation (image XOR repo)
cforge gateway buildยถ
Builds container images for gateway and/or plugins from source repositories.
Options:
| Option | Description | Default |
|---|---|---|
--plugins-only | Only build plugin containers, skip gateway | false |
--plugin NAME, -p NAME | Build specific plugin(s) only (can specify multiple) | All plugins |
--no-cache | Disable Docker build cache | false |
--copy-env-templates | Copy .env.template files from plugin repos | true |
Examples:
# Build everything
cforge gateway build deploy.yaml
# Build only plugins
cforge gateway build deploy.yaml --plugins-only
# Build specific plugin
cforge gateway build deploy.yaml --plugin OPAPluginFilter
# Build multiple plugins with no cache
cforge gateway build deploy.yaml --plugin OPAPluginFilter --plugin LLMGuardPlugin --no-cache
What it does: 1. Clones Git repositories (if repo specified) 2. Checks out specified branch/tag/commit (ref) 3. Builds Docker images from containerfile in context directory 4. Tags images appropriately for deployment 5. Copies .env.template files to deploy/env/ for customization
cforge gateway certsยถ
Generates mTLS certificate hierarchy for secure gateway โ plugin communication.
Example:
What it generates:
certs/mcp/
โโโ ca/
โ โโโ ca.crt # Root CA certificate
โ โโโ ca.key # Root CA private key
โโโ gateway/
โ โโโ client.crt # Gateway client certificate
โ โโโ client.key # Gateway client private key
โ โโโ ca.crt # CA cert (for verification)
โโโ plugins/
โโโ PluginName1/
โ โโโ server.crt # Plugin server certificate
โ โโโ server.key # Plugin server private key
โ โโโ ca.crt # CA cert (for verification)
โโโ PluginName2/
โโโ server.crt
โโโ server.key
โโโ ca.crt
Certificate Properties: - Validity: Configurable (default: 825 days) - CN for gateway: mcp-gateway - CN for plugins: mcp-plugin-{PluginName} - SANs: {PluginName}, mcp-plugin-{PluginName}, localhost
cforge gateway deployยถ
Deploys the complete MCP stack to the target environment.
Options:
| Option | Description | Default |
|---|---|---|
--output-dir DIR, -o DIR | Custom output directory for manifests | deploy/ |
--dry-run | Generate manifests without deploying | false |
--skip-build | Skip container build step | false |
--skip-certs | Skip certificate generation | false |
Examples:
# Full deployment
cforge gateway deploy deploy.yaml
# Dry-run (generate manifests only)
cforge gateway deploy deploy.yaml --dry-run
# Deploy with existing images and certs
cforge gateway deploy deploy.yaml --skip-build --skip-certs
# Custom output directory
cforge gateway deploy deploy.yaml --output-dir ./my-deployment
Deployment Process: 1. Validate configuration 2. Build containers (unless --skip-build) 3. Generate certificates (unless --skip-certs or already exist) 4. Generate manifests (Kubernetes or Docker Compose) 5. Apply to target environment: - Kubernetes: kubectl apply -f - Docker Compose: docker-compose up -d
Generated Files:
deploy/
โโโ env/ # Environment files
โ โโโ .env.gateway
โ โโโ .env.PluginName1
โ โโโ .env.PluginName2
โโโ manifests/ # Kubernetes OR
โ โโโ namespace.yaml
โ โโโ configmaps.yaml
โ โโโ secrets.yaml
โ โโโ gateway-deployment.yaml
โ โโโ gateway-service.yaml
โ โโโ plugin-deployments.yaml
โ โโโ plugin-services.yaml
โโโ docker-compose.yaml # Docker Compose
cforge gateway verifyยถ
Verifies that the deployed stack is healthy and running.
Options:
| Option | Description | Default |
|---|---|---|
--wait | Wait for deployment to be ready | true |
--timeout SECONDS | Wait timeout in seconds | 300 |
Examples:
# Verify deployment (wait up to 5 minutes)
cforge gateway verify deploy.yaml
# Quick check without waiting
cforge gateway verify deploy.yaml --no-wait
# Custom timeout
cforge gateway verify deploy.yaml --timeout 600
Checks: - Container/pod readiness - Health endpoint responses - Service connectivity - mTLS handshake (if enabled)
cforge gateway destroyยถ
Tears down the deployed MCP stack.
Options:
| Option | Description | Default |
|---|---|---|
--force | Skip confirmation prompt | false |
Examples:
# Destroy with confirmation
cforge gateway destroy deploy.yaml
# Force destroy without prompt
cforge gateway destroy deploy.yaml --force
What it removes: - Kubernetes: Deletes all resources in namespace - Docker Compose: Stops and removes containers, networks, volumes
โ ๏ธ Note: This does NOT delete generated certificates or build artifacts. To clean those:
cforge gateway generateยถ
Generates deployment manifests without deploying them.
Options:
| Option | Description | Default |
|---|---|---|
--output DIR, -o DIR | Output directory for manifests | deploy/ |
Examples:
# Generate manifests
cforge gateway generate deploy.yaml
# Custom output directory
cforge gateway generate deploy.yaml --output ./manifests
Use cases: - GitOps workflows (commit generated manifests) - Manual review before deployment - Integration with external deployment tools - CI/CD pipeline artifact generation
cforge gateway versionยถ
Shows version and runtime information.
Output:
โโ Version Info โโโโโโโโโโโโโโโโโโ
โ MCP Deploy โ
โ Version: 1.0.0 โ
โ Mode: dagger โ
โ Environment: local โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Global Optionsยถ
These options apply to all commands:
| Option | Description | Default |
|---|---|---|
--dagger | Enable Dagger mode (auto-downloads CLI if needed) | false (uses plain Python) |
--verbose, -v | Verbose output | false |
Examples:
# Use plain Python mode (default)
cforge gateway deploy deploy.yaml
# Enable Dagger mode for optimized builds
cforge gateway --dagger deploy deploy.yaml
# Verbose mode
cforge gateway -v build deploy.yaml
# Combine options
cforge gateway --dagger -v deploy deploy.yaml
Configuration Referenceยถ
Deployment Configurationยถ
Top-level deployment settings:
deployment:
type: kubernetes | compose # Required: Deployment target
project_name: my-project # Docker Compose only
namespace: mcp-gateway # Kubernetes only
container_engine: podman | docker # Container runtime (auto-detected if not specified)
# OpenShift-specific configuration (optional)
openshift:
create_routes: true # Create OpenShift Route resources
domain: apps-crc.testing # OpenShift apps domain (auto-detected if omitted)
tls_termination: edge # TLS termination mode: edge, passthrough, or reencrypt
| Field | Type | Required | Description | Default |
|---|---|---|---|---|
type | string | โ | Deployment type: kubernetes or compose | - |
project_name | string | โ | Docker Compose project name | - |
namespace | string | โ | Kubernetes namespace | - |
container_engine | string | โ | Container runtime: docker or podman | Auto-detected |
openshift | object | โ | OpenShift-specific configuration (see below) | - |
OpenShift Configurationยถ
OpenShift Routes provide native external access to services, with built-in TLS termination and integration with OpenShift's router/HAProxy infrastructure.
| Field | Type | Required | Description | Default |
|---|---|---|---|---|
create_routes | boolean | โ | Create OpenShift Route resources for external access | false |
domain | string | โ | OpenShift apps domain for route hostnames | Auto-detected from cluster |
tls_termination | string | โ | TLS termination mode: edge, passthrough, or reencrypt | edge |
Example:
deployment:
type: kubernetes
namespace: mcp-gateway-test
openshift:
create_routes: true
domain: apps-crc.testing
tls_termination: edge
When create_routes: true, the tool generates an OpenShift Route for the gateway: - Host: mcpgateway-admin-{namespace}.{domain} - Path: / - TLS: Edge termination (default) - Target: Gateway service on HTTP port
Access the gateway:
Domain auto-detection: If domain is not specified, the tool attempts to auto-detect the OpenShift apps domain from the cluster:
If auto-detection fails, it defaults to apps-crc.testing (OpenShift Local).
Gateway Configurationยถ
Gateway server settings:
gateway:
# Build Configuration (choose ONE)
image: mcpgateway/mcpgateway:latest # Pre-built image
# OR
repo: https://github.com/org/repo.git # Build from source
ref: main # Git branch/tag/commit
context: . # Build context directory
containerfile: Containerfile # Dockerfile path
target: production # Multi-stage build target
# Runtime Configuration
port: 4444 # Internal port
host_port: 4444 # Host port mapping (compose only)
# mTLS Client Configuration (gateway โ plugins)
mtls_enabled: true # Enable mTLS
mtls_verify: true # Verify server certs
mtls_check_hostname: false # Verify hostname
# Container Registry Configuration (optional)
registry:
enabled: true # Enable registry push
url: registry.example.com # Registry URL
namespace: myproject # Registry namespace/org
push: true # Push after build
image_pull_policy: IfNotPresent # Kubernetes imagePullPolicy
# Environment Variables
env_vars:
LOG_LEVEL: INFO
MCPGATEWAY_UI_ENABLED: "true"
AUTH_REQUIRED: "true"
# ... (see full reference below)
# Kubernetes-specific
replicas: 2 # Number of replicas
service_type: ClusterIP # Service type
service_port: 4444 # Service port
memory_request: 256Mi # Memory request
memory_limit: 512Mi # Memory limit
cpu_request: 100m # CPU request
cpu_limit: 500m # CPU limit
image_pull_policy: IfNotPresent # Image pull policy
Build Configuration Fields:
| Field | Type | Required | Description | Default |
|---|---|---|---|---|
image | string | โ* | Pre-built Docker image | - |
repo | string | โ* | Git repository URL | - |
ref | string | โ | Git branch/tag/commit | main |
context | string | โ | Build context subdirectory | . |
containerfile | string | โ | Containerfile/Dockerfile path | Containerfile |
target | string | โ | Multi-stage build target | - |
* Either image OR repo must be specified
Runtime Configuration Fields:
| Field | Type | Required | Description | Default |
|---|---|---|---|---|
port | integer | โ | Internal container port | 4444 |
host_port | integer | โ | Host port mapping (compose only) | - |
env_vars | object | โ | Environment variables | {} |
mtls_enabled | boolean | โ | Enable mTLS client | true |
mtls_verify | boolean | โ | Verify server certificates | true |
mtls_check_hostname | boolean | โ | Verify hostname in cert | false |
registry | object | โ | Container registry configuration | - |
Container Registry Configuration Fields:
| Field | Type | Required | Description | Default |
|---|---|---|---|---|
enabled | boolean | โ | Enable registry integration | false |
url | string | โ* | Registry URL (e.g., docker.io, quay.io, OpenShift registry) | - |
namespace | string | โ* | Registry namespace/organization/project | - |
push | boolean | โ | Push image to registry after build | true |
image_pull_policy | string | โ | Kubernetes imagePullPolicy (Always, IfNotPresent, Never) | IfNotPresent |
* Required when enabled: true
Kubernetes-specific Fields:
| Field | Type | Required | Description | Default |
|---|---|---|---|---|
replicas | integer | โ | Number of pod replicas | 1 |
service_type | string | โ | Service type (ClusterIP, NodePort, LoadBalancer) | ClusterIP |
service_port | integer | โ | Service port | 4444 |
memory_request | string | โ | Memory request | 256Mi |
memory_limit | string | โ | Memory limit | 512Mi |
cpu_request | string | โ | CPU request | 100m |
cpu_limit | string | โ | CPU limit | 500m |
image_pull_policy | string | โ | Image pull policy | IfNotPresent |
Plugin Configurationยถ
External plugin settings (array of plugin objects):
plugins:
- name: MyPlugin # Required: Unique plugin name
# Build Configuration (choose ONE)
image: myorg/myplugin:latest # Pre-built image
# OR
repo: https://github.com/org/repo.git # Build from source
ref: main
context: plugins/myplugin
containerfile: Containerfile
target: builder
# Runtime Configuration
port: 8000 # Internal port
expose_port: true # Expose on host (compose only)
# mTLS Server Configuration (plugin server)
mtls_enabled: true # Enable mTLS server
# Container Registry Configuration (optional)
registry:
enabled: true # Enable registry push
url: registry.example.com # Registry URL
namespace: myproject # Registry namespace/org
push: true # Push after build
image_pull_policy: IfNotPresent # Kubernetes imagePullPolicy
# Environment Variables
env_vars:
LOG_LEVEL: DEBUG
CUSTOM_SETTING: value
# Plugin Manager Overrides (client-side)
plugin_overrides:
priority: 10
mode: enforce
description: "My custom plugin"
tags: ["security", "filter"]
# Kubernetes-specific
replicas: 1
service_type: ClusterIP
service_port: 8000
memory_request: 128Mi
memory_limit: 256Mi
cpu_request: 50m
cpu_limit: 200m
image_pull_policy: IfNotPresent
Required Fields:
| Field | Type | Description |
|---|---|---|
name | string | Unique plugin identifier (used for cert CN, service names, etc.) |
Build Configuration: Same as Gateway (see above)
Runtime Configuration:
| Field | Type | Required | Description | Default |
|---|---|---|---|---|
port | integer | โ | Internal container port | 8000 |
expose_port | boolean | โ | Expose port on host (compose only) | false |
env_vars | object | โ | Environment variables | {} |
mtls_enabled | boolean | โ | Enable mTLS server | true |
registry | object | โ | Container registry configuration (same fields as gateway) | - |
plugin_overrides | object | โ | Plugin manager config overrides | {} |
Plugin Overrides:
| Field | Type | Description | Default |
|---|---|---|---|
priority | integer | Plugin execution priority (lower = earlier) | - |
mode | string | enforce, monitor, or dry-run | - |
description | string | Plugin description | - |
tags | array | Plugin tags for categorization | - |
hooks | array | Enabled hooks: prompt_pre_fetch, tool_pre_invoke, etc. | All hooks |
Kubernetes-specific: Same as Gateway (see above)
Certificate Configurationยถ
mTLS certificate generation settings:
certificates:
# Local certificate generation (default)
validity_days: 825 # Certificate validity period
auto_generate: true # Auto-generate if missing
ca_path: ./certs/mcp/ca # CA certificate directory
gateway_path: ./certs/mcp/gateway # Gateway cert directory
plugins_path: ./certs/mcp/plugins # Plugins cert directory
# OR use cert-manager (Kubernetes only)
use_cert_manager: true # Use cert-manager for certificates
cert_manager_issuer: mcp-ca-issuer # Issuer/ClusterIssuer name
cert_manager_kind: Issuer # Issuer or ClusterIssuer
| Field | Type | Required | Description | Default |
|---|---|---|---|---|
validity_days | integer | โ | Certificate validity in days | 825 |
auto_generate | boolean | โ | Auto-generate certificates locally if missing | true |
ca_path | string | โ | CA certificate directory (local mode) | ./certs/mcp/ca |
gateway_path | string | โ | Gateway client cert directory (local mode) | ./certs/mcp/gateway |
plugins_path | string | โ | Plugin server certs base directory (local mode) | ./certs/mcp/plugins |
use_cert_manager | boolean | โ | Use cert-manager for certificate management (Kubernetes only) | false |
cert_manager_issuer | string | โ | cert-manager Issuer/ClusterIssuer name | mcp-ca-issuer |
cert_manager_kind | string | โ | cert-manager issuer kind: Issuer or ClusterIssuer | Issuer |
cert-manager Integration (Kubernetes Only)ยถ
cert-manager is a Kubernetes-native certificate management controller that automates certificate issuance and renewal.
Benefits: - โ Automatic Renewal: Certificates renewed before expiry (default: at โ of lifetime) - โ Native Kubernetes: Certificates defined as Kubernetes Custom Resources - โ Simplified Operations: No manual certificate generation or rotation - โ GitOps Friendly: Certificate definitions version-controlled
Prerequisites: 1. Install cert-manager in your cluster:
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.0/cert-manager.yaml
- Create namespace and CA Issuer (one-time setup):
Configuration:
certificates:
use_cert_manager: true
cert_manager_issuer: mcp-ca-issuer
cert_manager_kind: Issuer
validity_days: 825
When use_cert_manager: true: - Local certificate generation is skipped - cert-manager Certificate CRDs are generated for gateway and plugins - cert-manager automatically creates Kubernetes TLS secrets - Certificates are auto-renewed before expiry
Important: The cert-manager Issuer and CA certificate are long-lived infrastructure. When you destroy your MCP deployment, the Issuer remains (by design) for reuse across deployments.
Infrastructure Servicesยถ
PostgreSQL and Redis are automatically deployed with the MCP Gateway stack using hardcoded defaults:
PostgreSQL (always deployed): - Image: postgres:17 - Database: mcp - User: postgres - Password: mysecretpassword (override with POSTGRES_PASSWORD env var) - Port: 5432 - Kubernetes: Uses 10Gi PVC
Redis (always deployed): - Image: redis:latest - Port: 6379
Connection strings (auto-configured):
DATABASE_URL=postgresql://postgres:${POSTGRES_PASSWORD}@postgres:5432/mcp
REDIS_URL=redis://redis:6379/0
These services are included in all deployments and cannot currently be disabled or customized via the deployment YAML. To customize PostgreSQL password:
# Set before deploying
export POSTGRES_PASSWORD=your-secure-password
cforge gateway deploy deploy.yaml
Example Configurationsยถ
Example 1: Docker Compose (No mTLS)ยถ
File: examples/deployment-configs/deploy-compose.yaml
Simple local deployment for development and testing:
deployment:
type: compose
project_name: mcp-stack-test
gateway:
image: mcpgateway/mcpgateway:latest
port: 4444
host_port: 4444
env_vars:
LOG_LEVEL: DEBUG
MCPGATEWAY_UI_ENABLED: "true"
AUTH_REQUIRED: "false"
mtls_enabled: false
plugins:
- name: OPAPluginFilter
repo: https://github.com/terylt/mcp-context-forge.git
ref: feat/use_mtls_plugins
context: plugins/external/opa
expose_port: true
mtls_enabled: false
plugin_overrides:
priority: 10
mode: "enforce"
certificates:
auto_generate: true
Use case: Quick local testing without security overhead
Deploy:
Access: - Gateway: http://localhost:4444 - Admin UI: http://localhost:4444/admin - Plugin (exposed): http://localhost:8000
Example 2: Docker Compose (With mTLS)ยถ
File: examples/deployment-configs/deploy-compose.mtls.yaml
Secure local deployment with mutual TLS:
deployment:
type: compose
project_name: mcp-stack-test
gateway:
image: mcpgateway/mcpgateway:latest
port: 4444
host_port: 4444
mtls_enabled: true # โ Enable mTLS client
mtls_verify: true
mtls_check_hostname: false # Don't verify hostname for localhost
plugins:
- name: OPAPluginFilter
repo: https://github.com/terylt/mcp-context-forge.git
ref: feat/use_mtls_plugins
context: plugins/external/opa
mtls_enabled: true # โ Enable mTLS server
plugin_overrides:
priority: 10
mode: "enforce"
certificates:
validity_days: 825
auto_generate: true # Auto-generate mTLS certs
Use case: Local testing with production-like security
Deploy:
# Certificates are auto-generated during deploy
cforge gateway deploy examples/deployment-configs/deploy-compose.mtls.yaml
How mTLS works: 1. cforge gateway certs generates CA + gateway client cert + plugin server certs 2. Gateway connects to plugins using client certificate 3. Plugins verify gateway's client certificate against CA 4. All communication is encrypted and mutually authenticated
Example 3: Kubernetes (Pre-built Images)ยถ
File: examples/deployment-configs/deploy-k8s.yaml
Production-ready Kubernetes deployment using pre-built images:
deployment:
type: kubernetes
namespace: mcp-gateway-prod
gateway:
image: mcpgateway/mcpgateway:latest
image_pull_policy: IfNotPresent
replicas: 2 # High availability
service_type: LoadBalancer
service_port: 4444
memory_request: 256Mi
memory_limit: 512Mi
cpu_request: 100m
cpu_limit: 500m
mtls_enabled: true
plugins:
- name: OPAPluginFilter
image: mcpgateway-opapluginfilter:latest
image_pull_policy: IfNotPresent
replicas: 2
service_type: ClusterIP
memory_request: 128Mi
memory_limit: 256Mi
cpu_request: 50m
cpu_limit: 200m
mtls_enabled: true
plugin_overrides:
priority: 10
mode: "enforce"
infrastructure:
postgres:
enabled: true
storage_size: 20Gi
storage_class: fast-ssd
redis:
enabled: true
certificates:
auto_generate: true
Use case: Production deployment with HA and resource limits
Deploy:
# Deploy to Kubernetes
cforge gateway deploy examples/deployment-configs/deploy-k8s.yaml
# Verify
kubectl get all -n mcp-gateway-prod
# Check logs
kubectl logs -n mcp-gateway-prod -l app=mcp-gateway
Example 4: Kubernetes (Build from Source)ยถ
Building plugins from Git repositories in Kubernetes:
deployment:
type: kubernetes
namespace: mcp-gateway-dev
gateway:
image: mcpgateway/mcpgateway:latest
plugins:
- name: OPAPluginFilter
# Build from source
repo: https://github.com/terylt/mcp-context-forge.git
ref: feat/use_mtls_plugins
context: plugins/external/opa
containerfile: Containerfile
# Push to registry (configure with env vars)
# See DOCKER_REGISTRY in deploy process
replicas: 1
mtls_enabled: true
certificates:
auto_generate: true
Deploy:
# Build locally and push to registry
export DOCKER_REGISTRY=myregistry.io/myorg
cforge gateway build deploy-k8s-build.yaml
# Deploy to Kubernetes
cforge gateway deploy deploy-k8s-build.yaml --skip-build
Example 5: Kubernetes with cert-managerยถ
File: examples/deployment-configs/deploy-k8s-cert-manager.yaml
Production deployment using cert-manager for automated certificate management:
deployment:
type: kubernetes
namespace: mcp-gateway-test
gateway:
image: mcpgateway/mcpgateway:latest
image_pull_policy: IfNotPresent
port: 4444
service_type: ClusterIP
service_port: 4444
replicas: 1
memory_request: 256Mi
memory_limit: 512Mi
cpu_request: 100m
cpu_limit: 500m
env_vars:
LOG_LEVEL: DEBUG
MCPGATEWAY_UI_ENABLED: "true"
mtls_enabled: true
mtls_verify: true
mtls_check_hostname: false
plugins:
- name: OPAPluginFilter
image: mcpgateway-opapluginfilter:latest
image_pull_policy: IfNotPresent
port: 8000
service_type: ClusterIP
replicas: 1
memory_request: 128Mi
memory_limit: 256Mi
mtls_enabled: true
plugin_overrides:
priority: 10
mode: "enforce"
# cert-manager configuration
certificates:
# Use cert-manager for automatic certificate management
use_cert_manager: true
# Reference the Issuer created in prerequisites
cert_manager_issuer: mcp-ca-issuer
cert_manager_kind: Issuer
# Certificate validity (auto-renewed at 2/3 of lifetime)
validity_days: 825
# Local paths not used when use_cert_manager=true
auto_generate: false
Prerequisites:
-
Install cert-manager:
-
Create namespace and CA Issuer (one-time setup):
Deploy:
# Deploy (no need to generate certificates manually)
cforge gateway deploy examples/deployment-configs/deploy-k8s-cert-manager.yaml
# Verify cert-manager created certificates
kubectl get certificates -n mcp-gateway-test
kubectl get secrets -n mcp-gateway-test | grep mcp-
How it works: 1. cforge gateway deploy skips local certificate generation 2. Generates cert-manager Certificate CRDs for gateway and plugins 3. Applies Certificate CRDs to Kubernetes 4. cert-manager automatically creates TLS secrets 5. Pods use the secrets created by cert-manager 6. cert-manager auto-renews certificates before expiry
Certificate lifecycle: - Creation: cert-manager generates certificates when CRDs are applied - Renewal: Automatic renewal at โ of lifetime (550 days for 825-day cert) - Deletion: Certificates deleted when stack is destroyed, Issuer remains
mTLS Configuration Guideยถ
Understanding mTLS in MCP Gatewayยถ
mTLS (Mutual TLS) provides: - Encryption: All gateway โ plugin traffic is encrypted - Authentication: Both parties prove their identity - Authorization: Only trusted certificates can communicate
Certificate Hierarchyยถ
CA (Root Certificate Authority)
โโโ Gateway Client Certificate
โ โโโ Used by gateway to connect to plugins
โโโ Plugin Server Certificates (one per plugin)
โโโ Used by plugins to authenticate gateway
Enabling mTLSยถ
In your configuration:
gateway:
mtls_enabled: true # Enable mTLS client
mtls_verify: true # Verify server certificates
mtls_check_hostname: false # Skip hostname verification (for localhost/IPs)
plugins:
- name: MyPlugin
mtls_enabled: true # Enable mTLS server
Certificate Generationยถ
Automatic (recommended):
Manual:
# Generate certificates explicitly
cforge gateway certs deploy.yaml
# Certificates are created in:
# - certs/mcp/ca/ (CA)
# - certs/mcp/gateway/ (gateway client cert)
# - certs/mcp/plugins/*/ (plugin server certs)
Environment Variablesยถ
The deployment tool automatically sets these environment variables:
Gateway (client):
PLUGINS_CLIENT_MTLS_CERTFILE=/certs/gateway/client.crt
PLUGINS_CLIENT_MTLS_KEYFILE=/certs/gateway/client.key
PLUGINS_CLIENT_MTLS_CA_BUNDLE=/certs/gateway/ca.crt
PLUGINS_CLIENT_MTLS_VERIFY=true
PLUGINS_CLIENT_MTLS_CHECK_HOSTNAME=false
Plugin (server):
PLUGINS_SERVER_SSL_CERTFILE=/certs/server.crt
PLUGINS_SERVER_SSL_KEYFILE=/certs/server.key
PLUGINS_SERVER_SSL_CA_CERTS=/certs/ca.crt
PLUGINS_SERVER_SSL_CERT_REQS=2 # CERT_REQUIRED
Troubleshooting mTLSยถ
Problem: Certificate verification fails
Check certificate validity:
openssl x509 -in certs/mcp/gateway/client.crt -noout -dates
openssl x509 -in certs/mcp/plugins/MyPlugin/server.crt -noout -dates
Problem: Hostname mismatch errors
Solution: Set mtls_check_hostname: false in gateway config, or use service DNS names
Problem: Connection refused
- Verify plugin has
mtls_enabled: true - Check plugin logs for certificate errors
- Ensure certificates are mounted correctly
Problem: Expired certificates
Regenerate:
Then redeploy to distribute new certificates.
Container Registry Integrationยถ
Overviewยถ
The container registry feature allows you to build images locally and automatically push them to container registries (Docker Hub, Quay.io, OpenShift internal registry, private registries, etc.). This is essential for:
โ Kubernetes/OpenShift deployments - Avoid ImagePullBackOff errors โ Team collaboration - Share images across developers and environments โ CI/CD pipelines - Build once, deploy everywhere โ Production deployments - Use trusted registry sources
How It Worksยถ
- Build: Images are built locally using docker/podman
- Tag: Images are automatically tagged with the registry path
- Push: Images are pushed to the registry (if
push: true) - Deploy: Kubernetes manifests reference the registry images
Configurationยถ
Add a registry section to your gateway and/or plugin configurations:
gateway:
repo: https://github.com/yourorg/yourrepo.git
# Container registry configuration
registry:
enabled: true # Enable registry integration
url: registry.example.com # Registry URL
namespace: myproject # Registry namespace/org/project
push: true # Push after build (default: true)
image_pull_policy: IfNotPresent # Kubernetes imagePullPolicy
Configuration Fields:
| Field | Required | Description | Example |
|---|---|---|---|
enabled | Yes | Enable registry push | true |
url | Yes* | Registry URL | docker.io, quay.io, registry.mycompany.com |
namespace | Yes* | Registry namespace/organization/project | myusername, myorg, mcp-gateway-test |
push | No | Push image after build | true (default) |
image_pull_policy | No | Kubernetes imagePullPolicy | IfNotPresent (default) |
* Required when enabled: true
Common Registry Examplesยถ
Docker Hubยถ
registry:
enabled: true
url: docker.io
namespace: myusername
push: true
image_pull_policy: IfNotPresent
Authentication:
Quay.ioยถ
registry:
enabled: true
url: quay.io
namespace: myorganization
push: true
image_pull_policy: IfNotPresent
Authentication:
OpenShift Internal Registryยถ
registry:
enabled: true
url: default-route-openshift-image-registry.apps-crc.testing
namespace: mcp-gateway-test
push: true
image_pull_policy: Always
Authentication:
# OpenShift Local (CRC)
podman login $(oc registry info) -u $(oc whoami) -p $(oc whoami -t)
# OpenShift on cloud
oc registry login
Private Registryยถ
registry:
enabled: true
url: registry.mycompany.com
namespace: devteam
push: true
image_pull_policy: IfNotPresent
Authentication:
Image Namingยถ
When registry is enabled, images are automatically tagged with the full registry path:
Local tag (without registry):
Registry tag (with registry enabled):
registry.example.com/myproject/mcpgateway-gateway:latest
registry.example.com/myproject/mcpgateway-opapluginfilter:latest
Image Pull Policiesยถ
Choose the appropriate policy for your use case:
| Policy | Description | Best For |
|---|---|---|
Always | Pull image every time pod starts | Development, testing latest changes |
IfNotPresent | Pull only if image doesn't exist locally | Production, stable releases |
Never | Never pull, only use local images | Air-gapped environments |
Workflow Exampleยถ
OpenShift Local Deploymentยถ
# 1. Authenticate to OpenShift registry
podman login $(oc registry info) -u $(oc whoami) -p $(oc whoami -t)
# 2. Build and push images
cforge gateway deploy examples/deployment-configs/deploy-openshift-local-registry.yaml
# The tool will:
# - Build images locally
# - Tag with registry paths
# - Push to OpenShift internal registry
# - Generate manifests with registry image references
# - Deploy to cluster
# 3. Verify images were pushed
oc get imagestreams -n mcp-gateway-test
# Output:
# NAME IMAGE REPOSITORY
# mcpgateway-gateway default-route-.../mcp-gateway-test/mcpgateway-gateway
# mcpgateway-opapluginfilter default-route-.../mcp-gateway-test/mcpgateway-opapluginfilter
CI/CD Pipeline Exampleยถ
# In your CI/CD pipeline:
# 1. Authenticate to registry
echo "$REGISTRY_PASSWORD" | docker login $REGISTRY_URL -u $REGISTRY_USER --password-stdin
# 2. Build and push
cforge gateway build deploy-prod.yaml
# 3. Images are automatically pushed to registry
# 4. Deploy to Kubernetes (manifests already reference registry images)
cforge gateway deploy deploy-prod.yaml --skip-build --skip-certs
Per-Component Configurationยถ
Each component (gateway and plugins) can have different registry settings:
gateway:
repo: https://github.com/myorg/gateway.git
registry:
enabled: true
url: quay.io
namespace: myorg
push: true
plugins:
- name: MyPlugin
repo: https://github.com/myorg/plugin.git
registry:
enabled: true
url: docker.io # Different registry
namespace: myusername # Different namespace
push: true
- name: InternalPlugin
repo: https://github.com/myorg/internal-plugin.git
# No registry - use local image only
registry:
enabled: false
This allows you to: - Push gateway to one registry, plugins to another - Skip registry push for some components - Use different namespaces per component - Mix local and registry images
Tag-Only Modeยถ
To tag images without pushing (useful for testing):
registry:
enabled: true
url: registry.example.com
namespace: myproject
push: false # Tag but don't push
Use cases: - Test registry configuration before pushing - Generate manifests with registry paths for GitOps - Manual push workflow
Troubleshootingยถ
Authentication Errorsยถ
Error: Failed to push to registry: unauthorized
Solution: Authenticate to the registry before building:
# Docker Hub
docker login
# Quay.io
podman login quay.io
# Private registry
podman login registry.mycompany.com -u myusername
# OpenShift
podman login $(oc registry info) -u $(oc whoami) -p $(oc whoami -t)
ImagePullBackOff in Kubernetesยถ
Error: Pods show ImagePullBackOff status
Possible causes: 1. Image doesn't exist in registry (push failed) 2. Registry authentication not configured in Kubernetes 3. Network connectivity issues 4. Wrong image path/tag
Solutions:
1. Verify image exists:
# OpenShift
oc get imagestreams -n mcp-gateway-test
# Docker Hub/Quay
podman search your-registry.com/namespace/image-name
2. Configure Kubernetes pull secrets:
# Create docker-registry secret
kubectl create secret docker-registry regcred \
--docker-server=registry.example.com \
--docker-username=myusername \
--docker-password=mypassword \
--docker-email=myemail@example.com \
-n mcp-gateway-test
# Update deployment to use secret (manual step, or add to template)
3. For OpenShift, grant pull permissions:
# Allow default service account to pull from namespace
oc policy add-role-to-user system:image-puller \
system:serviceaccount:mcp-gateway-test:default \
-n mcp-gateway-test
Push Failed: Too Largeยถ
Error: image push failed: blob upload exceeds max size
Solution: Some registries have size limits. Options: 1. Use multi-stage builds to reduce image size 2. Switch to a registry with larger limits 3. Split into smaller images
Podman Trying HTTP Instead of HTTPS (OpenShift/CRC)ยถ
Error: pinging container registry ...: Get "http://...: dial tcp 127.0.0.1:80: connection refused
Cause: Podman doesn't know the registry uses HTTPS and defaults to HTTP on port 80.
Solution: Configure podman to use HTTPS for the registry:
# SSH into podman machine and configure registries.conf
podman machine ssh -- "sudo bash -c '
if ! grep -q \"default-route-openshift-image-registry.apps-crc.testing\" /etc/containers/registries.conf 2>/dev/null; then
echo \"\" >> /etc/containers/registries.conf
echo \"[[registry]]\" >> /etc/containers/registries.conf
echo \"location = \\\"default-route-openshift-image-registry.apps-crc.testing\\\"\" >> /etc/containers/registries.conf
echo \"insecure = true\" >> /etc/containers/registries.conf
echo \"Registry configuration added\"
else
echo \"Registry already configured\"
fi
'"
# Restart podman machine
podman machine restart
# Wait for restart
sleep 10
# Verify you can now push
podman push default-route-openshift-image-registry.apps-crc.testing/namespace/image:tag
Alternative solution: Use the internal registry service name instead of the route:
This bypasses the external route and connects directly to the internal service (HTTPS on port 5000).
Registry URL Formatยถ
Correct formats:
url: docker.io # Docker Hub
url: quay.io # Quay.io
url: gcr.io # Google Container Registry
url: registry.mycompany.com # Private registry
url: default-route-openshift-image-registry.apps-crc.testing # OpenShift
Incorrect formats:
url: https://docker.io # No protocol
url: docker.io/myusername # No namespace in URL
url: registry:5000 # Include port in URL, not namespace
Best Practicesยถ
โ
DO: - Authenticate to registry before building - Use specific version tags in production (not :latest) - Test registry configuration with push: false first - Use image_pull_policy: Always for development - Use image_pull_policy: IfNotPresent for production - Organize images by namespace/project
โ DON'T: - Commit registry credentials to Git - Use latest tag in production - Mix local and registry images without testing - Skip authentication step - Use push: true for testing without verifying first
Example Configurationsยถ
Full examples available in: - examples/deployment-configs/deploy-openshift-local.yaml - Registry config commented - examples/deployment-configs/deploy-openshift-local-registry.yaml - Full registry setup
Deployment Modesยถ
Plain Python Mode (Default)ยถ
What is it? Pure Python implementation using standard tools (docker, kubectl, git, etc.). This is the default mode to avoid automatic downloads.
When to use: - โ Default choice (no surprises) - โ Environments without Dagger support - โ Air-gapped networks - โ Simple deployments - โ Debugging/troubleshooting
Requirements: - Python 3.11+ - Docker CLI - kubectl (for Kubernetes deployments) - git (for building from source)
Usage:
Characteristics: - Sequential builds - Standard caching - No external dependencies beyond Docker/kubectl
Dagger Mode (Opt-in)ยถ
What is Dagger? Dagger is a programmable CI/CD engine that runs pipelines in containers. It provides: - Reproducible builds: Same results everywhere - Parallel execution: Faster builds - Intelligent caching: Only rebuild what changed - Cross-platform: Works on any system with Docker
When to use: - โ Local development (fastest builds) - โ CI/CD pipelines (GitHub Actions, GitLab CI, etc.) - โ Team environments (consistent results) - โ When you want optimized build performance
Requirements: - Docker or compatible container runtime - dagger-io Python package (optional, installed separately) - Note: First use will auto-download the Dagger CLI (~100MB)
Enable:
# Install dagger-io package first
pip install dagger-io
# Use Dagger mode (opt-in with --dagger flag)
cforge gateway --dagger deploy deploy.yaml
Performance benefits: - 2-3x faster builds with caching - Parallel plugin builds - Efficient layer reuse
Important: Using --dagger will automatically download the Dagger CLI binary on first use if not already present. Use plain Python mode if you want to avoid automatic downloads
CI/CD Integrationยถ
GitHub Actionsยถ
name: Deploy MCP Gateway
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install cforge
run: pip install -e .
- name: Validate configuration
run: cforge gateway validate deploy/deploy-prod.yaml
- name: Build containers
run: cforge gateway build deploy/deploy-prod.yaml
env:
DOCKER_REGISTRY: ${{ secrets.DOCKER_REGISTRY }}
- name: Generate certificates
run: cforge gateway certs deploy/deploy-prod.yaml
- name: Deploy to Kubernetes
run: cforge gateway deploy deploy/deploy-prod.yaml --skip-build
env:
KUBECONFIG: ${{ secrets.KUBECONFIG }}
- name: Verify deployment
run: cforge gateway verify deploy/deploy-prod.yaml
GitLab CIยถ
stages:
- validate
- build
- deploy
variables:
CONFIG_FILE: deploy/deploy-prod.yaml
validate:
stage: validate
script:
- pip install -e .
- cforge gateway validate $CONFIG_FILE
build:
stage: build
script:
- pip install -e .
- cforge gateway build $CONFIG_FILE
artifacts:
paths:
- deploy/
deploy:
stage: deploy
script:
- pip install -e .
- cforge gateway deploy $CONFIG_FILE --skip-build
environment:
name: production
only:
- main
Best Practicesยถ
Configuration Managementยถ
โ
DO: - Version control your deploy.yaml - Use Git tags/branches for plugin versions (ref: v1.2.3) - Separate configs for dev/staging/prod - Document custom env_vars in comments
โ DON'T: - Hardcode secrets in YAML (use environment files) - Use ref: main in production (pin versions) - Commit generated certificates to Git
Environment Variablesยถ
โ DO:
# Review and customize .env files after build
cforge gateway build deploy.yaml
# Edit deploy/env/.env.gateway
# Edit deploy/env/.env.PluginName
cforge gateway deploy deploy.yaml --skip-build
โ DON'T:
# Deploy without reviewing environment
cforge gateway deploy deploy.yaml # May use default/insecure values
Certificate Managementยถ
โ
DO: - Let cforge auto-generate certificates - Rotate certificates before expiry - Use separate CAs for dev/staging/prod - Backup CA private key securely
โ DON'T: - Share certificates between environments - Commit CA private key to Git - Use expired certificates
Resource Limitsยถ
โ DO:
gateway:
memory_request: 256Mi
memory_limit: 512Mi # 2x request for burst capacity
cpu_request: 100m
cpu_limit: 500m # Allow bursting
โ DON'T:
High Availabilityยถ
โ DO:
gateway:
replicas: 2 # Multiple replicas
service_type: LoadBalancer
plugins:
- name: CriticalPlugin
replicas: 2 # HA for critical plugins
โ DON'T:
Troubleshootingยถ
Build Issuesยถ
Problem: Git clone fails
Solution: - Check repo URL is correct - Verify Git credentials/SSH keys - Ensure network connectivity - For private repos, configure Git auth
Problem: Docker build fails
Solution: 1. Check context and containerfile paths 2. Verify Containerfile syntax 3. Review plugin repository structure 4. Try building manually:
Deployment Issuesยถ
Problem: Pod/container fails to start
Solution: 1. Check logs:
# Kubernetes
kubectl logs -n <namespace> <pod-name>
# Docker Compose
docker-compose -f deploy/docker-compose.yaml logs <service>
deploy/env/ 3. Check resource limits (may be too low) 4. Verify image was built/pulled correctly Problem: mTLS connection fails
Solution: 1. Regenerate certificates:
2. Redeploy to distribute new certs: 3. Check certificate expiry:Verification Issuesยถ
Problem: Deployment verification timeout
Solution: 1. Increase timeout:
2. Check pod/container status manually 3. Review resource availability (CPU/memory) 4. Check for image pull errorsFAQยถ
Q: Can I use pre-built images instead of building from source?
A: Yes! Just specify image instead of repo:
Q: How do I update a plugin to a new version?
A: Update the ref and redeploy:
Then:
cforge gateway build deploy.yaml --plugin MyPlugin --no-cache
cforge gateway deploy deploy.yaml --skip-certs
Q: Can I deploy only the gateway without plugins?
A: Yes, just omit the plugins section or use an empty array:
Q: How do I add custom environment variables?
A: Two ways:
1. In YAML (committed to Git):
2. In .env file (not committed):
Q: Can I use cforge in a CI/CD pipeline?
A: Absolutely! See CI/CD Integration section above.
Q: How do I switch between Dagger and plain Python modes?
A:
# Plain Python mode (default)
cforge gateway deploy deploy.yaml
# Dagger mode (opt-in, requires dagger-io package)
cforge gateway --dagger deploy deploy.yaml
Note: Dagger mode requires installing the dagger-io package and will auto-download the Dagger CLI (~100MB) on first use
Q: Where are the generated manifests stored?
A: Default: deploy/ directory - deploy/docker-compose.yaml (Compose mode) - deploy/manifests/ (Kubernetes mode)
Custom location:
Q: How do I access the gateway after deployment?
A: - Docker Compose: http://localhost:<host_port> (default: 4444) - Kubernetes LoadBalancer: Get external IP:
Additional Resourcesยถ
- Main Documentation: ContextForge Documentation
- Plugin Development: Plugin Framework Guide
- mTLS Setup: mTLS Configuration Guide
- Example Configs:
examples/deployment-configs/ - Source Code:
mcpgateway/tools/builder/
Getting Helpยถ
If you encounter issues:
- Check logs: Review detailed error messages
- Validate config: Run
cforge gateway validate deploy.yaml - Dry-run: Test with
cforge gateway deploy deploy.yaml --dry-run - Verbose mode: Use
cforge gateway -v <command>for detailed output - Debug mode: Set
export MCP_DEBUG=1for stack traces - GitHub Issues: Report bugs and request features