From 429bfed0d6fc986dd5f3202b2a5e33374df71d70 Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Wed, 20 May 2026 08:47:51 -0400 Subject: [PATCH] Add TLS support for incoming MCP server connections --- config.yaml.sample | 7 +++++++ src/rhos_ls_mcps/main.py | 10 ++++++++++ src/rhos_ls_mcps/settings.py | 10 +++++++++- 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/config.yaml.sample b/config.yaml.sample index 47aa2c3..d3e8b63 100644 --- a/config.yaml.sample +++ b/config.yaml.sample @@ -16,6 +16,13 @@ openshift: allow_write: false insecure: false +# Incoming TLS settings for the MCP server +#tls: +# ssl_certfile: ./cert.pem +# ssl_keyfile: ./key.pem +# ssl_keyfile_password: null +# ssl_ca_certs: null + mcp_transport_security: token: supersecret enable_dns_rebinding_protection: false diff --git a/src/rhos_ls_mcps/main.py b/src/rhos_ls_mcps/main.py index 360caa1..d1bfad9 100644 --- a/src/rhos_ls_mcps/main.py +++ b/src/rhos_ls_mcps/main.py @@ -108,6 +108,15 @@ def main(): # Pass string instead of an instance to support multiple workers. # Pass the factory=True argument to use a function (create_app) instead of a variable. + ssl_kwargs = {} + if config.tls.ssl_certfile: + ssl_kwargs["ssl_certfile"] = config.tls.ssl_certfile + ssl_kwargs["ssl_keyfile"] = config.tls.ssl_keyfile + if config.tls.ssl_keyfile_password: + ssl_kwargs["ssl_keyfile_password"] = config.tls.ssl_keyfile_password + if config.tls.ssl_ca_certs: + ssl_kwargs["ssl_ca_certs"] = config.tls.ssl_ca_certs + uvicorn.run( "rhos_ls_mcps.main:create_app", host=config.ip, @@ -118,6 +127,7 @@ def main(): access_log=False, factory=True, log_config=log_config, + **ssl_kwargs, ) diff --git a/src/rhos_ls_mcps/settings.py b/src/rhos_ls_mcps/settings.py index 37d8cd5..ce5aa84 100644 --- a/src/rhos_ls_mcps/settings.py +++ b/src/rhos_ls_mcps/settings.py @@ -26,11 +26,18 @@ class OpenShiftSettings(BaseSettings): blocked_commands: list[str] = Field(default=oc_defaults.DEFAULT_BLOCKED_COMMANDS, description="Explicitly blocked commands") +class TLSSettings(BaseSettings): + ssl_certfile: Optional[str] = Field(default=None, description="Path to SSL certificate file for incoming TLS") + ssl_keyfile: Optional[str] = Field(default=None, description="Path to SSL private key file for incoming TLS") + ssl_keyfile_password: Optional[str] = Field(default=None, description="Password for encrypted SSL key file") + ssl_ca_certs: Optional[str] = Field(default=None, description="Path to CA certs file for client certificate verification (mutual TLS)") + + class TransportSecuritySettings(BaseSettings): token: Optional[str] = Field(default=os.environ.get("MCP_SECURITY_TOKEN"), description="Token to use for basic authentication (Env: MCP_SECURITY_TOKEN)") enable_dns_rebinding_protection: bool = Field(default=False, description="Enable DNS rebinding protection") allowed_hosts: list[str] = Field(default=["*:*"], description="Allowed hosts") - allowed_origins: list[str] = Field(default=["http://*:*"], description="Allowed origins") + allowed_origins: list[str] = Field(default=["http://*:*", "https://*:*"], description="Allowed origins") class Settings(BaseSettings): @@ -44,6 +51,7 @@ class Settings(BaseSettings): openstack: OpenStackSettings = Field(default=OpenStackSettings(), description="OpenStack settings") openshift: OpenShiftSettings = Field(default=OpenShiftSettings(), description="OpenShift settings") mcp_transport_security: TransportSecuritySettings = Field(default=TransportSecuritySettings(), description="Transport security settings") + tls: TLSSettings = Field(default=TLSSettings(), description="Incoming TLS settings for the MCP server") def load_config():