@ductape/mcp 0.1.47 → 0.1.49

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
@@ -576,6 +576,11 @@ ALL params are passed as a JSON array in positional order matching the SDK signa
576
576
  databases.update [{ product, env, database, table, data: {key:value}, where: {field: value}, returning?, session?, cache? }] ← CALL ductape_generate_payload FIRST (operation_family="database", method="update", targets={database, table})
577
577
  databases.delete [{ product, env, database, table, where: {field: value}, returning?, session?, cache? }] ← CALL ductape_generate_payload FIRST (operation_family="database", method="delete", targets={database, table})
578
578
  databases.upsert [{ product, env, database, table, data: {key:value}, conflictKeys: string[], returning?, session?, cache? }] ← CALL ductape_generate_payload FIRST (operation_family="database", method="upsert", targets={database, table})
579
+ NOTE on write operations (insert/update/delete/upsert): if the proxy returns "Authentication failed",
580
+ the publishable key does not have write access for that database. Write permissions are configured
581
+ in Workbench → Tokens → Publishable Key. An access key is required for write operations that are
582
+ not explicitly enabled for the publishable key. In that case the operation must be performed
583
+ server-side using a full Ductape SDK instance initialized with an access key.
579
584
  NOTE: ductape_generate_payload for databases returns:
580
585
  payload.input — ready-to-use input with real field names in where/data, plus session and cache inside input
581
586
  meta.schema_context.database.fields — { fieldName: { type, required, description?, sample? } } for the table
@@ -1187,9 +1192,58 @@ const docsInputSchema = z.object({
1187
1192
  topic: z.string().describe('Feature topic to look up. Supported: ' +
1188
1193
  'transactions, presave, triggers, aggregations, migrations, indexes, performance, actions, ' +
1189
1194
  'graphs, storage, cloud, vector, warehouse, secrets, apps, products, sessions, caches, ' +
1190
- 'notifications, resilience, features, events, logs'),
1195
+ 'notifications, resilience, features, events, logs, frontend, client, react, vue'),
1191
1196
  });
1192
1197
  const DOCS = {
1198
+ frontend: `
1199
+ DUCTAPE FRONTEND SDK GUIDE
1200
+
1201
+ Choose one integration package:
1202
+ React 17+ — npm install @ductape/react
1203
+ Provider and hooks built on @ductape/client.
1204
+ Continue with ductape_docs({ topic: "react" }).
1205
+ Vue 3+ — npm install @ductape/vue
1206
+ Plugin and composables built on @ductape/client.
1207
+ Continue with ductape_docs({ topic: "vue" }).
1208
+ Other UI — npm install @ductape/client
1209
+ frameworks Use directly with Svelte, Angular, vanilla JavaScript, or a custom adapter.
1210
+ Continue with ductape_docs({ topic: "client" }).
1211
+
1212
+ Do not install @ductape/client separately when using @ductape/react or @ductape/vue unless the
1213
+ application also needs direct access to a client API not exposed by the framework package. Both
1214
+ framework packages wrap @ductape/client and expose the underlying client through useDuctape().
1215
+
1216
+ SHARED APPLICATION LIFECYCLE
1217
+ 1. Create one client at the application root using a browser-safe publishableKey, proxy baseUrl,
1218
+ default product tag, and environment slug.
1219
+ 2. Connect the real-time client only in the browser. In React use DuctapeProvider autoConnect or
1220
+ connect() after mount; in Vue use createDuctape({ autoConnect: true }) or connect() in onMounted.
1221
+ 3. Authenticate the player with the sessions API and retain the returned session token according
1222
+ to the application's security policy. Refresh it before expiry (the React/Vue packages provide
1223
+ useSessionAutoRefresh) and revoke it on logout.
1224
+ 4. Pass the session value when connecting a broker that requires player-scoped authorization.
1225
+ 5. Subscribe through the framework hook/composable or the client service. Always unsubscribe on
1226
+ component teardown; the framework integrations do this automatically for declarative hooks.
1227
+ 6. The underlying client reconnects its WebSocket and restores active subscriptions. Observe
1228
+ connectionState to render disconnected/reconnecting UI; do not create duplicate subscriptions.
1229
+ 7. Disconnect resource sessions and the root client when the owning application scope is torn down.
1230
+
1231
+ AUTHENTICATION AND SECURITY
1232
+ - Use publishableKey in browser applications. Never ship workspace private keys or privileged
1233
+ access keys in frontend bundles.
1234
+ - A Ductape player session and the real-time transport connection are separate: authenticate or
1235
+ refresh the session, then use that session when opening player-scoped broker resources.
1236
+ - For SSR, create/connect the real-time client only on the browser side.
1237
+
1238
+ MIGRATING A CUSTOM WRAPPER
1239
+ - Keep @ductape/client when the wrapper implements application-specific projection or state logic.
1240
+ - For React, move root connection ownership to DuctapeProvider, replace imperative subscriptions
1241
+ with useBroker/useBrokerSubscription, and keep projection reduction in an application hook.
1242
+ - For Vue, move root ownership to createDuctape(), replace imperative subscriptions with
1243
+ useBroker/useBrokerSubscription, and keep projection reduction in an application composable.
1244
+ - Verify session handoff, initial loading state, error state, reconnect UI, subscription cleanup,
1245
+ and duplicate-event behavior with a live end-to-end run before removing the old wrapper.
1246
+ `.trim(),
1193
1247
  transactions: `
1194
1248
  DUCTAPE DATABASE TRANSACTIONS
1195
1249
 
@@ -3418,7 +3472,14 @@ async function main() {
3418
3472
  return { content: [{ type: 'text', text: JSON.stringify(result ?? null, null, 2) }] };
3419
3473
  }
3420
3474
  catch (err) {
3421
- const message = err instanceof Error ? err.message : String(err);
3475
+ let message = err instanceof Error ? err.message : String(err);
3476
+ const isAuthFailed = /authentication failed/i.test(message);
3477
+ const isDbWrite = args.module === 'databases' && /^(insert|update|delete|upsert)$/.test(args.method);
3478
+ if (isAuthFailed && isDbWrite) {
3479
+ message += '\n\nThe publishable key does not have write access for this database operation. ' +
3480
+ 'Enable it in Workbench → Tokens → Publishable Key. ' +
3481
+ 'If write access cannot be granted to the publishable key, perform this operation server-side using a full Ductape SDK instance initialized with an access key.';
3482
+ }
3422
3483
  return { content: [{ type: 'text', text: `Error: ${message}` }], isError: true };
3423
3484
  }
3424
3485
  };
@@ -3537,7 +3598,7 @@ async function main() {
3537
3598
  'index strategy, operation types) that should be confirmed with the user first.\n\n' +
3538
3599
  'Available topics: transactions, presave, triggers, aggregations, migrations, indexes, performance, actions, ' +
3539
3600
  'graphs, storage, cloud, vector, warehouse, secrets, apps, products, sessions, caches, ' +
3540
- 'notifications, resilience, features, events, logs, client, react, vue',
3601
+ 'notifications, resilience, features, events, logs, frontend, client, react, vue',
3541
3602
  inputSchema: docsInputSchema,
3542
3603
  }, docsHandler);
3543
3604
  server.registerTool('ductape_cli', {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ductape/mcp",
3
- "version": "0.1.47",
3
+ "version": "0.1.49",
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
@@ -587,6 +587,11 @@ ALL params are passed as a JSON array in positional order matching the SDK signa
587
587
  databases.update [{ product, env, database, table, data: {key:value}, where: {field: value}, returning?, session?, cache? }] ← CALL ductape_generate_payload FIRST (operation_family="database", method="update", targets={database, table})
588
588
  databases.delete [{ product, env, database, table, where: {field: value}, returning?, session?, cache? }] ← CALL ductape_generate_payload FIRST (operation_family="database", method="delete", targets={database, table})
589
589
  databases.upsert [{ product, env, database, table, data: {key:value}, conflictKeys: string[], returning?, session?, cache? }] ← CALL ductape_generate_payload FIRST (operation_family="database", method="upsert", targets={database, table})
590
+ NOTE on write operations (insert/update/delete/upsert): if the proxy returns "Authentication failed",
591
+ the publishable key does not have write access for that database. Write permissions are configured
592
+ in Workbench → Tokens → Publishable Key. An access key is required for write operations that are
593
+ not explicitly enabled for the publishable key. In that case the operation must be performed
594
+ server-side using a full Ductape SDK instance initialized with an access key.
590
595
  NOTE: ductape_generate_payload for databases returns:
591
596
  payload.input — ready-to-use input with real field names in where/data, plus session and cache inside input
592
597
  meta.schema_context.database.fields — { fieldName: { type, required, description?, sample? } } for the table
@@ -1237,11 +1242,61 @@ const docsInputSchema = z.object({
1237
1242
  'Feature topic to look up. Supported: ' +
1238
1243
  'transactions, presave, triggers, aggregations, migrations, indexes, performance, actions, ' +
1239
1244
  'graphs, storage, cloud, vector, warehouse, secrets, apps, products, sessions, caches, ' +
1240
- 'notifications, resilience, features, events, logs',
1245
+ 'notifications, resilience, features, events, logs, frontend, client, react, vue',
1241
1246
  ),
1242
1247
  });
1243
1248
 
1244
1249
  const DOCS: Record<string, string> = {
1250
+ frontend: `
1251
+ DUCTAPE FRONTEND SDK GUIDE
1252
+
1253
+ Choose one integration package:
1254
+ React 17+ — npm install @ductape/react
1255
+ Provider and hooks built on @ductape/client.
1256
+ Continue with ductape_docs({ topic: "react" }).
1257
+ Vue 3+ — npm install @ductape/vue
1258
+ Plugin and composables built on @ductape/client.
1259
+ Continue with ductape_docs({ topic: "vue" }).
1260
+ Other UI — npm install @ductape/client
1261
+ frameworks Use directly with Svelte, Angular, vanilla JavaScript, or a custom adapter.
1262
+ Continue with ductape_docs({ topic: "client" }).
1263
+
1264
+ Do not install @ductape/client separately when using @ductape/react or @ductape/vue unless the
1265
+ application also needs direct access to a client API not exposed by the framework package. Both
1266
+ framework packages wrap @ductape/client and expose the underlying client through useDuctape().
1267
+
1268
+ SHARED APPLICATION LIFECYCLE
1269
+ 1. Create one client at the application root using a browser-safe publishableKey, proxy baseUrl,
1270
+ default product tag, and environment slug.
1271
+ 2. Connect the real-time client only in the browser. In React use DuctapeProvider autoConnect or
1272
+ connect() after mount; in Vue use createDuctape({ autoConnect: true }) or connect() in onMounted.
1273
+ 3. Authenticate the player with the sessions API and retain the returned session token according
1274
+ to the application's security policy. Refresh it before expiry (the React/Vue packages provide
1275
+ useSessionAutoRefresh) and revoke it on logout.
1276
+ 4. Pass the session value when connecting a broker that requires player-scoped authorization.
1277
+ 5. Subscribe through the framework hook/composable or the client service. Always unsubscribe on
1278
+ component teardown; the framework integrations do this automatically for declarative hooks.
1279
+ 6. The underlying client reconnects its WebSocket and restores active subscriptions. Observe
1280
+ connectionState to render disconnected/reconnecting UI; do not create duplicate subscriptions.
1281
+ 7. Disconnect resource sessions and the root client when the owning application scope is torn down.
1282
+
1283
+ AUTHENTICATION AND SECURITY
1284
+ - Use publishableKey in browser applications. Never ship workspace private keys or privileged
1285
+ access keys in frontend bundles.
1286
+ - A Ductape player session and the real-time transport connection are separate: authenticate or
1287
+ refresh the session, then use that session when opening player-scoped broker resources.
1288
+ - For SSR, create/connect the real-time client only on the browser side.
1289
+
1290
+ MIGRATING A CUSTOM WRAPPER
1291
+ - Keep @ductape/client when the wrapper implements application-specific projection or state logic.
1292
+ - For React, move root connection ownership to DuctapeProvider, replace imperative subscriptions
1293
+ with useBroker/useBrokerSubscription, and keep projection reduction in an application hook.
1294
+ - For Vue, move root ownership to createDuctape(), replace imperative subscriptions with
1295
+ useBroker/useBrokerSubscription, and keep projection reduction in an application composable.
1296
+ - Verify session handoff, initial loading state, error state, reconnect UI, subscription cleanup,
1297
+ and duplicate-event behavior with a live end-to-end run before removing the old wrapper.
1298
+ `.trim(),
1299
+
1245
1300
  transactions: `
