@nitrostack/cli 1.0.6 → 1.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +39 -96
- package/dist/commands/build.d.ts.map +1 -1
- package/dist/commands/build.js +4 -1
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/dev.js +24 -52
- package/dist/commands/generate-types.d.ts +0 -1
- package/dist/commands/generate-types.d.ts.map +1 -1
- package/dist/commands/generate-types.js +18 -39
- package/dist/commands/generate.d.ts.map +1 -1
- package/dist/commands/generate.js +12 -4
- package/dist/commands/init.d.ts +3 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +27 -15
- package/dist/commands/install.d.ts.map +1 -1
- package/dist/commands/install.js +3 -1
- package/dist/commands/start.d.ts.map +1 -1
- package/dist/commands/start.js +4 -4
- package/dist/commands/upgrade.d.ts.map +1 -1
- package/dist/commands/upgrade.js +92 -77
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/ui/branding.d.ts +21 -4
- package/dist/ui/branding.d.ts.map +1 -1
- package/dist/ui/branding.js +121 -52
- package/package.json +5 -6
- package/templates/typescript-oauth/.env.example +27 -0
- package/templates/typescript-oauth/README.md +36 -231
- package/templates/typescript-pizzaz/.env.example +8 -0
- package/templates/typescript-pizzaz/README.md +42 -217
- package/templates/typescript-pizzaz/src/modules/pizzaz/pizzaz.module.ts +2 -1
- package/templates/typescript-pizzaz/src/modules/pizzaz/pizzaz.tasks.ts +294 -0
- package/templates/typescript-starter/.env.example +7 -0
- package/templates/typescript-starter/README.md +51 -284
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pizzaz Task Tools
|
|
3
|
+
*
|
|
4
|
+
* Demonstrates the MCP Tasks feature — long-running, async tool execution
|
|
5
|
+
* with progress reporting and cancellation support.
|
|
6
|
+
*
|
|
7
|
+
* To test via MCP Inspector (or any MCP client that supports tasks):
|
|
8
|
+
*
|
|
9
|
+
* tools/call name="audit_pizza_shops" task={}
|
|
10
|
+
* → returns { task: { taskId, status: "working", ... } }
|
|
11
|
+
*
|
|
12
|
+
* tasks/get taskId=<id>
|
|
13
|
+
* → returns current status & progress message
|
|
14
|
+
*
|
|
15
|
+
* tasks/result taskId=<id>
|
|
16
|
+
* → blocks until done, then returns the full audit report
|
|
17
|
+
*
|
|
18
|
+
* tasks/cancel taskId=<id>
|
|
19
|
+
* → cancels the running audit
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { ToolDecorator as Tool, ExecutionContext, Injectable, z } from '@nitrostack/core';
|
|
23
|
+
import { PizzazService } from './pizzaz.service.js';
|
|
24
|
+
|
|
25
|
+
// ─── Input Schemas ─────────────────────────────────────────────────────────
|
|
26
|
+
|
|
27
|
+
const AuditSchema = z.object({
|
|
28
|
+
/** Number of shops to audit. Defaults to all shops. */
|
|
29
|
+
maxShops: z
|
|
30
|
+
.number()
|
|
31
|
+
.int()
|
|
32
|
+
.min(1)
|
|
33
|
+
.max(20)
|
|
34
|
+
.optional()
|
|
35
|
+
.describe('Maximum number of pizza shops to audit (default: all)'),
|
|
36
|
+
/** Simulate a slow audit by adding a delay per shop in ms. */
|
|
37
|
+
delayPerShopMs: z
|
|
38
|
+
.number()
|
|
39
|
+
.int()
|
|
40
|
+
.min(0)
|
|
41
|
+
.max(5000)
|
|
42
|
+
.optional()
|
|
43
|
+
.default(800)
|
|
44
|
+
.describe('Simulated processing time per shop in milliseconds (default: 800ms)'),
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
const OrderPizzaSchema = z.object({
|
|
48
|
+
shopId: z.string().describe('ID of the pizza shop to order from'),
|
|
49
|
+
pizzaName: z.string().describe('Name of the pizza to order'),
|
|
50
|
+
quantity: z.number().int().min(1).max(10).default(1).describe('Number of pizzas to order'),
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// ─── Helpers ────────────────────────────────────────────────────────────────
|
|
54
|
+
|
|
55
|
+
function sleep(ms: number): Promise<void> {
|
|
56
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Score a shop 0–100 based on rating and review count */
|
|
60
|
+
function scoreShop(shop: { rating: number; reviews: number; openNow: boolean }): number {
|
|
61
|
+
const ratingScore = (shop.rating / 5) * 60; // 60% weight
|
|
62
|
+
const reviewScore = Math.min(shop.reviews / 500, 1) * 30; // 30% weight
|
|
63
|
+
const openBonus = shop.openNow ? 10 : 0; // 10% bonus
|
|
64
|
+
return Math.round(ratingScore + reviewScore + openBonus);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function grade(score: number): string {
|
|
68
|
+
if (score >= 90) return 'A+';
|
|
69
|
+
if (score >= 80) return 'A';
|
|
70
|
+
if (score >= 70) return 'B';
|
|
71
|
+
if (score >= 60) return 'C';
|
|
72
|
+
return 'D';
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// ─── Task Tools Controller ───────────────────────────────────────────────────
|
|
76
|
+
|
|
77
|
+
@Injectable({ deps: [PizzazService] })
|
|
78
|
+
export class PizzazTaskTools {
|
|
79
|
+
constructor(private readonly pizzazService: PizzazService) { }
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* audit_pizza_shops
|
|
83
|
+
*
|
|
84
|
+
* A long-running tool that audits every pizza shop in the database.
|
|
85
|
+
* It processes each shop one-by-one (with a configurable delay) so you
|
|
86
|
+
* can watch the progress messages update via tasks/get, then fetch the
|
|
87
|
+
* full report via tasks/result.
|
|
88
|
+
*
|
|
89
|
+
* taskSupport: 'optional' — works normally (sync) OR as a task.
|
|
90
|
+
* When invoked without `task: {}`, returns the audit immediately.
|
|
91
|
+
* When invoked with `task: {}`, returns a task handle immediately and
|
|
92
|
+
* runs the audit in the background.
|
|
93
|
+
*/
|
|
94
|
+
@Tool({
|
|
95
|
+
name: 'audit_pizza_shops',
|
|
96
|
+
description:
|
|
97
|
+
'Runs a quality audit across all pizza shops. ' +
|
|
98
|
+
'This is a long-running operation — use task augmentation to run it asynchronously. ' +
|
|
99
|
+
'Pass `task: {}` in your tools/call request to get a task handle, ' +
|
|
100
|
+
'then poll with tasks/get and retrieve the report with tasks/result.',
|
|
101
|
+
inputSchema: AuditSchema,
|
|
102
|
+
taskSupport: 'optional',
|
|
103
|
+
examples: {
|
|
104
|
+
request: { maxShops: 3, delayPerShopMs: 0 },
|
|
105
|
+
response: {
|
|
106
|
+
summary: {
|
|
107
|
+
totalAudited: 3,
|
|
108
|
+
averageScore: 82,
|
|
109
|
+
topShop: 'Bella Napoli',
|
|
110
|
+
completedAt: '2025-01-01T00:00:00.000Z',
|
|
111
|
+
},
|
|
112
|
+
results: [
|
|
113
|
+
{
|
|
114
|
+
shopId: 'bella-napoli',
|
|
115
|
+
shopName: 'Bella Napoli',
|
|
116
|
+
score: 92,
|
|
117
|
+
grade: 'A+',
|
|
118
|
+
notes: 'Exceptional rating and review volume. Currently open.',
|
|
119
|
+
},
|
|
120
|
+
],
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
})
|
|
124
|
+
async auditPizzaShops(
|
|
125
|
+
args: z.infer<typeof AuditSchema>,
|
|
126
|
+
ctx: ExecutionContext,
|
|
127
|
+
) {
|
|
128
|
+
const allShops = this.pizzazService.getAllShops();
|
|
129
|
+
const shops = args.maxShops ? allShops.slice(0, args.maxShops) : allShops;
|
|
130
|
+
const delayMs = args.delayPerShopMs ?? 800;
|
|
131
|
+
|
|
132
|
+
ctx.logger.info('Starting pizza shop audit', {
|
|
133
|
+
totalShops: shops.length,
|
|
134
|
+
delayPerShopMs: delayMs,
|
|
135
|
+
isTask: !!ctx.task,
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
const results: Array<{
|
|
139
|
+
shopId: string;
|
|
140
|
+
shopName: string;
|
|
141
|
+
score: number;
|
|
142
|
+
grade: string;
|
|
143
|
+
notes: string;
|
|
144
|
+
}> = [];
|
|
145
|
+
|
|
146
|
+
for (let i = 0; i < shops.length; i++) {
|
|
147
|
+
const shop = shops[i];
|
|
148
|
+
|
|
149
|
+
// ── Cooperative cancellation check ──────────────────────────────
|
|
150
|
+
// If the client called tasks/cancel, we stop gracefully here
|
|
151
|
+
// instead of wasting time completing the rest of the audit.
|
|
152
|
+
if (ctx.task) {
|
|
153
|
+
ctx.task.throwIfCancelled();
|
|
154
|
+
ctx.task.updateProgress(
|
|
155
|
+
`🔍 Auditing "${shop.name}" (${i + 1}/${shops.length})…`,
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Simulate I/O-bound work (DB queries, external API calls, etc.)
|
|
160
|
+
await sleep(delayMs);
|
|
161
|
+
|
|
162
|
+
// Check again after the async work — client may have cancelled
|
|
163
|
+
if (ctx.task?.isCancelled) {
|
|
164
|
+
ctx.task.throwIfCancelled();
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const score = scoreShop(shop);
|
|
168
|
+
const shopGrade = grade(score);
|
|
169
|
+
|
|
170
|
+
const notes: string[] = [];
|
|
171
|
+
if (score >= 90) notes.push('Exceptional rating and review volume.');
|
|
172
|
+
if (!shop.openNow) notes.push('Currently closed — may affect customer reach.');
|
|
173
|
+
if (shop.rating >= 4.7) notes.push('One of the highest-rated shops.');
|
|
174
|
+
if (shop.reviews < 100) notes.push('Low review count — still building reputation.');
|
|
175
|
+
|
|
176
|
+
results.push({
|
|
177
|
+
shopId: shop.id,
|
|
178
|
+
shopName: shop.name,
|
|
179
|
+
score,
|
|
180
|
+
grade: shopGrade,
|
|
181
|
+
notes: notes.join(' ') || 'Solid performer.',
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
ctx.logger.info(`Audited ${shop.name}: score=${score} (${shopGrade})`);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Final progress update before completing
|
|
188
|
+
if (ctx.task) {
|
|
189
|
+
ctx.task.updateProgress(`✅ Audit complete! Compiling report for ${results.length} shops…`);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const averageScore =
|
|
193
|
+
results.length > 0
|
|
194
|
+
? Math.round(results.reduce((sum, r) => sum + r.score, 0) / results.length)
|
|
195
|
+
: 0;
|
|
196
|
+
|
|
197
|
+
const topShop = results.sort((a, b) => b.score - a.score)[0];
|
|
198
|
+
|
|
199
|
+
return {
|
|
200
|
+
summary: {
|
|
201
|
+
totalAudited: results.length,
|
|
202
|
+
averageScore,
|
|
203
|
+
topShop: topShop?.shopName ?? 'N/A',
|
|
204
|
+
completedAt: new Date().toISOString(),
|
|
205
|
+
},
|
|
206
|
+
results,
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* order_pizza
|
|
212
|
+
*
|
|
213
|
+
* A task-REQUIRED tool — it MUST always be called with task: {} because
|
|
214
|
+
* orders involve payment processing and confirmation steps that take time.
|
|
215
|
+
* This demonstrates the 'required' task support level.
|
|
216
|
+
*
|
|
217
|
+
* Invoke: tools/call name="order_pizza" task={}
|
|
218
|
+
* arguments: { shopId: "bella-napoli", pizzaName: "Margherita", quantity: 2 }
|
|
219
|
+
*/
|
|
220
|
+
@Tool({
|
|
221
|
+
name: 'order_pizza',
|
|
222
|
+
description:
|
|
223
|
+
'Places an order at a pizza shop. This tool REQUIRES task augmentation — ' +
|
|
224
|
+
'you must pass `task: {}` in your tools/call request. ' +
|
|
225
|
+
'Poll with tasks/get and retrieve your order confirmation via tasks/result.',
|
|
226
|
+
inputSchema: OrderPizzaSchema,
|
|
227
|
+
taskSupport: 'required',
|
|
228
|
+
examples: {
|
|
229
|
+
request: { shopId: 'bella-napoli', pizzaName: 'Margherita', quantity: 1 },
|
|
230
|
+
response: {
|
|
231
|
+
orderId: 'ORD-12345',
|
|
232
|
+
status: 'confirmed',
|
|
233
|
+
estimatedMinutes: 30,
|
|
234
|
+
total: '$18.00',
|
|
235
|
+
items: [{ name: 'Margherita', quantity: 1, price: '$18.00' }],
|
|
236
|
+
},
|
|
237
|
+
},
|
|
238
|
+
})
|
|
239
|
+
async orderPizza(
|
|
240
|
+
args: z.infer<typeof OrderPizzaSchema>,
|
|
241
|
+
ctx: ExecutionContext,
|
|
242
|
+
) {
|
|
243
|
+
const shop = this.pizzazService.getShopById(args.shopId);
|
|
244
|
+
if (!shop) {
|
|
245
|
+
throw new Error(`Pizza shop not found: ${args.shopId}`);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
ctx.logger.info('Processing pizza order', {
|
|
249
|
+
shopId: args.shopId,
|
|
250
|
+
pizza: args.pizzaName,
|
|
251
|
+
quantity: args.quantity,
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
// Step 1 — validate stock
|
|
255
|
+
ctx.task?.updateProgress(`🛒 Checking availability of "${args.pizzaName}" at ${shop.name}…`);
|
|
256
|
+
await sleep(600);
|
|
257
|
+
ctx.task?.throwIfCancelled();
|
|
258
|
+
|
|
259
|
+
// Step 2 — process payment
|
|
260
|
+
ctx.task?.updateProgress(`💳 Processing payment…`);
|
|
261
|
+
await sleep(1000);
|
|
262
|
+
ctx.task?.throwIfCancelled();
|
|
263
|
+
|
|
264
|
+
// Step 3 — confirm with kitchen
|
|
265
|
+
ctx.task?.updateProgress(`🍕 Confirming order with kitchen…`);
|
|
266
|
+
await sleep(700);
|
|
267
|
+
ctx.task?.throwIfCancelled();
|
|
268
|
+
|
|
269
|
+
// Step 4 — dispatch
|
|
270
|
+
ctx.task?.updateProgress(`🚴 Order dispatched! Generating confirmation…`);
|
|
271
|
+
await sleep(300);
|
|
272
|
+
|
|
273
|
+
const pricePerPizza = shop.priceLevel * 9;
|
|
274
|
+
const total = pricePerPizza * args.quantity;
|
|
275
|
+
|
|
276
|
+
ctx.logger.info('Order confirmed', { shopId: args.shopId, total });
|
|
277
|
+
|
|
278
|
+
return {
|
|
279
|
+
orderId: `ORD-${Date.now().toString(36).toUpperCase()}`,
|
|
280
|
+
status: 'confirmed',
|
|
281
|
+
shop: shop.name,
|
|
282
|
+
estimatedMinutes: 25 + Math.floor(Math.random() * 15),
|
|
283
|
+
total: `$${total.toFixed(2)}`,
|
|
284
|
+
items: [
|
|
285
|
+
{
|
|
286
|
+
name: args.pizzaName,
|
|
287
|
+
quantity: args.quantity,
|
|
288
|
+
price: `$${(pricePerPizza * args.quantity).toFixed(2)}`,
|
|
289
|
+
},
|
|
290
|
+
],
|
|
291
|
+
placedAt: new Date().toISOString(),
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# NitroStack Starter Environment
|
|
2
|
+
# =============================================================================
|
|
3
|
+
# Add your environment variables here.
|
|
4
|
+
# =============================================================================
|
|
5
|
+
|
|
6
|
+
# Example:
|
|
7
|
+
# API_KEY=your_api_key_here
|
|
@@ -1,320 +1,87 @@
|
|
|
1
|
-
# NitroStack Starter Template
|
|
1
|
+
# ⚡ NitroStack Starter Template
|
|
2
2
|
|
|
3
|
-
**The
|
|
3
|
+
**The definitive starter template** — Learn the fundamentals of the NitroStack MCP framework with a clean, well-documented calculator example.
|
|
4
4
|
|
|
5
5
|
## 🎯 What's Inside
|
|
6
6
|
|
|
7
|
-
This template
|
|
7
|
+
This template is designed to showcase core NitroStack features with zero friction:
|
|
8
8
|
|
|
9
|
-
- **
|
|
10
|
-
- **
|
|
11
|
-
- **
|
|
12
|
-
- **
|
|
13
|
-
- **
|
|
14
|
-
- **
|
|
15
|
-
- **No Database** - Pure computation example
|
|
9
|
+
- **Modular Architecture** — Clean separation of concerns with a dedicated Calculator module.
|
|
10
|
+
- **Interactive Tools** — A `calculate` tool for performing arithmetic operations.
|
|
11
|
+
- **Dynamic Resources** — A `calculator://operations` resource for discovering capabilities.
|
|
12
|
+
- **Prompt Library** — Context-aware prompts for guiding users.
|
|
13
|
+
- **Pre-built UI Widgets** — Beautiful, high-performance UI components for results and listings.
|
|
14
|
+
- **Production-Ready** — Uses TypeScript, Zod for validation, and best-in-class logging.
|
|
16
15
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
### Prerequisites
|
|
16
|
+
---
|
|
20
17
|
|
|
21
|
-
|
|
22
|
-
# Install NitroStack CLI globally
|
|
23
|
-
npm install -g nitrostack
|
|
18
|
+
## 🚀 Quick Start
|
|
24
19
|
|
|
25
|
-
|
|
26
|
-
npx nitrostack --version
|
|
27
|
-
```
|
|
20
|
+
### 1. Initialize Your Project
|
|
28
21
|
|
|
29
|
-
|
|
22
|
+
If you haven't already, scaffold your project using the NitroStack CLI:
|
|
30
23
|
|
|
31
24
|
```bash
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
cd my-calculator
|
|
35
|
-
|
|
36
|
-
# Install all dependencies (root + widgets)
|
|
37
|
-
nitrostack install
|
|
25
|
+
npx nitrostack init my-server --template typescript-starter
|
|
26
|
+
cd my-server
|
|
38
27
|
```
|
|
39
28
|
|
|
40
|
-
|
|
41
|
-
- ✅ Installs all root dependencies
|
|
42
|
-
- ✅ Installs widget dependencies
|
|
43
|
-
- ✅ Sets up the project structure
|
|
29
|
+
### 2. Install Dependencies
|
|
44
30
|
|
|
45
|
-
|
|
31
|
+
Install all project dependencies (including the visual widget SDK) in one step:
|
|
46
32
|
|
|
47
33
|
```bash
|
|
48
|
-
npm run
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
This starts:
|
|
52
|
-
- **MCP Server** (dual transport: STDIO + HTTP) - Hot reloads on code changes
|
|
53
|
-
- **Studio** on http://localhost:3000 - Visual testing environment
|
|
54
|
-
- **Widget Dev Server** on http://localhost:3001 - Hot module replacement
|
|
55
|
-
|
|
56
|
-
> 💡 **Dual Transport**: Your server exposes tools via both STDIO (for direct connections) and HTTP (for remote access). Switch between transports in Studio → Settings.
|
|
57
|
-
|
|
58
|
-
The `nitrostack dev` command handles everything automatically:
|
|
59
|
-
- ✅ Auto-detects widget directory
|
|
60
|
-
- ✅ Installs dependencies (if needed)
|
|
61
|
-
- ✅ Builds widgets (on first run)
|
|
62
|
-
- ✅ Starts all services concurrently
|
|
63
|
-
- ✅ Hot reload for TypeScript and widgets
|
|
64
|
-
|
|
65
|
-
## 📁 Project Structure
|
|
66
|
-
|
|
34
|
+
npm run install:all
|
|
67
35
|
```
|
|
68
|
-
src/
|
|
69
|
-
├── modules/
|
|
70
|
-
│ └── calculator/
|
|
71
|
-
│ ├── calculator.module.ts # @Module definition
|
|
72
|
-
│ ├── calculator.tools.ts # @Tool with examples
|
|
73
|
-
│ ├── calculator.resources.ts # @Resource
|
|
74
|
-
│ └── calculator.prompts.ts # @Prompt
|
|
75
|
-
├── widgets/ # Next.js UI widgets
|
|
76
|
-
│ └── app/
|
|
77
|
-
│ ├── calculator-result/ # Tool result widget
|
|
78
|
-
│ └── calculator-operations/ # Resource widget
|
|
79
|
-
├── app.module.ts # Root @McpApp module
|
|
80
|
-
└── index.ts # Application bootstrap
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
## 🛠️ Available Features
|
|
84
|
-
|
|
85
|
-
### Health Check: `system`
|
|
86
36
|
|
|
87
|
-
|
|
37
|
+
### 3. Get NitroStudio
|
|
88
38
|
|
|
89
|
-
|
|
90
|
-
- **Memory Usage**: Heap memory consumption
|
|
91
|
-
- **Process Info**: PID and Node.js version
|
|
92
|
-
- **Status**: `up`, `degraded`, or `down`
|
|
39
|
+
NitroStudio is the recommended visual client for running, testing, and managing your NitroStack projects.
|
|
93
40
|
|
|
94
|
-
|
|
41
|
+
1. **Download NitroStudio**: [nitrostack.ai/studio](https://nitrostack.ai/studio)
|
|
42
|
+
2. **Open Project**: Launch NitroStudio and open this project folder.
|
|
43
|
+
3. **Run**: NitroStudio handles the rest!
|
|
95
44
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
Perform basic arithmetic operations:
|
|
99
|
-
|
|
100
|
-
```typescript
|
|
101
|
-
@Tool({
|
|
102
|
-
name: 'calculate',
|
|
103
|
-
description: 'Perform basic arithmetic calculations',
|
|
104
|
-
inputSchema: z.object({
|
|
105
|
-
operation: z.enum(['add', 'subtract', 'multiply', 'divide']),
|
|
106
|
-
a: z.number(),
|
|
107
|
-
b: z.number()
|
|
108
|
-
}),
|
|
109
|
-
examples: {
|
|
110
|
-
request: { operation: 'add', a: 5, b: 3 },
|
|
111
|
-
response: { result: 8, expression: '5 + 3 = 8' }
|
|
112
|
-
}
|
|
113
|
-
})
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
**Usage:**
|
|
117
|
-
```
|
|
118
|
-
User: "Calculate 5 + 3"
|
|
119
|
-
AI: [Calls calculate tool]
|
|
120
|
-
Result: Beautiful widget showing "5 + 3 = 8"
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
### Resource: `calculator://operations`
|
|
124
|
-
|
|
125
|
-
Lists all available operations with examples.
|
|
126
|
-
|
|
127
|
-
### Prompt: `calculator_help`
|
|
128
|
-
|
|
129
|
-
Get help on how to use the calculator.
|
|
130
|
-
|
|
131
|
-
## 🎨 Widgets
|
|
132
|
-
|
|
133
|
-
### Calculator Result Widget
|
|
134
|
-
- Gradient background
|
|
135
|
-
- Operation icon
|
|
136
|
-
- Breakdown of numbers
|
|
137
|
-
- Beautiful animations
|
|
138
|
-
|
|
139
|
-
### Calculator Operations Widget
|
|
140
|
-
- Grid of all operations
|
|
141
|
-
- Color-coded by type
|
|
142
|
-
- Examples for each operation
|
|
143
|
-
|
|
144
|
-
## 💡 Learning Path
|
|
145
|
-
|
|
146
|
-
This template is perfect for learning:
|
|
45
|
+
---
|
|
147
46
|
|
|
148
|
-
|
|
149
|
-
2. **Tools** - How to create a tool with `@Tool` decorator
|
|
150
|
-
3. **Resources** - How to expose data with `@Resource`
|
|
151
|
-
4. **Prompts** - How to create conversation templates
|
|
152
|
-
5. **Widgets** - How to build UI components
|
|
153
|
-
6. **Examples** - How to include request/response examples
|
|
154
|
-
7. **Validation** - How to use Zod schemas
|
|
47
|
+
## 🛠️ Development
|
|
155
48
|
|
|
156
|
-
|
|
49
|
+
If you prefer using the command line:
|
|
157
50
|
|
|
158
51
|
```bash
|
|
159
|
-
#
|
|
160
|
-
npm
|
|
161
|
-
nitrostack install # Same as above
|
|
162
|
-
|
|
163
|
-
# Development
|
|
164
|
-
npm run dev # Start dev server with Studio
|
|
165
|
-
npm run build # Build TypeScript and widgets for production
|
|
166
|
-
npm start # Run production server
|
|
167
|
-
|
|
168
|
-
# Upgrade
|
|
169
|
-
npm run upgrade # Upgrade nitrostack to latest version
|
|
170
|
-
|
|
171
|
-
# Widget Management
|
|
172
|
-
npm run widget <command> # Run npm command in widgets directory
|
|
173
|
-
npm run widget add <pkg> # Add a widget dependency (e.g., @mui/material)
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
## 📝 Example Interactions
|
|
177
|
-
|
|
178
|
-
### Basic Calculation
|
|
179
|
-
```
|
|
180
|
-
User: "What's 12 times 8?"
|
|
181
|
-
AI: Calls calculate(operation="multiply", a=12, b=8)
|
|
182
|
-
Result: Widget showing "12 × 8 = 96"
|
|
183
|
-
```
|
|
184
|
-
|
|
185
|
-
### Get Help
|
|
186
|
-
```
|
|
187
|
-
User: "How do I use the calculator?"
|
|
188
|
-
AI: Uses calculator_help prompt
|
|
189
|
-
Result: Complete usage instructions
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
### List Operations
|
|
193
|
-
```
|
|
194
|
-
User: "What operations are available?"
|
|
195
|
-
AI: Fetches calculator://operations resource
|
|
196
|
-
Result: Widget showing all 4 operations with examples
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
## 🎓 Code Walkthrough
|
|
200
|
-
|
|
201
|
-
### 1. Tool Definition
|
|
202
|
-
|
|
203
|
-
```typescript
|
|
204
|
-
@Tool({
|
|
205
|
-
name: 'calculate',
|
|
206
|
-
description: 'Perform basic arithmetic calculations',
|
|
207
|
-
inputSchema: z.object({...}),
|
|
208
|
-
examples: {...}
|
|
209
|
-
})
|
|
210
|
-
@Widget('calculator-result') // Link UI widget
|
|
211
|
-
async calculate(input: any, ctx: ExecutionContext) {
|
|
212
|
-
// Your logic here
|
|
213
|
-
return { result, expression };
|
|
214
|
-
}
|
|
215
|
-
```
|
|
216
|
-
|
|
217
|
-
**Key Points:**
|
|
218
|
-
- `@Tool` decorator defines the tool
|
|
219
|
-
- `inputSchema` validates input with Zod
|
|
220
|
-
- `examples` help AI understand usage
|
|
221
|
-
- `@Widget` links the UI component
|
|
222
|
-
- `ExecutionContext` provides logger, metadata
|
|
223
|
-
|
|
224
|
-
### 2. Resource Definition
|
|
225
|
-
|
|
226
|
-
```typescript
|
|
227
|
-
@Resource({
|
|
228
|
-
uri: 'calculator://operations',
|
|
229
|
-
name: 'Calculator Operations',
|
|
230
|
-
mimeType: 'application/json',
|
|
231
|
-
examples: {...}
|
|
232
|
-
})
|
|
233
|
-
@Widget('calculator-operations')
|
|
234
|
-
async getOperations(uri: string, ctx: ExecutionContext) {
|
|
235
|
-
return { contents: [{...}] };
|
|
236
|
-
}
|
|
237
|
-
```
|
|
238
|
-
|
|
239
|
-
### 3. Prompt Definition
|
|
240
|
-
|
|
241
|
-
```typescript
|
|
242
|
-
@Prompt({
|
|
243
|
-
name: 'calculator_help',
|
|
244
|
-
arguments: [...]
|
|
245
|
-
})
|
|
246
|
-
async getHelp(args: any, ctx: ExecutionContext) {
|
|
247
|
-
return { messages: [...] };
|
|
248
|
-
}
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
### 4. Module Definition
|
|
252
|
-
|
|
253
|
-
```typescript
|
|
254
|
-
@Module({
|
|
255
|
-
name: 'calculator',
|
|
256
|
-
controllers: [CalculatorTools, CalculatorResources, CalculatorPrompts]
|
|
257
|
-
})
|
|
258
|
-
export class CalculatorModule {}
|
|
259
|
-
```
|
|
52
|
+
# Start development server (Server + Widgets + Studio)
|
|
53
|
+
npm run dev
|
|
260
54
|
|
|
261
|
-
|
|
55
|
+
# Build for production
|
|
56
|
+
npm run build
|
|
262
57
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
server: { name: 'calculator-server', version: '1.0.0' }
|
|
266
|
-
})
|
|
267
|
-
@Module({
|
|
268
|
-
imports: [ConfigModule.forRoot(), CalculatorModule]
|
|
269
|
-
})
|
|
270
|
-
export class AppModule {}
|
|
58
|
+
# Start production server
|
|
59
|
+
npm start
|
|
271
60
|
```
|
|
272
61
|
|
|
273
|
-
##
|
|
274
|
-
|
|
275
|
-
### Add More Operations
|
|
276
|
-
|
|
277
|
-
Edit `calculator.tools.ts` and add new operations to the enum and switch statement.
|
|
278
|
-
|
|
279
|
-
### Add History Feature
|
|
280
|
-
|
|
281
|
-
1. Create a service to store calculations
|
|
282
|
-
2. Add a `get_history` tool
|
|
283
|
-
3. Create a history widget
|
|
284
|
-
|
|
285
|
-
### Add More Modules
|
|
62
|
+
## 📁 Project Structure
|
|
286
63
|
|
|
287
|
-
```
|
|
288
|
-
|
|
64
|
+
```text
|
|
65
|
+
src/
|
|
66
|
+
├── modules/
|
|
67
|
+
│ └── calculator/
|
|
68
|
+
│ ├── calculator.module.ts # @Module definition
|
|
69
|
+
│ ├── calculator.tools.ts # @Tool implementations
|
|
70
|
+
│ ├── calculator.resources.ts # @Resource definitions
|
|
71
|
+
│ └── calculator.prompts.ts # @Prompt templates
|
|
72
|
+
├── widgets/ # Visual SDK UI components
|
|
73
|
+
├── app.module.ts # Root application module
|
|
74
|
+
└── index.ts # Server entry point
|
|
289
75
|
```
|
|
290
76
|
|
|
291
|
-
##
|
|
292
|
-
|
|
293
|
-
Once you understand this template:
|
|
294
|
-
|
|
295
|
-
1. Try the **Pizza Shop Template** - Interactive maps and widgets
|
|
296
|
-
2. Try the **Flight Booking Template** - API integration with Duffel
|
|
297
|
-
3. Read the [NitroStack Documentation](https://nitrostack.ai/docs)
|
|
77
|
+
## 🎨 Next Generation MCP
|
|
298
78
|
|
|
299
|
-
|
|
79
|
+
NitroStack is more than just a server; it's a full-stack MCP ecosystem.
|
|
300
80
|
|
|
301
|
-
- **
|
|
302
|
-
- **
|
|
303
|
-
- **
|
|
304
|
-
- **Check Examples** - The `examples` field helps AI understand your tools
|
|
305
|
-
|
|
306
|
-
## 🎉 What to Build
|
|
307
|
-
|
|
308
|
-
Use this as a starting point for:
|
|
309
|
-
|
|
310
|
-
- **Unit Converters** - Temperature, currency, etc.
|
|
311
|
-
- **Text Tools** - String manipulation, formatting
|
|
312
|
-
- **Data Processors** - JSON, CSV, XML parsing
|
|
313
|
-
- **Simple APIs** - Weather, jokes, facts
|
|
314
|
-
- **Utilities** - Date/time, UUID generation
|
|
81
|
+
- **Website**: [nitrostack.ai](https://nitrostack.ai)
|
|
82
|
+
- **Documentation**: [docs.nitrostack.ai](https://docs.nitrostack.ai)
|
|
83
|
+
- **Discord**: [Join our community](https://nitrostack.ai/discord)
|
|
315
84
|
|
|
316
85
|
---
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
Start simple, learn the patterns, then build something amazing!
|
|
86
|
+
**Happy Coding! 🎉**
|
|
87
|
+
Build something amazing with NitroStack.
|