Skip to content

perf(startup): lazy-import SSE/HTTP transport stacks in CLI actions - #408

Merged
debugmcpdev merged 1 commit into
mainfrom
perf/400-lazy-transport-imports
Aug 22, 2026
Merged

perf(startup): lazy-import SSE/HTTP transport stacks in CLI actions#408
debugmcpdev merged 1 commit into
mainfrom
perf/400-lazy-transport-imports

Conversation

@debugmcpdev

Copy link
Copy Markdown
Collaborator

Fixes #400

stdio mode — every claude mcp add config — statically imported all three transport command modules, dragging express and the SDK's streamableHttp/sse/express stacks (body-parser, qs, send, …) into the module graph of a server that never uses them.

Change

  • src/index.ts: the SSE and HTTP command modules are now imported with await import() inside their commander action closures, so they only load when that subcommand actually runs (same pattern as check-rust-binary). The stdio command module stays static — it has no HTTP dependencies and is the default path.
  • The handleSSECommand/handleHttpCommand re-exports from index.ts are dropped. No consumers existed: tests and tooling import the command modules directly.
  • src/cli/stdio-command.ts: StdioOptions becomes an import type (it's a type-only use).

Laziness is locked in by a test

tests/unit/index-lazy-imports.test.ts mocks express with a factory that flips a flag on evaluation, imports the entry point, and asserts the flag stayed false. Before this change the test fails (express evaluates on import); after, it passes. vi.mock intercepts dynamic imports too, so the existing index.test.ts handler-closure assertions keep working unchanged.

Measured (mem-bench, this machine, Windows)

node scripts/mem-bench.mjs --target dist --scenario idle — median RSS at after-initialize, 5 trials:

RSS med peak med
main (2014358c) 108.5 MB 108.5 MB
this branch 97.4 MB 97.5 MB

−11.1 MB (−10.2%) idle stdio footprint.

Note: in the docker/npx single-file bundles the bytes still ship, but the express module graph is no longer parsed/executed on stdio startup — the win is parse/execute + heap, as scoped in the issue.

Verification

  • Full npm test green (259 files / 3947 tests), npm run lint clean
  • tests/unit/index.test.ts + tests/unit/cli/* pass unchanged

🤖 Generated with Claude Code

stdio mode (every claude mcp add config) no longer parses and instantiates
express + the SDK's streamableHttp/sse/express modules it never uses; the
sse/http command modules are imported inside their commander actions when
the subcommand actually runs (issue #400). The handler re-exports from
index.ts are dropped (no consumers; tests import the command modules
directly), and an import-graph test locks the laziness in.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@codecov

codecov Bot commented Aug 22, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 66.66667% with 2 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/index.ts 66.66% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

@debugmcpdev
debugmcpdev merged commit 74b329b into main Aug 22, 2026
8 of 9 checks passed
@debugmcpdev
debugmcpdev deleted the perf/400-lazy-transport-imports branch August 22, 2026 02:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

perf(startup): stdio mode eagerly imports express and all three transport stacks

2 participants