Skip to content

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

@injusticescorpio

Description

@injusticescorpio

Initial Checks

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions