Skip to content

Commit f3a0fa5

Browse files
committed
CR changes
1 parent 8aebebb commit f3a0fa5

File tree

3 files changed

+22
-19
lines changed

3 files changed

+22
-19
lines changed

src/server.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,20 +63,25 @@ export interface ServerOptions {
6363
*/
6464
tools?: ToolClass[];
6565
/**
66-
* Custom UIs for tools. Maps tool names to their HTML strings.
66+
* Custom UIs for tools. Function that returns HTML strings for tool names.
6767
* Use this to add UIs to tools or replace the default bundled UIs.
68+
* The function is called lazily when a UI is requested, allowing you to
69+
* defer loading large HTML files until needed.
6870
*
6971
* ```ts
7072
* import { readFileSync } from 'fs';
7173
* const server = new Server({
7274
* // ... other options
73-
* customUIs: {
74-
* 'list-databases': readFileSync('./my-custom-ui.html', 'utf-8'),
75+
* customUIs: (toolName) => {
76+
* if (toolName === 'list-databases') {
77+
* return readFileSync('./my-custom-ui.html', 'utf-8');
78+
* }
79+
* return null;
7580
* }
7681
* });
7782
* ```
7883
*/
79-
customUIs?: Record<string, string>;
84+
customUIs?: (toolName: string) => string | null | Promise<string | null>;
8085
}
8186

8287
export class Server {

src/tools/tool.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export type ToolExecutionContext = {
2222
};
2323

2424
/**
25-
* The type of operation the tool performs. This is used when evaluating if a tool is allowed to run based on
25+
* The ~`type of operation the tool performs. This is used when evaluating if a tool is allowed to run based on
2626
* the config's `disabledTools` and `readOnly` settings.
2727
* - `metadata` is used for tools that read but do not access potentially user-generated
2828
* data, such as listing databases, collections, or indexes, or inferring collection schema.
@@ -94,7 +94,7 @@ export type ToolConstructorParams = {
9494
* See `src/elicitation.ts` for further reference.
9595
*/
9696
elicitation: Elicitation;
97-
uiRegistry?: UIRegistry;
97+
uiRegistry: UIRegistry;
9898
};
9999

100100
/**
@@ -432,7 +432,7 @@ export abstract class ToolBase {
432432
* or inputs during tool execution.
433433
*/
434434
protected readonly elicitation: Elicitation;
435-
protected readonly uiRegistry?: UIRegistry;
435+
private readonly uiRegistry: UIRegistry;
436436
constructor({
437437
category,
438438
operationType,
@@ -728,7 +728,7 @@ export abstract class ToolBase {
728728
return result;
729729
}
730730

731-
const uiHtml = await this.uiRegistry?.get(this.name);
731+
const uiHtml = await this.uiRegistry.get(this.name);
732732
if (!uiHtml || !result.structuredContent) {
733733
return result;
734734
}

src/ui/registry/registry.ts

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,24 +10,22 @@ function toPascalCase(kebabCase: string): string {
1010
* UI Registry that manages bundled UI HTML strings for tools.
1111
*/
1212
export class UIRegistry {
13-
private customUIs: Map<string, string> = new Map();
13+
private customUIs?: (toolName: string) => string | null | Promise<string | null>;
1414
private cache: Map<string, string> = new Map();
1515

16-
constructor(options?: { customUIs?: Record<string, string> }) {
17-
if (options?.customUIs) {
18-
for (const [toolName, html] of Object.entries(options.customUIs)) {
19-
this.customUIs.set(toolName, html);
20-
}
21-
}
16+
constructor(options?: { customUIs?: (toolName: string) => string | null | Promise<string | null> }) {
17+
this.customUIs = options?.customUIs;
2218
}
2319

2420
/**
2521
* Gets the UI HTML string for a tool, or null if none exists.
2622
*/
2723
async get(toolName: string): Promise<string | null> {
28-
const customUI = this.customUIs.get(toolName);
29-
if (customUI !== undefined) {
30-
return customUI;
24+
if (this.customUIs) {
25+
const customUI = await this.customUIs(toolName);
26+
if (customUI !== null && customUI !== undefined) {
27+
return customUI;
28+
}
3129
}
3230

3331
const cached = this.cache.get(toolName);
@@ -38,7 +36,7 @@ export class UIRegistry {
3836
try {
3937
const module = (await import(`../lib/tools/${toolName}.js`)) as Record<string, string>;
4038
const exportName = `${toPascalCase(toolName)}Html`;
41-
const html = module[exportName];
39+
const html = module[exportName]; // HTML generated at build time
4240
if (html === undefined) {
4341
return null;
4442
}

0 commit comments

Comments
 (0)