| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| Expand Up | @@ -12,7 +12,12 @@ | |
|
|
||
| from mcp.shared._compat import resync_tracer | ||
| from mcp.shared._context_streams import create_context_streams | ||
| from mcp.shared._httpx_utils import McpHttpClientFactory, create_mcp_http_client | ||
| from mcp.shared._httpx_utils import ( | ||
| McpHttpClientFactory, | ||
| create_mcp_http_client, | ||
| request_within_origin, | ||
| sse_within_origin, | ||
| ) | ||
| from mcp.shared.message import SessionMessage | ||
|
|
||
| logger = logging.getLogger(__name__) | ||
| Expand Down Expand Up | @@ -47,15 +52,21 @@ async def sse_client( | |
| headers: Optional headers to include in requests. | ||
| timeout: HTTP timeout for regular operations (in seconds). | ||
| sse_read_timeout: Timeout for SSE read operations (in seconds). | ||
| httpx_client_factory: Factory function for creating the httpx2 client. | ||
| httpx_client_factory: Factory function for creating the httpx2 client. Whichever client it | ||
| returns, MCP requests follow a redirect only when it stays on the endpoint's origin | ||
| (same scheme, host and port, or http to https on the same host with default ports) and | ||
| keeps the request method; any other redirect is not followed, so connecting fails with | ||
| `httpx2.HTTPStatusError` for the redirect response. The client's `follow_redirects` | ||
| setting is not consulted, and requests `auth` makes during an MCP request do not follow | ||
| redirects. | ||
| auth: Optional httpx2 authentication handler. | ||
| on_session_created: Optional callback invoked with the session ID when received. | ||
| """ | ||
| logger.debug(f"Connecting to SSE endpoint: {remove_request_params(url)}") | ||
| async with httpx_client_factory( | ||
| headers=headers, auth=auth, timeout=httpx2.Timeout(timeout, read=sse_read_timeout) | ||
| ) as client: | ||
| async with client.sse(url) as event_source: | ||
| async with sse_within_origin(client, url) as event_source: | ||
|
Comment thread
Copy link
Copy Markdown
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityP1: When an SSE endpoint upgrades from HTTP to HTTPS, this wrapper connects the stream over HTTPS but sse_reader still resolves the relative endpoint event against the original HTTP URL. The first MCP POST therefore targets HTTP and can fail on common 301/302 upgrades or send the message over an insecure connection; resolve and validate the endpoint against the final SSE response URL. Prompt for AI agentsCheck if this issue is valid — if so, understand the root cause and fix it. At src/mcp/client/sse.py, line 69:
<comment>When an SSE endpoint upgrades from HTTP to HTTPS, this wrapper connects the stream over HTTPS but `sse_reader` still resolves the relative endpoint event against the original HTTP URL. The first MCP POST therefore targets HTTP and can fail on common 301/302 upgrades or send the message over an insecure connection; resolve and validate the endpoint against the final SSE response URL.</comment>
<file context>
@@ -47,15 +52,21 @@ async def sse_client(
headers=headers, auth=auth, timeout=httpx2.Timeout(timeout, read=sse_read_timeout)
) as client:
- async with client.sse(url) as event_source:
+ async with sse_within_origin(client, url) as event_source:
event_source.response.raise_for_status()
logger.debug("SSE connection established")
</file context>
Sorry, something went wrong.
All reactions
|
||
| event_source.response.raise_for_status() | ||
| logger.debug("SSE connection established") | ||
|
|
||
| Expand Down Expand Up | @@ -121,13 +132,11 @@ async def post_writer(endpoint_url: str): | |
|
|
||
| async def _send_message(session_message: SessionMessage) -> None: | ||
| logger.debug(f"Sending client message: {session_message}") | ||
| response = await client.post( | ||
| response = await request_within_origin( | ||
| client, | ||
| "POST", | ||
| endpoint_url, | ||
| json=session_message.message.model_dump( | ||
| by_alias=True, | ||
| mode="json", | ||
| exclude_unset=True, | ||
| ), | ||
| json=session_message.message.model_dump(by_alias=True, mode="json", exclude_unset=True), | ||
| ) | ||
| response.raise_for_status() | ||
|
Comment thread
maxisbey marked this conversation as resolved.
|
||
| logger.debug(f"Client message sent successfully: {response.status_code}") | ||
| Expand Down | ||
| Back | FazBrowse Home | New Git URL |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityP3: This line says the transport follows any redirect that stays on the endpoint's origin, but stream_within_origin also requires the method to be unchanged. A same-origin 301/302/303 that httpx2 turns into a GET (common for a POST) is treated as unfollowed, not followed. Qualify the wording to mention that only method-preserving redirects (e.g. 307/308) are followed.
Prompt for AI agents-v1's internal client set follow_redirects=True; set it explicitly when supplying your own httpx2.AsyncClient to preserve that behavior.
+v1's internal client set follow_redirects=True. You don't need it on your own client: the transport follows a redirect within the endpoint's origin (a trailing-slash redirect, say) itself, and does not follow one anywhere else, whatever the client is configured to do.
streamable_http_client itself keeps a small signature — streamable_http_client(url, *, http_client=None, terminate_on_close=True) — and now yields a 2-tuple (next section). The removed function's other parameters map onto the client you build:
</file context>
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.