You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Investigate migrating from unmaintained tsup to tsdown #1492
The CLI and TUI clients (and test-servers) currently bundle with tsup, which is effectively unmaintained. tsdown is the actively-maintained, Rolldown-powered successor positioned as a drop-in replacement.
Goal
Investigate why we're on tsup and evaluate migrating to tsdown.
Tasks
Inventory every place tsup is used (clients/cli, clients/tui, test-servers, any others) and the config/options each relies on.
Assess tsdown compatibility with those configs (entry points, formats, dts, externals, the @inspector/core alias, watch mode).
Prototype the migration for one client and confirm builds + tests pass.
Document findings and recommend whether/how to migrate.
Acceptance criteria
A clear recommendation on migrating to tsdown, with the migration path and any blockers identified.
Scored 6/16 with the priority rubric added to AGENTS.md in #1891. This card is already approved and sitting in Todo — only Priority was set here, its Status is unchanged.
Axis
Score
Reasoning
Severity / impact
2/5
Build tooling hygiene. tsup is effectively unmaintained but nothing is broken; this is an investigation whose outcome may legitimately be 'stay'.
Urgency / staleness
3/5
v2.2.0 milestone. No forcing function beyond the maintenance risk of sitting on an unmaintained bundler.
I tried this locally on v2/main (d0714d5) with tsdown 0.23.1 (Rolldown 1.2.13), migrating all four tsup builds: clients/cli, clients/tui, clients/mcpdo (two entries) and clients/web/tsup.runner.config.ts. All four build and --help works on each binary. The cli, mcpdo and tui test suites, scripts/verify-bundle-externals and the smoke:* scripts pass, and every package emits the same set of bare imports as with tsup. I didn't run the full web suite, pack:verify or local:gate.
The config mapping is mostly mechanical. Common shape:
The esbuild alias callbacks become a plain alias. noExternal/external become deps.alwaysBundle/deps.neverBundle (the old names still work but are deprecated). The TUI also needs inputOptions: { transform: { jsx: { runtime: "automatic" } } } and ink-form/ink-scroll-view in alwaysBundle. Shebangs are kept and tsdown sets the exec bit itself, so no banner is needed.
Gotchas, none of which fail the build:
A plain string in neverBundle only matches the exact id, so subpaths like zod/v4, @modelcontextprotocol/client/stdio and react/jsx-runtime got inlined (the CLI grew to 1.9 MB, the TUI to 2.1 MB). That's why the config adds a regex per name. tsdown prints "Detected dependencies in bundle", but the build still succeeds.
Output defaults to .mjs. fixedExtension: false keeps index.js/mcpdod.js, which e2e.test.ts, mcpdo/src/daemon/ensure.ts and pack-and-verify.mjs expect.
Rolldown keeps JSDoc comments, so the CLI bundle came out at 1.18 MB vs 877 KB with tsup. With comments: { jsdoc: false } it's 658 KB (I only checked that on the CLI).
scripts/verify-bundle-externals.mjs depends on tsup's output and config. It looks for esbuild's // path banners, but Rolldown writes //#region path, so it fails with "has no esbuild module banners". It also parses external: [ from the config text, and its test discovers tsup*.config.ts. clients/tui/__tests__/tsupConfig.test.ts imports the tsup config and its Options type. All of these need small updates, as do the config names in the tsconfig includes and in scripts/sdk-watch.mjs.
I'd migrate. The per-client change is small, and the externals guard catches the one subtle part once it understands Rolldown's region comments. Suggested order: CLI first (single entry, with an e2e test on the built binary), then the web runner and mcpdo, then the TUI (JSX plus the React externals policy test).
Activity
cliffhall commentedon Aug 1, 2026
Triage: Priority = Medium
Scored 6/16 with the priority rubric added to
AGENTS.mdin #1891. This card is already approved and sitting in Todo — only Priority was set here, its Status is unchanged.tsupis effectively unmaintained but nothing is broken; this is an investigation whose outcome may legitimately be 'stay'.Related issues. One connected issue:
Scores are a starting point, not a verdict — the rubric is meant to be overruled when it's plainly wrong, provided the reason is written down.
7 remaining items
FelixFangX commentedon Oct 20, 2026
I tried this locally on
v2/main(d0714d5) with tsdown 0.23.1 (Rolldown 1.2.13), migrating all four tsup builds:clients/cli,clients/tui,clients/mcpdo(two entries) andclients/web/tsup.runner.config.ts. All four build and--helpworks on each binary. The cli, mcpdo and tui test suites,scripts/verify-bundle-externalsand thesmoke:*scripts pass, and every package emits the same set of bare imports as with tsup. I didn't run the full web suite,pack:verifyorlocal:gate.The config mapping is mostly mechanical. Common shape:
The esbuild alias callbacks become a plain
alias.noExternal/externalbecomedeps.alwaysBundle/deps.neverBundle(the old names still work but are deprecated). The TUI also needsinputOptions: { transform: { jsx: { runtime: "automatic" } } }andink-form/ink-scroll-viewinalwaysBundle. Shebangs are kept and tsdown sets the exec bit itself, so no banner is needed.Gotchas, none of which fail the build:
neverBundleonly matches the exact id, so subpaths likezod/v4,@modelcontextprotocol/client/stdioandreact/jsx-runtimegot inlined (the CLI grew to 1.9 MB, the TUI to 2.1 MB). That's why the config adds a regex per name. tsdown prints "Detected dependencies in bundle", but the build still succeeds..mjs.fixedExtension: falsekeepsindex.js/mcpdod.js, whiche2e.test.ts,mcpdo/src/daemon/ensure.tsandpack-and-verify.mjsexpect.comments: { jsdoc: false }it's 658 KB (I only checked that on the CLI).scripts/verify-bundle-externals.mjsdepends on tsup's output and config. It looks for esbuild's// pathbanners, but Rolldown writes//#region path, so it fails with "has no esbuild module banners". It also parsesexternal: [from the config text, and its test discoverstsup*.config.ts.clients/tui/__tests__/tsupConfig.test.tsimports the tsup config and itsOptionstype. All of these need small updates, as do the config names in the tsconfig includes and inscripts/sdk-watch.mjs.I'd migrate. The per-client change is small, and the externals guard catches the one subtle part once it understands Rolldown's region comments. Suggested order: CLI first (single entry, with an e2e test on the built binary), then the web runner and mcpdo, then the TUI (JSX plus the React externals policy test).
cliffhall commentedon Oct 25, 2026
Shipped in #2803 (merged to
v2/mainas c621b99). Recommendation: migrate. The CLI is on tsdown now; the remaining builds are tracked in #2797.