### Initial Checks - [x] I confirm that I'm using the latest version of MCP Python SDK - [x] I confirm that I searched for my issue in https://github.com/modelcontextprotocol/python-sdk/issues before opening this issue ### Description ### Summary The MCP Python client crashes when receiving empty SSE (Server-Sent Events) data from the MCP server, which is sent as part of the resumability priming event. This causes a `ValidationError` when trying to parse empty strings as JSON-RPC messages. ### Error Message ``` Error parsing SSE message pydantic_core._pydantic_core.ValidationError: 1 validation error for JSONRPCMessage Invalid JSON: EOF while parsing a value at line 1 column 0 [type=json_invalid, input_value='', input_type=str] ``` ## Root Cause Analysis ### Server Behavior (Expected) The MCP Server SDK (`@modelcontextprotocol/sdk`) intentionally sends empty SSE events as "priming events" for resumability support: **File**: `node_modules/@modelcontextprotocol/sdk/dist/esm/server/streamableHttp.js` ```javascript // Lines 131-141 async _maybeWritePrimingEvent(res, streamId) { if (!this._eventStore) { return; } const primingEventId = await this._eventStore.storeEvent(streamId, {}); let primingEvent = `id: ${primingEventId}\ndata: \n\n`; // ← Empty data field if (this._retryInterval !== undefined) { primingEvent = `id: ${primingEventId}\nretry: ${this._retryInterval}\ndata: \n\n`; } res.write(primingEvent); } ``` This is called during POST request handling (line 441): ```javascript res.writeHead(200, headers); await this._maybeWritePrimingEvent(res, streamId); // Sends empty SSE event ``` ### Client Behavior (Buggy) The Python client attempts to parse ALL SSE data as JSON without checking if it's empty first: **File**: `mcp/client/streamable_http.py` ```python # Lines 160-162 if sse.event == "message": try: message = JSONRPCMessage.model_validate_json(sse.data) # ❌ Fails on empty data ``` ## Steps to Reproduce 1. Set up an MCP server using `@modelcontextprotocol/sdk` with `StreamableHTTPServerTransport` 2. Enable event store for resumability: 3. Connect a Python MCP client using `streamablehttp_client` 4. Send any request (e.g., `list_tools()`) 5. Observe the ValidationError when the priming event is received ## Workaround Until this is fixed in the SDK, users can apply a patch: ```python import logging from mcp.client.streamable_http import StreamableHTTPTransport # Save original method original_handle_sse_event = StreamableHTTPTransport._handle_sse_event # Create patched version async def patched_handle_sse_event(self, sse, read_stream_writer, original_request_id=None, resumption_callback=None, is_initialization=False): """Patched version that skips empty SSE data.""" # Skip empty data if not sse.data or sse.data.strip() == '': logging.debug(f"Skipping empty SSE data (event: {sse.event})") return False # Call original method for non-empty data return await original_handle_sse_event( self, sse, read_stream_writer, original_request_id, resumption_callback, is_initialization ) # Apply patch StreamableHTTPTransport._handle_sse_event = patched_handle_sse_event ``` ### Python & MCP Python SDK ```Text For Client (I'm using python-sdk):1.22.0 For Server (I'm using ts-sdk): 1.23.0 ```