fix(mcp): import MCP handler statically so the prod build emits it#227
Merged
Conversation
0f8b0cc to
122df63
Compare
With MCP_SERVER_ENABLED=true, lifecycle-web pods crashed at boot with "Cannot find module './src/server/mcp/handler'": ws-server.ts loaded the handler via a deferred require() that sits outside tsc's static import graph, so `tsc -p tsconfig.server.json` never emitted the module. The deferred require existed only to keep the ESM-only jose / MCP SDK off the boot path on Node < 20.19 (require(esm) support). That was valid when the MCP alphas shipped on node:20-slim, but #223 moved every build to node:22-slim before this code reached main — and the Docker image welds the Node runtime to the app code, so "MCP code on Node 20" can't occur. The workaround now guards an impossible state. Import the handler statically instead. tsc traces it through ws-server.ts's import graph and emits it normally, eliminating the build-vs-runtime gap at the root (no tsconfig "include" entry needed). The MCP_SERVER_ENABLED flag still gates whether the handler is wired up; only the module load moves to boot, which is a plain require on Node 22. Verified: tsc emits .next/src/server/mcp/handler.js via the static graph (absent before); server typecheck + lint clean.
122df63 to
5226282
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes the prod boot crash for the MCP server merged in #224. With
MCP_SERVER_ENABLED=true,lifecycle-webpods crashloop at startup:Root cause
ws-server.tsloaded the MCP handler via a deferredrequire('./src/server/mcp/handler'). Because that dynamic require is outside tsc's static import graph,tsc -p tsconfig.server.jsonnever compiled the module into.next/— so at boot the require of the never-emittedhandler.jsthrows. (Local dev viats-nodeand jest imports fromsrcboth resolve it, so only the prod build +MCP_SERVER_ENABLED=trueexposed it.)Why the deferred require is no longer needed
It existed solely to keep the ESM-only
jose/ MCP SDK off the boot path on Node < 20.19 (which can'trequire()ESM). That was a real concern when the MCP alphas shipped onnode:20-slim— but #223 moved every build tonode:22-slimbefore this code reachedmain. Since the Docker image welds the Node runtime to the app code, there is no artifact combining "MCP code + Node 20": old Node-20 images predate MCP entirely, and every MCP-carrying image is Node 22 (whererequire(esm)works). The workaround guards a state that can't occur.Fix
Import the handler statically. tsc traces it through
ws-server.ts's import graph and emits it normally, removing the build-vs-runtime gap at the root — notsconfig.server.jsonincludeentry or build-time guard needed. TheMCP_SERVER_ENABLEDflag still gates whether the handler is wired up; only the module load moves to boot (a plainrequireon Node 22). Worker / MCP-off pods now load jose+SDK at boot too — negligible on Node 22.Validation
tsc -p tsconfig.server.jsonnow emits.next/src/server/mcp/handler.js(+auth.js,server.js,truncate.js) via the static graph; confirmed absent before this change, reproducing the crash.tsconfig.server.json) exit 0;pnpm run lintclean; MCP unit tests matchmainbaseline (build/boot-path change, no test impact).Deploy: once merged, cut a fresh alpha from
mainand rolllifecycle-web— the prod realm and web env (MCP_SERVER_ENABLED,MCP_RESOURCE_URL) are already in place.