Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .changeset/fast-dragons-lead.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
'@modelcontextprotocol/express': patch
'@modelcontextprotocol/fastify': patch
'@modelcontextprotocol/hono': patch
'@modelcontextprotocol/node': patch
'@modelcontextprotocol/client': patch
'@modelcontextprotocol/server': patch
---

tsdown exports resolution fix
4 changes: 3 additions & 1 deletion packages/client/tsdown.config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { defineConfig } from 'tsdown';

export default defineConfig({
failOnWarn: 'ci-only',
// 1. Entry Points
// Directly matches package.json include/exclude globs
entry: ['src/index.ts', 'src/shimsNode.ts', 'src/shimsWorkerd.ts', 'src/shimsBrowser.ts'],
Expand All @@ -24,7 +25,8 @@ export default defineConfig({
compilerOptions: {
baseUrl: '.',
paths: {
'@modelcontextprotocol/core': ['../core/src/index.ts']
'@modelcontextprotocol/core': ['../core/src/index.ts'],
'@modelcontextprotocol/core/public': ['../core/src/exports/public/index.ts']
}
}
},
Expand Down
1 change: 1 addition & 0 deletions packages/middleware/express/tsdown.config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { defineConfig } from 'tsdown';

export default defineConfig({
failOnWarn: 'ci-only',
entry: ['src/index.ts'],
format: ['esm'],
outDir: 'dist',
Expand Down
1 change: 1 addition & 0 deletions packages/middleware/fastify/tsdown.config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { defineConfig } from 'tsdown';

export default defineConfig({
failOnWarn: 'ci-only',
entry: ['src/index.ts'],
format: ['esm'],
outDir: 'dist',
Expand Down
1 change: 1 addition & 0 deletions packages/middleware/hono/tsdown.config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { defineConfig } from 'tsdown';

export default defineConfig({
failOnWarn: 'ci-only',
entry: ['src/index.ts'],
format: ['esm'],
outDir: 'dist',
Expand Down
1 change: 1 addition & 0 deletions packages/middleware/node/tsdown.config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { defineConfig } from 'tsdown';

export default defineConfig({
failOnWarn: 'ci-only',
// 1. Entry Points
// Directly matches package.json include/exclude globs
entry: ['src/index.ts'],
Comment on lines 1 to 7
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟣 Pre-existing bug: all four middleware tsdown configs have incorrect relative paths in dts.compilerOptions.paths that resolve to non-existent directories. In packages/middleware/node/tsdown.config.ts, ../core/src/index.ts (with baseUrl: ".") resolves to packages/middleware/core/src/index.ts which does not exist — the correct path is ../../core/src/index.ts. Similarly, express/fastify/hono use ../server/src/index.ts which resolves to the non-existent packages/middleware/server/src/index.ts instead of packages/server/src/index.ts (../../server/src/index.ts). This PR did not introduce the bug but touches all four files by adding failOnWarn; the path mappings are currently dead no-ops since TypeScript silently falls back to node_modules resolution.

Extended reasoning...

What the bug is and how it manifests

All four middleware tsdown configs (packages/middleware/node, packages/middleware/express, packages/middleware/fastify, packages/middleware/hono) contain path mappings in dts.compilerOptions.paths that point to non-existent locations. The paths use a single ../ prefix, but these packages sit two levels deep in the monorepo (packages/middleware/<pkg>/), so they require ../../ to reach sibling top-level packages.

The specific code path that triggers it

In packages/middleware/node/tsdown.config.ts, baseUrl: "." resolves to packages/middleware/node/. Therefore ../core/src/index.ts resolves to packages/middleware/core/src/index.ts. No such directory exists — core lives at packages/core/. The correct relative path is ../../core/src/index.ts. The same depth error affects express, fastify, and hono: ../server/src/index.ts resolves to packages/middleware/server/src/index.ts (non-existent) instead of packages/server/src/index.ts (requires ../../server/src/index.ts).

Why existing code does not prevent it

For contrast, packages/server/tsdown.config.ts correctly uses ../core/src/index.ts because it lives at packages/server/ — only one level deep — so ../core correctly resolves to packages/core/. The middleware packages copied this pattern without adjusting for their extra directory nesting. TypeScript does not emit a warning or error when a paths mapping points to a non-existent file; it silently skips that alternative and falls back to standard node_modules resolution. This is why builds currently succeed and failOnWarn: ci-only (added by this PR) will not surface the issue.

Impact

The path mappings are dead no-ops. The DTS bundler resolves @modelcontextprotocol/core and @modelcontextprotocol/server from installed node_modules rather than from local source. In a workspace with workspace:* protocol this keeps versions in sync, so type output is currently correct. However, this is exactly the class of bug this PR is trying to fix for server and client — using installed package types instead of local source can cause stale or incomplete type exports if the installed package has not been rebuilt after source changes.

How to fix it

Change ../core/src/index.ts../../core/src/index.ts in packages/middleware/node/tsdown.config.ts, and change ../server/src/index.ts../../server/src/index.ts in packages/middleware/express/tsdown.config.ts, packages/middleware/fastify/tsdown.config.ts, and packages/middleware/hono/tsdown.config.ts.

Step-by-step proof

  1. Config file location: packages/middleware/node/tsdown.config.ts
  2. baseUrl: "." → resolves to directory packages/middleware/node/
  3. Path entry: @modelcontextprotocol/core → ["../core/src/index.ts"]
  4. Resolution: packages/middleware/node/ + ../core/src/index.ts = packages/middleware/core/src/index.ts
  5. packages/middleware/core/ does not exist in the repository
  6. TypeScript silently falls back; @modelcontextprotocol/core is resolved from node_modules instead
  7. Correct path: packages/middleware/node/ + ../../core/src/index.ts = packages/core/src/index.ts

The refutation notes this overlaps with bug_002; both describe the same underlying pattern, but bug_003 covers all four middleware packages comprehensively and the fix is concrete and actionable regardless of deduplication.

Expand Down
4 changes: 3 additions & 1 deletion packages/server/tsdown.config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { defineConfig } from 'tsdown';

export default defineConfig({
failOnWarn: 'ci-only',
// 1. Entry Points
// Directly matches package.json include/exclude globs
entry: ['src/index.ts', 'src/shimsNode.ts', 'src/shimsWorkerd.ts'],
Expand All @@ -24,7 +25,8 @@ export default defineConfig({
compilerOptions: {
baseUrl: '.',
paths: {
'@modelcontextprotocol/core': ['../core/src/index.ts']
'@modelcontextprotocol/core': ['../core/src/index.ts'],
'@modelcontextprotocol/core/public': ['../core/src/exports/public/index.ts']
}
}
},
Expand Down
Loading