v2 tsdown fix - #1840

Merged
felixweinberger merged 2 commits into
mainfrom
fix/tsdown-resolution-fix
Apr 1, 2026
Merged

v2 tsdown fix#1840
felixweinberger merged 2 commits into
mainfrom
fix/tsdown-resolution-fix

Conversation

@KKonstantinov

Copy link
Copy Markdown
Contributor

fix(build): restore missing core/public type re-exports in built packages

Motivation and Context

The tsdown DTS bundler was silently dropping all ~270 type re-exports from @modelcontextprotocol/core/public (including Tool, CallToolResult, Resource, ServerCapabilities, etc.) in the built dist/index.d.mts of both @modelcontextprotocol/server and @modelcontextprotocol/client.

Root cause: The tsdown dts.compilerOptions.paths override in server/tsdown.config.ts and client/tsdown.config.ts only mapped @modelcontextprotocol/core but not @modelcontextprotocol/core/public. Since this override replaces (not merges with) the tsconfig paths, the DTS resolver couldn't resolve the /public subpath import, causing export * from '@modelcontextprotocol/core/public' to be silently dropped. The build emitted a warning ("Failed to emit declaration file") but continued, producing packages missing most of their public API types.

How Has This Been Tested?

  • pnpm build:all — builds cleanly with no warnings (previously emitted "Failed to emit declaration file" warning)
  • Verified Tool and other core/public types appear in dist/index.d.mts export list for both server and client (went from 39 to 310 exports in the server package)
  • pnpm check:all — typecheck + lint pass
  • pnpm test:all — all tests pass

Breaking Changes

None. This is a bug fix — it restores types that were intended to be exported but were missing from the built output.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

Two changes per config:

  1. Bug fix — Added the missing @modelcontextprotocol/core/public path mapping to dts.compilerOptions.paths in server/tsdown.config.ts and client/tsdown.config.ts.

  2. Prevention — Added failOnWarn: 'ci-only' to all 6 tsdown configs (server, client, and 4 middleware packages) so that DTS warnings like this will fail CI builds in the future instead of silently producing incomplete packages.

@KKonstantinov
KKonstantinov requested a review from a team as a code ownerApril 1, 2026 16:27
@felixweinberger

Copy link
Copy Markdown
Contributor

@claude review

@pkg-pr-new

pkg-pr-newBot commented Apr 1, 2026

Copy link
Copy Markdown

Open in StackBlitz

@modelcontextprotocol/client

npm i https://pkg.pr.new/@modelcontextprotocol/client@1840

@modelcontextprotocol/server

npm i https://pkg.pr.new/@modelcontextprotocol/server@1840

@modelcontextprotocol/express

npm i https://pkg.pr.new/@modelcontextprotocol/express@1840

@modelcontextprotocol/fastify

npm i https://pkg.pr.new/@modelcontextprotocol/fastify@1840

@modelcontextprotocol/hono

npm i https://pkg.pr.new/@modelcontextprotocol/hono@1840

@modelcontextprotocol/node

npm i https://pkg.pr.new/@modelcontextprotocol/node@1840

commit: fbdd299

@changeset-bot

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: fbdd299

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 6 packages
NameType
@modelcontextprotocol/expressPatch
@modelcontextprotocol/fastifyPatch
@modelcontextprotocol/honoPatch
@modelcontextprotocol/nodePatch
@modelcontextprotocol/clientPatch
@modelcontextprotocol/serverPatch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@felixweinbergerfelixweinberger 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.

verified the exports are fixed by this locally.

@felixweinberger
felixweinberger merged commit 424cbae into mainApr 1, 2026
15 checks passed
@felixweinberger
felixweinberger deleted the fix/tsdown-resolution-fix branch April 1, 2026 16:34
@github-actionsgithub-actionsBot mentioned this pull request Apr 1, 2026

@claudeclaudeBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

LGTM — the core/public path mapping fix correctly restores the missing type exports, and failOnWarn: 'ci-only' is a sensible guard against silent DTS failures going forward.

Extended reasoning...

Overview

This PR modifies six tsdown.config.ts build config files (server, client, and four middleware packages). The substantive fix adds a @modelcontextprotocol/core/public subpath entry to the dts.compilerOptions.paths override in server and client, restoring ~270 type re-exports that were previously silently dropped. The secondary change adds failOnWarn: 'ci-only' to all six configs.

Security risks

None. These are build-time TypeScript compiler configuration files with no runtime security surface.

Level of scrutiny

Low. Changes are confined to build configuration, not runtime logic. The root cause is well-explained (paths override replaces rather than merges with tsconfig paths, so the /public subpath was unmapped), and the fix is the minimal correct addition to address it. The failOnWarn addition is mechanical and clearly beneficial.

Other factors

A pre-existing bug in the four middleware configs (wrong relative depth in path mappings — ../server/ instead of ../../server/) is flagged by the inline comment but was not introduced by this PR. Per the bug report, those paths are currently dead no-ops that TypeScript silently ignores, so they do not regress functionality. The primary fix has been validated by the author with measurable output (39 → 310 exports). All tests and typechecks pass.

Comment on lines 1 to 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'],

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.

@claudeclaudeBot mentioned this pull request Jun 23, 2026
Sign up for freeto 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.

2 participants

@KKonstantinov@felixweinberger
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

