Skip to content

Unbounded fastmcp constraint: image rebuilds pick up FastMCP 3.4.3 host-origin protection, kai-api returns 421 for all proxied requests #934

Description

@ibolton336

Summary

Since July 8, the kai-api MCP server (quay.io/konveyor/kai-solution-server:latest) returns HTTP 421 Misdirected Request for every request when deployed behind a proxy/ingress (minikube, and likely OpenShift routes). The server is completely unreachable through the ingress.

Root cause

Two compounding problems:

  1. The image build ignores the lockfile. tools/deploy/Containerfile runs pip3.12 install --no-cache-dir . against pyproject.toml only — requirements.txt / uv.lock (which pin fastmcp==2.14.3, mcp==1.25.0) are never copied into the image. pyproject declares only a floor: fastmcp>=2.8.0, so every rebuild resolves the newest fastmcp from PyPI.
  2. FastMCP 3.4.3 enabled host/origin (DNS-rebinding) protection by defaulthttp_host_origin_protection: bool = True with http_allowed_hosts: None, i.e. an effectively empty allowlist. The security middleware validates the Host header and returns 421 "Invalid Host header" on mismatch. Same failure mode hit other projects the same week: modelcontextprotocol/python-sdk#1798, CrowdStrike/falcon-mcp#291, blockscout/mcp-server#333, write-up.

The merge of #932 triggered the fresh :latest build that picked up fastmcp ≥3.4.3 — but the dependency bumps in #932 are themselves incidental; any merge would have produced the same broken image. (Earlier drafts of this issue blamed the starlette bump; that was wrong — starlette has no 421 code path.)

Behind a proxy, the forwarded Host header is the external host/IP (e.g. 192.168.49.2 via tackle-hub's /hub/services/kai/api route), which never matches the empty/localhost allowlist → every request is rejected before reaching the MCP session layer.

Evidence

kai-api pod logs — the server itself returns 421, not nginx:

INFO:     Starting MCP server 'KaiSolutionServer' with transport 'streamable-http' on http://0.0.0.0:8000/api
INFO:     10.244.0.16:45922 - "POST /api HTTP/1.1" 421 Misdirected Request
INFO:     10.244.0.16:37090 - "POST /api HTTP/1.1" 421 Misdirected Request
... (every request, deterministic)

Impact

  • All editor-extensions CI infrastructure tests (@requires-minikube) are broken
  • Any deployment behind an ingress/route that preserves the external Host header is unreachable

Reproduction

  1. Deploy kai-api via the konveyor operator on minikube with ingress enabled
  2. curl -k -X POST https://$(minikube ip)/hub/services/kai/api -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","method":"initialize","id":0,"params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"test","version":"0.0.0"}}}'
  3. Observe HTTP 421

Suggested fixes (increasing durability)

  • Immediate mitigation for existing deployments: set FASTMCP_HTTP_HOST_ORIGIN_PROTECTION=false on the kai-api container
  • Make the image reproducible: install from the lock (uv sync --frozen, or copy requirements.txt into the image and pip install -r) instead of resolving floors at build time
  • Cap the constraint (fastmcp>=2.8.0,<3) until a deliberate 3.x migration, and/or configure http_allowed_hosts explicitly for proxied deployments

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions