@clipform/mcp-server 3.3.1 → 3.7.1

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.
@@ -6,7 +6,7 @@ import {
6
6
  getWorkflowText,
7
7
  objectType,
8
8
  registerPrompts
9
- } from "./chunk-22BV4NSB.js";
9
+ } from "./chunk-GJ3XQSQY.js";
10
10
  import {
11
11
  GUIDE_TYPES,
12
12
  QUIZ_VARIANTS,
@@ -15,13 +15,18 @@ import {
15
15
  getGuideUri,
16
16
  guideFallbackText,
17
17
  registerResources
18
- } from "./chunk-ELK26KWM.js";
18
+ } from "./chunk-5SCRFNYJ.js";
19
+ import {
20
+ ANON_PREVIEW_NOTICE,
21
+ FULL_CAPS,
22
+ anonPreviewNotice,
23
+ capsFromToolsets
24
+ } from "./chunk-YOVLSXPW.js";
19
25
  import {
20
26
  ACTIVE_NODE_TYPES,
21
27
  CONTACT_FIELDS,
22
28
  FEATURE_FLAGS,
23
29
  FORM_TYPE_ALIASES,
24
- FULL_CAPS,
25
30
  MCP_ANON_PUBLISH_GATE,
26
31
  MCP_TOOL_SECURITY,
27
32
  MCP_TOOL_TIERS,
@@ -31,7 +36,6 @@ import {
31
36
  authChallengeMeta,
32
37
  bfsOrder,
33
38
  callApi,
34
- capsFromToolsets,
35
39
  defaultTarget,
36
40
  errorResult,
37
41
  exposedCompositionIds,
@@ -39,12 +43,12 @@ import {
39
43
  resolveFormType,
40
44
  structuredResult,
41
45
  textResult
42
- } from "./chunk-SEZ37YSH.js";
46
+ } from "./chunk-SHTP4AJC.js";
43
47
  import {
44
48
  getMcpAuth,
45
49
  runWithMcpAuth,
46
50
  runWithMcpTool
47
- } from "./chunk-A5CFGL27.js";
51
+ } from "./chunk-VPF6MLKM.js";
48
52
  import {
49
53
  __commonJS,
50
54
  __export,
@@ -17240,7 +17244,7 @@ function registerCreateFormTool(server) {
17240
17244
  "clipform_create_form",
17241
17245
  {
17242
17246
  title: "Create Clipform",
17243
- description: `Create a new Clipform (interactive video-style form). Returns a viewer URL and form ID. When connected via an authenticated MCP client (e.g. claude.ai), the form lands directly in the user's workspace. Anonymous sessions get a claim URL to transfer ownership later.
17247
+ description: `Create a new Clipform (interactive video-style form). Returns a viewer URL and form ID. When connected via an authenticated MCP client (e.g. claude.ai), the form lands directly in the user's workspace. Anonymous sessions build into a temporary account of their own: forms stay drafts with a private preview link. Some results also include a one-time claim URL that signs the user into that account; relay it when present.
17244
17248
 
17245
17249
  ${ONBOARDING_OFFER_TOOL_CUE}
17246
17250
 
@@ -17368,7 +17372,7 @@ Example: A form that asks a question, collects contact info, then finishes:
17368
17372
  });
17369
17373
  if (!createResult.ok) {
17370
17374
  const message = `Form NOT created (nothing was saved): ${createResult.error}`;
17371
- return isAnonymousAccountRequired(createResult) ? errorResult(message, authChallengeMeta("invalid_token", message)) : errorResult(message);
17375
+ return isAnonymousAccountRequired(createResult) ? errorResult(message, authChallengeMeta("invalid_token", createResult.apiMessage ?? message)) : errorResult(message);
17372
17376
  }
17373
17377
  const { data } = createResult;
17374
17378
  const formId = data.form_id;
@@ -17413,6 +17417,8 @@ Example: A form that asks a question, collects contact info, then finishes:
17413
17417
  formUrl ? `The URLs above are exact values; constructed or guessed URLs return 404. Use the ${firstUrlLabel} URL and ${secondUrlLabel} URL as shown.` : `The ${firstUrlLabel} URL above is an exact value; constructed or guessed URLs return 404.`,
17414
17418
  `Pass form_id on follow-up tools (get_form, add_node, attach_node_media, etc.).`
17415
17419
  );
