@ductape/mcp 0.1.42 → 0.1.44

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/dist/index.js CHANGED
@@ -180,20 +180,33 @@ global interceptors, decorators, and type-safe resource handles.
180
180
 
181
181
  SETUP — register once in AppModule:
182
182
 
183
+ ╔══════════════════════════════════════════════════════════════════════════╗
184
+ ║ redisUrl IS REQUIRED TO USE ANY *.dispatch() ║
185
+ ║ ║
186
+ ║ Every dispatch() call (actions, features, events, databases, storage, ║
187
+ ║ graph, notifications, messageBrokers, quotas, fallback) enqueues jobs ║
188
+ ║ via BullMQ over Redis. Without redisUrl the call throws at runtime: ║
189
+ ║ "Queues not configured. dispatch() requires a queue connection." ║
190
+ ║ ║
191
+ ║ *.run(), events.produce(), and @Events.Consumer do NOT need Redis. ║
192
+ ║ Only dispatch() does — and it is non-negotiable. ║
193
+ ╚══════════════════════════════════════════════════════════════════════════╝
194
+
183
195
  import { DuctapeModule } from '@ductape/nestjs';
184
196
 
185
197
  @Module({
186
198
  imports: [
187
199
  DuctapeModule.forIntegration({
188
200
  accessKey: process.env.DUCTAPE_ACCESS_KEY,
189
- product: 'my-product', // optional default — overridable per controller
201
+ product: 'my-product',
190
202
  env: process.env.NODE_ENV === 'production' ? 'prd' : 'snd',
203
+ redisUrl: process.env.DUCTAPE_REDIS_URL, // required — no dispatch() works without this
191
204
  }),
192
205
  ],
193
206
  })
194
207
  export class AppModule {}
195
208
 
196
- // Async (e.g. pulling key from ConfigService):
209
+ // Async (e.g. pulling from ConfigService):
197
210
  DuctapeModule.forRootAsync({
198
211
  imports: [ConfigModule],
199
212
  inject: [ConfigService],
@@ -201,9 +214,14 @@ SETUP — register once in AppModule:
201
214
  accessKey: cfg.get('DUCTAPE_ACCESS_KEY'),
202
215
  product: cfg.get('DUCTAPE_PRODUCT'),
203
216
  env: cfg.get('DUCTAPE_ENV'),
217
+ redisUrl: cfg.get('DUCTAPE_REDIS_URL'), // required — no dispatch() works without this
204
218
  }),
205
219
  })
206
220
 
221
+ Environment variable (add to .env and deployment secrets):
222
+ DUCTAPE_REDIS_URL=redis://localhost:6379 # local dev
223
+ DUCTAPE_REDIS_URL=rediss://:<password>@host:6380 # managed Redis (TLS)
224
+
207
225
  INJECTING IN SERVICES AND CONTROLLERS — use @InjectContext():
208
226
 
209
227
  import { InjectContext, DuctapeContext } from '@ductape/nestjs';
@@ -258,7 +276,7 @@ FOR MESSAGING (events.produce / events.consume / events.dispatch):
258
276
  @Events.Produce({ event: 'broker-tag:topic-tag' })
259
277
  emitOrderCreated(payload: { orderId: string }) { return payload; }
260
278
 
261
- Dispatch (scheduled or immediate) — static schedule in decorator:
279
+ Dispatch (scheduled or immediate) — dispatch() CANNOT be used without redisUrl in forIntegration:
262
280
  @Events.Dispatch({ broker: 'order-events', event: 'order-events:order-created', schedule: { every: 60000 } })
263
281
  dispatchHeartbeat(payload: { message: { ping: boolean } }) { return payload; }
264
282
 
@@ -273,6 +291,7 @@ FOR MESSAGING (events.produce / events.consume / events.dispatch):
273
291
  }
274
292
  // method return takes precedence over decorator schedule; use sdk.events.dispatch() directly
275
293
  // when even the broker/event must vary at call time.
294
+ // ALL *.dispatch() calls require redisUrl — BullMQ over Redis. Without it dispatch throws.
276
295
 
277
296
  Consume (method decorator — method is called for each incoming message):
278
297
  @Events.Consumer({ event: 'order-events:order-created' })
@@ -332,7 +351,7 @@ ALL params are passed as a JSON array in positional order matching the SDK signa
332
351
  actions.fetch [app_tag, action_tag]