v2 tsdown fix - #1840

Merged
felixweinberger merged 2 commits into
mainfrom
fix/tsdown-resolution-fix
Apr 1, 2026
Merged

v2 tsdown fix#1840
felixweinberger merged 2 commits into
mainfrom
fix/tsdown-resolution-fix

Conversation

@KKonstantinov

Copy link
Copy Markdown
Contributor

fix(build): restore missing core/public type re-exports in built packages

Motivation and Context

The tsdown DTS bundler was silently dropping all ~270 type re-exports from @modelcontextprotocol/core/public (including Tool, CallToolResult, Resource, ServerCapabilities, etc.) in the built dist/index.d.mts of both @modelcontextprotocol/server and @modelcontextprotocol/client.

Root cause: The tsdown dts.compilerOptions.paths override in server/tsdown.config.ts and client/tsdown.config.ts only mapped @modelcontextprotocol/core but not @modelcontextprotocol/core/public. Since this override replaces (not merges with) the tsconfig paths, the DTS resolver couldn't resolve the /public subpath import, causing export * from '@modelcontextprotocol/core/public' to be silently dropped. The build emitted a warning ("Failed to emit declaration file") but continued, producing packages missing most of their public API types.

How Has This Been Tested?

  • pnpm build:all — builds cleanly with no warnings (previously emitted "Failed to emit declaration file" warning)
  • Verified Tool and other core/public types appear in dist/index.d.mts export list for both server and client (went from 39 to 310 exports in the server package)
  • pnpm check:all — typecheck + lint pass
  • pnpm test:all — all tests pass

Breaking Changes

None. This is a bug fix — it restores types that were intended to be exported but were missing from the built output.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

Two changes per config:

  1. Bug fix — Added the missing @modelcontextprotocol/core/public path mapping to dts.compilerOptions.paths in server/tsdown.config.ts and client/tsdown.config.ts.

  2. Prevention — Added failOnWarn: 'ci-only' to all 6 tsdown configs (server, client, and 4 middleware packages) so that DTS warnings like this will fail CI builds in the future instead of silently producing incomplete packages.

@KKonstantinov
KKonstantinov requested a review from a team as a code ownerApril 1, 2026 16:27
@felixweinberger

Copy link
Copy Markdown
Contributor

@claude review

@pkg-pr-new

pkg-pr-newBot commented Apr 1, 2026

Copy link
Copy Markdown

Open in StackBlitz

@modelcontextprotocol/client

npm i https://pkg.pr.new/@modelcontextprotocol/client@1840

@modelcontextprotocol/server

npm i https://pkg.pr.new/@modelcontextprotocol/server@1840

@modelcontextprotocol/express

npm i https://pkg.pr.new/@modelcontextprotocol/express@1840

@modelcontextprotocol/fastify

npm i https://pkg.pr.new/@modelcontextprotocol/fastify@1840

@modelcontextprotocol/hono

npm i https://pkg.pr.new/@modelcontextprotocol/hono@1840

@modelcontextprotocol/node

npm i https://pkg.pr.new/@modelcontextprotocol/node@1840

commit: fbdd299

@changeset-bot

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: fbdd299

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 6 packages
NameType
@modelcontextprotocol/expressPatch
@modelcontextprotocol/fastifyPatch
@modelcontextprotocol/honoPatch
@modelcontextprotocol/nodePatch
@modelcontextprotocol/clientPatch
@modelcontextprotocol/serverPatch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@felixweinbergerfelixweinberger 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.

verified the exports are fixed by this locally.

@felixweinberger
felixweinberger merged commit 424cbae into mainApr 1, 2026
15 checks passed
@felixweinberger
felixweinberger deleted the fix/tsdown-resolution-fix branch April 1, 2026 16:34
@github-actionsgithub-actionsBot mentioned this pull request Apr 1, 2026

@claudeclaudeBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

LGTM — the core/public path mapping fix correctly restores the missing type exports, and failOnWarn: 'ci-only' is a sensible guard against silent DTS failures going forward.

Extended reasoning...

Overview

This PR modifies six tsdown.config.ts build config files (server, client, and four middleware packages). The substantive fix adds a @modelcontextprotocol/core/public subpath entry to the dts.compilerOptions.paths override in server and client, restoring ~270 type re-exports that were previously silently dropped. The secondary change adds failOnWarn: 'ci-only' to all six configs.

Security risks

None. These are build-time TypeScript compiler configuration files with no runtime security surface.

Level of scrutiny

Low. Changes are confined to build configuration, not runtime logic. The root cause is well-explained (paths override replaces rather than merges with tsconfig paths, so the /public subpath was unmapped), and the fix is the minimal correct addition to address it. The failOnWarn addition is mechanical and clearly beneficial.

Other factors

A pre-existing bug in the four middleware configs (wrong relative depth in path mappings — ../server/ instead of ../../server/) is flagged by the inline comment but was not introduced by this PR. Per the bug report, those paths are currently dead no-ops that TypeScript silently ignores, so they do not regress functionality. The primary fix has been validated by the author with measurable output (39 → 310 exports). All tests and typechecks pass.

Comment on lines 1 to 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'],

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.

@claudeclaudeBot mentioned this pull request Jun 23, 2026
Sign up for freeto 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.

2 participants

@KKonstantinov@felixweinberger
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

