@@ -57,7 +57,7 @@ impl sse_stream::Timer for TokioTimer {
5757 }
5858}
5959
60- #[ derive( Debug , Clone ) ]
60+ #[ derive( Debug , Clone , Default ) ]
6161#[ non_exhaustive]
6262pub struct ServerSseMessage {
6363 /// The event ID for this message. When set, clients can use this ID
@@ -71,6 +71,37 @@ pub struct ServerSseMessage {
7171 pub retry : Option < Duration > ,
7272}
7373
74+ impl ServerSseMessage {
75+ /// Create a message carrying a JSON-RPC response/notification with an event ID.
76+ pub fn new ( event_id : impl Into < String > , message : ServerJsonRpcMessage ) -> Self {
77+ Self {
78+ event_id : Some ( event_id. into ( ) ) ,
79+ message : Some ( Arc :: new ( message) ) ,
80+ retry : None ,
81+ }
82+ }
83+
84+ /// Wrap a JSON-RPC message without an event ID or retry hint.
85+ pub fn from_message ( message : ServerJsonRpcMessage ) -> Self {
86+ Self {
87+ event_id : None ,
88+ message : Some ( Arc :: new ( message) ) ,
89+ retry : None ,
90+ }
91+ }
92+
93+ /// Create a priming event that tells the client to reconnect after `retry`
94+ /// if the connection drops.
95+ /// See [SEP-1699](https://github.com/modelcontextprotocol/modelcontextprotocol/issues/1699).
96+ pub fn priming ( event_id : impl Into < String > , retry : Duration ) -> Self {
97+ Self {
98+ event_id : Some ( event_id. into ( ) ) ,
99+ message : None ,
100+ retry : Some ( retry) ,
101+ }
102+ }
103+ }
104+
74105pub ( crate ) fn sse_stream_response (
75106 stream : impl futures:: Stream < Item = ServerSseMessage > + Send + Sync + ' static ,
76107 keep_alive : Option < Duration > ,
@@ -169,3 +200,49 @@ where
169200 }
170201 }
171202}
203+
204+ #[ cfg( test) ]
205+ mod tests {
206+ use super :: * ;
207+ use crate :: model:: { EmptyResult , JsonRpcResponse , JsonRpcVersion2_0 , RequestId , ServerResult } ;
208+
209+ fn dummy_message ( ) -> ServerJsonRpcMessage {
210+ ServerJsonRpcMessage :: Response ( JsonRpcResponse {
211+ jsonrpc : JsonRpcVersion2_0 ,
212+ id : RequestId :: Number ( 1 ) ,
213+ result : ServerResult :: EmptyResult ( EmptyResult { } ) ,
214+ } )
215+ }
216+
217+ #[ test]
218+ fn default_has_all_none ( ) {
219+ let msg = ServerSseMessage :: default ( ) ;
220+ assert ! ( msg. event_id. is_none( ) ) ;
221+ assert ! ( msg. message. is_none( ) ) ;
222+ assert ! ( msg. retry. is_none( ) ) ;
223+ }
224+
225+ #[ test]
226+ fn new_sets_event_id_and_message ( ) {
227+ let msg = ServerSseMessage :: new ( "42" , dummy_message ( ) ) ;
228+ assert_eq ! ( msg. event_id. as_deref( ) , Some ( "42" ) ) ;
229+ assert ! ( msg. message. is_some( ) ) ;
230+ assert ! ( msg. retry. is_none( ) ) ;
231+ }
232+
233+ #[ test]
234+ fn from_message_has_no_event_id ( ) {
235+ let msg = ServerSseMessage :: from_message ( dummy_message ( ) ) ;
236+ assert ! ( msg. event_id. is_none( ) ) ;
237+ assert ! ( msg. message. is_some( ) ) ;
238+ assert ! ( msg. retry. is_none( ) ) ;
239+ }
240+
241+ #[ test]
242+ fn priming_sets_event_id_and_retry ( ) {
243+ let msg = ServerSseMessage :: priming ( "0" , Duration :: from_secs ( 5 ) ) ;
244+ assert_eq ! ( msg. event_id. as_deref( ) , Some ( "0" ) ) ;
245+ assert ! ( msg. message. is_none( ) ) ;
246+ assert_eq ! ( msg. retry, Some ( Duration :: from_secs( 5 ) ) ) ;
247+ }
248+ }
0 commit comments