1246
1301
  DUCTAPE DATABASE TRANSACTIONS
1247
1302
 
@@ -3517,7 +3572,14 @@ async function main() {
3517
3572
  const result = await executeViaProxy(key, proxyModule, args.method, params);
3518
3573
  return { content: [{ type: 'text', text: JSON.stringify(result ?? null, null, 2) }] };
3519
3574
  } catch (err) {
3520
- const message = err instanceof Error ? err.message : String(err);
3575
+ let message = err instanceof Error ? err.message : String(err);
3576
+ const isAuthFailed = /authentication failed/i.test(message);
3577
+ const isDbWrite = args.module === 'databases' && /^(insert|update|delete|upsert)$/.test(args.method);
3578
+ if (isAuthFailed && isDbWrite) {
3579
+ message += '\n\nThe publishable key does not have write access for this database operation. ' +
3580
+ 'Enable it in Workbench → Tokens → Publishable Key. ' +
3581
+ 'If write access cannot be granted to the publishable key, perform this operation server-side using a full Ductape SDK instance initialized with an access key.';
3582
+ }
3521
3583
  return { content: [{ type: 'text', text: `Error: ${message}` }], isError: true };
3522
3584
  }
3523
3585
  };
@@ -3670,7 +3732,7 @@ async function main() {
3670
3732
  'index strategy, operation types) that should be confirmed with the user first.\n\n' +
3671
3733
  'Available topics: transactions, presave, triggers, aggregations, migrations, indexes, performance, actions, ' +
3672
3734
  'graphs, storage, cloud, vector, warehouse, secrets, apps, products, sessions, caches, ' +
3673
- 'notifications, resilience, features, events, logs, client, react, vue',
3735
+ 'notifications, resilience, features, events, logs, frontend, client, react, vue',
3674
3736
  inputSchema: docsInputSchema,
3675
3737
  },
3676
3738
  docsHandler,