Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
6d27621
mTLS support
crivetimihai Sep 27, 2025
80df546
feat: added mTLS support to plugin mcp servers.
Oct 2, 2025
37d0eb5
merge: merged main into this branch.
Oct 2, 2025
196568d
fix: added streamable http support to runtime_mtls.py
Oct 2, 2025
66be241
fix: updated plugin server runtime.py to support mTLS. removed chuck-…
Oct 3, 2025
a5358d9
fix: switched chuk-mcp-runtime with mcp python sdk to support mTLS.
Oct 3, 2025
6d9bf90
fix: updated llmguard and opa plugins to install the mcp official sdk.
Oct 3, 2025
ba4e215
feat: added health check to plugin server runtimes.
Oct 6, 2025
214490d
fix: added health check for mtls plugin server
Oct 6, 2025
36b2b13
fix: removed chuk-mcp-runtime, replaced with official mcp library.
Oct 9, 2025
89b94ae
Merge branch 'main' into feat/plugin-client-server-mtls-support
Oct 9, 2025
fa69055
fix: runtime tests.
Oct 9, 2025
1f4e01e
feat: initial revision of configurable plugin builds.
Oct 9, 2025
c9d5ea6
docs: added mtls plugin documentation.
Oct 9, 2025
0001944
fix: linting issues.
Oct 9, 2025
254021d
Merge branch 'main' into feat/plugin-client-server-mtls-support
Oct 9, 2025
23c4ba5
Merge branch 'feat/plugin-client-server-mtls-support' into feat/confi…
Oct 9, 2025
5793e5f
fix: install templates with cli, fix error messages.
Oct 10, 2025
15a1af1
fix: mtls and stdio test cases.
Oct 10, 2025
4046e79
fix: remove commented code.
Oct 10, 2025
b0a073d
Merge branch 'main' into feat/plugin-client-server-mtls-support
Oct 10, 2025
773b463
Merge branch 'feat/plugin-client-server-mtls-support' into feat/confi…
Oct 10, 2025
422395e
docs: and examples
Oct 10, 2025
50e9da5
fix: docstring issues
Oct 10, 2025
92e564a
tests: added unit tests and more commenting.
Oct 10, 2025
0ef7d5f
tests: add tests. Fix doc tests.
Oct 14, 2025
5d3d8c6
fix: change to make python the default.
Oct 14, 2025
ba0888f
fix: bandit issue.
Oct 14, 2025
90c531e
fix: updated key length to 4096
Oct 14, 2025
0ed34fe
fix: utility function for verifying certificates.
Oct 14, 2025
b4b55cc
fix: added utility class for ssl certificate verification.
Oct 15, 2025
054a599
test: added certificate validation tests.
Oct 15, 2025
94be45e
feat: added support for cert-manager in k8s.
Oct 15, 2025
cc5b925
Merge branch 'feat/plugin-client-server-mtls-support' into feat/confi…
Oct 15, 2025
eae3a3b
tests: skipped tls doctest.
Oct 15, 2025
0c7f478
Merge branch 'feat/plugin-client-server-mtls-support' into feat/confi…
Oct 15, 2025
b1c279c
test: fix doctests.
Oct 15, 2025
88d2f27
fix: added example cert-manager issuer file.
Oct 15, 2025
e083fb0
docs: updated mtls documentation to point to plugins mtls documentation.
Oct 15, 2025
754a9c4
fix: forgot to add deploy-k8s-cert-manager.yaml
Oct 15, 2025
7926340
feat: add registry pushing support. clean up pydantics.
Oct 16, 2025
3cf32c3
fix: fixes to support Openshift, and support enabling plugins in k8s.
Oct 17, 2025
68bd4bd
feat: added openshift route file for installing route to mcpgateway a…
Oct 17, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,15 @@ PLUGINS_ENABLED=true
# Default: plugins/config.yaml
PLUGIN_CONFIG_FILE=plugins/config.yaml

# Optional defaults for mTLS when connecting to external MCP plugins (STREAMABLEHTTP transport)
# Provide file paths inside the container. Plugin-specific TLS blocks override these defaults.
# PLUGINS_MTLS_CA_BUNDLE=/app/certs/plugins/ca.crt
# PLUGINS_MTLS_CLIENT_CERT=/app/certs/plugins/gateway-client.pem
# PLUGINS_MTLS_CLIENT_KEY=/app/certs/plugins/gateway-client.key
# PLUGINS_MTLS_CLIENT_KEY_PASSWORD=
# PLUGINS_MTLS_VERIFY=true
# PLUGINS_MTLS_CHECK_HOSTNAME=true

