@ductape/mcp 0.2.33 → 0.2.34
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 +75 -9
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -311,6 +311,23 @@ When the target application is a NestJS service or controller, always use @ducta
|
|
|
311
311
|
instead of instantiating @ductape/sdk directly. It provides NestJS DI integration,
|
|
312
312
|
global interceptors, decorators, and type-safe resource handles.
|
|
313
313
|
|
|
314
|
+
PRODUCT RUNTIME SNAPSHOT — REQUIRED FOR SERVER INITIALIZATION:
|
|
315
|
+
Always provide both product and env at module initialization. Nest awaits the SDK's initial
|
|
316
|
+
product runtime snapshot during onModuleInit, before the application accepts traffic. The
|
|
317
|
+
snapshot preloads connected App versions/actions plus database actions/schema metadata, graphs,
|
|
318
|
+
vectors, storage, brokers/topics, sessions, notifications, resilience assets, agents, functions,
|
|
319
|
+
and caches into the execution bootstrap cache. External provider/database connections remain
|
|
320
|
+
lazy and pooled.
|
|
321
|
+
|
|
322
|
+
Runtime synchronization is enabled by default when product + env are present. Do not set
|
|
323
|
+
runtimeSync:false merely to simplify generated code. Configure it only when the user has an
|
|
324
|
+
explicit operational reason:
|
|
325
|
+
runtimeSync: { intervalMs: 30_000, jitter: 0.2, maxBackoffMs: 300_000 }
|
|
326
|
+
|
|
327
|
+
Polling uses runtimeRevision + HTTP ETag/304. databaseRevision is a refresh hint included in the
|
|
328
|
+
umbrella runtimeRevision, so schema and Database Action changes are detected. Failed refreshes
|
|
329
|
+
retain the last-known-good snapshot. Nest stops polling through onModuleDestroy automatically.
|
|
330
|
+
|
|
314
331
|
SETUP — register once in AppModule:
|
|
315
332
|
|
|
316
333
|
╔══════════════════════════════════════════════════════════════════════════╗
|
|
@@ -338,6 +355,7 @@ SETUP — register once in AppModule:
|
|
|
338
355
|
product: 'my-product',
|
|
339
356
|
env: process.env.NODE_ENV === 'production' ? 'prd' : 'snd',
|
|
340
357
|
redisUrl: process.env.DUCTAPE_REDIS_URL, // required — no dispatch() works without this
|
|
358
|
+
runtimeSync: { intervalMs: 30_000, jitter: 0.2 },
|
|
341
359
|
}),
|
|
342
360
|
],
|
|
343
361
|
})
|
|
@@ -352,6 +370,7 @@ SETUP — register once in AppModule:
|
|
|
352
370
|
product: cfg.get('DUCTAPE_PRODUCT'),
|
|
353
371
|
env: cfg.get('DUCTAPE_ENV'),
|
|
354
372
|
redisUrl: cfg.get('DUCTAPE_REDIS_URL'), // required — no dispatch() works without this
|
|
373
|
+
runtimeSync: { intervalMs: 30_000, jitter: 0.2 },
|
|
355
374
|
}),
|
|
356
375
|
})
|
|
357
376
|
|
|
@@ -1312,18 +1331,24 @@ function buildTypeScriptSnippet(payload, operationFamily, method) {
|
|
|
1312
1331
|
const invocationArgs = buildSdkInvocationArgs(payload);
|
|
1313
1332
|
return `import Ductape from "@ductape/sdk";
|
|
1314
1333
|
|
|
1334
|
+
const payload = ${toPrettyJson(payload)};
|
|
1315
1335
|
const ductape = new Ductape({
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1336
|
+
accessKey: process.env.DUCTAPE_ACCESS_KEY!,
|
|
1337
|
+
product: String(payload.product),
|
|
1338
|
+
env: String(payload.env),
|
|
1319
1339
|
redis_url: process.env.DUCTAPE_REDIS_URL,
|
|
1340
|
+
runtime_sync: { interval_ms: 30_000, jitter: 0.2 },
|
|
1320
1341
|
});
|
|
1321
1342
|
|
|
1322
1343
|
async function run() {
|
|
1323
|
-
|
|
1344
|
+
await ductape.ready();
|
|
1324
1345
|
const args = ${toPrettyJson(invocationArgs)};
|
|
1325
|
-
|
|
1326
|
-
|
|
1346
|
+
try {
|
|
1347
|
+
const result = await ductape.${callPath}(args);
|
|
1348
|
+
return { payload, result };
|
|
1349
|
+
} finally {
|
|
1350
|
+
await ductape.close();
|
|
1351
|
+
}
|
|
1327
1352
|
}
|
|
1328
1353
|
|
|
1329
1354
|
run().catch(console.error);
|
|
@@ -1598,7 +1623,7 @@ function shellArgument(value) {
|
|
|
1598
1623
|
}
|
|
1599
1624
|
const docsInputSchema = z.object({
|
|
1600
1625
|
topic: z.string().describe('Feature topic to look up. Supported: ' +
|
|
1601
|
-
'transactions, presave, triggers, aggregations, migrations, indexes, performance, actions, ' +
|
|
1626
|
+
'transactions, presave, triggers, aggregations, migrations, indexes, performance, runtime-sync, actions, ' +
|
|
1602
1627
|
'graphs, storage, cloud, vector, warehouse, secrets, apps, products, sessions, caches, ' +
|
|
1603
1628
|
'notifications, resilience, features, portable-functions, events, logs, migration, cli-authentication, frontend, frontend-analytics, client, react, vue'),
|
|
1604
1629
|
});
|
|
@@ -2509,6 +2534,39 @@ DUCTAPE DATABASE PERFORMANCE GUIDANCE
|
|
|
2509
2534
|
5. Caching
|
|
2510
2535
|
- For read-heavy, rarely-changing data use caches.get before databases.query.
|
|
2511
2536
|
- Invalidate cache keys in an afterWrite trigger (see ductape_docs({ topic: "triggers" })).
|
|
2537
|
+
`.trim(),
|
|
2538
|
+
'runtime-sync': `
|
|
2539
|
+
DUCTAPE PRODUCT RUNTIME SNAPSHOTS
|
|
2540
|
+
|
|
2541
|
+
For every long-lived TypeScript/Node backend, initialize @ductape/sdk with accessKey, product,
|
|
2542
|
+
and env, then await ready() before accepting work:
|
|
2543
|
+
|
|
2544
|
+
const ductape = new Ductape({
|
|
2545
|
+
accessKey: process.env.DUCTAPE_ACCESS_KEY!,
|
|
2546
|
+
product: "payments",
|
|
2547
|
+
env: "prd",
|
|
2548
|
+
runtime_sync: { interval_ms: 30_000, jitter: 0.2, max_backoff_ms: 300_000 },
|
|
2549
|
+
});
|
|
2550
|
+
await ductape.ready();
|
|
2551
|
+
|
|
2552
|
+
This fetches one environment-scoped product snapshot and primes the existing bootstrap cache with
|
|
2553
|
+
connected App versions/actions, databases/actions/table schemas, graphs, vectors, storage,
|
|
2554
|
+
brokers/topics, sessions, notifications, resilience assets, agents, functions, and caches.
|
|
2555
|
+
Connections remain lazy and pooled; snapshot bootstrap does not call external providers.
|
|
2556
|
+
|
|
2557
|
+
Runtime synchronization is automatic when product + env are supplied:
|
|
2558
|
+
- Conditional polling sends If-None-Match with runtimeRevision; unchanged state returns HTTP 304.
|
|
2559
|
+
- runtimeRevision is authoritative. databaseRevision, connectionRevision, secretRevision, and
|
|
2560
|
+
assetRevision are narrower change hints. Any databaseRevision change also changes runtimeRevision.
|
|
2561
|
+
- A changed snapshot is loaded off-path and atomically replaces cache entries. Deleted assets are removed.
|
|
2562
|
+
- Refresh failure retains the last-known-good snapshot and retries with jittered exponential backoff.
|
|
2563
|
+
- Use runtimeSnapshotStatus() for revision/error telemetry and refreshRuntime() for an explicit pull.
|
|
2564
|
+
- Call close() during process shutdown. Do not create one Ductape instance per request.
|
|
2565
|
+
|
|
2566
|
+
For NestJS, use DuctapeModule.forIntegration({ accessKey, product, env, runtimeSync }) instead of
|
|
2567
|
+
new Ductape(). @ductape/nestjs awaits ready() in onModuleInit and closes the poller in
|
|
2568
|
+
onModuleDestroy. Never omit product/env when the service has stable defaults: doing so disables
|
|
2569
|
+
product snapshot bootstrap and returns execution to lazy per-asset bootstrap misses.
|
|
2512
2570
|
`.trim(),
|
|
2513
2571
|
actions: `
|
|
2514
2572
|
DUCTAPE DATABASE ACTIONS
|
|
@@ -3202,8 +3260,11 @@ Product structure (IProduct fields):
|
|
|
3202
3260
|
workflows[] (features), models[], agents[], jobs[]
|
|
3203
3261
|
|
|
3204
3262
|
Bootstrap (single API call returning product context + component config + private key):
|
|
3205
|
-
|
|
3206
|
-
|
|
3263
|
+
Initialize @ductape/sdk with product + env and await ductape.ready(). It fetches the full
|
|
3264
|
+
environment-scoped product runtime snapshot and primes BootstrapCache for connected App actions
|
|
3265
|
+
and product components. A service falls back to its targeted bootstrap endpoint only when the
|
|
3266
|
+
requested asset is absent. Polling uses ETag/304 and atomically refreshes changed state.
|
|
3267
|
+
See ductape_docs({ topic: "runtime-sync" }).
|
|
3207
3268
|
`.trim(),
|
|
3208
3269
|
sessions: `
|
|
3209
3270
|
DUCTAPE SESSIONS
|
|
@@ -4537,8 +4598,12 @@ Import (register an EXISTING cloud resource):
|
|
|
4537
4598
|
// dispatch() requires redis_url in the Ductape initialization options — it throws at runtime without it.
|
|
4538
4599
|
const ductape = new Ductape({
|
|
4539
4600
|
accessKey: process.env.DUCTAPE_ACCESS_KEY,
|
|
4601
|
+
product: "my-product",
|
|
4602
|
+
env: "prd",
|
|
4540
4603
|
redis_url: process.env.DUCTAPE_REDIS_URL, // required for any dispatch(); omit only if never dispatching
|
|
4604
|
+
runtime_sync: { interval_ms: 30_000, jitter: 0.2 },
|
|
4541
4605
|
});
|
|
4606
|
+
await ductape.ready();
|
|
4542
4607
|
await ductape.events.produce({
|
|
4543
4608
|
product: "my-product",
|
|
4544
4609
|
env: "prd",
|
|
@@ -4561,6 +4626,7 @@ Import (register an EXISTING cloud resource):
|
|
|
4561
4626
|
product: 'my-product',
|
|
4562
4627
|
env: process.env.NODE_ENV === 'production' ? 'prd' : 'snd',
|
|
4563
4628
|
redisUrl: process.env.DUCTAPE_REDIS_URL, // required — dispatch() throws without this
|
|
4629
|
+
runtimeSync: { intervalMs: 30_000, jitter: 0.2 },
|
|
4564
4630
|
}),
|
|
4565
4631
|
});
|
|
4566
4632
|
// Environment: DUCTAPE_REDIS_URL=redis://localhost:6379 (local) or rediss://:<pw>@host:6380 (managed)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ductape/mcp",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.34",
|
|
4
4
|
"description": "MCP server that exposes Ductape SDK operations via the backend proxy",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
],
|
|
16
16
|
"scripts": {
|
|
17
17
|
"build": "tsc",
|
|
18
|
-
"test": "npm run build && node scripts/check-cli-command-security.mjs && node scripts/check-frontend-analytics-guidance.mjs && node scripts/check-events-discovery.mjs && node scripts/check-schema-fallback.mjs && node scripts/check-paystack-action-schema.mjs && node scripts/check-portable-functions.mjs && node scripts/check-feature-control-flow.mjs && node scripts/check-project-link-guidance.mjs && node scripts/check-graph-vector-projection-guidance.mjs && node scripts/check-asset-file-guidance.mjs && node scripts/check-database-action-contract-guidance.mjs",
|
|
18
|
+
"test": "npm run build && node scripts/check-cli-command-security.mjs && node scripts/check-frontend-analytics-guidance.mjs && node scripts/check-events-discovery.mjs && node scripts/check-schema-fallback.mjs && node scripts/check-paystack-action-schema.mjs && node scripts/check-portable-functions.mjs && node scripts/check-feature-control-flow.mjs && node scripts/check-project-link-guidance.mjs && node scripts/check-graph-vector-projection-guidance.mjs && node scripts/check-asset-file-guidance.mjs && node scripts/check-database-action-contract-guidance.mjs && node scripts/check-runtime-sync-guidance.mjs",
|
|
19
19
|
"start": "node dist/index.js",
|
|
20
20
|
"dev": "tsx src/index.ts"
|
|
21
21
|
},
|