Skip to content

Commit 2f1049f

Browse files
committed
use z.input type
1 parent 7f69be1 commit 2f1049f

File tree

2 files changed

+43
-30
lines changed

2 files changed

+43
-30
lines changed

src/client/index.ts

Lines changed: 39 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ import {
3838
type Tool,
3939
type UnsubscribeRequest,
4040
ToolListChangedNotificationSchema,
41-
ToolListChangedOptions
41+
ToolListChangedOptions,
42+
ToolListChangedOptionsSchema
4243
} from '../types.js';
4344
import { AjvJsonSchemaValidator } from '../validation/ajv-provider.js';
4445
import type { JsonSchemaType, JsonSchemaValidator, jsonSchemaValidator } from '../validation/types.js';
@@ -83,11 +84,11 @@ export type ClientOptions = ProtocolOptions & {
8384
/**
8485
* Configure automatic refresh behavior for tool list changed notifications
8586
*
87+
* Here's an example of how to get the updated tool list when the tool list changed notification is received:
88+
*
8689
* @example
87-
* ```ts
90+
* ```typescript
8891
* {
89-
* autoRefresh: true,
90-
* debounceMs: 300,
9192
* onToolListChanged: (err, tools) => {
9293
* if (err) {
9394
* console.error('Failed to refresh tool list:', err);
@@ -99,10 +100,13 @@ export type ClientOptions = ProtocolOptions & {
99100
* }
100101
* ```
101102
*
103+
* Here is an example of how to manually refresh the tool list when the tool list changed notification is received:
104+
*
102105
* @example
103-
* ```ts
106+
* ```typescript
104107
* {
105108
* autoRefresh: false,
109+
* debounceMs: 0,
106110
* onToolListChanged: (err, tools) => {
107111
* // err is always null when autoRefresh is false
108112
*
@@ -484,36 +488,45 @@ export class Client<
484488
public setToolListChangedOptions(options: ToolListChangedOptions | null): void {
485489
// Set up tool list changed options and add notification handler
486490
if (options) {
487-
const toolListChangedOptions: ToolListChangedOptions = {
488-
autoRefresh: !!options.autoRefresh,
489-
debounceMs: options.debounceMs ?? 300,
490-
onToolListChanged: options.onToolListChanged
491-
};
491+
const parseResult = ToolListChangedOptionsSchema.safeParse(options);
492+
if (parseResult.error) {
493+
throw new Error(`Tool List Changed options are invalid: ${parseResult.error.message}`);
494+
}
495+
496+
const toolListChangedOptions = parseResult.data;
492497
this._toolListChangedOptions = toolListChangedOptions;
498+
499+
const refreshToolList = async () => {
500+
let tools: Tool[] | null = null;
501+
let error: Error | null = null;
502+
try {
503+
const result = await this.listTools();
504+
tools = result.tools;
505+
} catch (e) {
506+
error = e instanceof Error ? e : new Error(String(e));
507+
}
508+
toolListChangedOptions.onToolListChanged?.(error, tools);
509+
};
510+
493511
this.setNotificationHandler(ToolListChangedNotificationSchema, () => {
494512
// If autoRefresh is false, call the callback for the notification, but without tools data
495513
if (!toolListChangedOptions.autoRefresh) {
496514
toolListChangedOptions.onToolListChanged?.(null, null);
497515
return;
498516
}
499517

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));
518+
if (toolListChangedOptions.debounceMs) {
519+
// Clear any pending debounce timer
520+
if (this._toolListChangedDebounceTimer) {
521+
clearTimeout(this._toolListChangedDebounceTimer);
514522
}
515-
toolListChangedOptions.onToolListChanged?.(error, tools);
516-
}, toolListChangedOptions.debounceMs);
523+
524+
// Set up debounced refresh
525+
this._toolListChangedDebounceTimer = setTimeout(refreshToolList, toolListChangedOptions.debounceMs);
526+
} else {
527+
// No debounce, refresh immediately
528+
refreshToolList();
529+
}
517530
});
518531
}
519532
// Reset tool list changed options and remove notification handler

src/types.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1049,17 +1049,17 @@ export const ToolListChangedOptionsSchema = z.object({
10491049
*
10501050
* If `onToolListChanged` is also provided, it will be called after the tool list is auto refreshed.
10511051
*
1052-
* @default false
1052+
* @default true
10531053
*/
1054-
autoRefresh: z.boolean().optional(),
1054+
autoRefresh: z.boolean().default(true),
10551055
/**
10561056
* Debounce time in milliseconds for tool list changed notification processing.
10571057
*
10581058
* Multiple notifications received within this timeframe will only trigger one refresh.
10591059
*
10601060
* @default 300
10611061
*/
1062-
debounceMs: z.number().int().optional(),
1062+
debounceMs: z.number().int().default(300),
10631063
/**
10641064
* This callback is always called when the server sends a tool list changed notification.
10651065
*
@@ -1068,7 +1068,7 @@ export const ToolListChangedOptionsSchema = z.object({
10681068
onToolListChanged: z.function(z.tuple([z.instanceof(Error).nullable(), z.array(ToolSchema).nullable()]), z.void())
10691069
});
10701070

1071-
export type ToolListChangedOptions = z.infer<typeof ToolListChangedOptionsSchema>;
1071+
export type ToolListChangedOptions = z.input<typeof ToolListChangedOptionsSchema>;
10721072

10731073
/* Logging */
10741074
/**

0 commit comments

Comments
 (0)