Skip to content

Make zod types strip instead of passthrough #792

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open

Conversation

ihrpr
Copy link
Contributor

@ihrpr ihrpr commented Jul 20, 2025

Context

This addresses issues raised in:

  • #182 - Type safety concerns
  • #119 - Schema validation issues
  • #612 - Previous attempts at strict types
  • mcp-types - solution using .strict()

The Problem

MCP is an extensible protocol. Servers can add custom fields. But our Zod schemas using .passthrough() were too loose - TypeScript couldn't catch typos or provide good autocomplete.

There solutions with .strict() schemas (see mcp-types), but that breaks when talking to servers with extensions - you get runtime errors for any unknown field.

This PR approach

We now generate a strictTypes.ts file that uses Zod's .strip() method instead of .passthrough() or .strict():

// types.ts (deprecated) - uses .passthrough()
const ToolSchema = z.object({
  name: z.string(),
  description: z.string()
}).passthrough(); // Allows ANY additional fields

// strictTypes.ts (recommended) - uses .strip()
const ToolSchema = z.object({
  name: z.string(),
  description: z.string()
}).strip(); // Removes unknown fields, keeping only validated ones

Benefits

  1. Type Safety: TypeScript only sees the known fields, preventing typos and providing better dev experience
  2. Protocol Compatibility: Unknown fields from extended servers/clients are silently removed, not rejected
  3. Forward Compatibility: Code won't break when servers add new fields in future protocol versions
  4. No Runtime Errors: Unlike .strict(), this approach doesn't throw errors for unknown fields

Example

import { ToolSchema } from "@modelcontextprotocol/sdk/strictTypes.js";

// Server sends a tool with extra fields
const toolData = {
  name: "calculator",
  description: "Performs calculations",
  customField: "extra data", // Non-standard field
  version: "1.0" // Another extension
};

// Parse with strip types
const tool = ToolSchema.parse(toolData);

console.log(tool);
// Output: { name: "calculator", description: "Performs calculations" }
// The extra fields are removed, not rejected

We can't just change it now, we need to wait for the major release v2. But we still can deprecate the types and start using typesafe eversion.

Migration Guide

Example for new projects

Use strictTypes.js by default:

import { ToolSchema, ResourceSchema } from "@modelcontextprotocol/sdk/strictTypes.js";

For Existing Projects

  1. Change your imports from types.js to strictTypes.js
  2. Your code will continue to work, but with better type safety
  3. Any code that relied on additional fields will need to be updated

If You Need Extensibility

If you need to preserve additional fields, you have options:

  1. Continue using types.js (deprecated but still available)
  2. Create your own extended schemas:
    import { ToolSchema } from "@modelcontextprotocol/sdk/strictTypes.js";
    
    const ExtendedToolSchema = ToolSchema.extend({
      myCustomField: z.string()
    });

Implementation Details

The strictTypes.ts file is auto-generated from types.ts by:

  1. Replacing all .passthrough() with .strip()
  2. Keeping specific fields (experimental, _meta, properties) as .passthrough()
  3. Adding appropriate documentation

Until the v2 version, we need to make sure we have backwards compatibility so the generation script runs automatically during the build process to ensure both files stay in sync.

V2 version of the SDK:

  • The types.js file is deprecated and will be removed in a future major version
  • All new code should use strictTypes.js

@ihrpr ihrpr marked this pull request as ready for review July 21, 2025 09:40
@ihrpr ihrpr requested a review from a team as a code owner July 21, 2025 09:40
@punkpeye
Copy link

Amazing change!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants