@@ -962,6 +962,50 @@ func TestMCPServer_Prompts(t *testing.T) {
962
962
assert .Equal (t , "test-prompt-2" , prompts [1 ].Name )
963
963
},
964
964
},
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
+ },
965
1009
}
966
1010
for _ , tt := range tests {
967
1011
t .Run (tt .name , func (t * testing.T ) {
@@ -997,6 +1041,211 @@ func TestMCPServer_Prompts(t *testing.T) {
997
1041
}
998
1042
}
999
1043
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
+
1000
1249
func TestMCPServer_HandleInvalidMessages (t * testing.T ) {
1001
1250
var errs []error
1002
1251
hooks := & Hooks {}
0 commit comments