# How Zod Schemas Are Converted to MCP Tool Definitions in DesktopCommanderMCP

> Discover how DesktopCommanderMCP converts Zod schemas to MCP tool definitions using zodToJsonSchema for seamless argument schema integration. Learn the process today.

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

---

**DesktopCommanderMCP converts Zod schemas to MCP tool definitions by mapping each tool's argument schema in [`src/server.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/server.ts) and transforming them into JSON Schema using the `zodToJsonSchema` function from the `zod-to-json-schema` library, which is then attached as the `inputSchema` field in tool definitions sent to clients.**

The DesktopCommanderMCP repository implements a type-safe pipeline for defining tool arguments using **Zod** schemas located in [`src/tools/schemas.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/schemas.ts). When the MCP server initializes and prepares tool definitions for client consumption, these TypeScript-first schemas are dynamically converted into standard JSON Schema format that any MCP-compatible client can parse for validation, form generation, or LLM prompt engineering.

## The Zod Schema Definition Layer

All argument validation schemas are centralized in [`src/tools/schemas.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/schemas.ts). Each tool exports a Zod object schema that defines required parameters, optional fields, default values, and type constraints. This file serves as the single source of truth for both runtime validation and schema documentation.

### Defining Arguments in schemas.ts

The repository defines schemas using standard Zod object constructors. For example, the `read_file` tool uses the following schema definition:

```typescript
import { z } from "zod";

export const ReadFileArgsSchema = z.object({
  path: z.string(),
  isUrl: z.boolean().optional().default(false),
  offset: z.number().optional().default(0),
  length: z.number().optional().default(1000),
  sheet: z.string().optional(),
  range: z.string().optional(),
  options: z.record(z.any()).optional(),
  origin: z.enum(['ui', 'llm']).optional(),
});

```

This schema enforces that `path` is a required string while providing sensible defaults for pagination parameters like `offset` and `length`.

## Mapping Schemas to Tool Names

The conversion process relies on a registry called `toolArgSchemas` that is imported into [`src/server.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/server.ts) from the schemas module. This object maps string tool names to their corresponding Zod schema objects, creating a lookup table that the server uses during tool registration.

When the server prepares its tool list for the `list_tools` RPC response, it iterates through the available tool implementations and retrieves the matching Zod schema from this registry. This decouples the validation logic from the tool implementation while maintaining type safety.

## Converting to JSON Schema for MCP Clients

MCP clients expect tool argument specifications in JSON Schema format rather than Zod objects. The conversion happens during server initialization when constructing the tool definition array.

### Using zodToJsonSchema

The server imports the `zodToJsonSchema` function from the `zod-to-json-schema` package to handle the transformation. This utility converts Zod object schemas into valid JSON Schema (Draft 7 or 2019-09) while preserving type information, required field arrays, and default values.

### Attaching inputSchema to Tool Definitions

The resulting JSON Schema object is assigned to the `inputSchema` property of each tool definition. This standardized field name is part of the MCP protocol specification, allowing clients to understand exactly what arguments each tool expects without needing to parse TypeScript or Zod-specific syntax.

```typescript
import { toolArgSchemas } from "./tools/schemas.js";
import { zodToJsonSchema } from "zod-to-json-schema";

// Constructing tool definitions for list_tools response
const allTools = Object.entries(toolImpls).map(([name, impl]) => ({
  name,
  description: impl.description,
  inputSchema: zodToJsonSchema(toolArgSchemas[name]),
}));

```

## Complete Example: From Zod to Client Response

Consider the complete flow for the `read_file` tool. First, the Zod schema is defined in [`src/tools/schemas.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/schemas.ts) as shown above. When the server starts, it processes this schema through the conversion pipeline:

```typescript
// Server-side conversion (src/server.ts)
const toolDefinition = {
  name: "read_file",
  description: "Read a file from the filesystem",
  inputSchema: zodToJsonSchema(ReadFileArgsSchema)
};

```

The resulting JSON Schema sent to the client looks like this:

```json
{
  "name": "read_file",
  "description": "Read a file from the filesystem",
  "inputSchema": {
    "type": "object",
    "properties": {
      "path": { "type": "string" },
      "isUrl": { "type": "boolean", "default": false },
      "offset": { "type": "number", "default": 0 },
      "length": { "type": "number", "default": 1000 },
      "sheet": { "type": "string" },
      "range": { "type": "string" },
      "options": { "type": "object", "additionalProperties": true },
      "origin": { "type": "string", "enum": ["ui", "llm"] }
    },
    "required": ["path"]
  }
}

```

This JSON Schema preserves the optional flags, default values, and enum constraints defined in the original Zod schema, enabling clients to generate accurate UI forms or validation logic.

## Summary

- **Zod schemas** are defined in [`src/tools/schemas.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/schemas.ts) to provide TypeScript-first argument validation with automatic type inference.
- The **`toolArgSchemas`** registry in [`src/server.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/server.ts) maps each tool name to its corresponding Zod schema object.
- **`zodToJsonSchema`** converts Zod definitions to standard JSON Schema format during server initialization, preserving types, defaults, and constraints.
- Converted schemas are attached to the **`inputSchema`** field in tool definitions returned by the `list_tools` RPC method.
- MCP clients receive standard JSON Schema compatible with form generators, validation libraries, and LLM function-calling specifications.

## Frequently Asked Questions

### What library does DesktopCommanderMCP use to convert Zod schemas to JSON Schema?

DesktopCommanderMCP uses the **`zod-to-json-schema`** npm package. The server imports the `zodToJsonSchema` function in [`src/server.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/server.ts) and calls it for each tool schema when constructing the tool list for MCP clients.

### Where are the Zod schemas for tool arguments defined?

All argument schemas are defined and exported from **[`src/tools/schemas.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/schemas.ts)**. Each tool has a corresponding Zod object schema (such as `ReadFileArgsSchema` or `EditBlockArgsSchema`) that validates incoming arguments before the tool logic executes.

### How does the MCP client receive the schema information?

The client receives schemas through the **`inputSchema`** field in each tool definition during the `list_tools` RPC call. This field contains the JSON Schema representation derived from the original Zod schema, allowing clients to understand expected parameters without accessing the server's TypeScript code.

### Are optional fields and default values preserved in the conversion?

Yes, the `zodToJsonSchema` function preserves Zod-specific metadata including **optional fields**, **default values**, and **enum constraints**. The resulting JSON Schema accurately reflects the intended argument structure, enabling clients to pre-populate forms with default values or mark fields as optional in the UI.