Skip to main content
Long calls needn’t be opaque. When the client attaches a progressToken and the server advertised streaming, the server MAY emit notifications/progress frames before the final response — reporting pipeline stages and even partial hits.

Opting in

The client sets _meta.progressToken on the request. The token is a client-chosen string or integer, unique among the client’s in-flight requests.

Progress frames

Each frame is a notification (no id, never answered):
string | integer
Echoes the request’s token verbatim. A server MUST NOT emit progress for a request that carried none.
float
Completion in 0.0–1.0.
string
The current pipeline stage (transform, recall, rerank, mmr, …).
object
Optional incremental payload — e.g. partial.hits with first-stage candidates before rerank.

The final response is authoritative

1

Frames are advisory

A client MUST function correctly even if it never receives a single progress frame. Never build correctness on them.
2

Ignore unknown tokens

A client MUST ignore a frame bearing a token it doesn’t recognise.
3

The result still arrives

The normal JSON-RPC response bearing the request id still follows every stream and is the single source of truth.

Over HTTP: SSE

Over stdio, progress frames simply interleave on stdout. Over HTTP, a client that sends Accept: text/event-stream receives them as Server-Sent Events — zero or more notifications/progress frames, then one final frame carrying the JSON-RPC response. See Transports. Each SSE frame is a single data: line whose payload is a compact JSON object, terminated by a blank line; the stream ends after the final response frame. A client that did not ask for SSE gets one buffered JSON response instead — so the same server handler serves both callers.

Writing a streaming handler

The reference Python SDK turns this into one idiom: a generator handler that yields rcp.Progress events and returns the final result. Register it with Server.stream(...) and advertise streaming. serve_http flushes each Progress as a notifications/progress frame the instant it is produced, then sends the final response frame; a plain unary POST drains the same generator and returns only the result.
frame
A progress event. progress is 0.0–1.0; stage names the pipeline phase; partial is an optional early-result payload. Serialised into a notifications/progress frame carrying the request’s progressToken — emitted only when the client supplied one.
The handler is written once and works both ways. Over SSE the frames stream live; over a plain request the generator is drained and only its return value is sent — satisfying §13’s rule that a non-SSE client MUST get a single buffered JSON response.
A complete, self-contained program — a real HTTP+SSE server plus a raw-socket client that prints each frame as the retrieve funnel fills — lives at examples/example_streaming.py:
Progress pairs naturally with cancellation: stream partial hits, let the user act on them, and send notifications/cancel if they navigate away.