@@ -5,6 +5,7 @@ import { AuthInfo } from "@modelcontextprotocol/sdk/server/auth/types.js";
55import { JSONRPCMessage } from "@modelcontextprotocol/sdk/types.js" ;
66import { Server } from "@modelcontextprotocol/sdk/server/index.js" ;
77
8+ let redisTransportCounter = 0 ;
89
910function getToServerChannel ( sessionId : string ) : string {
1011 return `mcp:shttp:toserver:${ sessionId } ` ;
@@ -24,6 +25,7 @@ export async function isLive(sessionId: string): Promise<boolean> {
2425
2526export class RedisTransport implements Transport {
2627 private redisCleanup : ( ( ) => Promise < void > ) | undefined ;
28+ private counter : number ;
2729
2830 onclose ?: ( ( ) => void ) | undefined ;
2931 onerror ?: ( ( error : Error ) => void ) | undefined ;
@@ -34,6 +36,7 @@ export class RedisTransport implements Transport {
3436 private recvChannel : string ,
3537 private isLiveKey : string | undefined = undefined
3638 ) {
39+ this . counter = redisTransportCounter ++ ;
3740 this . sendChannel = sendChannel ;
3841 this . recvChannel = recvChannel ;
3942 this . isLiveKey = isLiveKey ;
@@ -42,18 +45,26 @@ export class RedisTransport implements Transport {
4245
4346
4447 async start ( ) : Promise < void > {
45- console . log ( `[RedisTransport.start] Starting transport - send: ${ this . sendChannel } , recv: ${ this . recvChannel } ` ) ;
48+ console . log ( `[RedisTransport.${ this . counter } . start] Starting transport - send: ${ this . sendChannel } , recv: ${ this . recvChannel } ` ) ;
4649 if ( this . redisCleanup ) {
4750 throw new Error ( `Redis transport already started for channels ${ this . sendChannel } and ${ this . recvChannel } ` ) ;
4851 }
4952
53+ // Log when onmessage is set
54+ console . log ( `[RedisTransport.${ this . counter } .start] onmessage handler is ${ this . onmessage ? 'SET' : 'NOT SET' } ` ) ;
55+
5056 this . redisCleanup = await redisClient . createSubscription (
5157 this . recvChannel ,
5258 ( json ) => {
53- console . log ( `[RedisTransport] Received message on ${ this . recvChannel } :` , json . substring ( 0 , 100 ) ) ;
59+ console . log ( `[RedisTransport. ${ this . counter } ] Received message on ${ this . recvChannel } :` , json . substring ( 0 , 100 ) ) ;
5460 const message = JSON . parse ( json ) ;
5561 const extra = popExtra ( message ) ;
56- this . onmessage ?.( message , extra )
62+ if ( this . onmessage ) {
63+ console . log ( `[RedisTransport.${ this . counter } ] Calling onmessage handler for ${ this . recvChannel } ` ) ;
64+ this . onmessage ( message , extra )
65+ } else {
66+ console . log ( `[RedisTransport.${ this . counter } ] WARNING: No onmessage handler for ${ this . recvChannel } !` ) ;
67+ }
5768 } ,
5869 ( error ) => {
5970 console . error (
@@ -63,33 +74,37 @@ export class RedisTransport implements Transport {
6374 this . close ( )
6475 } ,
6576 ) ;
66- console . log ( `[RedisTransport.start] Successfully subscribed to ${ this . recvChannel } ` ) ;
77+ console . log ( `[RedisTransport.${ this . counter } . start] Successfully subscribed to ${ this . recvChannel } ` ) ;
6778 }
6879
69- send ( message : JSONRPCMessage , options ?: TransportSendOptions ) : Promise < void > {
80+ async send ( message : JSONRPCMessage , options ?: TransportSendOptions ) : Promise < void > {
7081 if ( options ) {
7182 setOptions ( message , options ) ;
7283 }
7384 const messageStr = JSON . stringify ( message ) ;
74- console . log ( `[RedisTransport.send] Publishing to ${ this . sendChannel } :` , messageStr . substring ( 0 , 100 ) ) ;
75- return redisClient . publish ( this . sendChannel , messageStr ) ;
85+ console . log ( `[RedisTransport.${ this . counter } .send] Publishing to ${ this . sendChannel } :` , messageStr . substring ( 0 , 100 ) ) ;
86+ console . log ( `[RedisTransport.${ this . counter } .send] Full message:` , messageStr ) ;
87+ await redisClient . publish ( this . sendChannel , messageStr ) ;
88+ console . log ( `[RedisTransport.${ this . counter } .send] Published successfully to ${ this . sendChannel } ` ) ;
7689 }
7790
7891
7992 async cleanup ( ) : Promise < void > {
8093 if ( this . redisCleanup ) {
94+ console . log ( `[RedisTransport.${ this . counter } .cleanup] Unsubscribing from ${ this . recvChannel } ` ) ;
8195 await this . redisCleanup ( )
8296 this . redisCleanup = undefined ;
97+ console . log ( `[RedisTransport.${ this . counter } .cleanup] Successfully unsubscribed from ${ this . recvChannel } ` ) ;
8398 }
8499 if ( this . isLiveKey ) {
85100 await redisClient . del ( this . isLiveKey ) ;
86101 }
87102 }
88103
89104 async close ( ) : Promise < void > {
90- console . log ( `[RedisTransport.close] Closing transport - send: ${ this . sendChannel } , recv: ${ this . recvChannel } ` ) ;
105+ console . log ( `[RedisTransport.${ this . counter } . close] Closing transport - send: ${ this . sendChannel } , recv: ${ this . recvChannel } ` ) ;
91106 this . onclose ?.( ) ;
92- this . cleanup ( )
107+ await this . cleanup ( )
93108 }
94109}
95110
@@ -186,18 +201,36 @@ function relayTransports(transport1: Transport, transport2: Transport): void {
186201 transport1 . onerror ?.( error ) ;
187202 } ;
188203
204+ // Prevent circular close calls
205+ let closing = false ;
206+
189207 transport1 . onclose = ( ) => {
190- transport2 . close ( ) . catch ( console . error ) ;
208+ if ( ! closing ) {
209+ closing = true ;
210+ transport2 . close ( ) . catch ( console . error ) ;
211+ }
191212 } ;
192213 transport2 . onclose = ( ) => {
193- transport1 . close ( ) . catch ( console . error ) ;
214+ if ( ! closing ) {
215+ closing = true ;
216+ transport1 . close ( ) . catch ( console . error ) ;
217+ }
194218 } ;
195219}
196220
197221
198222export async function startServerListeningToRedis ( server : Server , sessionId : string ) {
199223 console . log ( `[startServerListeningToRedis] Starting background server for session ${ sessionId } ` ) ;
200224 const serverRedisTransport = createBackgroundTaskSideRedisTransport ( sessionId )
225+
226+ // Log all messages sent by the server
227+ const originalSend = serverRedisTransport . send . bind ( serverRedisTransport ) ;
228+ serverRedisTransport . send = async ( message , options ) => {
229+ console . log ( `[MCP Server -> Redis] Sending response:` , JSON . stringify ( message ) . substring ( 0 , 200 ) ) ;
230+ return originalSend ( message , options ) ;
231+ } ;
232+
233+ // The server.connect() will call start() on the transport
201234 await server . connect ( serverRedisTransport )
202235 console . log ( `[startServerListeningToRedis] Background server connected for session ${ sessionId } ` ) ;
203236}
@@ -216,7 +249,7 @@ function createBackgroundTaskSideRedisTransport(sessionId: string): RedisTranspo
216249 ) ;
217250}
218251
219- export async function getFirstShttpTransport ( sessionId : string ) : Promise < StreamableHTTPServerTransport > {
252+ export async function getFirstShttpTransport ( sessionId : string ) : Promise < { shttpTransport : StreamableHTTPServerTransport , redisTransport : RedisTransport } > {
220253 const transport = new StreamableHTTPServerTransport ( {
221254 sessionIdGenerator : ( ) => sessionId ,
222255 enableJsonResponse : true , // Enable JSON response mode
@@ -227,14 +260,15 @@ export async function getFirstShttpTransport(sessionId: string): Promise<Streama
227260 // When shttpTransport closes, so does the redisTransport
228261 relayTransports ( redisTransport , transport ) ;
229262 await redisTransport . start ( )
230- return transport ;
263+ return { shttpTransport : transport , redisTransport } ;
231264}
232265
233- export async function getShttpTransport ( sessionId : string ) : Promise < StreamableHTTPServerTransport > {
266+ export async function getShttpTransport ( sessionId : string ) : Promise < { shttpTransport : StreamableHTTPServerTransport , redisTransport : RedisTransport } > {
234267 // Giving undefined here and setting the sessionId means the
235268 // transport wont try to create a new session.
236269 const shttpTransport = new StreamableHTTPServerTransport ( {
237- sessionIdGenerator : undefined
270+ sessionIdGenerator : undefined ,
271+ enableJsonResponse : true , // Use JSON response mode for all requests
238272 } )
239273 shttpTransport . sessionId = sessionId ;
240274
@@ -243,5 +277,5 @@ export async function getShttpTransport(sessionId: string): Promise<StreamableHT
243277 // When shttpTransport closes, so does the redisTransport
244278 relayTransports ( redisTransport , shttpTransport ) ;
245279 await redisTransport . start ( )
246- return shttpTransport ;
280+ return { shttpTransport, redisTransport } ;
247281}
0 commit comments