@@ -36,7 +36,9 @@ import {
3636 SUPPORTED_PROTOCOL_VERSIONS ,
3737 type SubscribeRequest ,
3838 type Tool ,
39- type UnsubscribeRequest
39+ type UnsubscribeRequest ,
40+ ToolListChangedNotificationSchema ,
41+ ToolListChangedOptions
4042} from '../types.js' ;
4143import { AjvJsonSchemaValidator } from '../validation/ajv-provider.js' ;
4244import type { JsonSchemaType , JsonSchemaValidator , jsonSchemaValidator } from '../validation/types.js' ;
@@ -77,6 +79,41 @@ export type ClientOptions = ProtocolOptions & {
7779 * ```
7880 */
7981 jsonSchemaValidator ?: jsonSchemaValidator ;
82+
83+ /**
84+ * Configure automatic refresh behavior for tool list changed notifications
85+ *
86+ * @example
87+ * ```ts
88+ * {
89+ * autoRefresh: true,
90+ * debounceMs: 300,
91+ * onToolListChanged: (err, tools) => {
92+ * if (err) {
93+ * console.error('Failed to refresh tool list:', err);
94+ * return;
95+ * }
96+ * // Use the updated tool list
97+ * console.log('Tool list changed:', tools);
98+ * }
99+ * }
100+ * ```
101+ *
102+ * @example
103+ * ```ts
104+ * {
105+ * autoRefresh: false,
106+ * onToolListChanged: (err, tools) => {
107+ * // err is always null when autoRefresh is false
108+ *
109+ * // Manually refresh the tool list
110+ * const result = await this.listTools();
111+ * console.log('Tool list changed:', result.tools);
112+ * }
113+ * }
114+ * ```
115+ */
116+ toolListChangedOptions ?: ToolListChangedOptions ;
80117} ;
81118
82119/**
@@ -115,6 +152,8 @@ export class Client<
115152 private _instructions ?: string ;
116153 private _jsonSchemaValidator : jsonSchemaValidator ;
117154 private _cachedToolOutputValidators : Map < string , JsonSchemaValidator < unknown > > = new Map ( ) ;
155+ private _toolListChangedOptions : ToolListChangedOptions | null = null ;
156+ private _toolListChangedDebounceTimer ?: ReturnType < typeof setTimeout > ;
118157
119158 /**
120159 * Initializes this client with the given name and version information.
@@ -126,6 +165,9 @@ export class Client<
126165 super ( options ) ;
127166 this . _capabilities = options ?. capabilities ?? { } ;
128167 this . _jsonSchemaValidator = options ?. jsonSchemaValidator ?? new AjvJsonSchemaValidator ( ) ;
168+
169+ // Set up tool list changed options
170+ this . setToolListChangedOptions ( options ?. toolListChangedOptions || null ) ;
129171 }
130172
131173 /**
@@ -434,6 +476,60 @@ export class Client<
434476 return result ;
435477 }
436478
479+ /**
480+ * Updates the tool list changed options
481+ *
482+ * Set to null to disable tool list changed notifications
483+ */
484+ public setToolListChangedOptions ( options : ToolListChangedOptions | null ) : void {
485+ // Set up tool list changed options and add notification handler
486+ if ( options ) {
487+ const toolListChangedOptions : ToolListChangedOptions = {
488+ autoRefresh : ! ! options . autoRefresh ,
489+ debounceMs : options . debounceMs ?? 300 ,
490+ onToolListChanged : options . onToolListChanged ,
491+ } ;
492+ this . _toolListChangedOptions = toolListChangedOptions ;
493+ this . setNotificationHandler ( ToolListChangedNotificationSchema , ( ) => {
494+ // If autoRefresh is false, call the callback for the notification, but without tools data
495+ if ( ! toolListChangedOptions . autoRefresh ) {
496+ toolListChangedOptions . onToolListChanged ?.( null , null ) ;
497+ return ;
498+ }
499+
500+ // Clear any pending debounce timer
501+ if ( this . _toolListChangedDebounceTimer ) {
502+ clearTimeout ( this . _toolListChangedDebounceTimer ) ;
503+ }
504+
505+ // Set up debounced refresh
506+ this . _toolListChangedDebounceTimer = setTimeout ( async ( ) => {
507+ let tools : Tool [ ] | null = null ;
508+ let error : Error | null = null ;
509+ try {
510+ const result = await this . listTools ( ) ;
511+ tools = result . tools ;
512+ } catch ( e ) {
513+ error = e instanceof Error ? e : new Error ( String ( e ) ) ;
514+ }
515+ toolListChangedOptions . onToolListChanged ?.( error , tools ) ;
516+ } , toolListChangedOptions . debounceMs ) ;
517+ } ) ;
518+ }
519+ // Reset tool list changed options and remove notification handler
520+ else {
521+ this . _toolListChangedOptions = null ;
522+ this . removeNotificationHandler ( ToolListChangedNotificationSchema . shape . method . value ) ;
523+ }
524+ }
525+
526+ /**
527+ * Gets the current tool list changed options
528+ */
529+ public getToolListChangedOptions ( ) : ToolListChangedOptions | null {
530+ return this . _toolListChangedOptions ;
531+ }
532+
437533 async sendRootsListChanged ( ) {
438534 return this . notification ( { method : 'notifications/roots/list_changed' } ) ;
439535 }
0 commit comments