This is an automated email from the ASF dual-hosted git repository.
FreeOnePlus pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris-mcp-server.git
The following commit(s) were added to refs/heads/master by this push:
new 95f1c24 fix: align compose ports and health probes (#132)
95f1c24 is described below
commit 95f1c24c25972a28fe263f0b82bd209c190ecc2d
Author: Yijia Su <[email protected]>
AuthorDate: Thu Jul 30 02:27:05 2026 +0800
fix: align compose ports and health probes (#132)
---
.dockerignore | 13 +++-
Dockerfile | 19 +++--
README.md | 25 ++++++-
docker-compose.yml | 25 +++----
doris_mcp_server/main.py | 8 ++-
doris_mcp_server/multiworker_app.py | 6 +-
doris_mcp_server/protocol.py | 46 +++++++++---
doris_mcp_server/utils/config.py | 20 ++++++
requirements.txt | 3 +-
start_server.sh | 17 +++--
test/deployment/test_compose_contract.py | 119 +++++++++++++++++++++++++++++++
test/protocol/test_mcp_v2_protocol.py | 19 +++++
test/protocol/test_multiworker_config.py | 7 ++
13 files changed, 287 insertions(+), 40 deletions(-)
diff --git a/.dockerignore b/.dockerignore
index 9f335b5..a4e0162 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -1,2 +1,11 @@
-**/.venv
-**/venv
\ No newline at end of file
+# Keep the build context limited to files copied by Dockerfile. In particular,
+# do not send source-control metadata, local operator files, tests, or reports
+# to the Docker daemon or a remote builder.
+**
+!.dockerignore
+!Dockerfile
+!LICENSE.txt
+!requirements.txt
+!start_server.sh
+!doris_mcp_server/
+!doris_mcp_server/**
diff --git a/Dockerfile b/Dockerfile
index 3a70519..c772ec6 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -41,8 +41,11 @@ COPY requirements.txt .
# Install Python dependencies
RUN pip install --no-cache-dir -r requirements.txt
-# Copy application code
-COPY . .
+# Copy only runtime files. This keeps source-control metadata, local reports,
+# tests, caches, and untracked operator files out of the production image.
+COPY doris_mcp_server ./doris_mcp_server
+COPY start_server.sh .
+COPY LICENSE.txt .
# Convert line endings for shell scripts and ensure proper execution format
RUN find . -name "*.sh" -exec dos2unix {} \; && \
@@ -56,12 +59,14 @@ RUN groupadd -r doris && useradd -r -g doris doris
RUN chown -R doris:doris /app
USER doris
-# Health check
-HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
- CMD curl -f http://localhost:3000/health || exit 1
+# The image-level probe reports process liveness. Deployments that route Doris
+# traffic should override it with the /ready probe, as docker-compose.yml does.
+HEALTHCHECK --interval=30s --timeout=5s --start-period=40s --retries=3 \
+ CMD curl --fail --silent --show-error --max-time 3 \
+ http://127.0.0.1:3000/live || exit 1
-# Expose ports
-EXPOSE 3000 3001 3002
+# Streamable HTTP, liveness, and readiness share the server's HTTP listener.
+EXPOSE 3000
# Start command
CMD ["/app/start_server.sh"]
diff --git a/README.md b/README.md
index edc2123..eeea7c2 100644
--- a/README.md
+++ b/README.md
@@ -379,8 +379,31 @@ If you want to run only Doris MCP Server in docker:
```bash
cd doris-mcp-server
docker build -t doris-mcp-server .
-docker run -d -p <port>:<port> -v /*your-host*/doris-mcp-server/.env:/app/.env
--name <your-mcp-server-name> -it doris-mcp-server:latest
+docker run -d -p <host-port>:3000 -v
/*your-host*/doris-mcp-server/.env:/app/.env --name <your-mcp-server-name>
doris-mcp-server:latest
```
+
+The container always listens on port `3000`. The bundled Compose deployment
+publishes it on host port `3000` by default and publishes Grafana on host port
+`3003`, so the two services do not contend for the same port. Override those
+defaults with `MCP_HTTP_PORT` and `GRAFANA_HTTP_PORT`:
+
+```bash
+MCP_HTTP_PORT=3100 GRAFANA_HTTP_PORT=3103 docker compose up -d
+```
+
+The image-level Docker health check uses `/live`, so a temporary Doris outage
+does not cause the MCP process to be treated as dead. Compose overrides that
+probe with `/ready` and only marks the service ready after the bounded Doris
+probe succeeds. Both probes use the actual internal listener on port `3000`.
+
+Compose allows `127.0.0.1:*` and `localhost:*` Host headers by default. A
+deployment reached through another hostname, IP address, or reverse proxy must
+set an explicit comma-separated allowlist; an allow-all `*` value is rejected:
+
+```bash
+MCP_ALLOWED_HOSTS='mcp.example.com,mcp.example.com:*' docker compose up -d
+```
+
**Service Endpoints:**
* **Streamable HTTP**: `http://<host>:<port>/mcp` (MCP messages use `POST`;
do not depend on `GET` or `DELETE` compatibility behavior)
diff --git a/docker-compose.yml b/docker-compose.yml
index c9cbed6..9061ba1 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -14,8 +14,6 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-version: '3.8'
-
services:
# Doris MCP Server
doris-mcp-server:
@@ -24,9 +22,7 @@ services:
dockerfile: Dockerfile
container_name: doris-mcp-server
ports:
- - "3000:3000" # MCP service port
- - "3001:3001" # Monitoring metrics port
- - "3002:3002" # Health check port
+ - "${MCP_HTTP_PORT:-3000}:3000" # Streamable HTTP, liveness, and
readiness
environment:
# Database configuration
- DORIS_HOST=doris-fe
@@ -40,7 +36,9 @@ services:
- DORIS_MAX_CONNECTIONS=20
# Security configuration
- - MCP_HOST=0.0.0.0
+ - SERVER_HOST=0.0.0.0
+ - SERVER_PORT=3000
+ - MCP_ALLOWED_HOSTS=${MCP_ALLOWED_HOSTS:-127.0.0.1:*,localhost:*}
- ENABLE_TOKEN_AUTH=true
- TOKEN_ADMIN=${MCP_STATIC_TOKEN:?Set MCP_STATIC_TOKEN to a securely
generated value of at least 32 characters}
- MAX_RESULT_ROWS=10000
@@ -60,15 +58,17 @@ services:
- ./logs:/app/logs
- ./config:/app/config
depends_on:
- - doris-fe
- - doris-be
+ doris-fe:
+ condition: service_healthy
+ doris-be:
+ condition: service_healthy
networks:
- doris-network
restart: unless-stopped
healthcheck:
- test: ["CMD", "curl", "-f", "http://localhost:8082/health"]
+ test: ["CMD", "curl", "--fail", "--silent", "--show-error",
"--max-time", "3", "http://127.0.0.1:3000/ready"]
interval: 30s
- timeout: 10s
+ timeout: 5s
retries: 3
start_period: 40s
@@ -165,7 +165,7 @@ services:
image: grafana/grafana:latest
container_name: doris-grafana
ports:
- - "3000:3000"
+ - "${GRAFANA_HTTP_PORT:-3003}:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin123
volumes:
@@ -190,7 +190,8 @@ services:
- ./nginx/ssl:/etc/nginx/ssl
- ./nginx/logs:/var/log/nginx
depends_on:
- - doris-mcp-server
+ doris-mcp-server:
+ condition: service_healthy
networks:
- doris-network
restart: unless-stopped
diff --git a/doris_mcp_server/main.py b/doris_mcp_server/main.py
index 7102194..ed46ba6 100644
--- a/doris_mcp_server/main.py
+++ b/doris_mcp_server/main.py
@@ -67,6 +67,8 @@ def _multiworker_environment(
"DORIS_DATABASE": config.database.database,
"SERVER_HOST": host,
"SERVER_PORT": str(port),
+ "MCP_ALLOWED_HOSTS": ",".join(config.mcp_allowed_hosts),
+ "MCP_ALLOWED_ORIGINS": ",".join(config.mcp_allowed_origins),
"SERVER_NAME": config.server_name,
"TRANSPORT": "http",
"WORKERS": str(workers),
@@ -218,7 +220,11 @@ class DorisServer:
app=self.server,
json_response=True,
stateless=True,
- security_settings=create_transport_security(host),
+ security_settings=create_transport_security(
+ host,
+ allowed_hosts=self.config.mcp_allowed_hosts,
+ allowed_origins=self.config.mcp_allowed_origins,
+ ),
)
self.logger.info(f"StreamableHTTP session manager created, will
start at http://{host}:{port}")
diff --git a/doris_mcp_server/multiworker_app.py
b/doris_mcp_server/multiworker_app.py
index 74d1335..cd45ae7 100644
--- a/doris_mcp_server/multiworker_app.py
+++ b/doris_mcp_server/multiworker_app.py
@@ -129,7 +129,11 @@ async def initialize_worker():
app=_worker_server,
json_response=True,
stateless=True,
- security_settings=create_transport_security(config.server_host),
+ security_settings=create_transport_security(
+ config.server_host,
+ allowed_hosts=config.mcp_allowed_hosts,
+ allowed_origins=config.mcp_allowed_origins,
+ ),
)
# Start the session manager context
diff --git a/doris_mcp_server/protocol.py b/doris_mcp_server/protocol.py
index 0790d1d..5194db9 100644
--- a/doris_mcp_server/protocol.py
+++ b/doris_mcp_server/protocol.py
@@ -20,7 +20,7 @@ from __future__ import annotations
import json
import logging
-from collections.abc import Mapping
+from collections.abc import Iterable, Mapping
from typing import Any, Protocol
from mcp.server import Server, ServerRequestContext
@@ -81,24 +81,52 @@ class PromptsManager(Protocol):
) -> GetPromptResult: ...
-def create_transport_security(host: str) -> TransportSecuritySettings:
+def _explicit_transport_allowlist(
+ values: Iterable[str] | None,
+ *,
+ setting: str,
+) -> list[str]:
+ """Normalize an explicit transport allowlist without accepting
allow-all."""
+ normalized = list(dict.fromkeys(str(value).strip() for value in values or
()))
+ normalized = [value for value in normalized if value]
+ if "*" in normalized:
+ raise ValueError(
+ f"{setting} must list deployment hosts explicitly; '*' is not
allowed"
+ )
+ return normalized
+
+
+def create_transport_security(
+ host: str,
+ *,
+ allowed_hosts: Iterable[str] | None = None,
+ allowed_origins: Iterable[str] | None = None,
+) -> TransportSecuritySettings:
"""Create a fail-closed Host and Origin policy for a bind host."""
+ configured_hosts = _explicit_transport_allowlist(
+ allowed_hosts,
+ setting="MCP_ALLOWED_HOSTS",
+ )
+ configured_origins = _explicit_transport_allowlist(
+ allowed_origins,
+ setting="MCP_ALLOWED_ORIGINS",
+ )
if host in {"127.0.0.1", "localhost", "::1"}:
- allowed_hosts = ["127.0.0.1:*", "localhost:*", "[::1]:*"]
- allowed_origins = [
+ default_hosts = ["127.0.0.1:*", "localhost:*", "[::1]:*"]
+ default_origins = [
"http://127.0.0.1:*",
"http://localhost:*",
"http://[::1]:*",
]
else:
# A bind address is not a public deployment hostname. Explicit
- # deployment allowlists will replace this conservative fallback.
- allowed_hosts = [host, f"{host}:*"]
- allowed_origins = []
+ # deployment allowlists replace this conservative fallback.
+ default_hosts = [host, f"{host}:*"]
+ default_origins = []
return TransportSecuritySettings(
enable_dns_rebinding_protection=True,
- allowed_hosts=allowed_hosts,
- allowed_origins=allowed_origins,
+ allowed_hosts=configured_hosts or default_hosts,
+ allowed_origins=configured_origins or default_origins,
)
diff --git a/doris_mcp_server/utils/config.py b/doris_mcp_server/utils/config.py
index 1adbef7..da2c5ed 100644
--- a/doris_mcp_server/utils/config.py
+++ b/doris_mcp_server/utils/config.py
@@ -604,6 +604,8 @@ class DorisConfig:
server_version: str = field(default=__version__, init=False)
server_host: str = "localhost"
server_port: int = 3000
+ mcp_allowed_hosts: list[str] = field(default_factory=list)
+ mcp_allowed_origins: list[str] = field(default_factory=list)
transport: str = "stdio"
# Temporary files configuration
@@ -1122,6 +1124,20 @@ class DorisConfig:
server_port = os.getenv("SERVER_PORT", "").strip()
if server_port and server_port.isdigit():
config.server_port = int(server_port)
+ if "MCP_ALLOWED_HOSTS" in os.environ:
+ config.mcp_allowed_hosts = [
+ value.strip()
+ for value in os.getenv("MCP_ALLOWED_HOSTS", "").split(",")
+ if value.strip()
+ ]
+ _mark_source(config, "mcp_allowed_hosts", "env")
+ if "MCP_ALLOWED_ORIGINS" in os.environ:
+ config.mcp_allowed_origins = [
+ value.strip()
+ for value in os.getenv("MCP_ALLOWED_ORIGINS", "").split(",")
+ if value.strip()
+ ]
+ _mark_source(config, "mcp_allowed_origins", "env")
config.temp_files_dir = os.getenv("TEMP_FILES_DIR",
config.temp_files_dir)
return config
@@ -1136,6 +1152,8 @@ class DorisConfig:
"server_name",
"server_host",
"server_port",
+ "mcp_allowed_hosts",
+ "mcp_allowed_origins",
"temp_files_dir",
"transport",
"workers",
@@ -1207,6 +1225,8 @@ class DorisConfig:
"server_version": self.server_version,
"server_host": self.server_host,
"server_port": self.server_port,
+ "mcp_allowed_hosts": self.mcp_allowed_hosts,
+ "mcp_allowed_origins": self.mcp_allowed_origins,
"temp_files_dir": self.temp_files_dir,
"database": {
"host": self.database.host,
diff --git a/requirements.txt b/requirements.txt
index 347f62d..670907c 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -2,7 +2,7 @@
# Do not edit this file manually, use 'python generate_requirements.py' to
regenerate
# === Core Dependencies ===
-mcp>=1.8.0,<2.0.0
+mcp>=2.0.0,<2.1.0
aiomysql>=0.2.0
PyMySQL>=1.1.0
adbc-driver-manager>=0.8.0
@@ -12,6 +12,7 @@ asyncio-mqtt>=0.16.0
aiofiles>=23.0.0
aiohttp>=3.9.0
aioredis>=2.0.0
+filelock>=3.16.1,<4.0.0
pandas>=2.0.0
numpy>=1.24.0
python-dateutil>=2.8.0
diff --git a/start_server.sh b/start_server.sh
index 0282650..6002233 100755
--- a/start_server.sh
+++ b/start_server.sh
@@ -66,7 +66,10 @@ fi
# Set HTTP-specific environment variables
# FIX for Issue #62 Bug 4: Use SERVER_PORT instead of MCP_PORT for consistency
with code
export MCP_TRANSPORT_TYPE="http"
-export MCP_HOST="${MCP_HOST:-127.0.0.1}"
+export SERVER_HOST="${SERVER_HOST:-${MCP_HOST:-127.0.0.1}}"
+# Keep MCP_HOST available for existing .env files while using the server's
+# canonical host setting for the actual process.
+export MCP_HOST="${SERVER_HOST}"
export SERVER_PORT="${SERVER_PORT:-3000}" # Changed from MCP_PORT to
SERVER_PORT
export WORKERS="${WORKERS:-1}"
export ALLOWED_ORIGINS="${ALLOWED_ORIGINS:-*}"
@@ -78,15 +81,16 @@ export MCP_DEBUG_ADAPTER="true"
export PYTHONPATH="$(pwd):$PYTHONPATH"
echo -e "${GREEN}Starting MCP server (Streamable HTTP mode)...${NC}"
-echo -e "${YELLOW}Service will run on
http://${MCP_HOST}:${SERVER_PORT}/mcp${NC}"
-echo -e "${YELLOW}Health Check: http://${MCP_HOST}:${SERVER_PORT}/health${NC}"
-echo -e "${YELLOW}MCP Endpoint: http://${MCP_HOST}:${SERVER_PORT}/mcp${NC}"
+echo -e "${YELLOW}Service will run on
http://${SERVER_HOST}:${SERVER_PORT}/mcp${NC}"
+echo -e "${YELLOW}Liveness: http://${SERVER_HOST}:${SERVER_PORT}/live${NC}"
+echo -e "${YELLOW}Readiness: http://${SERVER_HOST}:${SERVER_PORT}/ready${NC}"
+echo -e "${YELLOW}MCP Endpoint: http://${SERVER_HOST}:${SERVER_PORT}/mcp${NC}"
echo -e "${YELLOW}Local access: http://localhost:${SERVER_PORT}/mcp${NC}"
echo -e "${YELLOW}Workers: ${WORKERS}${NC}"
echo -e "${YELLOW}Use Ctrl+C to stop the service${NC}"
# Start the server in HTTP mode (Streamable HTTP)
-python -m doris_mcp_server.main --transport http --host ${MCP_HOST} --port
${SERVER_PORT} --workers ${WORKERS}
+python -m doris_mcp_server.main --transport http --host "${SERVER_HOST}"
--port "${SERVER_PORT}" --workers "${WORKERS}"
# Check exit status
if [ $? -ne 0 ]; then
@@ -98,4 +102,5 @@ fi
echo -e "${YELLOW}Tip: If the page displays abnormally, please clear your
browser cache or use incognito mode${NC}"
echo -e "${YELLOW}Chrome browser clear cache shortcut: Ctrl+Shift+Del
(Windows) or Cmd+Shift+Del (Mac)${NC}"
echo -e "${CYAN}For testing HTTP endpoints, you can use:${NC}"
-echo -e "${CYAN} curl http://127.0.0.1:${SERVER_PORT}/health${NC}"
+echo -e "${CYAN} curl --fail http://127.0.0.1:${SERVER_PORT}/live${NC}"
+echo -e "${CYAN} curl --fail http://127.0.0.1:${SERVER_PORT}/ready${NC}"
diff --git a/test/deployment/test_compose_contract.py
b/test/deployment/test_compose_contract.py
new file mode 100644
index 0000000..a6b3e23
--- /dev/null
+++ b/test/deployment/test_compose_contract.py
@@ -0,0 +1,119 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+import re
+from pathlib import Path
+
+import yaml
+
+REPOSITORY_ROOT = Path(__file__).resolve().parents[2]
+COMPOSE_PATH = REPOSITORY_ROOT / "docker-compose.yml"
+DOCKERFILE_PATH = REPOSITORY_ROOT / "Dockerfile"
+DOCKERIGNORE_PATH = REPOSITORY_ROOT / ".dockerignore"
+START_SCRIPT_PATH = REPOSITORY_ROOT / "start_server.sh"
+REQUIREMENTS_PATH = REPOSITORY_ROOT / "requirements.txt"
+DEFAULT_VARIABLE = re.compile(r"^\$\{[^}:]+:-([^}]+)\}$")
+
+
+def _compose() -> dict:
+ return yaml.safe_load(COMPOSE_PATH.read_text(encoding="utf-8"))
+
+
+def _default_published_port(port: str | dict) -> int:
+ published = str(
+ port["published"] if isinstance(port, dict) else port.rsplit(":", 1)[0]
+ )
+ match = DEFAULT_VARIABLE.fullmatch(published)
+ return int(match.group(1) if match else published)
+
+
+def test_default_compose_host_ports_are_unique() -> None:
+ compose = _compose()
+ published: list[int] = []
+ for service in compose["services"].values():
+ published.extend(
+ _default_published_port(port) for port in service.get("ports", [])
+ )
+
+ assert len(published) == len(set(published))
+
+
+def test_mcp_service_uses_one_real_listener_and_readiness_probe() -> None:
+ service = _compose()["services"]["doris-mcp-server"]
+
+ assert service["ports"] == ["${MCP_HTTP_PORT:-3000}:3000"]
+ assert "SERVER_HOST=0.0.0.0" in service["environment"]
+ assert "SERVER_PORT=3000" in service["environment"]
+ assert (
+ "MCP_ALLOWED_HOSTS=${MCP_ALLOWED_HOSTS:-127.0.0.1:*,localhost:*}"
+ in service["environment"]
+ )
+ assert service["healthcheck"]["test"] == [
+ "CMD",
+ "curl",
+ "--fail",
+ "--silent",
+ "--show-error",
+ "--max-time",
+ "3",
+ "http://127.0.0.1:3000/ready",
+ ]
+ assert service["depends_on"]["doris-fe"]["condition"] == "service_healthy"
+ assert service["depends_on"]["doris-be"]["condition"] == "service_healthy"
+
+
+def test_grafana_default_port_does_not_conflict_with_mcp() -> None:
+ grafana = _compose()["services"]["grafana"]
+
+ assert grafana["ports"] == ["${GRAFANA_HTTP_PORT:-3003}:3000"]
+
+
+def test_image_healthcheck_uses_liveness_on_the_real_listener() -> None:
+ dockerfile = DOCKERFILE_PATH.read_text(encoding="utf-8")
+
+ assert "http://127.0.0.1:3000/live" in dockerfile
+ assert "EXPOSE 3000\n" in dockerfile
+ assert "EXPOSE 3000 3001 3002" not in dockerfile
+ assert "COPY . ." not in dockerfile
+ assert "COPY doris_mcp_server ./doris_mcp_server" in dockerfile
+ assert "COPY start_server.sh ." in dockerfile
+
+
+def test_container_dependency_manifest_uses_mcp_sdk_v2() -> None:
+ requirements = REQUIREMENTS_PATH.read_text(encoding="utf-8").splitlines()
+
+ assert "mcp>=2.0.0,<2.1.0" in requirements
+ assert "mcp>=1.8.0,<2.0.0" not in requirements
+
+
+def test_docker_build_context_is_an_explicit_runtime_allowlist() -> None:
+ dockerignore = DOCKERIGNORE_PATH.read_text(encoding="utf-8").splitlines()
+
+ assert "**" in dockerignore
+ assert "!doris_mcp_server/**" in dockerignore
+ assert "!requirements.txt" in dockerignore
+ assert "!start_server.sh" in dockerignore
+ assert "!LICENSE.txt" in dockerignore
+
+
+def test_start_script_uses_canonical_server_host_and_documents_both_probes()
-> None:
+ script = START_SCRIPT_PATH.read_text(encoding="utf-8")
+
+ assert 'SERVER_HOST="${SERVER_HOST:-${MCP_HOST:-127.0.0.1}}"' in script
+ assert '--host "${SERVER_HOST}" --port "${SERVER_PORT}"' in script
+ assert "/live" in script
+ assert "/ready" in script
diff --git a/test/protocol/test_mcp_v2_protocol.py
b/test/protocol/test_mcp_v2_protocol.py
index 072d8d8..813ed4f 100644
--- a/test/protocol/test_mcp_v2_protocol.py
+++ b/test/protocol/test_mcp_v2_protocol.py
@@ -46,6 +46,25 @@ from test.protocol.stdio_capability_server import
OneToolManager as ProfileToolM
REQUIRED_EXTENSION = "io.apache.doris/read"
+def test_transport_security_accepts_explicit_deployment_allowlists():
+ settings = create_transport_security(
+ "0.0.0.0",
+ allowed_hosts=["mcp.example.test", "mcp.example.test:*"],
+ allowed_origins=["https://client.example.test"],
+ )
+
+ assert settings.allowed_hosts == [
+ "mcp.example.test",
+ "mcp.example.test:*",
+ ]
+ assert settings.allowed_origins == ["https://client.example.test"]
+
+
+def test_transport_security_rejects_allow_all_host():
+ with pytest.raises(ValueError, match="must list deployment hosts
explicitly"):
+ create_transport_security("0.0.0.0", allowed_hosts=["*"])
+
+
async def _unused_sampling_callback(context, params):
del context, params
raise AssertionError("The capability fixture must not issue sampling
requests")
diff --git a/test/protocol/test_multiworker_config.py
b/test/protocol/test_multiworker_config.py
index cccd204..9bf3cd4 100644
--- a/test/protocol/test_multiworker_config.py
+++ b/test/protocol/test_multiworker_config.py
@@ -23,6 +23,8 @@ def
test_multiworker_environment_preserves_resolved_parent_config(monkeypatch):
config.database.password = "test-password"
config.database.database = "hhm_dt_sim"
config.server_name = "doris-mcp-server"
+ config.mcp_allowed_hosts = ["mcp.example.test", "mcp.example.test:*"]
+ config.mcp_allowed_origins = ["https://client.example.test"]
worker_env = _multiworker_environment(
config,
@@ -43,6 +45,11 @@ def
test_multiworker_environment_preserves_resolved_parent_config(monkeypatch):
assert child_config.database.database == "hhm_dt_sim"
assert child_config.server_host == "127.0.0.1"
assert child_config.server_port == 31133
+ assert child_config.mcp_allowed_hosts == [
+ "mcp.example.test",
+ "mcp.example.test:*",
+ ]
+ assert child_config.mcp_allowed_origins == ["https://client.example.test"]
assert child_config.server_name == "doris-mcp-server"
assert child_config.server_version == __version__
assert child_config.transport == "http"
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]