# MCP Server Input Validation Patterns: Python and Node.js Implementation Guide

> Learn MCP server input validation patterns using Python Pydantic v2 and Node.js Zod. Prevent errors, generate OpenAPI schemas, and ensure data integrity.

- Repository: [Composio/awesome-claude-skills](https://github.com/composiohq/awesome-claude-skills)
- Tags: how-to-guide
- Published: 2026-07-24

---

**MCP servers use Pydantic v2 for Python and Zod for Node/TypeScript to enforce strict input validation, prevent malformed data from reaching tool handlers, and automatically generate OpenAPI-compatible schemas.**

The ComposioHQ/awesome-claude-skills repository establishes canonical patterns for validating LLM-driven tool calls in Model Context Protocol (MCP) servers. These validation strategies ensure that only properly formatted data reaches your business logic while providing clear error messages back to the calling LLM.

## Why Input Validation Matters for MCP Servers

MCP servers act as bridges between LLMs and external tools, making input validation a critical security and reliability layer. Without strict validation, malformed inputs can crash handlers, leak sensitive data, or trigger unexpected side effects. The reference implementations in [`mcp-builder/reference/python_mcp_server.md`](https://github.com/ComposioHQ/awesome-claude-skills/blob/main/mcp-builder/reference/python_mcp_server.md) and [`mcp-builder/reference/node_mcp_server.md`](https://github.com/ComposioHQ/awesome-claude-skills/blob/main/mcp-builder/reference/node_mcp_server.md) demonstrate how to reject unknown fields, enforce type constraints, and sanitize inputs before processing.

## Python Validation Pattern with Pydantic

Python MCP servers leverage **Pydantic v2** models to define tool inputs. FastMCP automatically derives the `inputSchema` from these models, creating an OpenAPI-compatible specification that clients use to format requests.

### Configuring BaseModel for Strict Validation

According to the Python MCP Server Guide, validation models should use `ConfigDict` with three critical settings: `str_strip_whitespace=True` to auto-trim strings, `validate_assignment=True` to re-validate on field updates, and `extra='forbid'` to reject unknown parameters.

```python
from pydantic import BaseModel, Field, ConfigDict, field_validator

class ServiceToolInput(BaseModel):
    """Input model for a service-tool operation."""
    model_config = ConfigDict(
        str_strip_whitespace=True,
        validate_assignment=True,
        extra='forbid'
    )

```

### Field Constraints and Custom Validators

Use `Field` parameters to enforce length limits, numeric ranges, and collection sizes. For complex validation logic, implement `@field_validator` methods as shown in [`mcp-builder/reference/python_mcp_server.md`](https://github.com/ComposioHQ/awesome-claude-skills/blob/main/mcp-builder/reference/python_mcp_server.md):

```python
    param1: str = Field(
        ...,
        description="First parameter (e.g. user ID)",
        min_length=1,
        max_length=100
    )
    param2: int | None = Field(
        default=None,
        description="Optional integer",
        ge=0,
        le=1000
    )
    tags: list[str] = Field(
        default_factory=list,
        description="List of tags",
        max_items=10
    )

    @field_validator('param1')
    @classmethod
    def non_empty(cls, v: str) -> str:
        if not v.strip():
            raise ValueError("param1 cannot be empty")
        return v

```

When you type a tool parameter with `ServiceToolInput`, FastMCP automatically generates the JSON Schema from the Pydantic model definition.

## Node/TypeScript Validation Pattern with Zod

Node.js and TypeScript implementations use **Zod** for runtime type checking. Unlike Pydantic, which generates schemas from types, Zod requires explicit schema construction that doubles as both validator and type definition.

### Creating Strict Schemas

The Node MCP Server Guide recommends chaining `.strict()` to `z.object()` to forbid unknown properties. Each field uses Zod primitives like `z.string()`, `z.number()`, or `z.nativeEnum()` with constraints attached via `.min()`, `.max()`, and `.describe()`:

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

const UserSearchInputSchema = z.object({
  query: z.string()
    .min(2, "Query must be at least 2 characters")
    .max(200, "Query must not exceed 200 characters")
    .describe("Search string to match against names/emails"),
  limit: z.number()
    .int()
    .min(1)
    .max(100)
    .default(20)
    .describe("Maximum results to return"),
  offset: z.number()
    .int()
    .min(0)
    .default(0)
    .describe("Number of results to skip for pagination"),
  response_format: z.nativeEnum(ResponseFormat)
    .default(ResponseFormat.MARKDOWN)
    .describe("Output format: markdown or json")
}).strict();

```

### Registering Tools with Input Validation

Pass the Zod schema as the `inputSchema` property when calling `server.registerTool()` in [`mcp-builder/reference/node_mcp_server.md`](https://github.com/ComposioHQ/awesome-claude-skills/blob/main/mcp-builder/reference/node_mcp_server.md). The framework validates inputs against this schema before invoking your handler:

```typescript
server.registerTool(
  "search_users",
  {
    inputSchema: UserSearchInputSchema,
    // ... other tool config
  },
  async (params) => {
    // params is guaranteed to match UserSearchInputSchema
  }
);

```

## Common Validation Principles Across Languages

Both the Python and Node.js patterns share four fundamental principles that ensure robust MCP server implementations:

- **Explicit field definitions** – Every expected argument must be declared with specific types and constraints.
- **Constraint enforcement** – Apply minimum/maximum values, regex patterns, and enum restrictions at the schema level.
- **Strict mode activation** – Use `extra='forbid'` in Pydantic or `.strict()` in Zod to reject unexpected parameters.
- **Consistent output** – Validated inputs guarantee that downstream code receives correctly typed data, eliminating defensive null checks and type coercion.

## Summary

- **Pydantic v2** provides Python MCP servers with declarative validation through `BaseModel`, `Field` constraints, and `@field_validator` decorators, with FastMCP automatically extracting the `inputSchema`.
- **Zod** enables TypeScript servers to define strict runtime schemas using `z.object().strict()` and chainable validation methods, explicitly passing the schema to `server.registerTool()`.
- Both approaches require `extra='forbid'` or `.strict()` to prevent parameter injection attacks.
- Validation occurs before handler execution, ensuring that business logic only processes sanitized, type-safe data.
- The ComposioHQ/awesome-claude-skills reference files provide production-ready templates for implementing these patterns.

## Frequently Asked Questions

### What happens if an MCP server receives invalid input?

When validation fails, the MCP framework returns a structured error to the calling LLM before executing the tool handler. In Python, Pydantic raises a `ValidationError` with detailed field-level messages. In Node.js, Zod throws a `ZodError` containing the specific constraint violations. These errors help the LLM correct its parameters in subsequent calls.

### Can MCP servers use alternative validation libraries?

While the ComposioHQ/awesome-claude-skills repository standardizes on Pydantic v2 for Python and Zod for TypeScript, you can technically use alternatives like `msgspec` or `valibot`. However, FastMCP's automatic `inputSchema` generation specifically targets Pydantic models, and the reference architecture in [`mcp-builder/reference/node_mcp_server.md`](https://github.com/ComposioHQ/awesome-claude-skills/blob/main/mcp-builder/reference/node_mcp_server.md) assumes Zod for TypeScript type inference.

### How do validation patterns affect the MCP tool's JSON Schema?

The `inputSchema` sent to MCP clients directly reflects your validation constraints. Pydantic generates JSON Schema properties from `Field` parameters like `min_length` and `ge`, while Zod's `.describe()` and constraint methods populate the schema's `description`, `minimum`, and `maximum` fields. This ensures LLMs receive accurate documentation about parameter requirements.

### Should MCP servers validate outputs as well as inputs?

Input validation remains the priority for MCP servers since they receive untrusted data from external LLMs. However, output validation using the same libraries (Pydantic or Zod) can ensure your tool responses conform to expected structures before serialization, particularly when returning complex objects to the client.