333
352
  actions.list [app_tag]
334
353
  actions.run [{ product, env, app, action, input: { "body:fieldName": value, ... } }] ← CALL ductape_generate_payload FIRST (operation_family="action", method="run", targets={app, action})
335
- actions.dispatch [{ product, env, app, action, input, retries?, session?, cache?, schedule?: { start_at?, cron?, every?, limit?, tz? } }] ← CALL ductape_generate_payload FIRST (operation_family="action", method="dispatch")
354
+ actions.dispatch [{ product, env, app, action, input, retries?, session?, cache?, schedule?: { start_at?, cron?, every?, limit?, tz? } }] ← CALL ductape_generate_payload FIRST (operation_family="action", method="dispatch") — requires redisUrl in ductape initialization
336
355
 
337
356
  ━━━ MODULE: auths ━━━
338
357
  auths.create [app_tag, data: { tag: string, name: string, setup_type: "header"|"bearer"|"basic"|"oauth2"|"apikey", expiry: number, period: "seconds"|"minutes"|"hours"|"days", description: string, action_tag?: string }]
@@ -410,7 +429,7 @@ ALL params are passed as a JSON array in positional order matching the SDK signa
410
429
  quotas.list [product_tag]
411
430
  quotas.delete [product_tag, quota_tag]
412
431
  quotas.run [{ product: string, env: string, tag: string, input: { fieldName: value }, session?: string, cache?: string }] ← CALL ductape_generate_payload FIRST (operation_family="quota", method="run", targets={tag})
413
- quotas.dispatch [{ product: string, env: string, tag: string, input: object, session?: string, cache?: string, schedule?: { cron?: string, delay?: number, at?: string } }] ← CALL ductape_generate_payload FIRST (operation_family="quota", method="dispatch")
432
+ quotas.dispatch [{ product: string, env: string, tag: string, input: object, session?: string, cache?: string, schedule?: { cron?: string, delay?: number, at?: string } }] ← CALL ductape_generate_payload FIRST (operation_family="quota", method="dispatch") — requires redisUrl in ductape initialization
414
433
 
415
434
  ━━━ MODULE: fallback ━━━
