Skip to content

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

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-141async_maybeWritePrimingEvent(res,streamId){if(!this._eventStore){return;}constprimingEventId=awaitthis._eventStore.storeEvent(streamId,{});letprimingEvent=`id: ${primingEventId}\ndata: \n\n`;// ← Empty data fieldif(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);awaitthis._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-162ifsse.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:

importloggingfrommcp.client.streamable_httpimportStreamableHTTPTransport# Save original methodoriginal_handle_sse_event=StreamableHTTPTransport._handle_sse_event# Create patched versionasyncdefpatched_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 dataifnotsse.dataorsse.data.strip() =='':
logging.debug(f"Skipping empty SSE data (event: {sse.event})")
returnFalse# Call original method for non-empty datareturnawaitoriginal_handle_sse_event(
self, sse, read_stream_writer, original_request_id, resumption_callback, is_initialization
)
# Apply patchStreamableHTTPTransport._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