-
Notifications
You must be signed in to change notification settings - Fork 425
feat: mcpgateway and plugin deployment as a configuration yaml. #1207
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
terylt
wants to merge
54
commits into
IBM:main
Choose a base branch
from
terylt:feat/configurable_plugin_deployment
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+11,027
−957
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
Signed-off-by: Teryl Taylor <terylt@ibm.com>
Signed-off-by: Teryl Taylor <terylt@ibm.com>
Signed-off-by: Teryl Taylor <terylt@ibm.com>
…mcp-runtime Signed-off-by: Teryl Taylor <terylt@ibm.com>
Signed-off-by: Teryl Taylor <terylt@ibm.com>
Signed-off-by: Teryl Taylor <terylt@ibm.com>
Signed-off-by: Teryl Taylor <terylt@ibm.com>
Signed-off-by: Teryl Taylor <terylt@ibm.com>
Signed-off-by: Teryl Taylor <terylt@ibm.com>
Signed-off-by: Teryl Taylor <terylt@ibm.com>
Signed-off-by: Teryl Taylor <terylt@ibm.com>
Signed-off-by: Teryl Taylor <terylt@ibm.com>
Signed-off-by: Teryl Taylor <terylt@ibm.com>
…gurable_plugin_deployment
Signed-off-by: Teryl Taylor <terylt@ibm.com>
Signed-off-by: Teryl Taylor <terylt@ibm.com>
Signed-off-by: Teryl Taylor <terylt@ibm.com>
…gurable_plugin_deployment
Signed-off-by: Teryl Taylor <terylt@ibm.com>
Signed-off-by: Teryl Taylor <terylt@ibm.com>
Signed-off-by: Teryl Taylor <terylt@ibm.com>
Signed-off-by: Teryl Taylor <terylt@ibm.com>
Signed-off-by: Teryl Taylor <terylt@ibm.com>
Signed-off-by: Teryl Taylor <terylt@ibm.com>
Signed-off-by: Teryl Taylor <terylt@ibm.com>
Signed-off-by: Teryl Taylor <terylt@ibm.com>
Signed-off-by: Teryl Taylor <terylt@ibm.com>
Signed-off-by: Teryl Taylor <terylt@ibm.com>
Signed-off-by: Teryl Taylor <terylt@ibm.com>
…dmin site. Signed-off-by: Teryl Taylor <terylt@ibm.com>
Signed-off-by: Teryl Taylor <terylt@ibm.com>
Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
araujof
approved these changes
Nov 26, 2025
Member
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
This PR introduces a YAML-based deployment workflow for MCP Gateway and its plugins, providing a single configuration source for build, deployment, and basic security settings.
Summary
- The configuration model covers gateway, plugins, certificates, and supporting services, enabling repeatable deployments across Docker Compose and Kubernetes environments.
- The tooling adds validate/build/certs/deploy/verify/destroy commands, health checks, and CI examples that make it easier to integrate into automated pipelines.
Suggestions for improvement
- The documentation is detailed; a short “minimal config” example near the top could help new users onboard more quickly.
Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
Signed-off-by: Frederico Araujo <frederico.araujo@ibm.com>
Signed-off-by: Teryl Taylor <terylt@ibm.com>
…lt/mcp-context-forge into feat/configurable_plugin_deployment
Signed-off-by: Teryl Taylor <terylt@ibm.com>
7 tasks
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
cforge gateway - Deployment Tool
Closes #1148
Overview
The
cforge gatewaycommand 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.Why We Created It
Before
cforge gateway, deploying MCP Gateway with external plugins required:cforge gatewaysolves these challenges by:✅ Automating the entire deployment pipeline from source to running services
✅ Managing mTLS certificates automatically with proper distribution
✅ Generating deployment manifests (Kubernetes or Docker Compose) from a single source
✅ Supporting multiple build modes (Dagger for performance, plain Python for portability)
✅ Validating configurations before deployment
✅ Integrating with CI/CD workflows and secret management
Features
Build System
Deployment Targets
Security
Workflow Automation
cforge gateway - Deployment Tool
Overview
The
cforge gatewaycommand 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
cforgeCLI is installed with the MCP Gateway package:pip install -e .Verify installation:
Basic Workflow
Simple Configuration Example
The
cforge gatewaytool uses custom YAML configuration files to describe your deployment. These are not standard Docker Compose or Kubernetes manifests - instead,cforgereads these configuration files and generates the actual deployment manifests for your target environment.Here's a minimal example configuration that demonstrates the key components:
Key sections explained:
How it works:
When you run
cforge gateway deploy <config-file>, the tool:type: compose→deploy/docker-compose.yamltype: kubernetes→deploy/manifests/*.yaml(Deployment, Service, ConfigMap, etc.)Additional example configurations are available in
examples/deployment-configs/:deploy-compose.yaml- Docker Compose without mTLSdeploy-compose.mtls.yaml- Docker Compose with mTLSdeploy-k8s.yaml- Kubernetes with pre-built imagesdeploy-k8s-cert-manager.yaml- Kubernetes with cert-manager integrationSee the Example Configurations section below for detailed examples with full explanations.
Commands
cforge gateway validateValidates the deployment configuration file without making any changes.
Example:
Output:
cforge gateway buildBuilds container images for gateway and/or plugins from source repositories.
Options:
--plugins-onlyfalse--plugin NAME,-p NAME--no-cachefalse--copy-env-templates.env.templatefiles from plugin repostrueExamples:
What it does:
repospecified)ref)containerfileincontextdirectory.env.templatefiles todeploy/env/for customizationcforge gateway certsGenerates mTLS certificate hierarchy for secure gateway ↔ plugin communication.
Example:
What it generates:
Certificate Properties:
mcp-gatewaymcp-plugin-{PluginName}{PluginName}, mcp-plugin-{PluginName}, localhostcforge gateway deployDeploys the complete MCP stack to the target environment.
Options:
--output-dir DIR,-o DIRdeploy/--dry-runfalse--skip-buildfalse--skip-certsfalseExamples:
Deployment Process:
--skip-build)--skip-certsor already exist)kubectl apply -fdocker-compose up -dGenerated Files:
cforge gateway verifyVerifies that the deployed stack is healthy and running.
Options:
--waittrue--timeout SECONDS300Examples:
Checks:
cforge gateway destroyTears down the deployed MCP stack.
Options:
--forcefalseExamples:
What it removes:
cforge gateway generateGenerates deployment manifests without deploying them.
Options:
--output DIR,-o DIRdeploy/Examples:
Use cases:
cforge gateway versionShows version and runtime information.
Output:
Global Options
These options apply to all commands:
--daggerfalse(uses plain Python)--verbose,-vfalseExamples:
Configuration Reference
Deployment Configuration
Top-level deployment settings:
typekubernetesorcomposeproject_namenamespacecontainer_enginedockerorpodmanopenshiftOpenShift Configuration
OpenShift Routes provide native external access to services, with built-in TLS termination and integration with OpenShift's router/HAProxy infrastructure.
create_routesfalsedomaintls_terminationedge,passthrough, orreencryptedgeExample:
When
create_routes: true, the tool generates an OpenShift Route for the gateway:mcpgateway-admin-{namespace}.{domain}/Access the gateway:
# OpenShift Local (CRC) example https://mcpgateway-admin-mcp-gateway-test.apps-crc.testingDomain auto-detection:
If
domainis not specified, the tool attempts to auto-detect the OpenShift apps domain from the cluster:kubectl get ingresses.config.openshift.io cluster -o jsonpath='{.spec.domain}'If auto-detection fails, it defaults to
apps-crc.testing(OpenShift Local).Gateway Configuration
Gateway server settings:
Build Configuration Fields:
imagereporefmaincontext.containerfileContainerfiletarget* Either
imageORrepomust be specifiedRuntime Configuration Fields:
port4444host_portenv_vars{}mtls_enabledtruemtls_verifytruemtls_check_hostnamefalseregistryContainer Registry Configuration Fields:
enabledfalseurldocker.io,quay.io, OpenShift registry)namespacepushtrueimage_pull_policyAlways,IfNotPresent,Never)IfNotPresent* Required when
enabled: trueKubernetes-specific Fields:
replicas1service_typeClusterIPservice_port4444memory_request256Mimemory_limit512Micpu_request100mcpu_limit500mimage_pull_policyIfNotPresentPlugin Configuration
External plugin settings (array of plugin objects):
Required Fields:
nameBuild Configuration: Same as Gateway (see above)
Runtime Configuration:
port8000expose_portfalseenv_vars{}mtls_enabledtrueregistryplugin_overrides{}Plugin Overrides:
prioritymodeenforce,monitor, ordry-rundescriptiontagshooksprompt_pre_fetch,tool_pre_invoke, etc.Kubernetes-specific: Same as Gateway (see above)
Certificate Configuration
mTLS certificate generation settings:
validity_days825auto_generatetrueca_path./certs/mcp/cagateway_path./certs/mcp/gatewayplugins_path./certs/mcp/pluginsuse_cert_managerfalsecert_manager_issuermcp-ca-issuercert_manager_kindIssuerorClusterIssuerIssuercert-manager Integration (Kubernetes Only)
cert-manager is a Kubernetes-native certificate management controller that automates certificate issuance and renewal.
Benefits:
Prerequisites:
Install cert-manager in your cluster:
Create namespace and CA Issuer (one-time setup):
Configuration:
When
use_cert_manager: true: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):
postgres:17mcppostgresmysecretpassword(override withPOSTGRES_PASSWORDenv var)5432Redis (always deployed):
redis:latest6379Connection strings (auto-configured):
DATABASE_URL=postgresql://postgres:${POSTGRES_PASSWORD}@postgres:5432/mcp REDIS_URL=redis://redis:6379/0These services are included in all deployments and cannot currently be disabled or customized via the deployment YAML. To customize PostgreSQL password:
Example Configurations
Example 1: Docker Compose (No mTLS)
File:
examples/deployment-configs/deploy-compose.yamlSimple local deployment for development and testing:
Use case: Quick local testing without security overhead
Deploy:
Access:
Example 2: Docker Compose (With mTLS)
File:
examples/deployment-configs/deploy-compose.mtls.yamlSecure local deployment with mutual TLS:
Use case: Local testing with production-like security
Deploy:
# Certificates are auto-generated during deploy cforge gateway deploy examples/deployment-configs/deploy-compose.mtls.yamlHow mTLS works:
cforge gateway certsgenerates CA + gateway client cert + plugin server certsExample 3: Kubernetes (Pre-built Images)
File:
examples/deployment-configs/deploy-k8s.yamlProduction-ready Kubernetes deployment using pre-built images:
Use case: Production deployment with HA and resource limits
Deploy:
Example 4: Kubernetes (Build from Source)
Building plugins from Git repositories in Kubernetes:
Deploy:
Example 5: Kubernetes with cert-manager
File:
examples/deployment-configs/deploy-k8s-cert-manager.yamlProduction deployment using cert-manager for automated certificate management:
Prerequisites:
Install cert-manager:
Create namespace and CA Issuer (one-time setup):
Deploy:
How it works:
cforge gateway deployskips local certificate generationCertificate lifecycle:
mTLS Configuration Guide
Understanding mTLS in MCP Gateway
mTLS (Mutual TLS) provides:
Certificate Hierarchy
Enabling mTLS
In your configuration:
Certificate Generation
Automatic (recommended):
Manual:
Environment Variables
The deployment tool automatically sets these environment variables:
Gateway (client):
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_REQUIREDTroubleshooting mTLS
Problem: Certificate verification fails
Check certificate validity:
Problem: Hostname mismatch errors
Solution: Set
mtls_check_hostname: falsein gateway config, or use service DNS namesProblem: Connection refused
mtls_enabled: trueProblem: 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
push: true)Configuration
Add a
registrysection to your gateway and/or plugin configurations:Configuration Fields:
enabledtrueurldocker.io,quay.io,registry.mycompany.comnamespacemyusername,myorg,mcp-gateway-testpushtrue(default)image_pull_policyIfNotPresent(default)* Required when
enabled: trueCommon Registry Examples
Docker Hub
Authentication:
Quay.io
Authentication:
OpenShift Internal Registry
Authentication:
Private Registry
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):
Image Pull Policies
Choose the appropriate policy for your use case:
AlwaysIfNotPresentNeverWorkflow Example
OpenShift Local Deployment
CI/CD Pipeline Example
Per-Component Configuration
Each component (gateway and plugins) can have different registry settings:
This allows you to:
Tag-Only Mode
To tag images without pushing (useful for testing):
Use cases:
Troubleshooting
Authentication Errors
Error:
Failed to push to registry: unauthorizedSolution: Authenticate to the registry before building:
ImagePullBackOff in Kubernetes
Error: Pods show
ImagePullBackOffstatusPossible causes:
Solutions:
1. Verify image exists:
2. Configure Kubernetes pull secrets:
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-testPush Failed: Too Large
Error:
image push failed: blob upload exceeds max sizeSolution: Some registries have size limits. Options:
Podman Trying HTTP Instead of HTTPS (OpenShift/CRC)
Error:
pinging container registry ...: Get "http://...: dial tcp 127.0.0.1:80: connection refusedCause: Podman doesn't know the registry uses HTTPS and defaults to HTTP on port 80.
Solution: Configure podman to use HTTPS for the registry:
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:
Incorrect formats:
Best Practices
✅ DO:
:latest)push: falsefirstimage_pull_policy: Alwaysfor developmentimage_pull_policy: IfNotPresentfor production❌ DON'T:
latesttag in productionpush: truefor testing without verifying firstExample Configurations
Full examples available in:
examples/deployment-configs/deploy-openshift-local.yaml- Registry config commentedexamples/deployment-configs/deploy-openshift-local-registry.yaml- Full registry setupDeployment 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:
Requirements:
kubectl(for Kubernetes deployments)git(for building from source)Usage:
# Plain Python mode (default, no flag needed) cforge gateway deploy deploy.yamlCharacteristics:
Dagger Mode (Opt-in)
What is Dagger?
Dagger is a programmable CI/CD engine that runs pipelines in containers. It provides:
When to use:
Requirements:
dagger-ioPython package (optional, installed separately)Enable:
Performance benefits:
Important: Using
--daggerwill automatically download the Dagger CLI binary on first use if not already present. Use plain Python mode if you want to avoid automatic downloadsCI/CD Integration
GitHub Actions
GitLab CI
Best Practices
Configuration Management
✅ DO:
deploy.yamlref: v1.2.3)env_varsin comments❌ DON'T:
ref: mainin production (pin versions)Environment Variables
✅ DO:
❌ DON'T:
Certificate Management
✅ DO:
cforgeauto-generate certificates❌ DON'T:
Resource Limits
✅ DO:
❌ DON'T:
High Availability
✅ DO:
❌ DON'T:
Troubleshooting
Build Issues
Problem: Git clone fails
Solution:
repoURL is correctProblem: Docker build fails
Solution:
contextandcontainerfilepathsDeployment Issues
Problem: Pod/container fails to start
Solution:
deploy/env/Problem: mTLS connection fails
Solution:
Verification Issues
Problem: Deployment verification timeout
Solution:
FAQ
Q: Can I use pre-built images instead of building from source?
A: Yes! Just specify
imageinstead ofrepo:Q: How do I update a plugin to a new version?
A: Update the
refand redeploy:Then:
Q: Can I deploy only the gateway without plugins?
A: Yes, just omit the
pluginssection 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):
# deploy/env/.env.gateway CUSTOM_VAR=valueQ: 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:
Note: Dagger mode requires installing the
dagger-iopackage and will auto-download the Dagger CLI (~100MB) on first useQ: Where are the generated manifests stored?
A: Default:
deploy/directorydeploy/docker-compose.yaml(Compose mode)deploy/manifests/(Kubernetes mode)Custom location:
Q: How do I access the gateway after deployment?
A:
http://localhost:<host_port>(default: 4444)Additional Resources
examples/deployment-configs/mcpgateway/tools/builder/Getting Help
If you encounter issues:
cforge gateway validate deploy.yamlcforge gateway deploy deploy.yaml --dry-runcforge gateway -v <command>for detailed outputexport MCP_DEBUG=1for stack traces