v2 tsdown fix - #1840

Merged
felixweinberger merged 2 commits into
mainfrom
fix/tsdown-resolution-fix
Apr 1, 2026
Merged

v2 tsdown fix#1840
felixweinberger merged 2 commits into
mainfrom
fix/tsdown-resolution-fix

Conversation

@KKonstantinov

Copy link
Copy Markdown
Contributor

fix(build): restore missing core/public type re-exports in built packages

Motivation and Context

The tsdown DTS bundler was silently dropping all ~270 type re-exports from @modelcontextprotocol/core/public (including Tool, CallToolResult, Resource, ServerCapabilities, etc.) in the built dist/index.d.mts of both @modelcontextprotocol/server and @modelcontextprotocol/client.

Root cause: The tsdown dts.compilerOptions.paths override in server/tsdown.config.ts and client/tsdown.config.ts only mapped @modelcontextprotocol/core but not @modelcontextprotocol/core/public. Since this override replaces (not merges with) the tsconfig paths, the DTS resolver couldn't resolve the /public subpath import, causing export * from '@modelcontextprotocol/core/public' to be silently dropped. The build emitted a warning ("Failed to emit declaration file") but continued, producing packages missing most of their public API types.

How Has This Been Tested?

  • pnpm build:all — builds cleanly with no warnings (previously emitted "Failed to emit declaration file" warning)
  • Verified Tool and other core/public types appear in dist/index.d.mts export list for both server and client (went from 39 to 310 exports in the server package)
  • pnpm check:all — typecheck + lint pass
  • pnpm test:all — all tests pass

Breaking Changes

None. This is a bug fix — it restores types that were intended to be exported but were missing from the built output.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

Two changes per config:

  1. Bug fix — Added the missing @modelcontextprotocol/core/public path mapping to dts.compilerOptions.paths in server/tsdown.config.ts and client/tsdown.config.ts.

  2. Prevention — Added failOnWarn: 'ci-only' to all 6 tsdown configs (server, client, and 4 middleware packages) so that DTS warnings like this will fail CI builds in the future instead of silently producing incomplete packages.

@KKonstantinov
KKonstantinov requested a review from a team as a code ownerApril 1, 2026 16:27
@felixweinberger

Copy link
Copy Markdown
Contributor

@claude review

@pkg-pr-new

pkg-pr-newBot commented Apr 1, 2026

Copy link
Copy Markdown

Open in StackBlitz

@modelcontextprotocol/client

npm i https://pkg.pr.new/@modelcontextprotocol/client@1840

@modelcontextprotocol/server

npm i https://pkg.pr.new/@modelcontextprotocol/server@1840

@modelcontextprotocol/express

npm i https://pkg.pr.new/@modelcontextprotocol/express@1840

@modelcontextprotocol/fastify

npm i https://pkg.pr.new/@modelcontextprotocol/fastify@1840

@modelcontextprotocol/hono

npm i https://pkg.pr.new/@modelcontextprotocol/hono@1840

@modelcontextprotocol/node

npm i https://pkg.pr.new/@modelcontextprotocol/node@1840

commit: fbdd299

@changeset-bot

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: fbdd299

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 6 packages
NameType
@modelcontextprotocol/expressPatch
@modelcontextprotocol/fastifyPatch
@modelcontextprotocol/honoPatch
@modelcontextprotocol/nodePatch
@modelcontextprotocol/clientPatch
@modelcontextprotocol/serverPatch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@felixweinbergerfelixweinberger 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.

verified the exports are fixed by this locally.

@felixweinberger
felixweinberger merged commit 424cbae into mainApr 1, 2026
15 checks passed
@felixweinberger
felixweinberger deleted the fix/tsdown-resolution-fix branch April 1, 2026 16:34
@github-actionsgithub-actionsBot mentioned this pull request Apr 1, 2026

@claudeclaudeBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

LGTM — the core/public path mapping fix correctly restores the missing type exports, and failOnWarn: 'ci-only' is a sensible guard against silent DTS failures going forward.

Extended reasoning...

Overview

This PR modifies six tsdown.config.ts build config files (server, client, and four middleware packages). The substantive fix adds a @modelcontextprotocol/core/public subpath entry to the dts.compilerOptions.paths override in server and client, restoring ~270 type re-exports that were previously silently dropped. The secondary change adds failOnWarn: 'ci-only' to all six configs.

Security risks

None. These are build-time TypeScript compiler configuration files with no runtime security surface.

Level of scrutiny

Low. Changes are confined to build configuration, not runtime logic. The root cause is well-explained (paths override replaces rather than merges with tsconfig paths, so the /public subpath was unmapped), and the fix is the minimal correct addition to address it. The failOnWarn addition is mechanical and clearly beneficial.

Other factors

A pre-existing bug in the four middleware configs (wrong relative depth in path mappings — ../server/ instead of ../../server/) is flagged by the inline comment but was not introduced by this PR. Per the bug report, those paths are currently dead no-ops that TypeScript silently ignores, so they do not regress functionality. The primary fix has been validated by the author with measurable output (39 → 310 exports). All tests and typechecks pass.

Comment on lines 1 to 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'],

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.

@claudeclaudeBot mentioned this pull request Jun 23, 2026
Sign up for freeto 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.

2 participants

@KKonstantinov@felixweinberger
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

