Skip to content

Commit 01847b3

Browse files
mcp: refactor notification of subscribed sessions (#1018)
This PR improves the notification of subscribed sessions removing duplicated part
1 parent b6649db commit 01847b3

1 file changed

Lines changed: 30 additions & 21 deletions

File tree

mcp/server.go

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -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 {
10671080
func (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

Comments
 (0)