Repository navigation
Description
Bug
@modelcontextprotocol/server@2.4.0 declares an ESM entry point in its package.json exports map that is not present in the published tarball. The "." export's import condition points to ./dist/index.mjs, but the 2.4.0 tarball does not contain dist/index.mjs. Any ESM import from the package root therefore fails at runtime with ERR_MODULE_NOT_FOUND.
2.3.1 (the immediately preceding release) ships dist/index.mjs correctly, so this is a packaging regression introduced in 2.4.0.
Package version
@modelcontextprotocol/server@2.4.0 (published 2026-10-23)
- Last known-good:
@modelcontextprotocol/server@2.3.1(published 2026-10-05) — shipsdist/index.mjs. 2.4.0is currently thelatestdist-tag.
Environment
- Node.js v24 (also expected on any pure-ESM consumer;
engines.nodeis>=20). - Reproduced via a transitive consumer (
@smartbear/mcp, which depends on@modelcontextprotocol/node@^2.0.0-beta.5→node@2.1.2, which ESM-imports@modelcontextprotocol/server).
Evidence
1. package.json promises dist/index.mjs (from the published 2.4.0 manifest):
"exports": {
".": {
"import": { "types": "./dist/index.d.mts", "default": "./dist/index.mjs" },
"require": { "types": "./dist/index.d.cts", "default": "./dist/index.cjs" }
}
}
"main": "./dist/index.cjs",
"types": "./dist/index.d.mts",
"type": "module"2. The 2.4.0 tarball does not contain dist/index.mjs.
The dist/ output includes index.cjs and index.mjs.map but no index.mjs. (unpackedSize ≈ 7 MB / 117 files, so this is a partial/regressed build output, not an intentionally slimmed package.)
3. Resulting runtime error:
Error [ERR_MODULE_NOT_FOUND]: Cannot find module '.../node_modules/@modelcontextprotocol/server/dist/index.mjs'
imported by .../node_modules/@modelcontextprotocol/node/dist/index.mjs
4. 2.3.1 is correct — the same dist/index.mjs path resolves to a real file, and downgrading/pinning @modelcontextprotocol/server (and server-legacy) to 2.3.1 fully resolves the error.
Why this looks like a build regression
PR #2405 ("feat(packaging): ship CommonJS builds alongside ESM for v2 packages", merged 2026-07-01) established exactly this dual import→index.mjs / require→index.cjs contract for the server package and verified "all exports / main / types / bin paths resolve to emitted files." The exports map in 2.4.0 is unchanged from that contract — only the emitted index.mjs file went missing, which points at the tsdown build/publish step for 2.4.0 rather than a config change.
Reproduction
# In a type:module project on Node 20+:
npm i @modelcontextprotocol/server@2.4.0
node --input-type=module -e "import('@modelcontextprotocol/server')"
# -> ERR_MODULE_NOT_FOUND: .../dist/index.mjs
# Contrast with the last good release:
npm i @modelcontextprotocol/server@2.3.1
node --input-type=module -e "import('@modelcontextprotocol/server').then(()=>console.log('ok'))"
# -> okExpected
The published 2.4.0 (or a 2.4.1 patch) tarball should include dist/index.mjs so the "." ESM export resolves, matching package.json exports and the behavior of 2.3.1. (Worth checking whether the sibling v2 packages — core, client, server-legacy, the middleware/* adapters — have the same missing-index.mjs regression in 2.4.0, since they share the build pipeline.)
Workaround
Pin @modelcontextprotocol/server and @modelcontextprotocol/server-legacy to 2.3.1 via overrides until a fixed release ships.
Activity
media-ctrl commentedon Nov 9, 2026
The published artifact does not reproduce that for me, so it is worth checking the copy that landed in your tree before treating it as a publish regression.
Measured just now against the registry:
npm pack @modelcontextprotocol/server@2.4.0gives 117 files,unpackedSize7,023,377, and the tarball containspackage/dist/index.mjsat 70,276 bytes, next todist/index.mjs.mapat 165,618 bytes,dist/index.cjs,dist/index.d.mtsanddist/index.d.cts.dist-tags.latest= 2.4.0,dist.integrity=sha512-rgR9yxSaAJ+bcsi/XroT/S2AfPiIWloXAnrdfYSCms9ivVju0ishu/wW0J21Ho6+ZOR1r7RyeRbjiRuF87ix5Q==.So the file is missing after install, not in the artifact. The decisive check is one command in the tree that fails:
and compare it to the
integrityrecorded for that package inpackage-lock.json(or the resolution entry inpnpm-lock.yaml). A mismatch means an incomplete copy was cached somewhere between you and the registry, which is a proxy mirror, a shared store, or a partially written cache entry, andnpm cache clean --forceplus a reinstall fixes it. A match means the package was installed intact and something afterwards removeddist/index.mjs: a postinstall step that prunes.mjsoutput, or a second copy of the package resolved into the same path by a different dependent.Worth ruling both out before a
2.4.1is cut, because pinning to 2.3.1 resolves the symptom either way and would leave the actual cause in place. If the integrity matches,ls node_modules/@modelcontextprotocol/server/dist/plusnpm ls @modelcontextprotocol/serverwould settle which of the two it is.DavidGangel commentedon Nov 10, 2026
Tested again and it turned out it was caused by a wrong npx cache. After deleted the cache and executed again the same action it has started to work and the missing .mjs file was also downloaded.