MCP Server Definition and Tool Registration in DesktopCommanderMCP
The DesktopCommanderMCP server is instantiated in src/server.ts with capabilities for tools, resources, and logging, while dynamic tool registration occurs in the ListToolsRequestSchema handler that assembles tool definitions with Zod schemas, UI metadata, and annotations into a capabilities array.
The DesktopCommanderMCP repository implements a Model-Context-Protocol (MCP) server that exposes filesystem operations, process management, and configuration editing to AI clients. Understanding the MCP server definition and tool registration flow is essential for developers extending the server's functionality or debugging capability advertisement issues.
MCP Server Definition and Capabilities
The server instance is created in src/server.ts (lines 98-104) using the MCP SDK Server class:
export const server = new Server(
{
name: "desktop-commander",
version: VERSION,
},
{
capabilities: {
tools: {},
resources: {},
prompts: {},
logging: {},
},
},
);
This definition establishes the server identity and advertises dynamic tool support, resource handling (for UI previews), and logging capabilities to connecting clients. The empty objects ({}) indicate that these capabilities are populated dynamically at runtime rather than being statically defined.
How Tools Are Registered
Tool registration in DesktopCommanderMCP follows a three-phase architecture: schema definition, capability advertisement via the list tools handler, and execution dispatch.
Schema Definition in schemas.ts
Tool argument schemas are centralized in src/tools/schemas.ts using Zod for runtime type safety:
export const ReadFileArgsSchema = z.object({
path: z.string(),
encoding: z.string().optional(),
});
export const StartProcessArgsSchema = z.object({
command: z.string(),
cwd: z.string().optional(),
});
These schemas are converted to JSON Schema at registration time using zodToJsonSchema for MCP protocol compliance.
The ListToolsRequest Handler
The ListToolsRequestSchema handler (lines ~300-460 in src/server.ts) constructs the tools array dynamically by mapping schema definitions to tool descriptors:
server.setRequestHandler(ListToolsRequestSchema, async () => {
const allTools = [
{
name: "read_file",
description: "Read the contents of a file...",
inputSchema: zodToJsonSchema(ReadFileArgsSchema),
_meta: buildUiToolMeta(FILE_PREVIEW_RESOURCE_URI, false, showMcpUiPreviews),
annotations: {
title: "Read File",
readOnlyHint: true
},
},
{
name: "get_config",
description: "Retrieve current configuration...",
inputSchema: zodToJsonSchema(GetConfigArgsSchema),
_meta: buildUiToolMeta(CONFIG_EDITOR_RESOURCE_URI, true, showMcpUiPreviews),
annotations: { title: "Get Configuration", readOnlyHint: true },
},
// ... filesystem, process, and editing tools
];
return {
tools: allTools.filter(tool => shouldIncludeTool(tool, clientInfo))
};
});
Each tool definition contains:
- name: The unique identifier used by clients in tool calls.
- description: A human-readable explanation of the tool's purpose.
- inputSchema: The JSON Schema generated from Zod definitions for argument validation.
- _meta: UI metadata constructed via
buildUiToolMeta, referencing resource URIs likeCONFIG_EDITOR_RESOURCE_URIorFILE_PREVIEW_RESOURCE_URIfromsrc/ui/contracts.tsto enable inline previews. - annotations: Behavioral hints including
readOnlyHintanddestructiveHintthat guide client UI decisions.
Tool Filtering by Client Context
The shouldIncludeTool helper filters the complete tool array based on the connecting client's identity. For example, it removes the give_feedback_to_desktop_commander tool when the client is the DesktopCommander application itself, preventing self-referential feedback loops.
Tool Execution Dispatch
When clients invoke tools, the CallToolRequestSchema handler (lines ~1250-1300 in src/server.ts) manages execution flow:
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
// Set remote call tracking for telemetry
setCurrentCallIsRemote(true);
setCurrentRemoteClient(clientInfo);
// Route to concrete implementation
switch (name) {
case "read_file":
return await handleReadFile(args);
case "start_process":
return await handleStartProcess(args);
// Additional tool implementations...
default:
throw new Error(`Unknown tool: ${name}`);
}
});
The handler imports concrete implementations from src/tools/filesystem.ts, src/tools/improved-process-tools.ts, and other tool modules. It leverages src/utils/trackTools.ts for telemetry logging via setCurrentCallIsRemote and setCurrentRemoteClient before invoking the business logic.
Adding a New Tool: Practical Example
To extend the server with a custom tool, implement the following three steps:
1. Define the Zod schema in src/tools/schemas.ts:
export const AnalyzeDirectoryArgsSchema = z.object({
path: z.string(),
includeHidden: z.boolean().optional(),
});
2. Implement the handler in src/tools/analysis.ts:
export async function analyzeDirectory(
args: z.infer<typeof AnalyzeDirectoryArgsSchema>
) {
// Implementation logic
return {
content: [{ type: "text", text: "Analysis complete" }]
};
}
3. Register in the tools array in src/server.ts:
{
name: "analyze_directory",
description: "Analyze directory structure and return statistics...",
inputSchema: zodToJsonSchema(AnalyzeDirectoryArgsSchema),
_meta: buildUiToolMeta(FILE_PREVIEW_RESOURCE_URI, false, showMcpUiPreviews),
annotations: {
title: "Analyze Directory",
readOnlyHint: true
},
}
Summary
- The MCP server definition resides in
src/server.ts(lines 98-104), instantiating theServerclass with capabilities for tools, resources, prompts, and logging. - Tool registration occurs dynamically in the
ListToolsRequestSchemahandler (lines ~300-460), which assembles tool arrays with JSON schemas, UI metadata fromsrc/ui/contracts.ts, and annotation hints. - Schema definitions are centralized in
src/tools/schemas.tsusing Zod for type safety and JSON Schema conversion viazodToJsonSchema. - Execution dispatch routes calls through the
CallToolRequestSchemahandler (lines ~1250-1300) to implementation files likesrc/tools/filesystem.ts, with telemetry tracking viasrc/utils/trackTools.tsand client-context filtering viashouldIncludeTool.
Frequently Asked Questions
Where is the MCP server defined in DesktopCommanderMCP?
The server is defined in src/server.ts at lines 98-104, where the Server class from the MCP SDK is instantiated with server metadata and capability flags for tools, resources, and logging.
How does the server advertise available tools to clients?
The server advertises tools through the ListToolsRequestSchema request handler (lines ~300-460), which returns a dynamically constructed array containing tool names, descriptions, Zod-generated input schemas, and metadata annotations that inform the client's UI rendering.
What determines which tools appear in the tool list?
The shouldIncludeTool helper function filters the complete tool array based on client context, removing client-specific tools like give_feedback_to_desktop_commander when the client is the DesktopCommander application itself to prevent feedback loops.
How are tool arguments validated?
Arguments are validated against Zod schemas defined in src/tools/schemas.ts, which are converted to JSON Schema using zodToJsonSchema and attached to each tool definition in the inputSchema field; the MCP client validates incoming calls against these schemas before the CallToolRequestSchema handler executes the implementation.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →