|
35 | 35 | from mcp.shared._context_streams import ContextReceiveStream, ContextSendStream, create_context_streams |
36 | 36 | from mcp.shared._httpx_utils import ( |
37 | 37 | create_mcp_http_client, |
| 38 | + redirect_location, |
38 | 39 | request_within_origin, |
39 | 40 | sse_within_origin, |
40 | 41 | stream_within_origin, |
@@ -69,12 +70,10 @@ class ResumptionError(StreamableHTTPError): |
69 | 70 |
|
70 | 71 | def _unfollowed_redirect(response: httpx2.Response) -> str | None: |
71 | 72 | """Describe a redirect `stream_within_origin` left unfollowed, or None if `response` is not one.""" |
72 | | - if response.next_request is None: |
| 73 | + location = redirect_location(response) |
| 74 | + if location is None: |
73 | 75 | return None |
74 | | - sent = response.request.url |
75 | | - # Query and userinfo are left out: they can carry state that does not belong in logs. |
76 | | - location = response.next_request.url.copy_with(userinfo=b"", query=None, fragment=None) |
77 | | - if sent.scheme == "https" and location.scheme == "http" and location.host == sent.host: |
| 76 | + if response.request.url.scheme == "https" and location.scheme == "http": |
78 | 77 | return ( |
79 | 78 | f"Redirect to {location} not followed: it would downgrade this HTTPS endpoint to plain HTTP.\n" |
80 | 79 | "The server is likely behind a TLS-terminating proxy whose forwarded headers it does not trust,\n" |
@@ -694,8 +693,9 @@ async def streamable_http_client( |
694 | 693 | authentication, or other HTTP settings, create an httpx2.AsyncClient and pass it here. |
695 | 694 | Whichever client is used, MCP requests follow a redirect only when it stays on the |
696 | 695 | endpoint's origin (same scheme, host and port, or http to https on the same host with |
697 | | - default ports) and keeps the request method (307/308); any other redirect is not |
698 | | - followed and the message it answered fails with an error naming the location. The |
| 696 | + default ports) and keeps the request method (307/308 for a POST; any status for the GET |
| 697 | + stream); any other redirect is not followed and the message it answered fails with an |
| 698 | + error naming the location. The |
699 | 699 | client's `follow_redirects` setting is not consulted; the SDK's OAuth providers apply the |
700 | 700 | same rule to the requests they make. |
701 | 701 | terminate_on_close: If True, send a DELETE request to terminate the session when the context exits. |
|
0 commit comments