How Desktop Commander MCP Validates Tool Arguments: Schema Enforcement and Runtime Checks

Desktop Commander MCP validates tool arguments through a layered system combining Zod schema enforcement, unsupported parameter detection, and command block-list validation to ensure only permitted arguments reach each tool while providing clear feedback to the LLM.

Desktop Commander MCP implements a robust validation pipeline for every tool invocation. According to the wonderwhy-er/DesktopCommanderMCP source code, the system combines static type checking through Zod schemas with dynamic runtime inspection to catch malformed or dangerous inputs before execution.

Static Schema Enforcement with Zod

Each tool declares its expected arguments through strict Zod schemas defined in src/tools/schemas.ts. This file exports toolArgSchemas, a mapping from tool names to their corresponding Zod object definitions that specify types, optionality, and default values.

Tool Schema Definitions

For example, the read_file tool schema requires a path string and accepts optional parameters like offset and length (lines 55-66). These schemas enforce type safety at the boundary of each tool call.

Dispatcher Integration

When the dispatcher in src/server.ts receives a tool call, it retrieves the appropriate schema via toolArgSchemas[name] before processing the arguments (around line 1648). The dispatcher checks if the schema exists and proceeds to validate the supplied arguments against it.

Runtime Detection of Unsupported Parameters

Zod silently strips unknown keys by default, which would hide errors from the calling model. To address this, Desktop Commander MCP implements an additional validation layer that detects and reports unsupported arguments.

The detectUnsupportedParams Utility

Located in src/utils/unsupportedParams.ts, the detectUnsupportedParams function inspects the raw arguments object and compares its keys against the schema's shape. The implementation retrieves the object shape from the Zod schema and returns any keys present in the input but absent from the whitelist (lines 45-55):

export function detectUnsupportedParams(args: unknown, schema: unknown): string[] {
    if (!args || typeof args !== 'object' || Array.isArray(args)) return [];
    const shape = getObjectShape(schema);
    if (shape === null) return [];
    const supported = new Set(Object.keys(shape));
    return Object.keys(args as Record<string, unknown>).filter(k => !supported.has(k));
}

This ensures that extraneous parameters are flagged rather than silently ignored.

Warning Generation and Model Feedback

When unsupported parameters are detected, the dispatcher invokes buildUnsupportedParamsWarning to generate a human-readable message. As implemented in src/server.ts (lines 1650-1658), the server prepends this warning to the tool's response content:

const warning = buildUnsupportedParamsWarning(
    name, unsupported, getSupportedParams(argSchema)
);
(result as any).content = [{ type: "text", text: warning }, ...(result as any).content];

This feedback loop informs the LLM exactly which parameters were ignored and lists the supported alternatives, improving subsequent interactions.

Command-Level Security Validation

Beyond structural validation, process-related tools undergo additional security screening. The start_process tool and similar commands use src/command-manager.ts to validate against dangerous operations.

Blocked Command Detection

The validateCommand method (lines 29-52) extracts individual command tokens from the input string—handling quoted strings, subshells, $() expansion, and backticks—and checks them against a user-configurable block list loaded from configManager.getConfig():

async validateCommand(command: string): Promise<boolean> {
    const config = await configManager.getConfig();
    const blockedCommands = config.blockedCommands || [];
    const allCommands = this.extractCommands(command);

    for (const cmd of allCommands) {
        if (blockedCommands.includes(cmd)) return false;
    }
    return true;
}

If any blocked command is detected, the validation fails and the server aborts the call with an error message, preventing execution of prohibited operations.

Practical Validation Examples

Valid Tool Call:

// LLM request
{
  name: "read_file",
  args: { path: "/tmp/report.txt", length: 200 }
}

Result: Zod parses successfully; no warning is appended.

Invalid Extra Argument:

{
  name: "read_file",
  args: { path: "/tmp/report.txt", bogus: "oops" }
}

Result: The response includes a warning: "You sent parameters not supported by this tool, which were ignored: bogus. Supported parameters for read_file: path, isUrl, offset, length, sheet, range, options, origin."

Blocked Command:

{
  name: "start_process",
  args: { command: "sudo rm -rf /", timeout_ms: 5000 }
}

Result: commandManager.validateCommand returns false; the server responds with an error indicating the command is prohibited.

Summary

  • Zod schemas in src/tools/schemas.ts define the structural requirements for every tool's arguments through the exported toolArgSchemas map.
  • The dispatcher in src/server.ts retrieves schemas and orchestrates validation before executing tool logic.
  • Unsupported parameter detection via detectUnsupportedParams in src/utils/unsupportedParams.ts catches extraneous arguments that Zod would otherwise strip silently.
  • Warning injection ensures the LLM receives immediate feedback about ignored parameters, listing supported alternatives.
  • Command validation in src/command-manager.ts provides an additional security layer by parsing command strings and checking against configurable block lists.

Frequently Asked Questions

What happens if I send an unsupported parameter to a Desktop Commander MCP tool?

The detectUnsupportedParams function identifies the extra keys and the server prepends a warning to the response. This message lists the specific unsupported parameters and enumerates the valid options for that tool, allowing the LLM to correct its subsequent request.

How does Desktop Commander MCP prevent dangerous shell commands?

The validateCommand method in src/command-manager.ts parses the command string to extract individual commands (including those inside quotes, subshells, and backticks) and validates them against the blockedCommands list from user configuration. If any blocked command is found, the tool call is rejected before execution.

Where are the Zod schemas for tool arguments defined?

All schemas reside in src/tools/schemas.ts and are exported as toolArgSchemas, which maps tool names to their Zod object definitions. This centralizes type definitions and makes the validation logic in src/server.ts generic and extensible.

Does Desktop Commander MCP strip unknown parameters or reject them?

Zod strips unknown parameters during parsing, but the additional detectUnsupportedParams utility ensures the model is notified. The tool executes with the valid parameters while the response includes a warning about what was ignored, rather than failing the entire request.

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 →