/templates
/starter

Starter Template (Calculator)

Time to read: 10 minutes

The beginner-friendly NitroStack template - Learn v3.0 fundamentals with a simple calculator example. Perfect for understanding the core concepts without authentication complexity.

What You'll Learn

  • v3.0 Decorators - @Tool, @Resource, @Prompt, @Module, @McpApp
  • Module Organization - How to structure a feature module
  • Input Validation - Using Zod schemas
  • UI Widgets - Creating beautiful Next.js components
  • Examples - Including request/response examples

Quick Start

# Install NitroStack CLI
npm install -g nitrostack

# Create project
nitrostack init my-calculator --template typescript-starter
cd my-calculator

# Start development
npm run dev

Opens Studio on http://localhost:3000.

Features

One Module: Calculator

A complete example showing all NitroStack features:

Tool:

  • calculate - Perform arithmetic (add, subtract, multiply, divide)

Resource:

  • calculator://operations - List all available operations

Prompt:

  • calculator_help - Get usage instructions

Widgets:

  • Calculator Result - Beautiful result display
  • Calculator Operations - Operation list viewer

No Authentication

Focus on learning the basics without auth complexity. Great for:

  • First-time users
  • Learning NitroStack fundamentals
  • Understanding the architecture
  • Building simple utilities

Project Structure

src/
ā”œā”€ā”€ modules/
│   └── calculator/
│       ā”œā”€ā”€ calculator.module.ts       # Module definition
│       ā”œā”€ā”€ calculator.tools.ts        # Tool with @Tool decorator
│       ā”œā”€ā”€ calculator.resources.ts    # Resource with @Resource
│       └── calculator.prompts.ts      # Prompt with @Prompt
ā”œā”€ā”€ widgets/
│   └── app/
│       ā”œā”€ā”€ calculator-result/         # Result widget
│       └── calculator-operations/     # Operations widget
ā”œā”€ā”€ app.module.ts                      # Root module with @McpApp
└── index.ts                           # Bootstrap

Code Examples

Tool with Examples

@Tool({
  name: 'calculate',
  description: 'Perform basic arithmetic calculations',
  inputSchema: z.object({
    operation: z.enum(['add', 'subtract', 'multiply', 'divide']),
    a: z.number().describe('First number'),
    b: z.number().describe('Second number')
  }),
  examples: {
    request: {
      operation: 'add',
      a: 5,
      b: 3
    },
    response: {
      operation: 'add',
      a: 5,
      b: 3,
      result: 8,
      expression: '5 + 3 = 8'
    }
  }
})
@Widget('calculator-result')
async calculate(input: any, ctx: ExecutionContext) {
  // Calculation logic
  return { result, expression };
}

Resource Definition

@Resource({
  uri: 'calculator://operations',
  name: 'Calculator Operations',
  description: 'List of available calculator operations',
  mimeType: 'application/json',
  examples: {
    response: {
      operations: [
        { name: 'add', symbol: '+', description: 'Addition' }
      ]
    }
  }
})
@Widget('calculator-operations')
async getOperations(uri: string, ctx: ExecutionContext) {
  const operations = [...];
  
  return {
    contents: [{
      uri,
      mimeType: 'application/json',
      text: JSON.stringify({ operations }, null, 2)
    }]
  };
}

Prompt Definition

@Prompt({
  name: 'calculator_help',
  description: 'Get help with calculator operations',
  arguments: [
    {
      name: 'operation',
      description: 'The operation to get help with (optional)',
      required: false
    }
  ]
})
async getHelp(args: any, ctx: ExecutionContext) {
  return {
    messages: [
      {
        role: 'user',
        content: { type: 'text', text: 'How do I use the calculator?' }
      },
      {
        role: 'assistant',
        content: { type: 'text', text: 'Instructions here...' }
      }
    ]
  };
}

Module Definition

@Module({
  name: 'calculator',
  description: 'Basic arithmetic calculator',
  controllers: [CalculatorTools, CalculatorResources, CalculatorPrompts]
})
export class CalculatorModule {}

Root Module

@McpApp({
  server: {
    name: 'calculator-server',
    version: '1.0.0'
  },
  logging: { level: 'info' }
})
@Module({
  imports: [
    ConfigModule.forRoot(),
    CalculatorModule
  ]
})
export class AppModule {}

Example Workflows

Basic Calculation

User: "What's 25 times 4?"
AI: Calls calculate(operation="multiply", a=25, b=4)
Result: Widget showing "25 Ɨ 4 = 100"

Get Help

User: "How do I divide numbers?"
AI: Uses calculator_help prompt with operation="divide"
Result: Instructions for division

List Operations

User: "What can this calculator do?"
AI: Fetches calculator://operations resource
Result: Widget showing all 4 operations with examples

Key Learning Points

1. Examples Are Important

The examples field in tools and resources helps:

  • AI understand how to use your tools
  • UI widgets get proper TypeScript types
  • Developers see expected input/output

2. Widgets Enhance UX

Instead of plain JSON, users see:

  • Beautiful gradients
  • Color-coded operations
  • Easy-to-read layouts

3. Decorators Reduce Boilerplate

Compare v3.0:

@Tool({ name: 'calculate' })
async calculate(input: any) { }

With v2.x (old):

server.tool(createTool({
  name: 'calculate',
  handler: async (input) => { }
}));

4. ExecutionContext is Powerful

async calculate(input: any, ctx: ExecutionContext) {
  ctx.logger.info('Calculating', { operation: input.operation });
  // ctx.auth - For authenticated requests
  // ctx.metadata - Request metadata
}

Customization Ideas

Add More Operations

Add power, square root, percentage:

operation: z.enum(['add', 'subtract', 'multiply', 'divide', 'power', 'sqrt'])

Add History

  1. Create HistoryService
  2. Store calculations in memory or file
  3. Add get_history tool
  4. Create history widget

Add Unit Converter Module

nitrostack generate module converter

Create tools for:

  • Temperature (C ↔ F)
  • Distance (km ↔ miles)
  • Weight (kg ↔ lbs)

Best Practices Demonstrated

  1. Clear Examples - Every tool has request/response examples
  2. Input Validation - Zod schemas validate all inputs
  3. Error Handling - Division by zero check
  4. Logging - ExecutionContext logger usage
  5. Type Safety - Full TypeScript throughout
  6. UI Components - Engaging widgets for all outputs
  7. Modular Code - Clean separation of concerns

When to Use This Template

Perfect for:

  • āœ… Learning NitroStack v3.0
  • āœ… Simple utilities (calculators, converters, formatters)
  • āœ… Proof of concepts
  • āœ… Teaching/demos
  • āœ… Stateless operations

Not ideal for:

  • āŒ Applications requiring authentication
  • āŒ Database-backed applications
  • āŒ Complex state management
  • āŒ Production e-commerce (use typescript-auth instead)

Next Steps

After mastering this template:

  1. E-commerce Template - Learn authentication, database, complex modules
  2. Tools Guide - Advanced tool patterns
  3. Widgets Guide - Build sophisticated UIs
  4. Dependency Injection - Services and DI

Troubleshooting

Tool Not Found

npm run build

Ensure TypeScript is compiled.

Widget Not Displaying

cd src/widgets
npm run build
cd ../..
npm run dev

Rebuild widgets and restart.

Division by Zero

The tool handles this automatically:

if (input.b === 0) {
  throw new Error('Cannot divide by zero');
}

Comparison with E-commerce Template

FeatureStarterE-commerce
ComplexitySimpleAdvanced
AuthenticationNoneJWT + Guards
DatabaseNoSQLite
Modules15
Tools120+
Learning CurveEasyModerate
Use CaseLearningProduction

Summary

The Starter Template is your first step into NitroStack v3.0:

  • āœ… Simple calculator example
  • āœ… All core features demonstrated
  • āœ… No authentication complexity
  • āœ… Beautiful UI widgets
  • āœ… Clear, commented code
  • āœ… Perfect for learning

Start here, understand the patterns, then move to the E-commerce template for production features!


Ready to Learn? Install NitroStack and create your first server!