Skip to content

@modelcontextprotocol/ext-apps consumers ship ~140K of unused zod v4 locale files in browser bundles #665

@les2

Description

@les2

I discovered while developing an mcp-app using the sdk (client side only) that the bundle contained all of zod's locales because of a start import that prevented vite's / rolldown's tree-shaking from working.

I was able to work around this by developing (with the help of AI) a little vite plugin to strip it:

// Zod v4 re-exports every locale via `export * as locales` from its classic
// entrypoint, which defeats tree-shaking when the MCP SDK imports `* as z from
// 'zod/v4'`. Replace the locales index with an `en`-only stub so the namespace
// still exists but the other ~50 locale files never enter the graph.
const zodLocalesEnOnly = {
  name: "zod-locales-en-only",
  enforce: "pre",
  load(id) {
    if (/[\\/]zod[\\/](?:v4[\\/])?locales[\\/]index\.js$/.test(id)) {
      return 'export { default as en } from "./en.js";';
    }
    return null;
  },
};

See https://github.com/les2/mcp-ext-apps-zod-locale-bloat for a minimal demonstration of the issue.

Below is an AI issue description:

@modelcontextprotocol/ext-apps consumers ship ~140K of unused zod v4 locale files in browser bundles

Summary

Any browser app that depends on @modelcontextprotocol/ext-apps (and therefore on @modelcontextprotocol/sdk) bundles all ~50 zod v4 locale files — Spanish, French, German, Japanese, Chinese, Korean, Russian, etc. — because of a tree-shaking dead-end in the transitive zod chain. On our widget (Ember + Vite + Rollup) this was ~140K of dead weight, ~20% of the final bundle.

The end result is that every browser bundle currently ships translated error strings like 数値過大:期望, Trop court, demasiado corto, zu kurz — none of which are ever displayed, since the SDK only uses zod's English error messages at runtime.

A minimal reproduction is available at https://github.com/les2/mcp-ext-apps-zod-locale-bloatnpm install && npm run compare builds twice (without and with the workaround) and prints the size delta.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions