@@ -28,6 +28,7 @@ import {
28
28
ListResourceTemplatesRequest ,
29
29
ListResourceTemplatesResultSchema ,
30
30
ListToolsRequest ,
31
+ ListToolsResult ,
31
32
ListToolsResultSchema ,
32
33
LoggingLevel ,
33
34
Notification ,
@@ -76,7 +77,7 @@ export type ClientOptions = ProtocolOptions & {
76
77
export class Client <
77
78
RequestT extends Request = Request ,
78
79
NotificationT extends Notification = Notification ,
79
- ResultT extends Result = Result ,
80
+ ResultT extends Result = Result
80
81
> extends Protocol <
81
82
ClientRequest | RequestT ,
82
83
ClientNotification | NotificationT ,
@@ -87,15 +88,38 @@ export class Client<
87
88
private _capabilities : ClientCapabilities ;
88
89
private _instructions ?: string ;
89
90
91
+ /**
92
+ * Callback for when the server indicates that the tools list has changed.
93
+ * Client should typically refresh its list of tools in response.
94
+ */
95
+ onToolListChanged ?: ( tools ?: ListToolsResult [ "tools" ] ) => void ;
96
+
90
97
/**
91
98
* Initializes this client with the given name and version information.
92
99
*/
93
- constructor (
94
- private _clientInfo : Implementation ,
95
- options ?: ClientOptions ,
96
- ) {
100
+ constructor ( private _clientInfo : Implementation , options ?: ClientOptions ) {
97
101
super ( options ) ;
98
102
this . _capabilities = options ?. capabilities ?? { } ;
103
+
104
+ // Set up notification handlers
105
+ this . setNotificationHandler (
106
+ "notifications/tools/list_changed" ,
107
+ async ( ) => {
108
+ // Automatically refresh the tools list when the server indicates a change
109
+ try {
110
+ // Only refresh if the server supports tools
111
+ if ( this . _serverCapabilities ?. tools ) {
112
+ const result = await this . listTools ( ) ;
113
+ // Call the user's callback with the updated tools list
114
+ this . onToolListChanged ?.( result . tools ) ;
115
+ }
116
+ } catch ( error ) {
117
+ console . error ( "Failed to refresh tools list:" , error ) ;
118
+ // Still call the callback even if refresh failed
119
+ this . onToolListChanged ?.( undefined ) ;
120
+ }
121
+ }
122
+ ) ;
99
123
}
100
124
101
125
/**
@@ -106,7 +130,7 @@ export class Client<
106
130
public registerCapabilities ( capabilities : ClientCapabilities ) : void {
107
131
if ( this . transport ) {
108
132
throw new Error (
109
- "Cannot register capabilities after connecting to transport" ,
133
+ "Cannot register capabilities after connecting to transport"
110
134
) ;
111
135
}
112
136
@@ -115,11 +139,11 @@ export class Client<
115
139
116
140
protected assertCapability (
117
141
capability : keyof ServerCapabilities ,
118
- method : string ,
142
+ method : string
119
143
) : void {
120
144
if ( ! this . _serverCapabilities ?. [ capability ] ) {
121
145
throw new Error (
122
- `Server does not support ${ capability } (required for ${ method } )` ,
146
+ `Server does not support ${ String ( capability ) } (required for ${ method } )`
123
147
) ;
124
148
}
125
149
}
@@ -137,7 +161,7 @@ export class Client<
137
161
clientInfo : this . _clientInfo ,
138
162
} ,
139
163
} ,
140
- InitializeResultSchema ,
164
+ InitializeResultSchema
141
165
) ;
142
166
143
167
if ( result === undefined ) {
@@ -146,7 +170,7 @@ export class Client<
146
170
147
171
if ( ! SUPPORTED_PROTOCOL_VERSIONS . includes ( result . protocolVersion ) ) {
148
172
throw new Error (
149
- `Server's protocol version is not supported: ${ result . protocolVersion } ` ,
173
+ `Server's protocol version is not supported: ${ result . protocolVersion } `
150
174
) ;
151
175
}
152
176
@@ -191,7 +215,7 @@ export class Client<
191
215
case "logging/setLevel" :
192
216
if ( ! this . _serverCapabilities ?. logging ) {
193
217
throw new Error (
194
- `Server does not support logging (required for ${ method } )` ,
218
+ `Server does not support logging (required for ${ method } )`
195
219
) ;
196
220
}
197
221
break ;
@@ -200,7 +224,7 @@ export class Client<
200
224
case "prompts/list" :
201
225
if ( ! this . _serverCapabilities ?. prompts ) {
202
226
throw new Error (
203
- `Server does not support prompts (required for ${ method } )` ,
227
+ `Server does not support prompts (required for ${ method } )`
204
228
) ;
205
229
}
206
230
break ;
@@ -212,7 +236,7 @@ export class Client<
212
236
case "resources/unsubscribe" :
213
237
if ( ! this . _serverCapabilities ?. resources ) {
214
238
throw new Error (
215
- `Server does not support resources (required for ${ method } )` ,
239
+ `Server does not support resources (required for ${ method } )`
216
240
) ;
217
241
}
218
242
@@ -221,7 +245,7 @@ export class Client<
221
245
! this . _serverCapabilities . resources . subscribe
222
246
) {
223
247
throw new Error (
224
- `Server does not support resource subscriptions (required for ${ method } )` ,
248
+ `Server does not support resource subscriptions (required for ${ method } )`
225
249
) ;
226
250
}
227
251
@@ -231,15 +255,15 @@ export class Client<
231
255
case "tools/list" :
232
256
if ( ! this . _serverCapabilities ?. tools ) {
233
257
throw new Error (
234
- `Server does not support tools (required for ${ method } )` ,
258
+ `Server does not support tools (required for ${ method } )`
235
259
) ;
236
260
}
237
261
break ;
238
262
239
263
case "completion/complete" :
240
264
if ( ! this . _serverCapabilities ?. prompts ) {
241
265
throw new Error (
242
- `Server does not support prompts (required for ${ method } )` ,
266
+ `Server does not support prompts (required for ${ method } )`
243
267
) ;
244
268
}
245
269
break ;
@@ -255,13 +279,23 @@ export class Client<
255
279
}
256
280
257
281
protected assertNotificationCapability (
258
- method : NotificationT [ "method" ] ,
282
+ method : NotificationT [ "method" ]
259
283
) : void {
260
284
switch ( method as ClientNotification [ "method" ] ) {
261
285
case "notifications/roots/list_changed" :
262
286
if ( ! this . _capabilities . roots ?. listChanged ) {
263
287
throw new Error (
264
- `Client does not support roots list changed notifications (required for ${ method } )` ,
288
+ `Client does not support roots list changed notifications (required for ${ method } )`
289
+ ) ;
290
+ }
291
+ break ;
292
+
293
+ case "notifications/tools/list_changed" :
294
+ if ( ! this . _capabilities . tools ?. listChanged ) {
295
+ throw new Error (
296
+ `Client does not support tools capability (required for ${ String (
297
+ method
298
+ ) } )`
265
299
) ;
266
300
}
267
301
break ;
@@ -285,15 +319,15 @@ export class Client<
285
319
case "sampling/createMessage" :
286
320
if ( ! this . _capabilities . sampling ) {
287
321
throw new Error (
288
- `Client does not support sampling capability (required for ${ method } )` ,
322
+ `Client does not support sampling capability (required for ${ method } )`
289
323
) ;
290
324
}
291
325
break ;
292
326
293
327
case "roots/list" :
294
328
if ( ! this . _capabilities . roots ) {
295
329
throw new Error (
296
- `Client does not support roots capability (required for ${ method } )` ,
330
+ `Client does not support roots capability (required for ${ method } )`
297
331
) ;
298
332
}
299
333
break ;
@@ -312,92 +346,92 @@ export class Client<
312
346
return this . request (
313
347
{ method : "completion/complete" , params } ,
314
348
CompleteResultSchema ,
315
- options ,
349
+ options
316
350
) ;
317
351
}
318
352
319
353
async setLoggingLevel ( level : LoggingLevel , options ?: RequestOptions ) {
320
354
return this . request (
321
355
{ method : "logging/setLevel" , params : { level } } ,
322
356
EmptyResultSchema ,
323
- options ,
357
+ options
324
358
) ;
325
359
}
326
360
327
361
async getPrompt (
328
362
params : GetPromptRequest [ "params" ] ,
329
- options ?: RequestOptions ,
363
+ options ?: RequestOptions
330
364
) {
331
365
return this . request (
332
366
{ method : "prompts/get" , params } ,
333
367
GetPromptResultSchema ,
334
- options ,
368
+ options
335
369
) ;
336
370
}
337
371
338
372
async listPrompts (
339
373
params ?: ListPromptsRequest [ "params" ] ,
340
- options ?: RequestOptions ,
374
+ options ?: RequestOptions
341
375
) {
342
376
return this . request (
343
377
{ method : "prompts/list" , params } ,
344
378
ListPromptsResultSchema ,
345
- options ,
379
+ options
346
380
) ;
347
381
}
348
382
349
383
async listResources (
350
384
params ?: ListResourcesRequest [ "params" ] ,
351
- options ?: RequestOptions ,
385
+ options ?: RequestOptions
352
386
) {
353
387
return this . request (
354
388
{ method : "resources/list" , params } ,
355
389
ListResourcesResultSchema ,
356
- options ,
390
+ options
357
391
) ;
358
392
}
359
393
360
394
async listResourceTemplates (
361
395
params ?: ListResourceTemplatesRequest [ "params" ] ,
362
- options ?: RequestOptions ,
396
+ options ?: RequestOptions
363
397
) {
364
398
return this . request (
365
399
{ method : "resources/templates/list" , params } ,
366
400
ListResourceTemplatesResultSchema ,
367
- options ,
401
+ options
368
402
) ;
369
403
}
370
404
371
405
async readResource (
372
406
params : ReadResourceRequest [ "params" ] ,
373
- options ?: RequestOptions ,
407
+ options ?: RequestOptions
374
408
) {
375
409
return this . request (
376
410
{ method : "resources/read" , params } ,
377
411
ReadResourceResultSchema ,
378
- options ,
412
+ options
379
413
) ;
380
414
}
381
415
382
416
async subscribeResource (
383
417
params : SubscribeRequest [ "params" ] ,
384
- options ?: RequestOptions ,
418
+ options ?: RequestOptions
385
419
) {
386
420
return this . request (
387
421
{ method : "resources/subscribe" , params } ,
388
422
EmptyResultSchema ,
389
- options ,
423
+ options
390
424
) ;
391
425
}
392
426
393
427
async unsubscribeResource (
394
428
params : UnsubscribeRequest [ "params" ] ,
395
- options ?: RequestOptions ,
429
+ options ?: RequestOptions
396
430
) {
397
431
return this . request (
398
432
{ method : "resources/unsubscribe" , params } ,
399
433
EmptyResultSchema ,
400
- options ,
434
+ options
401
435
) ;
402
436
}
403
437
@@ -406,27 +440,43 @@ export class Client<
406
440
resultSchema :
407
441
| typeof CallToolResultSchema
408
442
| typeof CompatibilityCallToolResultSchema = CallToolResultSchema ,
409
- options ?: RequestOptions ,
443
+ options ?: RequestOptions
410
444
) {
411
445
return this . request (
412
446
{ method : "tools/call" , params } ,
413
447
resultSchema ,
414
- options ,
448
+ options
415
449
) ;
416
450
}
417
451
418
452
async listTools (
419
453
params ?: ListToolsRequest [ "params" ] ,
420
- options ?: RequestOptions ,
454
+ options ?: RequestOptions
421
455
) {
422
456
return this . request (
423
457
{ method : "tools/list" , params } ,
424
458
ListToolsResultSchema ,
425
- options ,
459
+ options
426
460
) ;
427
461
}
428
462
463
+ /**
464
+ * Registers a callback to be called when the server indicates that
465
+ * the tools list has changed. The callback should typically refresh the tools list.
466
+ *
467
+ * @param callback Function to call when tools list changes
468
+ */
469
+ setToolListChangedCallback (
470
+ callback : ( tools ?: ListToolsResult [ "tools" ] ) => void
471
+ ) : void {
472
+ this . onToolListChanged = callback ;
473
+ }
474
+
429
475
async sendRootsListChanged ( ) {
430
476
return this . notification ( { method : "notifications/roots/list_changed" } ) ;
431
477
}
478
+
479
+ async sendToolListChanged ( ) {
480
+ return this . notification ( { method : "notifications/tools/list_changed" } ) ;
481
+ }
432
482
}
0 commit comments