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

src/index.ts
const server = await McpApplicationFactory.create(AppModule);
await server.start();

Root module Reference

src/app.module.ts
@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 = db

Tools, 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 messages

Widget 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 guards

Guard 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, OAuthGuard

Middleware 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 guards

Runtime

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 }) { /* ... */ }

Cache a result Guide

@cache(ttl=600)

Rate limit Guide

@rate_limit(max=100, window=3600)  # window in seconds

Health check Guide

@health_check(name="database")
async def check_database(self):
    ...

Events Guide

@on_event("order.created")
async def on_order(self, data):
    ...

Auth and scopes

TypeScript covers this in its own guide.

Auth modules Guide

ApiKeyModule.for_root(...)
JWTModule.for_root(...)
OAuthModule.for_root(...)

Scopes Guide

from nitrostack import has_scope, has_any_scope, has_all_scopes, require_scopes

# context.auth.aud is a list

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.

On this page