@ductape/mcp 0.2.34 → 0.2.35

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.
Files changed (2) hide show
  1. package/dist/index.js +90 -13
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -316,8 +316,16 @@ PRODUCT RUNTIME SNAPSHOT — REQUIRED FOR SERVER INITIALIZATION:
316
316
  product runtime snapshot during onModuleInit, before the application accepts traffic. The
317
317
  snapshot preloads connected App versions/actions plus database actions/schema metadata, graphs,
318
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.
319
+ and caches into the execution bootstrap cache. It also hydrates the selected Workbench App
320
+ connection for product+env (variables and token_access credentials). Do not emit api.config()
321
+ or api.oauth() boilerplate when that connection is already configured on the product. Explicit
322
+ api.config() is only a process-local override and has higher precedence. credential_access login
323
+ material remains isolated to the auth action and its encrypted refresh path. External provider/
324
+ database connections remain lazy and pooled.
325
+
326
+ Features, Quotas, Fallbacks, health checks, and direct api.run calls all reuse this same hydrated
327
+ connection through the action processor. Never create a second connection or copy secrets into a
328
+ Feature/Quota/Fallback definition. Reference the existing connected App access_tag and action tag.
321
329
 
322
330
  Runtime synchronization is enabled by default when product + env are present. Do not set
323
331
  runtimeSync:false merely to simplify generated code. Configure it only when the user has an
@@ -492,6 +500,7 @@ ALL params are passed as a JSON array in positional order matching the SDK signa
492
500
  ductape_cli("products apps list --product <id_or_tag> --json") ← compact linked apps only
493
501
  ductape_cli("products apps actions list --product <id_or_tag> --app <app_tag> --json")
494
502
  ductape_cli("products apps actions get --product <id_or_tag> --app <app_tag> --action <action_tag> --json")
503
+ ductape_cli("products apps configure --product <id_or_tag> --app <app_or_access_tag> --connection-file ductape/apps/<app_tag>/connection.json --json")
495
504
 
496
505
  SDK method signatures (for reference, admin key only):
497
506
  product.create [data: { name, description, tag?, envs?: [{slug, name}] }]
@@ -503,6 +512,7 @@ ALL params are passed as a JSON array in positional order matching the SDK signa
503
512
  product.apps.add [product_tag, app: { access_tag, envs: [{ app_env_slug, product_env_slug, variables?, auth? }] }]
504
513
  product.apps.list [product_tag]
505
514
  product.apps.fetch [product_tag, access_tag]
515
+ product.apps.update [product_tag, access_tag, { envs }] ← prefer CLI configure; it preserves omitted auth/variables
506
516
 
507
517
  ━━━ MODULE: app ━━━
508
518
  app.create [data: { app_name: string, description: string, unique?: boolean }]
@@ -1205,6 +1215,11 @@ const marketplaceConnectInputSchema = z.object({
1205
1215
  product_env_slug: z.string().min(1),
1206
1216
  })).min(1).describe('Explicit app-to-product environment mappings. Include every product environment that will use the app.'),
1207
1217
  });
1218
+ const appConnectionConfigureInputSchema = z.object({
1219
+ product_tag: z.string().min(1).describe('Product containing the existing App connection.'),
1220
+ app_tag: z.string().min(1).describe('Connected App tag or exact product access tag returned by products apps list.'),
1221
+ file: z.string().min(1).describe('Canonical JSON file under ductape/apps/<app-tag>/connection.json containing { envs: [...] }.'),
1222
+ });
1208
1223
  const marketplaceInspectInputSchema = z.object({
1209
1224
  app_tag: z.string().min(1).describe('Exact public app tag returned by ductape_marketplace_discover.'),
1210
1225
  });
@@ -3073,20 +3088,49 @@ CONNECT A DISCOVERED APP THROUGH MCP:
3073
3088
  4. Match each product environment explicitly to one environment exposed by the app.
3074
3089
  5. Call ductape_marketplace_connect({ product_tag, app_tag, environments }).
