NitroStack LogoNitroStack
/api
/decorators

Decorators API Reference

This document provides a comprehensive reference for all decorators available in NitroStack.

Table of Contents

MCP Primitives

@Tool

Defines an MCP tool that AI models can invoke.

Typescript
import { ToolDecorator as Tool, z, ExecutionContext } from '@nitrostack/core';

@Tool(options: ToolOptions)

Options:

PropertyTypeRequiredDescription
namestringYesUnique tool identifier (snake_case recommended)
titlestringNoHuman-readable display name
descriptionstringYesClear description of the tool's purpose
inputSchemaZodObjectNoZod schema for input validation
outputSchemaZodObjectNoZod schema for output validation
annotationsToolAnnotationsNoBehavioral hints for AI models
invocationToolInvocationMessagesNoUI status messages during execution
examplesobjectNoExample request/response for AI guidance and widget preview

ToolInvocationMessages:

PropertyTypeDescription
invokingstringMessage shown while tool is executing (e.g., "Loading...")
invokedstringMessage shown when tool completes (e.g., "Done")

ToolAnnotations:

PropertyTypeDefaultDescription
destructiveHintbooleantrueMay perform destructive updates
idempotentHintbooleanfalseSafe to retry with same arguments
readOnlyHintbooleanfalseDoes not modify state
openWorldHintbooleantrueMay interact with external systems

Example:

Typescript
@Tool({
  name: 'create_user',
  title: 'Create User Account',
  description: 'Create a new user account with email and profile information',
  inputSchema: z.object({
    email: z.string().email().describe('User email address'),
    name: z.string().min(2).describe('Full name'),
    role: z.enum(['user', 'admin']).optional().describe('User role')
  }),
  outputSchema: z.object({
    id: z.string(),
    email: z.string(),
    name: z.string()
  }),
  annotations: {
    destructiveHint: false,
    idempotentHint: false,
    readOnlyHint: false,
    openWorldHint: false
  },
  examples: {
    request: { email: 'user@example.com', name: 'Jane Doe' },
    response: { id: 'usr_123', email: 'user@example.com', name: 'Jane Doe' }
  }
})
async createUser(input: CreateUserInput, ctx: ExecutionContext) {
  return this.userService.create(input);
}

@Resource

Defines an MCP resource that provides data to AI models.

Typescript
import { ResourceDecorator as Resource, ExecutionContext } from '@nitrostack/core';

@Resource(options: ResourceOptions)

Options:

PropertyTypeRequiredDescription
uristringYesURI template with optional parameters
namestringYesHuman-readable resource name
titlestringNoHuman-readable display title
descriptionstringYesDescription of what data the resource provides
mimeTypestringNoContent MIME type (default: 'text/plain')
sizenumberNoSize in bytes (for binary resources)
annotationsResourceAnnotationsNoMetadata hints for clients
examplesobjectNoExample response

ResourceAnnotations:

PropertyTypeDescription
audience('user' | 'assistant')[]Who should see this resource
prioritynumberImportance (0.0-1.0, higher = more important)
lastModifiedstringISO 8601 timestamp of last modification

Example:

Typescript
@Resource({
  uri: 'user://{userId}/profile',
  name: 'User Profile',
  title: 'User Profile Details',
  description: 'Complete user profile with preferences and settings',
  mimeType: 'application/json',
  annotations: {
    audience: ['user', 'assistant'],
    priority: 0.8,
    lastModified: '2024-01-15T10:30:00Z'
  }
})
async getUserProfile(uri: string, ctx: ExecutionContext) {
  const userId = uri.match(/user:\/\/([^\/]+)/)?.[1];
  const profile = await this.userService.getProfile(userId);
  return {
    contents: [{
      uri,
      mimeType: 'application/json',
      text: JSON.stringify(profile, null, 2)
    }]
  };
}

@Prompt

Defines an MCP prompt template for AI conversations.

Typescript
import { PromptDecorator as Prompt, ExecutionContext } from '@nitrostack/core';

@Prompt(options: PromptOptions)

Options:

PropertyTypeRequiredDescription
namestringYesUnique prompt identifier
titlestringNoHuman-readable display title
descriptionstringYesDescription of the prompt's purpose
argumentsArrayNoInput parameters for the prompt

Example:

Typescript
@Prompt({
  name: 'code_review',
  title: 'Code Review Assistant',
  description: 'Generate a code review request with best practices checklist',
  arguments: [
    { name: 'language', description: 'Programming language', required: true },
    { name: 'focus', description: 'Review focus areas', required: false }
  ]
})
async getCodeReviewPrompt(args: { language: string; focus?: string }, ctx: ExecutionContext) {
  return [{
    role: 'user' as const,
    content: `Review this ${args.language} code focusing on: ${args.focus || 'general best practices'}`
  }];
}

