Skip to content

add support for Streamable HTTP server #294

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 5 commits into from
Apr 19, 2025

Conversation

shivdeepak
Copy link
Contributor

@shivdeepak shivdeepak commented Apr 10, 2025

Motivation and Context

typescript-sdk recently added support for Streamable HTTP client, and server. This PR leverages that change, and adds support for Streamable HTTP MCP Servers to inspector.

Other language bindings are also adding support for streamable HTTP. Integrating this change to the inspector will help towards those efforts by making testing and debugging easy.

Note that I am marking this PR as work in progress (WIP) because this PR cannot use the Streamable HTTP Client and Sever from typescript-sdk until a version bump.

How Has This Been Tested?

Clone this branch, and start the inspector locally

npm run dev

Caveat: You will have to manually build the latest typescript-sdk so that Streamable HTTP Client is available.

Once you have everything up and running. You should be able to see the new Streamable HTTP transport type.

Now, on a different terminal session, clone typescript-sdk and run.

npx tsx src/examples/server/simpleStreamableHttp.ts

This will start a Streamable HTTP MCP Server at http://localhost:3000/mcp

Connect to it, and you should be able to issue commands.

Screenshot 2025-04-09 at 8 55 50 PM

Here is an example tools/list command:

Screenshot 2025-04-09 at 9 04 36 PM

Here is an example ping command:

Screenshot 2025-04-09 at 9 07 06 PM

Breaking Changes

Currently this branch only works when typescript-sdk is built from the latest main. Therefore marking this PR as WIP.

There shouldn't be any breaking changes once there is a version bump in typescript-sdk and we update package.json here.

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

@shivdeepak
Copy link
Contributor Author

@cliffhall @jspahrsummers @pulkitsharma07 would appreciate some early feedback on this. 🙂

@shivdeepak shivdeepak changed the title add support for Streamable HTTP server [WIP] add support for Streamable HTTP server Apr 10, 2025
@cliffhall
Copy link
Contributor

@cliffhall @jspahrsummers @pulkitsharma07 would appreciate some early feedback on this. 🙂

Hi @shivdeepak!

Looks ok, but once the SDK version is bumped, we'll be able to test this more thoroughly. Hopefully that'll take place today. I have a PR queued up for it.

@cliffhall cliffhall requested a review from tadasant April 10, 2025 16:33
@ChrisLally
Copy link

we've got streamable http support live in https://inspect.mcp.garden for anyone that wants to try in the meantime!

@cliffhall
Copy link
Contributor

BTW, while modelcontextprotocol/typescript-sdk#305 has been merged, there are a few remaining bits such as resumability to be added to the SDK before we actually tag and publish its next release. As soon as it's good, we'll be doing a new inspector release.

@cliffhall cliffhall added enhancement New feature or request waiting on sdk Waiting for an SDK feature labels Apr 11, 2025
@ihrpr
Copy link

ihrpr commented Apr 17, 2025

@cliffhall, @shivdeepak TypeScript SDK new version is out now

@cliffhall
Copy link
Contributor

@cliffhall, @shivdeepak TypeScript SDK new version is out now

In order to test this, I will add streamable support to the everything server.

@shivdeepak
Copy link
Contributor Author

@cliffhall what is the everything server. do you need any support from my end?

