From 7ef8b56eace1ac92e7b1b0b96451bf76931e6c79 Mon Sep 17 00:00:00 2001 From: ChipGPT Date: Thu, 2 Oct 2025 11:06:33 -0500 Subject: [PATCH 1/5] 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 7dc4742e6..0407721ab 100644 --- a/src/server/mcp.test.ts +++ b/src/server/mcp.test.ts @@ -1961,6 +1961,60 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { // Clean up spies warnSpy.mockRestore(); }); + + /*** + * 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(); + }); }); describe('resource()', () => { diff --git a/src/server/mcp.ts b/src/server/mcp.ts index 1617dc37b..3c52a1719 100644 --- a/src/server/mcp.ts +++ b/src/server/mcp.ts @@ -1061,6 +1061,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. * @deprecated Use `registerPrompt` instead. From 2223eb76dce10217af6648d89f2fbdc1a804858d Mon Sep 17 00:00:00 2001 From: ChipGPT Date: Sun, 5 Oct 2025 13:48:59 -0500 Subject: [PATCH 2/5] tool management via server instance --- src/server/mcp.test.ts | 36 +++++++++++++++++++------ src/server/mcp.ts | 61 +++++++++++++++++++++++++++++++++--------- 2 files changed, 77 insertions(+), 20 deletions(-) diff --git a/src/server/mcp.test.ts b/src/server/mcp.test.ts index 0407721ab..b40ffadb1 100644 --- a/src/server/mcp.test.ts +++ b/src/server/mcp.test.ts @@ -1963,9 +1963,9 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { }); /*** - * 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", @@ -1981,18 +1981,28 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { ], })); - 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", @@ -2008,12 +2018,22 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { ], })); - 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 3c52a1719..cbb0a9c9c 100644 --- a/src/server/mcp.ts +++ b/src/server/mcp.ts @@ -1061,6 +1061,39 @@ 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. @@ -1068,7 +1101,7 @@ export class McpServer { removeTool(name: string) { const tool = this._registeredTools[name]; if (tool) { - tool.update({ name: null }); + tool.update({ name: null }); } }; @@ -1292,6 +1325,18 @@ export type ToolCallback = ToolCallback | ToolTaskHandler; +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; @@ -1304,17 +1349,9 @@ export type RegisteredTool = { 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; + update( + updates: ToolUpdates + ): void remove(): void; }; From 89759829019fa470ebb1f9705a39f3b1a8e7fad0 Mon Sep 17 00:00:00 2001 From: ChipGPT Date: Sun, 5 Oct 2025 16:06:37 -0500 Subject: [PATCH 3/5] fix tabs --- src/server/mcp.test.ts | 124 ++++++++++++++++++++--------------------- src/server/mcp.ts | 24 ++++---- 2 files changed, 74 insertions(+), 74 deletions(-) diff --git a/src/server/mcp.test.ts b/src/server/mcp.test.ts index b40ffadb1..0f58031fd 100644 --- a/src/server/mcp.test.ts +++ b/src/server/mcp.test.ts @@ -1966,74 +1966,74 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { * 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 cbb0a9c9c..d0ae80dac 100644 --- a/src/server/mcp.ts +++ b/src/server/mcp.ts @@ -1066,10 +1066,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(); + } }; /** @@ -1077,10 +1077,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(); + } }; /** @@ -1088,10 +1088,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); + } }; /** From 705b4f0d91f52a2ff5177055da6806f47db97993 Mon Sep 17 00:00:00 2001 From: ChipGPT Date: Sun, 5 Oct 2025 16:08:43 -0500 Subject: [PATCH 4/5] prettier --- src/server/mcp.test.ts | 52 +++++++++++++++++++++--------------------- src/server/mcp.ts | 25 ++++++++++---------- 2 files changed, 39 insertions(+), 38 deletions(-) diff --git a/src/server/mcp.test.ts b/src/server/mcp.test.ts index 0f58031fd..0653f63c8 100644 --- a/src/server/mcp.test.ts +++ b/src/server/mcp.test.ts @@ -1965,12 +1965,12 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { /*** * 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: [ @@ -1980,34 +1980,34 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { } ] })); - + 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: [ @@ -2017,22 +2017,22 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => { } ] })); - + 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 d0ae80dac..0f6c01e70 100644 --- a/src/server/mcp.ts +++ b/src/server/mcp.ts @@ -1070,8 +1070,8 @@ export class McpServer { if (tool) { tool.enable(); } - }; - + } + /** * Disables a tool from the server by name. * Does nothing if the tool is not registered. @@ -1081,19 +1081,22 @@ export class McpServer { 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) { + 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. @@ -1103,7 +1106,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. @@ -1335,7 +1338,7 @@ export type ToolUpdates; callback?: ToolCallback; enabled?: boolean; -} +}; export type RegisteredTool = { title?: string; @@ -1349,9 +1352,7 @@ export type RegisteredTool = { enabled: boolean; enable(): void; disable(): void; - update( - updates: ToolUpdates - ): void + update(updates: ToolUpdates): void; remove(): void; }; From 03faee37dbb932b3129d1aa6364f0be3662ae529 Mon Sep 17 00:00:00 2001 From: ChipGPT Date: Thu, 4 Dec 2025 15:21:51 -0600 Subject: [PATCH 5/5] use .remove() function --- src/server/mcp.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/mcp.ts b/src/server/mcp.ts index 0f6c01e70..002a7615b 100644 --- a/src/server/mcp.ts +++ b/src/server/mcp.ts @@ -1104,7 +1104,7 @@ export class McpServer { removeTool(name: string) { const tool = this._registeredTools[name]; if (tool) { - tool.update({ name: null }); + tool.remove(); } }