Module System

@Module

Defines a module that groups related functionality.

Typescript
import { Module } from '@nitrostack/core';

@Module(options: ModuleOptions)

Options:

PropertyTypeRequiredDescription
namestringYesUnique module identifier
descriptionstringNoModule description
controllersClass[]NoTool, resource, and prompt classes
providersClass[]NoServices for dependency injection
importsModule[]NoModules to import
exportsClass[]NoProviders to export
globalbooleanNoIf true, providers are available globally

Example:

Typescript
@Module({
  name: 'users',
  description: 'User management module',
  controllers: [UserTools, UserResources],
  providers: [UserService, UserRepository],
  imports: [DatabaseModule],
  exports: [UserService]
})
export class UsersModule {}

@McpApp

Marks the root application module with server configuration.

Typescript
import { McpApp, Module } from '@nitrostack/core';

@McpApp(options: McpAppOptions)

Options:

PropertyTypeRequiredDescription
moduleClassYesReference to the root module class
serverobjectYesServer name and version
loggingobjectNoLogging configuration

Example:

Typescript
@McpApp({
  module: AppModule,
  server: {
    name: 'my-mcp-server',
    version: '1.0.0'
  },
  logging: {
    level: 'info'
  }
})
@Module({
  imports: [ConfigModule.forRoot(), UsersModule]
})
export class AppModule {}

Middleware Pipeline

@UseGuards

Applies guards for authentication and authorization.

Typescript
import { UseGuards } from '@nitrostack/core';

@UseGuards(...guards: GuardConstructor[])

Example:

Typescript
@Tool({ name: 'admin_action' })
@UseGuards(JWTGuard, AdminGuard)
async adminAction(input: AdminInput, ctx: ExecutionContext) {
  // Only authenticated admins can access
}

@UseMiddleware

Applies middleware for cross-cutting concerns.

Typescript
import { UseMiddleware } from '@nitrostack/core';

@UseMiddleware(...middleware: MiddlewareConstructor[])

Example:

Typescript
@Tool({ name: 'tracked_operation' })
@UseMiddleware(LoggingMiddleware, TimingMiddleware)
async trackedOperation(input: OperationInput, ctx: ExecutionContext) {
  // Middleware runs before and after
}

@UseInterceptors

Applies interceptors for response transformation.

Typescript
import { UseInterceptors } from '@nitrostack/core';

@UseInterceptors(...interceptors: InterceptorConstructor[])

Example:

Typescript
@Tool({ name: 'get_data' })
@UseInterceptors(ResponseWrapperInterceptor, DataMaskingInterceptor)
async getData(input: DataInput, ctx: ExecutionContext) {
  return { sensitiveField: 'value' };
  // Response transformed and masked by interceptors
}

@UsePipes

Applies pipes for input validation and transformation.

Typescript
import { UsePipes } from '@nitrostack/core';

@UsePipes(...pipes: PipeConstructor[])

Example:

Typescript
@Tool({ name: 'search' })
@UsePipes(TrimPipe, ValidationPipe)
async search(input: { query: string }, ctx: ExecutionContext) {
  // Input is trimmed and validated
}

@UseFilters

Applies exception filters for error handling.

Typescript
import { UseFilters } from '@nitrostack/core';

@UseFilters(...filters: ExceptionFilterConstructor[])

Example:

Typescript
@Tool({ name: 'risky_operation' })
@UseFilters(GlobalExceptionFilter)
async riskyOperation(input: RiskyInput, ctx: ExecutionContext) {
  // Errors caught and formatted by filter
}

Caching and Rate Limiting

@Cache

Caches tool responses for improved performance.

Typescript
import { Cache } from '@nitrostack/core';

@Cache(options: CacheOptions)

Options:

PropertyTypeRequiredDescription
ttlnumberYesTime to live in seconds
keyfunctionNoCustom cache key generator
invalidateOnstring[]NoEvents that invalidate the cache

Example:

Typescript
@Tool({ name: 'get_product' })
@Cache({
  ttl: 300,
  key: (input) => `product:${input.productId}`,
  invalidateOn: ['product.updated']
})
async getProduct(input: { productId: string }, ctx: ExecutionContext) {
  return this.productService.findById(input.productId);
}

@RateLimit

Limits request rate to prevent abuse.

Typescript
import { RateLimit } from '@nitrostack/core';

@RateLimit(options: RateLimitOptions)

Options:

PropertyTypeRequiredDescription
requestsnumberYesMaximum requests allowed
windowstringYesTime window ('1m', '1h', '1d')
keyfunctionNoCustom rate limit key (e.g., per-user)
messagestringNoCustom error message

Example:

