DEBUG.WIKI
V.PS:让项目靠近用户,亚太、欧洲、北美 KVM VPS
IPPeak:从目标地区访问网页,住宅代理、SEO 监测、广告验证
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国

MCP 本地正常,部署后一直 421 Invalid Host header

MCP 返回 421 Invalid Host header 时,核对代理转发后的实际 Host 和 SDK 白名单。按目标版本分别配置 Host 与 Origin,并验证获准主机能初始化、未知主机仍被拒绝。

MCP 本地正常,部署后一直 421 Invalid Host header

服务在 127.0.0.1 上能连接,挂到域名后每次初始化都失败。客户端只显示传输异常,服务器日志里却有:

Invalid Host header

同时 HTTP 状态码是 421。这时先查 MCP 的 Host 白名单。请求还没有进入工具执行阶段,反复调整工具参数不会有帮助。

注意版本:下面代码针对 MCP Python SDK mcp==1.29.0 的 FastMCP。该版本把 transport_security 传给 FastMCP 构造函数;所引用的后续 main 文档使用 MCPServer,并允许在 HTTP 应用创建处配置。不能把不同版本的例子拼起来。先运行 python -m pip show mcp。

把服务器真正收到的 Host 配进去

外部 URL 是什么、代理转发后 Host 是什么,可能并不一致。记录请求头中的 Host,确认其中有没有端口。allowed_hosts 不写协议,也不写路径;Origin 才包含 https://。

下面的 example.com 是示例域名,部署前换成实际由你控制的域名。保存为 server.py:

from mcp.server.fastmcp import FastMCP
from mcp.server.transport_security import TransportSecuritySettings

security = TransportSecuritySettings(
    enable_dns_rebinding_protection=True,
    allowed_hosts=["mcp.example.com", "mcp.example.com:443"],
    allowed_origins=["https://console.example.com"],
)
mcp = FastMCP("order-tools", transport_security=security)

@mcp.tool()
def ping() -> str:
    return "pong"

app = mcp.streamable_http_app()

用 uvicorn server:app --host 127.0.0.1 --port 8000 启动,由已经配置好的反向代理转发。绑定地址要按你的部署拓扑决定;仅为验证报错不需要先把服务开放给公网。

当前 Host 匹配支持明确主机名和形如 mcp.example.com:* 的端口模式。只需要 443 就列 443;确实要接收多个不固定端口,再考虑端口模式。*.example.com 不是这里的通用子域名通配语法,不能照搬其他网关配置。

需要同时做一条反向测试

下面针对测试环境,直接访问本地端口,验证进入 MCP 的请求头检查;不需要模型或付费接口。

curl -i http://127.0.0.1:8000/mcp \
  -H 'Host: mcp.example.com' \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  --data '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"host-check","version":"1"}}}'

curl -i http://127.0.0.1:8000/mcp \
  -H 'Host: untrusted.invalid' \
  -H 'Content-Type: application/json' \
  --data '{}'

第一条应通过 Host 检查,并在该版本支持的初始化流程中得到有效响应;第二条应保持 421。之后还要从真实部署域名完成客户端初始化,确认代理没有把 Host 改成另一种形式。

如果带 Origin 的请求返回 403,转去核对 allowed_origins。浏览器的 CORS 预检、服务端 Origin 检查、Host 检查分别发生在不同位置,给 CORS 加一个域名不等于 MCP 的白名单也更新了。

不要把关闭 DNS rebinding 防护当成默认修复。只有明确把同等校验交给可信代理、且后端无法被绕过直连时,才适合单独评估安全边界;为了连接成功直接接受任意 Host,会把原本的保护一起撤掉。

官方依据:1.29.0 传输安全实现、部署排查文档快照。