fix: allow null id in JSONRPCError per JSON-RPC 2.0 spec (#2056)
This commit is contained in:
parent
3b53fb9a00
commit
705497a593
6 changed files with 151 additions and 24 deletions
|
|
@ -490,7 +490,7 @@ class Server(Generic[LifespanResultT]):
|
|||
except Exception as err:
|
||||
if raise_exceptions: # pragma: no cover
|
||||
raise err
|
||||
response = types.ErrorData(code=0, message=str(err), data=None)
|
||||
response = types.ErrorData(code=0, message=str(err))
|
||||
|
||||
await message.respond(response)
|
||||
else: # pragma: no cover
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@ class SseServerTransport:
|
|||
await sse_stream_writer.send(
|
||||
{
|
||||
"event": "message",
|
||||
"data": session_message.message.model_dump_json(by_alias=True, exclude_none=True),
|
||||
"data": session_message.message.model_dump_json(by_alias=True, exclude_unset=True),
|
||||
}
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ async def stdio_server(stdin: anyio.AsyncFile[str] | None = None, stdout: anyio.
|
|||
try:
|
||||
async with write_stream_reader:
|
||||
async for session_message in write_stream_reader:
|
||||
json = session_message.message.model_dump_json(by_alias=True, exclude_none=True)
|
||||
json = session_message.message.model_dump_json(by_alias=True, exclude_unset=True)
|
||||
await stdout.write(json + "\n")
|
||||
await stdout.flush()
|
||||
except anyio.ClosedResourceError: # pragma: no cover
|
||||
|
|
|
|||
|
|
@ -298,12 +298,12 @@ class StreamableHTTPServerTransport:
|
|||
# Return a properly formatted JSON error response
|
||||
error_response = JSONRPCError(
|
||||
jsonrpc="2.0",
|
||||
id="server-error", # We don't have a request ID for general errors
|
||||
id=None,
|
||||
error=ErrorData(code=error_code, message=error_message),
|
||||
)
|
||||
|
||||
return Response(
|
||||
error_response.model_dump_json(by_alias=True, exclude_none=True),
|
||||
error_response.model_dump_json(by_alias=True, exclude_unset=True),
|
||||
status_code=status_code,
|
||||
headers=response_headers,
|
||||
)
|
||||
|
|
@ -323,7 +323,7 @@ class StreamableHTTPServerTransport:
|
|||
response_headers[MCP_SESSION_ID_HEADER] = self.mcp_session_id
|
||||
|
||||
return Response(
|
||||
response_message.model_dump_json(by_alias=True, exclude_none=True) if response_message else None,
|
||||
response_message.model_dump_json(by_alias=True, exclude_unset=True) if response_message else None,
|
||||
status_code=status_code,
|
||||
headers=response_headers,
|
||||
)
|
||||
|
|
@ -336,7 +336,7 @@ class StreamableHTTPServerTransport:
|
|||
"""Create event data dictionary from an EventMessage."""
|
||||
event_data = {
|
||||
"event": "message",
|
||||
"data": event_message.message.model_dump_json(by_alias=True, exclude_none=True),
|
||||
"data": event_message.message.model_dump_json(by_alias=True, exclude_unset=True),
|
||||
}
|
||||
|
||||
# If an event ID was provided, include it
|
||||
|
|
@ -975,12 +975,11 @@ class StreamableHTTPServerTransport:
|
|||
# Determine which request stream(s) should receive this message
|
||||
message = session_message.message
|
||||
target_request_id = None
|
||||
# Check if this is a response
|
||||
if isinstance(message, JSONRPCResponse | JSONRPCError):
|
||||
response_id = str(message.id)
|
||||
# If this response is for an existing request stream,
|
||||
# send it there
|
||||
target_request_id = response_id
|
||||
# Check if this is a response with a known request id.
|
||||
# Null-id errors (e.g., parse errors) fall through to
|
||||
# the GET stream since they can't be correlated.
|
||||
if isinstance(message, JSONRPCResponse | JSONRPCError) and message.id is not None:
|
||||
target_request_id = str(message.id)
|
||||
# Extract related_request_id from meta if it exists
|
||||
elif ( # pragma: no cover
|
||||
session_message.metadata is not None
|
||||
|
|
|
|||
|
|
@ -244,11 +244,11 @@ class StreamableHTTPSessionManager:
|
|||
# See: https://github.com/modelcontextprotocol/python-sdk/issues/1821
|
||||
error_response = JSONRPCError(
|
||||
jsonrpc="2.0",
|
||||
id="server-error",
|
||||
id=None,
|
||||
error=ErrorData(code=INVALID_REQUEST, message="Session not found"),
|
||||
)
|
||||
response = Response(
|
||||
content=error_response.model_dump_json(by_alias=True, exclude_none=True),
|
||||
content=error_response.model_dump_json(by_alias=True, exclude_unset=True),
|
||||
status_code=HTTPStatus.NOT_FOUND,
|
||||
media_type="application/json",
|
||||
)
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ async def websocket_server(scope: Scope, receive: Receive, send: Send):
|
|||
try:
|
||||
async with write_stream_reader:
|
||||
async for session_message in write_stream_reader:
|
||||
obj = session_message.message.model_dump_json(by_alias=True, exclude_none=True)
|
||||
obj = session_message.message.model_dump_json(by_alias=True, exclude_unset=True)
|
||||
await websocket.send_text(obj)
|
||||
except anyio.ClosedResourceError:
|
||||
await websocket.close()
|
||||
|
|
|
|||
Loading…
Reference in a new issue