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 like CONFIG_EDITOR_RESOURCE_URI or FILE_PREVIEW_RESOURCE_URI from src/ui/contracts.ts to enable inline previews.
  • annotations: Behavioral hints including readOnlyHint and destructiveHint that 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 the Server class with capabilities for tools, resources, prompts, and logging.
  • Tool registration occurs dynamically in the ListToolsRequestSchema handler (lines ~300-460), which assembles tool arrays with JSON schemas, UI metadata from src/ui/contracts.ts, and annotation hints.
  • Schema definitions are centralized in src/tools/schemas.ts using Zod for type safety and JSON Schema conversion via zodToJsonSchema.
  • Execution dispatch routes calls through the CallToolRequestSchema handler (lines ~1250-1300) to implementation files like src/tools/filesystem.ts, with telemetry tracking via src/utils/trackTools.ts and client-context filtering via shouldIncludeTool.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →