# MCP Server Definition and Tool Registration in DesktopCommanderMCP

> Explore the MCP server definition in DesktopCommanderMCP and understand how tools are dynamically registered using Zod schemas and UI metadata within the ListToolsRequestSchema handler.

- Repository: [Eduard Ruzga/DesktopCommanderMCP](https://github.com/wonderwhy-er/DesktopCommanderMCP)
- Tags: architecture
- Published: 2026-07-19

---

**The DesktopCommanderMCP server is instantiated in [`src/server.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/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`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/server.ts) (lines 98-104) using the MCP SDK `Server` class:

```typescript
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`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/schemas.ts) using Zod for runtime type safety:

```typescript
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`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/server.ts)) constructs the tools array dynamically by mapping schema definitions to tool descriptors:

```typescript
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`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/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`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/server.ts)) manages execution flow:

```typescript
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`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/filesystem.ts), [`src/tools/improved-process-tools.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/improved-process-tools.ts), and other tool modules. It leverages [`src/utils/trackTools.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/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`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/schemas.ts):

```typescript
export const AnalyzeDirectoryArgsSchema = z.object({
  path: z.string(),
  includeHidden: z.boolean().optional(),
});

```

**2. Implement the handler** in [`src/tools/analysis.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/analysis.ts):

```typescript
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`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/server.ts):

```typescript
{
  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`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/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`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/ui/contracts.ts), and annotation hints.
- **Schema definitions** are centralized in [`src/tools/schemas.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/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`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/filesystem.ts), with telemetry tracking via [`src/utils/trackTools.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/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`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/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`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/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.