Skip to content

Commit 8c741be

Browse files
feat: add server-side SSE priming events and retry field (SEP-1699)
Add support for sending priming events with retry field when establishing SSE streams. When retryInterval is configured, the server sends an initial event with id, retry field, and empty data to prime the client for reconnection timing. Changes: - Add retryInterval option to StreamableHTTPServerTransportOptions - Send priming event after GET SSE stream headers when configured - Include retry field to control client reconnection timing
1 parent 8e761b3 commit 8c741be

File tree

1 file changed

+21
-0
lines changed

1 file changed

+21
-0
lines changed

src/server/streamableHttp.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,13 @@ export interface StreamableHTTPServerTransportOptions {
108108
* Default is false for backwards compatibility.
109109
*/
110110
enableDnsRebindingProtection?: boolean;
111+
112+
/**
113+
* Retry interval in milliseconds to suggest to clients in SSE retry field.
114+
* When set, the server will send a retry field in SSE events to control
115+
* client reconnection timing (SEP-1699).
116+
*/
117+
retryInterval?: number;
111118
}
112119

113120
/**
@@ -160,6 +167,7 @@ export class StreamableHTTPServerTransport implements Transport {
160167
private _allowedHosts?: string[];
161168
private _allowedOrigins?: string[];
162169
private _enableDnsRebindingProtection: boolean;
170+
private _retryInterval?: number;
163171

164172
sessionId?: string;
165173
onclose?: () => void;
@@ -175,6 +183,7 @@ export class StreamableHTTPServerTransport implements Transport {
175183
this._allowedHosts = options.allowedHosts;
176184
this._allowedOrigins = options.allowedOrigins;
177185
this._enableDnsRebindingProtection = options.enableDnsRebindingProtection ?? false;
186+
this._retryInterval = options.retryInterval;
178187
}
179188

180189
/**
@@ -320,6 +329,18 @@ export class StreamableHTTPServerTransport implements Transport {
320329
// otherwise the client will just wait for the first message
321330
res.writeHead(200, headers).flushHeaders();
322331

332+
// SEP-1699: Send priming event with id and empty data to establish resumption capability
333+
// This primes the client's Last-Event-ID for reconnection and sets retry interval
334+
// Only send when retryInterval is configured (enabling polling behavior)
335+
if (this._retryInterval !== undefined) {
336+
const primingEventId = this._eventStore
337+
? await this._eventStore.storeEvent(this._standaloneSseStreamId, {} as JSONRPCMessage)
338+
: `priming-${Date.now()}`;
339+
340+
const primingEvent = `id: ${primingEventId}\nretry: ${this._retryInterval}\ndata: \n\n`;
341+
res.write(primingEvent);
342+
}
343+
323344
// Assign the response to the standalone SSE stream
324345
this._streamMapping.set(this._standaloneSseStreamId, res);
325346
// Set up close handler for client disconnects

0 commit comments

Comments
 (0)