Build and Ship
Compile, run, and package your server for production.
Three commands take a project from source to production. build compiles it, start runs the server in production mode, and pack packages it for deployment. Python projects have no compile step, so they skip build, and can check the project with validate before packing it.
Build
TypeScript only. build compiles your TypeScript and bundles your widgets, ready for start or pack. A Python project runs straight from its source, so there is nothing to build.
Usage
Run it from your project folder:
nitrostack-cli build [options]Options
Every option is optional.
| Option | Description | Default |
|---|---|---|
--output <path> | Output directory for compiled JavaScript | dist |
How it works
The build runs in two steps:
- It looks for widgets. If
src/widgets/package.jsonexists, it installs the widget dependencies whennode_modulesis missing, finds each widget entry point (page.tsxorpage.jsx) undersrc/widgets/app/, and bundles it with esbuild into a standalone HTML file atsrc/widgets/out/<widget-name>.html. - It compiles your TypeScript with
npx tsc, using your project'stsconfig.json, and writes the JavaScript to the output directory.
Output
After a build, dist/ holds the compiled server and src/widgets/out/ holds one HTML file per widget:
dist/
├── index.js # Server entry point
├── app.module.js # Root application module
├── modules/ # Feature modules
└── ...
src/widgets/out/ # Standalone widget bundles (if widgets present)
├── calculator-result.html
└── ...Start
start runs your server in production mode. Unlike dev, it runs with no file watchers or development proxies, and sets NODE_ENV=production.
Usage
In a TypeScript project made by init, npm start builds first and then starts the compiled server.
npx @nitrostack/cli start [options]
# or, in a scaffolded project:
npm startBuild first
If you run start directly, make sure dist/ is current by running npm run build (or npx @nitrostack/cli build) first. Without a build, start stops and asks you to run one.
Options
Every option is optional.
| Option | Description | Default |
|---|---|---|
--port <port> | Port for the HTTP and SSE server | 3000 |
--widget <port> | Widget preview port (Python only) | 3001 |
Python servers in production
nitrostack-py start defaults MCP_TRANSPORT_TYPE to http unless you set it. Use it in Docker and cloud images, where a TypeScript image would run node dist/index.js.
Examples
Start on the default port, 3000:
nitrostack-cli startPass --port when 3000 is taken, or when your platform expects another port, as many cloud hosts and containers do:
nitrostack-cli start --port 8080In TypeScript, you can also skip the CLI and run the compiled entry point directly:
node dist/index.jsEndpoints
Over HTTP, or in dual transport, the server exposes two endpoints on the port you chose. The streamable HTTP endpoint, http://localhost:<PORT>/mcp, is the main one and takes JSON-RPC 2.0 requests such as tools/call and resources/read. The legacy SSE endpoint, http://localhost:<PORT>/sse, is for clients that need the classic Server-Sent Events handshake, such as Cursor and older MCP clients.
Validate
Python only. validate checks a project before you deploy it, and exits with code 1 if it finds an error, so it can stop a CI pipeline. It reports missing or conflicting dependencies, @mcp_app modules that fail to import, and @module() imports or exports that are not real classes. Code in the vendored SDK, vendor/nitrostack, is skipped.
nitrostack-py validatePack
pack packages your project for deployment. The TypeScript CLI creates a zip file and the Python CLI builds a wheel.
TypeScript zip
The TypeScript pack creates a zip file for deployment, building a container image, or sending to NitroCloud. It leaves out build artifacts, dependencies, and secrets, and keeps your .gitignore in line with NitroStack's canonical rules.
Usage
npx @nitrostack/cli pack [options]
# or:
nitrostack-cli pack [options]
# or standalone:
nitrostack-pack [options]Options
Every option is optional.
| Option | Shorthand | Description | Default |
|---|---|---|---|
--output <path> | -o | Zip filename, saved to the project root | <project-name>.zip |
--dry-run | Preview what is included and excluded without creating the zip | false | |
--include-env | Include .env files in the zip (use with caution) | false | |
--no-sync-gitignore | Skip merging NitroStack's canonical ignore rules into .gitignore | false | |
--cwd <dir> | Project directory | Current directory |
What is left out
To keep the archive small and protect your credentials, pack excludes node_modules/, build output (dist/, .next/, build/, out/), environment files (.env, .env.local, .env.production, unless you pass --include-env), version control folders (.git/, .github/), and logs and operating system files (*.log, .DS_Store, Thumbs.db).
Examples
Create a clean archive. The zip is saved in the project root as my-mcp-server.zip:
nitrostack-cli packPreview what would be included before packing:
nitrostack-cli pack --dry-runChoose the name of the zip file:
nitrostack-cli pack -o production-build.zipPython wheel
The Python pack builds a wheel in dist/ with setuptools, the same build backend as the SDK. It refreshes requirements.txt from pyproject.toml when it can, always includes .env.example, and deletes its temporary build folders afterwards. Real .env, .env.local, and .env.production files are left out unless you pass --include-env.
nitrostack-py pack --dry-run # list the files; write nothing
nitrostack-py pack # write dist/*.whl
nitrostack-py pack --include-env # also pack .env files (use with caution)