Skip to content

Fix event stream line parsing to handle CRLF and empty lines correctly #89

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 27, 2025

Conversation

aspitz
Copy link
Contributor

@aspitz aspitz commented Apr 25, 2025

Optimized code in connectToEventStream to use .lines computed value of AsyncSequence to produce a AsyncLineSequence instead of building a lines manually.

Motivation and Context

How Has This Been Tested?

Breaking Changes

No

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update
  • Optimization

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

…ue of `AsyncSequence` to produce a `AsyncLineSequence` instead of building a lines manually.
@mattt
Copy link
Contributor

mattt commented Apr 25, 2025

Nice! That sounds like a totally reasonable optimization. Thanks so much for sharing it.

I kicked off a CI build. Should get a chance to review it in depth over the weekend.

@stallent
Copy link
Contributor

stallent commented Apr 25, 2025

I def like the code change but checked out the branch and tested and it doesn't seem to be detecting the empty line that the code needs to dispatch notifications. I can only assume it works for you but for me line 225 is never catching so the client isn't getting the notes, where it did before going byte at a time.

- Fiexed original issue I experienced with line 229 `while let newlineIndex = buffer.firstIndex(of: "\n") {` not handling "\r\n" properly
- Added unit test to test for "\r\n" scenario
- Simplified `end of event` test - `line` creation trims newline, added code trims carriage return. Only thing that should be left is an empty line
@aspitz
Copy link
Contributor Author

aspitz commented Apr 27, 2025

Apologies, I jumped the gun in submitting this PR.

The core issue I experienced was that line 229 while let newlineIndex = buffer.firstIndex(of: "\n") { doesn't appear to handle "\r\n" as a separate carriage return followed by a newline so it returns a nil instead of an index.

I've updated the code to while let newlineIndex = buffer.utf8.firstIndex(where: { $0 == 10 }) which handles "\r\n" properly and I've added a unit test to test for the "\r\n" scenario. I've added code to trim carriage returns at the end of the line. Between that and the fact that creating line trims newline of the end of the line the end of event test becomes much simpler.

@stallent
Copy link
Contributor

@aspitz Thank you! Yeah, its annoying and we have run into that before. We have MCP servers running in python that return different line endings than the ones we have running in node+typescript, CRLF vs CRLF+CRLF.

@mattt
Copy link
Contributor

mattt commented Apr 27, 2025

@aspitz @stallent Good morning! Thank you both for looking into this. I started to write a reply, but waited too long and y'all beat me to it.

To @stallent's point, I found this post on the Apple Developer forums from someone running into the same problem using .lines for SSE parsing.

Taking a fresh look at this now 😄

@stallent
Copy link
Contributor

@mattt if you take this, i'll resolve any merge conflicts with my minimal fix to get streamable htttp client working with latest servers. Still think we have larger api chats around that, but hopefully the modest current PR (vs the too big of one i was pursuing) will unblock us until further chats can be had.

@mattt mattt changed the title Optimized code in connectToEventStream Fix event stream line parsing to handle CRLF and empty lines correctly Apr 27, 2025
@mattt
Copy link
Contributor

mattt commented Apr 27, 2025

This is looking good. Thank you again, @aspitz, for your work on this. I just updated the PR to reflect the final changes, and will merge this shortly.

@mattt mattt merged commit f6e401a into modelcontextprotocol:main Apr 27, 2025
4 checks passed
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.

3 participants