fix(client): send same-origin Origin header from streamable HTTP client#2729
Open
Bartok9 wants to merge 1 commit into
Open
fix(client): send same-origin Origin header from streamable HTTP client#2729Bartok9 wants to merge 1 commit into
Bartok9 wants to merge 1 commit into
Conversation
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Originheader by default.http.CrossOriginProtection) that otherwise reject the handshake with403.Motivation
Closes #2727.
The Python
streamablehttp_clientopened its POST handshake without anOriginheader. The official Go SDK (modelcontextprotocol/go-sdkv1.4.x) wraps every streamable-HTTP handler with Go 1.25'shttp.CrossOriginProtection, which denies any state-changing request that cannot prove same-origin viaSec-Fetch-Site, a matchingOrigin, or an allow-listed origin. A legitimate server-to-server connection from the Python client therefore looks like a CSRF attempt →HTTP 403 Forbiddenon the first POST, and the client (per #2110) swallows the non-2xx and hangs forever onsession.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 theOriginheader on every request. The derivation:urllib.parse.urlspliton the configured URL.None(adds no header) when the URL has no scheme or host, so malformed/relative URLs are unaffected.Callers needing a different
Origin(e.g. multi-tenant proxies) can still set one on the underlyinghttpx.AsyncClientdefault headers.Verification
uv run pytest tests/shared/test_streamable_http.py— 63 passed (includes the existingtest_streamable_http_client_mcp_headers_override_defaults/ custom-header tests, unchanged).test_prepare_headers_includes_same_origin—http://my-go-server:8081/mcp→Origin: http://my-go-server:8081;https://…/path?x=1→https://example.com.test_prepare_headers_omits_origin_for_invalid_url— noOriginadded for a URL lacking scheme/host.uv run ruff check/ruff format --check— clean.Diff: 2 files, +41/-0.