3075
3090
  6. Verify with ductape_cli("products apps list --product <product_tag> --json").
3091
+ 7. If the App requires variables or auth, create the canonical file at
3092
+ ductape/apps/<app_tag>/connection.json and call ductape_app_connection_configure. A bare
3093
+ connect only establishes access + environment mapping; it does not invent configuration.
3076
3094
  Never guess environment mappings or action tags. Connecting mutates product configuration;
3077
3095
  obtain user approval when the user has not already requested the connection.
3078
3096
 
3079
- CONFIRMED LIMITATION (2026-08-17): both ductape_marketplace_connect and the equivalent
3080
- ductape_cli("products apps connect --product <tag> --app <app-tag> --env-map ...") reject any
3081
- app that is not marked public in the marketplace, with error
3082
- App "<tag>" is not public in the marketplace. This includes apps a user creates themselves under
3083
- their own tag (e.g. a private "ductape:paystack") — private/workspace-owned apps CANNOT be
3084
- connected to a product through MCP or CLI at all, only through Workbench, even though
3085
- ductape_marketplace_inspect can still read a private app's full action catalogue (inspect and
3086
- connect have different visibility rules). If you hit this, do not keep retrying — tell the user
3087
- the app must be connected via Workbench, and once they confirm it's connected, verify with
3088
- ductape_cli("products apps list --product <product_tag> --json") rather than attempting the
3089
- connect call again.
3097
+ Visibility: public marketplace Apps and private Apps owned by the current workspace can be
3098
+ connected. A private App owned by another workspace must be rejected; do not retry around that
3099
+ ownership boundary.
3100
+
3101
+ CONNECTION FILE REQUIRED SHAPE:
3102
+ File: ductape/apps/<app_tag>/connection.json
3103
+ {
3104
+ "envs": [{
3105
+ "product_env_slug": "prd",
3106
+ "app_env_slug": "production",
3107
+ "variables": [{ "key": "region", "value": "ng" }],
3108
+ "auth": {
3109
+ "auth_tag": "secret-key",
3110
+ "data": {
3111
+ "headers": { "Authorization": "$Secret{PAYSTACK_SECRET_KEY}" },
3112
+ "query": {}, "params": {}, "body": {}
3113
+ }
3114
+ }
3115
+ }]
3116
+ }
3117
+
3118
+ Before writing this file, inspect the exact App version/auth/action schemas. auth.data must have
3119
+ headers/query/params/body objects and must match the selected auth schema. Never guess an auth_tag,
3120
+ variable key, input location, or required field. Store credentials with secrets.create first and
3121
+ write $Secret{KEY}, never plaintext, into the connection file.
3122
+
3123
+ CREATE/REPAIR/ROTATE:
3124
+ ductape_cli("products apps configure --product <product_tag> --app <app_or_access_tag> \
3125
+ --connection-file ductape/apps/<app_tag>/connection.json --json")
3126
+ The command is merge-safe: an omitted auth or variables field preserves the existing saved field.
3127
+ Providing auth or variables explicitly replaces that field for the named product environment.
3128
+ It never returns saved credential values. Include only environments intentionally being changed;
3129
+ other existing mappings are retained. To repair an old connection with no mapping, add its row.
3130
+
3131
+ After configuration, verify the non-secret summary with products apps list, then inspect the exact
3132
+ action contract. Do not test a payment or other side-effecting action merely to verify connection
3133
+ persistence unless the user explicitly requests a safe test and supplies appropriate test input.
3090
3134
 
3091
3135
  ONLY after all five steps can any code call:
3092
3136
  ctx.api.run({ app: '<app_tag>', action: '<action_tag>', input: { ... } }) ← in a feature handler
@@ -5731,6 +5775,12 @@ const integrateEndpointHandler = async (args) => {
5731
5775
  'Run: ductape_cli("products apps connect --product <product_tag> --app <app_tag> --env-map ' +
5732
5776
  '<app_env>:<product_env> [repeat --env-map per environment] --json"). If the app is a public ' +
5733
5777
  'marketplace app, ductape_marketplace_connect does the same thing in one call.',
5778
+ 'If the App declares variables or auth, connecting is not the end: call ductape_schema for the ' +
5779
+ 'exact app/auth contract, store credential values with secrets.create, write ' +
5780
+ 'ductape/apps/<app_tag>/connection.json using $Secret{KEY} references, and call ' +
5781
+ 'ductape_app_connection_configure. Never put plaintext secrets in the asset file.',
5782
+ 'For an already-connected App, skip connect and use configure. Omitted auth/variables preserve ' +
5783
+ 'the current encrypted values, so mapping-only repairs must not force credential rotation.',
5734
5784
  ],
5735
5785
  });