17420
+ const anonNotice = isPreview ? anonPreviewNotice() : null;
17421
+ if (anonNotice) lines.push(``, anonNotice);
17416
17422
  if (planContext) {
17417
17423
  const nodePart = planContext.node_limit === null ? "unlimited nodes" : `up to ${planContext.node_limit} nodes per form`;
17418
17424
  const formPart = planContext.form_limit === null ? "unlimited forms" : `up to ${planContext.form_limit} forms`;
@@ -17683,7 +17689,7 @@ function registerListFormsTool(server) {
17683
17689
  "clipform_list_forms",
17684
17690
  {
17685
17691
  title: "List Clipforms",
17686
- description: `List forms in your workspace with optional filtering. Returns paginated results (cursor-based). next_cursor is included when more results exist. To find or open a form by name, pass search with part of its title instead of paging through results.`,
17692
+ description: `List forms in your workspace with optional filtering. Returns paginated results (cursor-based). next_cursor is included when more results exist. To find or open a form by name, pass search with part of its title instead of paging through results. Needs a signed-in Clipform account (an anonymous session is asked to sign in).`,
17687
17693
  inputSchema: {
17688
17694
  workspace_id: workspaceIdInput,
17689
17695
  limit: external_exports.number().int().min(1).max(100).optional().describe("Number of forms to return (default 25, max 100)"),
@@ -18034,7 +18040,10 @@ function registerUpdateFormTool(server) {
18034
18040
  body
18035
18041
  });
18036
18042
  if (!result.ok) {
18037
- return isAnonymousAccountRequired(result) ? errorResult(result.error, authChallengeMeta("invalid_token", result.error)) : errorResult(result.error);
18043
+ return isAnonymousAccountRequired(result) ? errorResult(
18044
+ result.error,
18045
+ authChallengeMeta("invalid_token", result.apiMessage ?? result.error)
18046
+ ) : errorResult(result.error);
18038
18047
  }
18039
18048
  }
18040
18049
  if (tags) {
@@ -18043,7 +18052,10 @@ function registerUpdateFormTool(server) {
18043
18052
  body: { tags }
18044
18053
  });
18045
18054
  if (!tagResult.ok) {
18046
- return isAnonymousAccountRequired(tagResult) ? errorResult(tagResult.error, authChallengeMeta("invalid_token", tagResult.error)) : errorResult(tagResult.error);
18055
+ return isAnonymousAccountRequired(tagResult) ? errorResult(
18056
+ tagResult.error,
18057
+ authChallengeMeta("invalid_token", tagResult.apiMessage ?? tagResult.error)
18058
+ ) : errorResult(tagResult.error);
18047
18059
  }
18048
18060
  }
18049
18061
  const updates = [];
@@ -18117,6 +18129,10 @@ Your form is live at: ${viewerUrl}
18117
18129
  Share this URL with respondents. View responses any time with clipform_get_results (form_id: ${form_id})${responsesUrl ? `, or in the dashboard: ${responsesUrl}` : ""}`;
18118
18130
  }
18119
18131
  }
18132
+ const anonNotice = anonPreviewNotice();
18133
+ if (anonNotice) resultText += `
18134
+
18135
+ ${anonNotice}`;
18120
18136
  return structuredResult(resultText, { form_id, updated_fields: updatedFields });
18121
18137
  }
18122
18138
  );
@@ -18151,7 +18167,7 @@ function registerDeleteFormTool(server) {
18151
18167
  "clipform_delete_form",
18152
18168
  {
18153
18169
  title: "Delete Clipform",
18154
- description: `Move a form and all its nodes to the trash. It stops accepting responses immediately and can be restored later. Requires user confirmation before it runs.`,
18170
+ description: `Move a form and all its nodes to the trash. It stops accepting responses immediately and can be restored later. Requires user confirmation before it runs. Needs a signed-in Clipform account (an anonymous session is asked to sign in).`,
18155
18171
  inputSchema: {
18156
18172
  form_id: external_exports.string().uuid().describe("The form UUID to delete (returned by clipform_create_form, not the short share_id from the URL)"),
18157
18173
  confirm: external_exports.boolean().optional().describe(CONFIRM_FIELD_DESCRIPTION)
@@ -18258,7 +18274,7 @@ function registerGetResultsTool(server) {
18258
18274
  "clipform_get_results",
18259
18275
  {
18260
18276
  title: "Get Clipform Results",
18261
- description: `View response counts, choice/action answer breakdowns, and recent open-text answers for a form. Contact, file, draw, camera, and payment answers are counts only - use the dashboard for per-response detail.`,
18277
+ description: `View response counts, choice/action answer breakdowns, and recent open-text answers for a form. Contact, file, draw, camera, and payment answers are counts only - use the dashboard for per-response detail. Needs a signed-in Clipform account (an anonymous session is asked to sign in).`,
18262
18278
  inputSchema: {
18263
18279
  form_id: external_exports.string().describe("The form UUID (returned by clipform_create_form, not the short share_id from the URL)")
18264
18280
  },
@@ -18361,7 +18377,7 @@ function registerGetResponsesTool(server) {
18361
18377
  "clipform_get_responses",
18362
18378
  {
18363
18379
  title: "List form responses",
18364
- description: "List a Clipform form's individual responses (submissions) with time filtering - complements clipform_get_results (aggregates). Answers questions like 'what came in during the last 24 hours', 'what's the longest answer', 'what did people say'. Text answers plus a non-PII payment summary (amount and status); contact details, file uploads, and audio/video answers are redacted to placeholders and the customer's payment details stay in the dashboard (the responses URL from clipform_get_form). Responses are sorted newest first unless sort: 'oldest'.",
18380
+ description: "List a Clipform form's individual responses (submissions) with time filtering - complements clipform_get_results (aggregates). Answers questions like 'what came in during the last 24 hours', 'what's the longest answer', 'what did people say'. Text answers plus a non-PII payment summary (amount and status); contact details, file uploads, and audio/video answers are redacted to placeholders and the customer's payment details stay in the dashboard (the responses URL from clipform_get_form). Responses are sorted newest first unless sort: 'oldest'. Needs a signed-in Clipform account (an anonymous session is asked to sign in).",
18365
18381
  inputSchema: {
18366
18382
  form_id: external_exports.string().describe("Form UUID (from clipform_list_forms / clipform_create_form)"),
18367
18383
  since: external_exports.string().datetime({ offset: true }).optional().describe("Only responses submitted at or after this ISO 8601 time (e.g. '2026-08-29T00:00:00Z')"),
@@ -18498,7 +18514,7 @@ function registerWhoamiTool(server) {
18498
18514
  "clipform_whoami",
18499
18515
  {
18500
18516
  title: "Who Am I",
18501
- description: `Show the current identity: auth mode (api key, oauth, session, or anonymous), active workspace, and plan limits.`,
18517
+ description: `Show the current identity: auth mode (api key, oauth, session, or anonymous), active workspace, and plan limits. Needs a signed-in Clipform account (an anonymous session is asked to sign in).`,
18502
18518
  inputSchema: {},
18503
18519
  outputSchema: {
18504
18520
  auth_mode: external_exports.enum(["api_key", "oauth", "session", "anonymous"]).describe("How this session is authenticated"),
@@ -18515,7 +18531,8 @@ function registerWhoamiTool(server) {
18515
18531
  links: external_exports.object({
18516
18532
  dashboard: external_exports.string().describe("Dashboard home for the active workspace."),
18517
18533
  forms: external_exports.string().describe("Forms list for the active workspace.")
18518
- }).optional().describe("Workspace-level dashboard links - only present for a non-anonymous caller.")
18534
+ }).optional().describe("Workspace-level dashboard links - only present for a non-anonymous caller."),
18535
+ notice: external_exports.string().optional().describe("Anonymous sessions only: the account is a temporary preview until claimed.")
18519
18536
  },
18520
18537
  annotations: {
18521
18538
  readOnlyHint: true,
@@ -18531,8 +18548,9 @@ function registerWhoamiTool(server) {
18531
18548
  return errorResult(result.error);
18532
18549
  }
18533
18550
  const me = result.data;
18534
- const authMode = me.auth_mode ?? "anonymous";
18535
- const isAuthenticated = me.auth_mode != null && me.auth_mode !== "anonymous";
18551
+ const ctx = getMcpAuth();
18552
+ const authMode = ctx?.is_anonymous ? "anonymous" : me.auth_mode ?? "anonymous";
18553
+ const isAuthenticated = authMode !== "anonymous";
18536
18554
  const workspace = me.workspace ? { id: me.workspace.id, name: me.workspace.name } : null;
18537
18555
  const plan = {
18538
18556
  name: me.plan?.name ?? "Free",
@@ -18549,7 +18567,6 @@ function registerWhoamiTool(server) {
18549
18567
  if (Array.isArray(me.workspaces)) {
18550
18568
  structured.workspaces = me.workspaces.map((w) => ({ id: w.id, name: w.name }));
18551
18569
  }
18552
- const ctx = getMcpAuth();
18553
18570
  if (!structured.workspaces && ctx?.listWorkspaces) {
18554
18571
  try {
18555
18572
  const list = await ctx.listWorkspaces();
@@ -18569,6 +18586,13 @@ function registerWhoamiTool(server) {
18569
18586
  `Workspaces you can act in (pass one of these ids as the workspace argument to target it; omit it to use the default): ` + list.map((w) => `${w.name} (${w.id})`).join(", ")
18570
18587
  );
18571
18588
  }
18589
+ if (authMode === "anonymous") {
18590
+ structured.notice = ANON_PREVIEW_NOTICE;
18591
+ lines.push(ANON_PREVIEW_NOTICE);
18592
+ lines.push(
18593
+ "Anonymous session: forms are previews until claimed. Open the claim URL from clipform_create_form (or sign up) to claim the workspace and publish."
18594
+ );
18595
+ }
18572
18596
  if (structured.links) {
18573
18597
  const links = structured.links;
18574
18598
  lines.push(`Dashboard: ${links.dashboard}`, `Forms list: ${links.forms}`);
@@ -20411,12 +20435,18 @@ function registerListAssetsTool(server) {
20411
20435
  annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false }
20412
20436
  },
20413
20437
  async ({ type }) => {
20414
- const result = await callApi("/internal/assets", {
20415
- method: "GET",
20416
- params: { type: type ?? "all" }
20417
- });
20418
- if (!result.ok) return errorResult(result.error);
20419
- const data = result.data;
20438
+ const loader = getMcpAuth()?.loadInternalContent;
20439
+ let data;
20440
+ if (loader) {
20441
+ data = await loader("assets", { type: type ?? "all" });
20442
+ } else {
20443
+ const result = await callApi("/internal/assets", {
20444
+ method: "GET",
20445
+ params: { type: type ?? "all" }
20446
+ });
20447
+ if (!result.ok) return errorResult(result.error);
20448
+ data = result.data;
20449
+ }
20420
20450
  const lines = [];
20421
20451
  const structured = {
20422
20452
  sfx: (data.sfx ?? []).map((s) => ({ name: s.name, description: s.description ?? null, path: s.path })),
@@ -20961,4 +20991,4 @@ export {
20961
20991
  buildInstructions,
20962
20992
  createServer
20963
20993
  };
20964
- //# sourceMappingURL=chunk-4XCXDH3I.js.map
20994
+ //# sourceMappingURL=chunk-PXHGG57Z.js.map