Skip to content

fix: explain transport host rejections#2726

Open
he-yufeng wants to merge 1 commit into
modelcontextprotocol:mainfrom
he-yufeng:fix/host-rejection-diagnostics
Open

fix: explain transport host rejections#2726
he-yufeng wants to merge 1 commit into
modelcontextprotocol:mainfrom
he-yufeng:fix/host-rejection-diagnostics

Conversation

@he-yufeng
Copy link
Copy Markdown

Summary

  • keep the existing fail-closed Host validation behavior
  • return a structured HTTP 421 body that names host_not_allowed, the received Host value, and the TransportSecuritySettings.allowed_hosts setting
  • document reverse-proxy allowed_hosts configuration with host and host:port examples

Fixes #2688.

To verify

  • uv run pytest tests/server/test_transport_security.py tests/server/test_streamable_http_security.py tests/server/test_sse_security.py tests/interaction/transports/test_hosting_http.py -q
  • uv run ruff check src/mcp/server/transport_security.py tests/server/test_transport_security.py tests/server/test_streamable_http_security.py tests/server/test_sse_security.py tests/interaction/transports/test_hosting_http.py
  • uv run pyright src/mcp/server/transport_security.py tests/server/test_transport_security.py tests/server/test_streamable_http_security.py tests/server/test_sse_security.py tests/interaction/transports/test_hosting_http.py
  • git diff --check

@he-yufeng he-yufeng force-pushed the fix/host-rejection-diagnostics branch 2 times, most recently from 2405b73 to fe03909 Compare May 30, 2026 03:07
@he-yufeng he-yufeng force-pushed the fix/host-rejection-diagnostics branch from fe03909 to b737756 Compare June 6, 2026 21:53
@he-yufeng
Copy link
Copy Markdown
Author

Rebased this branch on current main and force-pushed b737756.

The conflicts were in the SSE and Streamable HTTP security tests because upstream moved these checks to in-process ASGI clients. I kept that newer test structure and re-applied this PR's structured host rejection assertions on top.

Validated locally:

  • uv run --frozen pytest tests/server/test_transport_security.py tests/server/test_streamable_http_security.py tests/server/test_sse_security.py tests/interaction/transports/test_hosting_http.py::test_origin_validation_rejects_disallowed_origins_when_enabled -q (49 passed)
  • uv run --frozen ruff check src/mcp/server/transport_security.py tests/interaction/transports/test_hosting_http.py tests/server/test_transport_security.py tests/server/test_sse_security.py tests/server/test_streamable_http_security.py
  • uv run --frozen ruff format --check src/mcp/server/transport_security.py tests/interaction/transports/test_hosting_http.py tests/server/test_transport_security.py tests/server/test_sse_security.py tests/server/test_streamable_http_security.py
  • uv run --frozen pyright src/mcp/server/transport_security.py tests/interaction/transports/test_hosting_http.py tests/server/test_transport_security.py tests/server/test_sse_security.py tests/server/test_streamable_http_security.py (0 errors)
  • python -m py_compile src\mcp\server\transport_security.py tests\interaction\transports\test_hosting_http.py tests\server\test_transport_security.py tests\server\test_sse_security.py tests\server\test_streamable_http_security.py
  • git diff --check --cached before completing the rebase

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TransportSecuritySettings.allowed_hosts=[] (default) silently rejects external Host headers with HTTP 421

1 participant