E-commerce Server Template
Time to read: 20 minutes
The official NitroStack template - A production-ready e-commerce MCP server showcasing v3.0 decorator-based architecture with authentication, database, and comprehensive UI widgets.
What You'll Learn
- v3.0 Architecture - Decorator-based development with
@Tool,@Module,@McpApp - JWT Authentication - Secure user authentication with guards
- SQLite Database - Embedded database with DI
- UI Widgets - Beautiful Next.js components
- Production Patterns - Middleware, interceptors, caching, rate limiting
Quick Start
# Install NitroStack CLI
npm install -g nitrostack
# Create project
nitrostack init my-store --template typescript-auth
cd my-store
# Setup database
npm run setup-db
# Start development
npm run dev
The server starts with Studio on http://localhost:3000.
Features Overview
š Authentication System
- JWT Tokens - Secure authentication with
JWTModule - Login/Logout - User management tools
- Guards -
@UseGuards(JWTGuard)for protected tools - Token Storage - Automatic browser storage
š¾ Database Layer
- SQLite - Embedded database with
better-sqlite3 - Seed Data - Pre-populated sample data
- DI Integration -
DatabaseServiceinjected everywhere - Tables: Users, Products, Cart, Orders, Addresses
š ļø Tools (20+)
All tools use decorator-based patterns with proper input validation and examples.
Public Tools:
browse_products- Browse product catalog with cachingget_categories- View product categoriesget_product- Get product detailssearch_products- Search products by querylogin- User authentication
Authenticated Tools (require @UseGuards(JWTGuard)):
whoami- Get current user profileadd_to_cart- Add products to cartget_cart- View shopping cartupdate_cart_item- Update cart item quantityremove_cart_item- Remove item from cartclear_cart- Empty entire cartget_addresses- View saved addressesadd_address- Add delivery addressupdate_address- Update existing addressset_default_address- Set default addressdelete_address- Remove addresscreate_order- Place order from cartget_orders- View order historyget_order_details- View specific order
šØ UI Widgets
Every tool has a beautifully designed Next.js widget with:
- Product grids with images and prices
- Shopping cart with item management
- Order confirmations and history
- Address management forms
- Login/logout UI
- User profile cards
- Inline styles from
ecommerce.ts
Project Structure (v3.0)
src/
āāā app.module.ts # Root @McpApp module
āāā index.ts # Application bootstrap
āāā modules/ # Feature modules
ā āāā auth/
ā ā āāā auth.module.ts # @Module definition
ā ā āāā auth.tools.ts # @Tool decorators
ā ā āāā auth.resources.ts # @Resource decorators
ā ā āāā auth.prompts.ts # @Prompt decorators
ā āāā products/
ā ā āāā products.module.ts
ā ā āāā products.tools.ts # With @Cache
ā ā āāā products.resources.ts
ā ā āāā products.prompts.ts
ā āāā cart/
ā ā āāā cart.module.ts
ā ā āāā cart.tools.ts # With @UseGuards
ā ā āāā cart.resources.ts
ā ā āāā cart.prompts.ts
ā āāā orders/
ā ā āāā ... (similar structure)
ā āāā addresses/
ā āāā ... (similar structure)
āāā services/
ā āāā database.service.ts # @Injectable service
āāā guards/
ā āāā jwt.guard.ts # JWT authentication guard
āāā middleware/
ā āāā logging.middleware.ts # @Middleware decorator
āāā interceptors/
ā āāā transform.interceptor.ts # @Interceptor decorator
āāā pipes/
ā āāā validation.pipe.ts # @Pipe for validation
āāā filters/
ā āāā global-exception.filter.ts # @ExceptionFilter
āāā health/
ā āāā database.health.ts # @HealthCheck
āāā events/
ā āāā analytics.service.ts # @OnEvent listeners
ā āāā notification.service.ts
āāā db/
ā āāā database.ts # Database setup
ā āāā seed.ts # Sample data
ā āāā setup.ts # DB initialization
āāā widgets/ # Next.js UI widgets
āāā app/
ā āāā whoami/
ā āāā products-grid/
ā āāā product-card/
ā āāā cart/
ā āāā order-confirmation/
ā āāā ... (20+ widgets)
āāā styles/
ā āāā ecommerce.ts # Shared inline styles
āāā types/
āāā tool-data.ts # Generated types
v3.0 Architecture Examples
Tool with Decorators
// src/modules/products/products.tools.ts
import { Tool, Widget, Cache, ExecutionContext } from 'nitrostack';
import { z } from 'zod';
export class ProductsTools {
constructor(
private productService: ProductService // DI
) {}
@Tool({
name: 'browse_products',
description: 'Browse products with optional filters',
inputSchema: z.object({
category: z.string().optional(),
page: z.number().default(1),
limit: z.number().default(10)
}),
examples: {
request: { category: 'Electronics', page: 1, limit: 10 },
response: {
products: [
{ id: 'p1', name: 'Laptop', price: 999, image_url: '...' }
],
total: 50,
page: 1
}
}
})
@Widget('products-grid')
@Cache({ ttl: 300 }) // Cache for 5 minutes
async browseProducts(input: any, ctx: ExecutionContext) {
ctx.logger.info('Browsing products', { category: input.category });
const products = await this.productService.browse({
category: input.category,
limit: input.limit,
offset: (input.page - 1) * input.limit
});
return {
products,
total: await this.productService.count(input.category),
page: input.page
};
}
}
Module with DI
// src/modules/products/products.module.ts
import { Module } from 'nitrostack';
import { ProductsTools } from './products.tools.js';
import { ProductsResources } from './products.resources.js';
import { ProductsPrompts } from './products.prompts.js';
import { ProductService } from './product.service.js';
@Module({
name: 'products',
description: 'Product catalog management',
controllers: [ProductsTools, ProductsResources, ProductsPrompts],
providers: [ProductService],
exports: [ProductService]
})
export class ProductsModule {}
Guard for Authentication
// src/guards/jwt.guard.ts
import { Guard, ExecutionContext, Injectable } from 'nitrostack';
import jwt from 'jsonwebtoken';
@Injectable()
export class JWTGuard implements Guard {
async canActivate(context: ExecutionContext): Promise<boolean> {
const token = this.extractToken(context);
if (!token) return false;
try {
const payload = jwt.verify(token, process.env.JWT_SECRET);
context.auth = { subject: payload.sub, email: payload.email };
return true;
} catch {
return false;
}
}
private extractToken(context: ExecutionContext): string | null {
return context.metadata?.authorization?.substring(7) || null;
}
}
Protected Tool
@Tool({
name: 'add_to_cart',
description: 'Add a product to shopping cart',
inputSchema: z.object({
product_id: z.string(),
quantity: z.number().min(1).default(1)
})
})
@UseGuards(JWTGuard) // Requires authentication
@Widget('add-to-cart')
async addToCart(input: any, ctx: ExecutionContext) {
const userId = ctx.auth?.subject; // From guard
await this.cartService.addItem({
userId,
productId: input.product_id,
quantity: input.quantity
});
return await this.cartService.getCart(userId);
}
Application Bootstrap
// src/app.module.ts
import { McpApp, Module } from 'nitrostack';
import { ConfigModule } from 'nitrostack';
import { JWTModule } from 'nitrostack';
import { ProductsModule } from './modules/products/products.module.js';
import { CartModule } from './modules/cart/cart.module.js';
// ... other modules
@McpApp({
server: {
name: 'ecommerce-server',
version: '3.0.0'
},
logging: {
level: 'info'
}
})
@Module({
imports: [
ConfigModule.forRoot(),
JWTModule.forRoot({
secret: process.env.JWT_SECRET,
expiresIn: '24h'
}),
ProductsModule,
CartModule,
OrdersModule,
AddressesModule,
AuthModule
],
providers: [DatabaseService],
globalMiddleware: [LoggingMiddleware],
globalInterceptors: [TransformInterceptor],
globalFilters: [GlobalExceptionFilter]
})
export class AppModule {}
Authentication Flow
1. Login
User: "Login as emily.johnson@x.dummyjson.com with password123"
LLM: [Calls login tool]
Result: JWT token saved in browser, user profile displayed
2. Protected Operations
User: "Add the laptop to my cart"
LLM: [Calls add_to_cart with JWT token]
Guard: Validates token, extracts user ID
Result: Cart updated, widget displayed
3. Order Placement
User: "Place an order"
LLM: [Calls create_order with JWT token]
Result: Order created, cart cleared, confirmation displayed
Database Schema
Users
CREATE TABLE users (
id TEXT PRIMARY KEY,
email TEXT UNIQUE NOT NULL,
password_hash TEXT NOT NULL,
name TEXT NOT NULL,
avatar_url TEXT,
created_at INTEGER NOT NULL
);
Products
CREATE TABLE products (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
description TEXT,
price REAL NOT NULL,
category TEXT NOT NULL,
image_url TEXT,
in_stock INTEGER DEFAULT 1
);
Cart Items
CREATE TABLE cart_items (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL,
product_id TEXT NOT NULL,
quantity INTEGER NOT NULL,
added_at INTEGER NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(id),
FOREIGN KEY (product_id) REFERENCES products(id)
);
Full schema includes Orders, Order Items, and Addresses tables.
Example Workflows
Browse & Purchase
User: "Show me laptops"
LLM: [browse_products category=Electronics]
ā Products grid widget with 10 laptops
User: "Add the Dell XPS to my cart"
LLM: [add_to_cart product_id=p1, quantity=1]
ā Cart widget showing 1 item
User: "Checkout"
LLM: [create_order]
ā Order confirmation widget
Manage Cart
User: "What's in my cart?"
LLM: [get_cart]
ā Cart widget with items, quantities, total
User: "Change laptop quantity to 2"
LLM: [update_cart_item item_id=c1, quantity=2]
ā Updated cart widget
User: "Remove the mouse from cart"
LLM: [remove_cart_item item_id=c2]
ā Updated cart widget
Advanced Features Demonstrated
1. Caching
@Tool({ name: 'browse_products' })
@Cache({ ttl: 300, key: (input) => `products:${input.category}` })
async browseProducts(input: any) {
// Results cached for 5 minutes per category
}
2. Rate Limiting
@Tool({ name: 'create_order' })
@RateLimit({ requests: 10, window: '1h', key: (ctx) => ctx.auth?.subject })
async createOrder(input: any, ctx: ExecutionContext) {
// Max 10 orders per hour per user
}
3. Event System
@Tool({ name: 'create_order' })
async createOrder(input: any, ctx: ExecutionContext) {
const order = await this.orderService.create(input);
// Emit event
ctx.emit('order.created', { orderId: order.id, userId: ctx.auth?.subject });
return order;
}
// In analytics service
@OnEvent('order.created')
async handleOrderCreated(data: any) {
await this.analyticsService.track('order_created', data);
}
4. Health Checks
@HealthCheck('database')
async checkDatabase() {
try {
await this.db.queryOne('SELECT 1');
return { status: 'healthy' };
} catch (error) {
return { status: 'unhealthy', error: error.message };
}
}
Testing Accounts
Pre-seeded users for testing:
emily.johnson@x.dummyjson.com / password123
michael.chen@x.dummyjson.com / password123
sarah.williams@x.dummyjson.com / password123
All accounts have sample orders and addresses.
Customization
Add New Module
nitrostack generate module reviews
Creates:
src/modules/reviews/reviews.module.tssrc/modules/reviews/reviews.tools.tssrc/modules/reviews/reviews.resources.tssrc/modules/reviews/reviews.prompts.tssrc/modules/reviews/reviews.service.ts
Add Payment Processing
import Stripe from 'stripe';
@Injectable()
export class PaymentService {
private stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
async processPayment(amount: number, token: string) {
return await this.stripe.charges.create({
amount: Math.round(amount * 100),
currency: 'usd',
source: token
});
}
}
Generate Types for Widgets
nitrostack generate types
Creates src/widgets/types/tool-data.ts with TypeScript interfaces from Zod schemas.
Best Practices Demonstrated
- Decorator-Based Architecture - Modern, declarative code
- Dependency Injection - Loose coupling, easy testing
- Module Organization - Clear feature boundaries
- Guard System - Declarative authentication
- Input Validation - Zod schemas for all inputs
- Error Handling - Global exception filter
- Type Safety - Full TypeScript with generated types
- UI Widgets - Rich user experience
- Caching - Performance optimization
- Events - Decoupled architecture
Production Deployment
Environment Variables
NODE_ENV=production
JWT_SECRET=your-super-secret-key-change-this
DATABASE_PATH=./data/ecommerce.db
PORT=3000
Build & Deploy
npm run build
npm start
Docker Deployment
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --production
COPY dist ./dist
COPY data ./data
CMD ["node", "dist/index.js"]
Next Steps
- Authentication Overview - Deep dive into JWT, OAuth, API Keys
- Caching Guide - Performance optimization
- Rate Limiting Guide - Protect your API
- Deployment Checklist - Go to production
Pro Tip: This template is a complete starting point. Customize it for your use case - replace products with articles for a CMS, tasks for a project manager, or services for a booking system!