# How DesktopCommanderMCP Implements the MCP Protocol Handshake During Initialization

> Learn how DesktopCommanderMCP implements the MCP protocol handshake. Discover version negotiation, client metadata capture, and capability descriptors for successful session establishment.

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

---

**TLDR:** The Desktop Commander server implements the MCP protocol handshake in [`src/server.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/server.ts) by registering an initialize request handler that negotiates protocol versions, captures client metadata, and returns capability descriptors to establish the client-server session.

The DesktopCommanderMCP repository provides a Model Context Protocol (MCP) server that enables desktop automation through a standardized JSON-RPC interface. Understanding how this server handles the **MCP protocol handshake** during initialization is critical for developers building compatible clients or debugging connection issues. The handshake implementation follows the official MCP specification by processing initialize requests in [`src/server.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/server.ts), where it validates client information and negotiates mutually supported protocol versions.

## Step-by-Step Handshake Implementation in src/server.ts

The initialization sequence spans lines 209–268 in [`src/server.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/server.ts), following the official MCP specification for server initialization.

### Server Instantiation and SDK Setup

The process begins at lines 98–103 where the server constructs a new `Server` instance imported from `@modelcontextprotocol/sdk`. The constructor receives the plugin identifier and the `VERSION` constant defined in [`src/version.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/version.ts), establishing the server's identity before any client connects.

### Registering the Initialize Request Handler

At lines 209–264, the server registers the core handshake logic using `server.setRequestHandler(InitializeRequestSchema, async (request) => { ... })`. This method binds the initialization logic to the MCP `initialize` method, which clients must call immediately after establishing a transport connection.

### Client Identity Extraction and Onboarding

Upon receiving the initialize request, the handler extracts `clientInfo` from `request.params?.clientInfo` (lines 211–215) and persists it via `updateCurrentClient`. This captures the caller's name and version for telemetry and feature-flag decisions.

Between lines 216–226, the server conditionally triggers `handleWelcomePageOnboarding` if the client is not the Desktop Commander app itself or a remote-device wrapper. This ensures first-time users see the welcome interface without interfering with programmatic clients.

### Telemetry and Environment Capture

At lines 238–243, the server records initialization telemetry using `capture('run_server_mcp_initialized', ...)`, logging environment variables such as entrypoint, agent, and plugin ID. This analytics call excludes PII while providing diagnostic context for server usage patterns.

### Protocol Version Negotiation

The critical version negotiation occurs at lines 245–250. The server inspects `request.params?.protocolVersion` and validates it against the `SUPPORTED_PROTOCOL_VERSIONS` array. If the requested version is supported, the server adopts it; otherwise, it falls back to `LATEST_PROTOCOL_VERSION`. This ensures backward compatibility while allowing modern clients to leverage newer protocol features.

### Returning the Handshake Payload

Lines 252–264 construct and return the handshake response object containing:

- **protocolVersion**: The agreed-upon version string
- **capabilities**: An object declaring support for `tools`, `resources`, `prompts`, and `logging` (currently empty objects serving as placeholders for future extensions)
- **serverInfo**: An object with `name: "desktop-commander"` and `version` set to the `VERSION` constant

### Error Handling and Logging

The handler wraps all logic in a try-catch block at lines 265–268. Any exceptions are logged to stderr and re-thrown, ensuring the MCP SDK transmits an appropriate error response to the client rather than failing silently.

## Key Source Files and Dependencies

The handshake implementation relies on several files within the repository:

- **[`src/server.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/server.ts)** – Contains the `Server` instantiation and the initialize request handler (lines 209–268)
- **[`src/version.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/version.ts)** – Exports the `VERSION` constant used in the handshake response
- **[`src/utils/system-info.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/system-info.ts)** – Gathers system information referenced during the onboarding phase
- **[`package.json`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/package.json)** – Declares `@modelcontextprotocol/sdk` as the core dependency providing the `Server` class and `InitializeRequestSchema`

## Practical Implementation Examples

The following examples demonstrate the handshake from both client and server perspectives.

### Client-Side Initialization

```typescript
import { ServerClient } from "@modelcontextprotocol/sdk/client";

const client = new ServerClient({
  url: "http://localhost:PORT",
  name: "my-app",
  version: "1.2.3",
});

const initResponse = await client.initialize({
  clientInfo: { name: "my-app", version: "1.2.3" },
  protocolVersion: "1.0",
});

console.log(initResponse.protocolVersion);
console.log(initResponse.serverInfo);

```

### Server-Side Handler

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

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

```

## Summary

- The **MCP protocol handshake** is implemented in [`src/server.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/server.ts) using the `@modelcontextprotocol/sdk` package
- The server registers a handler for `InitializeRequestSchema` at lines 209–264 to process incoming initialization requests
- Client identity is captured via `updateCurrentClient` and stored for telemetry and feature detection
- Protocol version negotiation checks `SUPPORTED_PROTOCOL_VERSIONS` and falls back to `LATEST_PROTOCOL_VERSION` if needed
- The handshake response includes the agreed protocol version, empty capability placeholders, and server metadata
- Errors during initialization are logged to stderr and re-thrown to ensure proper error propagation to the client

## Frequently Asked Questions

### Where is the MCP protocol handshake implemented in DesktopCommanderMCP?

The handshake logic is implemented in **[`src/server.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/server.ts)** between lines 209 and 268. This file contains the `setRequestHandler` call for `InitializeRequestSchema` that processes the initial client request and returns the protocol configuration.

### How does the server handle protocol version mismatches during the handshake?

The server checks the requested protocol version against `SUPPORTED_PROTOCOL_VERSIONS` at lines 245–250. If the client requests a version not in the supported list, the server automatically falls back to `LATEST_PROTOCOL_VERSION`, ensuring the connection succeeds while maintaining compatibility.

### What information does the server capture during initialization?

The server captures `clientInfo` (name and version) via `updateCurrentClient` and records telemetry using `capture('run_server_mcp_initialized', ...)` with environment variables like entrypoint and agent. This data is used for analytics and conditional onboarding flows, but excludes personally identifiable information.

### What capabilities does the server advertise during the MCP handshake?

The server returns an empty object for each capability type—**tools**, **resources**, **prompts**, and **logging**—at lines 252–264. These serve as placeholders indicating protocol support while the actual capability implementations are registered separately after the handshake completes.