# How the Request Schema is Defined and Validated Using Zod in the MCP Tool

> Learn how the MCP tool uses Zod schemas to define and validate request shapes at runtime. Ensure data integrity and efficient request processing.

- Repository: [Kevin Kern/deepwiki-mcp](https://github.com/regenrek/deepwiki-mcp)
- Tags: deep-dive
- Published: 2026-02-16

---

**The deepwiki-mcp repository uses Zod schemas in [`src/schemas/deepwiki.ts`](https://github.com/regenrek/deepwiki-mcp/blob/main/src/schemas/deepwiki.ts) to declaratively define request shapes, then validates incoming tool calls at runtime using `safeParse` before processing them.**

The **Model Context Protocol (MCP)** tools in the `regenrek/deepwiki-mcp` repository rely on **Zod** to enforce type safety and data integrity. By defining the request schema using Zod, the codebase ensures that every incoming tool request matches the expected structure before any business logic executes.

## Defining the Zod Request Schema in deepwiki-mcp

All request schemas reside in [`src/schemas/deepwiki.ts`](https://github.com/regenrek/deepwiki-mcp/blob/main/src/schemas/deepwiki.ts), where they combine TypeScript type inference with runtime validation constraints.

### Core FetchRequest Schema

The primary `FetchRequest` schema defines the contract for the `deepwiki_fetch` tool:

```typescript
// src/schemas/deepwiki.ts
export const ModeEnum = z.enum(['aggregate', 'pages'])

export const FetchRequest = z.object({
  /** Deepwiki repo URL, eg https://deepwiki.com/user/repo */
  url: z.string()
    .describe('URL, owner/repo, two‑word form, or a keyword'),
  /** Crawl depth limit: 0 = only root page */
  maxDepth: z.number().int().min(0).max(1).default(1)
    .describe('maxDepth 0 → single site, 1 → all sites'),
  /** Conversion mode */
  mode: ModeEnum.default('aggregate'),
  /** Verbose logging flag */
  verbose: z.boolean().default(false),
})

```

Key constraints include:
- `maxDepth` is restricted to integers between `0` and `1` with a default of `1`
- `mode` must be either `'aggregate'` or `'pages'`
- All fields include `.describe()` metadata for MCP client documentation

### Extending Schemas for Search Functionality

The search tool extends the base schema rather than duplicating it. In [`src/tools/deepwikiSearch.ts`](https://github.com/regenrek/deepwiki-mcp/blob/main/src/tools/deepwikiSearch.ts), the `SearchRequest` inherits from `FetchRequest` and adds search-specific fields:

```typescript
// src/tools/deepwikiSearch.ts
const SearchRequest = FetchRequest.extend({
  /** Case‑insensitive literal search term */
  query: z.string().min(1, 'query cannot be empty'),
  /** Hard cap on snippets to return (default 10) */
  maxMatches: z.number().int().positive().max(100).default(10),
})

```

This pattern ensures that search requests inherit all validation rules from fetch requests (like `maxDepth` constraints) while adding their own specific requirements, such as `query` being a non-empty string.

## Runtime Validation with Zod safeParse

Defining the schema is only half the implementation. The tools validate every incoming request at runtime using Zod's `safeParse` method.

### Normalizing Input Before Validation

In [`src/tools/deepwiki.ts`](https://github.com/regenrek/deepwiki-mcp/blob/main/src/tools/deepwiki.ts), the implementation first normalizes the raw input (for example, converting shorthand repository names like `vercel/ai` into full URLs) before passing it to the validator:

```typescript
// src/tools/deepwiki.ts
const normalizedInput = normalizeUrl(input.url) // Custom normalization logic
const parse = FetchRequest.safeParse(normalizedInput)

```

### Handling Validation Errors with ErrorEnvelope

If validation fails, the tool returns a structured error object rather than throwing an unhandled exception. The `ErrorEnvelope` schema (also defined in [`src/schemas/deepwiki.ts`](https://github.com/regenrek/deepwiki-mcp/blob/main/src/schemas/deepwiki.ts)) standardizes error responses:

```typescript
// src/tools/deepwiki.ts
if (!parse.success) {
  const err: z.infer<typeof ErrorEnvelope> = {
    status: 'error',
    code: 'VALIDATION',
    message: 'Request failed schema validation',
    details: parse.error.flatten(), // Structured Zod error details
  }
  return err
}

```

The `parse.error.flatten()` method produces a machine-readable error structure that MCP clients can display to users, showing exactly which fields failed validation and why.

## Registering Validated Tools with the MCP Server

When registering tools with the MCP server, the implementation exposes the schema's shape (not the Zod object itself) so that the protocol can communicate the expected parameters to clients:

```typescript
// src/tools/deepwiki.ts
mcp.tool(
  'deepwiki_fetch',
  'Fetch a deepwiki.com repo and return Markdown',
  FetchRequest.shape,  // Exposes the schema structure to MCP
  async (input) => {
    // Implementation uses safeParse as shown above
  }
)

```

The `FetchRequest.shape` property provides a JSON-serializable description of the schema that MCP clients use to render input forms or validate requests client-side before sending them to the server.

## Summary

- **Schema Location**: All Zod schemas are defined in [`src/schemas/deepwiki.ts`](https://github.com/regenrek/deepwiki-mcp/blob/main/src/schemas/deepwiki.ts), including `FetchRequest`, `SearchRequest`, and `ModeEnum`.
- **Extension Pattern**: The search tool in [`src/tools/deepwikiSearch.ts`](https://github.com/regenrek/deepwiki-mcp/blob/main/src/tools/deepwikiSearch.ts) uses `FetchRequest.extend()` to inherit base validation while adding query-specific fields.
- **Runtime Safety**: Both tools use `safeParse()` to validate normalized input, returning structured `ErrorEnvelope` objects on validation failures rather than throwing exceptions.
- **MCP Integration**: Tools register their schemas using `FetchRequest.shape` to expose parameter requirements to MCP clients, while `.describe()` calls provide human-readable documentation.

## Frequently Asked Questions

### How does the MCP tool handle invalid request parameters?

When a request fails validation, the tool uses Zod's `safeParse` method to catch errors gracefully. Instead of crashing, it returns a structured `ErrorEnvelope` object containing the error code `VALIDATION`, a descriptive message, and detailed field-level errors via `parse.error.flatten()`. This allows MCP clients to display precise feedback about which parameters are invalid and why.

### What is the difference between FetchRequest and SearchRequest schemas?

`FetchRequest` is the base schema defined in [`src/schemas/deepwiki.ts`](https://github.com/regenrek/deepwiki-mcp/blob/main/src/schemas/deepwiki.ts) that handles repository fetching with fields like `url`, `maxDepth`, and `mode`. `SearchRequest` extends this base schema in [`src/tools/deepwikiSearch.ts`](https://github.com/regenrek/deepwiki-mcp/blob/main/src/tools/deepwikiSearch.ts) using Zod's `.extend()` method, adding `query` (a required non-empty string) and `maxMatches` (a positive integer capped at 100). This inheritance ensures search requests maintain all base validation rules while adding search-specific constraints.

### Why does the tool use safeParse instead of parse?

The implementation chooses `safeParse` over `parse` to avoid throwing exceptions during request handling. Since MCP tools must return structured responses that clients can process programmatically, throwing would break the protocol contract. `safeParse` returns a discriminated union that allows the tool to check `parse.success` and, if false, construct a proper `ErrorEnvelope` response with validation details. This approach maintains stability and provides actionable error information to API consumers.

### Where are the default values for request parameters defined?

Default values are declared directly in the Zod schema definitions within [`src/schemas/deepwiki.ts`](https://github.com/regenrek/deepwiki-mcp/blob/main/src/schemas/deepwiki.ts). For example, `maxDepth` uses `.default(1)` to default to crawling all sites, `mode` defaults to `'aggregate'` via `ModeEnum.default('aggregate')`, and `verbose` defaults to `false`. These defaults are applied automatically by Zod during the `safeParse` call, ensuring that omitted fields receive sensible values before the tool logic executes.