How to Configure Allowed Directories and Access Restrictions in Desktop Commander MCP

Desktop Commander MCP restricts file-system access through the allowedDirectories array in its server configuration, enforcing path validation before any read or write operation.

The wonderwhy-er/DesktopCommanderMCP repository implements a configurable security sandbox that limits which directories the Model Context Protocol (MCP) server can access. By manipulating the allowedDirectories setting, you can lock down file operations to specific project folders or grant unrestricted system access.

Understanding the Configuration System

The security model centers on the ConfigManager singleton defined in src/config-manager.ts. This module persists server settings to a config.json file and maintains the ServerConfig schema.

According to the source code at lines 9-13, the configuration interface includes an optional allowedDirectories property:

interface ServerConfig {
  allowedDirectories?: string[];
  // ... other settings
}

If the configuration file omits this property, the system initializes an empty array ([]) at line 182, which historically meant no restrictions. However, the filesystem tools implement additional fallback logic for safer defaults.

How Path Validation Works

All file operations route through src/tools/filesystem.ts, which implements a three-stage validation pipeline:

Normalization and Subdirectory Checking

The validatePath() function expands ~ to the user's home directory, resolves absolute paths, and delegates access control to isPathAllowed() (lines 77-95). The validation logic follows these rules:

  • Full access mode: If allowedDirectories contains "/" or is empty, validation short-circuits and grants access.
  • Directory comparison: Each allowed path is normalized (lowercased on Windows, trailing separators stripped) and the target is checked for exact equality or subdirectory membership using startsWith(normalizedAllowedDir + path.sep).
  • Windows drive support: An entry like c: grants access to the entire C: drive.

The getAllowedDirs() function (lines 113-125) retrieves the current array from ConfigManager. If the configuration is missing, it falls back to the user's home directory and persists that default immediately.

To prevent directory traversal attacks via symbolic links, the resolver at lines 58-71 implements a defensive strategy:

  1. Attempt fs.realpath on the target path.
  2. If the target does not exist (ENOENT), resolve the parent directory's real path and re-append the filename.
  3. Validate the final canonical path against the allowed list before any write operation occurs.

This ensures attackers cannot place a symlink inside an allowed directory that points outside the whitelist.

Setting Up Allowed Directories

You can configure restrictions via the JSON config file or programmatically through the ConfigManager API.

Configuration via config.json

Edit the server configuration file to specify absolute paths:

{
  "allowedDirectories": [
    "/home/alice/projects",
    "/var/log/app-data",
    "~/Documents"
  ]
}

Restart the server after modifying this file, or use the web UI component located in src/ui/config-editor/src/app.ts to update settings dynamically.

Programmatic Configuration

Tools and integrations can modify restrictions at runtime using the ConfigManager singleton:

import { configManager } from './config-manager.js';

// Restrict to specific project directories
await configManager.setValue('allowedDirectories', [
  '/home/user/workspace',
  '~/Downloads'
]);

For non-blocking updates that don't await disk persistence:

configManager.setValueNonBlocking('allowedDirectories', ['/tmp/sandbox']);

Granting Full Access

To remove all directory restrictions, set the array to empty or include the root path:

// Method 1: Empty array (no restrictions)
await configManager.setValue('allowedDirectories', []);

// Method 2: Root access (Unix)
await configManager.setValue('allowedDirectories', ['/']);

// Method 3: Full drive access (Windows)
await configManager.setValue('allowedDirectories', ['c:']);

Security Enforcement and Error Handling

When isPathAllowed() returns false, the system throws a validation error at lines 91-100 that includes the configured whitelist for debugging. The error is captured for telemetry via capture('server_path_validation_error', …) before aborting the operation.

You can manually verify path permissions before operations:

import { isPathAllowed } from './tools/filesystem.js';

const permitted = await isPathAllowed('/sensitive/etc/passwd');
if (!permitted) {
  console.error('Access denied: Path outside allowed directories');
  process.exit(1);
}

Summary

  • Desktop Commander MCP uses the allowedDirectories array in config.json to whitelist accessible paths.
  • The ConfigManager singleton handles persistence, while src/tools/filesystem.ts enforces validation through validatePath() and isPathAllowed().
  • Path validation normalizes entries, supports Windows drive letters, and checks for subdirectory membership.
  • Symlink attacks are mitigated by resolving parent directories when targets don't exist.
  • Configure restrictions via JSON, web UI, or programmatically using configManager.setValue().

Frequently Asked Questions

How do I restrict Desktop Commander MCP to a single project folder?

Add the absolute path to your project directory to the allowedDirectories array in config.json. The server will block any file operation outside that directory tree. For example: ["/home/user/myproject"] permits access to /home/user/myproject and all subdirectories, but denies access to /home/user/other.

What happens if I leave allowedDirectories empty?

An empty array historically grants full system access on some versions, but recent implementations in src/tools/filesystem.ts fall back to the user's home directory when the array is undefined or empty. To ensure unrestricted access, explicitly set the array to ["/"] on Unix or ["c:"] on Windows.

No. The validation logic in src/tools/filesystem.ts resolves the canonical path using fs.realpath before checking permissions. If a symlink points outside the allowed directory tree, the resolved path fails the isPathAllowed() check and the operation is aborted with a validation error.

Can I update allowed directories without restarting the server?

Yes. Use configManager.setValue('allowedDirectories', [...]) for synchronous persistence, or setValueNonBlocking() for immediate in-memory updates. The web UI in src/ui/config-editor/src/app.ts also supports live configuration changes without requiring a server restart.

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 →