Skip to content

Conversation

@PeterRodenkirchAA
Copy link

@PeterRodenkirchAA PeterRodenkirchAA commented Sep 12, 2025

Related Issue: #8

Why?

The overhead of a stateful streamable HTTP mode might not be necessary for a lot of use cases that submit a simple code execution task via POST request.
We observed some issue with the stateful mode concerning pending GET requests and supporting a stateless mode would simplify the MCP server integration.

What?

  • New mode: streamable_http_stateless

    • Stateless per-request handling: a new MCP server and transport are created for each POST /mcp.
    • GET /mcp and DELETE /mcp return 405 -> server-to-client notifications are not supported.
    • The stateful mode is unaffected
  • CLI and Python API

    • adds streamable-http-stateless as a mode:
      • uvx mcp-run-python streamable-http-stateless --port 3001
  • TypeScript part:

    • runStreamableHttp delegates to:
      • createStatefulHttpServer(...)
      • createStatelessHttpServer(...)
    • Refactored path matching into shared helpers:
      • createPathMatcher(req, url) and pathMatch(req, url)

Usage

  • Stateful:
uvx mcp-run-python streamable-http --port 3001
  • Stateless:
uvx mcp-run-python streamable-http-stateless --port 3001

res.end()
}

function createPathMatcher(req: http.IncomingMessage, url: URL) {
Copy link

Choose a reason for hiding this comment

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

Does this need to be a factory?

}
}

function pathMatch(req: http.IncomingMessage, url: URL) {
Copy link

Choose a reason for hiding this comment

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

Can this be inlined as well?

@DouweM
Copy link

DouweM commented Oct 21, 2025

@PeterRodenkirchAA Sorry for the delay here!

@Kludex As our resident MCP maintainer, do you have any concerns with this?

@DouweM DouweM self-assigned this Oct 21, 2025
Comment on lines 220 to 230
} else if (match('GET', '/mcp')) {
// SSE notifications not supported in stateless mode
httpSetJsonResponse(res, 405, 'Method not allowed.', -32000)
} else if (match('DELETE', '/mcp')) {
// Session termination not needed in stateless mode
httpSetJsonResponse(res, 405, 'Method not allowed.', -32000)
} else if (pathMatch(req, url)) {
httpSetTextResponse(res, 405, 'Method not allowed')
} else {
httpSetTextResponse(res, 404, 'Page not found')
}
Copy link
Member

Choose a reason for hiding this comment

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

Why are we doing so much manually? Doesn't the MCP package handles those?

Copy link
Author

Choose a reason for hiding this comment

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

Good point, this is already handled by handleRequest() from the MCP SDK. I adapted this part now.

@Kludex
Copy link
Member

Kludex commented Oct 22, 2025

@Kludex As our resident MCP maintainer, do you have any concerns with this?

Conceptually this seems fine.

@PeterRodenkirchAA
Copy link
Author

@DouweM @Kludex Thank you for your feedback! I adapted the code according to your suggestions.

@DouweM
Copy link

DouweM commented Oct 22, 2025

@PeterRodenkirchAA Thanks Peter, looks good to me! @Kludex Can you have a final look too please? Feel free to merge and release.

@PeterRodenkirchAA
Copy link
Author

@Kludex just a small ping since we currently depend on the fork, would this be fine to merge?

@mwildehahn
Copy link

I just ran into this too 🙏

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.

4 participants