# How Desktop Commander Server Handles Client Requests and Tool Call Schemas

> Discover how Desktop Commander MCP Server manages client requests and tool call schemas. Learn about its request handling, Zod schema validation, and context separation for seamless execution.

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

---

**The Desktop Commander MCP server uses the Model Context Protocol (MCP) `Server` class to register typed request handlers, validates incoming tool arguments against Zod schemas in [`src/tools/schemas.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/schemas.ts), and dispatches execution through a central `handleCallToolRequest` function that separates local, remote, and UI-origin contexts.**

The Desktop Commander MCP server, available at `wonderwhy-er/DesktopCommanderMCP`, provides a production-ready example of handling client requests and enforcing tool call schemas in TypeScript. Built on the Model Context Protocol (MCP), this implementation demonstrates robust request validation, telemetry separation, and secure command execution across local and remote device contexts.

## Server Bootstrap and MCP Foundation

The server initializes in [`src/server.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/server.ts) by creating an MCP `Server` instance with explicit capabilities:

```typescript
export const server = new Server(
  { name: "desktop-commander", version: VERSION },
  { capabilities: { tools: {}, resources: {}, prompts: {}, logging: {} } },
);

```

This instance exports the server for other modules to register handlers. The capabilities object declares support for tools, resources, prompts, and logging, allowing MCP clients to discover available functionality during initialization.

## Registering Static Request Handlers

The server registers handlers for standard MCP method schemas to serve UI resources and prompts:

**List Resources** returns the available UI resources via `listUiResources()`:

```typescript
server.setRequestHandler(ListResourcesRequestSchema, async () => ({
  resources: listUiResources(),
}));

```

*(lines 14-17 of [`src/server.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/server.ts))*

**Read Resource** loads UI-specific files by URI, throwing errors for unknown resources (lines 20-27). **List Prompts** currently returns an empty array (lines 31-36). These static handlers operate independently of the tool execution pipeline.

## Handling Tool Call Requests

The core request processing logic resides in the `CallToolRequestSchema` handler (lines 44-57 of [`src/server.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/server.ts)):

```typescript
server.setRequestHandler(CallToolRequestSchema, async (request) => {
  const args = request.params.arguments;
  const isUiOriginCall = !!(args && typeof args === 'object' && (args as any).origin === 'ui');
  if (isUiOriginCall) {
    return runInUiOriginCallContext(() => handleCallToolRequest(request));
  }
  return handleCallToolRequest(request);
});

```

This handler detects **UI-origin calls** (where `origin: 'ui'`) and wraps them in `runInUiOriginCallContext`, which suppresses telemetry tracking. All other calls proceed directly to `handleCallToolRequest`.

### The Request Processing Pipeline

Inside `handleCallToolRequest` (starting line 60), the server executes a strict validation and dispatch sequence:

1. **Extract parameters**: `const { name, arguments: args } = request.params;`
2. **Remote attribution**: Detects `_meta.remote` and `_meta.clientInfo` to set `currentCallIsRemote` and `currentRemoteClient` (lines 70-92)
3. **Tool-specific telemetry**: For example, logging `set_config_value_key_name` when processing the `set_config_value` tool (lines 99-102)
4. **History tracking**: `trackToolCall(name, args)` persists the call to the tool-history store (lines 114-115)
5. **Dispatch**: A `switch (name)` statement routes to concrete implementations like `getConfig()` or `start_process` (lines 120-130)

If any handler throws, the server captures the error via `capture('server_request_error', ...)` and returns a structured error response, ensuring the MCP client always receives a well-formed `ServerResult`.

## Tool Call Schema Validation

