Skip to content

Conversation

@mattzcarey
Copy link
Contributor

@mattzcarey mattzcarey commented Dec 1, 2025

web standards based streamable http transport.
marked experimental

closes #260

Motivation and Context

How Has This Been Tested?

Breaking Changes

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

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

@mattzcarey mattzcarey requested a review from a team as a code owner December 1, 2025 22:49
@pkg-pr-new
Copy link

pkg-pr-new bot commented Dec 1, 2025

Open in StackBlitz

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/sdk@1209

commit: 4dfa889

@mattzcarey mattzcarey force-pushed the feat-fetch-transport branch from 62eb340 to cbaa269 Compare December 2, 2025 12:22
tonxxd added a commit to mcp-use/mcp-ts-sdk-fork that referenced this pull request Dec 8, 2025
@mattzcarey mattzcarey force-pushed the feat-fetch-transport branch from cbaa269 to 31b824d Compare December 8, 2025 16:04
Copy link
Contributor

@KKonstantinov KKonstantinov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, left a few comments when diffing with the original streamableHttp


let rawMessage;
try {
rawMessage = await req.json();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the original streamableHttp, we have:

                const body = await getRawBody(req, {
                    limit: MAXIMUM_MESSAGE_SIZE,
                    encoding: parsedCt.parameters.charset ?? 'utf-8'
                });

E.g. we're losing the 4mb maximum message size here, let's discuss if we want to keep it or get rid of it, but it is a difference in behavior

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is not a good way to keep it here.

Copy link
Contributor

@felixweinberger felixweinberger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 to @KKonstantinov's comments to be sure what we provide matches spec and existing features.

A more high level point: I'm a bit worried about introducing an additional transport (even if marked "experimental" - people are still going to import it) that is IIUC mostly duplicated code from the existing streamableHttpServerTransport with some changes at the edges to use the fetch API instead of Node API.

I think the motivation is valid - we want to meet people where they are if they want to use Web Standards. I wonder if this duplication is the right strategy though, as this essentially duplicates maintenance effort for any changes to the streamable http spec (and any bug fixes, e.g. some of the stuff @KKonstantinov pointed out).

I see we added nodeRequestToWebRequest() and webResponseToNodeResponse() adapters in the express example - have we considered going with an "adapters only" approach rather than duplicating much of the transport code for example?

mcpServer = result.mcpServer;

// Verify resumability is enabled on the transport
expect(transport['_eventStore']).toBeDefined();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did we need to remove this?

"client": "tsx scripts/cli.ts client"
},
"dependencies": {
"@hono/node-server": "^1.19.7",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looked into this library a bit https://github.com/honojs/hono

While it doesn't have a huge number of stars (~580), it's actually not a very big package - ~1.5k lines of code, mostly to convert between Node.js and WebStandards requests. 3.5M DLs on npm (cf. ~10M for TypeScript SDK). The maintainer is also the creator of hono and the package has had a very regular release cadence.

Compared to our other runtime dependencies it is a bit fresher / less mature. It's in the same ballpark as our eventsource (SSE) and eventsource-parser (SHTTP) dependencies roughly in terms of adoption, but those don't have an org like hono behind them, so arguably this new dependency has more backing than other ones we already depend on.

So in all I think this is fine to achieve our goal of decoupling from Express. What's worth discussing is whether we ship this in v1 or wait for v2 with this for risk management in case this causes unexpected regressions.

@mattzcarey @KKonstantinov have either of you potentially used this in production before?

"client": "tsx scripts/cli.ts client"
},
"dependencies": {
"@hono/node-server": "^1.19.7",

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is a dependency for the example only shouldn't this be a devDependency rather than a dependency (that would be installed with the library?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

its used in the rewritten transport

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh...as usual, GitHub is very bad at showing diffs.

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.

Transport for web standard fetch APIs: FetchSSEServerTransport

5 participants