v2 tsdown fix - #1840

Merged
felixweinberger merged 2 commits into
mainfrom
fix/tsdown-resolution-fix
Apr 1, 2026
Merged

v2 tsdown fix#1840
felixweinberger merged 2 commits into
mainfrom
fix/tsdown-resolution-fix

Conversation

@KKonstantinov

Copy link
Copy Markdown
Contributor

fix(build): restore missing core/public type re-exports in built packages

Motivation and Context

The tsdown DTS bundler was silently dropping all ~270 type re-exports from @modelcontextprotocol/core/public (including Tool, CallToolResult, Resource, ServerCapabilities, etc.) in the built dist/index.d.mts of both @modelcontextprotocol/server and @modelcontextprotocol/client.

Root cause: The tsdown dts.compilerOptions.paths override in server/tsdown.config.ts and client/tsdown.config.ts only mapped @modelcontextprotocol/core but not @modelcontextprotocol/core/public. Since this override replaces (not merges with) the tsconfig paths, the DTS resolver couldn't resolve the /public subpath import, causing export * from '@modelcontextprotocol/core/public' to be silently dropped. The build emitted a warning ("Failed to emit declaration file") but continued, producing packages missing most of their public API types.

How Has This Been Tested?

  • pnpm build:all — builds cleanly with no warnings (previously emitted "Failed to emit declaration file" warning)
  • Verified Tool and other core/public types appear in dist/index.d.mts export list for both server and client (went from 39 to 310 exports in the server package)
  • pnpm check:all — typecheck + lint pass
  • pnpm test:all — all tests pass

Breaking Changes

None. This is a bug fix — it restores types that were intended to be exported but were missing from the built output.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

Two changes per config:

  1. Bug fix — Added the missing @modelcontextprotocol/core/public path mapping to dts.compilerOptions.paths in server/tsdown.config.ts and client/tsdown.config.ts.

  2. Prevention — Added failOnWarn: 'ci-only' to all 6 tsdown configs (server, client, and 4 middleware packages) so that DTS warnings like this will fail CI builds in the future instead of silently producing incomplete packages.

@KKonstantinov
KKonstantinov requested a review from a team as a code ownerApril 1, 2026 16:27
@felixweinberger

Copy link
Copy Markdown
Contributor

@claude review

@pkg-pr-new

pkg-pr-newBot commented Apr 1, 2026

Copy link
Copy Markdown

Open in StackBlitz

@modelcontextprotocol/client

npm i https://pkg.pr.new/@modelcontextprotocol/client@1840

@modelcontextprotocol/server

npm i https://pkg.pr.new/@modelcontextprotocol/server@1840

@modelcontextprotocol/express

npm i https://pkg.pr.new/@modelcontextprotocol/express@1840

@modelcontextprotocol/fastify

npm i https://pkg.pr.new/@modelcontextprotocol/fastify@1840

@modelcontextprotocol/hono

npm i https://pkg.pr.new/@modelcontextprotocol/hono@1840

@modelcontextprotocol/node

npm i https://pkg.pr.new/@modelcontextprotocol/node@1840

commit: fbdd299

@changeset-bot

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: fbdd299

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 6 packages
NameType
@modelcontextprotocol/expressPatch
@modelcontextprotocol/fastifyPatch
@modelcontextprotocol/honoPatch
@modelcontextprotocol/nodePatch
@modelcontextprotocol/clientPatch
@modelcontextprotocol/serverPatch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@felixweinbergerfelixweinberger 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.

verified the exports are fixed by this locally.

@felixweinberger
felixweinberger merged commit 424cbae into mainApr 1, 2026
15 checks passed
@felixweinberger
felixweinberger deleted the fix/tsdown-resolution-fix branch April 1, 2026 16:34
@github-actionsgithub-actionsBot mentioned this pull request Apr 1, 2026

@claudeclaudeBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

LGTM — the core/public path mapping fix correctly restores the missing type exports, and failOnWarn: 'ci-only' is a sensible guard against silent DTS failures going forward.

Extended reasoning...

Overview

This PR modifies six tsdown.config.ts build config files (server, client, and four middleware packages). The substantive fix adds a @modelcontextprotocol/core/public subpath entry to the dts.compilerOptions.paths override in server and client, restoring ~270 type re-exports that were previously silently dropped. The secondary change adds failOnWarn: 'ci-only' to all six configs.

Security risks

None. These are build-time TypeScript compiler configuration files with no runtime security surface.

Level of scrutiny

Low. Changes are confined to build configuration, not runtime logic. The root cause is well-explained (paths override replaces rather than merges with tsconfig paths, so the /public subpath was unmapped), and the fix is the minimal correct addition to address it. The failOnWarn addition is mechanical and clearly beneficial.

Other factors

A pre-existing bug in the four middleware configs (wrong relative depth in path mappings — ../server/ instead of ../../server/) is flagged by the inline comment but was not introduced by this PR. Per the bug report, those paths are currently dead no-ops that TypeScript silently ignores, so they do not regress functionality. The primary fix has been validated by the author with measurable output (39 → 310 exports). All tests and typechecks pass.

Comment on lines 1 to 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'],

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.

@claudeclaudeBot mentioned this pull request Jun 23, 2026
Sign up for freeto 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.

2 participants

@KKonstantinov@felixweinberger
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