416
435
  fallback.create [product_tag, data: {
@@ -453,7 +472,7 @@ ALL params are passed as a JSON array in positional order matching the SDK signa
453
472
  fallback.list [product_tag]
454
473
  fallback.delete [product_tag, fallback_tag]
455
474
  fallback.run [{ product: string, env: string, tag: string, input: { fieldName: value }, session?: string, cache?: string }] ← CALL ductape_generate_payload FIRST (operation_family="fallback", method="run", targets={tag})
456
- fallback.dispatch [{ product: string, env: string, tag: string, input: object, session?: string, cache?: string, schedule?: { cron?: string, delay?: number, at?: string } }] ← CALL ductape_generate_payload FIRST (operation_family="fallback", method="dispatch")
475
+ fallback.dispatch [{ product: string, env: string, tag: string, input: object, session?: string, cache?: string, schedule?: { cron?: string, delay?: number, at?: string } }] ← CALL ductape_generate_payload FIRST (operation_family="fallback", method="dispatch") — requires redisUrl in ductape initialization
457
476
 
458
477
  ━━━ MODULE: health ━━━
459
478
  health.create [product_tag, data: { tag: string, name: string, description?: string, app?: string, event?: string, probe?: { type: "app"|"database"|"feature", app?: string, event?: string, input?: object }, interval: number, retries: number, envs: [{ slug: string, input?: object }], onFailure?: { notifications?: [{ notification: string, message: string, channels: { email?: { recipients: string[] }, push?: { recipients?: string[] }, sms?: { recipients: string[] } } }], webhooks?: [{ url: string, method?: "GET"|"POST", headers?: object, body?: object }] } }]
@@ -480,7 +499,7 @@ ALL params are passed as a JSON array in positional order matching the SDK signa
480
499
  notifications.push.send [{ product, env, notification, input: { ... }, session?, cache? }] ← CALL ductape_generate_payload FIRST (operation_family="notification", method="push.send")
481
500
  notifications.sms.send [{ product, env, notification, input: { ... }, session?, cache? }] ← CALL ductape_generate_payload FIRST (operation_family="notification", method="sms.send")
482
501
  notifications.callback.send [{ product, env, notification, input: { ... }, session?, cache? }] ← CALL ductape_generate_payload FIRST (operation_family="notification", method="callback.send")
483
- notifications.dispatch [{ product, env, notification, event, input, retries?, session?, cache?, schedule?: { cron?, every?, start_at? } }] ← CALL ductape_generate_payload FIRST (operation_family="notification", method="dispatch")
502
+ notifications.dispatch [{ product, env, notification, event, input, retries?, session?, cache?, schedule?: { cron?, every?, start_at? } }] ← CALL ductape_generate_payload FIRST (operation_family="notification", method="dispatch") — requires redisUrl in ductape initialization
484
503
  notifications.getMessages [{ product_tag?, env?, notification_tag?, status?, type?, start_date?, end_date?, page?, limit? }]
485
504
 
486
505
  ━━━ MODULE: messageBrokers ━━━
@@ -491,7 +510,7 @@ ALL params are passed as a JSON array in positional order matching the SDK signa
491
510
  messageBrokers.delete [product_tag, broker_tag]
492
511
  messageBrokers.topics.create ← FORBIDDEN with publishable key. Use ductape_cli instead:
493
512
  ductape_cli("events topics create -f topic.json")
494
- topic.json: { tag, name, broker, description?, sample?, idempotent?, queueUrls?: [{ env_slug, url }] }
513
+ topic.json: { tag: "broker-tag:topic-tag", name, description?, sample?, idempotent?, queueUrls?: [{ env_slug, url }] }
495
514
  ← Always required before consuming. For SQS: must include queueUrls per env.
496
515
  ← For Pub/Sub, Kafka, RabbitMQ, Redis, NATS: the first produce call auto-registers the topic,
497
516
  but you should still create it explicitly so consumers can subscribe before any produce occurs.
@@ -503,7 +522,7 @@ ALL params are passed as a JSON array in positional order matching the SDK signa
503
522
  messageBrokers.topics.list [product_tag, broker_tag] ← safe via ductape_execute
504
523
  messageBrokers.produce [{ product, env, event: "broker_tag:topic_tag", message: { key: value }, session?, cache? }]
505
524
  messageBrokers.consume [{ product, env, event: "broker_tag:topic_tag", callback: "function_ref" }]
506
- messageBrokers.dispatch [{ product, env, broker, event, input: { message }, retries?, session?, cache?, schedule?: { cron?, every?, start_at? } }]
525
+ messageBrokers.dispatch [{ product, env, broker, event, input: { message }, retries?, session?, cache?, schedule?: { cron?, every?, start_at? } }] — requires redisUrl in ductape initialization
507
526
  messageBrokers.messages.query [{ product, env, brokerTag, topicTag?, producerTag?, consumerTag?, status?, startDate?, endDate?, page?, limit? }]
508
527
  messageBrokers.messages.getProducers [{ product, env, brokerTag, topicTag?, page?, limit? }]
509
528
  messageBrokers.messages.getConsumers [{ product, env, brokerTag, topicTag?, page?, limit? }]
@@ -529,7 +548,7 @@ ALL params are passed as a JSON array in positional order matching the SDK signa
529
548
  storage.files.delete [{ product, env, storage, fileName }]
530
549
  storage.files.list [{ product, env, storage, prefix?, limit?, continuationToken? }]
531
550
  storage.files.getSignedUrl [{ product, env, storage, fileName, expiresIn?, action? }]
532
- storage.dispatch [{ product, env, storage, operation, input, retries?, session?, cache?, schedule? }] ← CALL ductape_generate_payload FIRST (operation_family="storage", method="dispatch", targets={storage})
551
+ storage.dispatch [{ product, env, storage, operation, input, retries?, session?, cache?, schedule? }] ← CALL ductape_generate_payload FIRST (operation_family="storage", method="dispatch", targets={storage}) — requires redisUrl in ductape initialization
533
552
 
534
553
  ━━━ MODULE: databases ━━━
535
554
  databases.create [{ product, tag, name, description?, type: "mongodb"|"postgresql"|"mysql"|"sqlite",
@@ -597,8 +616,8 @@ ALL params are passed as a JSON array in positional order matching the SDK signa
597
616
  databases.action.fetch [action_tag]
598
617
  databases.action.list [database_tag]
599
618
  databases.action.delete [action_tag]
600
- databases.action.dispatch [{ product, env, database, action, input, schedule? }] ← CALL ductape_generate_payload FIRST (operation_family="database", method="dispatch", targets={database: "db_tag", table: "table_name"})
601
- databases.dispatch [{ product, env, database, action, input, schedule? }] ← CALL ductape_generate_payload FIRST (operation_family="database", method="dispatch", targets={database: "db_tag", table: "table_name"})
619
+ databases.action.dispatch [{ product, env, database, action, input, schedule? }] ← CALL ductape_generate_payload FIRST (operation_family="database", method="dispatch", targets={database: "db_tag", table: "table_name"}) — requires redisUrl in ductape initialization
620
+ databases.dispatch [{ product, env, database, action, input, schedule? }] ← CALL ductape_generate_payload FIRST (operation_family="database", method="dispatch", targets={database: "db_tag", table: "table_name"}) — requires redisUrl in ductape initialization
602
621
  databases.beginTransaction [{ product, env, database, isolationLevel?: "READ_COMMITTED"|"REPEATABLE_READ"|"SERIALIZABLE" }]
603
622
  → returns a transaction object; pass it to insert/update/delete/upsert/query calls as the last argument.
604
623
  Commit with: transaction.commit() Rollback with: transaction.rollback()
@@ -660,7 +679,7 @@ ALL params are passed as a JSON array in positional order matching the SDK signa
660
679
  graph.beginTransaction [options?]
661
680
  graph.commitTransaction [transaction]
662
681
  graph.rollbackTransaction [transaction]
663
- graph.dispatch [data] ← CALL ductape_generate_payload FIRST (operation_family="graph", method="dispatch", targets={graph})
682
+ graph.dispatch [data] ← CALL ductape_generate_payload FIRST (operation_family="graph", method="dispatch", targets={graph}) — requires redisUrl in ductape initialization
664
683
 
665
684
  ━━━ MODULE: vector ━━━
666
685
  vector.create [{ product, tag, name, description?, provider: "pinecone"|"qdrant"|"weaviate", dimensions: number, metric?: "cosine"|"euclidean"|"dotproduct", envs: [{slug, api_key, environment?}] }]
@@ -780,7 +799,7 @@ ALL params are passed as a JSON array in positional order matching the SDK signa
780
799
  timeout?: number
781
800
  }]
782
801
 
783
- features.dispatch [{ ← CALL ductape_generate_payload FIRST (operation_family="features", method="dispatch", targets={feature})
802
+ features.dispatch [{ ← CALL ductape_generate_payload FIRST (operation_family="features", method="dispatch", targets={feature}) — requires redisUrl in ductape initialization
784
803
  product: string,
785
804
  env: string,
786
805
  feature: string,
@@ -2456,12 +2475,11 @@ Import (register an EXISTING cloud resource):
2456
2475
 
2457
2476
  topic.json schema:
2458
2477
  {
2459
- "tag": "order-created", // topic tag only NOT "broker:topic"
2478
+ "tag": "order-events:order-created", // ALWAYS "broker-tag:topic-tag"full event string
2460
2479
  "name": "Order Created",
2461
- "broker": "order-events", // broker component tag
2462
- "description": "...", // optional
2480
+ "description": "...", // optional
2463
2481
  "sample": { "orderId": "string", "total": 0 }, // expected message shape
2464
- "idempotent": false, // optional — deduplicates by idempotency_key when true
2482
+ "idempotent": false, // optional — deduplicates by idempotency_key when true
2465
2483
  // AWS SQS only — per-env queue URL:
2466
2484
  "queueUrls": [
2467
2485
  { "env_slug": "snd", "url": "https://sqs.us-east-1.amazonaws.com/123/queue-snd" },
@@ -3258,6 +3276,7 @@ async function loadMcpSdk() {
3258
3276
  console.error('Failed to load MCP SDK. Install: npm install @modelcontextprotocol/sdk zod\n' +
3259
3277
  'Or v2 alpha: npm install @modelcontextprotocol/server zod @cfworker/json-schema');
3260
3278
  process.exit(1);
3279
+ throw new Error('MCP SDK not available');
3261
3280
  }
3262
3281
  function handleCliFlags() {
3263
3282
  const arg = process.argv[2];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ductape/mcp",
3
- "version": "0.1.42",
3
+ "version": "0.1.44",
4
4
  "description": "MCP server that exposes Ductape SDK operations via the backend proxy",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/src/index.ts CHANGED
@@ -191,20 +191,33 @@ global interceptors, decorators, and type-safe resource handles.
191
191
 
192
192
  SETUP — register once in AppModule:
193
193
 
194
+ ╔══════════════════════════════════════════════════════════════════════════╗
195
+ ║ redisUrl IS REQUIRED TO USE ANY *.dispatch() ║
196
+ ║ ║
197
+ ║ Every dispatch() call (actions, features, events, databases, storage, ║
198
+ ║ graph, notifications, messageBrokers, quotas, fallback) enqueues jobs ║
199
+ ║ via BullMQ over Redis. Without redisUrl the call throws at runtime: ║
200
+ ║ "Queues not configured. dispatch() requires a queue connection." ║
201
+ ║ ║
202
+ ║ *.run(), events.produce(), and @Events.Consumer do NOT need Redis. ║
203
+ ║ Only dispatch() does — and it is non-negotiable. ║
204
+ ╚══════════════════════════════════════════════════════════════════════════╝
205
+
194
206
  import { DuctapeModule } from '@ductape/nestjs';
195
207
 
196
208
  @Module({
197
209
  imports: [
198
210
  DuctapeModule.forIntegration({
199
211
  accessKey: process.env.DUCTAPE_ACCESS_KEY,
200
- product: 'my-product', // optional default — overridable per controller
212
+ product: 'my-product',
201
213
  env: process.env.NODE_ENV === 'production' ? 'prd' : 'snd',
214
+ redisUrl: process.env.DUCTAPE_REDIS_URL, // required — no dispatch() works without this
202
215
  }),
203
216
  ],
204
217
  })
205
218
  export class AppModule {}
206
219
 
207
- // Async (e.g. pulling key from ConfigService):
220
+ // Async (e.g. pulling from ConfigService):
208
221
  DuctapeModule.forRootAsync({
209
222
  imports: [ConfigModule],
210
223
  inject: [ConfigService],
@@ -212,9 +225,14 @@ SETUP — register once in AppModule:
212
225
  accessKey: cfg.get('DUCTAPE_ACCESS_KEY'),
213
226
  product: cfg.get('DUCTAPE_PRODUCT'),
214
227
  env: cfg.get('DUCTAPE_ENV'),
228
+ redisUrl: cfg.get('DUCTAPE_REDIS_URL'), // required — no dispatch() works without this
215
229
  }),
216
230
  })
217
231
 
232
+ Environment variable (add to .env and deployment secrets):
233
+ DUCTAPE_REDIS_URL=redis://localhost:6379 # local dev
234
+ DUCTAPE_REDIS_URL=rediss://:<password>@host:6380 # managed Redis (TLS)
235
+
218
236
  INJECTING IN SERVICES AND CONTROLLERS — use @InjectContext():
219
237
 
220
238
  import { InjectContext, DuctapeContext } from '@ductape/nestjs';
@@ -269,7 +287,7 @@ FOR MESSAGING (events.produce / events.consume / events.dispatch):
269
287
  @Events.Produce({ event: 'broker-tag:topic-tag' })
270
288
  emitOrderCreated(payload: { orderId: string }) { return payload; }
271
289
 
272
- Dispatch (scheduled or immediate) — static schedule in decorator:
290
+ Dispatch (scheduled or immediate) — dispatch() CANNOT be used without redisUrl in forIntegration:
273
291
  @Events.Dispatch({ broker: 'order-events', event: 'order-events:order-created', schedule: { every: 60000 } })
274
292
  dispatchHeartbeat(payload: { message: { ping: boolean } }) { return payload; }
275
293
 
@@ -284,6 +302,7 @@ FOR MESSAGING (events.produce / events.consume / events.dispatch):
284
302
  }
285
303
  // method return takes precedence over decorator schedule; use sdk.events.dispatch() directly
286
304
  // when even the broker/event must vary at call time.
305
+ // ALL *.dispatch() calls require redisUrl — BullMQ over Redis. Without it dispatch throws.
287
306
 
288
307
  Consume (method decorator — method is called for each incoming message):
289
308
  @Events.Consumer({ event: 'order-events:order-created' })
@@ -343,7 +362,7 @@ ALL params are passed as a JSON array in positional order matching the SDK signa
343
362
  actions.fetch [app_tag, action_tag]
344
363
  actions.list [app_tag]
345
364
  actions.run [{ product, env, app, action, input: { "body:fieldName": value, ... } }] ← CALL ductape_generate_payload FIRST (operation_family="action", method="run", targets={app, action})
346
- actions.dispatch [{ product, env, app, action, input, retries?, session?, cache?, schedule?: { start_at?, cron?, every?, limit?, tz? } }] ← CALL ductape_generate_payload FIRST (operation_family="action", method="dispatch")
365
+ actions.dispatch [{ product, env, app, action, input, retries?, session?, cache?, schedule?: { start_at?, cron?, every?, limit?, tz? } }] ← CALL ductape_generate_payload FIRST (operation_family="action", method="dispatch") — requires redisUrl in ductape initialization
347
366
 
348
367
  ━━━ MODULE: auths ━━━
349
368
  auths.create [app_tag, data: { tag: string, name: string, setup_type: "header"|"bearer"|"basic"|"oauth2"|"apikey", expiry: number, period: "seconds"|"minutes"|"hours"|"days", description: string, action_tag?: string }]
@@ -421,7 +440,7 @@ ALL params are passed as a JSON array in positional order matching the SDK signa
421
440
  quotas.list [product_tag]
422
441
  quotas.delete [product_tag, quota_tag]
423
442
  quotas.run [{ product: string, env: string, tag: string, input: { fieldName: value }, session?: string, cache?: string }] ← CALL ductape_generate_payload FIRST (operation_family="quota", method="run", targets={tag})
424
- quotas.dispatch [{ product: string, env: string, tag: string, input: object, session?: string, cache?: string, schedule?: { cron?: string, delay?: number, at?: string } }] ← CALL ductape_generate_payload FIRST (operation_family="quota", method="dispatch")
443
+ quotas.dispatch [{ product: string, env: string, tag: string, input: object, session?: string, cache?: string, schedule?: { cron?: string, delay?: number, at?: string } }] ← CALL ductape_generate_payload FIRST (operation_family="quota", method="dispatch") — requires redisUrl in ductape initialization
425
444
 
426
445
  ━━━ MODULE: fallback ━━━
427
446
  fallback.create [product_tag, data: {
@@ -464,7 +483,7 @@ ALL params are passed as a JSON array in positional order matching the SDK signa
464
483
  fallback.list [product_tag]
465
484
  fallback.delete [product_tag, fallback_tag]
466
485
  fallback.run [{ product: string, env: string, tag: string, input: { fieldName: value }, session?: string, cache?: string }] ← CALL ductape_generate_payload FIRST (operation_family="fallback", method="run", targets={tag})
467
- fallback.dispatch [{ product: string, env: string, tag: string, input: object, session?: string, cache?: string, schedule?: { cron?: string, delay?: number, at?: string } }] ← CALL ductape_generate_payload FIRST (operation_family="fallback", method="dispatch")
486
+ fallback.dispatch [{ product: string, env: string, tag: string, input: object, session?: string, cache?: string, schedule?: { cron?: string, delay?: number, at?: string } }] ← CALL ductape_generate_payload FIRST (operation_family="fallback", method="dispatch") — requires redisUrl in ductape initialization
468
487
 
469
488
  ━━━ MODULE: health ━━━
470
489
  health.create [product_tag, data: { tag: string, name: string, description?: string, app?: string, event?: string, probe?: { type: "app"|"database"|"feature", app?: string, event?: string, input?: object }, interval: number, retries: number, envs: [{ slug: string, input?: object }], onFailure?: { notifications?: [{ notification: string, message: string, channels: { email?: { recipients: string[] }, push?: { recipients?: string[] }, sms?: { recipients: string[] } } }], webhooks?: [{ url: string, method?: "GET"|"POST", headers?: object, body?: object }] } }]
@@ -491,7 +510,7 @@ ALL params are passed as a JSON array in positional order matching the SDK signa
491
510
  notifications.push.send [{ product, env, notification, input: { ... }, session?, cache? }] ← CALL ductape_generate_payload FIRST (operation_family="notification", method="push.send")
492
511
  notifications.sms.send [{ product, env, notification, input: { ... }, session?, cache? }] ← CALL ductape_generate_payload FIRST (operation_family="notification", method="sms.send")
493
512
  notifications.callback.send [{ product, env, notification, input: { ... }, session?, cache? }] ← CALL ductape_generate_payload FIRST (operation_family="notification", method="callback.send")
494
- notifications.dispatch [{ product, env, notification, event, input, retries?, session?, cache?, schedule?: { cron?, every?, start_at? } }] ← CALL ductape_generate_payload FIRST (operation_family="notification", method="dispatch")
513
+ notifications.dispatch [{ product, env, notification, event, input, retries?, session?, cache?, schedule?: { cron?, every?, start_at? } }] ← CALL ductape_generate_payload FIRST (operation_family="notification", method="dispatch") — requires redisUrl in ductape initialization
495
514
  notifications.getMessages [{ product_tag?, env?, notification_tag?, status?, type?, start_date?, end_date?, page?, limit? }]
496
515
 
497
516
  ━━━ MODULE: messageBrokers ━━━
@@ -502,7 +521,7 @@ ALL params are passed as a JSON array in positional order matching the SDK signa
502
521
  messageBrokers.delete [product_tag, broker_tag]
503
522
  messageBrokers.topics.create ← FORBIDDEN with publishable key. Use ductape_cli instead:
504
523
  ductape_cli("events topics create -f topic.json")
505
- topic.json: { tag, name, broker, description?, sample?, idempotent?, queueUrls?: [{ env_slug, url }] }
524
+ topic.json: { tag: "broker-tag:topic-tag", name, description?, sample?, idempotent?, queueUrls?: [{ env_slug, url }] }
506
525
  ← Always required before consuming. For SQS: must include queueUrls per env.
507
526
  ← For Pub/Sub, Kafka, RabbitMQ, Redis, NATS: the first produce call auto-registers the topic,
508
527
  but you should still create it explicitly so consumers can subscribe before any produce occurs.
@@ -514,7 +533,7 @@ ALL params are passed as a JSON array in positional order matching the SDK signa
514
533
  messageBrokers.topics.list [product_tag, broker_tag] ← safe via ductape_execute
515
534
  messageBrokers.produce [{ product, env, event: "broker_tag:topic_tag", message: { key: value }, session?, cache? }]
516
535
  messageBrokers.consume [{ product, env, event: "broker_tag:topic_tag", callback: "function_ref" }]
517
- messageBrokers.dispatch [{ product, env, broker, event, input: { message }, retries?, session?, cache?, schedule?: { cron?, every?, start_at? } }]
536
+ messageBrokers.dispatch [{ product, env, broker, event, input: { message }, retries?, session?, cache?, schedule?: { cron?, every?, start_at? } }] — requires redisUrl in ductape initialization
518
537
  messageBrokers.messages.query [{ product, env, brokerTag, topicTag?, producerTag?, consumerTag?, status?, startDate?, endDate?, page?, limit? }]
519
538
  messageBrokers.messages.getProducers [{ product, env, brokerTag, topicTag?, page?, limit? }]
520
539
  messageBrokers.messages.getConsumers [{ product, env, brokerTag, topicTag?, page?, limit? }]
@@ -540,7 +559,7 @@ ALL params are passed as a JSON array in positional order matching the SDK signa
540
559
  storage.files.delete [{ product, env, storage, fileName }]
541
560
  storage.files.list [{ product, env, storage, prefix?, limit?, continuationToken? }]
542
561
  storage.files.getSignedUrl [{ product, env, storage, fileName, expiresIn?, action? }]
543
- storage.dispatch [{ product, env, storage, operation, input, retries?, session?, cache?, schedule? }] ← CALL ductape_generate_payload FIRST (operation_family="storage", method="dispatch", targets={storage})
562
+ storage.dispatch [{ product, env, storage, operation, input, retries?, session?, cache?, schedule? }] ← CALL ductape_generate_payload FIRST (operation_family="storage", method="dispatch", targets={storage}) — requires redisUrl in ductape initialization
544
563
 
545
564
  ━━━ MODULE: databases ━━━
546
565
  databases.create [{ product, tag, name, description?, type: "mongodb"|"postgresql"|"mysql"|"sqlite",
@@ -608,8 +627,8 @@ ALL params are passed as a JSON array in positional order matching the SDK signa
608
627
  databases.action.fetch [action_tag]
609
628
  databases.action.list [database_tag]
610
629
  databases.action.delete [action_tag]
611
- databases.action.dispatch [{ product, env, database, action, input, schedule? }] ← CALL ductape_generate_payload FIRST (operation_family="database", method="dispatch", targets={database: "db_tag", table: "table_name"})
612
- databases.dispatch [{ product, env, database, action, input, schedule? }] ← CALL ductape_generate_payload FIRST (operation_family="database", method="dispatch", targets={database: "db_tag", table: "table_name"})
630
+ databases.action.dispatch [{ product, env, database, action, input, schedule? }] ← CALL ductape_generate_payload FIRST (operation_family="database", method="dispatch", targets={database: "db_tag", table: "table_name"}) — requires redisUrl in ductape initialization
631
+ databases.dispatch [{ product, env, database, action, input, schedule? }] ← CALL ductape_generate_payload FIRST (operation_family="database", method="dispatch", targets={database: "db_tag", table: "table_name"}) — requires redisUrl in ductape initialization
613
632
  databases.beginTransaction [{ product, env, database, isolationLevel?: "READ_COMMITTED"|"REPEATABLE_READ"|"SERIALIZABLE" }]
614
633
  → returns a transaction object; pass it to insert/update/delete/upsert/query calls as the last argument.
615
634
  Commit with: transaction.commit() Rollback with: transaction.rollback()
@@ -671,7 +690,7 @@ ALL params are passed as a JSON array in positional order matching the SDK signa
671
690
  graph.beginTransaction [options?]
672
691
  graph.commitTransaction [transaction]
673
692
  graph.rollbackTransaction [transaction]
674
- graph.dispatch [data] ← CALL ductape_generate_payload FIRST (operation_family="graph", method="dispatch", targets={graph})
693
+ graph.dispatch [data] ← CALL ductape_generate_payload FIRST (operation_family="graph", method="dispatch", targets={graph}) — requires redisUrl in ductape initialization
675
694
 
676
695
  ━━━ MODULE: vector ━━━
677
696
  vector.create [{ product, tag, name, description?, provider: "pinecone"|"qdrant"|"weaviate", dimensions: number, metric?: "cosine"|"euclidean"|"dotproduct", envs: [{slug, api_key, environment?}] }]
@@ -791,7 +810,7 @@ ALL params are passed as a JSON array in positional order matching the SDK signa
791
810
  timeout?: number
792
811
  }]
793
812
 
794
- features.dispatch [{ ← CALL ductape_generate_payload FIRST (operation_family="features", method="dispatch", targets={feature})
813
+ features.dispatch [{ ← CALL ductape_generate_payload FIRST (operation_family="features", method="dispatch", targets={feature}) — requires redisUrl in ductape initialization
795
814
  product: string,
796
815
  env: string,
797
816
  feature: string,
@@ -2529,12 +2548,11 @@ Import (register an EXISTING cloud resource):
2529
2548
 
2530
2549
  topic.json schema:
2531
2550
  {
2532
- "tag": "order-created", // topic tag only NOT "broker:topic"
2551
+ "tag": "order-events:order-created", // ALWAYS "broker-tag:topic-tag"full event string
2533
2552
  "name": "Order Created",
2534
- "broker": "order-events", // broker component tag
2535
- "description": "...", // optional
2553
+ "description": "...", // optional
2536
2554
  "sample": { "orderId": "string", "total": 0 }, // expected message shape
2537
- "idempotent": false, // optional — deduplicates by idempotency_key when true
2555
+ "idempotent": false, // optional — deduplicates by idempotency_key when true
2538
2556
  // AWS SQS only — per-env queue URL:
2539
2557
  "queueUrls": [
2540
2558
  { "env_slug": "snd", "url": "https://sqs.us-east-1.amazonaws.com/123/queue-snd" },
@@ -3345,6 +3363,7 @@ async function loadMcpSdk(): Promise<{
3345
3363
  'Or v2 alpha: npm install @modelcontextprotocol/server zod @cfworker/json-schema',
3346
3364
  );
3347
3365
  process.exit(1);
3366
+ throw new Error('MCP SDK not available');
3348
3367
  }
3349
3368
 
3350
3369
  function handleCliFlags(): boolean {
package/tsconfig.json CHANGED
@@ -9,7 +9,8 @@
9
9
  "esModuleInterop": true,
10
10
  "skipLibCheck": true,
11
11
  "declaration": true,
12
- "declarationMap": true
12
+ "declarationMap": true,
13
+ "types": ["node"]
13
14
  },
14
15
  "include": ["src/**/*"],
15
16
  "exclude": ["node_modules"]