@@ -574,96 +574,60 @@ export async function startMcpServer(
574574 const app = express ( ) ;
575575 app . use ( express . json ( ) ) ;
576576
577- // Store active sessions
578- const sessions = new Map <
579- string ,
580- { transport : StreamableHTTPServerTransport ; server : McpServer }
581- > ( ) ;
582-
583577 // ─── Health check endpoint ────────────────────────────────────────
584578 app . get ( "/health" , ( _req : Request , res : Response ) => {
585579 res . json ( {
586580 status : "ok" ,
587581 whatsapp_connected : ! ! ( sock && sock . user ) ,
588- whatsapp_user : sock ?. user ?. name ?? null ,
589- active_sessions : sessions . size ,
590582 timestamp : new Date ( ) . toISOString ( ) ,
591583 } ) ;
592584 } ) ;
593585
594- // ─── Streamable HTTP: POST /sse — JSON-RPC messages ──────────────
586+ // ─── Streamable HTTP: POST /sse — stateless mode ─── ──────────────
595587 app . post ( "/sse" , async ( req : Request , res : Response ) => {
596- const sessionId = req . headers [ "mcp-session-id" ] as string | undefined ;
597-
598- // Existing session
599- if ( sessionId && sessions . has ( sessionId ) ) {
600- const session = sessions . get ( sessionId ) ! ;
601- await session . transport . handleRequest ( req , res , req . body ) ;
602- return ;
603- }
604-
605- // New session (initialize request)
606- const isInit =
607- req . body ?. method === "initialize" ||
608- ( Array . isArray ( req . body ) &&
609- req . body . some ( ( msg : any ) => msg . method === "initialize" ) ) ;
610-
611- if ( ! isInit && sessionId ) {
612- res . status ( 404 ) . json ( { error : "Session not found" } ) ;
613- return ;
614- }
588+ mcpLogger . info ( `POST /sse from ${ req . ip } ` ) ;
615589
616- mcpLogger . info ( `New Streamable HTTP session from ${ req . ip } ` ) ;
590+ try {
591+ const transport = new StreamableHTTPServerTransport ( {
592+ sessionIdGenerator : undefined , // stateless
593+ } ) ;
617594
618- const transport = new StreamableHTTPServerTransport ( {
619- sessionIdGenerator : ( ) => randomUUID ( ) ,
620- } ) ;
595+ const server = createMcpServer ( sock , mcpLogger , waLogger ) ;
621596
622- const server = createMcpServer ( sock , mcpLogger , waLogger ) ;
597+ res . on ( "close" , ( ) => {
598+ transport . close ( ) ;
599+ server . close ( ) ;
600+ } ) ;
623601
624- transport . onclose = ( ) => {
625- const sid = transport . sessionId ;
626- if ( sid ) {
627- mcpLogger . info ( `Session closed: ${ sid } ` ) ;
628- sessions . delete ( sid ) ;
602+ await server . connect ( transport ) ;
603+ await transport . handleRequest ( req , res , req . body ) ;
604+ } catch ( error : any ) {
605+ mcpLogger . error ( `Error handling POST /sse: ${ error . message } ` ) ;
606+ if ( ! res . headersSent ) {
607+ res . status ( 500 ) . json ( {
608+ jsonrpc : "2.0" ,
609+ error : { code : - 32603 , message : "Internal server error" } ,
610+ id : null ,
611+ } ) ;
629612 }
630- } ;
631-
632- await server . connect ( transport ) ;
633-
634- const sid = transport . sessionId ;
635- if ( sid ) {
636- sessions . set ( sid , { transport, server } ) ;
637- mcpLogger . info ( `Session created: ${ sid } ` ) ;
638613 }
639-
640- await transport . handleRequest ( req , res , req . body ) ;
641614 } ) ;
642615
643- // ─── Streamable HTTP: GET /sse — SSE stream for server notifications
644- app . get ( "/sse" , async ( req : Request , res : Response ) => {
645- const sessionId = req . headers [ "mcp-session-id" ] as string | undefined ;
646-
647- if ( sessionId && sessions . has ( sessionId ) ) {
648- const session = sessions . get ( sessionId ) ! ;
649- await session . transport . handleRequest ( req , res ) ;
650- } else {
651- res . status ( 400 ) . json ( {
652- error : "No valid session. Send an initialize request first." ,
653- } ) ;
654- }
616+ // ─── GET & DELETE not supported in stateless mode ─────────────────
617+ app . get ( "/sse" , ( _req : Request , res : Response ) => {
618+ res . status ( 405 ) . set ( "Allow" , "POST" ) . json ( {
619+ jsonrpc : "2.0" ,
620+ error : { code : - 32000 , message : "Method not allowed in stateless mode. Use POST." } ,
621+ id : null ,
622+ } ) ;
655623 } ) ;
656624
657- // ─── Streamable HTTP: DELETE /sse — session cleanup ───────────────
658- app . delete ( "/sse" , async ( req : Request , res : Response ) => {
659- const sessionId = req . headers [ "mcp-session-id" ] as string | undefined ;
660-
661- if ( sessionId && sessions . has ( sessionId ) ) {
662- const session = sessions . get ( sessionId ) ! ;
663- await session . transport . handleRequest ( req , res ) ;
664- } else {
665- res . status ( 404 ) . json ( { error : "Session not found" } ) ;
666- }
625+ app . delete ( "/sse" , ( _req : Request , res : Response ) => {
626+ res . status ( 405 ) . set ( "Allow" , "POST" ) . json ( {
627+ jsonrpc : "2.0" ,
628+ error : { code : - 32000 , message : "Method not allowed in stateless mode." } ,
629+ id : null ,
630+ } ) ;
667631 } ) ;
668632
669633 // ─── Start the HTTP server ────────────────────────────────────────
0 commit comments