v2 tsdown fix - #1840

Merged
felixweinberger merged 2 commits into
mainfrom
fix/tsdown-resolution-fix
Apr 1, 2026
Merged

v2 tsdown fix#1840
felixweinberger merged 2 commits into
mainfrom
fix/tsdown-resolution-fix

Conversation

@KKonstantinov

Copy link
Copy Markdown
Contributor

fix(build): restore missing core/public type re-exports in built packages

Motivation and Context

The tsdown DTS bundler was silently dropping all ~270 type re-exports from @modelcontextprotocol/core/public (including Tool, CallToolResult, Resource, ServerCapabilities, etc.) in the built dist/index.d.mts of both @modelcontextprotocol/server and @modelcontextprotocol/client.

Root cause: The tsdown dts.compilerOptions.paths override in server/tsdown.config.ts and client/tsdown.config.ts only mapped @modelcontextprotocol/core but not @modelcontextprotocol/core/public. Since this override replaces (not merges with) the tsconfig paths, the DTS resolver couldn't resolve the /public subpath import, causing export * from '@modelcontextprotocol/core/public' to be silently dropped. The build emitted a warning ("Failed to emit declaration file") but continued, producing packages missing most of their public API types.

How Has This Been Tested?

  • pnpm build:all — builds cleanly with no warnings (previously emitted "Failed to emit declaration file" warning)
  • Verified Tool and other core/public types appear in dist/index.d.mts export list for both server and client (went from 39 to 310 exports in the server package)
  • pnpm check:all — typecheck + lint pass
  • pnpm test:all — all tests pass

Breaking Changes

None. This is a bug fix — it restores types that were intended to be exported but were missing from the built output.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

Two changes per config:

  1. Bug fix — Added the missing @modelcontextprotocol/core/public path mapping to dts.compilerOptions.paths in server/tsdown.config.ts and client/tsdown.config.ts.

  2. Prevention — Added failOnWarn: 'ci-only' to all 6 tsdown configs (server, client, and 4 middleware packages) so that DTS warnings like this will fail CI builds in the future instead of silently producing incomplete packages.

@KKonstantinov
KKonstantinov requested a review from a team as a code ownerApril 1, 2026 16:27
@felixweinberger

Copy link
Copy Markdown
Contributor

@claude review

@pkg-pr-new

pkg-pr-newBot commented Apr 1, 2026

Copy link
Copy Markdown

Open in StackBlitz

@modelcontextprotocol/client

npm i https://pkg.pr.new/@modelcontextprotocol/client@1840

@modelcontextprotocol/server

npm i https://pkg.pr.new/@modelcontextprotocol/server@1840

@modelcontextprotocol/express

npm i https://pkg.pr.new/@modelcontextprotocol/express@1840

@modelcontextprotocol/fastify

npm i https://pkg.pr.new/@modelcontextprotocol/fastify@1840

@modelcontextprotocol/hono

npm i https://pkg.pr.new/@modelcontextprotocol/hono@1840

@modelcontextprotocol/node

npm i https://pkg.pr.new/@modelcontextprotocol/node@1840

commit: fbdd299

@changeset-bot

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: fbdd299

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 6 packages
NameType
@modelcontextprotocol/expressPatch
@modelcontextprotocol/fastifyPatch
@modelcontextprotocol/honoPatch
@modelcontextprotocol/nodePatch
@modelcontextprotocol/clientPatch
@modelcontextprotocol/serverPatch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@felixweinbergerfelixweinberger 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.

verified the exports are fixed by this locally.

@felixweinberger
felixweinberger merged commit 424cbae into mainApr 1, 2026
15 checks passed
@felixweinberger
felixweinberger deleted the fix/tsdown-resolution-fix branch April 1, 2026 16:34
@github-actionsgithub-actionsBot mentioned this pull request Apr 1, 2026

@claudeclaudeBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

LGTM — the core/public path mapping fix correctly restores the missing type exports, and failOnWarn: 'ci-only' is a sensible guard against silent DTS failures going forward.

Extended reasoning...

Overview

This PR modifies six tsdown.config.ts build config files (server, client, and four middleware packages). The substantive fix adds a @modelcontextprotocol/core/public subpath entry to the dts.compilerOptions.paths override in server and client, restoring ~270 type re-exports that were previously silently dropped. The secondary change adds failOnWarn: 'ci-only' to all six configs.

Security risks

None. These are build-time TypeScript compiler configuration files with no runtime security surface.

Level of scrutiny

Low. Changes are confined to build configuration, not runtime logic. The root cause is well-explained (paths override replaces rather than merges with tsconfig paths, so the /public subpath was unmapped), and the fix is the minimal correct addition to address it. The failOnWarn addition is mechanical and clearly beneficial.

Other factors

A pre-existing bug in the four middleware configs (wrong relative depth in path mappings — ../server/ instead of ../../server/) is flagged by the inline comment but was not introduced by this PR. Per the bug report, those paths are currently dead no-ops that TypeScript silently ignores, so they do not regress functionality. The primary fix has been validated by the author with measurable output (39 → 310 exports). All tests and typechecks pass.

Comment on lines 1 to 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'],

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.

@claudeclaudeBot mentioned this pull request Jun 23, 2026
Sign up for freeto 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.

2 participants

@KKonstantinov@felixweinberger
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