@@ -94,6 +95,13 @@ const createTransport = async (req: express.Request): Promise<Transport> => {

console.log("Connected to SSE transport");
return transport;
} else if (transportType === "streamable-http") {
const transport = new StreamableHTTPClientTransport(
Copy link

Choose a reason for hiding this comment

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

To Auth feature works you should send headers to the server

Suggested change
const transport = new StreamableHTTPClientTransport(
const STREAMABLE_HTTP_HEADERS_PASSTHROUGH = ["authorization"];
const headers: HeadersInit = {};
for (const key of STREAMABLE_HTTP_HEADERS_PASSTHROUGH) {
if (req.headers[key] === undefined) {
continue;
}
const value = req.headers[key];
headers[key] = Array.isArray(value) ? value[value.length - 1] : value;
}
const transport = new StreamableHTTPClientTransport(

Copy link
Contributor Author

@shivdeepak shivdeepak Apr 18, 2025

Choose a reason for hiding this comment

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

Thanks. I have added the recommended changes and tested them. They work well.

MCP Inspector
Screenshot 2025-04-17 at 9 28 21 PM

Req/Resp Headers
Screenshot 2025-04-17 at 9 27 49 PM
Screenshot 2025-04-17 at 9 28 02 PM

@cliffhall
Copy link
Contributor

@cliffhall what is the everything server. do you need any support from my end?

@shivdeepak, if you wanted to make a PR for this, it shouldn't be hard and it would help test this PR.

@cliffhall cliffhall removed the waiting on sdk Waiting for an SDK feature label Apr 18, 2025
@shivdeepak
Copy link
Contributor Author

@cliffhall, thanks for the additional info. I don't mind picking this up -- I will create a PR for it soon.

Copy link
Contributor

@cliffhall cliffhall left a comment

Choose a reason for hiding this comment

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

Excellent work @shivdeepak.

I tested with

  • streamableHttp using your additions to the everything server.
  • stdio using local path to GooseTeam stdio server.
  • sse using the everything server's sse.ts
  • sse with oauth using this handy demo by @max-stytch (using /sse endpoint instead of the /login in the link)
inspector-streamable-http

@cliffhall cliffhall merged commit 6ab7ac3 into modelcontextprotocol:main Apr 19, 2025
2 checks passed
@ferrants
Copy link

Thanks for this! I am using it and it's working pretty well for a session-less MCP Streamable HTTP Server.

I ran into two potential issues, though probably just missing functionality with the new Streamable HTTP type, not any regressions.

  1. For using a session, the inspector doesn't appear to be retaining the session id header: mcp-session-id and sending it with subsequent requests reliably.
  2. I get intermittent Error POSTing to endpoint (HTTP 500): SSE connection not established errors for both the sessioned mcp server and no-session mcp server. It's not clear to me why it's intermittent. The request doesn't appear to be making it out of the inspector (no logging in the MCP server from the request). And when it fails, I see an error about the inspector request and setting of headers:
Received message for sessionId b12b7c97-65e4-4a61-9a71-d58cfaaa75a7
Error in /message route: Error: SSE connection not established
    at SSEServerTransport.handlePostMessage (file:///home/matt/code/inspector/node_modules/@modelcontextprotocol/sdk/dist/esm/server/sse.js:61:19)
    at file:///home/matt/code/inspector/server/build/index.js:150:25
    at Layer.handleRequest (/home/matt/code/inspector/node_modules/router/lib/layer.js:152:17)
    at next (/home/matt/code/inspector/node_modules/router/lib/route.js:157:13)
    at Route.dispatch (/home/matt/code/inspector/node_modules/router/lib/route.js:117:3)
    at handle (/home/matt/code/inspector/node_modules/router/index.js:435:11)
    at Layer.handleRequest (/home/matt/code/inspector/node_modules/router/lib/layer.js:152:17)
    at /home/matt/code/inspector/node_modules/router/index.js:295:15
    at processParams (/home/matt/code/inspector/node_modules/router/index.js:582:12)
    at next (/home/matt/code/inspector/node_modules/router/index.js:291:5)
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
    at new NodeError (node:internal/errors:406:5)
    at ServerResponse.setHeader (node:_http_outgoing:652:11)
    at ServerResponse.header (/home/matt/code/inspector/node_modules/express/lib/response.js:684:10)
    at ServerResponse.json (/home/matt/code/inspector/node_modules/express/lib/response.js:247:10)
    at file:///home/matt/code/inspector/server/build/index.js:154:25
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
New SSE connection
Query parameters: [Object: null prototype] {
  transportType: 'streamable-http',
  url: 'http://localhost:3002/mcp'
}

Screenshot from 2025-04-21 02-03-55

@cliffhall
Copy link
Contributor

Hi @ferrants

Thanks for the report. In order to put this one through its paces, we've needed a server for testing, and that was the everything server in the example servers repo. Testing of these changes against it worked fine, but it has subsequently cast light on a bug in this implementation. We're working on that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants