How MCP Clients Configure the Desktop Commander Server: Claude Desktop and Cursor Integration

Different MCP clients configure the Desktop Commander server by sending client metadata through the InitializeRequest payload and optionally setting the DC_REMOTE_DEVICE environment variable, enabling the server to customize onboarding flows, tool availability, and telemetry collection for each client type.

The DesktopCommanderMCP repository implements a Model Context Protocol (MCP) server that dynamically adapts its behavior based on client identity. Whether connecting through Claude Desktop, Cursor, or the native Desktop Commander application, the server uses specific handshake protocols and environment flags to determine which features to expose.

Client Identification via InitializeRequest

The server captures client identity in src/server.ts through the MCP protocol's initialization handshake. When any client connects, it transmits a clientInfo object containing name and version fields within the InitializeRequest parameters.

The server stores this information using updateCurrentClient (lines 186-194) and references it throughout the session to drive behavior:

// src/server.ts – InitializeRequest handler
server.setRequestHandler(InitializeRequestSchema, async (request) => {
  const clientInfo = request.params?.clientInfo;
  if (clientInfo) {
    await updateCurrentClient(clientInfo);  // Stores name/version in currentClient
  }
  // ... initialization continues
});

Clients like Claude Desktop and Claude Code identify themselves with names such as "claude-code" or "claude-desktop", while the native Desktop Commander app uses "desktop-commander-app" or "desktop-commander".

Remote vs. Local Client Configuration

The DC_REMOTE_DEVICE Environment Variable

Remote clients—including Cursor and Claude Desktop integrations—configure the server through environment variables before the MCP handshake begins. The DesktopCommanderIntegration wrapper in src/remote-device/desktop-commander-integration.ts spawns the server process with DC_REMOTE_DEVICE=true:

// src/remote-device/desktop-commander-integration.ts
this.mcpTransport = new StdioClientTransport({
  ...config,
  env: { ...getDefaultEnvironment(), ...config.env, DC_REMOTE_DEVICE: 'true' }
});

this.mcpClient = new Client(
  { name: "desktop-commander-client", version: "1.0.0" },
  { capabilities: {} }
);

The server detects remote contexts using isRemoteClientContext (lines 79-81), which checks both the environment variable and the client name:

// src/server.ts
function isRemoteClientContext(clientName?: string): boolean {
  return process.env.DC_REMOTE_DEVICE === 'true' ||
         clientName === 'desktop-commander-client';
}

Separate State Tracking

When operating in remote mode, the server maintains two distinct client states: currentClient (from the InitializeRequest) and currentRemoteClient (set via setCurrentRemoteClient at lines 169-171). This dual tracking allows the server to distinguish between the wrapper application and the underlying AI agent.

Feature Gating and Behavior Customization

Onboarding Page Eligibility

The server conditionally displays welcome pages based on client identity. In the InitializeRequest handler (lines 21-27), the code checks currentClient.name against a whitelist and the remote context status:

// src/server.ts – Onboarding logic
const isWelcomePageEligibleClient =
  currentClient.name !== 'desktop-commander-app' &&
  currentClient.name !== 'desktop-commander' &&
  !isRemoteClientContext(currentClient.name) &&
  !(global as any).disableOnboarding;

if (isWelcomePageEligibleClient) {
  await handleWelcomePageOnboarding(currentClient.name);
} else {
  await skipWelcomePageOnboarding();
}

This ensures that third-party clients like Claude Desktop receive onboarding guidance, while the native Desktop Commander app and remote wrappers skip redundant UI flows.

Tool Availability Filtering

The shouldIncludeTool function (lines 84-92) consults currentClient.name to hide meta-tools from the native UI that would be redundant or confusing:

// src/server.ts – Tool gating logic
function shouldIncludeTool(toolName: string): boolean {
  if (currentClient?.name === 'desktop-commander-app') {
    if (toolName === 'give_feedback_to_desktop_commander' ||
        toolName === 'get_prompts') {
      return false;
    }
  }
  return true;
}

Docker-Specific Configuration

Client-specific feature suppression extends to Docker environments. In src/utils/dockerPrompt.ts (lines 14-15), the server checks for clientInfo.name === "docker" to determine whether to display Docker-specific prompts.

Telemetry and Analytics Integration

The server embeds client identity into analytics events through src/utils/capture.ts (lines 5-9). Each captured event includes metadata distinguishing between local and remote clients:

// src/utils/capture.ts – Metadata resolution
const metadata = {
  host_entrypoint: currentClient?.name,
  host_agent: currentRemoteClient?.name,
  host_plugin_id: process.env.DC_REMOTE_DEVICE === 'true' ? 'remote' : 'local'
};

This allows the analytics pipeline to differentiate usage patterns between Claude Desktop, Cursor, Claude Code CLI, and native Desktop Commander sessions.

Summary

  • Client identification occurs through the InitializeRequest payload's clientInfo field, parsed in src/server.ts and stored via updateCurrentClient.
  • Remote client signaling uses the DC_REMOTE_DEVICE=true environment variable, set by wrappers like DesktopCommanderIntegration for Cursor and Claude Desktop.
  • Onboarding control depends on whitelist checks against currentClient.name, suppressing welcome pages for native and remote contexts.
  • Tool gating is implemented in shouldIncludeTool, which filters the available tool list based on whether the client is the native Desktop Commander app.
  • Telemetry differentiation captures both currentClient and currentRemoteClient to track which specific MCP client initiated each session.

Frequently Asked Questions

How does Cursor identify itself to the Desktop Commander server?

Cursor connects through the DesktopCommanderIntegration wrapper, which sets DC_REMOTE_DEVICE=true and sends clientInfo: { name: "desktop-commander-client", version: "1.0.0" } in the InitializeRequest. The underlying Claude agent then sends its own identification (e.g., "claude-code") as the currentClient, allowing the server to distinguish between the wrapper and the AI agent.

What environment variable signals a remote MCP client connection?

The DC_REMOTE_DEVICE environment variable must be set to 'true'. This flag is checked by isRemoteClientContext in src/server.ts and triggers remote-specific behavior including separate client tracking and suppression of local-only UI components.

Why does the Desktop Commander server hide certain tools from specific clients?

The server uses the shouldIncludeTool function to filter meta-tools like give_feedback_to_desktop_commander when currentClient.name equals "desktop-commander-app". This prevents the native UI from exposing tools that would create circular references or redundant functionality within the Desktop Commander application itself.

How can I verify which client is currently connected to the server?

Check the currentClient object populated in src/server.ts after the InitializeRequest handshake. For remote connections, also inspect currentRemoteClient and the DC_REMOTE_DEVICE environment variable. These values are logged in telemetry events via src/utils/capture.ts and can be accessed programmatically to conditionally enable features based on client capabilities.

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 →