v2 tsdown fix - #1840

Merged
felixweinberger merged 2 commits into
mainfrom
fix/tsdown-resolution-fix
Apr 1, 2026
Merged

v2 tsdown fix#1840
felixweinberger merged 2 commits into
mainfrom
fix/tsdown-resolution-fix

Conversation

@KKonstantinov

Copy link
Copy Markdown
Contributor

fix(build): restore missing core/public type re-exports in built packages

Motivation and Context

The tsdown DTS bundler was silently dropping all ~270 type re-exports from @modelcontextprotocol/core/public (including Tool, CallToolResult, Resource, ServerCapabilities, etc.) in the built dist/index.d.mts of both @modelcontextprotocol/server and @modelcontextprotocol/client.

Root cause: The tsdown dts.compilerOptions.paths override in server/tsdown.config.ts and client/tsdown.config.ts only mapped @modelcontextprotocol/core but not @modelcontextprotocol/core/public. Since this override replaces (not merges with) the tsconfig paths, the DTS resolver couldn't resolve the /public subpath import, causing export * from '@modelcontextprotocol/core/public' to be silently dropped. The build emitted a warning ("Failed to emit declaration file") but continued, producing packages missing most of their public API types.

How Has This Been Tested?

  • pnpm build:all — builds cleanly with no warnings (previously emitted "Failed to emit declaration file" warning)
  • Verified Tool and other core/public types appear in dist/index.d.mts export list for both server and client (went from 39 to 310 exports in the server package)
  • pnpm check:all — typecheck + lint pass
  • pnpm test:all — all tests pass

Breaking Changes

None. This is a bug fix — it restores types that were intended to be exported but were missing from the built output.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

Two changes per config:

  1. Bug fix — Added the missing @modelcontextprotocol/core/public path mapping to dts.compilerOptions.paths in server/tsdown.config.ts and client/tsdown.config.ts.

  2. Prevention — Added failOnWarn: 'ci-only' to all 6 tsdown configs (server, client, and 4 middleware packages) so that DTS warnings like this will fail CI builds in the future instead of silently producing incomplete packages.

@KKonstantinov
KKonstantinov requested a review from a team as a code ownerApril 1, 2026 16:27
@felixweinberger

Copy link
Copy Markdown
Contributor

@claude review

@pkg-pr-new

pkg-pr-newBot commented Apr 1, 2026

Copy link
Copy Markdown

Open in StackBlitz

@modelcontextprotocol/client

npm i https://pkg.pr.new/@modelcontextprotocol/client@1840

@modelcontextprotocol/server

npm i https://pkg.pr.new/@modelcontextprotocol/server@1840

@modelcontextprotocol/express

npm i https://pkg.pr.new/@modelcontextprotocol/express@1840

@modelcontextprotocol/fastify

npm i https://pkg.pr.new/@modelcontextprotocol/fastify@1840

@modelcontextprotocol/hono

npm i https://pkg.pr.new/@modelcontextprotocol/hono@1840

@modelcontextprotocol/node

npm i https://pkg.pr.new/@modelcontextprotocol/node@1840

commit: fbdd299

@changeset-bot

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: fbdd299

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 6 packages
NameType
@modelcontextprotocol/expressPatch
@modelcontextprotocol/fastifyPatch
@modelcontextprotocol/honoPatch
@modelcontextprotocol/nodePatch
@modelcontextprotocol/clientPatch
@modelcontextprotocol/serverPatch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@felixweinbergerfelixweinberger 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.

verified the exports are fixed by this locally.

@felixweinberger
felixweinberger merged commit 424cbae into mainApr 1, 2026
15 checks passed
@felixweinberger
felixweinberger deleted the fix/tsdown-resolution-fix branch April 1, 2026 16:34
@github-actionsgithub-actionsBot mentioned this pull request Apr 1, 2026

@claudeclaudeBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

LGTM — the core/public path mapping fix correctly restores the missing type exports, and failOnWarn: 'ci-only' is a sensible guard against silent DTS failures going forward.

Extended reasoning...

Overview

This PR modifies six tsdown.config.ts build config files (server, client, and four middleware packages). The substantive fix adds a @modelcontextprotocol/core/public subpath entry to the dts.compilerOptions.paths override in server and client, restoring ~270 type re-exports that were previously silently dropped. The secondary change adds failOnWarn: 'ci-only' to all six configs.

Security risks

None. These are build-time TypeScript compiler configuration files with no runtime security surface.

Level of scrutiny

Low. Changes are confined to build configuration, not runtime logic. The root cause is well-explained (paths override replaces rather than merges with tsconfig paths, so the /public subpath was unmapped), and the fix is the minimal correct addition to address it. The failOnWarn addition is mechanical and clearly beneficial.

Other factors

A pre-existing bug in the four middleware configs (wrong relative depth in path mappings — ../server/ instead of ../../server/) is flagged by the inline comment but was not introduced by this PR. Per the bug report, those paths are currently dead no-ops that TypeScript silently ignores, so they do not regress functionality. The primary fix has been validated by the author with measurable output (39 → 310 exports). All tests and typechecks pass.

Comment on lines 1 to 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'],

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.

@claudeclaudeBot mentioned this pull request Jun 23, 2026
Sign up for freeto 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.

2 participants

@KKonstantinov@felixweinberger
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

