| 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 | @@ -17,6 +17,7 @@ | |
|
|
||
| from mcp.client._transport import TransportStreams | ||
| from mcp.shared._httpx_utils import create_mcp_http_client | ||
| from mcp.shared.exceptions import HttpError | ||
| from mcp.shared.message import ClientMessageMetadata, SessionMessage | ||
| from mcp.types import ( | ||
| INTERNAL_ERROR, | ||
| Expand Down Expand Up | @@ -269,17 +270,41 @@ async def _handle_post_request(self, ctx: RequestContext) -> None: | |
|
|
||
| if response.status_code == 404: # pragma: no branch | ||
| if isinstance(message, JSONRPCRequest): # pragma: no branch | ||
| error_data = ErrorData(code=INVALID_REQUEST, message="Session terminated") | ||
| error_data = ErrorData( | ||
| code=INVALID_REQUEST, | ||
| message="Session terminated (HTTP 404)", | ||
| data={"http_status": 404}, | ||
| ) | ||
| session_message = SessionMessage(JSONRPCError(jsonrpc="2.0", id=message.id, error=error_data)) | ||
| await ctx.read_stream_writer.send(session_message) | ||
| else: | ||
| raise HttpError(404, "Session terminated (HTTP 404)") | ||
| return | ||
|
|
||
| if response.status_code in (401, 403): | ||
| status_label = "Unauthorized" if response.status_code == 401 else "Forbidden" | ||
| error_message = f"HTTP {response.status_code} {status_label}" | ||
| if isinstance(message, JSONRPCRequest): | ||
|
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 QualityThis raises after already sending a JSONRPCError to the read stream (line 26). But handle_request_async wraps _handle_post_request in a try/except that catches this HttpError and sends it to read_stream_writer again. So for JSONRPCRequest messages hitting 401/403 (and same for the generic >=400 path below), the consumer receives both a SessionMessage(JSONRPCError) and then an HttpError exception from the same stream — two messages for one request. I think you either want to not raise here when the JSONRPCError was already sent, or skip the JSONRPCError and just raise (letting the wrapper forward it). The current approach of doing both will confuse callers.
Sorry, something went wrong.
All reactions
|
||
| error_data = ErrorData( | ||
| code=INTERNAL_ERROR, | ||
| message=error_message, | ||
| data={"http_status": response.status_code}, | ||
| ) | ||
| session_message = SessionMessage(JSONRPCError(jsonrpc="2.0", id=message.id, error=error_data)) | ||
| await ctx.read_stream_writer.send(session_message) | ||
| raise HttpError(response.status_code, error_message) | ||
|
|
||
| if response.status_code >= 400: | ||
| error_message = f"HTTP {response.status_code}" | ||
| if isinstance(message, JSONRPCRequest): | ||
| error_data = ErrorData(code=INTERNAL_ERROR, message="Server returned an error response") | ||
| error_data = ErrorData( | ||
| code=INTERNAL_ERROR, | ||
| message=error_message, | ||
| data={"http_status": response.status_code}, | ||
| ) | ||
| session_message = SessionMessage(JSONRPCError(jsonrpc="2.0", id=message.id, error=error_data)) | ||
| await ctx.read_stream_writer.send(session_message) | ||
| return | ||
| raise HttpError(response.status_code, error_message) | ||
|
|
||
| if is_initialization: | ||
| self._maybe_extract_session_id_from_response(response) | ||
| Expand Down Expand Up | @@ -467,19 +492,24 @@ async def post_writer( | |
| ) | ||
|
|
||
| async def handle_request_async(): | ||
| if is_resumption: | ||
| await self._handle_resumption_request(ctx) | ||
| else: | ||
| await self._handle_post_request(ctx) | ||
| try: | ||
| if is_resumption: | ||
| await self._handle_resumption_request(ctx) | ||
| else: | ||
| await self._handle_post_request(ctx) | ||
| except Exception as exc: | ||
| logger.exception("Error handling request") | ||
| await read_stream_writer.send(exc) | ||
|
|
||
| # If this is a request, start a new task to handle it | ||
| if isinstance(message, JSONRPCRequest): | ||
| tg.start_soon(handle_request_async) | ||
| else: | ||
| await handle_request_async() | ||
|
|
||
| except Exception: # pragma: lax no cover | ||
| except Exception as exc: # pragma: lax no cover | ||
| logger.exception("Error in post_writer") | ||
| await read_stream_writer.send(exc) | ||
| finally: | ||
| await read_stream_writer.aclose() | ||
| await write_stream.aclose() | ||
| 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 QualityRe-raising HttpError here means it escapes post_writer entirely — nothing above catches it, so it propagates into the task group and crashes the whole SSE client connection. The original code intentionally swallowed all exceptions to keep the writer alive for the connection lifetime.
For the SSE transport I think you want the same pattern as the other exceptions: send it through the read stream but don't re-raise. The caller can handle it from the stream without killing the connection.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
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 QualityThis is exactly the issue I'm having. I've fixed it in this PR: #2273
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.