5736
5786
  stages.push({
@@ -5933,6 +5983,11 @@ const DUCTAPE_FIRST_DOCTRINE = 'Follow this checklist before defaulting to plain
5933
5983
  '(ductape.functions.register/use) — register portable business logic once and reuse it across ' +
5934
5984
  'every Feature that needs it. Call ductape_schema before constructing any new resource file, ' +
5935
5985
  'so you match the exact required shape rather than guessing.\n\n' +
5986
+ '7. A Workbench App connection is perpetual product+environment runtime configuration. Once its ' +
5987
+ 'environment mapping, variables, and auth are saved, generated server code must initialize the ' +
5988
+ 'SDK with product+env and await ready(); do not repeat api.config/api.oauth in every codebase. ' +
5989
+ 'Direct actions, Features, Quotas, Fallbacks, and health checks reuse that hydrated connection. ' +
5990
+ 'Use api.config only when the user explicitly asks for a local override.\n\n' +
5936
5991
  'Default assumption for any backend built through this MCP server: orchestration goes through ' +
5937
5992
  'Features, provider risk goes through Quotas/Fallback, credentials go through Secrets, shared ' +
5938
5993
  'capability goes through reuse, and the ductape/ folder is what ships — not a database table ' +
@@ -6679,6 +6734,28 @@ async function main() {
6679
6734
  command: `products apps connect --product ${shellArgument(args.product_tag)} --app ${shellArgument(args.app_tag)}${mappings} --json`,
6680
6735
  });
6681
6736
  });
6737
+ server.registerTool('ductape_app_connection_configure', {
6738
+ title: 'Configure a Connected Ductape App',
6739
+ description: 'Configure, repair, or rotate an existing product App connection from its canonical JSON asset. ' +
6740
+ 'Inspect the App/auth schema first, store secrets separately, use $Secret{KEY} references, and ' +
6741
+ 'keep the file under ductape/apps/<app-tag>/connection.json. Omitted auth or variables preserve ' +
6742
+ 'the saved encrypted field; the tool never reads credential values back.',
6743
+ inputSchema: appConnectionConfigureInputSchema,
6744
+ }, async (args) => {
6745
+ const normalized = args.file.replace(/\\/g, '/');
6746
+ if (!/(^|\/)ductape\/apps\/[^/]+\/connection\.json$/.test(normalized)) {
6747
+ return {
6748
+ content: [{ type: 'text', text: JSON.stringify({
6749
+ error: 'INVALID_ASSET_PATH',
6750
+ message: 'Connection assets must be permanent JSON files at ductape/apps/<app-tag>/connection.json.',
6751
+ }, null, 2) }],
6752
+ isError: true,
6753
+ };
6754
+ }
6755
+ return cliHandler({
6756
+ command: `products apps configure --product ${shellArgument(args.product_tag)} --app ${shellArgument(args.app_tag)} --connection-file ${shellArgument(args.file)} --json`,
6757
+ });
6758
+ });
6682
6759
  server.registerTool('ductape_integrate_endpoint', {
6683
6760
  title: 'Integrate a New Endpoint',
6684
6761
  description: 'Call this FIRST whenever the user wants to integrate a new API endpoint — before writing any ' +
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ductape/mcp",
3
- "version": "0.2.34",
3
+ "version": "0.2.35",
4
4
  "description": "MCP server that exposes Ductape SDK operations via the backend proxy",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",