fix(mcp): disable DNS-rebinding protection on FastMCP

FastMCP defaults to an allow-list of localhost variants for the Host
header (DNS-rebinding protection). Any deployment behind a reverse
proxy hitting a non-localhost hostname (e.g. devassistant.traefik.internal)
gets 421 Misdirected Request with:

  WARNING mcp.server.transport_security: Invalid Host header: <name>

The protection exists to stop a malicious browser page from rebinding
DNS to attack a localhost MCP server. Our deployment is HTTP transport
behind a reverse proxy with bearer-token auth, which already gates
every request — so the rebinding threat doesn't apply. Disabling
the check lets any Host through; auth still rejects unauthorized
requests at 401.

This also makes the integration test pass without test-only host
hackery — every realistic Host header (Traefik internal hostname,
CDN domain, custom DNS) now reaches FastMCP cleanly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-27 14:16:47 -04:00
parent 06a532b0e6
commit 02fe500d61
+19 -2
View File
@@ -2,6 +2,7 @@
from __future__ import annotations
from mcp.server.fastmcp import FastMCP
from mcp.server.transport_security import TransportSecuritySettings
from quart import Quart
_INSTRUCTIONS = """
@@ -23,8 +24,24 @@ Hierarchy: Project -> Milestone -> Task/Note.
def build_mcp_server() -> FastMCP:
"""Build the FastMCP instance with all tools registered."""
mcp = FastMCP("scribe", instructions=_INSTRUCTIONS.strip())
"""Build the FastMCP instance with all tools registered.
DNS-rebinding protection is disabled: FastMCP's default allow-list is
just localhost variants, which means any deployment behind a reverse
proxy (Traefik with a hostname like devassistant.traefik.internal,
Cloudflare, nginx, etc.) gets 421 Misdirected Request. The threat
model that protection addresses — a malicious browser page rebinding
DNS to hit a localhost MCP — doesn't apply here: this is HTTP transport
behind a reverse proxy with bearer-token auth as the real security
boundary.
"""
mcp = FastMCP(
"scribe",
instructions=_INSTRUCTIONS.strip(),
transport_security=TransportSecuritySettings(
enable_dns_rebinding_protection=False,
),
)
from fabledassistant.mcp.tools import register_all
register_all(mcp)
return mcp