Skip to content

Conversation

@felixweinberger
Copy link
Contributor

@felixweinberger felixweinberger commented Nov 25, 2025

Skip empty SSE data events (keep-alive pings) in the streamable HTTP client to avoid JSON parsing errors.

Motivation and Context

SSE servers may send empty data lines as keep-alive pings. The current implementation attempts to parse all SSE data as JSON, which fails for empty data, causing connection errors.

How Has This Been Tested?

  • Added unit test for _handle_sse_event with empty SSE data
  • Existing streamable HTTP integration tests pass

Breaking Changes

None

Types of changes

  • Bug fix (non-breaking change which fixes an issue)

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

This is a defensive fix to handle keep-alive pings gracefully.

@felixweinberger felixweinberger changed the base branch from main to maxisbey/SEP-1686_Tasks November 25, 2025 18:36
@meffmadd
Copy link

meffmadd commented Nov 26, 2025

I provided a reproducible example in the relevant issue for this PR: #1146 (comment)
The issue also occurs on the reference everything MCP server.

@felixweinberger felixweinberger linked an issue Nov 26, 2025 that may be closed by this pull request
2 tasks
@meffmadd
Copy link

Patching the _handle_sse_event method as proposed by this PR fixes the error:

import asyncio
from functools import wraps
from unittest.mock import patch

from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client

def patch_mcp_sse_issue(view_func):
    @wraps(view_func)
    async def wrapper(*args, **kwargs):
        sse = args[1]
        if not sse.data:
            return False
        else:
            return await view_func(*args, **kwargs)

    return wrapper


async def example():
    async with streamablehttp_client("http://localhost:3001/mcp", headers={"Content-Type": "application/json"}) as (
            read_stream,
            write_stream,
            _,
    ):
        async with ClientSession(read_stream, write_stream) as session:
            await session.initialize()

if __name__ == "__main__":
    from mcp.client.streamable_http import StreamableHTTPTransport
    with patch("mcp.client.streamable_http.StreamableHTTPTransport._handle_sse_event",
               new=patch_mcp_sse_issue(StreamableHTTPTransport._handle_sse_event)):
        asyncio.run(example())

Skip empty SSE data events (keep-alive pings) in the streamable HTTP
client to avoid JSON parsing errors. SSE servers may send empty data
lines as keep-alive messages, and the current implementation attempts
to parse all SSE data as JSON, which fails for empty data.
@felixweinberger felixweinberger changed the title Skip empty SSE data and fix example client tool name Skip empty SSE data to avoid parsing errors Nov 26, 2025
@felixweinberger felixweinberger changed the base branch from maxisbey/SEP-1686_Tasks to main November 26, 2025 13:31
@felixweinberger felixweinberger marked this pull request as ready for review November 26, 2025 13:48
@maxisbey maxisbey enabled auto-merge (squash) November 26, 2025 14:00
@maxisbey maxisbey merged commit 5983a65 into main Nov 26, 2025
21 checks passed
@maxisbey maxisbey deleted the fweinberger/fix-demo branch November 26, 2025 18:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Streamable Http transport handle ping message

4 participants