v2 tsdown fix - #1840

Merged
felixweinberger merged 2 commits into
mainfrom
fix/tsdown-resolution-fix
Apr 1, 2026
Merged

v2 tsdown fix#1840
felixweinberger merged 2 commits into
mainfrom
fix/tsdown-resolution-fix

Conversation

@KKonstantinov

Copy link
Copy Markdown
Contributor

fix(build): restore missing core/public type re-exports in built packages

Motivation and Context

The tsdown DTS bundler was silently dropping all ~270 type re-exports from @modelcontextprotocol/core/public (including Tool, CallToolResult, Resource, ServerCapabilities, etc.) in the built dist/index.d.mts of both @modelcontextprotocol/server and @modelcontextprotocol/client.

Root cause: The tsdown dts.compilerOptions.paths override in server/tsdown.config.ts and client/tsdown.config.ts only mapped @modelcontextprotocol/core but not @modelcontextprotocol/core/public. Since this override replaces (not merges with) the tsconfig paths, the DTS resolver couldn't resolve the /public subpath import, causing export * from '@modelcontextprotocol/core/public' to be silently dropped. The build emitted a warning ("Failed to emit declaration file") but continued, producing packages missing most of their public API types.

How Has This Been Tested?

  • pnpm build:all — builds cleanly with no warnings (previously emitted "Failed to emit declaration file" warning)
  • Verified Tool and other core/public types appear in dist/index.d.mts export list for both server and client (went from 39 to 310 exports in the server package)
  • pnpm check:all — typecheck + lint pass
  • pnpm test:all — all tests pass

Breaking Changes

None. This is a bug fix — it restores types that were intended to be exported but were missing from the built output.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

Two changes per config:

  1. Bug fix — Added the missing @modelcontextprotocol/core/public path mapping to dts.compilerOptions.paths in server/tsdown.config.ts and client/tsdown.config.ts.

  2. Prevention — Added failOnWarn: 'ci-only' to all 6 tsdown configs (server, client, and 4 middleware packages) so that DTS warnings like this will fail CI builds in the future instead of silently producing incomplete packages.

@KKonstantinov
KKonstantinov requested a review from a team as a code ownerApril 1, 2026 16:27
@felixweinberger

Copy link
Copy Markdown
Contributor

@claude review

@pkg-pr-new

pkg-pr-newBot commented Apr 1, 2026

Copy link
Copy Markdown

Open in StackBlitz

@modelcontextprotocol/client

npm i https://pkg.pr.new/@modelcontextprotocol/client@1840

@modelcontextprotocol/server

npm i https://pkg.pr.new/@modelcontextprotocol/server@1840

@modelcontextprotocol/express

npm i https://pkg.pr.new/@modelcontextprotocol/express@1840

@modelcontextprotocol/fastify

npm i https://pkg.pr.new/@modelcontextprotocol/fastify@1840

@modelcontextprotocol/hono

npm i https://pkg.pr.new/@modelcontextprotocol/hono@1840

@modelcontextprotocol/node

npm i https://pkg.pr.new/@modelcontextprotocol/node@1840

commit: fbdd299

@changeset-bot

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: fbdd299

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 6 packages
NameType
@modelcontextprotocol/expressPatch
@modelcontextprotocol/fastifyPatch
@modelcontextprotocol/honoPatch
@modelcontextprotocol/nodePatch
@modelcontextprotocol/clientPatch
@modelcontextprotocol/serverPatch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@felixweinbergerfelixweinberger 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.

verified the exports are fixed by this locally.

@felixweinberger
felixweinberger merged commit 424cbae into mainApr 1, 2026
15 checks passed
@felixweinberger
felixweinberger deleted the fix/tsdown-resolution-fix branch April 1, 2026 16:34
@github-actionsgithub-actionsBot mentioned this pull request Apr 1, 2026

@claudeclaudeBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

LGTM — the core/public path mapping fix correctly restores the missing type exports, and failOnWarn: 'ci-only' is a sensible guard against silent DTS failures going forward.

Extended reasoning...

Overview

This PR modifies six tsdown.config.ts build config files (server, client, and four middleware packages). The substantive fix adds a @modelcontextprotocol/core/public subpath entry to the dts.compilerOptions.paths override in server and client, restoring ~270 type re-exports that were previously silently dropped. The secondary change adds failOnWarn: 'ci-only' to all six configs.

Security risks

None. These are build-time TypeScript compiler configuration files with no runtime security surface.

Level of scrutiny

Low. Changes are confined to build configuration, not runtime logic. The root cause is well-explained (paths override replaces rather than merges with tsconfig paths, so the /public subpath was unmapped), and the fix is the minimal correct addition to address it. The failOnWarn addition is mechanical and clearly beneficial.

Other factors

A pre-existing bug in the four middleware configs (wrong relative depth in path mappings — ../server/ instead of ../../server/) is flagged by the inline comment but was not introduced by this PR. Per the bug report, those paths are currently dead no-ops that TypeScript silently ignores, so they do not regress functionality. The primary fix has been validated by the author with measurable output (39 → 310 exports). All tests and typechecks pass.

Comment on lines 1 to 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'],

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.

@claudeclaudeBot mentioned this pull request Jun 23, 2026
Sign up for freeto 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.

2 participants

@KKonstantinov@felixweinberger
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

