@@ -726,18 +726,31 @@ func (s *Server) notifySessions(n string) {
726726 }
727727 s .mu .Unlock () // Don't hold the lock during notification: it causes deadlock.
728728
729+ // Notify legacy sessions on the shared session channel regardless of
730+ // their subscription status.
729731 notifySessions (legacySessions , n , changeNotificationParams [n ](), s .opts .Logger )
730732
731- // Sessions receive the notification only if they opened a
732- // subscriptions/listen stream that opted in to this notification type.
733+ // Notify modern sessions only if they have an active subscription for
734+ // this notification type.
735+ s .notifySubscribedSessions (subscribers , n , changeNotificationParams [n ])
736+ }
737+
738+ // notifySubscribedSessions delivers a list-changed or resource-updated
739+ // notification to each session in subscribers, stamping the session's
740+ // listen-request ID into the params' _meta so the receiving client can demultiplex
741+ // notifications belonging to different concurrent listens.
742+ func (s * Server ) notifySubscribedSessions (subscribers map [* ServerSession ]jsonrpc.ID , method string , makeParams func () Params ) {
743+ if len (subscribers ) == 0 {
744+ return
745+ }
733746 ctx , cancel := context .WithTimeout (context .Background (), 10 * time .Second )
734747 defer cancel ()
735748 for sess , reqID := range subscribers {
736- params := changeNotificationParams [ n ] ()
749+ params := makeParams ()
737750 injectMetaSubscriptionID (params , reqID )
738751 req := newRequest (sess , params )
739- if err := handleNotify (ctx , n , req ); err != nil {
740- s .opts .Logger .Warn (fmt .Sprintf ("calling %s: %v" , n , err ))
752+ if err := handleNotify (ctx , method , req ); err != nil {
753+ s .opts .Logger .Warn (fmt .Sprintf ("calling %s: %v" , method , err ))
741754 }
742755 }
743756}
@@ -1067,32 +1080,28 @@ func fileResourceHandler(dir string) ResourceHandler {
10671080func (s * Server ) ResourceUpdated (ctx context.Context , params * ResourceUpdatedNotificationParams ) error {
10681081 s .mu .Lock ()
10691082 subscribedSessions := s .resourceSubscriptions [params .URI ]
1070- sessions := slices .Collect (maps .Keys (subscribedSessions ))
1071- s .mu .Unlock ()
10721083 // Only add legacy sessions for the notification, new ones use the new notification mechanism.
10731084 var legacySessions []* ServerSession
1074- var newSessions [] * ServerSession
1075- for _ , sess := range sessions {
1085+ newSessions := make ( map [ * ServerSession ]jsonrpc. ID )
1086+ for sess , reqID := range subscribedSessions {
10761087 if sess .InitializeParams ().isNil () || sess .InitializeParams ().ProtocolVersion < protocolVersion20260728 {
10771088 legacySessions = append (legacySessions , sess )
10781089 } else {
1079- newSessions = append ( newSessions , sess )
1090+ newSessions [ sess ] = reqID
10801091 }
10811092 }
1093+ s .mu .Unlock ()
1094+
10821095 notifySessions (legacySessions , notificationResourceUpdated , params , s .opts .Logger )
1083- s .opts .Logger .Info ("resource updated notification sent" , "uri" , params .URI , "subscriber_count" , len (sessions ))
10841096
1085- ctx , cancel := context .WithTimeout (ctx , 10 * time .Second )
1086- defer cancel ()
1087- for _ , sess := range newSessions {
1088- reqID := subscribedSessions [sess ]
1097+ // Notify modern sessions, injecting the per-session subscription ID into the notification's metadata.
1098+ s .notifySubscribedSessions (newSessions , notificationResourceUpdated , func () Params {
10891099 p := * params
1090- injectMetaSubscriptionID (& p , reqID )
1091- req := newRequest (sess , & p )
1092- if err := handleNotify (ctx , notificationResourceUpdated , req ); err != nil {
1093- s .opts .Logger .Warn (fmt .Sprintf ("calling %s: %v" , notificationResourceUpdated , err ))
1094- }
1095- }
1100+ return & p
1101+ })
1102+ s .opts .Logger .Info ("resource updated notification sent" ,
1103+ "uri" , params .URI ,
1104+ "subscriber_count" , len (legacySessions )+ len (newSessions ))
10961105 return nil
10971106}
10981107
0 commit comments