@@ -17,10 +17,14 @@ import {
17
17
ErrorCode ,
18
18
ListToolsResultSchema ,
19
19
CallToolResultSchema ,
20
+ ListResourcesResultSchema ,
21
+ ListResourceTemplatesResultSchema ,
22
+ ReadResourceResultSchema ,
20
23
} from "../types.js" ;
21
24
import { Transport } from "../shared/transport.js" ;
22
25
import { InMemoryTransport } from "../inMemory.js" ;
23
26
import { Client } from "../client/index.js" ;
27
+ import { UriTemplate } from "../shared/uriTemplate.js" ;
24
28
25
29
test ( "should accept latest protocol version" , async ( ) => {
26
30
let sendPromiseResolve : ( value : unknown ) => void ;
@@ -478,6 +482,7 @@ test("should handle server cancelling a request", async () => {
478
482
// Request should be rejected
479
483
await expect ( createMessagePromise ) . rejects . toBe ( "Cancelled by test" ) ;
480
484
} ) ;
485
+
481
486
test ( "should handle request timeout" , async ( ) => {
482
487
const server = new Server (
483
488
{
@@ -927,3 +932,273 @@ describe("Server.tool", () => {
927
932
) . rejects . toThrow ( / T o o l n o n e x i s t e n t - t o o l n o t f o u n d / ) ;
928
933
} ) ;
929
934
} ) ;
935
+
936
+ describe ( "Server.resource" , ( ) => {
937
+ test ( "should register resource with uri and readCallback" , async ( ) => {
938
+ const server = new Server ( {
939
+ name : "test server" ,
940
+ version : "1.0" ,
941
+ } ) ;
942
+ const client = new Client ( {
943
+ name : "test client" ,
944
+ version : "1.0" ,
945
+ } ) ;
946
+
947
+ server . resource ( "test" , "test://resource" , async ( ) => ( {
948
+ contents : [
949
+ {
950
+ uri : "test://resource" ,
951
+ text : "Test content" ,
952
+ } ,
953
+ ] ,
954
+ } ) ) ;
955
+
956
+ const [ clientTransport , serverTransport ] =
957
+ InMemoryTransport . createLinkedPair ( ) ;
958
+
959
+ await Promise . all ( [
960
+ client . connect ( clientTransport ) ,
961
+ server . connect ( serverTransport ) ,
962
+ ] ) ;
963
+
964
+ const result = await client . request (
965
+ {
966
+ method : "resources/list" ,
967
+ } ,
968
+ ListResourcesResultSchema ,
969
+ ) ;
970
+
971
+ expect ( result . resources ) . toHaveLength ( 1 ) ;
972
+ expect ( result . resources [ 0 ] . name ) . toBe ( "test" ) ;
973
+ expect ( result . resources [ 0 ] . uri ) . toBe ( "test://resource" ) ;
974
+ } ) ;
975
+
976
+ test ( "should register resource with metadata" , async ( ) => {
977
+ const server = new Server ( {
978
+ name : "test server" ,
979
+ version : "1.0" ,
980
+ } ) ;
981
+ const client = new Client ( {
982
+ name : "test client" ,
983
+ version : "1.0" ,
984
+ } ) ;
985
+
986
+ server . resource (
987
+ "test" ,
988
+ "test://resource" ,
989
+ {
990
+ description : "Test resource" ,
991
+ mimeType : "text/plain" ,
992
+ } ,
993
+ async ( ) => ( {
994
+ contents : [
995
+ {
996
+ uri : "test://resource" ,
997
+ text : "Test content" ,
998
+ } ,
999
+ ] ,
1000
+ } ) ,
1001
+ ) ;
1002
+
1003
+ const [ clientTransport , serverTransport ] =
1004
+ InMemoryTransport . createLinkedPair ( ) ;
1005
+
1006
+ await Promise . all ( [
1007
+ client . connect ( clientTransport ) ,
1008
+ server . connect ( serverTransport ) ,
1009
+ ] ) ;
1010
+
1011
+ const result = await client . request (
1012
+ {
1013
+ method : "resources/list" ,
1014
+ } ,
1015
+ ListResourcesResultSchema ,
1016
+ ) ;
1017
+
1018
+ expect ( result . resources ) . toHaveLength ( 1 ) ;
1019
+ expect ( result . resources [ 0 ] . description ) . toBe ( "Test resource" ) ;
1020
+ expect ( result . resources [ 0 ] . mimeType ) . toBe ( "text/plain" ) ;
1021
+ } ) ;
1022
+
1023
+ test ( "should register resource template" , async ( ) => {
1024
+ const server = new Server ( {
1025
+ name : "test server" ,
1026
+ version : "1.0" ,
1027
+ } ) ;
1028
+ const client = new Client ( {
1029
+ name : "test client" ,
1030
+ version : "1.0" ,
1031
+ } ) ;
1032
+
1033
+ server . resource (
1034
+ "test" ,
1035
+ new UriTemplate ( "test://resource/{id}" ) ,
1036
+ async ( ) => ( {
1037
+ contents : [
1038
+ {
1039
+ uri : "test://resource/123" ,
1040
+ text : "Test content" ,
1041
+ } ,
1042
+ ] ,
1043
+ } ) ,
1044
+ ) ;
1045
+
1046
+ const [ clientTransport , serverTransport ] =
1047
+ InMemoryTransport . createLinkedPair ( ) ;
1048
+
1049
+ await Promise . all ( [
1050
+ client . connect ( clientTransport ) ,
1051
+ server . connect ( serverTransport ) ,
1052
+ ] ) ;
1053
+
1054
+ const result = await client . request (
1055
+ {
1056
+ method : "resources/templates/list" ,
1057
+ } ,
1058
+ ListResourceTemplatesResultSchema ,
1059
+ ) ;
1060
+
1061
+ expect ( result . resourceTemplates ) . toHaveLength ( 1 ) ;
1062
+ expect ( result . resourceTemplates [ 0 ] . name ) . toBe ( "test" ) ;
1063
+ expect ( result . resourceTemplates [ 0 ] . uriTemplate ) . toBe (
1064
+ "test://resource/{id}" ,
1065
+ ) ;
1066
+ } ) ;
1067
+
1068
+ test ( "should prevent duplicate resource registration" , ( ) => {
1069
+ const server = new Server ( {
1070
+ name : "test server" ,
1071
+ version : "1.0" ,
1072
+ } ) ;
1073
+
1074
+ server . resource ( "test" , "test://resource" , async ( ) => ( {
1075
+ contents : [
1076
+ {
1077
+ uri : "test://resource" ,
1078
+ text : "Test content" ,
1079
+ } ,
1080
+ ] ,
1081
+ } ) ) ;
1082
+
1083
+ expect ( ( ) => {
1084
+ server . resource ( "test2" , "test://resource" , async ( ) => ( {
1085
+ contents : [
1086
+ {
1087
+ uri : "test://resource" ,
1088
+ text : "Test content 2" ,
1089
+ } ,
1090
+ ] ,
1091
+ } ) ) ;
1092
+ } ) . toThrow ( / a l r e a d y r e g i s t e r e d / ) ;
1093
+ } ) ;
1094
+
1095
+ test ( "should prevent duplicate resource template registration" , ( ) => {
1096
+ const server = new Server ( {
1097
+ name : "test server" ,
1098
+ version : "1.0" ,
1099
+ } ) ;
1100
+
1101
+ server . resource (
1102
+ "test" ,
1103
+ new UriTemplate ( "test://resource/{id}" ) ,
1104
+ async ( ) => ( {
1105
+ contents : [
1106
+ {
1107
+ uri : "test://resource/123" ,
1108
+ text : "Test content" ,
1109
+ } ,
1110
+ ] ,
1111
+ } ) ,
1112
+ ) ;
1113
+
1114
+ expect ( ( ) => {
1115
+ server . resource (
1116
+ "test" ,
1117
+ new UriTemplate ( "test://resource/{id}" ) ,
1118
+ async ( ) => ( {
1119
+ contents : [
1120
+ {
1121
+ uri : "test://resource/123" ,
1122
+ text : "Test content 2" ,
1123
+ } ,
1124
+ ] ,
1125
+ } ) ,
1126
+ ) ;
1127
+ } ) . toThrow ( / a l r e a d y r e g i s t e r e d / ) ;
1128
+ } ) ;
1129
+
1130
+ test ( "should handle resource read errors gracefully" , async ( ) => {
1131
+ const server = new Server ( {
1132
+ name : "test server" ,
1133
+ version : "1.0" ,
1134
+ } ) ;
1135
+ const client = new Client ( {
1136
+ name : "test client" ,
1137
+ version : "1.0" ,
1138
+ } ) ;
1139
+
1140
+ server . resource ( "error-test" , "test://error" , async ( ) => {
1141
+ throw new Error ( "Resource read failed" ) ;
1142
+ } ) ;
1143
+
1144
+ const [ clientTransport , serverTransport ] =
1145
+ InMemoryTransport . createLinkedPair ( ) ;
1146
+
1147
+ await Promise . all ( [
1148
+ client . connect ( clientTransport ) ,
1149
+ server . connect ( serverTransport ) ,
1150
+ ] ) ;
1151
+
1152
+ await expect (
1153
+ client . request (
1154
+ {
1155
+ method : "resources/read" ,
1156
+ params : {
1157
+ uri : "test://error" ,
1158
+ } ,
1159
+ } ,
1160
+ ReadResourceResultSchema ,
1161
+ ) ,
1162
+ ) . rejects . toThrow ( / R e s o u r c e r e a d f a i l e d / ) ;
1163
+ } ) ;
1164
+
1165
+ test ( "should throw McpError for invalid resource URI" , async ( ) => {
1166
+ const server = new Server ( {
1167
+ name : "test server" ,
1168
+ version : "1.0" ,
1169
+ } ) ;
1170
+ const client = new Client ( {
1171
+ name : "test client" ,
1172
+ version : "1.0" ,
1173
+ } ) ;
1174
+
1175
+ server . resource ( "test" , "test://resource" , async ( ) => ( {
1176
+ contents : [
1177
+ {
1178
+ uri : "test://resource" ,
1179
+ text : "Test content" ,
1180
+ } ,
1181
+ ] ,
1182
+ } ) ) ;
1183
+
1184
+ const [ clientTransport , serverTransport ] =
1185
+ InMemoryTransport . createLinkedPair ( ) ;
1186
+
1187
+ await Promise . all ( [
1188
+ client . connect ( clientTransport ) ,
1189
+ server . connect ( serverTransport ) ,
1190
+ ] ) ;
1191
+
1192
+ await expect (
1193
+ client . request (
1194
+ {
1195
+ method : "resources/read" ,
1196
+ params : {
1197
+ uri : "test://nonexistent" ,
1198
+ } ,
1199
+ } ,
1200
+ ReadResourceResultSchema ,
1201
+ ) ,
1202
+ ) . rejects . toThrow ( / R e s o u r c e t e s t : \/ \/ n o n e x i s t e n t n o t f o u n d / ) ;
1203
+ } ) ;
1204
+ } ) ;
0 commit comments