From be8022e4f4abff7726246eac2b229a7b2da186e0 Mon Sep 17 00:00:00 2001 From: ChipGPT Date: Thu, 2 Oct 2025 11:06:33 -0500 Subject: [PATCH 1/4] Add `server.removeTool('name')` --- src/server/mcp.test.ts | 54 ++++++++++++++++++++++++++++++++++++++++++ src/server/mcp.ts | 11 +++++++++ 2 files changed, 65 insertions(+) diff --git a/src/server/mcp.test.ts b/src/server/mcp.test.ts index 4bb42d7fc..6a989f54f 100644 --- a/src/server/mcp.test.ts +++ b/src/server/mcp.test.ts @@ -505,6 +505,60 @@ describe('tool()', () => { ]); }); + /*** + * Test: Tool self removal + */ + test("should remove tool when using tool.remove()", async () => { + const mcpServer = new McpServer({ + name: "test server", + version: "1.0", + }); + + // Register initial tool + const tool = mcpServer.tool("test", async () => ({ + content: [ + { + type: "text", + text: "Test response", + }, + ], + })); + + expect(mcpServer['_registeredTools']['test']).toBeDefined(); + + // Now delete the tool + tool.remove(); + + expect(mcpServer['_registeredTools']['test']).toBeUndefined(); + }); + + /*** + * Test: Tool server removal + */ + test("should remove tool when using server.removeTool(...)", async () => { + const mcpServer = new McpServer({ + name: "test server", + version: "1.0", + }); + + // Register initial tool + mcpServer.tool("test", async () => ({ + content: [ + { + type: "text", + text: "Test response", + }, + ], + })); + + expect(mcpServer['_registeredTools']['test']).toBeDefined(); + + // Now delete the tool + mcpServer.removeTool("test"); + + expect(mcpServer['_registeredTools']['test']).toBeUndefined(); + }); + /*** * Test: Tool Registration with Parameters */ diff --git a/src/server/mcp.ts b/src/server/mcp.ts index cef1722d6..f7de13aa6 100644 --- a/src/server/mcp.ts +++ b/src/server/mcp.ts @@ -816,6 +816,17 @@ export class McpServer { ); } + /** + * Removes a tool from the server by name. + * Does nothing if the tool is not registered. + */ + removeTool(name: string) { + const tool = this._registeredTools[name]; + if (tool) { + tool.update({ name: null }); + } + }; + /** * Registers a zero-argument prompt `name`, which will run the given function when the client calls it. */ From e6219bb77f8231f69099b497c75f4f5b846bebfd Mon Sep 17 00:00:00 2001 From: ChipGPT Date: Sun, 5 Oct 2025 13:48:59 -0500 Subject: [PATCH 2/4] tool management via server instance --- src/server/mcp.test.ts | 36 +++++++++++++---- src/server/mcp.ts | 87 ++++++++++++++++++++++++++++++------------ 2 files changed, 90 insertions(+), 33 deletions(-) diff --git a/src/server/mcp.test.ts b/src/server/mcp.test.ts index 6a989f54f..ce36bff5e 100644 --- a/src/server/mcp.test.ts +++ b/src/server/mcp.test.ts @@ -506,9 +506,9 @@ describe('tool()', () => { }); /*** - * Test: Tool self removal + * Test: Tool disable, enable, and remove via tool instance */ - test("should remove tool when using tool.remove()", async () => { + test("should manage tool when using tool instance", async () => { const mcpServer = new McpServer({ name: "test server", version: "1.0", @@ -524,18 +524,28 @@ describe('tool()', () => { ], })); - expect(mcpServer['_registeredTools']['test']).toBeDefined(); + expect(mcpServer['_registeredTools'].test).toBeDefined(); + + // Now disable the tool + tool.disable(); + + expect(mcpServer['_registeredTools'].test.enabled).toBe(false); + + // Now enable the tool + tool.enable(); + + expect(mcpServer['_registeredTools'].test.enabled).toBe(true); // Now delete the tool tool.remove(); - expect(mcpServer['_registeredTools']['test']).toBeUndefined(); + expect(mcpServer['_registeredTools'].test).toBeUndefined(); }); /*** - * Test: Tool server removal + * Test: Tool disable, enable, and remove via server instance */ - test("should remove tool when using server.removeTool(...)", async () => { + test("should manage tool when using server instance", async () => { const mcpServer = new McpServer({ name: "test server", version: "1.0", @@ -551,12 +561,22 @@ describe('tool()', () => { ], })); - expect(mcpServer['_registeredTools']['test']).toBeDefined(); + expect(mcpServer['_registeredTools'].test).toBeDefined(); + + // Now disable the tool + mcpServer.disableTool("test"); + + expect(mcpServer['_registeredTools'].test.enabled).toBe(false); + + // Now enable the tool + mcpServer.enableTool("test"); + + expect(mcpServer['_registeredTools'].test.enabled).toBe(true); // Now delete the tool mcpServer.removeTool("test"); - expect(mcpServer['_registeredTools']['test']).toBeUndefined(); + expect(mcpServer['_registeredTools'].test).toBeUndefined(); }); /*** diff --git a/src/server/mcp.ts b/src/server/mcp.ts index f7de13aa6..ebd2d5d01 100644 --- a/src/server/mcp.ts +++ b/src/server/mcp.ts @@ -816,15 +816,48 @@ export class McpServer { ); } + /** + * Enables a tool from the server by name. + * Does nothing if the tool is not registered. + */ + enableTool(name: string) { + const tool = this._registeredTools[name]; + if (tool) { + tool.enable(); + } + }; + + /** + * Disables a tool from the server by name. + * Does nothing if the tool is not registered. + */ + disableTool(name: string) { + const tool = this._registeredTools[name]; + if (tool) { + tool.disable(); + } + }; + + /** + * Updates a tool from the server by name. + * Does nothing if the tool is not registered. + */ + updateTool(name: string, updates: ToolUpdates) { + const tool = this._registeredTools[name]; + if (tool) { + tool.update(updates); + } + }; + /** * Removes a tool from the server by name. * Does nothing if the tool is not registered. */ removeTool(name: string) { - const tool = this._registeredTools[name]; - if (tool) { + const tool = this._registeredTools[name]; + if (tool) { tool.update({ name: null }); - } + } }; /** @@ -1029,29 +1062,33 @@ export type ToolCallback = Arg ) => CallToolResult | Promise : (extra: RequestHandlerExtra) => CallToolResult | Promise; +export type ToolUpdates = { + name?: string | null, + title?: string, + description?: string, + paramsSchema?: InputArgs, + outputSchema?: OutputArgs, + annotations?: ToolAnnotations, + _meta?: Record, + callback?: ToolCallback, + enabled?: boolean +} + export type RegisteredTool = { - title?: string; - description?: string; - inputSchema?: AnyZodObject; - outputSchema?: AnyZodObject; - annotations?: ToolAnnotations; - _meta?: Record; - callback: ToolCallback; - enabled: boolean; - enable(): void; - disable(): void; - update(updates: { - name?: string | null; - title?: string; - description?: string; - paramsSchema?: InputArgs; - outputSchema?: OutputArgs; - annotations?: ToolAnnotations; - _meta?: Record; - callback?: ToolCallback; - enabled?: boolean; - }): void; - remove(): void; + title?: string; + description?: string; + inputSchema?: AnyZodObject; + outputSchema?: AnyZodObject; + annotations?: ToolAnnotations; + _meta?: Record; + callback: ToolCallback; + enabled: boolean; + enable(): void; + disable(): void; + update( + updates: ToolUpdates + ): void + remove(): void }; const EMPTY_OBJECT_JSON_SCHEMA = { From 49cab34e46aa533dfa8ca85404fd37b5d66b6ae4 Mon Sep 17 00:00:00 2001 From: ChipGPT Date: Sun, 5 Oct 2025 16:06:37 -0500 Subject: [PATCH 3/4] fix tabs --- src/server/mcp.test.ts | 124 ++++++++++++++++++++--------------------- src/server/mcp.ts | 78 +++++++++++++------------- 2 files changed, 101 insertions(+), 101 deletions(-) diff --git a/src/server/mcp.test.ts b/src/server/mcp.test.ts index ce36bff5e..60e65970c 100644 --- a/src/server/mcp.test.ts +++ b/src/server/mcp.test.ts @@ -509,74 +509,74 @@ describe('tool()', () => { * Test: Tool disable, enable, and remove via tool instance */ test("should manage tool when using tool instance", async () => { - const mcpServer = new McpServer({ - name: "test server", - version: "1.0", - }); - - // Register initial tool - const tool = mcpServer.tool("test", async () => ({ - content: [ - { - type: "text", - text: "Test response", - }, - ], - })); - - expect(mcpServer['_registeredTools'].test).toBeDefined(); - - // Now disable the tool - tool.disable(); - - expect(mcpServer['_registeredTools'].test.enabled).toBe(false); - - // Now enable the tool - tool.enable(); - - expect(mcpServer['_registeredTools'].test.enabled).toBe(true); - - // Now delete the tool - tool.remove(); - - expect(mcpServer['_registeredTools'].test).toBeUndefined(); + const mcpServer = new McpServer({ + name: "test server", + version: "1.0", + }); + + // Register initial tool + const tool = mcpServer.tool('test', async () => ({ + content: [ + { + type: 'text', + text: 'Test response' + } + ] + })); + + expect(mcpServer['_registeredTools'].test).toBeDefined(); + + // Now disable the tool + tool.disable(); + + expect(mcpServer['_registeredTools'].test.enabled).toBe(false); + + // Now enable the tool + tool.enable(); + + expect(mcpServer['_registeredTools'].test.enabled).toBe(true); + + // Now delete the tool + tool.remove(); + + expect(mcpServer['_registeredTools'].test).toBeUndefined(); }); /*** * Test: Tool disable, enable, and remove via server instance */ test("should manage tool when using server instance", async () => { - const mcpServer = new McpServer({ - name: "test server", - version: "1.0", - }); - - // Register initial tool - mcpServer.tool("test", async () => ({ - content: [ - { - type: "text", - text: "Test response", - }, - ], - })); - - expect(mcpServer['_registeredTools'].test).toBeDefined(); - - // Now disable the tool - mcpServer.disableTool("test"); - - expect(mcpServer['_registeredTools'].test.enabled).toBe(false); - - // Now enable the tool - mcpServer.enableTool("test"); - - expect(mcpServer['_registeredTools'].test.enabled).toBe(true); - - // Now delete the tool - mcpServer.removeTool("test"); - - expect(mcpServer['_registeredTools'].test).toBeUndefined(); + const mcpServer = new McpServer({ + name: "test server", + version: "1.0", + }); + + // Register initial tool + mcpServer.tool('test', async () => ({ + content: [ + { + type: 'text', + text: 'Test response' + } + ] + })); + + expect(mcpServer['_registeredTools'].test).toBeDefined(); + + // Now disable the tool + mcpServer.disableTool("test"); + + expect(mcpServer['_registeredTools'].test.enabled).toBe(false); + + // Now enable the tool + mcpServer.enableTool("test"); + + expect(mcpServer['_registeredTools'].test.enabled).toBe(true); + + // Now delete the tool + mcpServer.removeTool("test"); + + expect(mcpServer['_registeredTools'].test).toBeUndefined(); }); /*** diff --git a/src/server/mcp.ts b/src/server/mcp.ts index ebd2d5d01..e77ee62b5 100644 --- a/src/server/mcp.ts +++ b/src/server/mcp.ts @@ -821,10 +821,10 @@ export class McpServer { * Does nothing if the tool is not registered. */ enableTool(name: string) { - const tool = this._registeredTools[name]; - if (tool) { - tool.enable(); - } + const tool = this._registeredTools[name]; + if (tool) { + tool.enable(); + } }; /** @@ -832,10 +832,10 @@ export class McpServer { * Does nothing if the tool is not registered. */ disableTool(name: string) { - const tool = this._registeredTools[name]; - if (tool) { - tool.disable(); - } + const tool = this._registeredTools[name]; + if (tool) { + tool.disable(); + } }; /** @@ -843,10 +843,10 @@ export class McpServer { * Does nothing if the tool is not registered. */ updateTool(name: string, updates: ToolUpdates) { - const tool = this._registeredTools[name]; - if (tool) { - tool.update(updates); - } + const tool = this._registeredTools[name]; + if (tool) { + tool.update(updates); + } }; /** @@ -854,10 +854,10 @@ export class McpServer { * Does nothing if the tool is not registered. */ removeTool(name: string) { - const tool = this._registeredTools[name]; - if (tool) { - tool.update({ name: null }); - } + const tool = this._registeredTools[name]; + if (tool) { + tool.update({ name: null }); + } }; /** @@ -1063,32 +1063,32 @@ export type ToolCallback = Arg : (extra: RequestHandlerExtra) => CallToolResult | Promise; export type ToolUpdates = { - name?: string | null, - title?: string, - description?: string, - paramsSchema?: InputArgs, - outputSchema?: OutputArgs, - annotations?: ToolAnnotations, - _meta?: Record, - callback?: ToolCallback, - enabled?: boolean + name?: string | null, + title?: string, + description?: string, + paramsSchema?: InputArgs, + outputSchema?: OutputArgs, + annotations?: ToolAnnotations, + _meta?: Record, + callback?: ToolCallback, + enabled?: boolean } export type RegisteredTool = { - title?: string; - description?: string; - inputSchema?: AnyZodObject; - outputSchema?: AnyZodObject; - annotations?: ToolAnnotations; - _meta?: Record; - callback: ToolCallback; - enabled: boolean; - enable(): void; - disable(): void; - update( - updates: ToolUpdates - ): void - remove(): void + title?: string; + description?: string; + inputSchema?: AnyZodObject; + outputSchema?: AnyZodObject; + annotations?: ToolAnnotations; + _meta?: Record; + callback: ToolCallback; + enabled: boolean; + enable(): void; + disable(): void; + update( + updates: ToolUpdates + ): void + remove(): void }; const EMPTY_OBJECT_JSON_SCHEMA = { From 84c8254cff5762854ea2c8e8c9330bdbd697185b Mon Sep 17 00:00:00 2001 From: ChipGPT Date: Sun, 5 Oct 2025 16:08:43 -0500 Subject: [PATCH 4/4] prettier --- src/server/mcp.test.ts | 52 +++++++++++++++++++++--------------------- src/server/mcp.ts | 40 +++++++++++++++----------------- 2 files changed, 45 insertions(+), 47 deletions(-) diff --git a/src/server/mcp.test.ts b/src/server/mcp.test.ts index 60e65970c..0ff01ba0b 100644 --- a/src/server/mcp.test.ts +++ b/src/server/mcp.test.ts @@ -508,12 +508,12 @@ describe('tool()', () => { /*** * Test: Tool disable, enable, and remove via tool instance */ - test("should manage tool when using tool instance", async () => { + test('should manage tool when using tool instance', async () => { const mcpServer = new McpServer({ - name: "test server", - version: "1.0", + name: 'test server', + version: '1.0' }); - + // Register initial tool const tool = mcpServer.tool('test', async () => ({ content: [ @@ -523,34 +523,34 @@ describe('tool()', () => { } ] })); - + expect(mcpServer['_registeredTools'].test).toBeDefined(); - + // Now disable the tool tool.disable(); - + expect(mcpServer['_registeredTools'].test.enabled).toBe(false); - + // Now enable the tool tool.enable(); - + expect(mcpServer['_registeredTools'].test.enabled).toBe(true); - + // Now delete the tool tool.remove(); - + expect(mcpServer['_registeredTools'].test).toBeUndefined(); }); - + /*** * Test: Tool disable, enable, and remove via server instance */ - test("should manage tool when using server instance", async () => { + test('should manage tool when using server instance', async () => { const mcpServer = new McpServer({ - name: "test server", - version: "1.0", + name: 'test server', + version: '1.0' }); - + // Register initial tool mcpServer.tool('test', async () => ({ content: [ @@ -560,22 +560,22 @@ describe('tool()', () => { } ] })); - + expect(mcpServer['_registeredTools'].test).toBeDefined(); - + // Now disable the tool - mcpServer.disableTool("test"); - + mcpServer.disableTool('test'); + expect(mcpServer['_registeredTools'].test.enabled).toBe(false); - + // Now enable the tool - mcpServer.enableTool("test"); - + mcpServer.enableTool('test'); + expect(mcpServer['_registeredTools'].test.enabled).toBe(true); - + // Now delete the tool - mcpServer.removeTool("test"); - + mcpServer.removeTool('test'); + expect(mcpServer['_registeredTools'].test).toBeUndefined(); }); diff --git a/src/server/mcp.ts b/src/server/mcp.ts index e77ee62b5..8b638326b 100644 --- a/src/server/mcp.ts +++ b/src/server/mcp.ts @@ -825,8 +825,8 @@ export class McpServer { if (tool) { tool.enable(); } - }; - + } + /** * Disables a tool from the server by name. * Does nothing if the tool is not registered. @@ -836,8 +836,8 @@ export class McpServer { if (tool) { tool.disable(); } - }; - + } + /** * Updates a tool from the server by name. * Does nothing if the tool is not registered. @@ -847,8 +847,8 @@ export class McpServer { if (tool) { tool.update(updates); } - }; - + } + /** * Removes a tool from the server by name. * Does nothing if the tool is not registered. @@ -858,7 +858,7 @@ export class McpServer { if (tool) { tool.update({ name: null }); } - }; + } /** * Registers a zero-argument prompt `name`, which will run the given function when the client calls it. @@ -1063,16 +1063,16 @@ export type ToolCallback = Arg : (extra: RequestHandlerExtra) => CallToolResult | Promise; export type ToolUpdates = { - name?: string | null, - title?: string, - description?: string, - paramsSchema?: InputArgs, - outputSchema?: OutputArgs, - annotations?: ToolAnnotations, - _meta?: Record, - callback?: ToolCallback, - enabled?: boolean -} + name?: string | null; + title?: string; + description?: string; + paramsSchema?: InputArgs; + outputSchema?: OutputArgs; + annotations?: ToolAnnotations; + _meta?: Record; + callback?: ToolCallback; + enabled?: boolean; +}; export type RegisteredTool = { title?: string; @@ -1085,10 +1085,8 @@ export type RegisteredTool = { enabled: boolean; enable(): void; disable(): void; - update( - updates: ToolUpdates - ): void - remove(): void + update(updates: ToolUpdates): void; + remove(): void; }; const EMPTY_OBJECT_JSON_SCHEMA = {