Skip to content

Commit 2d82579

Browse files
committed
Client streamable-http: parse JSON-RPC errors from non-2xx response bodies
A spec-correct server may return the JSON-RPC error in an application/json body at a non-2xx status (e.g. 400 for INVALID_PARAMS, 404 for METHOD_NOT_FOUND per the 2026-07-28 transport binding). Surface that error to the caller instead of synthesizing a generic INTERNAL_ERROR / 'Session terminated' from the status alone. Falls back to the status-derived error if the body isn't valid JSON-RPC. Unconditional (not version-gated): parsing a JSON-RPC body from a 4xx application/json response is correct at any protocol version.
1 parent d64a738 commit 2d82579

1 file changed

Lines changed: 16 additions & 8 deletions

File tree

src/mcp/client/streamable_http.py

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -314,16 +314,24 @@ async def _handle_post_request(self, ctx: RequestContext) -> None:
314314
logger.debug("Received 202 Accepted")
315315
return
316316

317-
if response.status_code == 404:
318-
if isinstance(message, JSONRPCRequest):
319-
error_data = ErrorData(code=INVALID_REQUEST, message="Session terminated")
320-
session_message = SessionMessage(JSONRPCError(jsonrpc="2.0", id=message.id, error=error_data))
321-
await ctx.read_stream_writer.send(session_message)
322-
return
323-
324317
if response.status_code >= 400:
325318
if isinstance(message, JSONRPCRequest):
326-
error_data = ErrorData(code=INTERNAL_ERROR, message="Server returned an error response")
319+
# A spec-correct server may return the JSON-RPC error in the
320+
# body at a non-2xx status (e.g. 400 for INVALID_PARAMS, 404
321+
# for METHOD_NOT_FOUND). Surface that error rather than the
322+
# status-derived stand-in below.
323+
if response.headers.get("content-type", "").lower().startswith("application/json"):
324+
try:
325+
body = await response.aread()
326+
parsed = jsonrpc_message_adapter.validate_json(body, by_name=False)
327+
await ctx.read_stream_writer.send(SessionMessage(parsed))
328+
return
329+
except (httpx.StreamError, ValidationError):
330+
logger.debug("Non-2xx body was not a valid JSON-RPC message; using fallback error")
331+
if response.status_code == 404:
332+
error_data = ErrorData(code=INVALID_REQUEST, message="Session terminated")
333+
else:
334+
error_data = ErrorData(code=INTERNAL_ERROR, message="Server returned an error response")
327335
session_message = SessionMessage(JSONRPCError(jsonrpc="2.0", id=message.id, error=error_data))
328336
await ctx.read_stream_writer.send(session_message)
329337
return

0 commit comments

Comments
 (0)