#####################################
# Well-Known URI Configuration
#####################################
Expand Down
150 changes: 143 additions & 7 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -141,12 +141,6 @@ update:
check-env:
@echo "🔎 Validating .env against .env.example using Python (prod)..."
@python -m mcpgateway.scripts.validate_env .env.example
# @echo "🔎 Checking .env against .env.example..."
# @missing=0; \
# for key in $$(grep -Ev '^\s*#|^\s*$$' .env.example | cut -d= -f1); do \
# grep -q "^$$key=" .env || { echo "❌ Missing: $$key"; missing=1; }; \
# done; \
# if [ $$missing -eq 0 ]; then echo "✅ All environment variables are present."; fi

# Validate .env in development mode (warnings do not fail)
check-env-dev:
Expand All @@ -164,11 +158,17 @@ check-env-dev:
# help: certs-jwt - Generate JWT RSA keys in ./certs/jwt/ (idempotent)
# help: certs-jwt-ecdsa - Generate JWT ECDSA keys in ./certs/jwt/ (idempotent)
# help: certs-all - Generate both TLS certs and JWT keys (combo target)
# help: certs-mcp-ca - Generate MCP CA for plugin mTLS (./certs/mcp/ca/)
# help: certs-mcp-gateway - Generate gateway client certificate (./certs/mcp/gateway/)
# help: certs-mcp-plugin - Generate plugin server certificate (requires PLUGIN_NAME=name)
# help: certs-mcp-all - Generate complete MCP mTLS infrastructure (reads plugins from config.yaml)
# help: certs-mcp-check - Check expiry dates of MCP certificates
# help: serve-ssl - Run Gunicorn behind HTTPS on :4444 (uses ./certs)
# help: dev - Run fast-reload dev server (uvicorn)
# help: run - Execute helper script ./run.sh

.PHONY: serve serve-ssl dev run certs certs-jwt certs-jwt-ecdsa certs-all
.PHONY: serve serve-ssl dev run certs certs-jwt certs-jwt-ecdsa certs-all \
certs-mcp-ca certs-mcp-gateway certs-mcp-plugin certs-mcp-all certs-mcp-check

## --- Primary servers ---------------------------------------------------------
serve:
Expand Down Expand Up @@ -231,6 +231,142 @@ certs-all: certs certs-jwt ## Generate both TLS certificates and JWT RSA k
@echo "📁 JWT: ./certs/jwt/{private,public}.pem"
@echo "💡 Use JWT_ALGORITHM=RS256 with JWT_PUBLIC_KEY_PATH=certs/jwt/public.pem"

## --- MCP Plugin mTLS Certificate Management ----------------------------------
# Default validity period for MCP certificates (in days)
MCP_CERT_DAYS ?= 825

# Plugin configuration file for automatic certificate generation
MCP_PLUGIN_CONFIG ?= plugins/external/config.yaml

certs-mcp-ca: ## Generate CA for MCP plugin mTLS
@if [ -f certs/mcp/ca/ca.key ] && [ -f certs/mcp/ca/ca.crt ]; then \
echo "🔐 Existing MCP CA found in ./certs/mcp/ca - skipping generation."; \
echo "⚠️ To regenerate, delete ./certs/mcp/ca and run again."; \
else \
echo "🔐 Generating MCP Certificate Authority ($(MCP_CERT_DAYS) days validity)..."; \
mkdir -p certs/mcp/ca; \
openssl genrsa -out certs/mcp/ca/ca.key 4096; \
openssl req -new -x509 -key certs/mcp/ca/ca.key -out certs/mcp/ca/ca.crt \
-days $(MCP_CERT_DAYS) \
-subj "/CN=MCP-Gateway-CA/O=MCPGateway/OU=Plugins"; \
echo "01" > certs/mcp/ca/ca.srl; \
echo "✅ MCP CA created: ./certs/mcp/ca/ca.{key,crt}"; \
fi
@chmod 600 certs/mcp/ca/ca.key
@chmod 644 certs/mcp/ca/ca.crt
@echo "🔒 Permissions set: ca.key (600), ca.crt (644)"

certs-mcp-gateway: certs-mcp-ca ## Generate gateway client certificate
@if [ -f certs/mcp/gateway/client.key ] && [ -f certs/mcp/gateway/client.crt ]; then \
echo "🔐 Existing gateway client certificate found - skipping generation."; \
else \
echo "🔐 Generating gateway client certificate ($(MCP_CERT_DAYS) days)..."; \
mkdir -p certs/mcp/gateway; \
openssl genrsa -out certs/mcp/gateway/client.key 4096; \
openssl req -new -key certs/mcp/gateway/client.key \
-out certs/mcp/gateway/client.csr \
-subj "/CN=mcp-gateway-client/O=MCPGateway/OU=Gateway"; \
openssl x509 -req -in certs/mcp/gateway/client.csr \
-CA certs/mcp/ca/ca.crt -CAkey certs/mcp/ca/ca.key \
-CAcreateserial -out certs/mcp/gateway/client.crt \
-days $(MCP_CERT_DAYS) -sha256; \
rm certs/mcp/gateway/client.csr; \
cp certs/mcp/ca/ca.crt certs/mcp/gateway/ca.crt; \
echo "✅ Gateway client certificate created: ./certs/mcp/gateway/"; \
fi
@chmod 600 certs/mcp/gateway/client.key
@chmod 644 certs/mcp/gateway/client.crt certs/mcp/gateway/ca.crt
@echo "🔒 Permissions set: client.key (600), client.crt (644), ca.crt (644)"

