| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
|
CI note: the single red cell (test (3.12, lowest-direct, ubuntu-latest)) is an infra/flake failure unrelated to this change, not a regression from this PR.
A rerun of the failed job should clear it (I don't have rerun permission on the fork PR). Happy to rebase if main has moved. |
Sorry, something went wrong.
|
CI note — rebased onto current main. The only remaining red cell (test (3.14, lowest-direct, …)) is a pre-existing, main-wide failure unrelated to this PR: tests/interaction/transports/test_stdio.py::test_tool_call_and_notification_round_trip… asserts byte-exact child stderr, but anyio==4.9 (the lowest-direct floor) has return inside a finally: in from_thread.py:119, which Python 3.14 emits as SyntaxWarning to stderr and pollutes the snapshot. This PR does not touch stdio or that test. Full root-cause + the 6 parallel fixes already in flight are consolidated in #2734 (comment). All other cells (incl. the previously-flaky termination test, now run in-process via #2767) are green. |
Sorry, something went wrong.
Closes modelcontextprotocol#2727 The streamable HTTP client opened its POST handshake without an Origin header, so spec-compliant servers that enforce anti-DNS-rebinding / CSRF protection (e.g. the Go SDK's http.CrossOriginProtection) reject the very first request with 403 Forbidden, and the client then hangs on the read stream. _prepare_headers now derives a same-origin value (scheme://host[:port]) from the target URL and sends it as the Origin header. URLs without a scheme or host add no header. Callers needing a different Origin can set one on the underlying httpx client's default headers.
| Back | FazBrowse Home | New Git URL |
Summary
Motivation
Closes #2727.
The Python streamablehttp_client opened its POST handshake without an Origin header. The official Go SDK (modelcontextprotocol/go-sdk v1.4.x) wraps every streamable-HTTP handler with Go 1.25's http.CrossOriginProtection, which denies any state-changing request that cannot prove same-origin via Sec-Fetch-Site, a matching Origin, or an allow-listed origin. A legitimate server-to-server connection from the Python client therefore looks like a CSRF attempt → HTTP 403 Forbidden on the first POST, and the client (per #2110) swallows the non-2xx and hangs forever on session.initialize().
The two reference SDKs from the same org were out of sync by one spec revision: the Go server enforces the rule; the Python client never sent the header that satisfies it.
Fix
StreamableHTTPTransport._prepare_headers() now derives a same-origin value (scheme://host[:port]) from the target URL and sends it as the Origin header on every request. The derivation:
Callers needing a different Origin (e.g. multi-tenant proxies) can still set one on the underlying httpx.AsyncClient default headers.
Verification
Diff: 2 files, +41/-0.