Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 23 additions & 13 deletions sample-apps/README.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,29 @@
# CrisisMesh-server
# How to submit your project — step by step

CrisisMesh is a multilingual, human-supervised emergency coordination MCP server. It helps convert voice or text emergency reports into structured SOS incidents, identifies nearby safe shelters, shares consented live location, and routes cases to a simulated dispatcher dashboard for human review. This prototype uses synthetic emergency data and does not contact real emergency services.
No special permissions needed. If you can use GitHub, you can do this:

## Getting Started
1. **Fork the repo** — open [github.com/nitrocloudofficial/nitrostack](https://github.com/nitrocloudofficial/nitrostack) and click **Fork** (top right).

```bash
npm install
npm run dev
```
2. **Clone your fork** — on your machine:

## Building for Production
```bash
git clone https://github.com/YOUR_USERNAME/nitrostack.git
```

```bash
npm run build
npm start
```
3. **Create a branch** — e.g.

Built with [NitroStack](https://nitrostack.ai) ⚡
```bash
git checkout -b add-sample-Team-Nova
```

4. **Add your project** — place your hackathon app in the `sample-apps/` folder (include a README with what it does, how to run it, and your team name). Clean up any secrets or API keys first.

5. **Commit & push**:

```bash
git add .
git commit -m "Add Team Nova MCP sample app"
git push origin add-sample-Team-Nova
```

6. **Open a Pull Request** — go to your fork on GitHub, click **Compare & pull request**, describe your project in a few sentences, and submit. We'll review and merge eligible contributions.
141 changes: 141 additions & 0 deletions sample-apps/Triage/.agents/skills/auth-security/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
---
name: nitrostack-auth-security
description: Best practices for implementing JWT, API Keys, OAuth 2.1, and RBAC in a NitroStack application.
---

## When to Use
Use this skill when configuring security modules, implementing user authentication, restricting tool access via guards, or handling sensitive tokens.

---

## 1. JSON Web Tokens (JWT)
To secure tools with JWT authentication:

### Register `JWTModule`:
```typescript
import { JWTModule, Module, McpApp } from '@nitrostack/core';

@McpApp({
server: { name: 'my-server', version: '1.0.0' }
})
@Module({
imports: [
JWTModule.forRoot({
secret: process.env.JWT_SECRET!,
expiresIn: '7d',
}),
]
})
export class AppModule {}
```

### Write a `JWTGuard`:
```typescript
import { Guard, ExecutionContext, Injectable, ConfigService } from '@nitrostack/core';
import * as jwt from 'jsonwebtoken';

@Injectable()
export class JWTGuard implements Guard {
constructor(private config: ConfigService) {}

async canActivate(context: ExecutionContext): Promise<boolean> {
const token = this.extractToken(context);
if (!token) return false;

try {
const secret = this.config.get('JWT_SECRET');
const payload = jwt.verify(token, secret) as any;
context.auth = {
subject: payload.sub,
role: payload.role,
token,
};
return true;
} catch {
return false;
}
}

private extractToken(context: ExecutionContext): string | null {
const auth = context.metadata?.authorization;
if (auth?.startsWith('Bearer ')) {
return auth.substring(7);
}
return null;
}
}
```

---

## 2. API Key Authentication
Use `ApiKeyModule` for service-to-service validation.

### Register `ApiKeyModule`:
```typescript
import { ApiKeyModule, Module } from '@nitrostack/core';

@Module({
imports: [
ApiKeyModule.forRoot({
keysEnvPrefix: 'API_KEY', // Reads API_KEY_1, API_KEY_2, etc.
headerName: 'x-api-key',
hashed: false,
}),
]
})
export class AppModule {}
```

### API Key Guard:
```typescript
import { Guard, ExecutionContext, ApiKeyModule } from '@nitrostack/core';

export class ApiKeyGuard implements Guard {
async canActivate(context: ExecutionContext): Promise<boolean> {
const apiKey = context.metadata?.['x-api-key'] || context.metadata?.apiKey;
if (!apiKey) return false;

const isValid = await ApiKeyModule.validate(apiKey as string);
if (isValid) {
context.auth = {
subject: `apikey_${(apiKey as string).substring(0, 10)}`,
scopes: ['*'],
};
return true;
}
return false;
}
}
```

---

## 3. Role-Based Access Control (RBAC)
Chain guards sequentially to implement user-role authorization.

```typescript
import { Injectable, Guard, ExecutionContext, UseGuards, Tool, z } from '@nitrostack/core';
import { JWTGuard } from './jwt.guard.js';

@Injectable()
export class AdminGuard implements Guard {
async canActivate(context: ExecutionContext): Promise<boolean> {
// Requires JWTGuard to have populated context.auth first
return context.auth?.role === 'admin';
}
}

// Applying chained guards to a tool
export class SystemTools {
@Tool({
name: 'reset_database',
description: 'Dangerous action: wipes database. Admin only.',
inputSchema: z.object({}),
})
@UseGuards(JWTGuard, AdminGuard) // Chain auth first, then role check
async resetDatabase() {
return { success: true };
}
}
```
176 changes: 176 additions & 0 deletions sample-apps/Triage/.agents/skills/mcp-app-architecture/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
---
name: nitrostack-mcp-app-architecture
description: Best practices and guidelines for bootstrapping, defining modules, using dependency injection, managing server lifecycles, and handling events in the NitroStack SDK.
---

## When to Use
Use this skill whenever you are bootstrapping a new NitroStack MCP server, creating modules, injecting services, or handling application lifecycle events.

## Bootstrapping a NitroStack App
A NitroStack application is initialized with the `@McpApp` decorator on a root class, accompanied by a root `@Module`.

```typescript
import { McpApp, Module } from '@nitrostack/core';
import { DatabaseModule } from './database/database.module.js';
import { UsersModule } from './users/users.module.js';

@McpApp({
module: AppModule,
server: {
name: 'user-management-server',
version: '1.0.0',
},
})
@Module({
imports: [DatabaseModule, UsersModule],
})
export class AppModule {}
```

## Modules
Modules organize your application structure. Use the `@Module` decorator to define imports, exports, and providers.

* **`imports`**: Other modules whose exported providers should be available in this module.
* **`providers`**: Services, tools, resources, or prompts that should be instantiated and managed by the DI container within this module.
* **`exports`**: Providers defined in this module that should be visible to other modules importing this one.

```typescript
import { Module } from '@nitrostack/core';
import { UsersService } from './users.service.js';
import { UsersTools } from './users.tools.js';

@Module({
providers: [UsersService, UsersTools],
exports: [UsersService],
})

## Controllers
Use the `@ControllerDecorator` (or alias it as `@Controller`) to group tools, resources, and prompts together. Controllers are automatically registered as singletons in the DI container.

### Key Controller Options:
* **`prefix`**: A string prefix applied to every `@Tool` defined in this controller. For example, `@ControllerDecorator('github')` prefixing a tool named `create_issue` exposes it to MCP clients as `github_create_issue`.

```typescript
import { ControllerDecorator as Controller, Tool, ExecutionContext } from '@nitrostack/core';

@Controller('github')
export class GitHubController {
@Tool({
name: 'create_issue',
description: 'Create an issue in a repository',
inputSchema: z.object({ /* ... */ })
})
async createIssue(input: any, ctx: ExecutionContext) {
// Exposed to clients as "github_create_issue"
}
}
```

## Dependency Injection (DI)
NitroStack uses a robust dependency injection container to manage class instances and lifecycles.

### Injection Lifecycles
1. **Singleton (Default)**: A single instance is shared across the entire application.
2. **Transient**: A new instance is created every time it is resolved/injected.
3. **Scoped**: A new instance is created per incoming request or context.

```typescript
import { Injectable, Scope } from '@nitrostack/core';

@Injectable({ scope: Scope.SINGLETON })
export class UsersService {
constructor(private readonly db: DatabaseService) {}

async getUser(id: string) {
return this.db.query('SELECT * FROM users WHERE id = $1', [id]);
}
}
```

## Lifecycles and Hooks
Implement NestJS-style lifecycle interfaces on modules, controllers, or providers to hook into application state changes:

* **`OnModuleInit`** (`onModuleInit`): Called after modules have initialized but before the server starts listening.
* **`OnApplicationBootstrap`** (`onApplicationBootstrap`): Called once the server is fully started and listening.
* **`OnModuleDestroy`** (`onModuleDestroy`): Called when the module or application is shutting down.
* **`BeforeApplicationShutdown`** (`beforeApplicationShutdown(signal?: string)`): Called before the application starts shutting down. Receives the OS signal (e.g. `SIGINT`).
* **`OnApplicationShutdown`** (`onApplicationShutdown(signal?: string)`): Called during shutdown. Receives the OS signal.

```typescript
import {
Injectable,
OnModuleInit,
OnApplicationBootstrap,
OnModuleDestroy,
BeforeApplicationShutdown,
OnApplicationShutdown
} from '@nitrostack/core';

@Injectable()
export class DatabaseService
implements OnModuleInit, OnApplicationBootstrap, OnModuleDestroy, BeforeApplicationShutdown, OnApplicationShutdown
{
async onModuleInit() {
await this.connect();
}

async onApplicationBootstrap() {
console.log('App ready to handle connections.');
}

async onModuleDestroy() {
await this.cleanupPendingQueries();
}

async beforeApplicationShutdown(signal?: string) {
console.log(`Shutting down soon (signal: ${signal}).`);
}

async onApplicationShutdown(signal?: string) {
await this.disconnect();
}
}
```

---

## Eventing System (`emitEvent` and `@OnEvent`)
NitroStack includes an internal eventing system to decouple components. A service or tool can emit an event using `emitEvent`, and any injectable class (like a handler service or controller) can subscribe using the `@OnEvent` decorator.

### 1. Emitting Events
Call `emitEvent` to dispatch an event payload asynchronously.

```typescript
import { Injectable, emitEvent } from '@nitrostack/core';

@Injectable()
export class SpaceShipService {
async launchShip(shipId: string) {
// Process launch...

// Dispatch event
emitEvent('ship.launched', {
shipId,
timestamp: new Date().toISOString(),
});
}
}
```

### 2. Listening to Events
Decorate a method inside any `@Injectable()` class with `@OnEvent('event_pattern')` to register it as an event handler.

```typescript
import { Injectable, OnEvent } from '@nitrostack/core';

@Injectable({ deps: [] })
export class FlightLogHandler {
@OnEvent('ship.launched')
async logLaunch(data: { shipId: string; timestamp: string }) {
console.error(`🚀 [EVENT] Ship ${data.shipId} was successfully launched at ${data.timestamp}`);
}
}
```

> [!NOTE]
> For the `@OnEvent` decorator to register properly, the containing class must be declared as a provider inside an active module.
Loading