fix: configure MCP transport security with env-driven allowed hosts
All checks were successful
ci/woodpecker/push/build Pipeline was successful

FastMCP auto-enables DNS rebinding protection when host=127.0.0.1
(the default). Production requests from brain.woltje.com were rejected
with 421 Invalid Host header because the allowed_hosts list was empty.

Added MCP_ALLOWED_HOSTS config field (comma-separated). When set,
DNS rebinding protection is enabled with those hosts; when empty,
protection is disabled. Set MCP_ALLOWED_HOSTS=brain.woltje.com in
Portainer stack env.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-02 19:14:32 -06:00
parent 679fda8491
commit c02d1d8974
2 changed files with 12 additions and 1 deletions

View File

@@ -19,5 +19,10 @@ class Settings(BaseSettings):
port: int = 8000
log_level: str = "info"
# MCP transport security — comma-separated allowed Host header values.
# Set to the public hostname (e.g. "brain.woltje.com") in production.
# Empty disables DNS rebinding protection.
mcp_allowed_hosts: str = ""
settings = Settings()

View File

@@ -6,6 +6,7 @@ import logging
from fastapi import Depends, FastAPI, HTTPException, Security
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
from mcp.server.fastmcp import FastMCP
from mcp.server.transport_security import TransportSecuritySettings
from src import brain, db
from src.config import settings
@@ -29,7 +30,12 @@ def require_api_key(credentials: HTTPAuthorizationCredentials = Security(bearer)
# ---------------------------------------------------------------------------
# MCP server
# ---------------------------------------------------------------------------
mcp = FastMCP("openbrain", stateless_http=True)
_allowed_hosts = [h.strip() for h in settings.mcp_allowed_hosts.split(",") if h.strip()]
_transport_security = TransportSecuritySettings(
enable_dns_rebinding_protection=bool(_allowed_hosts),
allowed_hosts=_allowed_hosts,
)
mcp = FastMCP("openbrain", stateless_http=True, transport_security=_transport_security)
@mcp.tool()