python-sdk icon indicating copy to clipboard operation
python-sdk copied to clipboard

Python MCP Client ValidationError: Empty SSE data causes JSON parsing failure

Open injusticescorpio opened this issue 2 months ago • 0 comments

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

// 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):

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

# 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:

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

For Client (I'm using python-sdk):1.22.0
For Server (I'm using ts-sdk): 1.23.0

injusticescorpio avatar Nov 26 '25 17:11 injusticescorpio