Skip to content

Commit 72dbb12

Browse files
author
ci bot
committed
Merge branch 'fix/mcp-hosted-gateway-connectivity' into 'enterprise'
fix(mcp): support hosted MCP gateways (Databricks) See merge request dkinternal/testgen/dataops-testgen!548
2 parents 683b51c + ed82df7 commit 72dbb12

4 files changed

Lines changed: 25 additions & 4 deletions

File tree

testgen/mcp/server.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,9 @@ def _build_transport_security() -> TransportSecuritySettings:
110110
host_pattern = host if ":" in host else f"{host}:*"
111111
allowed_hosts.add(host_pattern)
112112
allowed_origins.update({f"http://{host_pattern}", f"https://{host_pattern}"})
113+
bare = host.split(":", 1)[0]
114+
allowed_hosts.add(bare)
115+
allowed_origins.update({f"http://{bare}", f"https://{bare}"})
113116

114117
return TransportSecuritySettings(
115118
enable_dns_rebinding_protection=True,

testgen/server/__init__.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,17 @@ def run_server() -> None:
180180
if settings.API_TLS_ENABLED:
181181
ssl_kwargs["ssl_certfile"] = settings.SSL_CERT_FILE
182182
ssl_kwargs["ssl_keyfile"] = settings.SSL_KEY_FILE
183+
# uvicorn defaults ssl_ciphers to "TLSv1", which restricts TLS 1.2 to legacy
184+
# CBC/SHA-1 suites with no AEAD. Hardened TLS clients (e.g. the Databricks
185+
# Unity Catalog HTTP-connection gateway) negotiate TLS 1.2 with an AEAD-only
186+
# policy and find no shared cipher, so the handshake fails before any request
187+
# is sent. Offer a modern AEAD cipher set (Mozilla intermediate).
188+
ssl_kwargs["ssl_ciphers"] = (
189+
"ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:"
190+
"ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:"
191+
"ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:"
192+
"DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384"
193+
)
183194

184195
LOG.info(
185196
"Starting server on %s:%s (TLS: %s, MCP: %s)",

testgen/settings.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -634,7 +634,8 @@ def _default_ui_base_url() -> str:
634634
Extra Host header values accepted by MCP DNS rebinding protection (comma-separated).
635635
BASE_URL's hostname and loopback are always allowed; this adds more for multi-domain
636636
deployments or reverse proxies that rewrite Host. Entries without a port (`tg.example.com`)
637-
get an automatic `:*` wildcard; entries with a port are matched literally
637+
are allowed both with an automatic `:*` port wildcard and bare, so gateways that send an
638+
Origin with no port are accepted; entries with a port are matched literally
638639
(`tg.example.com:8080`) or with explicit wildcard (`tg.example.com:*`).
639640
Only affects MCP routes — the parent FastAPI app does not validate Host headers.
640641

tests/unit/mcp/test_transport_security.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,20 @@ def test_loopback_and_base_url_always_present():
3030
assert "https://localhost:*" in settings.allowed_origins
3131

3232

33-
def test_extra_host_without_port_gets_wildcard():
34-
"""An extras entry without `:` gets `:*` automatically appended."""
33+
def test_extra_host_without_port_gets_wildcard_and_bare():
34+
"""An extras entry without `:` is allowed both with a `:*` port wildcard and bare.
35+
36+
The bare (port-less) form is required because some MCP gateways (e.g. Databricks)
37+
send an Origin with no port, which the `:*` wildcard does not match.
38+
"""
3539
settings = _build_with("http://localhost:8530", extras=["tg.example.com"])
3640

3741
assert "tg.example.com:*" in settings.allowed_hosts
38-
assert "tg.example.com" not in settings.allowed_hosts # bare entry should NOT be present
42+
assert "tg.example.com" in settings.allowed_hosts
3943
assert "http://tg.example.com:*" in settings.allowed_origins
4044
assert "https://tg.example.com:*" in settings.allowed_origins
45+
assert "http://tg.example.com" in settings.allowed_origins
46+
assert "https://tg.example.com" in settings.allowed_origins
4147

4248

4349
def test_extra_host_with_explicit_port_preserved_literally():

0 commit comments

Comments
 (0)