@clipform/mcp-server 2.3.0 → 2.5.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 +5 -4
- package/dist/auth-context.d.ts +25 -1
- package/dist/auth-context.js +5 -1
- package/dist/{chunk-YZJZ5NPL.js → chunk-3BYQLPTT.js} +338 -15
- package/dist/chunk-3BYQLPTT.js.map +1 -0
- package/dist/{chunk-QC4JULCW.js → chunk-3OX54HSJ.js} +509 -169
- package/dist/chunk-3OX54HSJ.js.map +1 -0
- package/dist/{chunk-WNXTF76M.js → chunk-6EHOUAPE.js} +3 -3
- package/dist/{chunk-WNXTF76M.js.map → chunk-6EHOUAPE.js.map} +1 -1
- package/dist/{chunk-V4L5RQWK.js → chunk-ENHVQDSI.js} +5 -1
- package/dist/chunk-ENHVQDSI.js.map +1 -0
- package/dist/{chunk-WCPHQ4GU.js → chunk-NYMC63ZK.js} +7 -7
- package/dist/{chunk-WCPHQ4GU.js.map → chunk-NYMC63ZK.js.map} +1 -1
- package/dist/index.js +27 -12
- package/dist/index.js.map +1 -1
- package/dist/prompts.js +3 -3
- package/dist/resources.js +3 -3
- package/dist/server.d.ts +11 -0
- package/dist/server.js +5 -5
- package/package.json +11 -4
- package/dist/chunk-QC4JULCW.js.map +0 -1
- package/dist/chunk-V4L5RQWK.js.map +0 -1
- package/dist/chunk-YZJZ5NPL.js.map +0 -1
package/README.md
CHANGED
|
@@ -65,9 +65,11 @@ Your MCP client lists these automatically on connect (via `tools/list`). Full re
|
|
|
65
65
|
|------|-------------|
|
|
66
66
|
| `clipform_create_form` | Create a new Clipform (interactive video-style form). |
|
|
67
67
|
| `clipform_list_forms` | List forms in your workspace with optional filtering. |
|
|
68
|
-
| `
|
|
68
|
+
| `clipform_whoami` | Show the current identity: auth mode (api key, session, or anonymous), active workspace, and plan limits. |
|
|
69
|
+
| `clipform_get_form` | Retrieve a form's details including all nodes in sequential order and their routing. |
|
|
69
70
|
| `clipform_update_form` | Update a form's title, publish status, settings, or tags. |
|
|
70
71
|
| `clipform_delete_form` | Move a form and all its nodes to the trash. |
|
|
72
|
+
| `clipform_get_results` | View response counts, choice/action answer breakdowns, and recent open-text answers for a form. |
|
|
71
73
|
| `clipform_add_node` | Add a new node to an existing form. |
|
|
72
74
|
| `clipform_update_node` | Update one or more existing nodes' text, type, config, or options. |
|
|
73
75
|
| `clipform_delete_node` | Delete a node from a form. |
|
|
@@ -76,10 +78,9 @@ Your MCP client lists these automatically on connect (via `tools/list`). Full re
|
|
|
76
78
|
| `clipform_attach_node_media` | Attach an existing workspace media asset (from clipform_upload_media_asset) to one or more nodes (max 10). |
|
|
77
79
|
| `clipform_get_node_media` | Get the media attached to a node, including processing status. |
|
|
78
80
|
| `clipform_delete_node_media` | Remove media from a node. |
|
|
79
|
-
| `clipform_set_logic` | Set
|
|
80
|
-
| `clipform_log_generation` |
|
|
81
|
+
| `clipform_set_logic` | Set the next node for one or more nodes, wiring a linear route (A to B to C). |
|
|
82
|
+
| `clipform_log_generation` | Internal audit step run by a form-generation workflow. |
|
|
81
83
|
| `clipform_search_news` | Fallback news lookup for clients without native web search. |
|
|
82
|
-
| `clipform_youtube_transcript` | Extract the transcript, title, and channel info from a YouTube video. |
|
|
83
84
|
| `clipform_generate_tts` | Generate narration audio from text with word-level captions. |
|
|
84
85
|
| `clipform_generate_video` | Generate a video from images, video clips, or both, synced to an audio track. |
|
|
85
86
|
| `clipform_search_media` | Search images or stock video clips. |
|
package/dist/auth-context.d.ts
CHANGED
|
@@ -14,9 +14,33 @@ interface McpAuthContext {
|
|
|
14
14
|
scopes: string[];
|
|
15
15
|
tool_name?: string;
|
|
16
16
|
api_key?: string;
|
|
17
|
+
is_anonymous?: boolean;
|
|
18
|
+
mcp_mint_proof?: string;
|
|
17
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* Marker header the in-process MCP tool layer sets on its outgoing API
|
|
22
|
+
* requests (api-client.ts) when `is_anonymous` is true, so an anonymous
|
|
23
|
+
* app-chat session can't launder itself into an unrestricted API-key caller
|
|
24
|
+
* by asking the bot to publish/mint credentials on its behalf. apps/api's
|
|
25
|
+
* authMiddleware / workspaceAccessMiddleware / requireWorkspaceWriteAuth
|
|
26
|
+
* read this on the API-key path and set isAnonymous accordingly - trusting
|
|
27
|
+
* it is safe because it can only RESTRICT a caller: a real integration that
|
|
28
|
+
* sets this header on its own API-key requests only denies itself, it can
|
|
29
|
+
* never use it to gain anonymous-JWT privileges it doesn't already have.
|
|
30
|
+
*/
|
|
31
|
+
declare const MCP_ANONYMOUS_HEADER = "x-clipform-anonymous";
|
|
32
|
+
/**
|
|
33
|
+
* Carries `mcp_mint_proof` on the same outgoing bot-key request. Unlike
|
|
34
|
+
* MCP_ANONYMOUS_HEADER (a boolean that can only ever RESTRICT), this header's
|
|
35
|
+
* VALUE matters - it names an identity a claim token gets bound to - so its
|
|
36
|
+
* value is HMAC-signed (mcp-mint-proof.ts) rather than trusted raw: a direct
|
|
37
|
+
* external caller reaching `POST /v1/forms` with any valid workspace API key
|
|
38
|
+
* could otherwise hand-set an unsigned "mint uid" header to an arbitrary
|
|
39
|
+
* victim's uid themselves (#3330 review).
|
|
40
|
+
*/
|
|
41
|
+
declare const MCP_MINT_PROOF_HEADER = "x-clipform-mcp-mint-proof";
|
|
18
42
|
declare function runWithMcpAuth<T>(ctx: McpAuthContext, fn: () => Promise<T> | T): Promise<T> | T;
|
|
19
43
|
declare function getMcpAuth(): McpAuthContext | undefined;
|
|
20
44
|
declare function runWithMcpTool<T>(toolName: string, fn: () => Promise<T> | T): Promise<T> | T;
|
|
21
45
|
|
|
22
|
-
export { type McpAuthContext, getMcpAuth, runWithMcpAuth, runWithMcpTool };
|
|
46
|
+
export { MCP_ANONYMOUS_HEADER, MCP_MINT_PROOF_HEADER, type McpAuthContext, getMcpAuth, runWithMcpAuth, runWithMcpTool };
|
package/dist/auth-context.js
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
|
+
MCP_ANONYMOUS_HEADER,
|
|
3
|
+
MCP_MINT_PROOF_HEADER,
|
|
2
4
|
getMcpAuth,
|
|
3
5
|
runWithMcpAuth,
|
|
4
6
|
runWithMcpTool
|
|
5
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-ENHVQDSI.js";
|
|
6
8
|
import "./chunk-G3PMV62Z.js";
|
|
7
9
|
export {
|
|
10
|
+
MCP_ANONYMOUS_HEADER,
|
|
11
|
+
MCP_MINT_PROOF_HEADER,
|
|
8
12
|
getMcpAuth,
|
|
9
13
|
runWithMcpAuth,
|
|
10
14
|
runWithMcpTool
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
|
+
MCP_ANONYMOUS_HEADER,
|
|
3
|
+
MCP_MINT_PROOF_HEADER,
|
|
2
4
|
getMcpAuth
|
|
3
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-ENHVQDSI.js";
|
|
4
6
|
import {
|
|
5
7
|
isAuthFault,
|
|
6
8
|
isServerFault,
|
|
@@ -95,6 +97,17 @@ var FEATURES = {
|
|
|
95
97
|
status: "live",
|
|
96
98
|
category: "builder"
|
|
97
99
|
},
|
|
100
|
+
anonymous_builder: {
|
|
101
|
+
name: "Anonymous builder",
|
|
102
|
+
description: "Try the builder without an account via /try - an anonymous Supabase session, converted to a real account at publish time",
|
|
103
|
+
// Desktop v1 (#2979) shipped flag-dark: the entry route, publish wall, and
|
|
104
|
+
// conversion modal all land behind this flag. Enabled at launch rollout -
|
|
105
|
+
// the prod Supabase Anonymous Sign-Ins toggle must stay on for /try guest
|
|
106
|
+
// sessions to mint (dev first, then prod after #3016).
|
|
107
|
+
enabled: true,
|
|
108
|
+
status: "beta",
|
|
109
|
+
category: "builder"
|
|
110
|
+
},
|
|
98
111
|
// -- Node types --
|
|
99
112
|
node_start: {
|
|
100
113
|
name: "Start node",
|
|
@@ -339,8 +352,30 @@ var FEATURES = {
|
|
|
339
352
|
dynamic_link: {
|
|
340
353
|
name: "Dynamic links",
|
|
341
354
|
description: "A named link that points at a form, so the target can be swapped from the dashboard without changing the embed code or printed link",
|
|
355
|
+
enabled: true,
|
|
356
|
+
status: "live",
|
|
357
|
+
category: "sharing",
|
|
358
|
+
wentLiveAt: "2026-08-27"
|
|
359
|
+
},
|
|
360
|
+
custom_domains: {
|
|
361
|
+
name: "Custom domains",
|
|
362
|
+
description: "Serve your forms on your own subdomain (forms.yourbrand.com) with vanity paths, instead of a clipform.io link",
|
|
342
363
|
enabled: false,
|
|
343
|
-
status: "
|
|
364
|
+
status: "planned",
|
|
365
|
+
category: "sharing"
|
|
366
|
+
},
|
|
367
|
+
branded_qr: {
|
|
368
|
+
name: "Branded QR codes",
|
|
369
|
+
description: "Render a form's share QR in its theme color with the logo centered, instead of plain black",
|
|
370
|
+
enabled: false,
|
|
371
|
+
status: "planned",
|
|
372
|
+
category: "sharing"
|
|
373
|
+
},
|
|
374
|
+
email_share: {
|
|
375
|
+
name: "Add to an email",
|
|
376
|
+
description: "Copy-paste image + link snippet for pasting a Clipform into an email campaign",
|
|
377
|
+
enabled: false,
|
|
378
|
+
status: "planned",
|
|
344
379
|
category: "sharing"
|
|
345
380
|
},
|
|
346
381
|
remove_branding: {
|
|
@@ -544,6 +579,9 @@ var DRAW_GAME_DEFAULT_TIERS = [
|
|
|
544
579
|
{ min_score: 75, label: "Great match" },
|
|
545
580
|
{ min_score: 92, label: "Perfect" }
|
|
546
581
|
];
|
|
582
|
+
var DEFAULT_MAX_RECORDING_SECONDS = 120;
|
|
583
|
+
var MAX_RECORDING_SECONDS_MIN = 10;
|
|
584
|
+
var MAX_RECORDING_SECONDS_MAX = 300;
|
|
547
585
|
var NODE_TYPES = {
|
|
548
586
|
start: {
|
|
549
587
|
label: "Start",
|
|
@@ -719,6 +757,14 @@ var NODE_TYPES = {
|
|
|
719
757
|
type: "string",
|
|
720
758
|
label: "Content media type",
|
|
721
759
|
description: "How the node media was provided"
|
|
760
|
+
},
|
|
761
|
+
max_recording_seconds: {
|
|
762
|
+
type: "number",
|
|
763
|
+
default: DEFAULT_MAX_RECORDING_SECONDS,
|
|
764
|
+
minimum: MAX_RECORDING_SECONDS_MIN,
|
|
765
|
+
maximum: MAX_RECORDING_SECONDS_MAX,
|
|
766
|
+
label: "Max recording length (seconds)",
|
|
767
|
+
description: "Cap on the audio/video recorder for this node, in seconds"
|
|
722
768
|
}
|
|
723
769
|
}
|
|
724
770
|
},
|
|
@@ -1029,6 +1075,22 @@ var NODE_TYPES = {
|
|
|
1029
1075
|
value: { type: "string" }
|
|
1030
1076
|
}
|
|
1031
1077
|
}
|
|
1078
|
+
},
|
|
1079
|
+
// Consent/opt-in agreements the respondent was shown. Present only when
|
|
1080
|
+
// the node has consent items. `accepted` is their choice; `label` is the
|
|
1081
|
+
// exact wording they agreed to, snapshotted per response (#2828).
|
|
1082
|
+
consent: {
|
|
1083
|
+
type: "array",
|
|
1084
|
+
items: {
|
|
1085
|
+
type: "object",
|
|
1086
|
+
required: ["name", "accepted", "type", "label"],
|
|
1087
|
+
properties: {
|
|
1088
|
+
name: { type: "string" },
|
|
1089
|
+
accepted: { type: "boolean" },
|
|
1090
|
+
type: { type: "string", enum: CONSENT_TYPES },
|
|
1091
|
+
label: { type: "string" }
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1032
1094
|
}
|
|
1033
1095
|
}
|
|
1034
1096
|
}
|
|
@@ -1810,7 +1872,10 @@ var NODE_TYPES = {
|
|
|
1810
1872
|
supports_media: false,
|
|
1811
1873
|
is_system: false,
|
|
1812
1874
|
show_in_results: false,
|
|
1813
|
-
default_config:
|
|
1875
|
+
default_config: {
|
|
1876
|
+
title: "Thank you!",
|
|
1877
|
+
message: "Your response has been submitted."
|
|
1878
|
+
},
|
|
1814
1879
|
config_schema: {
|
|
1815
1880
|
type: "object",
|
|
1816
1881
|
properties: {
|
|
@@ -2115,7 +2180,10 @@ var HELP_TOPICS = {
|
|
|
2115
2180
|
liveAndDraft: { path: "/help/managing-forms", anchor: "live-and-draft" },
|
|
2116
2181
|
publishingChanges: { path: "/help/managing-forms", anchor: "publishing-changes" },
|
|
2117
2182
|
embedding: { path: "/help/embed", anchor: null },
|
|
2118
|
-
|
|
2183
|
+
emailShare: { path: "/help/sharing", anchor: "share-by-email" },
|
|
2184
|
+
publicResults: { path: "/help/public-results", anchor: null },
|
|
2185
|
+
trash: { path: "/help/managing-forms", anchor: "trash" },
|
|
2186
|
+
agreementVersions: { path: "/help/responses", anchor: "agreement-versions" }
|
|
2119
2187
|
};
|
|
2120
2188
|
function buildHelpLinks(docsBaseUrl) {
|
|
2121
2189
|
const links = {};
|
|
@@ -2125,6 +2193,58 @@ function buildHelpLinks(docsBaseUrl) {
|
|
|
2125
2193
|
return links;
|
|
2126
2194
|
}
|
|
2127
2195
|
|
|
2196
|
+
// ../config/logic-types.js
|
|
2197
|
+
function isBranchingActive(node) {
|
|
2198
|
+
if (!node) return true;
|
|
2199
|
+
return node.type === "choice" || node.type === "binary" ? node.config?.choice?.enable_branching === true : true;
|
|
2200
|
+
}
|
|
2201
|
+
function isOptionEdge(action) {
|
|
2202
|
+
return !!action?.condition?.vars?.some((v) => v.type === "option");
|
|
2203
|
+
}
|
|
2204
|
+
function isInactiveOptionEdge(node, action) {
|
|
2205
|
+
return isOptionEdge(action) && !isBranchingActive(node);
|
|
2206
|
+
}
|
|
2207
|
+
|
|
2208
|
+
// ../config/logic-chain.js
|
|
2209
|
+
function outgoingTargets(actions, node) {
|
|
2210
|
+
const out = [];
|
|
2211
|
+
for (const a of actions ?? []) {
|
|
2212
|
+
if (node && isInactiveOptionEdge(node, a)) continue;
|
|
2213
|
+
const v = a?.details?.to?.value;
|
|
2214
|
+
if (v && !out.includes(v)) out.push(v);
|
|
2215
|
+
}
|
|
2216
|
+
return out;
|
|
2217
|
+
}
|
|
2218
|
+
function defaultTarget(actions) {
|
|
2219
|
+
if (!actions || actions.length === 0) return null;
|
|
2220
|
+
const nodeLevel = actions.find((a) => {
|
|
2221
|
+
const vars = a.condition?.vars;
|
|
2222
|
+
return !!vars && vars.length > 0 && vars.every((v) => v.type === "node");
|
|
2223
|
+
});
|
|
2224
|
+
return (nodeLevel ?? actions[0])?.details?.to ?? null;
|
|
2225
|
+
}
|
|
2226
|
+
function bfsOrder(nodes, logicByNode) {
|
|
2227
|
+
const byId = new Map(nodes.map((n) => [n.id, n]));
|
|
2228
|
+
const ordered = [];
|
|
2229
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2230
|
+
const start = nodes.find((n) => n.type === "start");
|
|
2231
|
+
if (start) {
|
|
2232
|
+
const queue = [start.id];
|
|
2233
|
+
while (queue.length) {
|
|
2234
|
+
const id = queue.shift();
|
|
2235
|
+
if (seen.has(id)) continue;
|
|
2236
|
+
seen.add(id);
|
|
2237
|
+
const node = byId.get(id);
|
|
2238
|
+
if (node) ordered.push(node);
|
|
2239
|
+
for (const target of outgoingTargets(logicByNode.get(id), node)) {
|
|
2240
|
+
if (!seen.has(target) && byId.has(target)) queue.push(target);
|
|
2241
|
+
}
|
|
2242
|
+
}
|
|
2243
|
+
}
|
|
2244
|
+
for (const node of nodes) if (!seen.has(node.id)) ordered.push(node);
|
|
2245
|
+
return ordered;
|
|
2246
|
+
}
|
|
2247
|
+
|
|
2128
2248
|
// ../config/index.js
|
|
2129
2249
|
var isServer = typeof window === "undefined";
|
|
2130
2250
|
var isBrowser = typeof window !== "undefined";
|
|
@@ -2206,6 +2326,168 @@ var MEDIA_DIRECT_MAX_BYTES = 20 * 1024 * 1024;
|
|
|
2206
2326
|
var SUPABASE_STORAGE_MAX_BYTES = 50 * 1024 * 1024;
|
|
2207
2327
|
var VIDEO_COMPRESS_FLOOR_BYTES = 1 * 1024 * 1024;
|
|
2208
2328
|
var HELP_LINKS = buildHelpLinks(BUSINESS.urls.docs);
|
|
2329
|
+
var PLAN_LIMITS = {
|
|
2330
|
+
free_v1: {
|
|
2331
|
+
tier: 0,
|
|
2332
|
+
name: "Free",
|
|
2333
|
+
price: "$0",
|
|
2334
|
+
period: "forever",
|
|
2335
|
+
price_cents: 0,
|
|
2336
|
+
stripe_price_id: { test: null, live: null },
|
|
2337
|
+
// Shopify App Pricing plan NAME (must match the Partner Dashboard plan
|
|
2338
|
+
// exactly - the app_subscriptions/update payload carries this name). Free
|
|
2339
|
+
// generates no subscription, so this is only used by the drift check.
|
|
2340
|
+
shopify_plan_handle: "Free",
|
|
2341
|
+
node_limit: null,
|
|
2342
|
+
form_limit: 5,
|
|
2343
|
+
workspace_limit: 1,
|
|
2344
|
+
show_branding: true,
|
|
2345
|
+
custom_theme: false,
|
|
2346
|
+
dynamic_links: false,
|
|
2347
|
+
custom_domain: false,
|
|
2348
|
+
response_limit: 100,
|
|
2349
|
+
features: [
|
|
2350
|
+
"Up to 5 forms",
|
|
2351
|
+
"Unlimited questions per form",
|
|
2352
|
+
// "completed" is not a tightening: response_limit has always been 100,
|
|
2353
|
+
// but the counter now excludes partials (#2618), so this wording is both
|
|
2354
|
+
// accurate and strictly more generous than what it replaced.
|
|
2355
|
+
"100 completed responses per month",
|
|
2356
|
+
"Full AI tooling (TTS, media, video)",
|
|
2357
|
+
"Clipform branding"
|
|
2358
|
+
]
|
|
2359
|
+
},
|
|
2360
|
+
pro_v1: {
|
|
2361
|
+
tier: 1,
|
|
2362
|
+
name: "Pro",
|
|
2363
|
+
price: "$25",
|
|
2364
|
+
period: "/month",
|
|
2365
|
+
price_cents: 2500,
|
|
2366
|
+
stripe_price_id: { test: "price_1TZnmhCWdEPD0KoNWWJTc3B6", live: "price_1TZnrZEJOD9ik3LhhFwGZ6ut" },
|
|
2367
|
+
// Must match the Partner Dashboard plan name exactly (drives webhook plan
|
|
2368
|
+
// mapping + the price drift check). Keep in step with price_cents above.
|
|
2369
|
+
shopify_plan_handle: "Pro",
|
|
2370
|
+
node_limit: null,
|
|
2371
|
+
form_limit: null,
|
|
2372
|
+
workspace_limit: null,
|
|
2373
|
+
show_branding: false,
|
|
2374
|
+
custom_theme: true,
|
|
2375
|
+
dynamic_links: true,
|
|
2376
|
+
custom_domain: true,
|
|
2377
|
+
response_limit: null,
|
|
2378
|
+
features: [
|
|
2379
|
+
"Unlimited forms",
|
|
2380
|
+
"Unlimited questions",
|
|
2381
|
+
"Unlimited responses",
|
|
2382
|
+
"Custom themes & colors",
|
|
2383
|
+
"Remove Clipform branding",
|
|
2384
|
+
"Dynamic links - repoint a printed URL to a new form"
|
|
2385
|
+
]
|
|
2386
|
+
},
|
|
2387
|
+
// Banded Pro (#1937). pro_v2_1k IS the current tier-1 version (#2671) - new
|
|
2388
|
+
// Pro signups land here; pro_v1 is retained only to grandfather the accounts
|
|
2389
|
+
// that predate the flip.
|
|
2390
|
+
//
|
|
2391
|
+
// Billing is one subscription with TWO Stripe items: this licensed base
|
|
2392
|
+
// billed in advance, plus a volume-tiered metered top-up (STRIPE_BAND_PRICE_ID
|
|
2393
|
+
// below) billed in arrears - so the band a workspace lands in is decided by
|
|
2394
|
+
// usage, never by swapping plan version. Completed responses report to the
|
|
2395
|
+
// Stripe usage meter (#2651, apps/api/src/lib/usage-metering.ts) via
|
|
2396
|
+
// planMetersUsage below, and checkout appends the metered item whenever a band
|
|
2397
|
+
// price is configured for the mode (#2652). The band price now exists in BOTH
|
|
2398
|
+
// test and live (STRIPE_BAND_PRICE_ID), so a new Pro checkout is two-item and
|
|
2399
|
+
// usage above the base band IS charged once this deploys - the HUMAN LEGAL
|
|
2400
|
+
// REVIEW on LEGAL.billing below must clear before that go-live.
|
|
2401
|
+
//
|
|
2402
|
+
// `response_limit` counts COMPLETED response sets only; partials never
|
|
2403
|
+
// consume allowance.
|
|
2404
|
+
//
|
|
2405
|
+
// shopify_plan_handle is null until the matching Partner Dashboard plans
|
|
2406
|
+
// exist - so planVersionForShopifyPlan still maps Shopify's "Pro" to pro_v1
|
|
2407
|
+
// ($25 unlimited) while web signups get this band. Creating those plans is
|
|
2408
|
+
// what closes that cross-channel gap.
|
|
2409
|
+
pro_v2_1k: {
|
|
2410
|
+
tier: 1,
|
|
2411
|
+
name: "Pro",
|
|
2412
|
+
price: "$24",
|
|
2413
|
+
period: "/month",
|
|
2414
|
+
price_cents: 2400,
|
|
2415
|
+
stripe_price_id: {
|
|
2416
|
+
test: "price_1U0lA6EJOD9ik3Lhube5eBcK",
|
|
2417
|
+
live: "price_1U115SEJOD9ik3LhOU9OkqJk"
|
|
2418
|
+
},
|
|
2419
|
+
shopify_plan_handle: null,
|
|
2420
|
+
node_limit: null,
|
|
2421
|
+
form_limit: null,
|
|
2422
|
+
workspace_limit: null,
|
|
2423
|
+
show_branding: false,
|
|
2424
|
+
custom_theme: true,
|
|
2425
|
+
dynamic_links: true,
|
|
2426
|
+
custom_domain: true,
|
|
2427
|
+
response_limit: 1e3,
|
|
2428
|
+
features: [
|
|
2429
|
+
"Unlimited forms",
|
|
2430
|
+
"Unlimited questions",
|
|
2431
|
+
"1,000 completed responses per month",
|
|
2432
|
+
"Custom themes & colors",
|
|
2433
|
+
"Remove Clipform branding",
|
|
2434
|
+
"Dynamic links - repoint a printed URL to a new form"
|
|
2435
|
+
]
|
|
2436
|
+
},
|
|
2437
|
+
pro_v2_5k: {
|
|
2438
|
+
tier: 1,
|
|
2439
|
+
name: "Pro",
|
|
2440
|
+
price: "$49",
|
|
2441
|
+
period: "/month",
|
|
2442
|
+
price_cents: 4900,
|
|
2443
|
+
stripe_price_id: { test: null, live: null },
|
|
2444
|
+
shopify_plan_handle: null,
|
|
2445
|
+
node_limit: null,
|
|
2446
|
+
form_limit: null,
|
|
2447
|
+
workspace_limit: null,
|
|
2448
|
+
show_branding: false,
|
|
2449
|
+
custom_theme: true,
|
|
2450
|
+
dynamic_links: true,
|
|
2451
|
+
custom_domain: true,
|
|
2452
|
+
response_limit: 5e3,
|
|
2453
|
+
features: [
|
|
2454
|
+
"Unlimited forms",
|
|
2455
|
+
"Unlimited questions",
|
|
2456
|
+
"5,000 completed responses per month",
|
|
2457
|
+
"Custom themes & colors",
|
|
2458
|
+
"Remove Clipform branding",
|
|
2459
|
+
"Dynamic links - repoint a printed URL to a new form"
|
|
2460
|
+
]
|
|
2461
|
+
},
|
|
2462
|
+
pro_v2_20k: {
|
|
2463
|
+
tier: 1,
|
|
2464
|
+
name: "Pro",
|
|
2465
|
+
price: "$99",
|
|
2466
|
+
period: "/month",
|
|
2467
|
+
price_cents: 9900,
|
|
2468
|
+
stripe_price_id: { test: null, live: null },
|
|
2469
|
+
shopify_plan_handle: null,
|
|
2470
|
+
node_limit: null,
|
|
2471
|
+
form_limit: null,
|
|
2472
|
+
workspace_limit: null,
|
|
2473
|
+
show_branding: false,
|
|
2474
|
+
custom_theme: true,
|
|
2475
|
+
dynamic_links: true,
|
|
2476
|
+
custom_domain: true,
|
|
2477
|
+
response_limit: 2e4,
|
|
2478
|
+
features: [
|
|
2479
|
+
"Unlimited forms",
|
|
2480
|
+
"Unlimited questions",
|
|
2481
|
+
"20,000 completed responses per month",
|
|
2482
|
+
"Custom themes & colors",
|
|
2483
|
+
"Remove Clipform branding",
|
|
2484
|
+
"Dynamic links - repoint a printed URL to a new form"
|
|
2485
|
+
]
|
|
2486
|
+
}
|
|
2487
|
+
};
|
|
2488
|
+
var PRO_BANDS = ["pro_v2_1k", "pro_v2_5k", "pro_v2_20k"].map(
|
|
2489
|
+
(version) => ({ version, ...PLAN_LIMITS[version] })
|
|
2490
|
+
);
|
|
2209
2491
|
var CONTACT_FIELDS = [
|
|
2210
2492
|
{ id: "first_name", label: "First Name", type: "text", placeholder: "Enter first name", order: 1 },
|
|
2211
2493
|
{ id: "last_name", label: "Last Name", type: "text", placeholder: "Enter last name", order: 2 },
|
|
@@ -2287,6 +2569,42 @@ function exposedCompositionIds(includeNonPublic) {
|
|
|
2287
2569
|
}
|
|
2288
2570
|
var SCENE_LAYER_COMPOSITION_IDS = COMPOSITION_REGISTRY.filter((c) => c.scene_layer).map((c) => c.id);
|
|
2289
2571
|
var MCP_TOOL_TIERS = {};
|
|
2572
|
+
var MCP_TOOL_TOOLSETS = {
|
|
2573
|
+
// account: workspace/account-scoped read + admin tools.
|
|
2574
|
+
clipform_list_forms: "account",
|
|
2575
|
+
clipform_get_form: "account",
|
|
2576
|
+
clipform_delete_form: "account",
|
|
2577
|
+
clipform_whoami: "account",
|
|
2578
|
+
clipform_get_results: "account",
|
|
2579
|
+
// forms: form/node structure + research tools used while building.
|
|
2580
|
+
clipform_create_form: "forms",
|
|
2581
|
+
clipform_add_node: "forms",
|
|
2582
|
+
clipform_update_node: "forms",
|
|
2583
|
+
clipform_delete_node: "forms",
|
|
2584
|
+
clipform_update_form: "forms",
|
|
2585
|
+
clipform_set_logic: "forms",
|
|
2586
|
+
clipform_get_guide: "forms",
|
|
2587
|
+
clipform_get_workflow: "forms",
|
|
2588
|
+
clipform_search_news: "forms",
|
|
2589
|
+
clipform_fetch_boundary: "forms",
|
|
2590
|
+
clipform_log_generation: "forms",
|
|
2591
|
+
// media: creative/render/asset tools.
|
|
2592
|
+
clipform_generate_tts: "media",
|
|
2593
|
+
clipform_generate_video: "media",
|
|
2594
|
+
clipform_render_composition: "media",
|
|
2595
|
+
clipform_render_video_template: "media",
|
|
2596
|
+
clipform_check_render: "media",
|
|
2597
|
+
clipform_upload_media_asset: "media",
|
|
2598
|
+
clipform_complete_media_upload: "media",
|
|
2599
|
+
clipform_attach_node_media: "media",
|
|
2600
|
+
clipform_get_node_media: "media",
|
|
2601
|
+
clipform_delete_node_media: "media",
|
|
2602
|
+
clipform_search_media: "media",
|
|
2603
|
+
clipform_search_music: "media",
|
|
2604
|
+
clipform_list_compositions: "media",
|
|
2605
|
+
clipform_list_assets: "media",
|
|
2606
|
+
clipform_list_video_templates: "media"
|
|
2607
|
+
};
|
|
2290
2608
|
|
|
2291
2609
|
// src/lib/api-client.ts
|
|
2292
2610
|
function getApiBaseUrl() {
|
|
@@ -2314,7 +2632,14 @@ function getAuthHeaders() {
|
|
|
2314
2632
|
});
|
|
2315
2633
|
throw new Error(message);
|
|
2316
2634
|
}
|
|
2317
|
-
|
|
2635
|
+
const headers = { "Authorization": `Bearer ${apiKey}` };
|
|
2636
|
+
if (authCtx?.is_anonymous) {
|
|
2637
|
+
headers[MCP_ANONYMOUS_HEADER] = "1";
|
|
2638
|
+
}
|
|
2639
|
+
if (authCtx?.mcp_mint_proof) {
|
|
2640
|
+
headers[MCP_MINT_PROOF_HEADER] = authCtx.mcp_mint_proof;
|
|
2641
|
+
}
|
|
2642
|
+
return headers;
|
|
2318
2643
|
}
|
|
2319
2644
|
async function callApi(path, options = {}) {
|
|
2320
2645
|
const { body, params, timeoutMs = 3e4 } = options;
|
|
@@ -2352,9 +2677,7 @@ async function callApi(path, options = {}) {
|
|
|
2352
2677
|
return {
|
|
2353
2678
|
ok: false,
|
|
2354
2679
|
status: 0,
|
|
2355
|
-
error:
|
|
2356
|
-
|
|
2357
|
-
Error: ${message}`
|
|
2680
|
+
error: "Unable to reach the Clipform API right now. Please try again in a moment."
|
|
2358
2681
|
};
|
|
2359
2682
|
}
|
|
2360
2683
|
if (response.status === 204) {
|
|
@@ -2434,13 +2757,11 @@ async function getSessionContextWithAuth() {
|
|
|
2434
2757
|
lines.push(
|
|
2435
2758
|
apiAuthMode === "api_key" ? "Auth: API key (workspace-scoped)" : "Auth: signed in (connected to a Clipform account)"
|
|
2436
2759
|
);
|
|
2437
|
-
lines.push(`Workspace: ${me.workspace?.name ?? "Unknown"}
|
|
2438
|
-
if (me.user_id) lines.push(`User: ${me.user_id}`);
|
|
2439
|
-
if (me.company_id) lines.push(`Company: ${me.company_id}`);
|
|
2760
|
+
lines.push(`Workspace: ${me.workspace?.name ?? "Unknown"}`);
|
|
2440
2761
|
} else {
|
|
2441
2762
|
lines.push("Auth: anonymous (not connected to a Clipform account)");
|
|
2442
2763
|
if (me.workspace) {
|
|
2443
|
-
lines.push(`Workspace: ${me.workspace.name}
|
|
2764
|
+
lines.push(`Workspace: ${me.workspace.name}`);
|
|
2444
2765
|
}
|
|
2445
2766
|
}
|
|
2446
2767
|
lines.push(`Plan: ${plan.name} (tier ${plan.tier})`);
|
|
@@ -2459,7 +2780,7 @@ async function getSessionContextWithAuth() {
|
|
|
2459
2780
|
}
|
|
2460
2781
|
if (authMode === "anonymous") {
|
|
2461
2782
|
lines.push(`
|
|
2462
|
-
|
|
2783
|
+
Anonymous session: forms are not tied to a Clipform account until you sign in.`);
|
|
2463
2784
|
}
|
|
2464
2785
|
return { text: lines.join("\n"), authMode };
|
|
2465
2786
|
}
|
|
@@ -2479,7 +2800,8 @@ export {
|
|
|
2479
2800
|
ALL_VARIANTS,
|
|
2480
2801
|
resolveFormType,
|
|
2481
2802
|
getDiscoveryParams,
|
|
2482
|
-
|
|
2803
|
+
defaultTarget,
|
|
2804
|
+
bfsOrder,
|
|
2483
2805
|
CONTACT_FIELDS,
|
|
2484
2806
|
KEN_BURNS_EFFECTS,
|
|
2485
2807
|
KEN_BURNS_PRESETS,
|
|
@@ -2487,6 +2809,7 @@ export {
|
|
|
2487
2809
|
SLIDESHOW_TRANSITIONS,
|
|
2488
2810
|
exposedCompositionIds,
|
|
2489
2811
|
MCP_TOOL_TIERS,
|
|
2812
|
+
MCP_TOOL_TOOLSETS,
|
|
2490
2813
|
callApi,
|
|
2491
2814
|
errorResult,
|
|
2492
2815
|
textResult,
|
|
@@ -2494,4 +2817,4 @@ export {
|
|
|
2494
2817
|
getSessionContextWithAuth,
|
|
2495
2818
|
getSessionContext
|
|
2496
2819
|
};
|
|
2497
|
-
//# sourceMappingURL=chunk-
|
|
2820
|
+
//# sourceMappingURL=chunk-3BYQLPTT.js.map
|