Skip to content

Fix example servers crashing at startup on Node older than 20.11 - #787

Merged
ochafik merged 1 commit into
mainfrom
ochafik/pdf-server-node-floor
Sep 23, 2026
Merged

ochafik merged 1 commit into
mainfrom
ochafik/pdf-server-node-floor

Conversation

@ochafik

@ochafik ochafik commented Sep 23, 2026

Copy link
Copy Markdown
Contributor

Summary

The example servers compute their dist directory from import.meta.filename / import.meta.dirname, which only exist from Node 20.11. On Node 18.x and 20.0 to 20.10 the module throws at load, before the server can answer initialize:

TypeError: Cannot read properties of undefined (reading 'endsWith')

This affects the published packages, including @modelcontextprotocol/server-pdf 1.7.5 and 2.0.0, while the README and quickstart say Node 20+ is supported.

Changes

  • 21 example servers (examples/*/server.ts): derive the path from import.meta.url with fileURLToPath, the idiom examples/lazy-auth-server/server.ts already uses. No behaviour change on Node 20.11+.
  • Quickstart (examples/quickstart/server.ts): same fix; docs/quickstart.md resynced with npm run sync:snippets.
  • engines.node: ">=20" added to the 21 published example packages (the ones with a bin), matching the root package. package-lock.json gains only those 21 engines entries (63 added lines, nothing removed, no dependency changes).
  • CI: after the existing MCPB smoke test, install Node 20.0.0 and run the same pdf-server bundle on it, so a regression fails the build.

Testing

Everything below was run in a clean Linux arm64 container, with the build done on Node 22 as in CI and official Node tarballs (SHA-256 checked against SHASUMS256.txt) used to run the built servers.

npm ci, npm run build, npm run examples:build, npm run generate:schemas (no diff), npm run sync:snippets (no diff after the resync), npm test (438 pass, 2 skip, 0 fail), npm run prettier, node scripts/check-versions.mjs, the TypeDoc link validation and the lockfile registry check all pass.

Each built server was started with node dist/index.js --stdio, sent initialize, and then asked for its ui:// resource (which is what reads from the computed dist directory). lazy-auth-server is HTTP-only, so it was probed over HTTP instead.

Node main (before) This branch (after)
18.20.4 0 of 21 start 21 of 22 start (not a supported version)
20.0.0 0 of 21 start 22 of 22 start
20.10.0 0 of 21 start 22 of 22 start
20.11.0 21 of 21 start 22 of 22 start
22.x 21 of 21 start 22 of 22 start

The "before" column counts the 21 servers that used the pattern (lazy-auth-server was already fine). On Node 18.20.4 the one remaining failure is wiki-explorer-server, whose cheerio/undici dependency needs the File global; Node 18 is outside the declared range.

For pdf-server specifically:

  • The MCPB bundle was built with node build-mcpb.mjs, unzipped, and the exact CI smoke command (node .mcpb-smoke/dist/index.js --stdio < /dev/null, then grep -q Ready) passes on Node 22 and on Node 20.0.0.
  • As a control, the same command on a build of main fails on Node 20.0.0 with the TypeError above, so the new CI step does detect the bug.
  • display_pdf on a local PDF succeeds on 18.20.4, 20.0.0, 20.10.0, 20.11.0 and 22.

The new CI step itself (the actions/setup-node switch to 20.0.0) can only be exercised by CI on this PR.

Notes on the engines floor

>=20 is what was verified: every published example starts and serves its UI on Node 20.0.0. Two dependencies declare a higher floor than that, which npm reports as an EBADENGINE warning at install time:

  • pdfjs-dist declares >=20.16.0 || >=22.3.0. On older Node it logs a warning about process.getBuiltinModule to stderr; pdf-server still starts and opens PDFs.
  • cheerio declares >=20.18.1 (used by wiki-explorer-server), which starts and answers tool calls on 20.0.0.

If we would rather not claim more than those dependencies do, the alternative is to raise the floor for those two packages only. Happy to change it either way.

Follow-ups

  • plugins/mcp-apps/skills/add-app-to-server/SKILL.md and plugins/mcp-apps/skills/convert-web-app/SKILL.md still show import.meta.dirname in their snippets. They are fragments without imports, so they are left for a separate docs change.
  • examples/pdf-server/server.test.ts uses import.meta.dirname, but it only runs under Bun.

The example servers located their dist directory with
import.meta.filename / import.meta.dirname, which only exist from
Node 20.11. On older versions (18.x, 20.0 to 20.10) the module threw
"TypeError: Cannot read properties of undefined (reading 'endsWith')"
at load, before the server could answer `initialize`, even though the
packages are documented as supporting Node 20+.

- Derive the path from import.meta.url with fileURLToPath, the idiom
  lazy-auth-server already uses, in the 21 affected example servers and
  in the quickstart (docs/quickstart.md resynced).
- Declare engines.node ">=20" in the published example packages and
  record it in package-lock.json.
- CI: after the MCPB smoke test, run the same pdf-server bundle on
  Node 20.0.0 so a regression fails the build.
@github-actions

github-actions Bot commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

Preview

Preview deployments for this PR have been cleaned up.

@pkg-pr-new

pkg-pr-new Bot commented Sep 23, 2026

Copy link
Copy Markdown

Open in StackBlitz

@modelcontextprotocol/ext-apps

npm i https://pkg.pr.new/@modelcontextprotocol/ext-apps@787

@modelcontextprotocol/server-basic-preact

npm i https://pkg.pr.new/@modelcontextprotocol/server-basic-preact@787

@modelcontextprotocol/server-basic-react

npm i https://pkg.pr.new/@modelcontextprotocol/server-basic-react@787

@modelcontextprotocol/server-basic-solid

npm i https://pkg.pr.new/@modelcontextprotocol/server-basic-solid@787

@modelcontextprotocol/server-basic-svelte

npm i https://pkg.pr.new/@modelcontextprotocol/server-basic-svelte@787

@modelcontextprotocol/server-basic-vanillajs

npm i https://pkg.pr.new/@modelcontextprotocol/server-basic-vanillajs@787

@modelcontextprotocol/server-basic-vue

npm i https://pkg.pr.new/@modelcontextprotocol/server-basic-vue@787

@modelcontextprotocol/server-budget-allocator

npm i https://pkg.pr.new/@modelcontextprotocol/server-budget-allocator@787

@modelcontextprotocol/server-cohort-heatmap

npm i https://pkg.pr.new/@modelcontextprotocol/server-cohort-heatmap@787

@modelcontextprotocol/server-customer-segmentation

npm i https://pkg.pr.new/@modelcontextprotocol/server-customer-segmentation@787

@modelcontextprotocol/server-debug

npm i https://pkg.pr.new/@modelcontextprotocol/server-debug@787

@modelcontextprotocol/server-lazy-auth

npm i https://pkg.pr.new/@modelcontextprotocol/server-lazy-auth@787

@modelcontextprotocol/server-map

npm i https://pkg.pr.new/@modelcontextprotocol/server-map@787

@modelcontextprotocol/server-pdf

npm i https://pkg.pr.new/@modelcontextprotocol/server-pdf@787

@modelcontextprotocol/server-scenario-modeler

npm i https://pkg.pr.new/@modelcontextprotocol/server-scenario-modeler@787

@modelcontextprotocol/server-shadertoy

npm i https://pkg.pr.new/@modelcontextprotocol/server-shadertoy@787

@modelcontextprotocol/server-sheet-music

npm i https://pkg.pr.new/@modelcontextprotocol/server-sheet-music@787

@modelcontextprotocol/server-system-monitor

npm i https://pkg.pr.new/@modelcontextprotocol/server-system-monitor@787

@modelcontextprotocol/server-threejs

npm i https://pkg.pr.new/@modelcontextprotocol/server-threejs@787

@modelcontextprotocol/server-transcript

npm i https://pkg.pr.new/@modelcontextprotocol/server-transcript@787

@modelcontextprotocol/server-video-resource

npm i https://pkg.pr.new/@modelcontextprotocol/server-video-resource@787

@modelcontextprotocol/server-wiki-explorer

npm i https://pkg.pr.new/@modelcontextprotocol/server-wiki-explorer@787

commit: 54299cb

@ochafik
ochafik merged commit 8e1b3bd into main Sep 23, 2026
23 checks passed
@ochafik ochafik mentioned this pull request Sep 23, 2026
ochafik added a commit that referenced this pull request Sep 24, 2026
Patch release picking up the fix for example servers crashing at startup on Node older than 20.11 (#787) and the canonical repository.url form (#773).
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.

1 participant