certs-mcp-plugin: certs-mcp-ca ## Generate plugin server certificate (PLUGIN_NAME=name)
@if [ -z "$(PLUGIN_NAME)" ]; then \
echo "❌ ERROR: PLUGIN_NAME not set"; \
echo "💡 Usage: make certs-mcp-plugin PLUGIN_NAME=my-plugin"; \
exit 1; \
fi
@if [ -f certs/mcp/plugins/$(PLUGIN_NAME)/server.key ] && \
[ -f certs/mcp/plugins/$(PLUGIN_NAME)/server.crt ]; then \
echo "🔐 Existing certificate for plugin '$(PLUGIN_NAME)' found - skipping."; \
else \
echo "🔐 Generating server certificate for plugin '$(PLUGIN_NAME)' ($(MCP_CERT_DAYS) days)..."; \
mkdir -p certs/mcp/plugins/$(PLUGIN_NAME); \
openssl genrsa -out certs/mcp/plugins/$(PLUGIN_NAME)/server.key 4096; \
openssl req -new -key certs/mcp/plugins/$(PLUGIN_NAME)/server.key \
-out certs/mcp/plugins/$(PLUGIN_NAME)/server.csr \
-subj "/CN=mcp-plugin-$(PLUGIN_NAME)/O=MCPGateway/OU=Plugins"; \
openssl x509 -req -in certs/mcp/plugins/$(PLUGIN_NAME)/server.csr \
-CA certs/mcp/ca/ca.crt -CAkey certs/mcp/ca/ca.key \
-CAcreateserial -out certs/mcp/plugins/$(PLUGIN_NAME)/server.crt \
-days $(MCP_CERT_DAYS) -sha256 \
-extfile <(printf "subjectAltName=DNS:$(PLUGIN_NAME),DNS:mcp-plugin-$(PLUGIN_NAME),DNS:localhost"); \
rm certs/mcp/plugins/$(PLUGIN_NAME)/server.csr; \
cp certs/mcp/ca/ca.crt certs/mcp/plugins/$(PLUGIN_NAME)/ca.crt; \
echo "✅ Plugin '$(PLUGIN_NAME)' certificate created: ./certs/mcp/plugins/$(PLUGIN_NAME)/"; \
fi
@chmod 600 certs/mcp/plugins/$(PLUGIN_NAME)/server.key
@chmod 644 certs/mcp/plugins/$(PLUGIN_NAME)/server.crt certs/mcp/plugins/$(PLUGIN_NAME)/ca.crt
@echo "🔒 Permissions set: server.key (600), server.crt (644), ca.crt (644)"

certs-mcp-all: certs-mcp-ca certs-mcp-gateway ## Generate complete mTLS infrastructure
@echo "🔐 Generating certificates for plugins..."
@# Read plugin names from config file if it exists
@if [ -f "$(MCP_PLUGIN_CONFIG)" ]; then \
echo "📋 Reading plugin names from $(MCP_PLUGIN_CONFIG)"; \
python3 -c "import yaml; \
config = yaml.safe_load(open('$(MCP_PLUGIN_CONFIG)')); \
plugins = [p['name'] for p in config.get('plugins', []) if p.get('kind') == 'external']; \
print('\n'.join(plugins))" 2>/dev/null | while read plugin_name; do \
if [ -n "$$plugin_name" ]; then \
echo " Generating for: $$plugin_name"; \
$(MAKE) certs-mcp-plugin PLUGIN_NAME="$$plugin_name"; \
fi; \
done || echo "⚠️ PyYAML not installed or config parse failed, generating example plugins..."; \
fi
@# Fallback to example plugins if no config or parsing failed
@if [ ! -f "$(MCP_PLUGIN_CONFIG)" ] || ! python3 -c "import yaml" 2>/dev/null; then \
echo "🔐 Generating certificates for example plugins..."; \
$(MAKE) certs-mcp-plugin PLUGIN_NAME=example-plugin-a; \
$(MAKE) certs-mcp-plugin PLUGIN_NAME=example-plugin-b; \
fi
@echo ""
@echo "🎯 MCP mTLS infrastructure generated successfully!"
@echo "📁 Structure:"
@echo " certs/mcp/ca/ - Certificate Authority"
@echo " certs/mcp/gateway/ - Gateway client certificate"
@echo " certs/mcp/plugins/*/ - Plugin server certificates"
@echo ""
@echo "💡 Generate additional plugin certificates with:"
@echo " make certs-mcp-plugin PLUGIN_NAME=your-plugin-name"
@echo ""
@echo "💡 Certificate validity: $(MCP_CERT_DAYS) days"
@echo " To change: make certs-mcp-all MCP_CERT_DAYS=365"

