Skip to content

fix: add explicit .js extensions to relative imports so declarations resolve under NodeNext/Node16 - #705

Merged
ochafik merged 1 commit into
modelcontextprotocol:mainfrom
ken-jo:fix/nodenext-extensionless-relative-imports
Sep 8, 2026
Merged

fix: add explicit .js extensions to relative imports so declarations resolve under NodeNext/Node16#705
ochafik merged 1 commit into
modelcontextprotocol:mainfrom
ken-jo:fix/nodenext-extensionless-relative-imports

Conversation

@ken-jo

@ken-jo ken-jo commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #704.

The published type declarations use extensionless relative import specifiers (e.g. import { ProtocolWithEvents } from "./events"; in dist/src/app-bridge.d.ts). tsc (emitDeclarationOnly) copies specifiers verbatim from src, and under Node16/NodeNext module resolution a relative specifier must carry an explicit extension — so these imports don't resolve for downstream consumers. Any type that transitively depends on one loses its members; most visibly, the recommended bridge.addEventListener("sandboxready", …) API (inherited from ProtocolWithEvents via ./events) becomes invisible, producing TS2339.

This adds explicit .js extensions to every relative import/export specifier across src. It is types-only — runtime JavaScript is unaffected, since the .js bundles are produced by Bun.build, which inlines relative modules (no extensionless relative import survives at runtime). The change matches the existing external-SDK import style (e.g. @modelcontextprotocol/sdk/shared/protocol.js), which already uses explicit .js; only the relative imports were inconsistent. It is compatible with both the repo's bundler-mode type-check and Bun.build (both resolve ./x.js./x.ts). No bare package specifiers were touched.

Verification

  • NodeNext repro from the issue — a consumer tsconfig with moduleResolution: NodeNext and index.ts doing bridge.addEventListener("sandboxready", () => {}), type-checked against a freshly built dist:
    • Before: index.ts: error TS2339: Property 'addEventListener' does not exist on type 'AppBridge'. (tsc --noEmit exits 2)
    • After: tsc --noEmit exits 0.
  • npm run prettier — the changed files are clean.
  • npm test373 pass, 2 skip, 0 fail (types-only change; no test behavior affected).

Scope: 13 files, 35 relative specifiers under src/** (including the *.test.ts relative imports, for consistency).

…resolve under NodeNext/Node16

The emitted .d.ts copy relative specifiers verbatim, and the extensionless form
(e.g. `from "./events"`) doesn't resolve under Node16/NodeNext, hiding inherited
members such as `addEventListener` (TS2339). Appending `.js` matches the existing
SDK-import style and works with both bundler-mode type-checking and Bun.build.
Types-only; runtime is unaffected.

Fixes modelcontextprotocol#704
@ochafik
ochafik force-pushed the fix/nodenext-extensionless-relative-imports branch from 59110ed to 264d9ca Compare September 8, 2026 12:41
@ochafik

ochafik commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Thanks Ken! Sorry for the slow turnaround here. This still reproduced on 1.7.5, lgtm. I rebased your commit onto main now that #720 (the SDK 2.0 migration) has landed, since the two touched the same import lines, and pushed it to your branch with your authorship intact. Merging; the remaining test-file imports come in #768 :-)

@ochafik ochafik left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rebased onto main and verified (typecheck, unit tests, prettier). lgtm

@ochafik
ochafik merged commit f9c671c into modelcontextprotocol:main Sep 8, 2026
3 of 16 checks passed
ochafik added a commit that referenced this pull request Sep 8, 2026
…sts (#768)

Follow-up to #720 and #705: regenerated lockfile, ^2.0.0 peers with client required, types from @modelcontextprotocol/client, restored double-registration guard, deprecated raw-shape registerAppTool overload, migration guide, wire-compat tests, MCPB build from the local package.
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.

Emitted .d.ts use extensionless relative imports — types break under NodeNext/Node16 (addEventListener invisible, TS2339)

2 participants