# Multi-stage: esbuild produces a single Node file (deps inlined) + minified UI. # Final image has no node_modules — only dist/ + runtime Node. FROM node:20-alpine 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:20-alpine 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"]