|
17 | 17 |
|
18 | 18 | from mcp.client._transport import TransportStreams |
19 | 19 | from mcp.shared._httpx_utils import create_mcp_http_client |
| 20 | +from mcp.shared.exceptions import HttpError |
20 | 21 | from mcp.shared.message import ClientMessageMetadata, SessionMessage |
21 | 22 | from mcp.types import ( |
22 | 23 | INTERNAL_ERROR, |
@@ -269,17 +270,41 @@ async def _handle_post_request(self, ctx: RequestContext) -> None: |
269 | 270 |
|
270 | 271 | if response.status_code == 404: # pragma: no branch |
271 | 272 | if isinstance(message, JSONRPCRequest): # pragma: no branch |
272 | | - error_data = ErrorData(code=INVALID_REQUEST, message="Session terminated") |
| 273 | + error_data = ErrorData( |
| 274 | + code=INVALID_REQUEST, |
| 275 | + message="Session terminated (HTTP 404)", |
| 276 | + data={"http_status": 404}, |
| 277 | + ) |
273 | 278 | session_message = SessionMessage(JSONRPCError(jsonrpc="2.0", id=message.id, error=error_data)) |
274 | 279 | await ctx.read_stream_writer.send(session_message) |
| 280 | + else: |
| 281 | + raise HttpError(404, "Session terminated (HTTP 404)") |
275 | 282 | return |
276 | 283 |
|
| 284 | + if response.status_code in (401, 403): |
| 285 | + status_label = "Unauthorized" if response.status_code == 401 else "Forbidden" |
| 286 | + error_message = f"HTTP {response.status_code} {status_label}" |
| 287 | + if isinstance(message, JSONRPCRequest): |
| 288 | + error_data = ErrorData( |
| 289 | + code=INTERNAL_ERROR, |
| 290 | + message=error_message, |
| 291 | + data={"http_status": response.status_code}, |
| 292 | + ) |
| 293 | + session_message = SessionMessage(JSONRPCError(jsonrpc="2.0", id=message.id, error=error_data)) |
| 294 | + await ctx.read_stream_writer.send(session_message) |
| 295 | + raise HttpError(response.status_code, error_message) |
| 296 | + |
277 | 297 | if response.status_code >= 400: |
| 298 | + error_message = f"HTTP {response.status_code}" |
278 | 299 | if isinstance(message, JSONRPCRequest): |
279 | | - error_data = ErrorData(code=INTERNAL_ERROR, message="Server returned an error response") |
| 300 | + error_data = ErrorData( |
| 301 | + code=INTERNAL_ERROR, |
| 302 | + message=error_message, |
| 303 | + data={"http_status": response.status_code}, |
| 304 | + ) |
280 | 305 | session_message = SessionMessage(JSONRPCError(jsonrpc="2.0", id=message.id, error=error_data)) |
281 | 306 | await ctx.read_stream_writer.send(session_message) |
282 | | - return |
| 307 | + raise HttpError(response.status_code, error_message) |
283 | 308 |
|
284 | 309 | if is_initialization: |
285 | 310 | self._maybe_extract_session_id_from_response(response) |
@@ -467,19 +492,24 @@ async def post_writer( |
467 | 492 | ) |
468 | 493 |
|
469 | 494 | async def handle_request_async(): |
470 | | - if is_resumption: |
471 | | - await self._handle_resumption_request(ctx) |
472 | | - else: |
473 | | - await self._handle_post_request(ctx) |
| 495 | + try: |
| 496 | + if is_resumption: |
| 497 | + await self._handle_resumption_request(ctx) |
| 498 | + else: |
| 499 | + await self._handle_post_request(ctx) |
| 500 | + except Exception as exc: |
| 501 | + logger.exception("Error handling request") |
| 502 | + await read_stream_writer.send(exc) |
474 | 503 |
|
475 | 504 | # If this is a request, start a new task to handle it |
476 | 505 | if isinstance(message, JSONRPCRequest): |
477 | 506 | tg.start_soon(handle_request_async) |
478 | 507 | else: |
479 | 508 | await handle_request_async() |
480 | 509 |
|
481 | | - except Exception: # pragma: lax no cover |
| 510 | + except Exception as exc: # pragma: lax no cover |
482 | 511 | logger.exception("Error in post_writer") |
| 512 | + await read_stream_writer.send(exc) |
483 | 513 | finally: |
484 | 514 | await read_stream_writer.aclose() |
485 | 515 | await write_stream.aclose() |
|
0 commit comments