# Multi-stage: esbuild produces a single Node file (deps inlined) + minified UI. # Final image has no node_modules — only dist/ + runtime Node. FROM node:22-alpine@sha256:fe4f6d74e20370acb04ad889077d14d0f64a9c8ea6a42bc60cddf1e844699914 AS build WORKDIR /app COPY package.json package-lock.json ./ RUN npm ci COPY src/ ./src/ COPY ui/ ./ui/ COPY scripts/ ./scripts/ RUN npm run build FROM node:22-alpine@sha256:fe4f6d74e20370acb04ad889077d14d0f64a9c8ea6a42bc60cddf1e844699914 WORKDIR /app ENV NODE_ENV=production # Runtime is only the bundled server + UI (no node_modules, no source, no mcp-only entry) COPY --from=build /app/dist/server.js ./dist/server.js COPY --from=build /app/dist/ui ./dist/ui EXPOSE 3001 CMD ["node", "dist/server.js"]