certs-mcp-check: ## Check expiry dates of MCP certificates
@echo "🔍 Checking MCP certificate expiry dates..."
@echo ""
@if [ -f certs/mcp/ca/ca.crt ]; then \
echo "📋 CA Certificate:"; \
openssl x509 -in certs/mcp/ca/ca.crt -noout -enddate | sed 's/notAfter=/ Expires: /'; \
echo ""; \
fi
@if [ -f certs/mcp/gateway/client.crt ]; then \
echo "📋 Gateway Client Certificate:"; \
openssl x509 -in certs/mcp/gateway/client.crt -noout -enddate | sed 's/notAfter=/ Expires: /'; \
echo ""; \
fi
@if [ -d certs/mcp/plugins ]; then \
echo "📋 Plugin Certificates:"; \
for plugin_dir in certs/mcp/plugins/*; do \
if [ -f "$$plugin_dir/server.crt" ]; then \
plugin_name=$$(basename "$$plugin_dir"); \
expiry=$$(openssl x509 -in "$$plugin_dir/server.crt" -noout -enddate | sed 's/notAfter=//'); \
echo " $$plugin_name: $$expiry"; \
fi; \
done; \
echo ""; \
fi
@echo "💡 To regenerate expired certificates, delete the cert directory and run make certs-mcp-all"

## --- House-keeping -----------------------------------------------------------
# help: clean - Remove caches, build artefacts, virtualenv, docs, certs, coverage, SBOM, database files, etc.
.PHONY: clean
Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1623,6 +1623,12 @@ MCP Gateway uses Alembic for database migrations. Common commands:
| ------------------------------ | ------------------------------------------------ | --------------------- | ------- |
| `PLUGINS_ENABLED` | Enable the plugin framework | `false` | bool |
| `PLUGIN_CONFIG_FILE` | Path to main plugin configuration file | `plugins/config.yaml` | string |
| `PLUGINS_MTLS_CA_BUNDLE` | (Optional) default CA bundle for external plugin mTLS | _(empty)_ | string |
| `PLUGINS_MTLS_CLIENT_CERT` | (Optional) gateway client certificate for plugin mTLS | _(empty)_ | string |
| `PLUGINS_MTLS_CLIENT_KEY` | (Optional) gateway client key for plugin mTLS | _(empty)_ | string |
| `PLUGINS_MTLS_CLIENT_KEY_PASSWORD` | (Optional) password for plugin client key | _(empty)_ | string |
| `PLUGINS_MTLS_VERIFY` | (Optional) verify remote plugin certificates (`true`/`false`) | `true` | bool |
| `PLUGINS_MTLS_CHECK_HOSTNAME` | (Optional) enforce hostname verification for plugins | `true` | bool |
| `PLUGINS_CLI_COMPLETION` | Enable auto-completion for plugins CLI | `false` | bool |
| `PLUGINS_CLI_MARKUP_MODE` | Set markup mode for plugins CLI | (none) | `rich`, `markdown`, `disabled` |

Expand Down
6 changes: 6 additions & 0 deletions charts/mcp-stack/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,12 @@ mcpContextForge:
# ─ Plugin Configuration ─
PLUGINS_ENABLED: "false" # enable the plugin framework
PLUGIN_CONFIG_FILE: "plugins/config.yaml" # path to main plugin configuration file
PLUGINS_MTLS_CA_BUNDLE: "" # default CA bundle for external plugins (optional)
PLUGINS_MTLS_CLIENT_CERT: "" # gateway client certificate for plugin mTLS
PLUGINS_MTLS_CLIENT_KEY: "" # gateway client key for plugin mTLS (optional)
PLUGINS_MTLS_CLIENT_KEY_PASSWORD: "" # password for the plugin client key (optional)
PLUGINS_MTLS_VERIFY: "true" # verify remote plugin certificates
PLUGINS_MTLS_CHECK_HOSTNAME: "true" # enforce hostname verification when verifying certs
PLUGINS_CLI_COMPLETION: "false" # enable auto-completion for plugins CLI
PLUGINS_CLI_MARKUP_MODE: "" # set markup mode for plugins CLI

Expand Down
1 change: 1 addition & 0 deletions docs/docs/deployment/.pages
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ nav:
- azure.md
- fly-io.md
- proxy-auth.md
- cforge-gateway.md
Loading