@@ -12,7 +12,12 @@ import {
1212 McpServer ,
1313 ResourceTemplate
1414} from '@modelcontextprotocol/sdk/server/mcp.js' ;
15- import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js' ;
15+ import {
16+ StreamableHTTPServerTransport ,
17+ EventStore ,
18+ EventId ,
19+ StreamId
20+ } from '@modelcontextprotocol/sdk/server/streamableHttp.js' ;
1621import { z } from 'zod' ;
1722import express from 'express' ;
1823import cors from 'cors' ;
@@ -26,6 +31,41 @@ const watchedResourceContent = 'Watched resource content';
2631const transports : { [ sessionId : string ] : StreamableHTTPServerTransport } = { } ;
2732const servers : { [ sessionId : string ] : McpServer } = { } ;
2833
34+ // In-memory event store for SEP-1699 resumability
35+ const eventStoreData = new Map <
36+ string ,
37+ { eventId : string ; message: any ; streamId: string }
38+ > ( ) ;
39+
40+ function createEventStore ( ) : EventStore {
41+ return {
42+ async storeEvent ( streamId : StreamId , message : any ) : Promise < EventId > {
43+ const eventId = `${ streamId } ::${ Date . now ( ) } _${ randomUUID ( ) } ` ;
44+ eventStoreData . set ( eventId , { eventId, message, streamId } ) ;
45+ return eventId ;
46+ } ,
47+ async replayEventsAfter (
48+ lastEventId : EventId ,
49+ { send } : { send : ( eventId : EventId , message : any ) = > Promise < void > }
50+ ) : Promise < StreamId > {
51+ const streamId = lastEventId . split ( '::' ) [ 0 ] ;
52+ const eventsToReplay : Array < [ string , { message : any } ] > = [ ] ;
53+ for ( const [ eventId , data ] of eventStoreData . entries ( ) ) {
54+ if ( data . streamId === streamId && eventId > lastEventId ) {
55+ eventsToReplay . push ( [ eventId , data ] ) ;
56+ }
57+ }
58+ eventsToReplay . sort ( ( [ a ] , [ b ] ) => a . localeCompare ( b ) ) ;
59+ for ( const [ eventId , { message } ] of eventsToReplay ) {
60+ if ( Object . keys ( message ) . length > 0 ) {
61+ await send ( eventId , message ) ;
62+ }
63+ }
64+ return streamId ;
65+ }
66+ } ;
67+ }
68+
2969// Sample base64 encoded 1x1 red PNG pixel for testing
3070const TEST_IMAGE_BASE64 =
3171 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8DwHwAFBQIAX8jx0gAAAABJRU5ErkJggg == ';
@@ -872,6 +912,8 @@ app.post('/mcp', async (req, res) => {
872912
873913 transport = new StreamableHTTPServerTransport ( {
874914 sessionIdGenerator : ( ) => randomUUID ( ) ,
915+ eventStore : createEventStore ( ) ,
916+ retryInterval : 5000 , // 5 second retry interval for SEP-1699
875917 onsessioninitialized : ( newSessionId ) => {
876918 transports [ newSessionId ] = transport ;
877919 servers [ newSessionId ] = mcpServer ;
0 commit comments