@@ -962,6 +962,50 @@ func TestMCPServer_Prompts(t *testing.T) {
962962				assert .Equal (t , "test-prompt-2" , prompts [1 ].Name )
963963			},
964964		},
965+ 		{
966+ 			name : "SetPrompts sends single notifications/prompts/list_changed with one active session" ,
967+ 			action : func (t  * testing.T , server  * MCPServer , notificationChannel  chan  mcp.JSONRPCNotification ) {
968+ 				err  :=  server .RegisterSession (context .TODO (), & fakeSession {
969+ 					sessionID :           "test" ,
970+ 					notificationChannel : notificationChannel ,
971+ 					initialized :         true ,
972+ 				})
973+ 				require .NoError (t , err )
974+ 				server .SetPrompts (ServerPrompt {
975+ 					Prompt : mcp.Prompt {
976+ 						Name :        "test-prompt-1" ,
977+ 						Description : "A test prompt" ,
978+ 						Arguments : []mcp.PromptArgument {
979+ 							{
980+ 								Name :        "arg1" ,
981+ 								Description : "First argument" ,
982+ 							},
983+ 						},
984+ 					},
985+ 					Handler : nil ,
986+ 				}, ServerPrompt {
987+ 					Prompt : mcp.Prompt {
988+ 						Name :        "test-prompt-2" ,
989+ 						Description : "Another test prompt" ,
990+ 						Arguments : []mcp.PromptArgument {
991+ 							{
992+ 								Name :        "arg2" ,
993+ 								Description : "Second argument" ,
994+ 							},
995+ 						},
996+ 					},
997+ 					Handler : nil ,
998+ 				})
999+ 			},
1000+ 			expectedNotifications : 1 ,
1001+ 			validate : func (t  * testing.T , notifications  []mcp.JSONRPCNotification , promptsList  mcp.JSONRPCMessage ) {
1002+ 				assert .Equal (t , mcp .MethodNotificationPromptsListChanged , notifications [0 ].Method )
1003+ 				prompts  :=  promptsList .(mcp.JSONRPCResponse ).Result .(mcp.ListPromptsResult ).Prompts 
1004+ 				assert .Len (t , prompts , 2 )
1005+ 				assert .Equal (t , "test-prompt-1" , prompts [0 ].Name )
1006+ 				assert .Equal (t , "test-prompt-2" , prompts [1 ].Name )
1007+ 			},
1008+ 		},
9651009	}
9661010	for  _ , tt  :=  range  tests  {
9671011		t .Run (tt .name , func (t  * testing.T ) {
@@ -997,6 +1041,211 @@ func TestMCPServer_Prompts(t *testing.T) {
9971041	}
9981042}
9991043
1044+ func  TestMCPServer_Resources (t  * testing.T ) {
1045+ 	tests  :=  []struct  {
1046+ 		name                   string 
1047+ 		action                 func (* testing.T , * MCPServer , chan  mcp.JSONRPCNotification )
1048+ 		expectedNotifications  int 
1049+ 		validate               func (* testing.T , []mcp.JSONRPCNotification , mcp.JSONRPCMessage )
1050+ 	}{
1051+ 		{
1052+ 			name : "DeleteResources sends single notifications/resources/list_changed" ,
1053+ 			action : func (t  * testing.T , server  * MCPServer , notificationChannel  chan  mcp.JSONRPCNotification ) {
1054+ 				err  :=  server .RegisterSession (context .TODO (), & fakeSession {
1055+ 					sessionID :           "test" ,
1056+ 					notificationChannel : notificationChannel ,
1057+ 					initialized :         true ,
1058+ 				})
1059+ 				require .NoError (t , err )
1060+ 				server .AddResource (
1061+ 					mcp.Resource {
1062+ 						URI :  "test://test-resource-1" ,
1063+ 						Name : "Test Resource 1" ,
1064+ 					},
1065+ 					func (ctx  context.Context , request  mcp.ReadResourceRequest ) ([]mcp.ResourceContents , error ) {
1066+ 						return  []mcp.ResourceContents {}, nil 
1067+ 					},
1068+ 				)
1069+ 				server .DeleteResources ("test://test-resource-1" )
1070+ 			},
1071+ 			expectedNotifications : 2 ,
1072+ 			validate : func (t  * testing.T , notifications  []mcp.JSONRPCNotification , resourcesList  mcp.JSONRPCMessage ) {
1073+ 				// One for AddResource 
1074+ 				assert .Equal (t , mcp .MethodNotificationResourcesListChanged , notifications [0 ].Method )
1075+ 				// One for DeleteResources 
1076+ 				assert .Equal (t , mcp .MethodNotificationResourcesListChanged , notifications [1 ].Method )
1077+ 
1078+ 				// Expect a successful response with an empty list of resources 
1079+ 				resp , ok  :=  resourcesList .(mcp.JSONRPCResponse )
1080+ 				assert .True (t , ok , "Expected JSONRPCResponse, got %T" , resourcesList )
1081+ 
1082+ 				result , ok  :=  resp .Result .(mcp.ListResourcesResult )
1083+ 				assert .True (t , ok , "Expected ListResourcesResult, got %T" , resp .Result )
1084+ 
1085+ 				assert .Empty (t , result .Resources , "Expected empty resources list" )
1086+ 			},
1087+ 		},
1088+ 		{
1089+ 			name : "DeleteResources removes the first resource and retains the other" ,
1090+ 			action : func (t  * testing.T , server  * MCPServer , notificationChannel  chan  mcp.JSONRPCNotification ) {
1091+ 				err  :=  server .RegisterSession (context .TODO (), & fakeSession {
1092+ 					sessionID :           "test" ,
1093+ 					notificationChannel : notificationChannel ,
1094+ 					initialized :         true ,
1095+ 				})
1096+ 				require .NoError (t , err )
1097+ 				server .AddResource (
1098+ 					mcp.Resource {
1099+ 						URI :  "test://test-resource-1" ,
1100+ 						Name : "Test Resource 1" ,
1101+ 					},
1102+ 					func (ctx  context.Context , request  mcp.ReadResourceRequest ) ([]mcp.ResourceContents , error ) {
1103+ 						return  []mcp.ResourceContents {}, nil 
1104+ 					},
1105+ 				)
1106+ 				server .AddResource (
1107+ 					mcp.Resource {
1108+ 						URI :  "test://test-resource-2" ,
1109+ 						Name : "Test Resource 2" ,
1110+ 					},
1111+ 					func (ctx  context.Context , request  mcp.ReadResourceRequest ) ([]mcp.ResourceContents , error ) {
1112+ 						return  []mcp.ResourceContents {}, nil 
1113+ 					},
1114+ 				)
1115+ 				server .DeleteResources ("test://test-resource-1" )
1116+ 			},
1117+ 			expectedNotifications : 3 ,
1118+ 			validate : func (t  * testing.T , notifications  []mcp.JSONRPCNotification , resourcesList  mcp.JSONRPCMessage ) {
1119+ 				// first notification expected for AddResource test-resource-1 
1120+ 				assert .Equal (t , mcp .MethodNotificationResourcesListChanged , notifications [0 ].Method )
1121+ 				// second notification expected for AddResource test-resource-2 
1122+ 				assert .Equal (t , mcp .MethodNotificationResourcesListChanged , notifications [1 ].Method )
1123+ 				// third notification expected for DeleteResources test-resource-1 
1124+ 				assert .Equal (t , mcp .MethodNotificationResourcesListChanged , notifications [2 ].Method )
1125+ 
1126+ 				// Confirm the resource list contains only test-resource-2 
1127+ 				resources  :=  resourcesList .(mcp.JSONRPCResponse ).Result .(mcp.ListResourcesResult ).Resources 
1128+ 				assert .Len (t , resources , 1 )
1129+ 				assert .Equal (t , "test://test-resource-2" , resources [0 ].URI )
1130+ 			},
1131+ 		},
1132+ 		{
1133+ 			name : "DeleteResources with non-existent resources does nothing and not receives notifications from MCPServer" ,
1134+ 			action : func (t  * testing.T , server  * MCPServer , notificationChannel  chan  mcp.JSONRPCNotification ) {
1135+ 				err  :=  server .RegisterSession (context .TODO (), & fakeSession {
1136+ 					sessionID :           "test" ,
1137+ 					notificationChannel : notificationChannel ,
1138+ 					initialized :         true ,
1139+ 				})
1140+ 				require .NoError (t , err )
1141+ 				server .AddResource (
1142+ 					mcp.Resource {
1143+ 						URI :  "test://test-resource-1" ,
1144+ 						Name : "Test Resource 1" ,
1145+ 					},
1146+ 					func (ctx  context.Context , request  mcp.ReadResourceRequest ) ([]mcp.ResourceContents , error ) {
1147+ 						return  []mcp.ResourceContents {}, nil 
1148+ 					},
1149+ 				)
1150+ 				server .AddResource (
1151+ 					mcp.Resource {
1152+ 						URI :  "test://test-resource-2" ,
1153+ 						Name : "Test Resource 2" ,
1154+ 					},
1155+ 					func (ctx  context.Context , request  mcp.ReadResourceRequest ) ([]mcp.ResourceContents , error ) {
1156+ 						return  []mcp.ResourceContents {}, nil 
1157+ 					},
1158+ 				)
1159+ 				// Remove non-existing resources 
1160+ 				server .DeleteResources ("test://test-resource-3" , "test://test-resource-4" )
1161+ 			},
1162+ 			expectedNotifications : 2 ,
1163+ 			validate : func (t  * testing.T , notifications  []mcp.JSONRPCNotification , resourcesList  mcp.JSONRPCMessage ) {
1164+ 				// first notification expected for AddResource test-resource-1 
1165+ 				assert .Equal (t , mcp .MethodNotificationResourcesListChanged , notifications [0 ].Method )
1166+ 				// second notification expected for AddResource test-resource-2 
1167+ 				assert .Equal (t , mcp .MethodNotificationResourcesListChanged , notifications [1 ].Method )
1168+ 
1169+ 				// Confirm the resource list does not change 
1170+ 				resources  :=  resourcesList .(mcp.JSONRPCResponse ).Result .(mcp.ListResourcesResult ).Resources 
1171+ 				assert .Len (t , resources , 2 )
1172+ 				// Resources are sorted by name 
1173+ 				assert .Equal (t , "test://test-resource-1" , resources [0 ].URI )
1174+ 				assert .Equal (t , "test://test-resource-2" , resources [1 ].URI )
1175+ 			},
1176+ 		},
1177+ 		{
1178+ 			name : "SetResources sends single notifications/resources/list_changed with one active session" ,
1179+ 			action : func (t  * testing.T , server  * MCPServer , notificationChannel  chan  mcp.JSONRPCNotification ) {
1180+ 				err  :=  server .RegisterSession (context .TODO (), & fakeSession {
1181+ 					sessionID :           "test" ,
1182+ 					notificationChannel : notificationChannel ,
1183+ 					initialized :         true ,
1184+ 				})
1185+ 				require .NoError (t , err )
1186+ 				server .SetResources (ServerResource {
1187+ 					Resource : mcp.Resource {
1188+ 						URI :  "test://test-resource-1" ,
1189+ 						Name : "Test Resource 1" ,
1190+ 					},
1191+ 					Handler : func (ctx  context.Context , request  mcp.ReadResourceRequest ) ([]mcp.ResourceContents , error ) {
1192+ 						return  []mcp.ResourceContents {}, nil 
1193+ 					},
1194+ 				}, ServerResource {
1195+ 					Resource : mcp.Resource {
1196+ 						URI :  "test://test-resource-2" ,
1197+ 						Name : "Test Resource 2" ,
1198+ 					},
1199+ 					Handler : func (ctx  context.Context , request  mcp.ReadResourceRequest ) ([]mcp.ResourceContents , error ) {
1200+ 						return  []mcp.ResourceContents {}, nil 
1201+ 					},
1202+ 				})
1203+ 			},
1204+ 			expectedNotifications : 1 ,
1205+ 			validate : func (t  * testing.T , notifications  []mcp.JSONRPCNotification , resourcesList  mcp.JSONRPCMessage ) {
1206+ 				assert .Equal (t , mcp .MethodNotificationResourcesListChanged , notifications [0 ].Method )
1207+ 				resources  :=  resourcesList .(mcp.JSONRPCResponse ).Result .(mcp.ListResourcesResult ).Resources 
1208+ 				assert .Len (t , resources , 2 )
1209+ 				// Resources are sorted by name 
1210+ 				assert .Equal (t , "test://test-resource-1" , resources [0 ].URI )
1211+ 				assert .Equal (t , "test://test-resource-2" , resources [1 ].URI )
1212+ 			},
1213+ 		},
1214+ 	}
1215+ 	for  _ , tt  :=  range  tests  {
1216+ 		t .Run (tt .name , func (t  * testing.T ) {
1217+ 			ctx  :=  context .Background ()
1218+ 			server  :=  NewMCPServer ("test-server" , "1.0.0" , WithResourceCapabilities (true , true ))
1219+ 			_  =  server .HandleMessage (ctx , []byte (`{ 
1220+ 				"jsonrpc": "2.0", 
1221+ 				"id": 1, 
1222+ 				"method": "initialize" 
1223+ 			}` ))
1224+ 			notificationChannel  :=  make (chan  mcp.JSONRPCNotification , 100 )
1225+ 			notifications  :=  make ([]mcp.JSONRPCNotification , 0 )
1226+ 			tt .action (t , server , notificationChannel )
1227+ 			for  done  :=  false ; ! done ; {
1228+ 				select  {
1229+ 				case  serverNotification  :=  <- notificationChannel :
1230+ 					notifications  =  append (notifications , serverNotification )
1231+ 					if  len (notifications ) ==  tt .expectedNotifications  {
1232+ 						done  =  true 
1233+ 					}
1234+ 				case  <- time .After (1  *  time .Second ):
1235+ 					done  =  true 
1236+ 				}
1237+ 			}
1238+ 			assert .Len (t , notifications , tt .expectedNotifications )
1239+ 			resourcesList  :=  server .HandleMessage (ctx , []byte (`{ 
1240+ 				"jsonrpc": "2.0", 
1241+ 				"id": 1, 
1242+ 				"method": "resources/list" 
1243+ 			}` ))
1244+ 			tt .validate (t , notifications , resourcesList )
1245+ 		})
1246+ 	}
1247+ }
1248+ 
10001249func  TestMCPServer_HandleInvalidMessages (t  * testing.T ) {
10011250	var  errs  []error 
10021251	hooks  :=  & Hooks {}
0 commit comments