MCP Security Boundary for Allowed Directories and Terminal Commands in Desktop Commander MCP
The Desktop Commander MCP server implements a dual-layer security boundary using allowedDirectories and blockedCommands whitelists—empty allowedDirectories grants full filesystem access, while blockedCommands prevents specific shell commands from executing.
Desktop Commander MCP is a Model Context Protocol server that exposes filesystem and terminal operations to AI agents. To prevent unauthorized access, the codebase implements a configurable security boundary that restricts which directories can be accessed and which terminal commands can be executed. This article examines the implementation across src/config-field-definitions.ts, src/config-manager.ts, src/tools/filesystem.ts, and src/tools/improved-process-tools.ts to show how whitelist validation works at runtime.
How the Security Boundary Works in Desktop Commander MCP
The security model relies on two independent whitelists defined in src/config-field-definitions.ts. The allowedDirectories array controls filesystem access, while blockedCommands filters shell execution. Both are stored in a centralized configuration managed by src/config-manager.ts and enforced at the tool level.
| Whitelist | Purpose | Default Behavior |
|---|---|---|
allowedDirectories |
Paths that MCP may read, write, or manipulate | Empty array grants full filesystem access |
blockedCommands |
Shell commands that MCP will refuse to execute | Empty array means no commands are blocked |
Configuring Allowed Directories in MCP
Configuration Schema in config-field-definitions.ts
The whitelist structure is defined in src/config-field-definitions.ts lines 16-19. The allowedDirectories field is typed as an array with a descriptive label warning users about the empty array behavior.
// src/config-field-definitions.ts
export const CONFIG_FIELD_DEFINITIONS = {
allowedDirectories: {
label: 'Allowed Folders',
description: 'These are the folders Desktop Commander is allowed to read and edit. … If this list is empty, Desktop Commander can access your entire filesystem.',
valueType: 'array',
},
// ...
} as const;
Default Configuration and Runtime Storage
In src/config-manager.ts line 172, the default configuration initializes allowedDirectories as an empty array. This empty state serves as the fallback that grants unrestricted access.
// src/config-manager.ts
export interface Config {
allowedDirectories?: string[];
// ...
}
export const defaultConfig: Config = {
allowedDirectories: [], // empty → full access
// ...
};
Loading and Caching the Whitelist
When the filesystem tools initialize in src/tools/filesystem.ts lines 110-119, the configuration is read and cached. If the array is missing or invalid, it falls back to an empty array.
// src/tools/filesystem.ts (excerpt)
let allowedDirectories: string[];
if (config.allowedDirectories && Array.isArray(config.allowedDirectories)) {
allowedDirectories = config.allowedDirectories;
} else {
allowedDirectories = []; // fallback → unrestricted
}
await configManager.setValue('allowedDirectories', allowedDirectories);
Path Validation with isPathAllowed in filesystem.ts
The isPathAllowed Implementation
Every filesystem operation calls isPathAllowed (lines 172-209 in src/tools/filesystem.ts) before executing. This function normalizes paths and checks against the whitelist.
// src/tools/filesystem.ts
export async function isPathAllowed(requestedPath: string): Promise<boolean> {
const allowedDirs = await getAllowedDirs();
// Root allowed → everything allowed
if (allowedDirs.includes('/') || allowedDirs.length === 0) return true;
// Normalise & check each whitelist entry
return allowedDirs.some(dir => {
const normalized = normalizePath(dir);
if (requestedPath === normalized) return true; // exact match
if (requestedPath.startsWith(normalized + '/')) return true; // sub‑folder
// Windows drive root handling …
return false;
});
}
Error Handling for Unauthorized Paths
When validation fails at lines 298-303, the user receives a descriptive error:
Path not allowed: /secret/file.txt. Must be within one of these directories: /home/user/project, /tmp
This error bubbles up through all filesystem endpoints including readFile, writeFile, and copyFile.
Blocking Terminal Commands with blockedCommands
Command Validation in improved-process-tools.ts
Terminal security is enforced in src/tools/improved-process-tools.ts at line 123. Before spawning any process, the requested command is checked against the blockedCommands array.
// src/tools/improved-process-tools.ts
if (config.blockedCommands?.includes(parsed.data.command)) {
return {
type: "error",
content: [{ type: "text", text: `Error: Command not allowed: ${parsed.data.command}` }],
};
}
Default Behavior and Security Implications
By default, blockedCommands is empty, meaning no commands are restricted unless explicitly added. This provides a defense-in-depth layer: even if an AI prompt requests a dangerous command like rm -rf /, the execution will be blocked if that command appears in the whitelist.
API Exposure and UI Integration
Server-Side Documentation in server.ts
The HTTP API in src/server.ts (lines 335-340) explicitly documents the security boundary in its OpenAPI description, warning that an empty allowedDirectories array removes all restrictions.
// src/server.ts (excerpt)
// - allowedDirectories (array of paths)
// IMPORTANT: Setting allowedDirectories to an empty array ([]) allows full access
Configuration UI in app.ts
The web interface in src/ui/config-editor/src/app.ts (lines 310-327) displays the current count of allowed folders and blocked commands, enabling users to modify the security boundary without editing configuration files directly.
Practical Implementation Examples
Querying Current Whitelist Settings
import { get_config } from "./config-manager";
async function showWhitelists() {
const cfg = await get_config();
console.log("Allowed directories:", cfg.allowedDirectories ?? []);
console.log("Blocked commands:", cfg.blockedCommands ?? []);
}
showWhitelists();
Reading Files with Directory Validation
import { readFile } from "./tools/filesystem";
async function safeRead(path: string) {
try {
const content = await readFile(path);
console.log(content);
} catch (e) {
console.error("Access denied:", e.message);
}
}
safeRead("/home/user/project/notes.md"); // succeeds if folder is whitelisted
safeRead("/etc/passwd"); // throws if not whitelisted
Attempting Blocked Command Execution
import { runProcess } from "./tools/improved-process-tools";
async function tryRun(cmd: string) {
const result = await runProcess({ command: cmd, args: [] });
console.log(result);
}
tryRun("rm -rf /"); // returns error if "rm" is in blockedCommands
Programmatically Adding Allowed Directories
import { configManager } from "./config-manager";
async function addAllowedDir(dir: string) {
const cfg = await configManager.getConfig();
const dirs = cfg.allowedDirectories ?? [];
dirs.push(dir);
await configManager.setValue("allowedDirectories", dirs);
}
addAllowedDir("/home/user/documents");
Summary
allowedDirectoriesinsrc/config-field-definitions.tsandsrc/config-manager.tsdefines which filesystem paths are accessible—empty array means full access.isPathAllowedinsrc/tools/filesystem.ts(lines 172-209) validates every path before filesystem operations, with clear error messages at lines 298-303.blockedCommandsinsrc/tools/improved-process-tools.ts(line 123) prevents specific shell commands from executing, providing a secondary security layer.- The default configuration grants unrestricted access, requiring explicit user configuration to enable sandboxing.
- All endpoints in
src/server.tsand the UI insrc/ui/config-editor/src/app.tsexpose these settings for runtime adjustment.
Frequently Asked Questions
What happens if allowedDirectories is empty in Desktop Commander MCP?
When allowedDirectories is an empty array, Desktop Commander MCP grants full filesystem access. This default is set in src/config-manager.ts line 172 and enforced by isPathAllowed in src/tools/filesystem.ts, which returns true for any path when the whitelist is empty.
How does Desktop Commander MCP block dangerous terminal commands?
The blockedCommands array in the configuration defines which shell commands are prohibited. In src/tools/improved-process-tools.ts line 123, the code checks if the requested command exists in this array before spawning the process, returning an error if matched.
Can subdirectories access parent directories if only the parent is whitelisted?
No. The isPathAllowed function in src/tools/filesystem.ts uses startsWith(normalized + '/') to validate that requested paths are either exact matches or children of whitelisted directories. Accessing sibling or parent directories of a whitelisted folder is denied.
Where is the security boundary configured in the Desktop Commander MCP codebase?
The security boundary is configured across multiple files: src/config-field-definitions.ts defines the schema, src/config-manager.ts stores the values, src/tools/filesystem.ts enforces directory restrictions, and src/tools/improved-process-tools.ts handles command blocking. The UI in src/ui/config-editor/src/app.ts provides a user-friendly interface for modifications.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →