refactor: disable tools instead of not registering them (#2636)

This commit is contained in:
Nikolay Vitkov
2026-09-22 07:34:36 +00:00
committed by GitHub
parent dc9d14dc6f
commit b4554691cf
5 changed files with 24 additions and 28 deletions
+6 -6
View File
@@ -169,7 +169,7 @@ export class ToolHandler {
zod.ZodRawShape,
zod.core.$loose
>;
readonly shouldRegister: boolean;
readonly disabled: boolean;
private readonly disabledReason?: string;
constructor(
@@ -180,7 +180,7 @@ export class ToolHandler {
) {
const {disabled, reason} = getToolStatusInfo(tool, serverArgs);
this.disabledReason = reason;
this.shouldRegister = !(disabled && !serverArgs.viaCli);
this.disabled = disabled && !serverArgs.viaCli;
this.inputSchema = tool.schema;
this.registeredInputSchema = zod.object(this.inputSchema).loose();
@@ -192,7 +192,9 @@ export class ToolHandler {
);
}
async handle(params: Record<string, unknown>): Promise<CallToolResult> {
handle = async (params: Record<string, unknown>): Promise<CallToolResult> => {
using _guard = await this.toolMutex.acquire();
if (this.disabledReason) {
return {
content: [
@@ -222,7 +224,6 @@ export class ToolHandler {
};
}
const guard = await this.toolMutex.acquire();
const startTime = Date.now();
let success = false;
let devToolsData: DevToolsData | undefined;
@@ -329,7 +330,6 @@ export class ToolHandler {
devToolsData,
pageUrl,
});
guard[Symbol.dispose]();
}
}
};
}
+6 -8
View File
@@ -294,21 +294,19 @@ export class McpServer {
this.#toolMutex,
);
if (!toolHandler.shouldRegister) {
return;
}
this.server.registerTool(
const registeredTool = this.server.registerTool(
tool.name,
{
description: tool.description,
inputSchema: toolHandler.registeredInputSchema,
annotations: tool.annotations,
},
async params => {
return await toolHandler.handle(params);
},
toolHandler.handle,
);
if (toolHandler.disabled) {
registeredTool.disable();
}
}
}
+1 -1
View File
@@ -18,7 +18,7 @@ export type {Options as YargsOptions} from 'yargs';
export {default as yargs} from 'yargs';
export {hideBin} from 'yargs/helpers';
export {default as semver} from 'semver';
export {McpServer} from '@modelcontextprotocol/server';
export {McpServer, type RegisteredTool} from '@modelcontextprotocol/server';
export {
StdioServerTransport,
serveStdio,
+1 -3
View File
@@ -56,9 +56,7 @@ export const createTools = (args: ParsedArguments) => {
tools.push(tool(args));
}
tools.sort((a, b) => {
return a.name.localeCompare(b.name);
});
tools.sort((a, b) => a.name.localeCompare(b.name));
return tools;
};
+10 -10
View File
@@ -70,7 +70,7 @@ describe('ToolHandler', () => {
toolMutex,
);
assert.strictEqual(toolHandler.shouldRegister, true);
assert.strictEqual(toolHandler.disabled, false);
await toolHandler.handle({pageId: 1});
assert.strictEqual(mockContext.getPageById.calledOnce, true);
@@ -115,7 +115,7 @@ describe('ToolHandler', () => {
toolMutex,
);
assert.strictEqual(toolHandler.shouldRegister, true);
assert.strictEqual(toolHandler.disabled, false);
await toolHandler.handle({});
assert.strictEqual(mockContext.getSelectedMcpPage.calledOnce, true);
@@ -155,7 +155,7 @@ describe('ToolHandler', () => {
toolMutex,
);
assert.strictEqual(toolHandler.shouldRegister, true);
assert.strictEqual(toolHandler.disabled, false);
const result = await toolHandler.handle({});
assert.strictEqual(mockContext.getDevToolsData.calledOnce, true);
@@ -300,7 +300,7 @@ describe('ToolHandler', () => {
assert.strictEqual(handlerCalled, false);
});
it('sets shouldRegister to false and returns disabled reason when category is disabled', async () => {
it('sets disabled to true and returns disabled reason when category is disabled', async () => {
let handlerCalled = false;
const tool: ToolDefinition = {
name: 'disabled_tool',
@@ -332,7 +332,7 @@ describe('ToolHandler', () => {
toolMutex,
);
assert.strictEqual(toolHandler.shouldRegister, false);
assert.strictEqual(toolHandler.disabled, true);
const result = await toolHandler.handle({});
assert.strictEqual(result.isError, true);
@@ -362,7 +362,7 @@ describe('ToolHandler', () => {
async () => mockContext,
toolMutex,
);
assert.strictEqual(defaultHandler.shouldRegister, true);
assert.strictEqual(defaultHandler.disabled, false);
const disabledServerArgs = parseArguments(
'1.0.0',
@@ -381,7 +381,7 @@ describe('ToolHandler', () => {
async () => mockContext,
toolMutex,
);
assert.strictEqual(disabledHandler.shouldRegister, false);
assert.strictEqual(disabledHandler.disabled, true);
const disabledResult = await disabledHandler.handle({function: '() => 1'});
assert.strictEqual(disabledResult.isError, true);
@@ -409,7 +409,7 @@ describe('ToolHandler', () => {
async () => mockContext,
toolMutex,
);
assert.strictEqual(cliHandler.shouldRegister, true);
assert.strictEqual(cliHandler.disabled, false);
const cliResult = await cliHandler.handle({function: '() => 1'});
assert.strictEqual(cliResult.isError, true);
assert.match(
@@ -439,7 +439,7 @@ describe('ToolHandler', () => {
async () => mockContext,
toolMutex,
);
assert.strictEqual(defaultHandler.shouldRegister, true);
assert.strictEqual(defaultHandler.disabled, false);
const disabledServerArgs = parseArguments(
'1.0.0',
@@ -458,7 +458,7 @@ describe('ToolHandler', () => {
async () => mockContext,
toolMutex,
);
assert.strictEqual(disabledHandler.shouldRegister, false);
assert.strictEqual(disabledHandler.disabled, true);
});
it('validates files specified in verifyFilesSchema and rewrites input with validated paths/URLs', async () => {