@@ -460,3 +460,135 @@ func (s *MCPServer) DeleteSessionTools(sessionID string, names ...string) error
460460
461461	return  nil 
462462}
463+ 
464+ // AddSessionResource adds a resource for a specific session 
465+ func  (s  * MCPServer ) AddSessionResource (sessionID  string , resource  mcp.Resource , handler  ResourceHandlerFunc ) error  {
466+ 	return  s .AddSessionResources (sessionID , ServerResource {Resource : resource , Handler : handler })
467+ }
468+ 
469+ // AddSessionResources adds resources for a specific session 
470+ func  (s  * MCPServer ) AddSessionResources (sessionID  string , resources  ... ServerResource ) error  {
471+ 	sessionValue , ok  :=  s .sessions .Load (sessionID )
472+ 	if  ! ok  {
473+ 		return  ErrSessionNotFound 
474+ 	}
475+ 
476+ 	session , ok  :=  sessionValue .(SessionWithResources )
477+ 	if  ! ok  {
478+ 		return  ErrSessionDoesNotSupportResources 
479+ 	}
480+ 
481+ 	// For session resources, we want listChanged enabled by default 
482+ 	s .implicitlyRegisterCapabilities (
483+ 		func () bool  { return  s .capabilities .resources  !=  nil  },
484+ 		func () { s .capabilities .resources  =  & resourceCapabilities {listChanged : true } },
485+ 	)
486+ 
487+ 	// Get existing resources (this should return a thread-safe copy) 
488+ 	sessionResources  :=  session .GetSessionResources ()
489+ 
490+ 	// Create a new map to avoid concurrent modification issues 
491+ 	newSessionResources  :=  make (map [string ]ServerResource , len (sessionResources )+ len (resources ))
492+ 
493+ 	// Copy existing resources 
494+ 	for  k , v  :=  range  sessionResources  {
495+ 		newSessionResources [k ] =  v 
496+ 	}
497+ 
498+ 	// Add new resources 
499+ 	for  _ , resource  :=  range  resources  {
500+ 		newSessionResources [resource .Resource .URI ] =  resource 
501+ 	}
502+ 
503+ 	// Set the resources (this should be thread-safe) 
504+ 	session .SetSessionResources (newSessionResources )
505+ 
506+ 	// It only makes sense to send resource notifications to initialized sessions -- 
507+ 	// if we're not initialized yet the client can't possibly have sent their 
508+ 	// initial resources/list message. 
509+ 	// 
510+ 	// For initialized sessions, honor resources.listChanged, which is specifically 
511+ 	// about whether notifications will be sent or not. 
512+ 	// see <https://modelcontextprotocol.io/specification/2025-03-26/server/resources#capabilities> 
513+ 	if  session .Initialized () &&  s .capabilities .resources  !=  nil  &&  s .capabilities .resources .listChanged  {
514+ 		// Send notification only to this session 
515+ 		if  err  :=  s .SendNotificationToSpecificClient (sessionID , "notifications/resources/list_changed" , nil ); err  !=  nil  {
516+ 			// Log the error but don't fail the operation 
517+ 			// The resources were successfully added, but notification failed 
518+ 			if  s .hooks  !=  nil  &&  len (s .hooks .OnError ) >  0  {
519+ 				hooks  :=  s .hooks 
520+ 				go  func (sID  string , hooks  * Hooks ) {
521+ 					ctx  :=  context .Background ()
522+ 					hooks .onError (ctx , nil , "notification" , map [string ]any {
523+ 						"method" :    "notifications/resources/list_changed" ,
524+ 						"sessionID" : sID ,
525+ 					}, fmt .Errorf ("failed to send notification after adding resources: %w" , err ))
526+ 				}(sessionID , hooks )
527+ 			}
528+ 		}
529+ 	}
530+ 
531+ 	return  nil 
532+ }
533+ 
534+ // DeleteSessionResources removes resources from a specific session 
535+ func  (s  * MCPServer ) DeleteSessionResources (sessionID  string , uris  ... string ) error  {
536+ 	sessionValue , ok  :=  s .sessions .Load (sessionID )
537+ 	if  ! ok  {
538+ 		return  ErrSessionNotFound 
539+ 	}
540+ 
541+ 	session , ok  :=  sessionValue .(SessionWithResources )
542+ 	if  ! ok  {
543+ 		return  ErrSessionDoesNotSupportResources 
544+ 	}
545+ 
546+ 	// Get existing resources (this should return a thread-safe copy) 
547+ 	sessionResources  :=  session .GetSessionResources ()
548+ 	if  sessionResources  ==  nil  {
549+ 		return  nil 
550+ 	}
551+ 
552+ 	// Create a new map to avoid concurrent modification issues 
553+ 	newSessionResources  :=  make (map [string ]ServerResource , len (sessionResources ))
554+ 
555+ 	// Copy existing resources except those being deleted 
556+ 	for  k , v  :=  range  sessionResources  {
557+ 		newSessionResources [k ] =  v 
558+ 	}
559+ 
560+ 	// Remove specified resources 
561+ 	for  _ , uri  :=  range  uris  {
562+ 		delete (newSessionResources , uri )
563+ 	}
564+ 
565+ 	// Set the resources (this should be thread-safe) 
566+ 	session .SetSessionResources (newSessionResources )
567+ 
568+ 	// It only makes sense to send resource notifications to initialized sessions -- 
569+ 	// if we're not initialized yet the client can't possibly have sent their 
570+ 	// initial resources/list message. 
571+ 	// 
572+ 	// For initialized sessions, honor resources.listChanged, which is specifically 
573+ 	// about whether notifications will be sent or not. 
574+ 	// see <https://modelcontextprotocol.io/specification/2025-03-26/server/resources#capabilities> 
575+ 	if  session .Initialized () &&  s .capabilities .resources  !=  nil  &&  s .capabilities .resources .listChanged  {
576+ 		// Send notification only to this session 
577+ 		if  err  :=  s .SendNotificationToSpecificClient (sessionID , "notifications/resources/list_changed" , nil ); err  !=  nil  {
578+ 			// Log the error but don't fail the operation 
579+ 			// The resources were successfully deleted, but notification failed 
580+ 			if  s .hooks  !=  nil  &&  len (s .hooks .OnError ) >  0  {
581+ 				hooks  :=  s .hooks 
582+ 				go  func (sID  string , hooks  * Hooks ) {
583+ 					ctx  :=  context .Background ()
584+ 					hooks .onError (ctx , nil , "notification" , map [string ]any {
585+ 						"method" :    "notifications/resources/list_changed" ,
586+ 						"sessionID" : sID ,
587+ 					}, fmt .Errorf ("failed to send notification after deleting resources: %w" , err ))
588+ 				}(sessionID , hooks )
589+ 			}
590+ 		}
591+ 	}
592+ 
593+ 	return  nil 
594+ }
0 commit comments