@clipform/mcp-server 1.30.0 → 1.31.0

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/README.md CHANGED
@@ -55,7 +55,7 @@ You can also pass the key as a CLI flag: `npx -y @clipform/mcp-server --api-key=
55
55
 
56
56
  | Tool | Description |
57
57
  |------|-------------|
58
- | `clipform_create_form` | Create a new form with nodes, theming, and tags in one call |
58
+ | `clipform_create_form` | Create a new form with nodes, theming, and tags in one call. Returns the created node IDs (structured output) so media steps need no follow-up lookup |
59
59
  | `clipform_list_forms` | List forms in your workspace with filtering and pagination |
60
60
  | `clipform_get_form` | View a form and all its nodes |
61
61
  | `clipform_update_form` | Change title, publish status, or settings |
@@ -17167,6 +17167,13 @@ Example: A form that asks a question, collects contact info, then finishes:
17167
17167
  font_family: external_exports.string().optional().describe("AI-PROTECTED: Only set when the user explicitly requests a specific font."),
17168
17168
  tags: external_exports.array(external_exports.string()).optional().describe("Tags for indexing (e.g. ['quiz', 'trivia', 'arsenal']). Include format, genre, and topics.")
17169
17169
  },
17170
+ outputSchema: {
17171
+ form_id: external_exports.string().describe("Form UUID - pass to follow-up tools"),
17172
+ viewer_url: external_exports.string().describe("Live form URL for respondents"),
17173
+ dashboard_url: external_exports.string().optional().describe("Builder URL (sign in to edit)"),
17174
+ nodes: external_exports.array(external_exports.object({ id: external_exports.string(), type: external_exports.string(), prompt: external_exports.string() })).describe("Created nodes in order - IDs for upload_node_media / update_node"),
17175
+ plan: external_exports.object({ name: external_exports.string(), auth_mode: external_exports.string() }).optional().describe("Plan and auth context for this session")
17176
+ },
17170
17177
  annotations: {
17171
17178
  readOnlyHint: false,
17172
17179
  destructiveHint: false,
@@ -17250,6 +17257,7 @@ Example: A form that asks a question, collects contact info, then finishes:
17250
17257
  body: settingsBody
17251
17258
  });
17252
17259
  }
17260
+ const createdNodes = [];
17253
17261
  for (const q of nodes) {
17254
17262
  applyNodeDefaults(q);
17255
17263
  const addResult = await callApi(`/forms/${formId}/nodes`, {
@@ -17259,6 +17267,11 @@ Example: A form that asks a question, collects contact info, then finishes:
17259
17267
  if (!addResult.ok) {
17260
17268
  return errorResult(`Failed to add node "${q.prompt}": ${addResult.error}`);
17261
17269
  }
17270
+ createdNodes.push({
17271
+ id: addResult.data.node_id,
17272
+ type: q.type,
17273
+ prompt: q.prompt
17274
+ });
17262
17275
  }
17263
17276
  if (tags && tags.length > 0) {
17264
17277
  await callApi(`/forms/${formId}/tags`, {
@@ -17266,13 +17279,16 @@ Example: A form that asks a question, collects contact info, then finishes:
17266
17279
  body: { tags }
17267
17280
  });
17268
17281
  }
17282
+ const truncate = (s, n = 60) => s.length > n ? `${s.slice(0, n - 1)}\u2026` : s;
17269
17283
  const lines = [
17270
17284
  `Form created and live.`,
17271
17285
  ``,
17272
17286
  `Title: ${title}`,
17273
- `Nodes: ${nodes.length}`,
17274
17287
  `Form ID: ${formId}`,
17275
17288
  ``,
17289
+ `Node IDs (use directly with upload_node_media / update_node - no get_form round-trip needed):`,
17290
+ ...createdNodes.map((n) => `- [${n.type}] "${truncate(n.prompt)}": ${n.id}`),
17291
+ ``,
17276
17292
  `FORM URL (live - share this with respondents): ${data.viewer_url}`
17277
17293
  ];
17278
17294
  if (formUrl) {
@@ -17281,7 +17297,7 @@ Example: A form that asks a question, collects contact info, then finishes:
17281
17297
  lines.push(
17282
17298
  ``,
17283
17299
  `The form is live and accessible at the FORM URL above. Continue with media/narration steps if needed - changes appear immediately.`,
17284
- `CRITICAL: Copy the URLs above character-for-character into your response. Do NOT construct, guess, or invent any URLs. Only use the exact FORM URL and DASHBOARD URL provided here.`,
17300
+ `The URLs above are exact values; constructed or guessed URLs return 404. Use the FORM URL and DASHBOARD URL as shown.`,
17285
17301
  `Pass form_id on follow-up tools (get_form, add_node, upload_node_media, etc.).`
17286
17302
  );
17287
17303
  if (planContext) {
@@ -17300,7 +17316,16 @@ Example: A form that asks a question, collects contact info, then finishes:
17300
17316
  );
17301
17317
  }
17302
17318
  }
17303
- return textResult(lines.join("\n"));
17319
+ return {
17320
+ content: [{ type: "text", text: lines.join("\n") }],
17321
+ structuredContent: {
17322
+ form_id: formId,
17323
+ viewer_url: data.viewer_url,
17324
+ ...formUrl ? { dashboard_url: formUrl } : {},
17325
+ nodes: createdNodes,
17326
+ ...planContext ? { plan: { name: planContext.plan_name, auth_mode: planContext.auth_mode } } : {}
17327
+ }
17328
+ };
17304
17329
  }
17305
17330
  );
17306
17331
  }
@@ -17678,6 +17703,10 @@ function registerUpdateNodeTool(server) {
17678
17703
  if (options !== void 0)
17679
17704
  changes.push(`Options \u2192 ${options.map((o) => o.content).join(", ")}`);
17680
17705
  allLines.push(`Node ${node_id} updated: ${changes.join(", ")}`);
17706
+ const warnings = result.data.warnings;
17707
+ if (warnings?.length) {
17708
+ for (const w of warnings) allLines.push(`Node ${node_id} warning: ${w}`);
17709
+ }
17681
17710
  }
17682
17711
  return textResult(allLines.join("\n"));
17683
17712
  }
@@ -18838,4 +18867,4 @@ export {
18838
18867
  JSONRPCMessageSchema,
18839
18868
  createServer
18840
18869
  };
18841
- //# sourceMappingURL=chunk-Y3A5HHT6.js.map
18870
+ //# sourceMappingURL=chunk-46RSQK6L.js.map