Overview
The handful of ideas behind every NitroStack server, and how they fit together.
A NitroStack server is a set of classes that the framework wires together at startup. Once you know a few ideas, you can read any NitroStack project and know where to make a change.
Core architecture
Designed for enterprise applications, NitroStack enforces architectural best practices. Your codebase stays clean, testable, and adaptable as it scales from a single tool to a complex distributed system. Both SDKs share the same mental model (modules, controllers, providers, and a request pipeline), each with idiomatic APIs for its language.
Decorator-based design. NitroStack utilizes a descriptive, decorator-based architecture. This approach reduces boilerplate and improves readability by keeping configuration close to the implementation. Behavior such as authentication, caching, and rate limiting is applied through composable decorators, and schemas give you end-to-end type safety and runtime validation.
@Tool({
name: 'search_products',
description: 'Search product catalog with advanced filtering specification',
inputSchema: z.object({
query: z.string(),
category: z.string().optional(),
filters: z.object({
minPrice: z.number().optional(),
maxPrice: z.number().optional(),
}).optional(),
pagination: z.object({
page: z.number().default(1),
limit: z.number().default(20)
}).default({})
})
})
@UseGuards(JwtAuthGuard)
@UseMiddleware(AuditLoggingMiddleware)
@Cache({ ttl: 600, key: (input) => `search:${input.query}` })
@RateLimit({ requests: 100, window: '1h' })
@Widget('product-grid-view')
async searchProducts(input: any, ctx: ExecutionContext) {
ctx.logger.info('Executing product search', { query: input.query });
return await this.productService.executeSearch(input);
}This single declaration encapsulates API definition, validation, security, observability, performance optimization, and UI presentation layer association.
from nitrostack import injectable, tool, ExecutionContext
from pydantic import BaseModel, Field
class AddInput(BaseModel):
a: float = Field(description="First number")
b: float = Field(description="Second number")
@injectable(deps=[])
class CalculatorService:
def add(self, a: float, b: float) -> float:
return a + b
@injectable(deps=[CalculatorService])
class CalculatorController:
def __init__(self, service: CalculatorService):
self.service = service
@tool(name="add", description="Add two numbers", input_schema=AddInput)
async def add(self, input: AddInput, context: ExecutionContext) -> float:
return self.service.add(input.a, input.b)The Python SDK uses Pydantic models as input schemas. See the Python introduction.
Concepts
MCP Basics
Tools, resources, prompts, and how a request reaches your code.
Project Structure
What each file does, and what happens when the server starts.
Modules
Group a feature's tools, resources, prompts, and services.
Dependency Injection
Share services across your server without wiring them by hand.
Request Lifecycle
Guards, middleware, interceptors, and pipes, in order.
Widgets
Return interactive React UI from a tool.
Transports
STDIO and HTTP, and when to use each.
Decorators at a glance
Most of NitroStack is expressed through decorators. This table maps each one to the concept it belongs to.
| Decorator | What it does | Learn more |
|---|---|---|
@McpApp | Configures the server: name, version, transport, logging | Project Structure |
@Module | Groups a feature's classes | Modules |
@Tool, @Resource, @Prompt | Expose a method to MCP clients | MCP Basics |
@Injectable | Makes a class available for injection | Dependency Injection |
@UseGuards, @UseMiddleware, @UseInterceptors, @UsePipes, @UseFilters | Attach pipeline steps to a handler | Request Lifecycle |
@Widget | Attaches a React UI to a tool | Widgets |
For every option on every decorator, see the Decorators reference.
