@@ -37,6 +37,7 @@ import type {
3737 McpServerElicitationRequestParams ,
3838 McpServerElicitationRequestResponse ,
3939} from "./app-server/v2" ;
40+ import { logger } from "./Logger" ;
4041
4142export interface ApprovalHandler {
4243 handleCommandExecution ( params : CommandExecutionRequestApprovalParams ) : Promise < CommandExecutionRequestApprovalResponse > ;
@@ -69,6 +70,8 @@ const McpServerElicitationRequest = new RequestType<
6970export class CodexAppServerClient {
7071 readonly connection : MessageConnection ;
7172 private approvalHandlers = new Map < string , ApprovalHandler > ( ) ;
73+ private readonly notificationHandlers = new Map < string , ( event : ServerNotification ) => void | Promise < void > > ( ) ;
74+ private readonly notificationQueues = new Map < string , Promise < void > | null > ( ) ;
7275 private mcpStartupCompleteVersion = 0 ;
7376 private lastMcpStartupComplete : McpStartupCompleteEvent | null = null ;
7477 private readonly mcpStartupCompleteResolvers : Array < SignalResolver < McpStartupCompleteEvent > > = [ ] ;
@@ -207,22 +210,56 @@ export class CodexAppServerClient {
207210 * Registers a notification handler for a specific session.
208211 * Replaces any existing handler for the same session, preventing handler accumulation.
209212 */
210- onServerNotification ( sessionId : string , callback : ( event : ServerNotification ) => void ) {
213+ onServerNotification ( sessionId : string , callback : ( event : ServerNotification ) => void | Promise < void > ) {
211214 this . notificationHandlers . set ( sessionId , callback ) ;
215+ this . notificationQueues . set ( sessionId , null ) ;
212216 }
213217
214218 private codexEventHandlers : Array < ( event : CodexConnectionEvent ) => void > = [ ] ;
215219 onClientTransportEvent ( callback : ( event : CodexConnectionEvent ) => void ) {
216220 this . codexEventHandlers . push ( callback ) ;
217221 }
218222
219- private notificationHandlers = new Map < string , ( event : ServerNotification ) => void > ( ) ;
220223 private notify ( notification : ServerNotification ) {
221- for ( const notificationHandler of this . notificationHandlers . values ( ) ) {
222- notificationHandler ( notification ) ;
224+ for ( const [ sessionId , notificationHandler ] of this . notificationHandlers . entries ( ) ) {
225+ const queue = this . notificationQueues . get ( sessionId ) ;
226+ if ( queue ) {
227+ const next = queue
228+ . then ( ( ) => notificationHandler ( notification ) )
229+ . catch ( ( error ) => {
230+ logger . error ( "Error handling server notification" , error ) ;
231+ } ) ;
232+ this . notificationQueues . set ( sessionId , this . trackNotificationQueue ( sessionId , next ) ) ;
233+ continue ;
234+ }
235+
236+ try {
237+ const result = notificationHandler ( notification ) ;
238+ if ( result instanceof Promise ) {
239+ const next = result . catch ( ( error ) => {
240+ logger . error ( "Error handling server notification" , error ) ;
241+ } ) ;
242+ this . notificationQueues . set ( sessionId , this . trackNotificationQueue ( sessionId , next ) ) ;
243+ }
244+ } catch ( error ) {
245+ logger . error ( "Error handling server notification" , error ) ;
246+ }
223247 }
224248 }
225249
250+ async flushServerNotifications ( sessionId : string ) : Promise < void > {
251+ await ( this . notificationQueues . get ( sessionId ) ?? Promise . resolve ( ) ) ;
252+ }
253+
254+ private trackNotificationQueue ( sessionId : string , queue : Promise < void > ) : Promise < void > {
255+ const trackedQueue = queue . finally ( ( ) => {
256+ if ( this . notificationQueues . get ( sessionId ) === trackedQueue ) {
257+ this . notificationQueues . set ( sessionId , null ) ;
258+ }
259+ } ) ;
260+ return trackedQueue ;
261+ }
262+
226263 private resolveSignal < T > (
227264 event : T ,
228265 version : number ,
0 commit comments