Skip to content

feat(compiler): warn on missing export default at build time#581

Open
lzvxck wants to merge 3 commits into
basementstudio:canaryfrom
lzvxck:feat/build-default-export-check
Open

feat(compiler): warn on missing export default at build time#581
lzvxck wants to merge 3 commits into
basementstudio:canaryfrom
lzvxck:feat/build-default-export-check

Conversation

@lzvxck

@lzvxck lzvxck commented May 29, 2026

Copy link
Copy Markdown
Contributor

Important: Please ensure your pull request is targeting the canary branch. PRs to other branches may be closed or require retargeting.

⚠️ If you are updating documentation or the site, please target the main branch instead of canary.

Summary

Adds a build-time warning when a tool, resource, or prompt file is missing export default. Without a default export the runtime destructures const { default: handler } = module and the server crashes silently when the tool is called. The warning fires inside generateCode() — before rspack bundles — so the developer sees it immediately on xmcp dev or xmcp build.

Only export default is checked. metadata and schema are intentionally not flagged: the framework defaults both, and omitting them is valid.

This is the follow-up to #560. That PR introduced a standalone xmcp validate command; the reviewer (@valebearzotti) pointed out that a separate command was unnecessary and that only the default export check mattered, hooked into the build step. This PR implements exactly that.

Type of Change

  • Bug fixing
  • Adding a feature
  • Improving documentation
  • Adding or updating examples
  • Performance - bundle size improvement (if applicable)

Affected Packages

  • xmcp (core framework)
  • create-xmcp-app
  • init-xmcp
  • Plugins
  • Documentation
  • Examples

Contributor Checklist

  • I read AGENTS.md and the scoped rules for the areas I touched.
  • I kept this PR focused on the stated change.
  • I ran the relevant build, lint, test, or example checks.
  • I updated docs and a runnable example for user-facing behavior, or explained why an example does not fit.
  • I checked REVIEW_RULES.md for logging, timers, config shape, wrappers, compiler/loader changes, and stale examples.

Docs/example note: No docs or example update — the warning message is self-documenting (⚠ src/tools/foo.ts is missing export default — tool handler required) and there is no new config, API, or CLI surface.

Screenshots/Examples

Terminal output with a tool file missing export default:

 XMCP  Starting development mode...
⚠ src/tools/no-default.ts is missing export default — tool handler required
✔ Built HTTP server
✔ Registered 3 tools, 1 prompts
✔ Compiled in 110ms

Related Issues

Closes #560

@lzvxck lzvxck requested a review from valebearzotti as a code owner May 29, 2026 12:57
@vercel

vercel Bot commented May 29, 2026

Copy link
Copy Markdown
Contributor

@lzvxck is attempting to deploy a commit to the xmcp Team on Vercel.

A member of the Team first needs to authorize it.

@0xKoller

Copy link
Copy Markdown
Contributor

Thanks for following up on #560! I think this mostly overlaps with what we already have, though, so I'd love to rescope it before merging.

Since PR #528 , the runtime already handles a missing default export, it skips the tool and warns:

[xmcp] Failed to load tool file: src/tools/foo.ts
  -> File does not export a default tool handler.

The same for prompts/resources. So there's no silent crash, and xmcp dev already surfaces this since it boots the server, including in your screenshot. The one spot it doesn't cover is xmcp build, which builds the bundle but never runs it.

My only concerns with the current approach:

  • The regex is weaker than the runtime check: it misflags export { x as default }, can match export default inside comments/strings, and can't catch a non-function default.
  • It prints a different message than the runtime does, for the same case.

Could you rescope to just the build-time coverage, and lean on the bundler's module graph (instead of a source regex) so detection + messaging stay consistent with classifyToolModule()? Per packages/AGENTS.md that'd also fit better as a compiler-plugin step than a file read in generateCode().

valebearzotti
valebearzotti previously approved these changes May 29, 2026
@lzvxck

lzvxck commented May 29, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the detailed feedback! Rescoped as requested:

  • Removed the regex-based helper (findMissingDefaultExports) and the file read in generateCode() entirely.
  • Added CheckDefaultExportsPlugin, registered in the rspack plugin array alongside InjectRuntimePlugin and CreateTypeDefinitionPlugin. It taps compiler.hooks.done and calls stats.toJson({ all: false, modules: true, providedExports: true }) to read provided exports from rspack's own module graph (FlagDependencyExportsPlugin), so export { x as default }, re-exports, and non-function defaults are all handled correctly without source scanning.
  • Only runs in production mode (xmcp build), not dev — dev is already covered by the runtime.
  • Warning message now matches the runtime exactly: [xmcp] Failed to load tool file: … -> File does not export a default tool handler.

@0xKoller

0xKoller commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

Perfect @lzvxck! One thing I’m not seeing correctly is that in the description you mention xmcp dev, while the code snippet is for development mode. Could you correct this?

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.

3 participants