All tool arguments are strictly validated using **Zod** schemas defined in [`src/tools/schemas.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/schemas.ts). Each schema describes the shape, defaults, and allowed values for a specific tool.

For example, the **StartProcess** tool schema (lines 27-35):

```typescript
export const StartProcessArgsSchema = z.object({
  command: z.string(),
  timeout_ms: z.number(),
  shell: z.string().optional(),
  verbose_timing: z.boolean().optional(),
  origin: z.enum(['ui', 'llm']).optional(),
});

```

The server maintains a `toolArgSchemas` lookup map (lines 49-78) that associates each tool name with its validator:

```typescript
export const toolArgSchemas: Record<string, z.ZodTypeAny> = {
  get_config: GetConfigArgsSchema,
  set_config_value: SetConfigValueArgsSchema,
  start_process: StartProcessArgsSchema,
  // ... all other tools
};

```

When processing a `CallTool` request, the server looks up the schema by name, parses `request.params.arguments` against it, and either returns a validation error or passes the parsed arguments to the tool implementation.

## Remote Device Context and Telemetry Separation

The server supports remote device operation via the `DC_REMOTE_DEVICE` environment variable. When a tool call contains `_meta.remote`, the handler marks the call as remote using `setCurrentCallIsRemote(true)` and stores originating client information via `setCurrentRemoteClient`. This separation ensures that telemetry for remote clients does not contaminate the local device's `currentClient` state.

## Complete Request Flow

The request lifecycle follows this architecture:

```

Client → (MCP) → Server
   │
   ├─ InitializeRequest → server sets clientInfo, returns capabilities
   ├─ ListResources/ReadResource/ListPrompts → static UI handlers
   └─ CallToolRequest
        │
        ├─ UI-origin? → runInUiOriginCallContext (telemetry suppressed)
        │
        └─ Remote? → setCurrentCallIsRemote / setCurrentRemoteClient
        │
        ├─ Validate args against toolArgSchemas
        ├─ Track tool call (toolHistory)
        └─ Dispatch via switch → concrete implementation
            → result (or captured error) returned to client

```

## Summary

- The server instantiates an MCP `Server` in [`src/server.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/server.ts) with capabilities for tools, resources, prompts, and logging
- Static handlers manage UI resources and prompts, while dynamic tool calls route through `handleCallToolRequest`
- **Zod schemas** in [`src/tools/schemas.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/schemas.ts) provide strict validation via the `toolArgSchemas` map
- UI-origin calls (marked with `origin: 'ui'`) execute inside `runInUiOriginCallContext` to suppress telemetry
- Remote calls identified via `_meta.remote` trigger separate state tracking to prevent client information bleeding
- All errors are captured and returned as well-formed `ServerResult` objects to maintain protocol compliance

## Frequently Asked Questions

### What is the Model Context Protocol (MCP) used in Desktop Commander?

The Model Context Protocol (MCP) is an open protocol that enables AI systems to interact with external tools and resources through a standardized interface. Desktop Commander implements an MCP server that exposes filesystem operations, process management, and configuration tools, allowing AI clients to discover and invoke these capabilities via JSON-RPC messages.

### How does Desktop Commander validate tool arguments before execution?

The server validates all tool arguments against **Zod** schemas defined in [`src/tools/schemas.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/schemas.ts). Each tool has a corresponding entry in the `toolArgSchemas` record map. When a `CallTool` request arrives, the server looks up the schema by tool name and parses the arguments; if validation fails, it returns an error before the tool implementation executes.

### What is the difference between UI-origin and LLM-origin tool calls?

UI-origin calls include `origin: 'ui'` in their arguments and are wrapped in `runInUiOriginCallContext`, which suppresses telemetry tracking to avoid logging internal UI operations. LLM-origin calls (or calls without an origin flag) proceed through standard telemetry and tracking via `trackToolCall`, allowing the server to maintain a history of AI-initiated actions for the `get_recent_tool_calls` feature.

### How does the server handle errors from tool execution?

Errors are captured in the `handleCallToolRequest` function using `capture('server_request_error', ...)` and converted into structured error responses. This ensures that even when a tool handler throws, the MCP client receives a valid `ServerResult` object rather than an unhandled exception, maintaining protocol stability and providing actionable error information.