@ductape/mcp 0.2.16 → 0.2.17

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 +127 -18
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -445,7 +445,9 @@ ALL params are passed as a JSON array in positional order matching the SDK signa
445
445
  ductape_cli("products create --name <name> --tag <tag>")
446
446
  ductape_cli("products environments list <tag> --json")
447
447
  ductape_cli("products environments get <tag> <slug> --json")
448
- ductape_cli("products apps list --product <id> --json")
448
+ ductape_cli("products apps list --product <id_or_tag> --json") ← compact linked apps only
449
+ ductape_cli("products apps actions list --product <id_or_tag> --app <app_tag> --json")
450
+ ductape_cli("products apps actions get --product <id_or_tag> --app <app_tag> --action <action_tag> --json")
449
451
 
450
452
  SDK method signatures (for reference, admin key only):
451
453
  product.create [data: { name, description, tag?, envs?: [{slug, name}] }]
@@ -1086,6 +1088,25 @@ const snippetGenerateInputSchema = payloadGenerateInputSchema.extend({
1086
1088
  const schemaInputSchema = z.object({
1087
1089
  module: z.enum(['app', 'product']).optional().describe('Optional. Scope the result to one module. With no method, returns only the compact list of available methods.'),
1088
1090
  method: z.string().optional().describe('Optional method key such as "databases.create" or "notifications.update". Use with module to return only that method schema.'),
1091
+ product_tag: z.string().optional().describe('For live app-action discovery, the product the app is linked to. Must be supplied with app_tag and action_tag.'),
1092
+ app_tag: z.string().optional().describe('For live app-action discovery, the linked app tag. Must be supplied with product_tag and action_tag.'),
1093
+ action_tag: z.string().optional().describe('For live app-action discovery, the exact action tag whose complete contract should be returned.'),
1094
+ });
1095
+ const marketplaceDiscoverInputSchema = z.object({
1096
+ query: z.string().min(1).describe('Capability or provider search, for example "payments" or "paystack".'),
1097
+ category: z.string().optional().describe('Optional marketplace category/domain filter.'),
1098
+ limit: z.number().int().min(1).max(50).optional().default(10),
1099
+ });
1100
+ const marketplaceConnectInputSchema = z.object({
1101
+ product_tag: z.string().min(1).describe('Product that should receive the marketplace app connection.'),
1102
+ app_tag: z.string().min(1).describe('Exact public app tag returned by ductape_marketplace_discover.'),
1103
+ environments: z.array(z.object({
1104
+ app_env_slug: z.string().min(1),
1105
+ product_env_slug: z.string().min(1),
1106
+ })).min(1).describe('Explicit app-to-product environment mappings. Include every product environment that will use the app.'),
1107
+ });
1108
+ const marketplaceInspectInputSchema = z.object({
1109
+ app_tag: z.string().min(1).describe('Exact public app tag returned by ductape_marketplace_discover.'),
1089
1110
  });
1090
1111
  function toPrettyJson(value) {
1091
1112
  return JSON.stringify(value ?? {}, null, 2);
@@ -2636,17 +2657,27 @@ An App must be fully set up in Ductape before any code can use it:
2636
2657
  5. The App must be connected to the product (product.apps.add) and its envs mapped
2637
2658
 
2638
2659
  DISCOVER BEFORE CREATING:
2639
- ductape_cli("marketplace search payments --json")
2640
- ductape_cli("marketplace search paystack --json")
2660
+ ductape_marketplace_discover({ query: "payments" })
2661
+ ductape_marketplace_discover({ query: "paystack" })
2641
2662
  ductape_cli("marketplace categories --json")
2642
- ductape_cli("marketplace get <app_tag> --json")
2663
+ ductape_marketplace_inspect({ app_tag: "<exact-returned-tag>" })
2643
2664
 
2644
2665
  marketplace search matches capability terms against public app names, tags, descriptions,
2645
- categories, actions, and webhooks. marketplace get returns the complete public app definition,
2646
- including the exact current-version action tags and body/query/header/param schemas. Never infer
2666
+ categories, actions, and webhooks. Marketplace inspect returns a compact current-version definition,
2667
+ including the exact action tags and body/query/header/param schemas. Never infer
2647
2668
  Paystack action names such as "initialize" or "verify": inspect the marketplace record first.
2648
2669
  If no suitable app exists, create one or import Paystack's OpenAPI/Postman definition.
2649
2670
 
2671
+ CONNECT A DISCOVERED APP THROUGH MCP:
2672
+ 1. Run ductape_marketplace_discover and select an exact returned app tag.
2673
+ 2. Run ductape_marketplace_inspect to read its environments and compact action contracts.
2674
+ 3. Read product environments with ductape_cli("products environments list <product_tag> --json").
2675
+ 4. Match each product environment explicitly to one environment exposed by the app.
2676
+ 5. Call ductape_marketplace_connect({ product_tag, app_tag, environments }).
2677
+ 6. Verify with ductape_cli("products apps list --product <product_tag> --json").
2678
+ Never guess environment mappings or action tags. Connecting mutates product configuration;
2679
+ obtain user approval when the user has not already requested the connection.
2680
+
2650
2681
  ONLY after all five steps can any code call:
2651
2682
  ctx.api.run({ app: '<app_tag>', event: '<action_tag>', input: { ... } }) ← in a feature handler
2652
2683
  actions.run([{ product, env, app: '<app_tag>', action: '<action_tag>', input }]) ← at runtime
@@ -2676,18 +2707,21 @@ Manage environments (base URLs per stage) in Workbench; this currently has no CL
2676
2707
 
2677
2708
  Discover apps in a product and their actions (ALWAYS do this before writing any ctx.api.run call):
2678
2709
  Step 1 — list apps connected to the product:
2679
- ductape_cli("products get --tag <product_tag> --json") → full product document; check apps[]
2680
- ductape_cli("products apps list --product <product_id> --json") → apps[] with access_tag, envs
2681
- Step 2 — list actions in an app:
2682
- ductape_execute("actions.list", [app_tag]) → returns all action tags + names
2683
- Step 3 — fetch the input schema for an action:
2684
- ductape_execute("actions.fetch", [app_tag, action_tag])
2710
+ ductape_cli("products apps list --product <product_id_or_tag> --json")
2711
+ compact list containing ONLY apps linked to that product; accepts an id or tag
2712
+ Step 2 — list compact action summaries for one linked app:
2713
+ ductape_cli("products apps actions list --product <product_id_or_tag> --app <app_tag> --json")
2714
+ Step 3 — fetch one complete action contract:
2715
+ ductape_cli("products apps actions get --product <product_id_or_tag> --app <app_tag> --action <action_tag> --json")
2716
+ OR ductape_schema({ product_tag: "<product_tag>", app_tag: "<app_tag>", action_tag: "<action_tag>" })
2685
2717
  → returns { body: {fieldName: {type, required}}, params: {}, query: {}, headers: {} }
2686
2718
  OR: call ductape_generate_payload (operation_family="action", method="run",
2687
2719
  targets={app: "app_tag", action: "action_tag"}) to get the exact resolved payload shape
2688
2720
  Step 4 — call ductape_schema({ module: "app" }) if you need the JSON schema for creating/updating
2689
2721
  app resources (not for runtime input — use actions.fetch or ductape_generate_payload for that)
2690
2722
  NEVER assume action input field names. Always fetch the action definition first.
2723
+ NEVER fetch products get, apps get, marketplace get, or products apps list --full merely to inspect
2724
+ one action. Those expanded catalogues can be very large and may exceed MCP/client token limits.
2691
2725
 
2692
2726
  Manage actions (individual API endpoints) in Workbench or import an OpenAPI/Postman file.
2693
2727
  Creation/update are administrative and must never use ductape_execute.
@@ -2746,11 +2780,11 @@ Connecting an app to a product (after creation):
2746
2780
  3. Configure auth: Workbench
2747
2781
  4. Define actions: Workbench
2748
2782
  OR import: ductape_cli("apps import <file.json> -t postman|openapi")
2749
- 5. Connect to product: Requires the product_id (from ductape_cli("products get --tag <tag> --json")).
2783
+ 5. Connect to product: Requires the product_id.
2750
2784
  There is no CLI command for this step — the SDK product.apps.add method requires
2751
2785
  an access key which only the backend can provide. Connect via Workbench.
2752
- 6. Verify: ductape_cli("products get --tag <product_tag> --json") → check apps[] contains the app
2753
- ductape_execute("actions.list", [app_tag]) verify actions are registered
2786
+ 6. Verify: ductape_cli("products apps list --product <product_tag> --json")
2787
+ ductape_cli("products apps actions list --product <product_tag> --app <app_tag> --json")
2754
2788
  `.trim(),
2755
2789
  products: `
2756
2790
  DUCTAPE PRODUCTS
@@ -3524,7 +3558,8 @@ STEP 1 — UNDERSTAND the goal
3524
3558
  understand: what the feature does, what it returns, what can fail and how failures should behave.
3525
3559
 
3526
3560
  STEP 2 — INVENTORY existing Ductape components
3527
- Call ductape_cli("products get --tag <product_tag> --json") to read the full product document.
3561
+ Call ductape_cli("products components list --product-tag <product_tag> --json") for the compact inventory.
3562
+ Call ductape_cli("products apps list --product <product_tag> --json") for linked apps only.
3528
3563
  (product.* requires the access key — never use ductape_execute for product reads, it will return 403)
3529
3564
  Note what already exists:
3530
3565
  - databases[] → available for ctx.database.insert/query/update/delete steps
@@ -3616,10 +3651,25 @@ STEP 8 — SET rollbacks for reversible steps
3616
3651
  async (result) => ctx.api.run({ app: 'stripe', event: 'refund', input: { chargeId: result.id } })
3617
3652
  );
3618
3653
 
3619
- Code-first ctx step types currently record: function | action | database | graph | vector |
3654
+ Code-first ctx step types currently record: function | action | database | graph | vector | session |
3620
3655
  notification | storage | produce | quota | fallback | child_feature | sleep | wait_for_signal |
3621
3656
  checkpoint.
3622
3657
 
3658
+ CODE-FIRST SESSION LIFECYCLE:
3659
+ ctx.session is the optional session token inherited by the Feature and all nested Ductape
3660
+ operations. It is read-only execution context and is not a session service.
3661
+ ctx.sessions records explicit product-session lifecycle steps:
3662
+ ctx.sessions.start<T>({ session: "player-session", data, cache? })
3663
+ ctx.sessions.verify<T>({ session: "player-session", token, cache? })
3664
+ ctx.sessions.refresh<T>({ session: "player-session", refreshToken, cache? })
3665
+ ctx.sessions.revoke({ session: "player-session", sessionId?, identifier? })
3666
+ ctx.sessions.list<T>({ session: "player-session", identifier?, page?, limit?, cache? })
3667
+ Put each call inside ctx.step(). The session field identifies the configured product session; the
3668
+ executor supplies product and env. start creates a new token pair but does not replace ctx.session
3669
+ for subsequent steps in the same Feature. Pass the returned token explicitly where application
3670
+ logic needs the newly created session. Never serialize the inherited ctx.session into the Feature
3671
+ definition, logs, metadata, or another step unless the target operation explicitly requires a token.
3672
+
3623
3673
  Valid synchronous Feature candidates include generate-world, resolve-nation-turn,
3624
3674
  calculate-route-capacity, price-subscription, evaluate-entitlement, and build-replay.
3625
3675
 
@@ -5376,6 +5426,35 @@ async function main() {
5376
5426
  };
5377
5427
  const schemaHandler = async (args) => {
5378
5428
  try {
5429
+ const liveActionScope = [args.product_tag, args.app_tag, args.action_tag];
5430
+ if (liveActionScope.some(Boolean)) {
5431
+ if (!liveActionScope.every(Boolean)) {
5432
+ throw new Error('product_tag, app_tag, and action_tag are all required to fetch a live app action contract');
5433
+ }
5434
+ const response = await cliHandler({
5435
+ command: `products apps actions get --product ${shellArgument(args.product_tag)} --app ${shellArgument(args.app_tag)} --action ${shellArgument(args.action_tag)} --json`,
5436
+ });
5437
+ if (response.isError)
5438
+ return response;
5439
+ const raw = response.content[0]?.type === 'text' ? response.content[0].text : '';
5440
+ let action = raw;
5441
+ try {
5442
+ action = JSON.parse(raw);
5443
+ }
5444
+ catch { /* Preserve the CLI diagnostic verbatim. */ }
5445
+ return {
5446
+ content: [{
5447
+ type: 'text',
5448
+ text: JSON.stringify({
5449
+ product_tag: args.product_tag,
5450
+ app_tag: args.app_tag,
5451
+ action_tag: args.action_tag,
5452
+ action,
5453
+ hint: 'This is the complete contract for one action linked to this product; use products apps actions list for compact discovery.',
5454
+ }, null, 2),
5455
+ }],
5456
+ };
5457
+ }
5379
5458
  if (args.method && !args.module) {
5380
5459
  throw new Error('module is required when method is provided');
5381
5460
  }
@@ -5465,9 +5544,10 @@ async function main() {
5465
5544
  }, snippetGenerateHandler);
5466
5545
  server.registerTool('ductape_schema', {
5467
5546
  title: 'Ductape Asset Schema',
5468
- description: 'Returns a compact method index or one targeted asset schema derived from the SDK Joi validators. ' +
5547
+ description: 'Returns a compact method index, one targeted asset schema, or one complete live app-action contract. ' +
5469
5548
  'Call with module="app" or module="product" first to list method keys, then call again with ' +
5470
5549
  'module and method (for example method="databases.create") for the complete field schema. ' +
5550
+ 'For one linked app action, call with product_tag, app_tag, and action_tag; do not fetch a full app catalogue. ' +
5471
5551
  'Avoid calling without module unless you explicitly need the entire manifest.\n\n' +
5472
5552
  'ALWAYS call this before constructing a file for "resources <type> create" or any cloud ' +
5473
5553
  'import/provision operation — field shapes are not guessable from context.\n\n' +
@@ -5542,6 +5622,35 @@ async function main() {
5542
5622
  'Supports in-place and new-codebase guidance destinations. Read-only unless write or ensure_product is explicitly enabled.',
5543
5623
  inputSchema: migrationInputSchema,
5544
5624
  }, migrationHandler);
5625
+ server.registerTool('ductape_marketplace_discover', {
5626
+ title: 'Discover Ductape Marketplace Apps',
5627
+ description: 'Search public marketplace apps by capability and return compact app, environment, and action summaries. ' +
5628
+ 'Use the returned exact app tag; never infer provider or action tags from a brand name.',
5629
+ inputSchema: marketplaceDiscoverInputSchema,
5630
+ }, async (args) => cliHandler({
5631
+ command: `marketplace search ${shellArgument(args.query)}${args.category ? ` --category ${shellArgument(args.category)}` : ''} --limit ${args.limit ?? 10} --json`,
5632
+ }));
5633
+ server.registerTool('ductape_marketplace_inspect', {
5634
+ title: 'Inspect a Ductape Marketplace App',
5635
+ description: 'Return the selected public app version, supported environment slugs, and compact action contracts. ' +
5636
+ 'Call this after discovery and before choosing environment mappings or writing action calls.',
5637
+ inputSchema: marketplaceInspectInputSchema,
5638
+ }, async (args) => cliHandler({
5639
+ command: `marketplace get ${shellArgument(args.app_tag)} --json`,
5640
+ }));
5641
+ server.registerTool('ductape_marketplace_connect', {
5642
+ title: 'Connect a Marketplace App to a Product',
5643
+ description: 'Create/reuse secure app access, connect an exact discovered marketplace app to a product, and map its environments. ' +
5644
+ 'Discover first, inspect the returned environments/actions, obtain any required user configuration, and never guess mappings.',
5645
+ inputSchema: marketplaceConnectInputSchema,
5646
+ }, async (args) => {
5647
+ const mappings = args.environments
5648
+ .map((env) => ` --env-map ${shellArgument(`${env.app_env_slug}:${env.product_env_slug}`)}`)
5649
+ .join('');
5650
+ return cliHandler({
5651
+ command: `products apps connect --product ${shellArgument(args.product_tag)} --app ${shellArgument(args.app_tag)}${mappings} --json`,
5652
+ });
5653
+ });
5545
5654
  server.registerTool('ductape_cli', {
5546
5655
  title: 'Ductape CLI',
5547
5656
  description: 'Run a Ductape CLI command for administrative operations.\n\n' +
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ductape/mcp",
3
- "version": "0.2.16",
3
+ "version": "0.2.17",
4
4
  "description": "MCP server that exposes Ductape SDK operations via the backend proxy",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",