@clipform/mcp-server 1.8.0 → 1.9.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 +3 -2
- package/dist/auth-context.js +9 -0
- package/dist/auth-context.js.map +1 -0
- package/dist/chunk-BWCZX7XY.js +3824 -0
- package/dist/chunk-BWCZX7XY.js.map +1 -0
- package/dist/chunk-MYWOSQ66.js +15 -0
- package/dist/chunk-MYWOSQ66.js.map +1 -0
- package/dist/index.js +15 -10
- package/dist/index.js.map +1 -1
- package/dist/server.js +7 -72
- package/dist/server.js.map +1 -1
- package/package.json +5 -4
- package/dist/__tests__/api-parity.test.d.ts +0 -1
- package/dist/__tests__/api-parity.test.js +0 -157
- package/dist/__tests__/api-parity.test.js.map +0 -1
- package/dist/__tests__/config-sync.test.d.ts +0 -1
- package/dist/__tests__/config-sync.test.js +0 -16
- package/dist/__tests__/config-sync.test.js.map +0 -1
- package/dist/index.d.ts +0 -2
- package/dist/lib/api-client.d.ts +0 -36
- package/dist/lib/api-client.js +0 -129
- package/dist/lib/api-client.js.map +0 -1
- package/dist/lib/auth-context.d.ts +0 -17
- package/dist/lib/auth-context.js +0 -9
- package/dist/lib/auth-context.js.map +0 -1
- package/dist/lib/config.d.ts +0 -23
- package/dist/lib/config.js +0 -6
- package/dist/lib/config.js.map +0 -1
- package/dist/lib/format-form.d.ts +0 -2
- package/dist/lib/format-form.js +0 -32
- package/dist/lib/format-form.js.map +0 -1
- package/dist/lib/render-jobs.d.ts +0 -13
- package/dist/lib/render-jobs.js +0 -38
- package/dist/lib/render-jobs.js.map +0 -1
- package/dist/lib/schemas.d.ts +0 -64
- package/dist/lib/schemas.js +0 -140
- package/dist/lib/schemas.js.map +0 -1
- package/dist/lib/session-context.d.ts +0 -1
- package/dist/lib/session-context.js +0 -38
- package/dist/lib/session-context.js.map +0 -1
- package/dist/prompts.d.ts +0 -2
- package/dist/prompts.js +0 -272
- package/dist/prompts.js.map +0 -1
- package/dist/resources.d.ts +0 -2
- package/dist/resources.js +0 -336
- package/dist/resources.js.map +0 -1
- package/dist/server.d.ts +0 -2
- package/dist/tools/add-node.d.ts +0 -2
- package/dist/tools/add-node.js +0 -50
- package/dist/tools/add-node.js.map +0 -1
- package/dist/tools/attach-node-audio.d.ts +0 -2
- package/dist/tools/attach-node-audio.js +0 -37
- package/dist/tools/attach-node-audio.js.map +0 -1
- package/dist/tools/check-render.d.ts +0 -2
- package/dist/tools/check-render.js +0 -47
- package/dist/tools/check-render.js.map +0 -1
- package/dist/tools/create-form.d.ts +0 -2
- package/dist/tools/create-form.js +0 -217
- package/dist/tools/create-form.js.map +0 -1
- package/dist/tools/delete-form.d.ts +0 -2
- package/dist/tools/delete-form.js +0 -28
- package/dist/tools/delete-form.js.map +0 -1
- package/dist/tools/delete-node-media.d.ts +0 -2
- package/dist/tools/delete-node-media.js +0 -29
- package/dist/tools/delete-node-media.js.map +0 -1
- package/dist/tools/delete-node.d.ts +0 -2
- package/dist/tools/delete-node.js +0 -32
- package/dist/tools/delete-node.js.map +0 -1
- package/dist/tools/generate-slideshow.d.ts +0 -2
- package/dist/tools/generate-slideshow.js +0 -155
- package/dist/tools/generate-slideshow.js.map +0 -1
- package/dist/tools/generate-tts.d.ts +0 -2
- package/dist/tools/generate-tts.js +0 -73
- package/dist/tools/generate-tts.js.map +0 -1
- package/dist/tools/generate-video.d.ts +0 -2
- package/dist/tools/generate-video.js +0 -119
- package/dist/tools/generate-video.js.map +0 -1
- package/dist/tools/get-form.d.ts +0 -2
- package/dist/tools/get-form.js +0 -31
- package/dist/tools/get-form.js.map +0 -1
- package/dist/tools/get-node-media.d.ts +0 -2
- package/dist/tools/get-node-media.js +0 -39
- package/dist/tools/get-node-media.js.map +0 -1
- package/dist/tools/list-assets.d.ts +0 -2
- package/dist/tools/list-assets.js +0 -45
- package/dist/tools/list-assets.js.map +0 -1
- package/dist/tools/list-compositions.d.ts +0 -2
- package/dist/tools/list-compositions.js +0 -34
- package/dist/tools/list-compositions.js.map +0 -1
- package/dist/tools/log-generation.d.ts +0 -2
- package/dist/tools/log-generation.js +0 -34
- package/dist/tools/log-generation.js.map +0 -1
- package/dist/tools/render-composition.d.ts +0 -2
- package/dist/tools/render-composition.js +0 -50
- package/dist/tools/render-composition.js.map +0 -1
- package/dist/tools/search-media.d.ts +0 -2
- package/dist/tools/search-media.js +0 -40
- package/dist/tools/search-media.js.map +0 -1
- package/dist/tools/search-music.d.ts +0 -2
- package/dist/tools/search-music.js +0 -40
- package/dist/tools/search-music.js.map +0 -1
- package/dist/tools/search-news.d.ts +0 -2
- package/dist/tools/search-news.js +0 -47
- package/dist/tools/search-news.js.map +0 -1
- package/dist/tools/set-node-logic.d.ts +0 -2
- package/dist/tools/set-node-logic.js +0 -56
- package/dist/tools/set-node-logic.js.map +0 -1
- package/dist/tools/update-form.d.ts +0 -2
- package/dist/tools/update-form.js +0 -140
- package/dist/tools/update-form.js.map +0 -1
- package/dist/tools/update-node.d.ts +0 -2
- package/dist/tools/update-node.js +0 -71
- package/dist/tools/update-node.js.map +0 -1
- package/dist/tools/upload-node-media.d.ts +0 -2
- package/dist/tools/upload-node-media.js +0 -109
- package/dist/tools/upload-node-media.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/server.ts","../src/tools/create-form.ts","../../config/node-types.js","../../config/integration-catalog.js","../../config/index.js","../src/lib/schemas.ts","../src/lib/api-client.ts","../src/tools/list-forms.ts","../src/tools/get-form.ts","../src/lib/format-form.ts","../src/tools/update-form.ts","../src/tools/delete-form.ts","../src/tools/add-node.ts","../src/tools/update-node.ts","../src/tools/delete-node.ts","../src/tools/upload-node-media.ts","../src/tools/get-node-media.ts","../src/tools/delete-node-media.ts","../src/tools/set-node-logic.ts","../src/tools/attach-node-audio.ts","../src/tools/log-generation.ts","../src/tools/search-news.ts","../src/tools/generate-tts.ts","../src/tools/generate-slideshow.ts","../../../node_modules/uuid/dist/esm/stringify.js","../../../node_modules/uuid/dist/esm/rng.js","../../../node_modules/uuid/dist/esm/native.js","../../../node_modules/uuid/dist/esm/v4.js","../src/lib/render-jobs.ts","../src/tools/search-media.ts","../src/tools/render-composition.ts","../src/tools/search-music.ts","../src/tools/list-compositions.ts","../src/tools/list-assets.ts","../src/tools/generate-video.ts","../src/tools/check-render.ts","../src/lib/session-context.ts","../src/prompts.ts","../src/resources.ts"],"sourcesContent":["import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { readFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst pkg = JSON.parse(readFileSync(join(__dirname, \"..\", \"package.json\"), \"utf-8\"));\nconst MCP_VERSION: string = pkg.version;\n\n// Form CRUD tools\nimport { registerCreateFormTool } from \"./tools/create-form.js\";\nimport { registerListFormsTool } from \"./tools/list-forms.js\";\nimport { registerGetFormTool } from \"./tools/get-form.js\";\nimport { registerUpdateFormTool } from \"./tools/update-form.js\";\nimport { registerDeleteFormTool } from \"./tools/delete-form.js\";\n\n// Node CRUD tools\nimport { registerAddNodeTool } from \"./tools/add-node.js\";\nimport { registerUpdateNodeTool } from \"./tools/update-node.js\";\nimport { registerDeleteNodeTool } from \"./tools/delete-node.js\";\n\n// Node media & logic tools\nimport { registerUploadNodeMediaTool } from \"./tools/upload-node-media.js\";\nimport { registerGetNodeMediaTool } from \"./tools/get-node-media.js\";\nimport { registerDeleteNodeMediaTool } from \"./tools/delete-node-media.js\";\nimport { registerSetNodeLogicTool } from \"./tools/set-node-logic.js\";\nimport { registerAttachNodeAudioTool } from \"./tools/attach-node-audio.js\";\n\n// Audit logging\nimport { registerLogGenerationTool } from \"./tools/log-generation.js\";\n\n// Content research tools\nimport { registerSearchNewsTool } from \"./tools/search-news.js\";\n\n// Creative tools\nimport { registerGenerateTtsTool } from \"./tools/generate-tts.js\";\nimport { registerGenerateSlideshowTool } from \"./tools/generate-slideshow.js\";\nimport { registerSearchMediaTool } from \"./tools/search-media.js\";\nimport { registerRenderCompositionTool } from \"./tools/render-composition.js\";\nimport { registerSearchMusicTool } from \"./tools/search-music.js\";\nimport { registerListCompositionsTool } from \"./tools/list-compositions.js\";\nimport { registerListAssetsTool } from \"./tools/list-assets.js\";\nimport { registerGenerateVideoTool } from \"./tools/generate-video.js\";\nimport { registerCheckRenderTool } from \"./tools/check-render.js\";\n\n// Prompts & Resources\nimport { registerPrompts } from \"./prompts.js\";\nimport { registerResources } from \"./resources.js\";\n\nexport function createServer(): McpServer {\n const server = new McpServer({\n name: \"clipform-mcp-server\",\n version: MCP_VERSION,\n });\n\n // Form CRUD\n registerCreateFormTool(server);\n registerListFormsTool(server);\n registerGetFormTool(server);\n registerUpdateFormTool(server);\n registerDeleteFormTool(server);\n\n // Node CRUD\n registerAddNodeTool(server);\n registerUpdateNodeTool(server);\n registerDeleteNodeTool(server);\n\n // Node media & logic\n registerUploadNodeMediaTool(server);\n registerGetNodeMediaTool(server);\n registerDeleteNodeMediaTool(server);\n registerSetNodeLogicTool(server);\n registerAttachNodeAudioTool(server);\n\n // Audit logging\n registerLogGenerationTool(server);\n\n // Content research\n registerSearchNewsTool(server);\n\n // Creative tools\n registerGenerateTtsTool(server);\n registerGenerateSlideshowTool(server);\n registerGenerateVideoTool(server);\n registerSearchMediaTool(server);\n registerRenderCompositionTool(server);\n registerSearchMusicTool(server);\n registerListCompositionsTool(server);\n registerListAssetsTool(server);\n registerCheckRenderTool(server);\n\n // Prompts & Resources\n registerPrompts(server);\n registerResources(server);\n\n return server;\n}\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\nimport { BUSINESS } from \"@vid-master/config\";\nimport {\n NodeSchema,\n NODE_TYPES_DESCRIPTION,\n} from \"../lib/schemas.js\";\nimport { callApi, errorResult, textResult } from \"../lib/api-client.js\";\n\nexport function registerCreateFormTool(server: McpServer) {\n server.registerTool(\n \"clipform_create_form\",\n {\n title: \"Create Clipform\",\n 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.\n\n${NODE_TYPES_DESCRIPTION}\n\nAll type definitions and config schemas are derived from @vid-master/config (answer-types). Refer to the config descriptions above for the correct keys and shapes.\n\nExample: A form that asks a question, collects contact info, then finishes:\n{\n title: \"Quick Survey\",\n questions: [\n { type: \"open\", prompt: \"What's your biggest challenge?\" },\n { type: \"contact\", prompt: \"Leave your details\", config: { fields: [{ id: \"first_name\", required: true }, { id: \"email\", required: true }] } },\n { type: \"end_screen\", prompt: \"Thanks for your response!\" }\n ]\n}`,\n inputSchema: {\n title: z.string().describe(\"Form title\"),\n questions: z\n .array(NodeSchema)\n .min(1)\n .describe(\"Ordered list of questions/steps\"),\n show_step_counter: z\n .boolean()\n .optional()\n .describe(\"Show step counter (e.g. '1/5'). Set true for quizzes.\"),\n disable_back_navigation: z\n .boolean()\n .optional()\n .describe(\"Prevent going back. Set true for quizzes.\"),\n primary_color: z\n .string()\n .optional()\n .describe(\"Primary/brand color (hex or CSS color). Used for buttons and accents.\"),\n background_color: z\n .string()\n .optional()\n .describe(\"Background color (hex, rgba, or CSS color).\"),\n font_family: z\n .string()\n .optional()\n .describe(\"Font family name (e.g. 'Inter', 'Roboto', 'Playfair Display').\"),\n embed_autoplay: z\n .boolean()\n .optional()\n .describe(\"Auto-play video when embedded (default: false). When off, embeds show a thumbnail + play button.\"),\n tags: z\n .array(z.string())\n .optional()\n .describe(\"Tags for indexing (e.g. ['quiz', 'trivia', 'arsenal']). Include format, genre, and topics.\"),\n },\n annotations: {\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: true,\n },\n },\n async ({ title, questions, show_step_counter, disable_back_navigation, primary_color, background_color, font_family, embed_autoplay, tags }) => {\n // 0. Pre-flight: resolve the caller's plan and reject up-front if the\n // requested question count exceeds it. Without this we'd build a\n // scaffold + N-1 questions, then 403 on the Nth, leaving an orphan.\n // /v1/me is the single source for plan info; PLAN_LIMITS lives in\n // @vid-master/config and is read there. The MCP tool is intentionally\n // thin and never duplicates limit numbers.\n let planContext: {\n auth_mode: \"oauth\" | \"anonymous\";\n workspace_id: string;\n workspace_name: string | null;\n plan_name: string;\n node_limit: number | null;\n } | null = null;\n const meResult = await callApi(\"/me\", { method: \"GET\" });\n\n if (!meResult.ok) {\n return errorResult(`Unable to determine workspace: ${meResult.error}`);\n }\n\n const me = meResult.data as any;\n const workspaceId: string | null = me.workspace?.id ?? null;\n\n if (!workspaceId) {\n return errorResult(\n \"No workspace available. Connect your Clipform account in claude.ai → Settings → Connectors, or ensure MCP_WORKSPACE_ID is configured for anonymous mode.\"\n );\n }\n\n planContext = {\n auth_mode: me.auth_mode,\n workspace_id: workspaceId,\n workspace_name: me.workspace?.name ?? null,\n plan_name: me.plan?.name ?? \"Free\",\n node_limit: me.plan?.node_limit ?? null,\n };\n\n // questions includes any end_screen the user supplied; the scaffold\n // already has one so we count \"real\" content nodes only.\n const contentCount = questions.filter((q) => q.type !== \"end_screen\").length;\n\n if (planContext.node_limit !== null && contentCount > planContext.node_limit) {\n const upgradeUrl = `${BUSINESS.urls.dashboard}/billing`;\n const message =\n planContext.auth_mode === \"oauth\"\n ? `Your '${planContext.workspace_name}' workspace is on the ${planContext.plan_name} plan, capped at ${planContext.node_limit} questions per form. You asked for ${contentCount}. Either rerun with ${planContext.node_limit} questions or upgrade at ${upgradeUrl}.`\n : `Anonymous sessions are capped at ${planContext.node_limit} questions per form (${planContext.plan_name} plan). You asked for ${contentCount}. Either rerun with ${planContext.node_limit} questions, or connect your Clipform account in claude.ai → Settings → Connectors so forms land in your workspace with your real plan limits.`;\n return errorResult(message);\n }\n\n // 1. Create bare scaffold\n const createResult = await callApi(\"/forms\", {\n method: \"POST\",\n body: { title, workspace_id: workspaceId },\n });\n\n if (!createResult.ok) {\n return errorResult(createResult.error);\n }\n\n const { data } = createResult;\n const formId = data.form_id as string;\n const claimUrl = (data.claim_url as string | null) ?? undefined;\n\n // 2. Apply form settings and theme if provided\n const settingsBody: Record<string, unknown> = {};\n if (show_step_counter !== undefined) settingsBody.show_step_counter = show_step_counter;\n if (disable_back_navigation !== undefined) settingsBody.disable_back_navigation = disable_back_navigation;\n if (primary_color !== undefined) settingsBody.primary_color = primary_color;\n if (background_color !== undefined) settingsBody.background_color = background_color;\n if (font_family !== undefined) settingsBody.font_family = font_family;\n if (embed_autoplay !== undefined) settingsBody.embed_autoplay = embed_autoplay;\n\n if (Object.keys(settingsBody).length > 0) {\n await callApi(`/forms/${formId}`, {\n method: \"PATCH\",\n body: settingsBody,\n });\n }\n\n // 3. Add each question via the add-question endpoint\n for (const q of questions) {\n // If it's an end_screen, update the default one instead of adding another\n if (q.type === \"end_screen\") {\n // The scaffold already has an end_screen — find it and update its prompt\n const getResult = await callApi(`/forms/${formId}`, {\n method: \"GET\",\n });\n if (getResult.ok) {\n const questions_list = (getResult.data as any).questions as any[] | undefined;\n const endScreen = questions_list?.find((qq: any) => qq.type === \"end_screen\");\n if (endScreen) {\n await callApi(`/forms/${formId}/nodes/${endScreen.id}`, {\n method: \"PATCH\",\n body: { prompt: q.prompt, ...(q.config ? { config: q.config } : {}) },\n });\n continue;\n }\n }\n // Fallback: add it normally if we couldn't find the default\n }\n\n const addResult = await callApi(`/forms/${formId}/nodes`, {\n method: \"POST\",\n body: { question: q },\n });\n\n if (!addResult.ok) {\n return errorResult(`Failed to add question \"${q.prompt}\": ${addResult.error}`);\n }\n }\n\n // 4. Publish the form\n await callApi(`/forms/${formId}`, {\n method: \"PATCH\",\n body: { is_published: true },\n });\n\n // 5. Tag the form (best-effort)\n if (tags && tags.length > 0) {\n await callApi(`/forms/${formId}/tags`, {\n method: \"PUT\",\n body: { tags },\n });\n }\n\n const lines = [\n `Form created successfully!`,\n ``,\n `Title: ${title}`,\n `Questions: ${questions.length}`,\n `Form ID: ${formId}`,\n ``,\n `FORM URL (share this with respondents): ${data.viewer_url}`,\n ];\n\n if (claimUrl) {\n lines.push(`CLAIM URL (transfer ownership to your account): ${claimUrl}`);\n }\n\n lines.push(\n ``,\n `IMPORTANT: Always show the user the exact URLs above — do not rewrite or modify them.`,\n `Pass form_id on follow-up tools (get_form, add_node, upload_node_media, etc.).`\n );\n\n // One-line plan/auth summary so the model can mention it ONCE and not\n // re-prompt on every follow-up call.\n if (planContext) {\n const limitNote =\n planContext.node_limit === null\n ? \"unlimited questions\"\n : `up to ${planContext.node_limit} questions per form`;\n if (planContext.auth_mode === \"oauth\") {\n lines.push(\n ``,\n `Plan: ${planContext.plan_name} (${limitNote}) in workspace '${planContext.workspace_name}'.`\n );\n } else {\n lines.push(\n ``,\n `Plan: anonymous ${planContext.plan_name} (${limitNote}). Mention this once: the user can connect their Clipform account in claude.ai → Settings → Connectors → ${BUSINESS.urls.mcp} so future forms land directly in their workspace - do not repeat on follow-up calls.`\n );\n }\n }\n\n return textResult(lines.join(\"\\n\"));\n }\n );\n}\n","// @vid-master/config/node-types\n// Static node type definitions — single source of truth for all apps.\n// New node types require code changes (new component, renderer, etc.),\n// so this data is version-controlled rather than stored in the database.\n\nexport const NODE_TYPES = {\n start: {\n label: 'Start',\n shorthand: 'Start',\n icon: 'ArrowRight',\n color: '#D1FAE5',\n description: 'Entry point for the form - connects to the first question',\n category: 'start',\n sort_order: 0,\n has_options: false,\n is_terminal: false,\n show_nav_bar: false,\n loading: 'eager',\n supports_prompt: false,\n supports_media: false,\n is_system: true,\n is_active: true,\n default_config: null,\n config_schema: null,\n response_schema: null,\n output_schema: null,\n },\n choice: {\n label: 'Multiple Choice',\n shorthand: 'Multi',\n icon: 'CheckSquare',\n color: '#DBEAFE',\n description: 'Single or multiple choice questions with predefined options',\n category: 'question',\n sort_order: 1,\n has_options: true,\n min_options: 1,\n max_option_length: 36,\n is_terminal: false,\n show_nav_bar: true,\n loading: 'eager',\n supports_prompt: true,\n supports_media: true,\n is_system: false,\n is_active: true,\n default_config: {\n selection_mode: 'single',\n choice: { enable_branching: true, record_scores: false },\n randomise_options: false,\n show_option_count: false,\n options: [\n { content: 'Option 1' },\n { content: 'Option 2' },\n ],\n },\n config_schema: {\n type: 'object',\n properties: {\n choice: {\n type: 'object',\n properties: {\n enable_branching: {\n type: 'boolean',\n label: 'Enable branching logic',\n default: true,\n description: 'Allow each option to have its own logic path. When disabled, all options share a single jump action.',\n },\n show_answer_feedback: {\n type: 'boolean',\n label: 'Show answer feedback',\n default: false,\n description: 'Show correct/incorrect feedback after selection (requires scored options).',\n },\n record_scores: {\n type: 'boolean',\n label: 'Mark correct answer',\n default: false,\n description: 'Select which option is the correct answer.',\n },\n },\n },\n selection_mode: {\n enum: ['single', 'multiple'],\n type: 'string',\n label: 'Selection mode',\n default: 'single',\n description: 'Allow single or multiple selections',\n },\n allow_text_response: {\n type: 'boolean',\n label: 'Allow text response',\n default: false,\n description: 'Allow free-text response in addition to options (single choice only)',\n },\n randomise_options: {\n type: 'boolean',\n label: 'Randomise options',\n default: false,\n description: 'Show options in random order',\n },\n show_option_count: {\n type: 'boolean',\n label: 'Show option count',\n default: false,\n description: 'Display number of options',\n },\n content_media_type: {\n enum: ['upload', 'recorded'],\n type: 'string',\n label: 'Content media type',\n description: 'How the question media was provided',\n },\n },\n },\n response_schema: {\n type: 'string',\n description: 'Selected option ID',\n },\n output_schema: {\n type: 'object',\n required: ['type', 'label', 'option_id'],\n properties: {\n type: { type: 'string', const: 'choice' },\n label: { type: 'string', description: 'Human-readable option label' },\n option_id: { type: 'string', format: 'uuid', description: 'Selected option UUID' },\n },\n },\n },\n open: {\n label: 'Open Ended',\n shorthand: 'Open',\n icon: 'Type',\n color: '#DBEAFE',\n description: 'Free-form text responses from users',\n category: 'question',\n sort_order: 2,\n has_options: false,\n is_terminal: false,\n show_nav_bar: true,\n loading: 'eager',\n supports_prompt: true,\n supports_media: true,\n is_system: false,\n is_active: true,\n default_config: {\n formats: [\n { order: 0, format: 'text' },\n { order: 1, format: 'audio' },\n { order: 2, format: 'video' },\n ],\n },\n config_schema: {\n type: 'object',\n properties: {\n formats: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n format: { enum: ['text', 'audio', 'video'], type: 'string' },\n order: { type: 'number' },\n },\n },\n label: 'Allowed response formats',\n description: 'Which formats the user can respond with, in display order',\n },\n content_media_type: {\n enum: ['upload', 'recorded'],\n type: 'string',\n label: 'Content media type',\n description: 'How the question media was provided',\n },\n },\n },\n response_schema: {\n type: 'object',\n required: ['response_type'],\n properties: {\n text: {\n type: 'string',\n description: 'Text response (when response_type is text) or transcribed text from audio/video',\n },\n media: {\n type: 'object',\n properties: {\n type: { enum: ['audio', 'video'], type: 'string' },\n storage_path: { type: 'string' },\n },\n description: 'Media response (when response_type is audio or video)',\n },\n response_type: {\n enum: ['text', 'audio', 'video'],\n type: 'string',\n },\n transcription: {\n type: 'object',\n properties: {\n text: { type: 'string' },\n language: { type: 'string' },\n duration: { type: 'number' },\n words: { type: 'array' },\n },\n description: 'Whisper transcription data for audio/video responses',\n },\n },\n },\n output_schema: {\n type: 'object',\n required: ['type'],\n properties: {\n type: { type: 'string', const: 'text' },\n text: { type: 'string', description: 'Text response or transcription' },\n media: {\n type: 'object',\n properties: {\n type: { enum: ['audio', 'video'], type: 'string' },\n storage_path: { type: 'string' },\n },\n },\n transcription: {\n type: 'object',\n properties: {\n text: { type: 'string' },\n language: { type: 'string' },\n },\n },\n },\n },\n },\n scale: {\n label: 'Scale',\n shorthand: 'Scale',\n icon: 'BarChart3',\n color: '#DBEAFE',\n description: 'Numerical rating or scale questions (1-10, etc.)',\n category: 'question',\n sort_order: 3,\n has_options: false,\n is_terminal: false,\n show_nav_bar: true,\n loading: 'eager',\n supports_prompt: true,\n supports_media: true,\n is_system: false,\n is_active: false,\n default_config: null,\n config_schema: {\n type: 'object',\n properties: {\n max: { type: 'number', label: 'Maximum value', default: 10, required: true },\n min: { type: 'number', label: 'Minimum value', default: 1, required: true },\n step: { min: 0.1, type: 'number', label: 'Step increment', default: 1 },\n left_label: { type: 'string', label: 'Left label', placeholder: 'Not likely' },\n right_label: { type: 'string', label: 'Right label', placeholder: 'Very likely' },\n show_numbers: { type: 'boolean', label: 'Show numbers', default: true },\n },\n },\n response_schema: {\n type: 'number',\n description: 'Selected scale value',\n },\n output_schema: null,\n },\n booking: {\n label: 'Booking',\n shorthand: 'Booking',\n icon: 'Calendar',\n color: '#E9D5FF',\n description: null,\n category: 'action',\n sort_order: 4,\n has_options: false,\n is_terminal: false,\n show_nav_bar: true,\n loading: 'lazy',\n supports_prompt: false,\n supports_media: false,\n is_system: false,\n is_active: false,\n default_config: null,\n config_schema: {\n type: 'object',\n oneOf: [\n {\n required: ['calendly'],\n properties: {\n calendly: {\n type: 'object',\n properties: {\n event_name: { type: 'string', label: 'Event name', description: 'Display name for the event' },\n event_type_uri: { type: 'string', label: 'Event type URI', format: 'uri', description: 'Your Calendly event type URI', placeholder: 'https://calendly.com/your-link' },\n },\n },\n },\n },\n {\n required: ['google_meet'],\n properties: {\n google_meet: {\n type: 'object',\n properties: {\n duration: { type: 'number', label: 'Duration (minutes)', default: 30, description: 'Meeting duration in minutes' },\n calendar_id: { type: 'string', label: 'Calendar', description: 'Google Calendar to use for bookings' },\n event_title: { type: 'string', label: 'Event title', default: 'Meeting', description: 'Default title for scheduled meetings' },\n calendar_name: { type: 'string', label: 'Calendar name', description: 'Display name for the selected calendar' },\n },\n },\n },\n },\n ],\n description: 'Booking provider configuration (one provider per question)',\n },\n response_schema: {\n type: 'object',\n oneOf: [\n {\n required: ['calendly'],\n properties: {\n calendly: {\n type: 'object',\n required: ['event_uri', 'scheduled_time'],\n properties: {\n event_uri: { type: 'string', format: 'uri' },\n event_type: { type: 'string' },\n invitee_uri: { type: 'string', format: 'uri' },\n reschedule_url: { type: 'string', format: 'uri' },\n scheduled_time: { type: 'string', format: 'date-time' },\n cancellation_url: { type: 'string', format: 'uri' },\n },\n },\n },\n },\n ],\n description: 'Booking response with provider-specific data',\n },\n output_schema: null,\n },\n contact: {\n label: 'Contact Form',\n shorthand: 'Contact',\n icon: 'User',\n color: '#FEF9C3',\n description: 'Collect standardized contact information (name, email, phone, company)',\n category: 'input',\n sort_order: 5,\n has_options: false,\n is_terminal: false,\n show_nav_bar: true,\n loading: 'lazy',\n supports_prompt: false,\n supports_media: false,\n is_system: false,\n is_active: true,\n default_config: {\n contact: {\n fields: [\n { id: 'first_name', type: 'first_name', label: 'First Name', enabled: true, required: true },\n { id: 'email', type: 'email', label: 'Email', enabled: true, required: true },\n ],\n prompt: '',\n },\n consent_items: [\n { id: 'default-consent', label: 'I agree to the privacy policy and terms of service', order: 0, required: true },\n ],\n },\n config_schema: {\n type: 'object',\n properties: {\n title: { type: 'string' },\n fields: {\n type: 'array',\n items: {\n type: 'object',\n required: ['id', 'required'],\n properties: {\n id: { type: 'string' },\n type: { enum: ['text', 'textarea', 'email', 'tel', 'url'], type: 'string' },\n label: { type: 'string' },\n order: { type: 'number' },\n required: { type: 'boolean', default: true },\n is_custom: { type: 'boolean', default: false },\n },\n },\n },\n description: { type: 'string' },\n consent_items: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n id: { type: 'string' },\n label: { type: 'string' },\n order: { type: 'number' },\n required: { type: 'boolean' },\n },\n },\n },\n },\n },\n response_schema: {\n type: 'object',\n required: ['fields'],\n properties: {\n fields: {\n type: 'array',\n items: {\n type: 'object',\n required: ['id', 'type', 'label', 'value'],\n properties: {\n id: { type: 'string' },\n type: { type: 'string' },\n label: { type: 'string' },\n value: { type: 'string' },\n },\n },\n description: 'Contact form field entries with metadata',\n },\n consent: {\n type: 'array',\n items: {\n type: 'object',\n required: ['id', 'label', 'accepted'],\n properties: {\n id: { type: 'string' },\n label: { type: 'string' },\n accepted: { type: 'boolean' },\n },\n },\n description: 'Consent checkbox entries',\n },\n },\n },\n output_schema: {\n type: 'object',\n required: ['type', 'fields'],\n properties: {\n type: { type: 'string', const: 'contact' },\n fields: {\n type: 'array',\n items: {\n type: 'object',\n required: ['type', 'value'],\n properties: {\n type: { type: 'string' },\n value: { type: 'string' },\n },\n },\n },\n },\n },\n },\n file_upload: {\n label: 'File Upload',\n shorthand: 'Upload',\n icon: 'Upload',\n color: '#FEF9C3',\n description: 'Collect file uploads from respondents',\n category: 'input',\n sort_order: 6,\n has_options: false,\n is_terminal: false,\n show_nav_bar: true,\n loading: 'lazy',\n supports_prompt: false,\n supports_media: false,\n is_system: false,\n is_active: false,\n default_config: null,\n config_schema: {\n type: 'object',\n properties: {\n max_files: { max: 20, min: 1, type: 'number', label: 'Max files', default: 5, description: 'Maximum number of files respondents can upload' },\n max_file_size_mb: { max: 500, min: 1, type: 'number', label: 'Max file size (MB)', default: 50, description: 'Maximum size per file (1-500 MB)' },\n allowed_media_types: {\n type: 'array',\n items: { enum: ['images', 'videos', 'documents', 'all'], type: 'string' },\n label: 'Allowed media types',\n default: ['images', 'documents'],\n enumLabels: {\n all: 'All file types',\n images: 'Images (JPEG, PNG, GIF, WebP, HEIC)',\n videos: 'Videos (MP4, MOV, WebM, AVI)',\n documents: 'Documents (PDF, DOC, DOCX, XLS, XLSX, TXT, CSV)',\n },\n description: 'Select which types of files respondents can upload',\n },\n },\n },\n response_schema: {\n type: 'object',\n required: ['files'],\n properties: {\n files: {\n type: 'array',\n items: {\n type: 'object',\n required: ['id', 'name', 'storage_path', 'url', 'mime_type', 'size', 'uploaded_at'],\n properties: {\n id: { type: 'string', format: 'uuid', description: 'Unique file identifier' },\n url: { type: 'string', format: 'uri', description: 'Signed Supabase Storage URL for download' },\n name: { type: 'string', description: 'Original filename' },\n size: { type: 'integer', minimum: 1, description: 'File size in bytes' },\n mime_type: { type: 'string', description: 'File MIME type' },\n uploaded_at: { type: 'string', format: 'date-time', description: 'ISO timestamp of upload completion' },\n storage_path: { type: 'string', description: 'Full storage path: workspace_id/form_id/question_id/uuid.ext' },\n },\n },\n minItems: 1,\n description: 'Array of uploaded file metadata',\n },\n },\n },\n output_schema: null,\n },\n payment: {\n label: 'Payment',\n shorthand: 'Payment',\n icon: 'DollarSign',\n color: '#E9D5FF',\n description: null,\n category: 'action',\n sort_order: 7,\n has_options: false,\n is_terminal: false,\n show_nav_bar: true,\n loading: 'lazy',\n supports_prompt: false,\n supports_media: false,\n is_system: false,\n is_active: false,\n default_config: { amount: null, currency: 'usd', provider: 'stripe' },\n config_schema: {\n type: 'object',\n required: ['amount', 'currency', 'provider'],\n properties: {\n amount: { type: 'number', label: 'Amount (in cents)', minimum: 50, required: true, description: 'Payment amount in cents (e.g., 5000 = $50.00)' },\n currency: { enum: ['usd', 'eur', 'gbp', 'cad', 'aud'], type: 'string', label: 'Currency', default: 'usd', required: true, description: 'Three-letter ISO currency code' },\n provider: { enum: ['stripe', 'paddle'], type: 'string', label: 'Payment Provider', default: 'stripe', required: true, description: 'Payment provider to use' },\n workspace_integration_id: { type: 'string', label: 'Workspace Integration ID', description: 'UUID of the workspace_integrations record for the connected payment account' },\n },\n description: 'Payment configuration with provider-agnostic flat structure',\n },\n response_schema: {\n type: 'object',\n oneOf: [\n {\n required: ['stripe'],\n properties: {\n stripe: {\n type: 'object',\n required: ['payment_intent_id', 'status', 'amount', 'currency'],\n properties: {\n name: { type: 'string', description: 'Customer name from Stripe billing details' },\n email: { type: 'string', format: 'email', description: 'Customer email from Stripe billing details' },\n amount: { type: 'number', description: 'Payment amount in cents' },\n status: { enum: ['pending', 'succeeded', 'failed'], type: 'string', description: 'Payment status' },\n currency: { type: 'string', description: 'Three-letter ISO currency code (e.g., usd, eur)' },\n payment_intent_id: { type: 'string', description: 'Stripe payment intent ID' },\n },\n },\n },\n },\n {\n required: ['square'],\n properties: {\n square: {\n type: 'object',\n properties: {\n amount: { type: 'number' },\n status: { type: 'string' },\n order_id: { type: 'string' },\n payment_id: { type: 'string' },\n },\n },\n },\n },\n {\n required: ['paddle'],\n properties: {\n paddle: {\n type: 'object',\n properties: {\n amount: { type: 'number' },\n status: { type: 'string' },\n order_id: { type: 'string' },\n checkout_id: { type: 'string' },\n },\n },\n },\n },\n ],\n description: 'Payment response with provider-specific data',\n },\n output_schema: null,\n },\n binary: {\n label: 'Binary',\n shorthand: 'A/B',\n icon: 'CircleCheck',\n color: '#D1FAE5',\n description: 'Two-option choice - yes/no, true/false, or this vs that',\n category: 'question',\n sort_order: 1.5,\n has_options: true,\n min_options: 2,\n max_options: 2,\n max_option_length: 12,\n is_terminal: false,\n show_nav_bar: true,\n loading: 'eager',\n supports_prompt: true,\n supports_media: true,\n is_system: false,\n is_active: false,\n default_config: {\n choice: { enable_branching: true },\n options: [\n { content: 'Yes' },\n { content: 'No' },\n ],\n },\n config_schema: {\n type: 'object',\n properties: {\n choice: {\n type: 'object',\n properties: {\n enable_branching: {\n type: 'boolean',\n label: 'Enable branching logic',\n default: true,\n description: 'Allow each option to have its own logic path.',\n },\n },\n },\n content_media_type: {\n enum: ['upload', 'recorded'],\n type: 'string',\n label: 'Content media type',\n description: 'How the question media was provided',\n },\n },\n },\n response_schema: {\n type: 'string',\n description: 'Selected option ID',\n },\n output_schema: {\n type: 'object',\n required: ['type', 'label', 'option_id'],\n properties: {\n type: { type: 'string', const: 'binary' },\n label: { type: 'string', description: 'Human-readable option label' },\n option_id: { type: 'string', format: 'uuid', description: 'Selected option UUID' },\n },\n },\n },\n button: {\n label: 'Button',\n shorthand: 'Button',\n icon: 'RectangleHorizontal',\n color: '#DBEAFE',\n description: 'Simple button for acknowledgment or navigation',\n category: 'question',\n sort_order: 3,\n has_options: true,\n min_options: 1,\n max_options: 1,\n max_option_length: 28,\n is_terminal: false,\n show_nav_bar: true,\n loading: 'eager',\n supports_prompt: true,\n supports_media: true,\n is_system: false,\n is_active: true,\n default_config: { options: [{ content: 'Continue' }] },\n config_schema: {\n type: 'object',\n properties: {\n button_text: { type: 'string', label: 'Button text', default: 'Continue' },\n button_style: { enum: ['primary', 'secondary', 'outline'], type: 'string', label: 'Button style', default: 'primary' },\n },\n },\n response_schema: {\n type: 'string',\n description: 'Selected option ID',\n },\n output_schema: {\n type: 'object',\n required: ['type', 'label', 'option_id'],\n properties: {\n type: { type: 'string', const: 'button' },\n label: { type: 'string', description: 'Human-readable option label' },\n option_id: { type: 'string', format: 'uuid', description: 'Selected option UUID' },\n },\n },\n },\n redirect: {\n label: 'Redirect',\n shorthand: 'Redirect',\n icon: 'ExternalLink',\n color: '#FEE2E2',\n description: 'Redirect users to an external URL',\n category: 'end',\n sort_order: 101,\n has_options: false,\n is_terminal: true,\n show_nav_bar: false,\n loading: 'lazy',\n supports_prompt: false,\n supports_media: false,\n is_system: false,\n is_active: true,\n default_config: { url: '', auto_redirect: true },\n config_schema: {\n type: 'object',\n properties: {\n url: { type: 'string', label: 'Redirect URL', placeholder: 'https://example.com' },\n auto_redirect: { type: 'boolean', label: 'Auto-redirect', default: true, description: 'Automatically redirect to the URL instead of showing a button' },\n },\n },\n response_schema: {\n type: 'string',\n description: 'URL the user was redirected to',\n },\n output_schema: null,\n },\n link_list: {\n label: 'Link List',\n shorthand: 'Links',\n icon: 'ExternalLink',\n color: '#FEE2E2',\n description: 'Display a list of links for users to choose from',\n category: 'end',\n sort_order: 102,\n has_options: false,\n is_terminal: true,\n show_nav_bar: false,\n loading: 'lazy',\n supports_prompt: false,\n supports_media: false,\n is_system: false,\n is_active: false,\n default_config: { links: [{ id: 'default', url: '', title: '', description: '', order: 0 }], auto_redirect: false },\n config_schema: {\n type: 'object',\n properties: {\n links: {\n type: 'array',\n items: {\n type: 'object',\n required: ['id', 'url'],\n properties: {\n id: { type: 'string' },\n url: { type: 'string', label: 'URL', placeholder: 'https://example.com' },\n title: { type: 'string', label: 'Heading' },\n description: { type: 'string', label: 'Description' },\n order: { type: 'number', label: 'Sort order' },\n },\n },\n label: 'Links',\n minItems: 1,\n },\n auto_redirect: { type: 'boolean', label: 'Auto-redirect', default: false, description: 'Automatically redirect to the URL instead of showing a button' },\n },\n },\n response_schema: {\n type: 'string',\n description: 'URL of the link that was clicked',\n },\n output_schema: null,\n },\n file_download: {\n label: 'File Download',\n shorthand: 'Download',\n icon: 'Download',\n color: '#E9D5FF',\n description: 'Provide a file for respondents to download',\n category: 'action',\n sort_order: 103,\n has_options: false,\n is_terminal: false,\n show_nav_bar: true,\n loading: 'lazy',\n supports_prompt: false,\n supports_media: false,\n is_system: false,\n is_active: false,\n default_config: null,\n config_schema: {\n type: 'object',\n properties: {\n files: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n file_name: { type: 'string', label: 'Display file name', required: true },\n file_path: { type: 'string', label: 'File path in storage', required: true },\n file_size: { type: 'number', label: 'File size in bytes' },\n mime_type: { type: 'string', label: 'MIME type' },\n },\n },\n label: 'Downloadable files',\n },\n button_text: { type: 'string', label: 'Button text', default: 'Download Files' },\n description: { type: 'string', label: 'Description text' },\n },\n },\n response_schema: {\n type: 'object',\n required: ['files'],\n properties: {\n files: {\n type: 'array',\n items: {\n type: 'object',\n required: ['file_path', 'file_name', 'downloaded_at'],\n properties: {\n file_name: { type: 'string', description: 'Display name of the file' },\n file_path: { type: 'string', description: 'Storage path of the downloaded file' },\n downloaded_at: { type: 'string', format: 'date-time', description: 'Timestamp when download was initiated' },\n },\n },\n description: 'List of files downloaded by respondent',\n },\n },\n },\n output_schema: null,\n },\n shopping: {\n label: 'Shopping',\n shorthand: 'Shop',\n icon: 'ShoppingBag',\n color: '#D1FAE5',\n description: 'Product recommendations with direct checkout',\n category: 'action',\n sort_order: 8,\n has_options: false,\n is_terminal: true,\n show_nav_bar: true,\n loading: 'lazy',\n supports_prompt: false,\n supports_media: false,\n is_system: false,\n is_active: true,\n default_config: { provider: 'shopify', cta_mode: 'checkout', source_mode: 'manual' },\n config_schema: {\n type: 'object',\n required: ['provider', 'cta_mode'],\n properties: {\n title: { type: 'string', label: 'Heading', description: 'Heading shown above the product list' },\n description: { type: 'string', label: 'Description', description: 'Body text shown below the heading' },\n provider: { enum: ['shopify'], type: 'string', label: 'Provider', default: 'shopify', description: 'Ecommerce provider' },\n workspace_integration_id: { type: 'string', label: 'Workspace Integration ID', description: 'UUID of the workspace_integrations record for the connected store' },\n cta_mode: { enum: ['checkout', 'add_to_cart'], type: 'string', label: 'CTA Mode', default: 'checkout', description: 'Whether to go to checkout or add to cart' },\n source_mode: { enum: ['manual', 'collection'], type: 'string', label: 'Product source', default: 'manual', description: 'How products are selected: manually picked or from a collection' },\n collection_id: { type: 'string', label: 'Collection ID', description: 'Shopify collection GID (when source_mode is collection)' },\n collection_title: { type: 'string', label: 'Collection title', description: 'Display name of the selected collection' },\n products: {\n type: 'array',\n label: 'Selected Products',\n description: 'Products to show (static mode)',\n items: {\n type: 'object',\n properties: {\n product_id: { type: 'string', description: 'Shopify product GID' },\n variant_id: { type: 'string', description: 'Shopify variant GID' },\n title: { type: 'string' },\n handle: { type: 'string' },\n image_url: { type: 'string' },\n price: { type: 'string' },\n currency: { type: 'string' },\n recommended: { type: 'boolean', default: true, description: 'Pre-ticked in viewer' },\n },\n },\n },\n product_mappings: {\n type: 'array',\n label: 'Score-based product mappings',\n description: 'Map score ranges to different product sets. First matching range wins.',\n items: {\n type: 'object',\n required: ['min', 'max'],\n properties: {\n min: { type: 'integer', label: 'Minimum score (inclusive)' },\n max: { type: 'integer', label: 'Maximum score (inclusive)' },\n message: { type: 'string', label: 'Message' },\n products: { type: 'array', description: 'Products for this score range' },\n },\n },\n },\n },\n description: 'Shopping configuration with provider-agnostic structure',\n },\n response_schema: null,\n output_schema: null,\n },\n end_screen: {\n label: 'End Screen',\n shorthand: 'End',\n icon: 'Flag',\n color: '#FEE2E2',\n description: 'Final screen shown when form is completed',\n category: 'end',\n sort_order: 999,\n has_options: false,\n is_terminal: true,\n show_nav_bar: false,\n loading: 'eager',\n supports_prompt: false,\n supports_media: true,\n is_system: false,\n is_active: true,\n default_config: null,\n config_schema: {\n type: 'object',\n properties: {\n title: { type: 'string', label: 'Title', default: 'Thank you!', description: 'Heading shown on completion' },\n message: { type: 'string', label: 'Message', default: 'Your response has been submitted.', description: 'Message shown on completion' },\n show_score: { type: 'boolean', label: 'Show score', default: false, description: 'Display score on the end screen (e.g. \"You scored 4 out of 5\")' },\n icon: { type: 'string', label: 'Icon', enum: ['tick', 'trophy', 'star', 'crown', 'party', 'none'], default: 'tick', description: 'Icon shown above the title' },\n show_share_button: { type: 'boolean', label: 'Show share button', default: false, description: 'Show a share button above the CTA' },\n cta_type: { type: 'string', label: 'CTA type', enum: ['none', 'restart', 'external_link'], default: 'none', description: 'Primary call-to-action button type' },\n cta_text: { type: 'string', label: 'CTA button text', default: 'Continue', description: 'Button label for the CTA' },\n cta_url: { type: 'string', label: 'CTA URL', format: 'uri', description: 'URL to open (only for external_link CTA type)', placeholder: 'https://example.com' },\n score_ranges: {\n type: 'array',\n label: 'Score-based content',\n description: 'Show different content based on cumulative score. First matching range wins.',\n items: {\n type: 'object',\n required: ['min', 'max', 'title'],\n properties: {\n min: { type: 'integer', label: 'Minimum score (inclusive)' },\n max: { type: 'integer', label: 'Maximum score (inclusive)' },\n title: { type: 'string', label: 'Title' },\n message: { type: 'string', label: 'Message' },\n },\n },\n },\n scoring_results: {\n type: 'array',\n label: 'Category-based results',\n description: 'Results keyed by scoring category. The winning category (highest non-knocked-out score) determines which result is shown.',\n items: {\n type: 'object',\n required: ['category', 'title'],\n properties: {\n category: { type: 'string', label: 'Category key (must match keys used in option scores)' },\n title: { type: 'string', label: 'Title' },\n message: { type: 'string', label: 'Message' },\n cta_url: { type: 'string', label: 'CTA URL', format: 'uri' },\n cta_text: { type: 'string', label: 'CTA button text' },\n },\n },\n },\n },\n },\n response_schema: null,\n output_schema: null,\n },\n};\n\n// Derived exports\n\n/** Sorted list of all node types with their type key included */\nexport const NODE_TYPES_LIST = Object.entries(NODE_TYPES)\n .map(([type, def]) => ({ type, ...def }))\n .sort((a, b) => a.sort_order - b.sort_order);\n\n/** All valid node type keys */\nexport const NODE_TYPE_KEYS = Object.keys(NODE_TYPES);\n\n/** Response schemas keyed by node type */\nexport const RESPONSE_SCHEMAS = Object.fromEntries(\n Object.entries(NODE_TYPES).map(([k, v]) => [k, v.response_schema])\n);\n\n/** Config schemas keyed by node type */\nexport const CONFIG_SCHEMAS = Object.fromEntries(\n Object.entries(NODE_TYPES).map(([k, v]) => [k, v.config_schema])\n);\n\n/** Output schemas keyed by node type */\nexport const OUTPUT_SCHEMAS = Object.fromEntries(\n Object.entries(NODE_TYPES).map(([k, v]) => [k, v.output_schema])\n);\n\n/** Metadata subset used by viewer for layout decisions */\nexport const NODE_TYPE_METADATA = Object.fromEntries(\n Object.entries(NODE_TYPES).map(([k, v]) => [k, {\n supports_prompt: v.supports_prompt,\n supports_media: v.supports_media,\n is_terminal: v.is_terminal,\n show_nav_bar: v.show_nav_bar,\n category: v.category,\n loading: v.loading,\n }])\n);\n\n/** Terminal node type keys (is_terminal === true) */\nexport const TERMINAL_TYPES = Object.entries(NODE_TYPES)\n .filter(([, v]) => v.is_terminal)\n .map(([k]) => k);\n\n/** Node types excluded from counts (system + terminal) */\nexport const NON_COUNTABLE_TYPES = Object.entries(NODE_TYPES)\n .filter(([, v]) => v.is_system || v.is_terminal)\n .map(([k]) => k);\n\n/** Supabase .not() filter string for non-countable types */\nexport const NON_COUNTABLE_FILTER = `(${NON_COUNTABLE_TYPES.map(t => `\"${t}\"`).join(',')})`;\n\n/** Check if a node type is terminal */\nexport function isTerminalType(type) {\n return NODE_TYPE_METADATA[type]?.is_terminal === true;\n}\n\n","// @vid-master/config/integration-catalog\n// Static integration catalog — single source of truth for all apps.\n// Integration metadata rarely changes, so this is version-controlled\n// rather than stored in the database. User connections (workspace_integrations)\n// remain in the DB as dynamic data.\n\nexport const INTEGRATION_CATALOG = {\n stripe: {\n name: 'Stripe',\n category: 'form_action',\n description: 'Accept payments directly in your forms',\n logo_url: 'https://cdn.brandfetch.io/stripe.com/w/400/h/400',\n color: '#635BFF',\n sort_order: 1,\n tags: ['payment'],\n external_account_id_field: 'account_id',\n display_name_field: 'account_name',\n is_active: true,\n },\n paddle: {\n name: 'Paddle',\n category: 'form_action',\n description: 'Accept payments with Paddle',\n logo_url: 'https://cdn.brandfetch.io/paddle.com/w/400/h/400',\n color: '#6837FC',\n sort_order: 2,\n tags: ['payment'],\n external_account_id_field: null,\n display_name_field: null,\n is_active: true,\n },\n square: {\n name: 'Square',\n category: 'form_action',\n description: 'Accept payments with Square',\n logo_url: 'https://cdn.brandfetch.io/square.com/w/400/h/400',\n color: '#000000',\n sort_order: 3,\n tags: ['payment'],\n external_account_id_field: null,\n display_name_field: null,\n is_active: true,\n },\n calendly: {\n name: 'Calendly',\n category: 'form_action',\n description: 'Schedule meetings directly in your forms',\n logo_url: 'https://cdn.brandfetch.io/calendly.com/w/400/h/400',\n color: '#006BFF',\n sort_order: 4,\n tags: ['booking'],\n external_account_id_field: 'user_uri',\n display_name_field: 'user_name',\n is_active: true,\n },\n calcom: {\n name: 'Cal.com',\n category: 'form_action',\n description: 'Open-source scheduling platform for booking meetings',\n logo_url: null,\n color: '#292929',\n sort_order: 4,\n tags: ['booking'],\n external_account_id_field: 'id',\n display_name_field: 'name',\n is_active: true,\n },\n docusign: {\n name: 'DocuSign',\n category: 'form_action',\n description: 'Collect signatures in your forms',\n logo_url: 'https://cdn.brandfetch.io/docusign.com/w/400/h/400',\n color: '#FF0037',\n sort_order: 5,\n tags: ['document', 'e-signature', 'contract'],\n external_account_id_field: null,\n display_name_field: null,\n is_active: true,\n },\n webhook: {\n name: 'Webhook',\n category: 'automation',\n description: 'Send responses to custom webhooks',\n logo_url: null,\n color: '#6B7280',\n sort_order: 100,\n tags: ['webhook', 'automation', 'developer'],\n external_account_id_field: null,\n display_name_field: null,\n is_active: true,\n },\n zapier: {\n name: 'Zapier',\n category: 'automation',\n description: 'Connect to 5,000+ apps and automate workflows',\n logo_url: 'https://cdn.brandfetch.io/zapier.com/w/400/h/400',\n color: '#FF4A00',\n sort_order: 101,\n tags: ['automation', 'workflow', 'no-code'],\n external_account_id_field: null,\n display_name_field: null,\n is_active: true,\n },\n make: {\n name: 'Make',\n category: 'automation',\n description: 'Advanced automation and integrations',\n logo_url: 'https://cdn.brandfetch.io/make.com/w/400/h/400',\n color: '#6B4AFF',\n sort_order: 102,\n tags: ['automation', 'workflow', 'integration'],\n external_account_id_field: null,\n display_name_field: null,\n is_active: true,\n },\n hubspot: {\n name: 'HubSpot',\n category: 'automation',\n description: 'Sync responses to HubSpot CRM',\n logo_url: 'https://cdn.brandfetch.io/hubspot.com/w/400/h/400',\n color: '#FF7A59',\n sort_order: 103,\n tags: ['automation', 'crm', 'marketing'],\n external_account_id_field: 'portal_id',\n display_name_field: 'portal_name',\n is_active: true,\n },\n salesforce: {\n name: 'Salesforce',\n category: 'automation',\n description: 'Sync responses to Salesforce CRM',\n logo_url: 'https://cdn.brandfetch.io/salesforce.com/w/400/h/400',\n color: '#00A1E0',\n sort_order: 104,\n tags: ['automation', 'crm', 'sales'],\n external_account_id_field: null,\n display_name_field: null,\n is_active: true,\n },\n slack: {\n name: 'Slack',\n category: 'automation',\n description: 'Send notifications to Slack channels',\n logo_url: 'https://cdn.brandfetch.io/slack.com/w/400/h/400',\n color: '#4A154B',\n sort_order: 105,\n tags: ['automation', 'communication', 'notifications'],\n external_account_id_field: null,\n display_name_field: null,\n is_active: true,\n },\n shopify: {\n name: 'Shopify',\n category: 'ecommerce',\n description: 'Product recommendations from quiz results with direct checkout',\n logo_url: 'https://cdn.brandfetch.io/shopify.com/w/400/h/400',\n color: '#95BF47',\n sort_order: 200,\n tags: ['ecommerce', 'product', 'checkout', 'quiz'],\n external_account_id_field: 'shop_domain',\n display_name_field: 'shop_name',\n is_active: true,\n },\n};\n\n// Derived exports\n\n/** Sorted list of all integrations with their slug included */\nexport const INTEGRATION_CATALOG_LIST = Object.entries(INTEGRATION_CATALOG)\n .map(([slug, def]) => ({ slug, ...def }))\n .sort((a, b) => a.sort_order - b.sort_order);\n\n/** All valid integration slugs */\nexport const INTEGRATION_SLUGS = Object.keys(INTEGRATION_CATALOG);\n\n/** Get integrations filtered by category */\nexport const getIntegrationsByCategory = (category) =>\n INTEGRATION_CATALOG_LIST.filter(i => i.category === category);\n\n/** Get integrations filtered by tags (matches any) */\nexport const getIntegrationsByTags = (tags) =>\n INTEGRATION_CATALOG_LIST.filter(i => i.tags.some(t => tags.includes(t)));\n","// @vid-master/config - Essential shared configuration\n\n/**\n * Environment Detection\n * Automatically detects dev/localhost vs production\n */\nconst isServer = typeof window === 'undefined';\nconst isBrowser = typeof window !== 'undefined';\n\n// Detect localhost/development environment\nconst isLocalhost = isBrowser && (\n window.location.hostname === 'localhost' ||\n window.location.hostname === '127.0.0.1' ||\n window.location.hostname.includes('local')\n);\n\nconst isDevelopment = isServer\n ? process.env.NODE_ENV !== 'production'\n : isLocalhost;\n\nexport const ENV = {\n isDevelopment,\n isProduction: !isDevelopment,\n isLocalhost: isDevelopment, // alias for clarity\n};\n\n/**\n * Cookie domain for cross-subdomain auth & tracking\n * undefined in dev (browsers reject explicit domain on localhost)\n * .clipform.io in production (covers www., app., and apex)\n */\nexport const COOKIE_DOMAIN = ENV.isDevelopment ? undefined : '.clipform.io';\n\n/**\n * Get environment-aware URLs\n * In development: Uses localhost with appropriate ports\n * In production: Uses production domains\n */\nfunction getUrls() {\n if (ENV.isDevelopment) {\n return {\n marketing: 'http://localhost:3002',\n dashboard: 'http://localhost:3000',\n viewer: 'http://localhost:3001',\n api: 'http://localhost:3003',\n // No separate MCP host in dev - tools live on the api subpath.\n mcp: 'http://localhost:3003/mcp',\n docs: 'http://localhost:3004',\n };\n }\n\n return {\n marketing: 'https://www.clipform.io',\n dashboard: 'https://app.clipform.io',\n viewer: 'https://clipform.io',\n api: 'https://api.clipform.io',\n // Dedicated subdomain for the remote MCP server. Same Render service\n // as `api`, just routed by Host header. Token audience is bound here.\n mcp: 'https://mcp.clipform.io',\n docs: 'https://docs.clipform.io',\n };\n}\n\n/**\n * Core business information - UPDATE THESE AS NEEDED\n */\nexport const BUSINESS = {\n name: \"ClipForm\",\n tagline: \"Video-Driven Form Builder\",\n description:\n \"Create engaging forms that combine video content with interactive questions. Capture authentic responses with text, audio, or video recordings.\",\n shortDescription:\n \"Interactive video forms that capture authentic responses. Build engaging forms in minutes.\",\n domain: \"clipform.io\",\n email: {\n support: \"support@clipform.io\",\n sales: \"sales@clipform.io\",\n hello: \"hello@clipform.io\",\n },\n phone: \"+1 (555) 123-4567\",\n urls: getUrls(),\n};\n\n/**\n * Brand assets and visual identity\n */\nexport const BRAND = {\n logo: {\n // Logo files (should be in public/ directory of each app)\n primary: \"/logo.svg\",\n withText: \"/logo_text.svg\",\n icon: \"/favicon.ico\",\n iconSvg: \"/icon.svg\",\n appleTouchIcon: \"/apple-touch-icon.png\",\n // Logo usage guidelines\n minWidth: \"120px\",\n maxWidth: \"200px\",\n spacing: \"16px\", // minimum clear space around logo\n },\n colors: {\n // Reference to design system colors for brand consistency\n primary: \"#424242\", // Matches body text\n secondary: \"#424242\", // --color-neutral-700\n accent: \"#3182CE\", // Electric blue for highlights\n },\n fonts: {\n primary: \"Inter, sans-serif\",\n headings: \"Inter, sans-serif\",\n body: \"Inter, sans-serif\",\n },\n};\n\n/**\n * Plan limits — shared between API (enforcement), dashboard (UI gating), and viewer (branding)\n *\n * Keyed by plan_version string (e.g. 'free_v1', 'pro_v1') so we can\n * grandfather old limits when pricing changes. New signups get the version\n * from CURRENT_PLAN_VERSIONS; existing companies keep theirs until\n * explicitly migrated.\n */\nexport const PLAN_LIMITS = {\n free_v1: {\n tier: 0,\n name: 'Free',\n price: '$0',\n period: 'forever',\n stripe_price_id: { test: null, live: null },\n node_limit: 3,\n show_branding: true,\n custom_theme: false,\n response_limit: null,\n features: [\n 'Up to 3 questions per form',\n 'Unlimited responses',\n 'Video integration',\n 'Clipform branding',\n ],\n },\n pro_v1: {\n tier: 1,\n name: 'Pro',\n price: '$20',\n period: '/month',\n stripe_price_id: { test: 'price_1TPQLdCWdEPD0KoNOtrm0Fav', live: null },\n node_limit: null,\n show_branding: false,\n custom_theme: true,\n response_limit: null,\n features: [\n 'Unlimited questions',\n 'Unlimited responses',\n 'Custom themes & colors',\n 'No Clipform branding',\n ],\n },\n};\n\n/** Maps tier integer → version string assigned to new signups */\nexport const CURRENT_PLAN_VERSIONS = { 0: 'free_v1', 1: 'pro_v1' };\n\n/**\n * Product information and features\n */\nexport const PRODUCT = {\n features: {\n core: [\n \"Video Integration\",\n \"Audio & Video Responses\",\n \"Smart Logic & Branching\",\n \"Real-time Analytics\",\n ],\n premium: [\n \"Custom Branding\",\n \"Advanced Integrations\",\n \"Enterprise Security\",\n \"Priority Support\",\n ],\n },\n // Derived from PLAN_LIMITS (source of truth)\n get pricing() {\n const free = PLAN_LIMITS[CURRENT_PLAN_VERSIONS[0]];\n const pro = PLAN_LIMITS[CURRENT_PLAN_VERSIONS[1]];\n return {\n free: { name: free.name, price: free.price, period: free.period, features: free.features },\n pro: { name: pro.name, price: pro.price, period: pro.period, features: pro.features },\n };\n },\n};\n\n/**\n * Social media links\n */\nexport const SOCIAL = {\n twitter: \"@clipform\",\n linkedin: \"company/clipform\",\n github: \"clipform\",\n urls: {\n twitter: \"https://twitter.com/clipform\",\n linkedin: \"https://linkedin.com/company/clipform\",\n github: \"https://github.com/clipform\",\n },\n};\n\n/**\n * Legal and compliance\n */\nexport const LEGAL = {\n company: \"Reco Ventures Ltd.\",\n copyright: \"© 2026 ClipForm. All rights reserved.\",\n privacy: \"/privacy\",\n terms: \"/terms\",\n};\n\n/**\n * Standard contact form field definitions\n * Source of truth for both dashboard (field picker) and viewer (form rendering)\n */\nexport const CONTACT_FIELDS = [\n { id: 'first_name', label: 'First Name', type: 'text', placeholder: 'Enter first name', order: 1 },\n { id: 'last_name', label: 'Last Name', type: 'text', placeholder: 'Enter last name', order: 2 },\n { id: 'email', label: 'Email Address', type: 'email', placeholder: 'you@example.com', order: 3 },\n { id: 'phone', label: 'Phone Number', type: 'tel', placeholder: '(555) 123-4567', order: 4 },\n { id: 'company', label: 'Company', type: 'text', placeholder: 'Company name', order: 5 },\n { id: 'job_title', label: 'Job Title', type: 'text', placeholder: 'Your role', order: 6 },\n { id: 'website', label: 'Website', type: 'url', placeholder: 'https://example.com', order: 7 },\n { id: 'linkedin', label: 'LinkedIn Profile', type: 'url', placeholder: 'https://linkedin.com/in/username', order: 8 },\n { id: 'message', label: 'Message', type: 'textarea', placeholder: 'Your message...', order: 9 },\n];\n\nexport const CONTACT_FIELDS_MAP = Object.fromEntries(\n CONTACT_FIELDS.map(f => [f.id, f])\n);\n\n/**\n * Node type definitions — re-exported from node-types.js\n */\nexport {\n NODE_TYPES,\n NODE_TYPES_LIST,\n NODE_TYPE_KEYS,\n NODE_TYPE_METADATA,\n RESPONSE_SCHEMAS,\n CONFIG_SCHEMAS,\n OUTPUT_SCHEMAS,\n TERMINAL_TYPES,\n NON_COUNTABLE_TYPES,\n NON_COUNTABLE_FILTER,\n isTerminalType,\n} from './node-types.js';\n\nexport {\n validateAgainstSchema,\n validateConfig,\n validateOptions,\n validateResponse,\n validateOutput,\n} from './validate.js';\n\nexport { FEATURE_FLAGS } from './feature-flags.js';\n\n/**\n * Integration catalog definitions — re-exported from integration-catalog.js\n */\nexport {\n INTEGRATION_CATALOG,\n INTEGRATION_CATALOG_LIST,\n INTEGRATION_SLUGS,\n getIntegrationsByCategory,\n getIntegrationsByTags,\n} from './integration-catalog.js';\n\n/**\n * API key prefixes — shared between API (validation) and dashboard (generation)\n */\nexport const API_KEY_PREFIXES = ['cf_live_', 'cf_test_'];\nexport const API_KEY_PREFIX = ENV.isProduction ? 'cf_live_' : 'cf_test_';\n\n/**\n * Input validation limits — shared between API routes and MCP server\n */\nexport const VALIDATION_LIMITS = {\n form: {\n title: { max: 1000 },\n questions: { max: 100 },\n },\n question: {\n prompt: { max: 5000 },\n options: { max: 50 },\n },\n};\n","import { z } from \"zod\";\nimport { NODE_TYPES, CONTACT_FIELDS } from \"./config.js\";\n\n// --- Derived constants (zero hardcoded type lists) ---\n\n/** Active, non-system node types — the only types the MCP server exposes */\nexport const ACTIVE_NODE_TYPES = Object.entries(NODE_TYPES as Record<string, any>)\n .filter(([, def]) => def.is_active && !def.is_system)\n .map(([type]) => type) as [string, ...string[]]; // tuple for z.enum\n\n/** Contact field IDs derived from the config package */\nexport const CONTACT_FIELD_IDS = CONTACT_FIELDS.map(\n (f: { id: string }) => f.id\n);\n\n// --- Auto-generated config descriptions ---\n\n/**\n * Walk a JSON-Schema-style config_schema and produce a concise one-line summary.\n * Handles primitives, enums, nested objects (1 level), and arrays with item shapes.\n */\nfunction generateConfigSummary(\n configSchema: any,\n typeKey?: string\n): string {\n if (!configSchema?.properties) return \"\";\n\n const parts: string[] = [];\n\n for (const [key, prop] of Object.entries<any>(configSchema.properties)) {\n // Skip internal-only fields the LLM shouldn't set\n if (key === \"content_media_type\") continue;\n\n if (prop.enum) {\n const vals = prop.enum.map((v: string) => `\"${v}\"`).join(\"|\");\n let s = `${key} (${vals}`;\n if (prop.default !== undefined) s += `, default: \"${prop.default}\"`;\n s += \")\";\n parts.push(s);\n } else if (prop.type === \"boolean\") {\n let s = `${key} (boolean`;\n if (prop.default !== undefined) s += `, default: ${prop.default}`;\n s += \")\";\n parts.push(s);\n } else if (prop.type === \"number\") {\n let s = `${key} (number`;\n if (prop.default !== undefined) s += `, default: ${prop.default}`;\n s += \")\";\n parts.push(s);\n } else if (prop.type === \"string\") {\n let s = `${key} (string`;\n if (prop.default !== undefined) s += `, default: \"${prop.default}\"`;\n s += \")\";\n parts.push(s);\n } else if (prop.type === \"array\" && prop.items?.properties) {\n // Array of objects — show item shape\n const itemKeys = Object.keys(prop.items.properties).join(\", \");\n parts.push(`${key} (array of {${itemKeys}})`);\n } else if (prop.type === \"array\" && prop.items?.enum) {\n const vals = prop.items.enum.map((v: string) => `\"${v}\"`).join(\"|\");\n parts.push(`${key} (array of ${vals})`);\n } else if (prop.type === \"object\" && prop.properties) {\n // Nested object — summarize child keys\n const childKeys = Object.keys(prop.properties).join(\", \");\n parts.push(`${key} ({${childKeys}})`);\n }\n }\n\n // Special case: for contact type, append available field IDs\n if (typeKey === \"contact\") {\n parts.push(`Available field IDs: ${CONTACT_FIELD_IDS.join(\", \")}`);\n }\n\n return parts.length > 0 ? `Config: ${parts.join(\", \")}` : \"\";\n}\n\n/** Per-type description including config hints, auto-generated from NODE_TYPES */\nexport const NODE_TYPES_DESCRIPTION = (() => {\n const lines: string[] = [\"Node types:\"];\n\n for (const type of ACTIVE_NODE_TYPES) {\n const def = (NODE_TYPES as Record<string, any>)[type];\n let line = `- ${type}: ${def.description || def.label}`;\n\n if (def.has_options) {\n line += \" (supports options array)\";\n }\n\n const configHint = generateConfigSummary(def.config_schema, type);\n if (configHint) {\n line += `. ${configHint}`;\n }\n\n lines.push(line);\n }\n\n return lines.join(\"\\n\");\n})();\n\n/** Aggregate config description for Zod .describe() on the config field */\nexport const CONFIG_DESCRIPTION = (() => {\n const lines: string[] = [\"Type-specific configuration. Per-type keys:\"];\n\n for (const type of ACTIVE_NODE_TYPES) {\n const def = (NODE_TYPES as Record<string, any>)[type];\n const summary = generateConfigSummary(def.config_schema, type);\n if (summary) {\n lines.push(` ${type}: ${summary}`);\n }\n }\n\n return lines.join(\"\\n\");\n})();\n\n// --- Zod schemas ---\n\nexport const OptionSchema = z.object({\n content: z.string().describe(\"Option text\"),\n score: z.number().optional().describe(\"Score value for this option (for scored quizzes)\"),\n scores: z.record(z.number()).optional().describe(\"Category-based scores keyed by category name (for personality/category quizzes)\"),\n});\n\n/** Build options description from config - which types need options, min counts, max lengths */\nconst OPTIONS_DESCRIPTION = (() => {\n const hints: string[] = [\"Answer options.\"];\n for (const type of ACTIVE_NODE_TYPES) {\n const def = (NODE_TYPES as Record<string, any>)[type];\n if (!def.has_options) continue;\n const parts: string[] = [`${type}: required`];\n if (def.min_options !== undefined) parts.push(`min ${def.min_options}`);\n if (def.max_options !== undefined) parts.push(`max ${def.max_options}`);\n if (def.max_option_length !== undefined) parts.push(`content max ${def.max_option_length} chars`);\n hints.push(parts.join(\", \"));\n }\n return hints.join(\" \");\n})();\n\nexport const NodeSchema = z.object({\n type: z.enum(ACTIVE_NODE_TYPES),\n prompt: z.string().describe(\"The text shown to the respondent\"),\n label: z.string().optional().describe(\"Short label for the node (used in logic builder). Defaults to the prompt text.\"),\n required: z.boolean().optional().default(true),\n config: z\n .record(z.unknown())\n .optional()\n .describe(CONFIG_DESCRIPTION),\n options: z\n .array(OptionSchema)\n .optional()\n .describe(OPTIONS_DESCRIPTION),\n});\n","import { BUSINESS } from \"@vid-master/config\";\nimport { getMcpAuth } from \"./auth-context.js\";\n\nconst DASHBOARD_URL =\n process.env.SERVER_URL || process.env.DASHBOARD_URL || \"https://api.clipform.io\";\nconst API_VERSION = \"v1\";\n\nconst INTERNAL_API_URL =\n process.env.INTERNAL_API_URL || DASHBOARD_URL;\nconst INTERNAL_SECRET = process.env.INTERNAL_SERVICE_SECRET || \"\";\n\nlet _apiKey: string | undefined;\n\nexport function setApiKey(key: string) {\n _apiKey = key;\n}\n\nexport function getApiKey(): string | undefined {\n return _apiKey;\n}\n\ninterface ApiOptions {\n method?: string;\n body?: Record<string, unknown>;\n params?: Record<string, string>;\n}\n\ntype ApiResult =\n | { ok: true; data: Record<string, unknown> }\n | { ok: false; status: number; error: string };\n\nexport async function callApi(\n path: string,\n options: ApiOptions = {}\n): Promise<ApiResult> {\n const { method = \"GET\", body, params } = options;\n\n let url = `${DASHBOARD_URL}/${API_VERSION}${path}`;\n if (params) {\n const searchParams = new URLSearchParams(params);\n url += `?${searchParams.toString()}`;\n }\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n\n // If the MCP server is running in-process inside the API host AND the\n // request has been OAuth-authenticated, forward the end-user identity\n // via internal headers instead of propagating the caller's Bearer.\n //\n // Token passthrough is forbidden by the MCP Authorization spec: the\n // token that claude.ai presented was issued for audience `${api}/mcp`\n // and must not be replayed against downstream routes like /v1/forms/*.\n // Those routes instead trust the INTERNAL_SECRET + X-Mcp-User /\n // X-Mcp-Workspace headers set below.\n const mcpAuth = getMcpAuth();\n if (mcpAuth && INTERNAL_SECRET) {\n headers[\"Authorization\"] = `Bearer ${INTERNAL_SECRET}`;\n headers[\"X-Mcp-User\"] = mcpAuth.user_id;\n headers[\"X-Mcp-Workspace\"] = mcpAuth.workspace_id;\n } else if (_apiKey) {\n headers[\"Authorization\"] = `Bearer ${_apiKey}`;\n }\n\n const fetchOptions: RequestInit = { method, headers };\n\n if (body && method !== \"GET\") {\n fetchOptions.body = JSON.stringify(body);\n }\n\n let response: Response;\n try {\n response = await fetch(url, fetchOptions);\n } catch (err) {\n return {\n ok: false,\n status: 0,\n error: `Failed to connect to dashboard API at ${url}. Make sure the dashboard is running.\\n\\nError: ${err instanceof Error ? err.message : String(err)}`,\n };\n }\n\n // 204 No Content — successful delete with no body\n if (response.status === 204) {\n return { ok: true, data: {} };\n }\n\n const data = (await response.json()) as Record<string, unknown>;\n\n if (!response.ok) {\n return {\n ok: false,\n status: response.status,\n error: (data.error as string) || `API error (${response.status})`,\n };\n }\n\n return { ok: true, data };\n}\n\n/**\n * Call an internal API endpoint (formgen, media, etc.)\n * Uses INTERNAL_SECRET for auth and INTERNAL_API_URL as base.\n */\nexport async function callInternalApi(\n path: string,\n options: ApiOptions = {}\n): Promise<ApiResult> {\n const { method = \"POST\", body, params } = options;\n\n let url = `${INTERNAL_API_URL}${path}`;\n if (params) {\n const searchParams = new URLSearchParams(params);\n url += `?${searchParams.toString()}`;\n }\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n if (INTERNAL_SECRET) {\n headers[\"Authorization\"] = `Bearer ${INTERNAL_SECRET}`;\n }\n\n const fetchOptions: RequestInit = { method, headers };\n if (body && method !== \"GET\") {\n fetchOptions.body = JSON.stringify(body);\n }\n\n let response: Response;\n try {\n response = await fetch(url, fetchOptions);\n } catch (err) {\n return {\n ok: false,\n status: 0,\n error: `Failed to connect to internal API at ${url}.\\n\\nError: ${err instanceof Error ? err.message : String(err)}`,\n };\n }\n\n if (response.status === 204) {\n return { ok: true, data: {} };\n }\n\n const data = (await response.json()) as Record<string, unknown>;\n\n if (!response.ok) {\n return {\n ok: false,\n status: response.status,\n error: (data.error as string) || `Internal API error (${response.status})`,\n };\n }\n\n return { ok: true, data };\n}\n\nexport function errorResult(message: string) {\n return {\n content: [{ type: \"text\" as const, text: message }],\n isError: true,\n };\n}\n\nexport function textResult(text: string) {\n return {\n content: [{ type: \"text\" as const, text }],\n };\n}\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\nimport { callApi, errorResult, textResult } from \"../lib/api-client.js\";\n\nexport function registerListFormsTool(server: McpServer) {\n server.registerTool(\n \"clipform_list_forms\",\n {\n title: \"List Clipforms\",\n description: `List forms in your workspace with optional filtering. Returns paginated results (cursor-based). Use the next_cursor value to fetch the next page.`,\n inputSchema: {\n limit: z\n .number()\n .int()\n .min(1)\n .max(100)\n .optional()\n .describe(\"Number of forms to return (default 25, max 100)\"),\n cursor: z\n .string()\n .optional()\n .describe(\n \"Pagination cursor from previous response's next_cursor\"\n ),\n tag: z\n .string()\n .optional()\n .describe(\n \"Filter by tag name(s), comma-separated. AND logic: only forms with ALL tags are returned.\"\n ),\n published: z\n .enum([\"true\", \"false\"])\n .optional()\n .describe(\"Filter by publish status\"),\n search: z\n .string()\n .optional()\n .describe(\"Search forms by title (case-insensitive substring match)\"),\n sort: z\n .enum([\"created_at\", \"updated_at\"])\n .optional()\n .describe(\"Sort field (default: created_at)\"),\n order: z\n .enum([\"asc\", \"desc\"])\n .optional()\n .describe(\"Sort order (default: desc, newest first)\"),\n },\n annotations: {\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: true,\n },\n },\n async ({ limit, cursor, tag, published, search, sort, order }) => {\n const params: Record<string, string> = { include: \"tags\" };\n if (limit !== undefined) params.limit = String(limit);\n if (cursor) params.cursor = cursor;\n if (tag) params.tag = tag;\n if (published) params.published = published;\n if (search) params.search = search;\n if (sort) params.sort = sort;\n if (order) params.order = order;\n\n const result = await callApi(\"/forms\", { params });\n\n if (!result.ok) {\n return errorResult(result.error);\n }\n\n const data = result.data as {\n forms: Array<{\n id: string;\n title: string;\n share_id: string;\n is_published: boolean;\n created_at: string;\n updated_at: string;\n tags: Array<{ id: string; name: string; color: string | null }>;\n }>;\n next_cursor: string | null;\n };\n\n if (data.forms.length === 0) {\n return textResult(\"No forms found matching the criteria.\");\n }\n\n const lines: string[] = [`Found ${data.forms.length} form(s):\\n`];\n\n for (const f of data.forms) {\n const status = f.is_published ? \"published\" : \"draft\";\n const tagStr = f.tags.length > 0 ? ` [${f.tags.map((t) => t.name).join(\", \")}]` : \"\";\n lines.push(`- **${f.title || \"(untitled)\"}** [${status}]${tagStr}`);\n lines.push(` ID: ${f.id}`);\n lines.push(` Share ID: ${f.share_id}`);\n lines.push(` Created: ${f.created_at}`);\n lines.push(\"\");\n }\n\n if (data.next_cursor) {\n lines.push(\n `More results available. Pass cursor: \"${data.next_cursor}\" to get the next page.`\n );\n }\n\n return textResult(lines.join(\"\\n\"));\n }\n );\n}\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\nimport { callApi, errorResult, textResult } from \"../lib/api-client.js\";\nimport { formatFormState } from \"../lib/format-form.js\";\n\nexport function registerGetFormTool(server: McpServer) {\n server.registerTool(\n \"clipform_get_form\",\n {\n title: \"Get Clipform\",\n description: `Retrieve a form's details including all questions in sequential order. Use this to see the current state of a form before making changes.`,\n inputSchema: {\n form_id: z.string().uuid().describe(\"The form UUID (returned by clipform_create_form, not the short share_id from the URL)\"),\n },\n annotations: {\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: true,\n },\n },\n async ({ form_id }) => {\n const result = await callApi(`/forms/${form_id}`);\n\n if (!result.ok) {\n return errorResult(result.error);\n }\n\n return textResult(formatFormState(result.data));\n }\n );\n}\n","import { callApi } from \"./api-client.js\";\n\nexport function formatFormState(data: Record<string, unknown>): string {\n const questions = data.questions as Array<{\n id: string;\n type: string;\n prompt: string;\n label?: string;\n required: boolean;\n config?: Record<string, unknown>;\n options?: Array<{ id: string; content: string }>;\n }>;\n\n const lines: string[] = [\n `Form: ${data.title}`,\n `Form ID: ${data.form_id}`,\n `Published: ${data.is_published}`,\n ``,\n `Nodes (in order):`,\n ];\n\n for (let i = 0; i < questions.length; i++) {\n const q = questions[i];\n lines.push(` ${i + 1}. [${q.type}] ${q.prompt || \"(no prompt)\"}`);\n lines.push(` Node ID: ${q.id}`);\n if (q.required) lines.push(` Required: yes`);\n if (q.config && Object.keys(q.config).length > 0) {\n lines.push(` Config: ${JSON.stringify(q.config)}`);\n }\n if (q.options && q.options.length > 0) {\n lines.push(\n ` Options: ${q.options.map((o) => o.content).join(\", \")}`\n );\n }\n }\n\n return lines.join(\"\\n\");\n}\n\nexport async function fetchAndFormatFormState(\n formId: string\n): Promise<string | null> {\n const result = await callApi(`/forms/${formId}`);\n if (!result.ok) return null;\n return formatFormState(result.data);\n}\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\nimport { callApi, errorResult, textResult } from \"../lib/api-client.js\";\nimport { fetchAndFormatFormState } from \"../lib/format-form.js\";\n\nexport function registerUpdateFormTool(server: McpServer) {\n server.registerTool(\n \"clipform_update_form\",\n {\n title: \"Update Clipform\",\n description: `Update a form's title, publish status, settings, or tags. Use clipform_get_form first to see current values.`,\n inputSchema: {\n form_id: z.string().uuid().describe(\"The form UUID (returned by clipform_create_form, not the short share_id from the URL)\"),\n title: z.string().optional().describe(\"New form title\"),\n is_published: z\n .boolean()\n .optional()\n .describe(\"Set to true to publish, false to unpublish\"),\n show_step_counter: z\n .boolean()\n .optional()\n .describe(\"Show step counter (e.g. '1/5'). Recommended for quizzes.\"),\n disable_back_navigation: z\n .boolean()\n .optional()\n .describe(\"Prevent respondents from going back. Recommended for quizzes.\"),\n total_steps: z\n .number()\n .nullable()\n .optional()\n .describe(\"Override the total step count shown in the step counter. Set null to auto-calculate.\"),\n primary_color: z\n .string()\n .optional()\n .describe(\"Primary/brand color (hex or CSS color). Used for buttons and accents.\"),\n background_color: z\n .string()\n .optional()\n .describe(\"Background color (hex, rgba, or CSS color).\"),\n font_family: z\n .string()\n .optional()\n .describe(\"Font family name (e.g. 'Inter', 'Roboto', 'Playfair Display').\"),\n embed_autoplay: z\n .boolean()\n .optional()\n .describe(\"Auto-play video when embedded (default: false). When off, embeds show a thumbnail + play button.\"),\n description: z\n .string()\n .nullable()\n .optional()\n .describe(\"SEO description (meta description, og:description). Set null to clear.\"),\n author: z\n .string()\n .nullable()\n .optional()\n .describe(\"Author/brand name shown to respondents. Set null to clear.\"),\n brand_name: z\n .string()\n .nullable()\n .optional()\n .describe(\"Brand name shown alongside the logo in the viewer. Set null to clear.\"),\n logo_url: z\n .string()\n .nullable()\n .optional()\n .describe(\"URL to a logo image shown in the viewer header. Set null to clear.\"),\n tags: z\n .array(z.string())\n .optional()\n .describe(\"Replace all tags on this form. Pass the full desired set (e.g. ['quiz', 'trivia', 'slug:elephants']). Omit to leave tags unchanged.\"),\n },\n annotations: {\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: true,\n },\n },\n async ({ form_id, title, is_published, show_step_counter, disable_back_navigation, total_steps, primary_color, background_color, font_family, embed_autoplay, description, author, brand_name, logo_url, tags }) => {\n const body: Record<string, unknown> = {};\n if (title !== undefined) body.title = title;\n if (is_published !== undefined) body.is_published = is_published;\n if (show_step_counter !== undefined) body.show_step_counter = show_step_counter;\n if (disable_back_navigation !== undefined) body.disable_back_navigation = disable_back_navigation;\n if (total_steps !== undefined) body.total_steps = total_steps;\n if (primary_color !== undefined) body.primary_color = primary_color;\n if (background_color !== undefined) body.background_color = background_color;\n if (font_family !== undefined) body.font_family = font_family;\n if (embed_autoplay !== undefined) body.embed_autoplay = embed_autoplay;\n if (description !== undefined) body.description = description;\n if (author !== undefined) body.author = author;\n if (brand_name !== undefined) body.brand_name = brand_name;\n if (logo_url !== undefined) body.logo_url = logo_url;\n\n if (Object.keys(body).length > 0) {\n const result = await callApi(`/forms/${form_id}`, {\n method: \"PATCH\",\n body,\n });\n\n if (!result.ok) {\n return errorResult(result.error);\n }\n }\n\n if (tags) {\n const tagResult = await callApi(`/forms/${form_id}/tags`, {\n method: \"PUT\",\n body: { tags },\n });\n\n if (!tagResult.ok) {\n return errorResult(tagResult.error);\n }\n }\n\n const updates: string[] = [];\n if (title !== undefined) updates.push(`Title → \"${title}\"`);\n if (is_published !== undefined)\n updates.push(`Published → ${is_published}`);\n if (show_step_counter !== undefined)\n updates.push(`Step counter → ${show_step_counter}`);\n if (disable_back_navigation !== undefined)\n updates.push(`Back navigation → ${disable_back_navigation ? \"disabled\" : \"enabled\"}`);\n if (total_steps !== undefined)\n updates.push(`Total steps → ${total_steps === null ? \"auto\" : total_steps}`);\n if (primary_color !== undefined)\n updates.push(`Primary color → ${primary_color}`);\n if (background_color !== undefined)\n updates.push(`Background color → ${background_color}`);\n if (font_family !== undefined)\n updates.push(`Font → ${font_family}`);\n if (embed_autoplay !== undefined)\n updates.push(`Embed autoplay → ${embed_autoplay}`);\n if (description !== undefined)\n updates.push(`Description → ${description === null ? \"cleared\" : `\"${description}\"`}`);\n if (author !== undefined)\n updates.push(`Author → ${author === null ? \"cleared\" : `\"${author}\"`}`);\n if (brand_name !== undefined)\n updates.push(`Brand name → ${brand_name === null ? \"cleared\" : `\"${brand_name}\"`}`);\n if (logo_url !== undefined)\n updates.push(`Logo URL → ${logo_url === null ? \"cleared\" : logo_url}`);\n if (tags)\n updates.push(`Tags → [${tags.join(\", \")}]`);\n\n const confirmMsg = `Form updated:\\n${updates.join(\"\\n\")}`;\n const formState = await fetchAndFormatFormState(form_id);\n return textResult(formState ? `${confirmMsg}\\n\\n---\\n\\n${formState}` : confirmMsg);\n }\n );\n}\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\nimport { callApi, errorResult, textResult } from \"../lib/api-client.js\";\n\nexport function registerDeleteFormTool(server: McpServer) {\n server.registerTool(\n \"clipform_delete_form\",\n {\n title: \"Delete Clipform\",\n description: `Permanently delete an unclaimed form and all its questions. This cannot be undone. Only works on forms that haven't been claimed yet.`,\n inputSchema: {\n form_id: z.string().uuid().describe(\"The form UUID to delete (returned by clipform_create_form, not the short share_id from the URL)\"),\n },\n annotations: {\n readOnlyHint: false,\n destructiveHint: true,\n idempotentHint: false,\n openWorldHint: true,\n },\n },\n async ({ form_id }) => {\n const result = await callApi(`/forms/${form_id}`, {\n method: \"DELETE\",\n });\n\n if (!result.ok) {\n return errorResult(result.error);\n }\n\n return textResult(`Form ${form_id} has been permanently deleted.`);\n }\n );\n}\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\nimport { NodeSchema, NODE_TYPES_DESCRIPTION } from \"../lib/schemas.js\";\nimport { callApi, errorResult, textResult } from \"../lib/api-client.js\";\nimport { fetchAndFormatFormState } from \"../lib/format-form.js\";\n\nexport function registerAddNodeTool(server: McpServer) {\n server.registerTool(\n \"clipform_add_node\",\n {\n title: \"Add Node\",\n description: `Add a new node to an existing form. By default, the node is inserted before the end screen (appended to the end of the flow). Use after_node_id to insert at a specific position.\n\n${NODE_TYPES_DESCRIPTION}\n\nAll type definitions and config schemas are derived from @vid-master/config (answer-types).`,\n inputSchema: {\n form_id: z.string().uuid().describe(\"The form UUID (returned by clipform_create_form, not the short share_id from the URL)\"),\n question: NodeSchema.describe(\"The node to add\"),\n after_node_id: z\n .string()\n .optional()\n .describe(\n \"Insert after this node ID. Omit to append before the end screen.\"\n ),\n },\n annotations: {\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: true,\n },\n },\n async ({ form_id, question, after_node_id }) => {\n const body: Record<string, unknown> = { question };\n if (after_node_id) body.after_node_id = after_node_id;\n\n const result = await callApi(`/forms/${form_id}/nodes`, {\n method: \"POST\",\n body,\n });\n\n if (!result.ok) {\n return errorResult(result.error);\n }\n\n const confirmMsg = [\n `Node added successfully!`,\n `Node ID: ${result.data.node_id}`,\n `Type: ${question.type}`,\n `Prompt: ${question.prompt}`,\n ].join(\"\\n\");\n\n const formState = await fetchAndFormatFormState(form_id);\n return textResult(formState ? `${confirmMsg}\\n\\n---\\n\\n${formState}` : confirmMsg);\n }\n );\n}\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\nimport { ACTIVE_NODE_TYPES, CONTACT_FIELD_IDS, CONFIG_DESCRIPTION, OptionSchema } from \"../lib/schemas.js\";\nimport { callApi, errorResult, textResult } from \"../lib/api-client.js\";\nimport { fetchAndFormatFormState } from \"../lib/format-form.js\";\n\nexport function registerUpdateNodeTool(server: McpServer) {\n server.registerTool(\n \"clipform_update_node\",\n {\n title: \"Update Node\",\n description: `Update an existing node's text, type, config, or options. Use clipform_get_form first to find the node ID. Does not change the node's position in the flow. All type definitions and config schemas are derived from @vid-master/config (answer-types).`,\n inputSchema: {\n form_id: z.string().uuid().describe(\"The form UUID (returned by clipform_create_form, not the short share_id from the URL)\"),\n node_id: z.string().describe(\"The node ID to update\"),\n prompt: z.string().optional().describe(\"New question text\"),\n label: z.string().optional().describe(\"Short label for the question (used in logic builder)\"),\n type: z\n .enum(ACTIVE_NODE_TYPES)\n .optional()\n .describe(\"Change the question type\"),\n required: z.boolean().optional().describe(\"Whether an answer is required\"),\n config: z\n .record(z.unknown())\n .optional()\n .describe(CONFIG_DESCRIPTION),\n options: z\n .array(OptionSchema)\n .optional()\n .describe(\n \"Replace all options (for choice questions). Omit to keep existing options.\"\n ),\n },\n annotations: {\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: true,\n },\n },\n async ({\n form_id,\n node_id,\n prompt,\n label,\n type,\n required,\n config,\n options,\n }) => {\n const body: Record<string, unknown> = {};\n if (prompt !== undefined) body.prompt = prompt;\n if (label !== undefined) body.label = label;\n if (type !== undefined) body.type = type;\n if (required !== undefined) body.required = required;\n if (config !== undefined) body.config = config;\n if (options !== undefined) body.options = options;\n\n const result = await callApi(\n `/forms/${form_id}/nodes/${node_id}`,\n { method: \"PATCH\", body }\n );\n\n if (!result.ok) {\n return errorResult(result.error);\n }\n\n const updates: string[] = [];\n if (prompt !== undefined) updates.push(`Prompt → \"${prompt}\"`);\n if (label !== undefined) updates.push(`Label → \"${label}\"`);\n if (type !== undefined) updates.push(`Type → ${type}`);\n if (required !== undefined) updates.push(`Required → ${required}`);\n if (config !== undefined) updates.push(`Config updated`);\n if (options !== undefined)\n updates.push(`Options → ${options.map((o) => o.content).join(\", \")}`);\n\n const confirmMsg = `Node ${node_id} updated:\\n${updates.join(\"\\n\")}`;\n const formState = await fetchAndFormatFormState(form_id);\n return textResult(formState ? `${confirmMsg}\\n\\n---\\n\\n${formState}` : confirmMsg);\n }\n );\n}\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\nimport { callApi, errorResult, textResult } from \"../lib/api-client.js\";\nimport { fetchAndFormatFormState } from \"../lib/format-form.js\";\n\nexport function registerDeleteNodeTool(server: McpServer) {\n server.registerTool(\n \"clipform_delete_node\",\n {\n title: \"Delete Node\",\n description: `Delete a node from a form. The logic chain is automatically re-linked (the previous node will point to the next one). Cannot delete the start node or the last end screen.`,\n inputSchema: {\n form_id: z.string().uuid().describe(\"The form UUID (returned by clipform_create_form, not the short share_id from the URL)\"),\n node_id: z.string().describe(\"The node ID to delete\"),\n },\n annotations: {\n readOnlyHint: false,\n destructiveHint: true,\n idempotentHint: false,\n openWorldHint: true,\n },\n },\n async ({ form_id, node_id }) => {\n const result = await callApi(\n `/forms/${form_id}/nodes/${node_id}`,\n { method: \"DELETE\" }\n );\n\n if (!result.ok) {\n return errorResult(result.error);\n }\n\n const confirmMsg = `Node ${node_id} deleted. The logic chain has been re-linked.`;\n const formState = await fetchAndFormatFormState(form_id);\n return textResult(formState ? `${confirmMsg}\\n\\n---\\n\\n${formState}` : confirmMsg);\n }\n );\n}\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\nimport { callApi, errorResult, textResult } from \"../lib/api-client.js\";\n\nconst MediaItemSchema = z.object({\n node_id: z.string().describe(\"The node ID\"),\n media_type: z.enum([\"video\", \"still\"]).describe(\"Type of media\"),\n media_source: z\n .enum([\"uploaded\", \"recorded\"])\n .default(\"uploaded\")\n .describe(\"How the media was created\"),\n url: z\n .string()\n .url()\n .optional()\n .describe(\"Public URL of the media file. When provided, the server fetches and stores it directly.\"),\n captions: z\n .array(\n z.object({\n start: z.number().describe(\"Segment start time in seconds\"),\n end: z.number().describe(\"Segment end time in seconds\"),\n text: z.string().describe(\"Full segment text\"),\n words: z\n .array(\n z.object({\n word: z.string(),\n start: z.number(),\n end: z.number(),\n })\n )\n .optional()\n .describe(\"Per-word timestamps within the segment\"),\n })\n )\n .optional()\n .describe(\"Word-level captions from clipform_generate_tts. Always include when uploading narrated video - pass the full objects including 'words' so per-word highlighting works.\"),\n show_captions: z\n .boolean()\n .optional()\n .default(true)\n .describe(\"Display captions/subtitles on the question\"),\n});\n\nexport function registerUploadNodeMediaTool(server: McpServer) {\n server.registerTool(\n \"clipform_upload_node_media\",\n {\n title: \"Upload Node Media\",\n description: `Upload media for one or more nodes. Pass one item or many (max 10). Multiple items upload sequentially.\n\nWhen a public URL is provided, the media is fetched and stored automatically. Only works on node types that support media (choice, open, scale, button). For video: ingested via Mux. For image: stored in Supabase. When attaching TTS narration video, always include captions from clipform_generate_tts.`,\n inputSchema: {\n form_id: z\n .string()\n .uuid()\n .describe(\"The form UUID (returned by clipform_create_form, not the short share_id from the URL)\"),\n items: z\n .array(MediaItemSchema)\n .min(1)\n .max(10)\n .describe(\"One or more media items to upload\"),\n },\n annotations: {\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: true,\n },\n },\n async ({ form_id, items }) => {\n const lines: string[] = [];\n let successCount = 0;\n\n for (let i = 0; i < items.length; i++) {\n const item = items[i];\n if (items.length > 1) lines.push(`--- Item ${i + 1} (node ${item.node_id}) ---`);\n\n const body: Record<string, unknown> = {\n media_type: item.media_type,\n media_source: item.media_source,\n };\n if (item.url) body.url = item.url;\n if (item.captions) body.captions = item.captions;\n if (item.show_captions !== undefined) body.show_captions = item.show_captions;\n\n const result = await callApi(\n `/forms/${form_id}/nodes/${item.node_id}/media`,\n { method: \"POST\", body }\n );\n\n if (result.ok) {\n successCount++;\n const resultLines = [`Media ID: ${result.data.media_id}`];\n if (result.data.upload_url) {\n resultLines.push(\n `Upload URL: ${result.data.upload_url}`,\n `Upload method: ${result.data.upload_method}`,\n `Upload the file directly to the upload URL using ${result.data.upload_method === \"tus\" ? \"TUS resumable upload\" : \"HTTP PUT\"}.`\n );\n }\n if (item.captions) {\n resultLines.push(`Captions: ${item.captions.length} segments saved`);\n }\n lines.push(resultLines.join(\"\\n\"));\n } else {\n lines.push(`FAILED: ${result.error}`);\n }\n lines.push(\"\");\n }\n\n if (items.length > 1) {\n lines.unshift(`Media upload: ${successCount}/${items.length} succeeded\\n`);\n } else if (successCount > 0) {\n lines.unshift(`Media uploaded successfully.`);\n }\n\n if (successCount === 0) return errorResult(lines.join(\"\\n\"));\n return textResult(lines.join(\"\\n\"));\n }\n );\n}\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\nimport { callApi, errorResult, textResult } from \"../lib/api-client.js\";\n\nexport function registerGetNodeMediaTool(server: McpServer) {\n server.registerTool(\n \"clipform_get_node_media\",\n {\n title: \"Get Node Media\",\n description: `Get the media attached to a node, including processing status. Useful for checking if a video upload has finished processing.`,\n inputSchema: {\n form_id: z.string().uuid().describe(\"The form UUID (returned by clipform_create_form, not the short share_id from the URL)\"),\n node_id: z.string().describe(\"The node ID\"),\n },\n annotations: {\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: true,\n },\n },\n async ({ form_id, node_id }) => {\n const result = await callApi(\n `/forms/${form_id}/nodes/${node_id}/media`\n );\n\n if (!result.ok) {\n return errorResult(result.error);\n }\n\n const media = result.data.media as Record<string, unknown> | null;\n if (!media) {\n return textResult(\"No media attached to this node.\");\n }\n\n return textResult(\n `Media ID: ${media.id}\\n` +\n `Type: ${media.media_type}\\n` +\n `Status: ${media.status}\\n` +\n (media.playback_id ? `Playback ID: ${media.playback_id}\\n` : \"\") +\n (media.storage_path ? `Storage path: ${media.storage_path}\\n` : \"\") +\n (media.duration ? `Duration: ${media.duration}s\\n` : \"\") +\n `Transcription: ${media.transcription_status}`\n );\n }\n );\n}\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\nimport { callApi, errorResult, textResult } from \"../lib/api-client.js\";\n\nexport function registerDeleteNodeMediaTool(server: McpServer) {\n server.registerTool(\n \"clipform_delete_node_media\",\n {\n title: \"Delete Node Media\",\n description: `Remove media from a node. Deletes the media record and cleans up external resources (Mux video asset, storage file).`,\n inputSchema: {\n form_id: z.string().uuid().describe(\"The form UUID (returned by clipform_create_form, not the short share_id from the URL)\"),\n node_id: z.string().describe(\"The node ID\"),\n },\n annotations: {\n readOnlyHint: false,\n destructiveHint: true,\n idempotentHint: false,\n openWorldHint: true,\n },\n },\n async ({ form_id, node_id }) => {\n const result = await callApi(\n `/forms/${form_id}/nodes/${node_id}/media`,\n { method: \"DELETE\" }\n );\n\n if (!result.ok) {\n return errorResult(result.error);\n }\n\n return textResult(\"Media removed from node.\");\n }\n );\n}\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\nimport { callApi, errorResult, textResult } from \"../lib/api-client.js\";\nimport { fetchAndFormatFormState } from \"../lib/format-form.js\";\n\nconst LogicRuleSchema = z.object({\n option_content: z\n .string()\n .optional()\n .describe(\n \"The option text to match. Omit for a default rule (applies to all unmatched options).\"\n ),\n target_node_id: z\n .string()\n .describe(\"The node ID to jump to when this rule matches\"),\n});\n\nexport function registerSetNodeLogicTool(server: McpServer) {\n server.registerTool(\n \"clipform_set_logic\",\n {\n title: \"Set Node Logic\",\n description: `Set branching logic on a node. Routes respondents to different nodes based on their answer.\n\nEach rule maps an option (by its text content) to a target node. Rules without option_content are \"default\" rules applied to all unmatched options.\n\nExample: Route correct answer to a \"Well done\" node, everything else to \"Wrong\":\n rules: [\n { option_content: \"42\", target_node_id: \"well-done-id\" },\n { target_node_id: \"wrong-id\" }\n ]`,\n inputSchema: {\n form_id: z.string().uuid().describe(\"The form UUID (returned by clipform_create_form, not the short share_id from the URL)\"),\n node_id: z\n .string()\n .describe(\"The node ID to set logic on\"),\n rules: z\n .array(LogicRuleSchema)\n .min(1)\n .describe(\"Branching rules. Each maps an option or default to a target node.\"),\n },\n annotations: {\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: true,\n },\n },\n async ({ form_id, node_id, rules }) => {\n const result = await callApi(\n `/forms/${form_id}/nodes/${node_id}/logic`,\n {\n method: \"PUT\",\n body: { rules },\n }\n );\n\n if (!result.ok) {\n return errorResult(result.error);\n }\n\n const confirmMsg = `Logic set on node ${node_id}.\\nRules created: ${result.data.rules_count}`;\n const formState = await fetchAndFormatFormState(form_id);\n return textResult(formState ? `${confirmMsg}\\n\\n---\\n\\n${formState}` : confirmMsg);\n }\n );\n}\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\nimport { callApi, errorResult, textResult } from \"../lib/api-client.js\";\n\nexport function registerAttachNodeAudioTool(server: McpServer) {\n server.registerTool(\n \"clipform_attach_audio\",\n {\n title: \"Attach Audio to Node\",\n description: `Attach a sound effect or audio file to a node with existing media (stills only). The audio auto-plays once when a respondent reaches this node. Provide a public URL to the audio file (WAV, MP3, or OGG). The node must already have media uploaded (use clipform_upload_node_media first).`,\n inputSchema: {\n form_id: z.string().uuid().describe(\"The form UUID (returned by clipform_create_form, not the short share_id from the URL)\"),\n node_id: z\n .string()\n .describe(\"The node ID (must already have media attached)\"),\n url: z\n .string()\n .url()\n .describe(\"Public URL to the audio file (WAV, MP3, or OGG)\"),\n },\n annotations: {\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: true,\n },\n },\n async ({ form_id, node_id, url }) => {\n const result = await callApi(\n `/forms/${form_id}/nodes/${node_id}/audio`,\n {\n method: \"PUT\",\n body: { url },\n }\n );\n\n if (!result.ok) {\n return errorResult(result.error);\n }\n\n return textResult(\n `Audio attached to node ${node_id}.\\n` +\n `Audio path: ${result.data.audio_storage_path}`\n );\n }\n );\n}\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\nimport { callInternalApi, errorResult, textResult } from \"../lib/api-client.js\";\n\nexport function registerLogGenerationTool(server: McpServer) {\n server.registerTool(\n \"clipform_log_generation\",\n {\n title: \"Log Form Generation Audit\",\n description: `Save an audit trail for a generated form. Records where content came from - the sources and image attributions. Call this as the final step after building a form or quiz.`,\n inputSchema: {\n form_id: z.string().uuid().describe(\"The form ID (UUID format, not the share ID)\"),\n summary: z.string().describe(\"Short description of what was generated\"),\n details: z.object({\n sources: z.array(z.object({\n title: z.string(),\n url: z.string().optional(),\n type: z.string().optional(),\n })).optional().describe(\"Knowledge sources used\"),\n images: z.array(z.object({\n url: z.string(),\n attribution: z.string().optional(),\n license: z.string().optional(),\n })).optional().describe(\"Images used with attribution\"),\n }).describe(\"Content sources and attributions\"),\n },\n annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false },\n },\n async ({ form_id, summary, details }) => {\n const result = await callInternalApi(\"/internal/log-generation\", {\n body: { form_id, summary, details },\n });\n if (!result.ok) return errorResult(result.error);\n\n return textResult(`Audit log saved for form ${form_id}\\nSummary: ${summary}`);\n }\n );\n}\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\nimport { callInternalApi, errorResult, textResult } from \"../lib/api-client.js\";\n\nexport function registerSearchNewsTool(server: McpServer) {\n server.registerTool(\n \"clipform_search_news\",\n {\n title: \"Search News (fallback)\",\n description: `FALLBACK news lookup for clients without native web search. Returns structured current-news articles from NewsAPI and The Guardian.\n\nWHEN TO USE:\n- The user asks for a quiz about an event, person, or topic that is recent (post-May-2025) or that you are not confident you know accurately.\n- Your client does NOT already expose a native web search / web fetch tool. If it does (e.g. WebSearch in Claude Code, web search in Claude Desktop), prefer that - it is broader and more current than this tool.\n- You would otherwise be at risk of hallucinating facts.\n\nDO NOT USE for timeless topics you already know well (history, geography, science, general knowledge) - write those from your own knowledge, it is faster and the result is better.\n\nIf neither native web search nor this tool is available and the topic is post-cutoff or uncertain, REFUSE rather than fabricate.`,\n inputSchema: {\n query: z.string().describe(\"News search query (e.g. 'Iran war 2026', 'Australian Open final', 'UK election')\"),\n count: z.number().min(1).max(15).default(5).optional()\n .describe(\"Max results per provider (default 5)\"),\n },\n annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },\n },\n async ({ query, count }) => {\n const result = await callInternalApi(\"/internal/search-news\", {\n body: { query, count },\n });\n if (!result.ok) return errorResult(result.error);\n\n const results = (result.data as any).results as any[];\n if (!results.length) return textResult(`No news articles found for \"${query}\".`);\n\n const lines = [`Found ${results.length} articles for \"${query}\":\\n`];\n for (const article of results) {\n lines.push(`- [${article.source}] ${article.title}`);\n if (article.description) lines.push(` ${article.description}`);\n if (article.author) lines.push(` Author: ${article.author}`);\n lines.push(` Date: ${article.publishedAt}`);\n lines.push(` URL: ${article.url}`);\n if (article.imageUrl) lines.push(` Image: ${article.imageUrl}`);\n lines.push(\"\");\n }\n return textResult(lines.join(\"\\n\"));\n }\n );\n}\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\nimport { callInternalApi, errorResult, textResult } from \"../lib/api-client.js\";\n\nconst TtsItemSchema = z.object({\n text: z.string().min(1).max(5000).describe(\"Narration text\"),\n voice: z\n .enum([\"ryan\", \"sonia\", \"andrew\", \"ava\", \"guy\"])\n .optional()\n .default(\"ryan\")\n .describe(\"TTS voice (default: ryan)\"),\n});\n\nexport function registerGenerateTtsTool(server: McpServer) {\n server.registerTool(\n \"clipform_generate_tts\",\n {\n title: \"Generate Text-to-Speech\",\n description: `Generate narration audio from text using Edge TTS (free) with ElevenLabs fallback. Pass one item or many (max 10) - multiple items run in parallel.\n\nWorkflow:\n1. Generate TTS audio with this tool\n2. Search for images with clipform_search_media (kind: \"image\")\n3. Create a slideshow with clipform_generate_slideshow (pass the audio URL + image URLs)\n4. Attach the video to a node with clipform_upload_node_media\n\nAvailable voices: ryan (British male, default), sonia (British female), andrew (American male), ava (American female), guy (American male casual).\n\nReturns audio URL and word-level captions per item.`,\n inputSchema: {\n items: z\n .array(TtsItemSchema)\n .min(1)\n .max(10)\n .describe(\"One or more TTS items to generate\"),\n },\n annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true },\n },\n async ({ items }) => {\n const workspace_id = process.env.MCP_WORKSPACE_ID;\n\n const results = await Promise.allSettled(\n items.map((item) =>\n callInternalApi(\"/internal/tts\", {\n body: { text: item.text, voice: item.voice, workspace_id },\n })\n )\n );\n\n const lines: string[] = [];\n let successCount = 0;\n\n for (let i = 0; i < results.length; i++) {\n const r = results[i];\n if (items.length > 1) lines.push(`--- Item ${i + 1} ---`);\n\n if (r.status === \"fulfilled\" && r.value.ok) {\n successCount++;\n const data = r.value.data as Record<string, unknown>;\n lines.push(`Voice: ${data.voice}`);\n lines.push(`Audio URL: ${data.audioUrl}`);\n lines.push(`Storage path: ${data.storagePath}`);\n lines.push(`Captions: ${JSON.stringify(data.captions)}`);\n } else {\n const error =\n r.status === \"rejected\"\n ? r.reason?.message || String(r.reason)\n : (r.value as { error: string; status: number }).error;\n const status =\n r.status === \"fulfilled\" ? (r.value as { status: number }).status : 0;\n const hint =\n status === 500 || status === 0\n ? \" (transient - retrying may help)\"\n : \"\";\n lines.push(`FAILED: ${error}${hint}`);\n }\n lines.push(\"\");\n }\n\n if (items.length > 1) {\n lines.unshift(`TTS: ${successCount}/${items.length} succeeded\\n`);\n }\n\n lines.push(\n `IMPORTANT: When uploading the final video with clipform_upload_node_media, pass the COMPLETE Captions JSON above as the \"captions\" parameter — including the \"words\" arrays inside each segment. Do NOT strip or simplify the JSON. The viewer needs word-level timing data to display captions.`\n );\n\n if (successCount === 0) return errorResult(lines.join(\"\\n\"));\n return textResult(lines.join(\"\\n\"));\n }\n );\n}\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\nimport { callInternalApi, errorResult, textResult } from \"../lib/api-client.js\";\nimport { createJob, completeJob, failJob, RENDER_TIMING } from \"../lib/render-jobs.js\";\n\n// Style knobs - mirror packages/remotion/src/compositions/slideshow/KenBurnsImage.tsx.\n// Every field optional; unset fields fall back to library defaults (which shift\n// automatically between 'cover' and 'blur-pad' fit modes).\nconst slideshowStyleSchema = z.object({\n preset: z.enum([\"cinematic\", \"dramatic\", \"calm\", \"documentary\", \"dreamy\", \"moody\"]).optional().describe(\"Named shortcut applied before per-field overrides. cinematic = defaults; dramatic = big zoom, wider pan, ease-out, stronger vignette; calm = minimal motion, linear, no vignette; documentary = near-static, no pan; dreamy = bright heavy blur-pad, soft vignette, gentle zoom; moody = desaturated low-key blur-pad, strong vignette. Set any other field to override individual knobs on top of the preset.\"),\n zoom: z.object({\n from: z.number().optional().describe(\"Starting scale for zoom-in / ending scale for zoom-out. Default 1.0.\"),\n to: z.number().optional().describe(\"Ending scale for zoom-in / starting scale for zoom-out. Default 1.3 (cover) / 1.15 (blur-pad).\"),\n }).optional().describe(\"Zoom range. Lower 'to' (e.g. 1.05) for near-static cinematography; higher (e.g. 1.4) for dramatic push-in.\"),\n pan: z.object({\n range: z.number().optional().describe(\"Pan drift as fraction of viewport on each side. Default 0.05 (cover) / 0.03 (blur-pad). 0.08+ feels like sweeping.\"),\n scale: z.number().optional().describe(\"Baseline scale during pan effects. Must exceed 1 + 2×range so edges never show. Default 1.12 / 1.08.\"),\n }).optional(),\n zoomPan: z.object({\n from: z.number().optional(),\n to: z.number().optional(),\n rangeFraction: z.number().optional().describe(\"Multiplier on pan.range for zoom-in-pan-* effects. Default 0.5.\"),\n }).optional(),\n easing: z.enum([\"ease-in-out\", \"ease-in\", \"ease-out\", \"linear\"]).optional().describe(\"Motion curve. 'ease-in-out' = cinematic default. 'linear' = mechanical/deliberate. 'ease-out' = fast-start slow-finish, good for reveals.\"),\n blurPad: z.object({\n blurPx: z.number().optional().describe(\"Blur strength on the background layer. Default 40. 60+ for heavy dreamy effect, 20 for just-barely.\"),\n brightness: z.number().optional().describe(\"Background brightness multiplier. Default 0.55 (dimmed). Raise to 0.8+ for a brighter bed; lower for moodier.\"),\n saturate: z.number().optional().describe(\"Background saturation. Default 1.15. Lower (0.6) for desaturated/muted bg; higher for vivid.\"),\n overscale: z.number().optional().describe(\"Background overscale to hide blur edges. Default 1.12.\"),\n foregroundScale: z.number().optional().describe(\"Gentle crop on the contain-fit sharp layer. Default 1.0 (pure contain). 1.2 reduces letterbox by accepting mild crop.\"),\n }).optional().describe(\"Styling for the blurred-letterbox layer. Only applies when fit resolves to 'blur-pad' (landscape source in portrait viewport).\"),\n vignette: z.union([\n z.literal(false),\n z.object({\n opacity: z.number().optional().describe(\"Edge darkness opacity, 0-1. Default 0.35 (cover) / 0.4 (blur-pad).\"),\n innerRadiusPercent: z.number().optional().describe(\"Where darkening starts, 0 = center, 100 = edge. Default 50-55.\"),\n }),\n ]).optional().describe(\"Edge darkening for cinematic framing. Pass false to disable.\"),\n backgroundColor: z.string().optional().describe(\"Hex color behind the image frame. Default '#000'.\"),\n autoBlurPadThreshold: z.number().optional().describe(\"When fit='auto', trigger blur-pad if aspectRatio > this value. Default 1.1.\"),\n}).describe(\"Creative style overrides. Every field optional - unset inherits defaults.\");\n\nexport function registerGenerateSlideshowTool(server: McpServer) {\n server.registerTool(\n \"clipform_generate_slideshow\",\n {\n title: \"Generate Slideshow\",\n description: `**Deprecated: prefer clipform_generate_video** which supports both images and video clips.\n\nGenerate a slideshow video from images and audio. Creates a 9:16 (720x1280) video with smooth pan/zoom effects (Ken Burns style), eased motion, and crossfade transitions, synced to the audio duration. Uploaded to storage; returns a public URL.\n\nYou are the director. Every stylistic choice below is yours - defaults exist for convenience but override anything that fits your creative vision.\n\n## Workflow\n\n1. Source images (use clipform_search_media with kind: \"image\"). Prefer portrait sources for 9:16 output; landscape works too via blur-pad fallback.\n2. Produce narration audio (clipform_generate_tts).\n3. Call this tool with images + audio_url + your creative direction.\n4. Attach the returned public URL to a question via clipform_upload_media with media_type \"video\".\n\n## Image framing (per-image)\n\n- **aspect_ratio** (width/height): pass through from the image source so the composition can auto-pick framing. Landscape images with no aspect_ratio will cover-crop and may pixelate.\n- **fit**: 'cover' (fill frame, crop), 'blur-pad' (sharp contained foreground + blurred cover background for landscape sources), 'auto' (default: cover for portrait, blur-pad for landscape > 1.1:1).\n- **style**: per-image creative overrides (see Style Knobs below).\n\n## Effects\n\nzoom-in, zoom-out, pan-left, pan-right, pan-up, pan-down, zoom-in-pan-left, zoom-in-pan-right, random, static. Set 'random' or pass random_effects: true to shuffle per image.\n\n## Transitions\n\nfade (default), slide, wipe. Legacy names (fadeblack, slideleft, etc.) also work. duration is in seconds.\n\n## Style presets (fastest path)\n\nPick one as a starting point via \\`style.preset\\` (per-image) or \\`default_style.preset\\` (global). Override individual knobs on top.\n\n- **cinematic** - the default feel. Smooth ease-in-out, zoom 1.0→1.3, subtle pan, subtle vignette.\n- **dramatic** - zoom 1.0→1.4, ease-out, wider pan (0.07), strong vignette. Good for big-reveal content, competitions, climactic moments.\n- **calm** - zoom 1.0→1.08, linear easing, no vignette. Reflective topics, wellness, educational explainers.\n- **documentary** - near-static (zoom 1.0→1.05, tiny pan, no vignette). Talking-heads-style context shots, historical photos.\n- **dreamy** - heavy blur-pad (blurPx 60, brightness 0.75), soft vignette. Aspirational, romantic, nostalgic.\n- **moody** - desaturated blur-pad (brightness 0.35, saturate 0.7), strong vignette, dark wrapper color. Crime, mystery, somber topics.\n\nPer-image preset wins over default_style preset. Per-field overrides (zoom, pan, etc.) merge on top of whichever preset is active.\n\n## Style Knobs (per-image via images[i].style, or global via default_style)\n\n- **zoom**: { from, to } - push-in/pull-out range. Cinematic default 1.0→1.3. Drop to 1.0→1.05 for near-static; push to 1.0→1.4 for dramatic.\n- **pan**: { range, scale } - drift magnitude. 0.03 subtle, 0.05 default, 0.08+ sweeping.\n- **easing**: 'ease-in-out' (default, cinematic) | 'ease-in' (accelerate) | 'ease-out' (decelerate, good for reveals) | 'linear' (mechanical).\n- **blurPad**: { blurPx, brightness, saturate, overscale, foregroundScale } - only applies when blur-pad fit is active. Heavier blurPx (60) + lower brightness (0.35) for moody; foregroundScale: 1.2 to reduce letterbox at the cost of mild crop.\n- **vignette**: false to disable, or { opacity, innerRadiusPercent }. Stronger vignette (opacity 0.6) for dramatic focus; disable for bright, flat looks.\n- **backgroundColor**: hex color shown behind the image frame (default '#000').\n- **autoBlurPadThreshold**: when fit='auto', images wider than this ratio get blur-pad. Default 1.1.\n\n## Global options\n\n- **default_style**: style applied to every image unless the image overrides per-field. Per-image style merges over default_style at the field level.\n- **background_color**: viewport wrapper color, visible during cross-fades.\n- **random_effects**: shuffles effects across images when true.\n\n## Creative guidance\n\n- For the same 5-image quiz slideshow, vary the effects (one zoom-in on the opener, pan-left on a cityscape, zoom-out on the closer) rather than random_effects: true, unless you want the dice-roll.\n- Quiet/reflective topics: slow easing ('linear'), tight zoom (1.0→1.08), no vignette.\n- Energetic topics: punchy zoom (1.0→1.35), ease-out, wider pan.\n- Mixed orientation sets: rely on fit: 'auto' + pass aspect_ratio per image. The composition will cover-crop portraits and blur-pad landscapes without more work.`,\n inputSchema: {\n images: z.array(\n z.object({\n url: z.string().url().describe(\"Image URL\"),\n effect: z.string().optional().describe(\"Ken Burns effect name (see description). Pass 'random' to shuffle this image only.\"),\n aspect_ratio: z.number().positive().optional().describe(\"Source image width / height. Enables auto blur-pad for landscape images in the 9:16 viewport.\"),\n fit: z.enum([\"cover\", \"blur-pad\", \"auto\"]).optional().describe(\"Framing mode. 'auto' (default) picks cover for portrait, blur-pad for landscape.\"),\n style: slideshowStyleSchema.optional(),\n })\n ).min(1).max(20).describe(\"Images for the slideshow (1-20)\"),\n audio_url: z.string().url().describe(\"URL of the audio track (mp3/wav). Slideshow duration matches audio duration.\"),\n random_effects: z.boolean().optional().default(true).describe(\"Shuffle effects across all images (default: true). Set false when specifying effects explicitly per-image.\"),\n transition: z.object({\n type: z.string().optional().default(\"fade\").describe(\"Transition type: fade (default), slide, wipe.\"),\n duration: z.number().optional().default(1).describe(\"Transition duration in seconds (default: 1).\"),\n }).optional().describe(\"Transition between images.\"),\n default_style: slideshowStyleSchema.optional().describe(\"Style applied to every image unless overridden per-image.\"),\n background_color: z.string().optional().describe(\"Viewport background color behind all images (default '#000').\"),\n },\n annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true },\n },\n async ({ images, audio_url, random_effects, transition, default_style, background_color }) => {\n const workspace_id = process.env.MCP_WORKSPACE_ID;\n const job = createJob(\"clipform_generate_slideshow\");\n\n callInternalApi(\"/internal/slideshow\", {\n body: {\n images,\n audio_url,\n random_effects: random_effects ?? true,\n transition: transition ?? { type: \"fade\", duration: 1 },\n default_style,\n background_color,\n workspace_id,\n },\n }).then((result) => {\n if (!result.ok) {\n failJob(job.id, result.error);\n } else {\n completeJob(job.id, result.data);\n }\n }).catch((err) => {\n failJob(job.id, err instanceof Error ? err.message : String(err));\n });\n\n return textResult(\n [\n `Slideshow render started (${images.length} image${images.length > 1 ? \"s\" : \"\"}).`,\n ``,\n `Job ID: ${job.id}`,\n ``,\n `Renders typically take ${RENDER_TIMING.expectedRange}. Use clipform_check_render with this job ID to check status.`,\n ].join(\"\\n\")\n );\n }\n );\n}\n","import validate from './validate.js';\nconst byteToHex = [];\nfor (let i = 0; i < 256; ++i) {\n byteToHex.push((i + 0x100).toString(16).slice(1));\n}\nexport function unsafeStringify(arr, offset = 0) {\n return (byteToHex[arr[offset + 0]] +\n byteToHex[arr[offset + 1]] +\n byteToHex[arr[offset + 2]] +\n byteToHex[arr[offset + 3]] +\n '-' +\n byteToHex[arr[offset + 4]] +\n byteToHex[arr[offset + 5]] +\n '-' +\n byteToHex[arr[offset + 6]] +\n byteToHex[arr[offset + 7]] +\n '-' +\n byteToHex[arr[offset + 8]] +\n byteToHex[arr[offset + 9]] +\n '-' +\n byteToHex[arr[offset + 10]] +\n byteToHex[arr[offset + 11]] +\n byteToHex[arr[offset + 12]] +\n byteToHex[arr[offset + 13]] +\n byteToHex[arr[offset + 14]] +\n byteToHex[arr[offset + 15]]).toLowerCase();\n}\nfunction stringify(arr, offset = 0) {\n const uuid = unsafeStringify(arr, offset);\n if (!validate(uuid)) {\n throw TypeError('Stringified UUID is invalid');\n }\n return uuid;\n}\nexport default stringify;\n","import { randomFillSync } from 'crypto';\nconst rnds8Pool = new Uint8Array(256);\nlet poolPtr = rnds8Pool.length;\nexport default function rng() {\n if (poolPtr > rnds8Pool.length - 16) {\n randomFillSync(rnds8Pool);\n poolPtr = 0;\n }\n return rnds8Pool.slice(poolPtr, (poolPtr += 16));\n}\n","import { randomUUID } from 'crypto';\nexport default { randomUUID };\n","import native from './native.js';\nimport rng from './rng.js';\nimport { unsafeStringify } from './stringify.js';\nfunction v4(options, buf, offset) {\n if (native.randomUUID && !buf && !options) {\n return native.randomUUID();\n }\n options = options || {};\n const rnds = options.random ?? options.rng?.() ?? rng();\n if (rnds.length < 16) {\n throw new Error('Random bytes length must be >= 16');\n }\n rnds[6] = (rnds[6] & 0x0f) | 0x40;\n rnds[8] = (rnds[8] & 0x3f) | 0x80;\n if (buf) {\n offset = offset || 0;\n if (offset < 0 || offset + 16 > buf.length) {\n throw new RangeError(`UUID byte range ${offset}:${offset + 15} is out of buffer bounds`);\n }\n for (let i = 0; i < 16; ++i) {\n buf[offset + i] = rnds[i];\n }\n return buf;\n }\n return unsafeStringify(rnds);\n}\nexport default v4;\n","import { v4 as uuidv4 } from \"uuid\";\n\nexport interface RenderJob {\n id: string;\n status: \"rendering\" | \"complete\" | \"failed\";\n tool: string;\n createdAt: number;\n result?: Record<string, unknown>;\n error?: string;\n}\n\nconst jobs = new Map<string, RenderJob>();\n\nconst MAX_AGE_MS = 30 * 60 * 1000; // 30 minutes\n\n// Keep in sync with apps/api/src/lib/remotion/render-lambda.ts (framesPerLambda).\n// With framesPerLambda=20 and 1000 concurrent Lambdas, renders finish in ~15-45s.\nexport const RENDER_TIMING = {\n expectedRange: \"15-45 seconds\",\n pollDelay: \"~10 seconds\",\n} as const;\n\nexport function createJob(tool: string): RenderJob {\n const job: RenderJob = {\n id: uuidv4(),\n status: \"rendering\",\n tool,\n createdAt: Date.now(),\n };\n jobs.set(job.id, job);\n return job;\n}\n\nexport function completeJob(id: string, result: Record<string, unknown>): void {\n const job = jobs.get(id);\n if (job) {\n job.status = \"complete\";\n job.result = result;\n }\n}\n\nexport function failJob(id: string, error: string): void {\n const job = jobs.get(id);\n if (job) {\n job.status = \"failed\";\n job.error = error;\n }\n}\n\nexport function getJob(id: string): RenderJob | undefined {\n return jobs.get(id);\n}\n\nexport function pruneJobs(): void {\n const cutoff = Date.now() - MAX_AGE_MS;\n for (const [id, job] of jobs) {\n if (job.createdAt < cutoff) jobs.delete(id);\n }\n}\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\nimport { callInternalApi, errorResult, textResult } from \"../lib/api-client.js\";\n\nexport function registerSearchMediaTool(server: McpServer) {\n server.registerTool(\n \"clipform_search_media\",\n {\n title: \"Search Media\",\n description: `Search royalty-free images or stock video clips to attach to a node. Routes across Pexels, Unsplash, Pixabay, Wikimedia, NASA, and iNaturalist for images; Pexels and Pixabay for video. The router picks relevant providers based on the topic (space → NASA, nature → iNaturalist, general → stock libraries). Returns URLs you can pass to clipform_upload_node_media or clipform_generate_slideshow.`,\n inputSchema: {\n query: z.string().describe(\"What to search for (e.g. 'african lion', 'saturn rings', 'city timelapse')\"),\n kind: z.enum([\"image\", \"video\"]).describe(\"image = stock photos, video = stock clips\"),\n count: z.number().min(1).max(20).default(6).optional()\n .describe(\"Max results per provider (default 6 for image, 3 for video)\"),\n },\n annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },\n },\n async ({ query, kind, count }) => {\n const result = await callInternalApi(\"/internal/search-media\", {\n body: { query, kind, count },\n });\n if (!result.ok) return errorResult(result.error);\n\n const results = (result.data as any).results as any[];\n if (!results.length) return textResult(`No ${kind}s found for \"${query}\".`);\n\n const lines = [`Found ${results.length} ${kind}s for \"${query}\":\\n`];\n for (const item of results.slice(0, 15)) {\n lines.push(`- [${item.source}] ${item.title}`);\n lines.push(` URL: ${item.url}`);\n if (item.width && item.height) lines.push(` Size: ${item.width}x${item.height}`);\n if (kind === \"video\" && item.duration) lines.push(` Duration: ${item.duration}s`);\n if (item.attribution) lines.push(` Attribution: ${item.attribution}`);\n if (item.license) lines.push(` License: ${item.license}`);\n lines.push(\"\");\n }\n return textResult(lines.join(\"\\n\"));\n }\n );\n}\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\nimport { callInternalApi, errorResult, textResult } from \"../lib/api-client.js\";\nimport { createJob, completeJob, failJob, RENDER_TIMING } from \"../lib/render-jobs.js\";\n\nexport function registerRenderCompositionTool(server: McpServer) {\n server.registerTool(\n \"clipform_render_composition\",\n {\n title: \"Render Composition\",\n description: `Render a Remotion composition to MP4, PNG, or GIF. MP4 renders use AWS Lambda in production for fast, scalable rendering. PNG and GIF render locally.\n\nOutput formats:\n- mp4: Video file (H.264 codec, best for social media)\n- png: Still image (single frame)\n- gif: Animated GIF (looping)\n\nFor narrated quiz slideshows, prefer clipform_generate_slideshow which handles the full workflow (focal point detection, audio sync, storage upload). Use this tool for custom compositions like ScorecardQuiz, ShortFormQuiz, or PresenterDirected.`,\n inputSchema: {\n compositionId: z.string().describe(\"The composition ID (e.g. 'ScorecardQuiz', 'ShortFormQuiz', 'PresenterDirected')\"),\n outputFormat: z.enum([\"mp4\", \"png\", \"gif\"]).default(\"mp4\").describe(\"Output format (default: mp4)\"),\n inputProps: z.record(z.unknown()).optional().describe(\"Props object matching the composition's expected schema\"),\n },\n annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false },\n },\n async ({ compositionId, outputFormat, inputProps }) => {\n const job = createJob(\"clipform_render_composition\");\n\n callInternalApi(\"/internal/render\", {\n body: {\n compositionId,\n outputFormat,\n inputProps: inputProps ?? {},\n },\n }).then((result) => {\n if (!result.ok) {\n failJob(job.id, result.error);\n } else {\n completeJob(job.id, result.data);\n }\n }).catch((err) => {\n failJob(job.id, err instanceof Error ? err.message : String(err));\n });\n\n return textResult(\n [\n `Render started.`,\n ``,\n `Composition: ${compositionId}`,\n `Format: ${outputFormat}`,\n `Job ID: ${job.id}`,\n ``,\n `Renders typically take ${RENDER_TIMING.expectedRange}. Use clipform_check_render with this job ID to check status.`,\n ].join(\"\\n\")\n );\n }\n );\n}\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\nimport { callInternalApi, errorResult, textResult } from \"../lib/api-client.js\";\n\nexport function registerSearchMusicTool(server: McpServer) {\n server.registerTool(\n \"clipform_search_music\",\n {\n title: \"Search Music\",\n description: `Search for royalty-free music tracks and ambient sounds via Jamendo and Freesound. Returns download URLs for background music, quiz soundtracks, or ambient audio.`,\n inputSchema: {\n query: z.string().describe(\"What to search for (e.g. 'upbeat quiz background', 'calm ambient', 'playful pizzicato')\"),\n count: z.number().min(1).max(10).default(5).optional().describe(\"Max results (default: 5)\"),\n instrumentalOnly: z.boolean().optional().default(true).describe(\"Only instrumental tracks (default: true)\"),\n minDuration: z.number().optional().describe(\"Minimum duration in seconds\"),\n maxDuration: z.number().optional().describe(\"Maximum duration in seconds\"),\n tags: z.array(z.string()).optional().describe(\"Genre/mood tags to filter by\"),\n },\n annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },\n },\n async ({ query, count, instrumentalOnly, minDuration, maxDuration, tags }) => {\n const result = await callInternalApi(\"/internal/search-music\", {\n body: { query, count, instrumentalOnly, minDuration, maxDuration, tags },\n });\n if (!result.ok) return errorResult(result.error);\n\n const results = (result.data as any).results as any[];\n if (!results.length) return textResult(`No music found for \"${query}\".`);\n\n const lines = [`Found ${results.length} tracks for \"${query}\":\\n`];\n for (const item of results) {\n lines.push(`- ${item.title} by ${item.artist}`);\n lines.push(` URL: ${item.url}`);\n if (item.duration) lines.push(` Duration: ${item.duration}s`);\n if (item.source) lines.push(` Source: ${item.source}`);\n if (item.license) lines.push(` License: ${item.license}`);\n lines.push(\"\");\n }\n return textResult(lines.join(\"\\n\"));\n }\n );\n}\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { callInternalApi, errorResult, textResult } from \"../lib/api-client.js\";\n\nexport function registerListCompositionsTool(server: McpServer) {\n server.registerTool(\n \"clipform_list_compositions\",\n {\n title: \"List Compositions\",\n description: `List all available Remotion compositions and their expected props schemas. Use clipform_render_composition to render them.`,\n inputSchema: {},\n annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },\n },\n async () => {\n const result = await callInternalApi(\"/internal/compositions\", {\n method: \"GET\",\n });\n\n if (!result.ok) {\n if (result.status === 0 || result.status === 404) {\n return errorResult(\"Remotion compositions are not available (API server may not be running). Start the API with 'npm run dev --workspace=apps/api'.\");\n }\n return errorResult(result.error);\n }\n\n const compositions = (result.data as any).compositions as any[];\n if (!compositions.length) return textResult(\"No compositions found.\");\n\n const lines = [`Available compositions (${compositions.length}):\\n`];\n for (const comp of compositions) {\n lines.push(`## ${comp.id}`);\n lines.push(` Duration: ${comp.durationInFrames} frames @ ${comp.fps}fps (${(comp.durationInFrames / comp.fps).toFixed(1)}s)`);\n lines.push(` Size: ${comp.width}x${comp.height}`);\n if (comp.defaultProps) {\n lines.push(` Default props: ${JSON.stringify(comp.defaultProps, null, 2)}`);\n }\n lines.push(\"\");\n }\n return textResult(lines.join(\"\\n\"));\n }\n );\n}\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\nimport { callInternalApi, errorResult, textResult } from \"../lib/api-client.js\";\n\nexport function registerListAssetsTool(server: McpServer) {\n server.registerTool(\n \"clipform_list_assets\",\n {\n title: \"List Assets\",\n description: `List available creative assets (sound effects, animations, fonts). Use this to discover what assets are available for use in compositions.`,\n inputSchema: {\n type: z.enum([\"sfx\", \"animation\", \"font\", \"all\"]).default(\"all\").optional()\n .describe(\"Asset type to list (default: all)\"),\n },\n annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },\n },\n async ({ type }) => {\n const result = await callInternalApi(\"/internal/assets\", {\n method: \"GET\",\n params: { type: type ?? \"all\" },\n });\n if (!result.ok) return errorResult(result.error);\n\n const data = result.data as any;\n const lines: string[] = [];\n\n if (data.sfx?.length) {\n lines.push(`## Sound Effects (${data.sfx.length})\\n`);\n for (const sfx of data.sfx) {\n lines.push(`- ${sfx.name}: ${sfx.description || sfx.path}`);\n }\n lines.push(\"\");\n }\n\n if (data.animations?.length) {\n lines.push(`## Animations (${data.animations.length})\\n`);\n for (const anim of data.animations) {\n lines.push(`- ${anim.name}: ${anim.description || anim.path}`);\n }\n lines.push(\"\");\n }\n\n if (data.fonts?.length) {\n lines.push(`## Fonts (${data.fonts.length})\\n`);\n for (const font of data.fonts) {\n lines.push(`- ${font.name}: weights ${font.weights?.join(\", \") || \"default\"}`);\n }\n lines.push(\"\");\n }\n\n return textResult(lines.length ? lines.join(\"\\n\") : \"No assets found.\");\n }\n );\n}\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\nimport { callInternalApi, errorResult, textResult } from \"../lib/api-client.js\";\nimport { createJob, completeJob, failJob, RENDER_TIMING } from \"../lib/render-jobs.js\";\n\nconst slideshowStyleSchema = z.object({\n preset: z.enum([\"cinematic\", \"dramatic\", \"calm\", \"documentary\", \"dreamy\", \"moody\"]).optional(),\n zoom: z.object({ from: z.number().optional(), to: z.number().optional() }).optional(),\n pan: z.object({ range: z.number().optional(), scale: z.number().optional() }).optional(),\n zoomPan: z.object({\n from: z.number().optional(), to: z.number().optional(), rangeFraction: z.number().optional(),\n }).optional(),\n easing: z.enum([\"ease-in-out\", \"ease-in\", \"ease-out\", \"linear\"]).optional(),\n blurPad: z.object({\n blurPx: z.number().optional(), brightness: z.number().optional(),\n saturate: z.number().optional(), overscale: z.number().optional(),\n foregroundScale: z.number().optional(),\n }).optional(),\n vignette: z.union([\n z.literal(false),\n z.object({ opacity: z.number().optional(), innerRadiusPercent: z.number().optional() }),\n ]).optional(),\n backgroundColor: z.string().optional(),\n autoBlurPadThreshold: z.number().optional(),\n});\n\nexport function registerGenerateVideoTool(server: McpServer) {\n server.registerTool(\n \"clipform_generate_video\",\n {\n title: \"Generate Video\",\n description: `Generate a video from images, video clips, or a mix of both, synced to audio. Creates a 9:16 (720x1280) video with transitions, uploaded to storage. Returns a public URL.\n\n## Workflow\n\n1. Source media with clipform_search_media (kind: \"image\" or \"video\")\n2. Source audio with clipform_generate_tts (narration) or clipform_search_music (background)\n3. Call this tool with items + audio_url\n4. Attach the returned URL to a node via clipform_upload_node_media with media_type \"video\"\n\n## Items\n\nEach item is an image or video clip:\n- **type: \"image\"** - still image with Ken Burns motion (pan/zoom). Supports effect, fit, and style overrides.\n- **type: \"video\"** - video clip, cover-cropped to fill 9:16 frame. Audio muted by default (set volume: 1 to mix in). Use start_from to trim.\n\n## Style presets (image items)\n\nPick one via default_style.preset (all images) or per-image style.preset:\n- **cinematic** (default) - smooth ease-in-out, subtle zoom/pan, subtle vignette\n- **dramatic** - big zoom, wide pan, ease-out, strong vignette. Reveals, climactic moments.\n- **calm** - minimal motion, linear easing, no vignette. Educational, reflective.\n- **documentary** - near-static, tiny pan, no vignette. Historical photos, talking-heads context.\n- **dreamy** - heavy blur-pad, soft vignette. Aspirational, nostalgic.\n- **moody** - desaturated, dark, strong vignette. Mystery, somber.\n\n## Effects (image items)\n\nzoom-in, zoom-out, pan-left, pan-right, pan-up, pan-down, zoom-in-pan-left, zoom-in-pan-right, random, static.\nSet per-image or use random_effects: true to shuffle.\n\n## Transitions\n\nfade (default), slide, wipe, none. Duration in seconds.\n\n## Duration\n\nMatches audio when audio_url is provided. Use duration_seconds for videos without audio.`,\n inputSchema: {\n items: z.array(\n z.object({\n type: z.enum([\"image\", \"video\"]).describe(\"'image' for still images with Ken Burns effects, 'video' for video clips\"),\n url: z.string().url().describe(\"Media URL\"),\n effect: z.string().optional().describe(\"Ken Burns effect (image only): zoom-in, zoom-out, pan-left, pan-right, pan-up, pan-down, zoom-in-pan-left, zoom-in-pan-right, random, static\"),\n aspect_ratio: z.number().positive().optional().describe(\"Image width/height ratio (image only). Enables auto blur-pad for landscape images.\"),\n fit: z.enum([\"cover\", \"blur-pad\", \"auto\"]).optional().describe(\"Framing mode (image only). auto = cover for portrait, blur-pad for landscape.\"),\n style: slideshowStyleSchema.optional().describe(\"Creative style overrides (image only)\"),\n start_from: z.number().min(0).optional().describe(\"Start time in seconds (video only). Trims the clip.\"),\n volume: z.number().min(0).max(1).optional().describe(\"Clip audio volume 0-1 (video only, default 0 = muted)\"),\n })\n ).min(1).max(20).describe(\"Media items (images, video clips, or a mix)\"),\n audio_url: z.string().url().optional().describe(\"Audio track URL. Video duration matches audio duration.\"),\n duration_seconds: z.number().positive().optional().describe(\"Video duration in seconds (required if no audio_url)\"),\n random_effects: z.boolean().optional().default(true).describe(\"Shuffle Ken Burns effects across image items (default: true)\"),\n transition: z.object({\n type: z.string().optional().default(\"fade\").describe(\"Transition: fade (default), slide, wipe, none\"),\n duration: z.number().optional().default(1).describe(\"Transition duration in seconds (default: 1)\"),\n }).optional(),\n default_style: slideshowStyleSchema.optional().describe(\"Style applied to all image items unless overridden per-item\"),\n background_color: z.string().optional().describe(\"Background color (default '#000')\"),\n },\n annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true },\n },\n async ({ items, audio_url, duration_seconds, random_effects, transition, default_style, background_color }) => {\n const workspace_id = process.env.MCP_WORKSPACE_ID;\n const job = createJob(\"clipform_generate_video\");\n\n callInternalApi(\"/internal/generate-video\", {\n body: {\n items,\n audio_url,\n duration_seconds,\n random_effects: random_effects ?? true,\n transition: transition ?? { type: \"fade\", duration: 1 },\n default_style,\n background_color,\n workspace_id,\n },\n }).then((result) => {\n if (!result.ok) {\n failJob(job.id, result.error);\n } else {\n completeJob(job.id, result.data);\n }\n }).catch((err) => {\n failJob(job.id, err instanceof Error ? err.message : String(err));\n });\n\n return textResult(\n [\n `Render started (${items.length} item${items.length > 1 ? \"s\" : \"\"}).`,\n ``,\n `Job ID: ${job.id}`,\n ``,\n `Renders typically take ${RENDER_TIMING.expectedRange}. Use clipform_check_render with this job ID to check status.`,\n ].join(\"\\n\")\n );\n }\n );\n}\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\nimport { errorResult, textResult } from \"../lib/api-client.js\";\nimport { getJob, pruneJobs, RENDER_TIMING } from \"../lib/render-jobs.js\";\n\nexport function registerCheckRenderTool(server: McpServer) {\n server.registerTool(\n \"clipform_check_render\",\n {\n title: \"Check Render Status\",\n description: `Check the status of a render job started by clipform_generate_video, clipform_generate_slideshow, or clipform_render_composition.\n\nReturns the current status and, when complete, the output URL. If still rendering, wait ${RENDER_TIMING.pollDelay} before checking again.`,\n inputSchema: {\n job_id: z.string().uuid().describe(\"The job ID returned by the render tool\"),\n },\n annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },\n },\n async ({ job_id }) => {\n pruneJobs();\n const job = getJob(job_id);\n\n if (!job) {\n return errorResult(`No render job found with ID ${job_id}. Jobs expire after 30 minutes.`);\n }\n\n if (job.status === \"rendering\") {\n const elapsed = Math.round((Date.now() - job.createdAt) / 1000);\n return textResult(\n [\n `Status: rendering (${elapsed}s elapsed)`,\n `Tool: ${job.tool}`,\n ``,\n `Still in progress. Check again in ${RENDER_TIMING.pollDelay}.`,\n ].join(\"\\n\")\n );\n }\n\n if (job.status === \"failed\") {\n return errorResult(`Render failed: ${job.error}`);\n }\n\n const data = job.result as any;\n return textResult(\n [\n `Status: complete`,\n `Tool: ${job.tool}`,\n ``,\n ...(data.public_url ? [`Public URL: ${data.public_url}`] : []),\n ...(data.storage_path ? [`Storage path: ${data.storage_path}`] : []),\n ...(data.duration_seconds ? [`Duration: ${data.duration_seconds}s`] : []),\n ...(data.outputPath ? [`Output: ${data.outputPath}`] : []),\n ...(data.format ? [`Format: ${data.format}`] : []),\n ``,\n `Use clipform_upload_node_media with the public URL to attach this video to a node.`,\n ].join(\"\\n\")\n );\n }\n );\n}\n","import { BUSINESS } from \"@vid-master/config\";\nimport { callApi } from \"./api-client.js\";\n\nexport async function getSessionContext(): Promise<string> {\n const result = await callApi(\"/me\", { method: \"GET\" });\n if (!result.ok) return \"\";\n\n const me = result.data as any;\n const plan = me.plan;\n const lines: string[] = [];\n\n lines.push(\"## Your Session\");\n if (me.auth_mode === \"oauth\") {\n lines.push(`Auth: OAuth (connected)`);\n lines.push(`Workspace: ${me.workspace?.name ?? \"Unknown\"} (${me.workspace?.id ?? \"?\"})`);\n lines.push(`User: ${me.user_id ?? \"?\"}`);\n lines.push(`Company: ${me.company_id ?? \"none\"}`);\n } else {\n lines.push(\"Auth: anonymous (not connected to a Clipform account)\");\n if (me.workspace) {\n lines.push(`Workspace: ${me.workspace.name} (${me.workspace.id})`);\n }\n }\n lines.push(`Plan: ${plan.name} (tier ${plan.tier})`);\n if (plan.node_limit !== null) {\n lines.push(`Question limit: ${plan.node_limit} per form`);\n } else {\n lines.push(\"Questions: unlimited\");\n }\n if (plan.custom_theme === false) {\n lines.push(\"Custom themes: not available on this plan\");\n }\n if (me.auth_mode !== \"oauth\") {\n lines.push(`\\nTo unlock your full plan: connect your Clipform account in Settings > Connectors > ${BUSINESS.urls.mcp}`);\n }\n\n return lines.join(\"\\n\");\n}\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { getSessionContext } from \"./lib/session-context.js\";\n\nexport function registerPrompts(server: McpServer) {\n server.registerPrompt(\n \"create-quiz\",\n {\n title: \"Create a Quiz\",\n description: \"Build a scored knowledge quiz with narrated video questions\",\n },\n async () => {\n const sessionContext = await getSessionContext();\n return {\n messages: [\n {\n role: \"user\" as const,\n content: {\n type: \"text\" as const,\n text: \"I want to create a quiz. What's the best approach?\",\n },\n },\n {\n role: \"assistant\" as const,\n content: {\n type: \"text\" as const,\n text: `${sessionContext ? sessionContext + \"\\n\\n\" : \"\"}Here's how to build a great quiz with Clipform. Read the quiz writing guide (clipform://guides/quiz) for detailed craft knowledge on question design, difficulty curves, and narration style.\n\n## Workflow\n\n1. **Research** the topic - find surprising facts, common misconceptions, myth-busters\n2. **Write questions** - follow the difficulty curve (easy start, hard middle, satisfying end). Target 5-8 questions.\n3. **Create the form** with clipform_create_form:\n - show_step_counter: true\n - disable_back_navigation: true\n4. **Add questions** with clipform_add_node (type: \"choice\"):\n - config: { choice: { show_answer_feedback: true } }\n - randomise_options: true in config\n - score: 1 on correct option, score: 0 on wrong\n - 3-4 wrong answers per question\n5. **Generate narration** with clipform_generate_tts for each question. Tease the question - do NOT reveal the answer or read options aloud. Keep each narration 5-15 seconds.\n6. **Build video** for each question:\n - clipform_search_media (kind: \"image\") - 3 images per question\n - clipform_generate_video - creates Ken Burns video synced to audio\n7. **Attach media** with clipform_upload_node_media. Include captions, set show_captions: true.\n8. **Update end screen** with clipform_update_node - EVERY quiz must have:\n - show_score: true, icon: \"trophy\"\n - show_share_button: true (drives virality)\n - cta_type: \"restart\", cta_text: a short challenge like \"Beat your score?\" or \"Try again?\"\n - score_ranges with personalised title + message per tier. Write these in the quiz's voice - short, punchy, and specific to the topic (not generic \"Good job!\"). Example for a geography quiz:\n \\`\\`\\`json\n { \"min\": 0, \"max\": 2, \"title\": \"Lost Tourist\", \"message\": \"You might need a map - and a compass.\" },\n { \"min\": 3, \"max\": 5, \"title\": \"Frequent Flyer\", \"message\": \"Not bad! You know your way around.\" },\n { \"min\": 6, \"max\": 8, \"title\": \"World Explorer\", \"message\": \"Impressive - you really know your stuff.\" }\n \\`\\`\\`\n9. **Publish** with clipform_update_form\n10. **Tag the form** - pass tags: one format (quiz/survey/interview/feedback/lead-gen), one genre (trivia/personality/nps/poll/testimonial), and 2-3 topic words\n11. **Log** with clipform_log_generation (sources, images, attributions)\n\n## Before building, ask\n\n1. How many questions?\n2. Media style: text only, still images, or slideshow video with narration?\n3. Any topic or style preferences?`,\n },\n },\n ],\n };\n }\n );\n\n server.registerPrompt(\n \"create-personality-quiz\",\n {\n title: \"Create a Personality Quiz\",\n description: \"Build a 'Which X are you?' personality quiz with category-based scoring and outcome screens\",\n },\n async () => {\n const sessionContext = await getSessionContext();\n return {\n messages: [\n {\n role: \"user\" as const,\n content: {\n type: \"text\" as const,\n text: \"I want to create a personality quiz. What's the best approach?\",\n },\n },\n {\n role: \"assistant\" as const,\n content: {\n type: \"text\" as const,\n text: `${sessionContext ? sessionContext + \"\\n\\n\" : \"\"}Here's how to build a personality quiz with Clipform. Read the personality quiz guide (clipform://guides/personality-quiz) for craft knowledge on category design, option weighting, and outcome writing.\n\n## How it differs from a knowledge quiz\n\nThere are NO correct answers. Each option maps to one or more outcome categories via \\`scores\\` (not \\`score\\`). The winning category at the end determines which result screen the respondent sees.\n\n## Workflow\n\n1. **Define 3-5 outcome categories** - these are the \"personalities\" (e.g. \"Creative\", \"Analytical\", \"Leader\", \"Collaborator\"). More than 5 gets muddy.\n2. **Write questions** - each question should feel revealing but fun. Target 5-8 questions.\n3. **Create the form** with clipform_create_form:\n - show_step_counter: true\n - disable_back_navigation: true\n4. **Add questions** with clipform_add_node (type: \"choice\"):\n - config: { choice: { show_answer_feedback: false } } (no right/wrong!)\n - Do NOT set randomise_options (option order matters for personality quizzes - lead with the most appealing)\n - Each option gets \\`scores: { \"CategoryA\": 2, \"CategoryB\": 1 }\\` - weight towards relevant categories\n - Every option should score in at least one category (no dead options)\n5. **Generate narration** with clipform_generate_tts - conversational, reflective tone. \"What does this say about you?\" not \"Do you know the answer?\"\n6. **Build video** + **attach media** (same as knowledge quiz workflow)\n7. **Update end screen** with clipform_update_node - EVERY personality quiz must have:\n - show_score: false, icon: \"star\"\n - show_share_button: true (personality results are inherently shareable - \"I got X, what did you get?\")\n - cta_type: \"restart\", cta_text: \"Find out again?\" or \"Take it again?\"\n - scoring_results (NOT score_ranges) with a result per category. Write the title as an identity reveal (\"You're a Creative!\") and the message as a short, flattering description that makes people want to share it. Be specific to the quiz theme, not generic. Example:\n \\`\\`\\`json\n {\n \"show_score\": false,\n \"icon\": \"star\",\n \"show_share_button\": true,\n \"cta_type\": \"restart\",\n \"cta_text\": \"Retake quiz\",\n \"scoring_results\": [\n { \"category\": \"Creative\", \"title\": \"You're a Creative!\", \"message\": \"You see the world through colour and possibility. Where others see problems, you see raw material.\" },\n { \"category\": \"Analytical\", \"title\": \"You're an Analyst!\", \"message\": \"You don't guess - you figure it out. Your superpower is turning chaos into clarity.\" }\n ]\n }\n \\`\\`\\`\n8. **Publish** with clipform_update_form\n9. **Tag the form** - pass tags: one format (quiz/survey/interview/feedback/lead-gen), one genre (trivia/personality/nps/poll/testimonial), and 2-3 topic words\n10. **Log** with clipform_log_generation\n\n## Before building, ask\n\n1. What are the possible outcomes/personalities? (3-5 categories)\n2. What's the theme? (\"Which city are you?\", \"What's your work style?\", \"Which character are you?\")\n3. Media style: text only, still images, or slideshow video with narration?`,\n },\n },\n ],\n };\n }\n );\n\n server.registerPrompt(\n \"create-interview\",\n {\n title: \"Create an Interview\",\n description:\n \"Build a form to collect testimonials, case studies, async video interviews, or journalist responses\",\n },\n async () => {\n const sessionContext = await getSessionContext();\n return {\n messages: [\n {\n role: \"user\" as const,\n content: {\n type: \"text\" as const,\n text: \"I want to collect responses or testimonials from people. What's the best approach?\",\n },\n },\n {\n role: \"assistant\" as const,\n content: {\n type: \"text\" as const,\n text: `${sessionContext ? sessionContext + \"\\n\\n\" : \"\"}Here's how to build an interview or testimonial form with Clipform. Read the interview guide (clipform://guides/interview) for detailed craft knowledge on question design and pacing.\n\n## Workflow\n\n1. **Identify the ask** - what do you need from respondents? Testimonial, case study, expert comment, job application?\n2. **Create the form** with clipform_create_form:\n - show_step_counter: true\n - disable_back_navigation: false\n3. **Add a warm-up question** - something easy: \"Tell us your name and role\" (type: \"open\")\n4. **Add core questions** (type: \"open\") - 2-3 max, one topic per question. Enable text + audio + video responses.\n5. **Add contact collection** (type: \"contact\") - first name + email minimum\n6. **Add consent** if needed - \"I agree that my response may be used in [context]\"\n7. **Update end screen** - set expectations: \"Thanks! We'll be in touch.\"\n8. **Optional: add narration** - warm, inviting tone. \"We'd love to hear your story...\"\n9. **Publish** with clipform_update_form\n10. **Tag the form** - pass tags: one format (quiz/survey/interview/feedback/lead-gen), one genre (trivia/personality/nps/poll/testimonial), and 2-3 topic words\n\n## Before building, ask\n\n1. What are you collecting? (testimonial, case study, interview, application)\n2. Should respondents reply with video, audio, text, or all three?\n3. Do you need a consent statement?`,\n },\n },\n ],\n };\n }\n );\n\n server.registerPrompt(\n \"create-survey\",\n {\n title: \"Create a Survey\",\n description:\n \"Build a feedback survey, NPS form, or research questionnaire\",\n },\n async () => {\n const sessionContext = await getSessionContext();\n return {\n messages: [\n {\n role: \"user\" as const,\n content: {\n type: \"text\" as const,\n text: \"I want to collect feedback or run a survey. What's the best approach?\",\n },\n },\n {\n role: \"assistant\" as const,\n content: {\n type: \"text\" as const,\n text: `${sessionContext ? sessionContext + \"\\n\\n\" : \"\"}Here's how to build a survey with Clipform. Read the survey guide (clipform://guides/survey) for craft knowledge on question design and reducing respondent fatigue.\n\n## Workflow\n\n1. **Define the key metric** - what's the one number you care about? (NPS, satisfaction, likelihood to recommend)\n2. **Create the form** with clipform_create_form:\n - show_step_counter: true\n - disable_back_navigation: false\n3. **Add key metric question first** (type: \"choice\" or \"rating\") - put it first while attention is highest\n4. **Add one \"why?\" follow-up** (type: \"open\") - \"What's the main reason for your score?\"\n5. **Add 2-3 specific questions** (type: \"choice\") - only ask what you'll act on\n6. **Contact** (optional) - only if you need to follow up. Many surveys work better anonymous.\n7. **Update end screen** - \"Thanks for your feedback!\"\n8. **Publish** with clipform_update_form\n9. **Tag the form** - pass tags: one format (quiz/survey/interview/feedback/lead-gen), one genre (trivia/personality/nps/poll/testimonial), and 2-3 topic words\n\n## Key rule: 5 questions max. Every extra question costs completions.\n\n## Before building, ask\n\n1. What feedback are you collecting? (NPS, satisfaction, event feedback, product research)\n2. Anonymous or identified?\n3. Any specific areas you want to ask about?`,\n },\n },\n ],\n };\n }\n );\n\n server.registerPrompt(\n \"create-funnel\",\n {\n title: \"Create a Funnel\",\n description:\n \"Build a lead qualification funnel or product recommendation quiz with branching logic\",\n },\n async () => {\n const sessionContext = await getSessionContext();\n return {\n messages: [\n {\n role: \"user\" as const,\n content: {\n type: \"text\" as const,\n text: \"I want to qualify leads or recommend products based on answers. What's the best approach?\",\n },\n },\n {\n role: \"assistant\" as const,\n content: {\n type: \"text\" as const,\n text: `${sessionContext ? sessionContext + \"\\n\\n\" : \"\"}Here's how to build a qualification funnel with Clipform. Read the funnel guide (clipform://guides/funnel) for craft knowledge on branching logic and conversion.\n\n## Workflow\n\n1. **Define outcomes** - what segments or recommendations exist? (e.g., Basic/Pro/Enterprise, or product categories)\n2. **Create the form** with clipform_create_form:\n - show_step_counter: false (funnels feel shorter without it)\n - disable_back_navigation: true (prevents answer shopping that breaks scoring)\n3. **Add hook question** (type: \"choice\") - \"What best describes you?\" or \"What are you looking for?\" This segments the user.\n4. **Add qualifying questions** (type: \"choice\") - 2-3 questions that narrow down the need. Assign scores to each option.\n5. **Set branching logic** with clipform_set_logic - route based on answers\n6. **Add contact capture** (type: \"contact\") - name, email, phone. Place AFTER qualifying questions.\n7. **Update end screen** with score_ranges for personalised outcomes: \"Based on your answers, we recommend...\"\n8. **Publish** with clipform_update_form\n9. **Tag the form** - pass tags: one format (quiz/survey/interview/feedback/lead-gen), one genre (trivia/personality/nps/poll/testimonial), and 2-3 topic words\n\n## Key rule: 3-5 questions max. Every extra step loses leads.\n\n## Before building, ask\n\n1. What outcomes are you routing to? (products, plans, team members, messages)\n2. What criteria determine the routing?\n3. Do you need contact capture?`,\n },\n },\n ],\n };\n }\n );\n}\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { getSessionContext } from \"./lib/session-context.js\";\n\nconst WRITING_PRINCIPLES = `## Writing Principles\n\n- **Write for the ear.** Narration is spoken aloud. Short sentences. Natural rhythm.\n- **Research before writing.** Find 2-3 genuinely interesting facts per topic. Generic content doesn't hold attention.\n- **Conversational, not encyclopaedic.** \"Here's what's wild about this...\" not \"The subject is characterized by...\"\n- **Cut ruthlessly.** Every word must earn its place.\n- **Never reveal answers in narration.** The user picks from options - narration teases and builds intrigue.\n- **Don't read answer options aloud.** The viewer can see them on screen.\n\n## Narration Tips\n\n- Tease the topic, don't summarise it\n- Give one interesting fact that makes the user curious\n- 5-15 seconds per question narration\n- If TTS comes back too long, trim the copy and regenerate\n\n## Research\n\nSearch for the specific subject, not generic terms (\"komodo dragon habitat\" not \"reptile\"). Cross-reference facts - quiz answers must be correct. Look for the surprising angle: what would make someone say \"wait, really?\"\n\nFor timeless topics (history, geography, science), write from your own knowledge. For anything recent or uncertain, use web search or clipform_search_news. If neither is available, refuse rather than fabricate.`;\n\nconst MEDIA_WORKFLOW = `## Media Workflow\n\n1. **clipform_generate_tts** - narration audio (returns word-level captions)\n2. **clipform_search_media** (kind: \"image\") - find 3 images per question\n3. **clipform_generate_video** - Ken Burns video from images + audio\n4. **clipform_upload_node_media** - attach video with captions (set show_captions: true)\n\n**Image selection:**\n- ONLY use URLs from clipform_search_media results\n- Search for the specific subject, not generic terms\n- Pick visually distinct images (different angles, colors, subjects)\n- Landscape images work best for pan effects\n\n**Slideshow defaults:**\n- 3 images per question, random_effects: true\n- transition: { type: \"fade\", duration: 1 }\n- Auto focal point detection, eased motion, and cinematic vignette are built in`;\n\nexport function registerResources(server: McpServer) {\n server.registerResource(\n \"guide-quiz\",\n \"clipform://guides/quiz\",\n {\n description:\n \"Craft knowledge for writing engaging quizzes - difficulty curves, question psychology, narration style, scoring\",\n mimeType: \"text/markdown\",\n },\n async () => ({\n contents: [\n {\n uri: \"clipform://guides/quiz\",\n mimeType: \"text/markdown\",\n text: `# Quiz Writing Guide\n\n## Psychology\n\nEach question is a micro variable-reward event - the same dopamine loop that keeps people watching. Once someone answers 2-3 questions, sunk cost kicks in and they finish. Viewers mentally compete, then want to compare scores.\n\n**Target 50-60% correct.** Too easy = no challenge. Too hard = people feel stupid and won't share.\n\n## Difficulty Curve\n\n| Position | Difficulty | Purpose |\n|----------|-----------|---------|\n| Q1-Q2 | Easy (80%+ get right) | Build confidence and commitment |\n| Q3-Q5 | Medium | Peak engagement |\n| Q6-Q8 | Hard (include one \"gotcha\") | The \"everyone gets this wrong\" moment |\n| Q9-Q10 | One hard, one satisfying medium | End on a smart feeling, not defeat |\n\n## Question Design\n\n- **Myth-busters**: \"Sushi means raw fish - True or False?\" (False - it means seasoned rice)\n- **Sounds fake but true**: counterintuitive correct answers make people rewatch\n- **Common misconceptions**: \"Capital of Australia?\" (not Sydney - Canberra)\n- Under 12-15 words per question for mobile readability\n- Trigger gut reactions, not deep thinking\n\n## Wrong Answer Generation\n\nFor numeric questions (population, speed, weight), scale the real answer by random multipliers (0.3x to 3x) rounded to the same magnitude. Makes wrong answers plausible but clearly different.\n\n## Narration Style\n\nYou're a quiz master, not a question reader. Each question's narration should:\n\n1. **Tease** - set the scene, build intrigue (\"This one catches everyone out\")\n2. **Give context** - one interesting fact that makes the question richer\n3. **Pose the question** - \"So here's the question...\"\n\n**Don't say:**\n- \"You either know it or you don't\" (meaningless filler)\n- \"This is a really hard one\" on every question (loses impact)\n- \"Welcome to my quiz\" / \"Hey guys\" (wastes time, skip to Q1)\n\n${WRITING_PRINCIPLES}\n\n${MEDIA_WORKFLOW}`,\n },\n ],\n })\n );\n\n server.registerResource(\n \"guide-personality-quiz\",\n \"clipform://guides/personality-quiz\",\n {\n description:\n \"Craft knowledge for building personality quizzes - category design, option weighting, outcome writing, no right/wrong answers\",\n mimeType: \"text/markdown\",\n },\n async () => ({\n contents: [\n {\n uri: \"clipform://guides/personality-quiz\",\n mimeType: \"text/markdown\",\n text: `# Personality Quiz Guide\n\n## How it works\n\nPersonality quizzes use **category-based scoring** (the \\`scores\\` field on options) instead of right/wrong scoring. Each option distributes points across outcome categories. The category with the highest total at the end determines the result.\n\n## Category Design\n\n- **3-5 categories** is the sweet spot. Fewer feels too binary, more feels random.\n- Categories should be **distinct but equally appealing**. Nobody wants to get the \"bad\" result.\n- Name them after the outcome, not the trait: \"Explorer\" not \"Adventurous\", \"The Architect\" not \"Organised\".\n\n## Option Weighting\n\nEach option scores into one or more categories:\n\n\\`\\`\\`json\n{ \"scores\": { \"Explorer\": 3, \"Homebody\": 0, \"Foodie\": 1 } }\n\\`\\`\\`\n\nGuidelines:\n- **Primary category**: 2-3 points (this is the option's \"home\" category)\n- **Secondary**: 1 point (slight lean towards another category)\n- **Unrelated**: 0 (omit or set to 0)\n- **Knockout**: -1 (use sparingly - strongly rules out a category)\n- Every option should score positively in at least one category\n- Avoid giving every option the same spread - it makes results feel random\n\n## Question Design\n\n- Questions should feel **personally revealing** but low-stakes: \"Pick your ideal Saturday morning\" not \"What's your biggest weakness?\"\n- Scenario-based questions work better than abstract preference questions\n- Each question should meaningfully differentiate between categories\n- Avoid questions where all options clearly map to one obvious personality\n\n## Outcome Screens\n\nEach category needs a \\`scoring_results\\` entry on the end screen:\n\n- **Title**: \"You're a [Category]!\" - celebratory, not clinical\n- **Message**: 2-3 sentences that feel like a personalised insight. Reference specific traits the quiz measured.\n- **Optional CTA**: link to relevant content, product, or next step\n\n## Narration Style\n\nReflective and curious, not quizmaster-y:\n- \"This one says a lot about you...\"\n- \"There's no wrong answer here - go with your gut\"\n- \"What does your choice reveal?\"\n\nDo NOT say \"let's see if you get this right\" - there is no right answer.\n\n${WRITING_PRINCIPLES}\n\n${MEDIA_WORKFLOW}`,\n },\n ],\n })\n );\n\n server.registerResource(\n \"guide-interview\",\n \"clipform://guides/interview\",\n {\n description:\n \"Craft knowledge for building interview and testimonial collection forms - warm-up pacing, open questions, consent, video responses\",\n mimeType: \"text/markdown\",\n },\n async () => ({\n contents: [\n {\n uri: \"clipform://guides/interview\",\n mimeType: \"text/markdown\",\n text: `# Interview & Testimonial Guide\n\n## Purpose\n\nCollect responses from people - testimonials, case studies, journalist callouts, async video interviews, candidate screening. The common thread: you're asking someone to respond on camera or in their own words.\n\n## Structure\n\n1. **Warm-up question** - something easy and low-stakes to get them comfortable. \"Tell us your name and what you do\" or \"What's your role?\"\n2. **Core questions** - the real ask. Open-ended, one topic per question. Don't over-split - 2-3 core questions max.\n3. **Follow-up** (optional) - \"Anything else you'd like to add?\" catches things you didn't think to ask.\n4. **Contact collection** - first name + email minimum. Add phone/company if relevant.\n5. **Consent** - \"I agree that my response may be used in [context].\" Always include for testimonials and media.\n6. **End screen** - set expectations: \"Thanks! We'll be in touch if we'd like to take things further.\"\n\n## Question Design\n\n- **Open-ended by default.** Use \"open\" type with text + audio + video response enabled. Let the respondent choose their format.\n- **One topic per question.** \"Tell us about your experience AND what you'd change\" is two questions.\n- **Prompt, don't interrogate.** \"What surprised you most about working with us?\" beats \"Rate your satisfaction.\"\n- **Keep it short.** 3-5 questions total. Every extra question loses respondents.\n\n## Narration for Interviews\n\nWarmer and more personal than quiz narration. You're inviting someone to share, not testing them.\n\n- \"We'd love to hear your story...\"\n- \"Take your time with this one - there's no wrong answer\"\n- Keep narration under 10 seconds - the respondent's answer is the content, not yours\n\n## Settings\n\n- disable_back_navigation: false (let people review their answers)\n- show_step_counter: true (so they know how much is left)\n\n${WRITING_PRINCIPLES}\n\n${MEDIA_WORKFLOW}`,\n },\n ],\n })\n );\n\n server.registerResource(\n \"guide-survey\",\n \"clipform://guides/survey\",\n {\n description:\n \"Craft knowledge for feedback surveys, NPS, and research forms - brevity, rating scales, respondent fatigue\",\n mimeType: \"text/markdown\",\n },\n async () => ({\n contents: [\n {\n uri: \"clipform://guides/survey\",\n mimeType: \"text/markdown\",\n text: `# Survey & Feedback Guide\n\n## Purpose\n\nCollect structured feedback - NPS, customer satisfaction, product research, post-event feedback. The goal is clean, analysable data with minimal respondent fatigue.\n\n## Structure\n\nSurveys should be ruthlessly short. Every extra question costs you completions.\n\n1. **Key metric** - the one number you care about (NPS, satisfaction rating, likelihood to recommend). Put it first while attention is highest.\n2. **Follow-up** - one open-ended \"why?\" question. \"What's the main reason for your score?\" This is where the insight lives.\n3. **Specific questions** (optional) - 2-3 targeted choice questions on specific areas. Don't fish - only ask what you'll act on.\n4. **Contact** (optional) - only if you need to follow up. Many surveys are better anonymous.\n5. **End screen** - \"Thanks for your feedback!\" Keep it simple.\n\n## Question Design\n\n- **Choice questions for data, open questions for insight.** Don't use open-ended where a rating scale would do, and don't use ratings where you need to understand why.\n- **Balanced scales.** Equal positive and negative options. \"Excellent / Good / Fair / Poor\" not \"Amazing / Great / Good / OK / Bad.\"\n- **No leading questions.** \"How much did you enjoy...?\" assumes they enjoyed it.\n- **5 questions max.** If you need more, you're running research, not a survey - split it up.\n\n## Narration for Surveys\n\nOptional - many surveys work fine as text only. If using narration:\n\n- Keep it brief (5-8 seconds). \"We'd love your quick feedback on...\"\n- Don't narrate every question - just the opener to set the tone\n- Friendly but efficient. Respect their time.\n\n## Settings\n\n- disable_back_navigation: false\n- show_step_counter: true (shows progress, reduces abandonment)\n\n${WRITING_PRINCIPLES}`,\n },\n ],\n })\n );\n\n server.registerResource(\n \"guide-funnel\",\n \"clipform://guides/funnel\",\n {\n description:\n \"Craft knowledge for lead qualification funnels and product recommendation quizzes - branching logic, progressive profiling, conversion\",\n mimeType: \"text/markdown\",\n },\n async () => ({\n contents: [\n {\n uri: \"clipform://guides/funnel\",\n mimeType: \"text/markdown\",\n text: `# Lead Qualification & Product Recommendation Guide\n\n## Purpose\n\nRoute people to the right outcome based on their answers. Lead qualification scores and segments prospects. Product recommendation guides users to the right product. Both use branching logic to personalise the journey.\n\n## Structure\n\n1. **Hook question** - immediately relevant, low friction. \"What are you looking for?\" or \"What best describes you?\" This segments the user and determines the branch.\n2. **Qualifying questions** - 2-3 questions that narrow down the need. Each answer can branch to a different path.\n3. **Contact capture** - name, email, phone. Place AFTER qualifying questions so they've invested before you ask for details.\n4. **Outcome screen** - personalised end screen based on their answers. Use score_ranges or branching logic to show different messages.\n\n## Question Design\n\n- **Progressive profiling.** Start broad, get specific. Don't ask for budget on question 1.\n- **Every question must earn its place.** If the answer doesn't change the outcome or routing, cut the question.\n- **Choice questions, not open-ended.** You need structured data to route and score. Save open-ended for \"anything else?\"\n- **3-5 questions max.** Every extra step loses leads. The funnel is leaky by nature - keep it tight.\n\n## Branching Logic\n\nUse clipform_set_logic to route based on answers:\n\n- **Segment early.** Q1 answer determines which Q2 they see.\n- **Converge at capture.** All branches should reach the contact collection step.\n- **Different outcomes for different segments.** The end screen should feel personalised: \"Based on your answers, we recommend...\" not a generic \"Thanks!\"\n\n## Scoring for Product Recommendation\n\n- Assign scores to each option based on which product/outcome it points to\n- Use score_ranges on the end screen to show different recommendations\n- Example: score 0-3 = \"Basic plan\", 4-6 = \"Pro plan\", 7+ = \"Enterprise - let's talk\"\n\n## Narration for Funnels\n\nShort and action-oriented. You're guiding, not teaching.\n\n- \"Let's find the right fit for you...\"\n- \"Just a couple of quick questions...\"\n- Keep total narration under 30 seconds across the whole funnel\n\n## Settings\n\n- disable_back_navigation: true (prevent answer shopping that breaks scoring)\n- show_step_counter: false (funnels feel shorter without a counter)\n\n${WRITING_PRINCIPLES}`,\n },\n ],\n })\n );\n\n server.registerResource(\n \"context-session\",\n \"clipform://context/session\",\n {\n description:\n \"Current session info: auth mode, workspace, plan tier, node limits, feature flags. Read this before planning content to know your constraints.\",\n mimeType: \"text/markdown\",\n annotations: { audience: [\"assistant\"], priority: 1.0 },\n },\n async () => {\n const text = await getSessionContext();\n return {\n contents: [\n {\n uri: \"clipform://context/session\",\n mimeType: \"text/markdown\",\n text: text || \"Session context unavailable - API may not be reachable.\",\n },\n ],\n };\n }\n );\n}\n"],"mappings":"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","names":["z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","slideshowStyleSchema","z","z","z"]}
|