Typescript
@Tool({ name: 'send_email' })
@RateLimit({
  requests: 10,
  window: '1m',
  key: (ctx) => ctx.auth?.subject || 'anonymous',
  message: 'Email rate limit exceeded. Please wait.'
})
async sendEmail(input: EmailInput, ctx: ExecutionContext) {
  return this.emailService.send(input);
}

Dependency Injection

@Injectable

Marks a class for dependency injection.

Typescript
import { Injectable } from '@nitrostack/core';

@Injectable()

Example:

Typescript
@Injectable()
export class UserService {
  constructor(
    private db: DatabaseService,
    private cache: CacheService
  ) {}

  async findById(id: string): Promise<User | null> {
    return this.db.query('SELECT * FROM users WHERE id = $1', [id]);
  }
}

@Middleware

Marks a class as middleware.

Typescript
import { Middleware, MiddlewareInterface } from '@nitrostack/core';

@Middleware()
export class LoggingMiddleware implements MiddlewareInterface {
  async use(context: ExecutionContext, next: () => Promise<any>): Promise<any> {
    // Implementation
  }
}

@Interceptor

Marks a class as an interceptor.

Typescript
import { Interceptor, InterceptorInterface } from '@nitrostack/core';

@Interceptor()
export class TransformInterceptor implements InterceptorInterface {
  async intercept(context: ExecutionContext, next: () => Promise<any>): Promise<any> {
    // Implementation
  }
}

@Pipe

Marks a class as a pipe.

Typescript
import { Pipe, PipeInterface } from '@nitrostack/core';

@Pipe()
export class ValidationPipe implements PipeInterface {
  transform(value: any, metadata?: ArgumentMetadata): any {
    // Implementation
  }
}

@ExceptionFilter

Marks a class as an exception filter.

Typescript
import { ExceptionFilter, ExceptionFilterInterface } from '@nitrostack/core';

@ExceptionFilter()
export class HttpExceptionFilter implements ExceptionFilterInterface {
  catch(exception: unknown, context: ExecutionContext): any {
    // Implementation
  }
}

UI Components

@Widget

Attaches a UI widget to a tool. The widget is a Next.js page component that renders the tool's output.

Typescript
import { Widget } from '@nitrostack/core';

@Widget(routePath: string)

Parameters:

ParameterTypeDescription
routePathstringWidget route path matching src/widgets/app/{routePath}/page.tsx

Basic Example:

Typescript
@Tool({ name: 'get_chart_data' })
@Widget('chart-visualization')
async getChartData(input: ChartInput, ctx: ExecutionContext) {
  return this.chartService.getData(input);
  // Widget at src/widgets/app/chart-visualization/page.tsx renders result
}

Complete Example with Invocation Messages:

Typescript
@Tool({
  name: 'get_dashboard',
  title: 'User Dashboard',
  description: 'Get user dashboard with stats',
  inputSchema: z.object({ userId: z.string() }),
  // Status messages shown during execution
  invocation: {
    invoking: 'Loading dashboard...',
    invoked: 'Dashboard ready'
  },
  // Example data for widget preview (IMPORTANT!)
  examples: {
    request: { userId: 'user-123' },
    response: {
      user: { name: 'John', email: 'john@example.com' },
      stats: { orders: 42, totalSpent: 1234.56 }
    }
  }
})
@Widget('user-dashboard')
async getDashboard(input: { userId: string }, ctx: ExecutionContext) {
  return { user: {...}, stats: {...} };
}

Note: The examples.response data is used by clients to render widget previews. Always provide realistic example data matching your response structure.

@HealthCheck

Defines a health check for system monitoring.

Typescript
import { HealthCheck, HealthCheckInterface } from '@nitrostack/core';

@HealthCheck(options: HealthCheckOptions)

Options:

PropertyTypeRequiredDescription
namestringYesHealth check identifier
descriptionstringNoDescription of what is checked
intervalnumberNoCheck interval in seconds

Example:

Typescript
@HealthCheck({
  name: 'database',
  description: 'Database connectivity check',
  interval: 30
})
export class DatabaseHealthCheck implements HealthCheckInterface {
  async check(): Promise<HealthCheckResult> {
    const isHealthy = await this.db.ping();
    return {
      status: isHealthy ? 'up' : 'down',
      message: isHealthy ? 'Database connected' : 'Database unreachable'
    };
  }
}

@OnEvent

Subscribes to events.

Typescript
import { OnEvent } from '@nitrostack/core';

@OnEvent(eventName: string)

Example:

Typescript
@Injectable()
export class NotificationService {
  @OnEvent('order.created')
  async handleOrderCreated(data: OrderCreatedEvent): Promise<void> {
    await this.emailService.sendOrderConfirmation(data.userId, data.orderId);
  }
}