diff --git a/Dockerfile b/Dockerfile index a3b544b8..c9635c20 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,17 +13,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ curl \ && rm -rf /var/lib/apt/lists/* -# Install Python dependencies for all services -RUN pip install --no-cache-dir --upgrade \ - qdrant-client \ - fastembed \ - watchdog \ - onnxruntime \ - tokenizers \ - tree_sitter \ - tree_sitter_languages \ - mcp \ - fastmcp +# Python deps: reuse shared requirements file for consistency across services +COPY requirements.txt /tmp/requirements.txt +RUN pip install --no-cache-dir --upgrade -r /tmp/requirements.txt # Copy scripts for all services COPY scripts /app/scripts diff --git a/Dockerfile.mcp b/Dockerfile.mcp index 5d8a6a4f..a97142ed 100644 --- a/Dockerfile.mcp +++ b/Dockerfile.mcp @@ -7,9 +7,10 @@ ENV PYTHONDONTWRITEBYTECODE=1 \ HF_HOME=/tmp/cache \ TRANSFORMERS_CACHE=/tmp/cache -# Install deps + create cache/rerank directories in single layer -# Pin qdrant-client to 1.15.x - version 1.16+ removed .search() which breaks OpenLit instrumentation -RUN pip install --no-cache-dir --upgrade mcp fastmcp 'qdrant-client>=1.15.0,<1.16.0' fastembed openlit \ +# Python deps: reuse shared requirements file for consistency across services +# Create cache/rerank directories in same layer +COPY requirements.txt /tmp/requirements.txt +RUN pip install --no-cache-dir --upgrade -r /tmp/requirements.txt \ && mkdir -p /tmp/cache && chmod 755 /tmp/cache \ && mkdir -p /tmp/rerank_events /tmp/rerank_weights \ && chmod 777 /tmp/rerank_events /tmp/rerank_weights diff --git a/scripts/mcp_indexer_server.py b/scripts/mcp_indexer_server.py index 3da76d7d..09e3c270 100644 --- a/scripts/mcp_indexer_server.py +++ b/scripts/mcp_indexer_server.py @@ -213,12 +213,16 @@ def _highlight_snippet(snippet, tokens): # type: ignore try: - # Official MCP Python SDK (FastMCP convenience server) from mcp.server.fastmcp import FastMCP, Context # type: ignore except Exception as e: # pragma: no cover - # Keep FastMCP import error loud; Context is for type hints only raise SystemExit("mcp package is required inside the container: pip install mcp") +# TransportSecuritySettings only exists in mcp >= 1.x with transport_security module +try: + from mcp.server.transport_security import TransportSecuritySettings # type: ignore +except ImportError: + TransportSecuritySettings = None # type: ignore + APP_NAME = os.environ.get("FASTMCP_SERVER_NAME", "qdrant-indexer-mcp") HOST = os.environ.get("FASTMCP_HOST", "0.0.0.0") PORT = safe_int( @@ -287,7 +291,13 @@ def _highlight_snippet(snippet, tokens): # type: ignore _work_script, ) -mcp = FastMCP(APP_NAME) +# Disable DNS rebinding protection - breaks Docker internal networking (Host: mcp:8000) +_security_settings = ( + TransportSecuritySettings(enable_dns_rebinding_protection=False) + if TransportSecuritySettings + else None +) +mcp = FastMCP(APP_NAME, transport_security=_security_settings) # Capture tool registry automatically by wrapping the decorator once diff --git a/scripts/mcp_memory_server.py b/scripts/mcp_memory_server.py index 7db3fcdd..710a38bb 100644 --- a/scripts/mcp_memory_server.py +++ b/scripts/mcp_memory_server.py @@ -28,10 +28,11 @@ # FastMCP server and request Context (ctx) for per-connection state try: from mcp.server.fastmcp import FastMCP, Context # type: ignore + from mcp.server.transport_security import TransportSecuritySettings # type: ignore except Exception: - # Fallback: keep FastMCP import; treat Context as Any for type hints from mcp.server.fastmcp import FastMCP # type: ignore Context = Any # type: ignore + TransportSecuritySettings = None # type: ignore from scripts.mcp_auth import ( require_auth_session as _require_auth_session, @@ -122,7 +123,13 @@ def _ensure_once(name: str) -> bool: except Exception: return False -mcp = FastMCP(name="memory-server") +# Disable DNS rebinding protection - breaks Docker internal networking (Host: mcp:8000) +_security_settings = ( + TransportSecuritySettings(enable_dns_rebinding_protection=False) + if TransportSecuritySettings + else None +) +mcp = FastMCP(name="memory-server", transport_security=_security_settings) # Capture tool registry automatically by wrapping the decorator once _TOOLS_REGISTRY: list[dict] = []