# How MCP Server Initialization and Client Negotiation Work in DesktopCommanderMCP

> Explore MCP server initialization and client negotiation in DesktopCommanderMCP. Learn how the server bootstraps, instantiates, and negotiates protocol versions with clients for effective configuration.

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

---

**DesktopCommanderMCP initializes by bootstrapping a larger libuv thread pool, instantiating a Server object with declared capabilities, and negotiating protocol versions through an `initialize` request handler that captures client metadata and configures client-specific tool gating.**

DesktopCommanderMCP exposes filesystem and system commands through the Model Context Protocol (MCP). Understanding MCP server initialization and client negotiation reveals how the codebase manages protocol compatibility, distinguishes local from remote clients, and filters capabilities based on the negotiated context. The process spans environment setup in [`bootstrap.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/bootstrap.ts) and runtime negotiation logic centralized in [`server.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/server.ts).

## Thread-Pool Bootstrap and Environment Setup

Before any MCP traffic flows, the server forces a larger libuv thread pool to prevent filesystem-bound operations from starving concurrent requests. This occurs in [`src/bootstrap.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/bootstrap.ts) (lines 1-23) before other modules load.

```typescript
// src/bootstrap.ts
process.env.UV_THREADPOOL_SIZE = '128';

```

This pre-initialization step ensures that subsequent tool calls—such as recursive directory searches or large file reads—have sufficient threads available in the underlying libuv pool.

## Server Construction and Capability Declaration

The core server object is instantiated from `@modelcontextprotocol/sdk/server` in [`src/server.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/server.ts) (lines 98-103). It receives a static identifier and version:

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

```

At construction time, the server declares empty capability buckets (lines 104-109). Individual handlers populate these buckets later based on the negotiated client context. The module also implements **deferred logging** (lines 82-94), storing early messages in a `deferredMessages` array that flushes only after the client completes initialization.

## Protocol Version Negotiation

The `InitializeRequestSchema` handler (lines 209-271) manages the primary client negotiation sequence. When a client connects, it sends an `initialize` request containing a desired protocol version. The server validates this against `SUPPORTED_PROTOCOL_VERSIONS` and falls back to `LATEST_PROTOCOL_VERSION` if the request is unsupported or absent.

```typescript
server.setRequestHandler(InitializeRequestSchema, async (request) => {
  const requestedVersion = request.params?.protocolVersion;
  const protocolVersion = (requestedVersion && SUPPORTED_PROTOCOL_VERSIONS.includes(requestedVersion))
    ? requestedVersion
    : LATEST_PROTOCOL_VERSION;

  return {
    protocolVersion,
    capabilities: { tools: {}, resources: {}, prompts: {}, logging: {} },
    serverInfo: { name: "desktop-commander", version: VERSION },
  };
});

```

This negotiation ensures backward compatibility while allowing modern clients to leverage newer protocol features.

## Client Metadata Capture and Remote Detection

During initialization, the server extracts `clientInfo` (name and version) from the request parameters and invokes `updateCurrentClient()` (lines 86-106) to merge this into the global `currentClient` state. If the client name changes, the transport layer reconfigures for client-specific behavior.

The server detects remote execution contexts through `isRemoteClientContext` (lines 79-81), which checks:
- The `DC_REMOTE_DEVICE` environment variable
- Known remote client names in the user agent string

Helper functions `setCurrentCallIsRemote` and `setCurrentRemoteClient` export this state (lines 78-80) so that tool handlers can attribute telemetry and adjust behavior for remote sessions.

## Onboarding Logic and Telemetry Emission

For eligible clients—excluding the native DesktopCommander desktop app and remote contexts—the initialize handler runs A/B-tested onboarding logic (lines 21-33 within the handler). It also emits a `run_server_mcp_initialized` telemetry event containing host environment details without collecting personally identifiable information.

This telemetry captures the negotiated protocol version and client type, enabling performance analysis across different host applications.

## Tool Gating and Capability Filtering

After negotiation completes, the server filters available tools based on the client identity. The `shouldIncludeTool` function (lines 84-98) prevents circular dependencies by removing feedback or prompt tools when the client is the DesktopCommander UI itself.

Tool handlers query this filter when responding to `ListToolsRequestSchema`:

```typescript
server.setRequestHandler(ListToolsRequestSchema, async () => {
  const allTools = [
    { name: "execute_command", ... },
    { name: "submit_feedback", ... } // Removed for DesktopCommander UI clients
  ];
  return { tools: allTools.filter(t => shouldIncludeTool(t.name)) };
});

```

## Entry Point and Client Connection Flow

The initialization sequence begins in [`src/index.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/index.ts), which imports the bootstrap module before the server:

```typescript
// src/index.ts
import "./bootstrap";               // Thread pool expansion first
import { server } from "./server";   // Server instantiation second

// Server now listens for MCP connections

```

A connecting client performs negotiation by sending structured parameters:

```typescript
// Client-side pseudo-code
const initResp = await mcpClient.call("initialize", {
  clientInfo: { name: "my-client", version: "1.2.3" },
  protocolVersion: "2024-11-05",
});
// initResp.protocolVersion contains the negotiated version

```

## Summary

- **Pre-initialization**: [`src/bootstrap.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/bootstrap.ts) expands the libuv thread pool via `UV_THREADPOOL_SIZE` before any imports execute (lines 1-23).
- **Server construction**: [`src/server.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/server.ts) instantiates the Server object with static metadata and empty capability buckets (lines 98-109).
- **Version negotiation**: The `InitializeRequestSchema` handler validates requested versions against `SUPPORTED_PROTOCOL_VERSIONS`, defaulting to `LATEST_PROTOCOL_VERSION` if incompatible (lines 209-271).
- **Client context**: `updateCurrentClient` captures metadata and configures transport-specific behavior, while `isRemoteClientContext` detects remote execution via environment variables (lines 79-106).
- **Feature gating**: `shouldIncludeTool` filters the tool manifest post-negotiation to exclude UI-specific tools from incompatible clients (lines 84-98).

## Frequently Asked Questions

### What happens if a client requests an unsupported MCP protocol version?

The server falls back to `LATEST_PROTOCOL_VERSION`. The negotiation logic checks the requested version against `SUPPORTED_PROTOCOL_VERSIONS`, and if the requested version is absent from that array, the server returns its latest supported version to maintain backward compatibility.

### How does DesktopCommanderMCP detect remote vs. local client contexts?

The `isRemoteClientContext` function checks for the `DC_REMOTE_DEVICE` environment variable or known remote client names (lines 79-81). When detected, `setCurrentRemoteClient` configures the transport layer and sets `currentCallIsRemote` to true, enabling telemetry attribution and context-aware tool filtering throughout the session.

### Why does the server defer log messages during initialization?

Early log messages accumulate in the `deferredMessages` array (lines 82-94) because the MCP logging capability is not active until the client completes the `initialize` handshake. Once the client confirms initialization, the server flushes these messages through the established MCP logging channel, ensuring diagnostic data is not lost during startup.

### Which source files contain the core initialization implementation?

The initialization sequence spans [`src/bootstrap.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/bootstrap.ts) (thread-pool setup), [`src/server.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/server.ts) (Server construction, handler registration, and negotiation logic), and [`src/remote-device/desktop-commander-integration.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/remote-device/desktop-commander-integration.ts) (remote context detection). System information gathering for telemetry occurs in [`src/utils/system-info.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/system-info.ts).