v2 tsdown fix - #1840

Merged
felixweinberger merged 2 commits into
mainfrom
fix/tsdown-resolution-fix
Apr 1, 2026
Merged

v2 tsdown fix#1840
felixweinberger merged 2 commits into
mainfrom
fix/tsdown-resolution-fix

Conversation

@KKonstantinov

Copy link
Copy Markdown
Contributor

fix(build): restore missing core/public type re-exports in built packages

Motivation and Context

The tsdown DTS bundler was silently dropping all ~270 type re-exports from @modelcontextprotocol/core/public (including Tool, CallToolResult, Resource, ServerCapabilities, etc.) in the built dist/index.d.mts of both @modelcontextprotocol/server and @modelcontextprotocol/client.

Root cause: The tsdown dts.compilerOptions.paths override in server/tsdown.config.ts and client/tsdown.config.ts only mapped @modelcontextprotocol/core but not @modelcontextprotocol/core/public. Since this override replaces (not merges with) the tsconfig paths, the DTS resolver couldn't resolve the /public subpath import, causing export * from '@modelcontextprotocol/core/public' to be silently dropped. The build emitted a warning ("Failed to emit declaration file") but continued, producing packages missing most of their public API types.

How Has This Been Tested?

  • pnpm build:all — builds cleanly with no warnings (previously emitted "Failed to emit declaration file" warning)
  • Verified Tool and other core/public types appear in dist/index.d.mts export list for both server and client (went from 39 to 310 exports in the server package)
  • pnpm check:all — typecheck + lint pass
  • pnpm test:all — all tests pass

Breaking Changes

None. This is a bug fix — it restores types that were intended to be exported but were missing from the built output.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

Two changes per config:

  1. Bug fix — Added the missing @modelcontextprotocol/core/public path mapping to dts.compilerOptions.paths in server/tsdown.config.ts and client/tsdown.config.ts.

  2. Prevention — Added failOnWarn: 'ci-only' to all 6 tsdown configs (server, client, and 4 middleware packages) so that DTS warnings like this will fail CI builds in the future instead of silently producing incomplete packages.

@KKonstantinov
KKonstantinov requested a review from a team as a code ownerApril 1, 2026 16:27
@felixweinberger

Copy link
Copy Markdown
Contributor

@claude review

@pkg-pr-new

pkg-pr-newBot commented Apr 1, 2026

Copy link
Copy Markdown

Open in StackBlitz

@modelcontextprotocol/client

npm i https://pkg.pr.new/@modelcontextprotocol/client@1840

@modelcontextprotocol/server

npm i https://pkg.pr.new/@modelcontextprotocol/server@1840

@modelcontextprotocol/express

npm i https://pkg.pr.new/@modelcontextprotocol/express@1840

@modelcontextprotocol/fastify

npm i https://pkg.pr.new/@modelcontextprotocol/fastify@1840

@modelcontextprotocol/hono

npm i https://pkg.pr.new/@modelcontextprotocol/hono@1840

@modelcontextprotocol/node

npm i https://pkg.pr.new/@modelcontextprotocol/node@1840

commit: fbdd299

@changeset-bot

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: fbdd299

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 6 packages
NameType
@modelcontextprotocol/expressPatch
@modelcontextprotocol/fastifyPatch
@modelcontextprotocol/honoPatch
@modelcontextprotocol/nodePatch
@modelcontextprotocol/clientPatch
@modelcontextprotocol/serverPatch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@felixweinbergerfelixweinberger 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.

verified the exports are fixed by this locally.

@felixweinberger
felixweinberger merged commit 424cbae into mainApr 1, 2026
15 checks passed
@felixweinberger
felixweinberger deleted the fix/tsdown-resolution-fix branch April 1, 2026 16:34
@github-actionsgithub-actionsBot mentioned this pull request Apr 1, 2026

@claudeclaudeBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

LGTM — the core/public path mapping fix correctly restores the missing type exports, and failOnWarn: 'ci-only' is a sensible guard against silent DTS failures going forward.

Extended reasoning...

Overview

This PR modifies six tsdown.config.ts build config files (server, client, and four middleware packages). The substantive fix adds a @modelcontextprotocol/core/public subpath entry to the dts.compilerOptions.paths override in server and client, restoring ~270 type re-exports that were previously silently dropped. The secondary change adds failOnWarn: 'ci-only' to all six configs.

Security risks

None. These are build-time TypeScript compiler configuration files with no runtime security surface.

Level of scrutiny

Low. Changes are confined to build configuration, not runtime logic. The root cause is well-explained (paths override replaces rather than merges with tsconfig paths, so the /public subpath was unmapped), and the fix is the minimal correct addition to address it. The failOnWarn addition is mechanical and clearly beneficial.

Other factors

A pre-existing bug in the four middleware configs (wrong relative depth in path mappings — ../server/ instead of ../../server/) is flagged by the inline comment but was not introduced by this PR. Per the bug report, those paths are currently dead no-ops that TypeScript silently ignores, so they do not regress functionality. The primary fix has been validated by the author with measurable output (39 → 310 exports). All tests and typechecks pass.

Comment on lines 1 to 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'],

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.

@claudeclaudeBot mentioned this pull request Jun 23, 2026
Sign up for freeto 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.

2 participants

@KKonstantinov@felixweinberger