SDK Quick Reference
The syntax you reach for most, ready to copy
The syntax you reach for most, ready to copy, for both languages. Pick TypeScript or Python in any section and the rest of the page follows. Each card links to its full guide.
TypeScript snippets assume import { ... } from '@nitrostack/core', and Python snippets assume from nitrostack import .... Install with npm install @nitrostack/core or pip install nitrostack. A Python server is configured with a .env file and ServerConfig; there is no nitro.yaml.
Server
Start the server Guide
const server = await McpApplicationFactory.create(AppModule);
await server.start();Root module Reference
@McpApp({
module: AppModule,
server: { name: 'my-server', version: '1.0.0' },
})
@Module({
name: 'app',
imports: [ConfigModule.forRoot(), ProductsModule],
})
export class AppModule {}Feature module Guide
@Module({
name: 'products',
controllers: [ProductsTools],
providers: [ProductService],
exports: [ProductService],
})
export class ProductsModule {}Service Guide
@Injectable()
export class ProductService {
async findById(id: string) { /* ... */ }
}
// Ask for it in a constructor
constructor(private products: ProductService) {}Start the server Guide
from nitrostack import McpApplicationFactory
app = await McpApplicationFactory.create(AppModule)
await app.start()Root module Guide
@module(
name="app",
imports=[ConfigModule.for_root(env_file_path=".env")],
controllers=[ProductTools],
)
class AppModule: ...
# Optional: name the server
# @mcp_app(module=AppModule, server=ServerConfig(name="my-server", version="1.0.0"))Feature module Guide
@module(
name="products",
controllers=[ProductTools],
providers=[ProductService],
exports=[ProductService],
)
class ProductsModule: ...Service Guide
@injectable(deps=[Database]) # constructor args must match deps
class ProductService:
def __init__(self, db: Database):
self.db = dbTools, resources, prompts
Tool Reference
import { ToolDecorator as Tool, z } from '@nitrostack/core';
@Tool({
name: 'get_product',
description: 'Look up a product by ID',
inputSchema: z.object({ id: z.string() }),
})
async getProduct(input: { id: string }, ctx: ExecutionContext) {
return this.products.findById(input.id);
}Resource Reference
import { ResourceDecorator as Resource } from '@nitrostack/core';
@Resource({ uri: 'docs://guide', name: 'Guide', mimeType: 'text/markdown' })
async guide(uri: string, ctx: ExecutionContext) {
return { contents: [{ uri, mimeType: 'text/markdown', text: '# Hi' }] };
}Prompt Reference
import { PromptDecorator as Prompt } from '@nitrostack/core';
@Prompt({ name: 'review_code', description: 'Ask for a code review' })
async review(args: { language: string }, ctx: ExecutionContext) {
return [{ role: 'user' as const,
content: { type: 'text' as const, text: `Review this ${args.language} code` } }];
}Widget on a tool Guide
@Tool({ name: 'show_product', description: 'Show a product' })
@Widget('product-card') // src/widgets/app/product-card/page.tsx
async showProduct(input: { id: string }, ctx: ExecutionContext) {
return this.products.findById(input.id);
}Tool Guide
from nitrostack import tool, ExecutionContext
@tool(
name="get_product",
description="Look up a product by ID",
input_schema=GetProductInput,
)
async def get_product(self, input: GetProductInput, context: ExecutionContext) -> dict:
...Resource Guide
from nitrostack import resource
@resource(
uri="docs://guide",
name="Guide",
description="The product guide",
mime_type="text/markdown",
)
async def guide(self, uri: str, context: ExecutionContext) -> dict:
...Prompt Guide
from nitrostack import prompt, PromptArgument
@prompt(
name="review_code",
description="Ask for a code review",
arguments=[PromptArgument(name="language", description="Programming language", required=True)],
)
async def review(self, args: dict, context: ExecutionContext):
... # return a list of messagesWidget on a tool Guide
@tool(name="show_product", description="Show a product", input_schema=ShowInput)
@widget("product-card") # HTML at widgets/out/product-card.html
async def show_product(self, input: ShowInput, context: ExecutionContext) -> dict:
...Request pipeline
Guard Reference
@Injectable()
export class AdminGuard implements Guard {
canActivate(ctx: ExecutionContext) {
return ctx.auth?.scopes?.includes('admin') ?? false;
}
}
@UseGuards(AdminGuard)Middleware Reference
@Middleware()
export class Timing implements MiddlewareInterface {
async use(ctx: ExecutionContext, next: () => Promise<any>) {
const start = Date.now();
const result = await next();
ctx.logger.info('done', { ms: Date.now() - start });
return result;
}
}
@UseMiddleware(Timing)Interceptor Reference
@Interceptor()
export class Wrap implements InterceptorInterface {
async intercept(ctx: ExecutionContext, next: () => Promise<any>) {
return { data: await next() };
}
}
@UseInterceptors(Wrap)Pipe Reference
@Pipe()
export class Trim implements PipeInterface {
transform(value: any, metadata: ArgumentMetadata) {
return typeof value === 'string' ? value.trim() : value;
}
}
@UsePipes(Trim)Exception filter Reference
@ExceptionFilter()
export class Errors implements ExceptionFilterInterface {
catch(exception: unknown, ctx: ExecutionContext) {
return { error: String(exception) };
}
}
@UseFilters(Errors)Execution context Reference
ctx.logger.info('message', { key: 'value' });
ctx.requestId; // trace a request
ctx.toolName; // current tool
ctx.auth?.subject; // set by guardsGuard Guide
class AdminGuard:
async def can_activate(self, context: ExecutionContext) -> bool:
return "admin" in (context.auth.scopes or [])
@use_guards(AdminGuard) # built in: ApiKeyGuard, JwtGuard, OAuthGuardMiddleware Guide
class Timing:
async def use(self, context: ExecutionContext, next_fn):
result = await next_fn()
context.logger.info("done")
return result
@use_middleware(Timing)Interceptor Guide
class Wrap:
async def intercept(self, context: ExecutionContext, next_fn):
return {"data": await next_fn()}
@use_interceptors(Wrap)Pipe Guide
class Trim:
def transform(self, value, metadata):
return value.strip() if isinstance(value, str) else value
@use_pipes(Trim)Exception filter Guide
class Errors:
def catch(self, exception, context: ExecutionContext):
return {"error": str(exception)}
@use_filters(Errors)Execution context Guide
context.logger.info("message")
context.request_id # trace a request
context.metadata # headers, authorization
context.auth # set by guardsRuntime
Cache a result Reference
@Cache({ ttl: 600, key: (input) => `search:${input.query}` })Rate limit Reference
@RateLimit({ requests: 100, window: '1h' })Health check Reference
@HealthCheck({ name: 'database' })
export class DbHealth implements HealthCheckInterface {
async check() {
return { status: 'up', message: 'Database connected' };
}
}Events Guide
emitEvent('order.created', { orderId });
@OnEvent('order.created')
async onOrder(data: { orderId: string }) { /* ... */ }Auth and scopes
TypeScript covers this in its own guide.
Tasks
TypeScript covers this in its own guide.
Long-running tools Guide
@tool(name="export", description="...", input_schema=ExportInput, task_support="optional")
async def export(self, input: ExportInput, context: ExecutionContext) -> dict:
context.task.update_progress(...)
...Testing
TypeScript covers this in its own guide.
Call your server in process Guide
from nitrostack.testing import NitroTestingModule
h = await NitroTestingModule.create(AppModule)
await h.call_tool("add", {"a": 5, "b": 10})
await h.read_resource("calc://info")
await h.get_prompt("name", {})Errors
TypeScript covers this in Error Handling.
Raise these from handlers or let the framework raise them: ToolExecutionError, ValidationError, ResourceNotFoundError, PromptNotFoundError, ConfigurationError, DependencyResolutionError, OAuthError, TokenInactiveError, AudienceMismatchError, and the task errors. See Error Handling.
Using a coding agent?
Point it at the full SDK reference for coding agents, which covers every API on one page.
