Skip to content

Streamable HTTP transport support: design and scoping #598

@mkjsix

Description

@mkjsix

Context

RESTHeart #594 added SseService as a first-class plugin type for Server-Sent Events, built on Undertow's ServerSentEventHandler. This covers pure SSE use cases well (live feeds, MongoDB change streams, heartbeats).

The MCP protocol (spec version 2026-03-26) replaced the classic HTTP+SSE transport with Streamable HTTP. This is increasingly relevant as AI agent frameworks adopt MCP as a standard integration protocol.

This issue is a scoping and design discussion — no implementation direction has been chosen yet.

What is Streamable HTTP?

Classic HTTP+SSE uses two separate endpoints:

GET  /sse       → long-lived text/event-stream
POST /messages  → client→server messages (separate endpoint)

Streamable HTTP unifies them into a single endpoint:

POST /mcp  → reads JSON-RPC body, responds with either:
               application/json      (simple/stateless response)
               text/event-stream     (on-demand SSE, only when the server needs to stream)
GET  /mcp  → optional subscription for server-initiated notifications

The key property: the server decides at request time whether to respond as plain JSON or upgrade to SSE. This enables stateless server implementations for the simple case.

The structural gap

SseService cannot support Streamable HTTP because ServerSentEventHandler takes ownership of the HttpServerExchange immediately and always opens a text/event-stream response. There is no way to conditionally respond as JSON or SSE from the same handler.

Supporting Streamable HTTP would require a custom HttpHandler that:

  1. Handles both GET and POST on the same path
  2. For POST: reads the body before deciding the response content type
  3. Conditionally transfers the exchange to SSE if the handler requests it

Options

Option A — Do nothing

SseService is sufficient for non-MCP streaming use cases. Developers can combine JsonService (for POST) with SseService (for GET) on different paths and approximate MCP old-style. No new work needed.

Limit: not spec-compliant with MCP 2026-03-26. A modern MCP client expecting a single unified endpoint will not work.

Option B — New StreamableHttpService plugin type (transport layer only)

A new plugin interface that exposes the unified endpoint abstraction. The plugin author handles the JSON-RPC message content themselves. RESTHeart provides only the transport plumbing (routing, SSE upgrade, security).

Scope: ~1–2 weeks. Does not require RESTHeart to understand the MCP protocol.

Option C — McpService plugin type (protocol-aware)

A higher-level abstraction where the plugin implements MCP primitives (initialize, tools/list, tools/call, etc.) and RESTHeart handles the full JSON-RPC/Streamable HTTP protocol layer.

Scope: significantly larger (4–6 weeks+). Requires tracking the MCP spec for future changes. High positioning value for RESTHeart Cloud.

Questions to resolve

  • Is MCP server capability a target use case for RESTHeart in the near term?
  • Should RESTHeart be a tool to build MCP servers (Option B) or a ready-made MCP server host (Option C)?
  • Is backward compatibility with existing SSE clients a hard requirement (it is with both B and C)?

References

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions