@clipform/mcp-server 1.16.1 → 1.17.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.
@@ -2,8 +2,9 @@ import {
2
2
  __commonJS,
3
3
  __export,
4
4
  __toESM,
5
+ getMcpAuth,
5
6
  runWithMcpTool
6
- } from "./chunk-VWGIVJMQ.js";
7
+ } from "./chunk-HCZI2UJ5.js";
7
8
 
8
9
  // ../../node_modules/@modelcontextprotocol/sdk/node_modules/ajv/dist/compile/codegen/code.js
9
10
  var require_code = __commonJS({
@@ -22278,24 +22279,13 @@ if (!API_BASE_URL) {
22278
22279
  "API_URL must be set (e.g. http://localhost:3003 or https://api.clipform.io)"
22279
22280
  );
22280
22281
  }
22281
- var MCP_SERVICE_USER_ID = "00000000-0000-4000-8000-000000000001";
22282
22282
  function getAuthHeaders() {
22283
- const serviceSecret = process.env.INTERNAL_SERVICE_SECRET || process.env.CLIPFORM_INTERNAL_SERVICE_SECRET;
22284
- const workspaceId = process.env.MCP_WORKSPACE_ID;
22285
- if (serviceSecret && workspaceId) {
22286
- return {
22287
- "Authorization": `Bearer ${serviceSecret}`,
22288
- "X-Mcp-Workspace": workspaceId,
22289
- "X-Mcp-User": MCP_SERVICE_USER_ID
22290
- };
22283
+ const authCtx = getMcpAuth();
22284
+ const apiKey = authCtx?.api_key || process.env.CLIPFORM_API_KEY;
22285
+ if (!apiKey) {
22286
+ throw new Error("CLIPFORM_API_KEY must be set.");
22291
22287
  }
22292
- const apiKey = process.env.CLIPFORM_API_KEY;
22293
- if (apiKey) {
22294
- return { "Authorization": `Bearer ${apiKey}` };
22295
- }
22296
- throw new Error(
22297
- "No API authentication configured. Set INTERNAL_SERVICE_SECRET + MCP_WORKSPACE_ID, or CLIPFORM_API_KEY."
22298
- );
22288
+ return { "Authorization": `Bearer ${apiKey}` };
22299
22289
  }
22300
22290
  async function callApi(path, options = {}) {
22301
22291
  const { body, params } = options;
@@ -22402,7 +22392,7 @@ Example: A form that asks a question, collects contact info, then finishes:
22402
22392
  const workspaceId = me.workspace?.id ?? null;
22403
22393
  if (!workspaceId) {
22404
22394
  return errorResult(
22405
- "No workspace available. Connect your Clipform account in claude.ai \u2192 Settings \u2192 Connectors, or ensure MCP_WORKSPACE_ID is configured for anonymous mode."
22395
+ "No workspace available. This usually means authentication is misconfigured - check your API key or OAuth connection."
22406
22396
  );
22407
22397
  }
22408
22398
  planContext = {
@@ -22416,7 +22406,7 @@ Example: A form that asks a question, collects contact info, then finishes:
22416
22406
  const contentCount = nodes.filter((q) => !NON_COUNTABLE_TYPES.includes(q.type)).length;
22417
22407
  if (planContext.node_limit !== null && contentCount > planContext.node_limit) {
22418
22408
  const upgradeUrl = `${BUSINESS.urls.dashboard}/billing`;
22419
- const message = planContext.auth_mode === "oauth" ? `Your '${planContext.workspace_name}' workspace is on the ${planContext.plan_name} plan, capped at ${planContext.node_limit} nodes per form. You asked for ${contentCount}. Either rerun with ${planContext.node_limit} nodes or upgrade at ${upgradeUrl}.` : `Anonymous sessions are capped at ${planContext.node_limit} nodes per form (${planContext.plan_name} plan). You asked for ${contentCount}. Either rerun with ${planContext.node_limit} nodes, or connect your Clipform account in claude.ai \u2192 Settings \u2192 Connectors so forms land in your workspace with your real plan limits.`;
22409
+ const message = planContext.auth_mode === "oauth" ? `Your '${planContext.workspace_name}' workspace is on the ${planContext.plan_name} plan, capped at ${planContext.node_limit} nodes per form. You asked for ${contentCount}. Either rerun with ${planContext.node_limit} nodes or upgrade at ${upgradeUrl}.` : `Anonymous sessions are capped at ${planContext.node_limit} nodes per form (${planContext.plan_name} plan). You asked for ${contentCount}. Either rerun with ${planContext.node_limit} nodes, or sign in to your Clipform account so forms land in your workspace with your real plan limits.`;
22420
22410
  return errorResult(message);
22421
22411
  }
22422
22412
  if (planContext.form_limit !== null) {
@@ -22473,7 +22463,8 @@ Example: A form that asks a question, collects contact info, then finishes:
22473
22463
  body: { is_live: true }
22474
22464
  });
22475
22465
  if (!publishResult.ok) {
22476
- return errorResult(`Form created but failed to publish: ${publishResult.error}. Form ID: ${formId}`);
22466
+ return errorResult(`Form created but failed to publish: ${publishResult.error}. Form ID: ${formId}
22467
+ FORM URL: ${data.viewer_url}`);
22477
22468
  }
22478
22469
  if (tags && tags.length > 0) {
22479
22470
  await callApi(`/forms/${formId}/tags`, {
@@ -22495,7 +22486,7 @@ Example: A form that asks a question, collects contact info, then finishes:
22495
22486
  }
22496
22487
  lines.push(
22497
22488
  ``,
22498
- `IMPORTANT: Always show the user the exact URLs above \u2014 do not rewrite or modify them.`,
22489
+ `CRITICAL: Copy the URLs above character-for-character into your response. Do NOT construct, guess, or invent any URLs. Only use the exact FORM URL and CLAIM URL provided here.`,
22499
22490
  `Pass form_id on follow-up tools (get_form, add_node, upload_node_media, etc.).`
22500
22491
  );
22501
22492
  if (planContext) {
@@ -22510,7 +22501,7 @@ Example: A form that asks a question, collects contact info, then finishes:
22510
22501
  } else {
22511
22502
  lines.push(
22512
22503
  ``,
22513
- `Plan: anonymous ${planContext.plan_name} (${limitNote}). Mention this once: the user can connect their Clipform account in claude.ai \u2192 Settings \u2192 Connectors \u2192 ${BUSINESS.urls.mcp} so future forms land directly in their workspace - do not repeat on follow-up calls.`
22504
+ `Plan: anonymous ${planContext.plan_name} (${limitNote}). Mention this once: the user can sign in to their Clipform account so future forms land directly in their workspace - do not repeat on follow-up calls.`
22514
22505
  );
22515
22506
  }
22516
22507
  }
@@ -23316,7 +23307,7 @@ Returns audio URL and word-level captions per item.`,
23316
23307
  annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true }
23317
23308
  },
23318
23309
  async ({ items }) => {
23319
- const workspace_id = process.env.MCP_WORKSPACE_ID;
23310
+ const workspace_id = getMcpAuth()?.workspace_id;
23320
23311
  const results = await Promise.allSettled(
23321
23312
  items.map(
23322
23313
  (item) => callApi("/internal/tts", {
@@ -23425,7 +23416,7 @@ Style presets via default_style.preset: cinematic (default), dramatic, calm, doc
23425
23416
  annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true }
23426
23417
  },
23427
23418
  async ({ images, audio_url, random_effects, transition, default_style, background_color }) => {
23428
- const workspace_id = process.env.MCP_WORKSPACE_ID;
23419
+ const workspace_id = getMcpAuth()?.workspace_id;
23429
23420
  const result = await callApi("/internal/slideshow", {
23430
23421
  body: {
23431
23422
  images,
@@ -23721,7 +23712,7 @@ Items: type "image" (Ken Burns motion) or "video" (cover-cropped, muted by defau
23721
23712
  annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true }
23722
23713
  },
23723
23714
  async ({ items, audio_url, duration_seconds, random_effects, transition, default_style, background_color }) => {
23724
- const workspace_id = process.env.MCP_WORKSPACE_ID;
23715
+ const workspace_id = getMcpAuth()?.workspace_id;
23725
23716
  const result = await callApi("/internal/generate-video", {
23726
23717
  body: {
23727
23718
  items,
@@ -23898,40 +23889,62 @@ async function getSessionContext() {
23898
23889
  }
23899
23890
  if (me.auth_mode !== "oauth") {
23900
23891
  lines.push(`
23901
- To unlock your full plan: connect your Clipform account in Settings > Connectors > ${BUSINESS.urls.mcp}`);
23892
+ To unlock your full plan: sign in to your Clipform account.`);
23902
23893
  }
23903
23894
  return lines.join("\n");
23904
23895
  }
23905
23896
 
23906
23897
  // src/prompts.ts
23898
+ var MEDIA_STYLE_ENUM = ["text", "images", "video"];
23899
+ function resourceLink(name, uri, title) {
23900
+ return {
23901
+ role: "assistant",
23902
+ content: {
23903
+ type: "resource_link",
23904
+ uri,
23905
+ name,
23906
+ title,
23907
+ mimeType: "text/markdown"
23908
+ }
23909
+ };
23910
+ }
23907
23911
  function registerPrompts(server) {
23908
23912
  server.registerPrompt(
23909
23913
  "create-quiz",
23910
23914
  {
23911
23915
  title: "Create a Quiz",
23912
- description: "Build a scored knowledge quiz with narrated video questions"
23916
+ description: "Build a scored knowledge quiz with narrated video questions",
23917
+ argsSchema: {
23918
+ topic: external_exports.string().optional().describe("Quiz topic (e.g. 'Space exploration', 'Premier League')"),
23919
+ question_count: external_exports.number().optional().default(8).describe("Number of questions (default: 8)"),
23920
+ media_style: external_exports.enum(MEDIA_STYLE_ENUM).optional().default("video").describe("Media style: text only, still images, or slideshow video with narration (default: video)")
23921
+ }
23913
23922
  },
23914
- async () => {
23923
+ async (args) => {
23915
23924
  const sessionContext = await getSessionContext();
23925
+ const topic = args.topic ? ` about "${args.topic}"` : "";
23926
+ const count = args.question_count ?? 8;
23927
+ const media = args.media_style ?? "video";
23916
23928
  return {
23917
23929
  messages: [
23918
23930
  {
23919
23931
  role: "user",
23920
23932
  content: {
23921
23933
  type: "text",
23922
- text: "I want to create a quiz. What's the best approach?"
23934
+ text: `I want to create a quiz${topic}. ${count} questions, ${media} style.`
23923
23935
  }
23924
23936
  },
23937
+ resourceLink("guide-quiz", "clipform://guides/quiz", "Quiz Writing Guide"),
23925
23938
  {
23926
23939
  role: "assistant",
23927
23940
  content: {
23928
23941
  type: "text",
23929
- 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.
23942
+ text: `${sessionContext ? sessionContext + "\n\n" : ""}Here's how to build a great ${count}-question ${media} quiz${topic} with Clipform. Read the attached quiz guide for craft knowledge on question design, difficulty curves, and narration style.
23930
23943
 
23931
23944
  ## Workflow
23932
23945
 
23933
23946
  1. **Research** the topic - find surprising facts, common misconceptions, myth-busters
23934
- 2. **Write questions** - follow the difficulty curve (easy start, hard middle, satisfying end). Target 5-8 questions.
23947
+ 2. **Write questions** - follow the difficulty curve (easy start, hard middle, satisfying end). Target ${count} questions.
23935
23948
  3. **Create the form** with clipform_create_form:
23936
23949
  - show_step_counter: true
23937
23950
  - disable_back_navigation: true
@@ -23940,12 +23953,12 @@ function registerPrompts(server) {
23940
23953
  - randomise_options: true in config
23941
23954
  - score: 1 on correct option, score: 0 on wrong
23942
23955
  - 3-4 wrong answers per question
23943
- 5. **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.
23956
+ 5. **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.${media !== "text" ? `
23944
23957
  6. **Build video** for each question:
23945
23958
  - clipform_search_media (kind: "image") - 3 images per question
23946
23959
  - clipform_generate_video - creates Ken Burns video synced to audio
23947
- 7. **Attach media** with clipform_upload_node_media. Include captions, set show_captions: true.
23948
- 8. **Update end screen** with clipform_update_node - EVERY quiz must have:
23960
+ 7. **Attach media** with clipform_upload_node_media. Include captions, set show_captions: true.` : ""}
23961
+ ${media !== "text" ? "8" : "6"}. **Update end screen** with clipform_update_node - EVERY quiz must have:
23949
23962
  - show_score: true, icon: "trophy"
23950
23963
  - show_share_button: true (drives virality)
23951
23964
  - cta_type: "restart", cta_text: a short challenge like "Beat your score?" or "Try again?"
@@ -23955,15 +23968,9 @@ function registerPrompts(server) {
23955
23968
  { "min": 3, "max": 5, "title": "Frequent Flyer", "message": "Not bad! You know your way around." },
23956
23969
  { "min": 6, "max": 8, "title": "World Explorer", "message": "Impressive - you really know your stuff." }
23957
23970
  \`\`\`
23958
- 9. **Publish** with clipform_update_form
23959
- 10. **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
23960
- 11. **Log** with clipform_log_generation (sources, images, attributions)
23961
-
23962
- ## Before building, ask
23963
-
23964
- 1. How many questions?
23965
- 2. Media style: text only, still images, or slideshow video with narration?
23966
- 3. Any topic or style preferences?`
23971
+ ${media !== "text" ? "9" : "7"}. **Publish** with clipform_update_form
23972
+ ${media !== "text" ? "10" : "8"}. **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
23973
+ ${media !== "text" ? "11" : "9"}. **Log** with clipform_log_generation (sources, images, attributions)`
23967
23974
  }
23968
23975
  }
23969
23976
  ]
@@ -23974,24 +23981,37 @@ function registerPrompts(server) {
23974
23981
  "create-personality-quiz",
23975
23982
  {
23976
23983
  title: "Create a Personality Quiz",
23977
- description: "Build a 'Which X are you?' personality quiz with category-based scoring and outcome screens"
23984
+ description: "Build a 'Which X are you?' personality quiz with category-based scoring and outcome screens",
23985
+ argsSchema: {
23986
+ topic: external_exports.string().optional().describe("Quiz theme (e.g. 'Which city are you?', 'What's your work style?')"),
23987
+ categories: external_exports.string().optional().describe("Comma-separated outcome categories (e.g. 'Creative, Analytical, Leader, Collaborator')"),
23988
+ question_count: external_exports.number().optional().default(8).describe("Number of questions (default: 8)"),
23989
+ media_style: external_exports.enum(MEDIA_STYLE_ENUM).optional().default("video").describe("Media style (default: video)")
23990
+ }
23978
23991
  },
23979
- async () => {
23992
+ async (args) => {
23980
23993
  const sessionContext = await getSessionContext();
23994
+ const topic = args.topic ? ` - "${args.topic}"` : "";
23995
+ const count = args.question_count ?? 8;
23996
+ const media = args.media_style ?? "video";
23997
+ const categoriesNote = args.categories ? `
23998
+
23999
+ Outcome categories: ${args.categories}` : "";
23981
24000
  return {
23982
24001
  messages: [
23983
24002
  {
23984
24003
  role: "user",
23985
24004
  content: {
23986
24005
  type: "text",
23987
- text: "I want to create a personality quiz. What's the best approach?"
24006
+ text: `I want to create a personality quiz${topic}. ${count} questions, ${media} style.${categoriesNote}`
23988
24007
  }
23989
24008
  },
24009
+ resourceLink("guide-personality-quiz", "clipform://guides/personality-quiz", "Personality Quiz Guide"),
23990
24010
  {
23991
24011
  role: "assistant",
23992
24012
  content: {
23993
24013
  type: "text",
23994
- 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.
24014
+ text: `${sessionContext ? sessionContext + "\n\n" : ""}Here's how to build a ${count}-question personality quiz${topic} with Clipform. Read the attached personality quiz guide for craft knowledge on category design, option weighting, and outcome writing.
23995
24015
 
23996
24016
  ## How it differs from a knowledge quiz
23997
24017
 
@@ -24000,7 +24020,7 @@ There are NO correct answers. Each option maps to one or more outcome categories
24000
24020
  ## Workflow
24001
24021
 
24002
24022
  1. **Define 3-5 outcome categories** - these are the "personalities" (e.g. "Creative", "Analytical", "Leader", "Collaborator"). More than 5 gets muddy.
24003
- 2. **Write questions** - each question should feel revealing but fun. Target 5-8 questions.
24023
+ 2. **Write questions** - each question should feel revealing but fun. Target ${count} questions.
24004
24024
  3. **Create the form** with clipform_create_form:
24005
24025
  - show_step_counter: true
24006
24026
  - disable_back_navigation: true
@@ -24031,13 +24051,7 @@ There are NO correct answers. Each option maps to one or more outcome categories
24031
24051
  \`\`\`
24032
24052
  8. **Publish** with clipform_update_form
24033
24053
  9. **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
24034
- 10. **Log** with clipform_log_generation
24035
-
24036
- ## Before building, ask
24037
-
24038
- 1. What are the possible outcomes/personalities? (3-5 categories)
24039
- 2. What's the theme? ("Which city are you?", "What's your work style?", "Which character are you?")
24040
- 3. Media style: text only, still images, or slideshow video with narration?`
24054
+ 10. **Log** with clipform_log_generation`
24041
24055
  }
24042
24056
  }
24043
24057
  ]
@@ -24048,45 +24062,49 @@ There are NO correct answers. Each option maps to one or more outcome categories
24048
24062
  "create-interview",
24049
24063
  {
24050
24064
  title: "Create an Interview",
24051
- description: "Build a form to collect testimonials, case studies, async video interviews, or journalist responses"
24065
+ description: "Build a form to collect testimonials, case studies, async video interviews, or journalist responses",
24066
+ argsSchema: {
24067
+ purpose: external_exports.string().optional().describe("What you're collecting (e.g. 'testimonial', 'case study', 'job application')"),
24068
+ response_format: external_exports.enum(["video", "audio", "text", "all"]).optional().default("all").describe("How respondents reply (default: all - video, audio, and text)"),
24069
+ needs_consent: external_exports.boolean().optional().default(true).describe("Include a consent statement (default: true)")
24070
+ }
24052
24071
  },
24053
- async () => {
24072
+ async (args) => {
24054
24073
  const sessionContext = await getSessionContext();
24074
+ const purpose = args.purpose ?? "responses";
24075
+ const format = args.response_format ?? "all";
24076
+ const consent = args.needs_consent ?? true;
24055
24077
  return {
24056
24078
  messages: [
24057
24079
  {
24058
24080
  role: "user",
24059
24081
  content: {
24060
24082
  type: "text",
24061
- text: "I want to collect responses or testimonials from people. What's the best approach?"
24083
+ text: `I want to collect ${purpose} from people. Responses via ${format}.${consent ? " Include consent." : ""}`
24062
24084
  }
24063
24085
  },
24086
+ resourceLink("guide-interview", "clipform://guides/interview", "Interview & Testimonial Guide"),
24064
24087
  {
24065
24088
  role: "assistant",
24066
24089
  content: {
24067
24090
  type: "text",
24068
- 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.
24091
+ text: `${sessionContext ? sessionContext + "\n\n" : ""}Here's how to build an interview form for collecting ${purpose} with Clipform. Read the attached interview guide for craft knowledge on question design and pacing.
24069
24092
 
24070
24093
  ## Workflow
24071
24094
 
24072
- 1. **Identify the ask** - what do you need from respondents? Testimonial, case study, expert comment, job application?
24095
+ 1. **Identify the ask** - what do you need from respondents? ${purpose}.
24073
24096
  2. **Create the form** with clipform_create_form:
24074
24097
  - show_step_counter: true
24075
24098
  - disable_back_navigation: false
24076
24099
  3. **Add a warm-up question** - something easy: "Tell us your name and role" (type: "open")
24077
- 4. **Add core questions** (type: "open") - 2-3 max, one topic per question. Enable text + audio + video responses.
24078
- 5. **Add contact collection** (type: "contact") - first name + email minimum
24079
- 6. **Add consent** if needed - "I agree that my response may be used in [context]"
24100
+ 4. **Add core questions** (type: "open") - 2-3 max, one topic per question.${format === "all" ? " Enable text + audio + video responses." : ` Enable ${format} responses.`}
24101
+ 5. **Add contact collection** (type: "contact") - first name + email minimum${consent ? `
24102
+ 6. **Add consent** - "I agree that my response may be used in [context]"` : ""}
24080
24103
  7. **Update end screen** - set expectations: "Thanks! We'll be in touch."
24081
24104
  8. **Optional: add narration** - warm, inviting tone. "We'd love to hear your story..."
24082
24105
  9. **Publish** with clipform_update_form
24083
24106
  10. **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
24084
-
24085
- ## Before building, ask
24086
-
24087
- 1. What are you collecting? (testimonial, case study, interview, application)
24088
- 2. Should respondents reply with video, audio, text, or all three?
24089
- 3. Do you need a consent statement?`
24107
+ 11. **Log** with clipform_log_generation`
24090
24108
  }
24091
24109
  }
24092
24110
  ]
@@ -24097,24 +24115,31 @@ There are NO correct answers. Each option maps to one or more outcome categories
24097
24115
  "create-survey",
24098
24116
  {
24099
24117
  title: "Create a Survey",
24100
- description: "Build a feedback survey, NPS form, or research questionnaire"
24118
+ description: "Build a feedback survey, NPS form, or research questionnaire",
24119
+ argsSchema: {
24120
+ topic: external_exports.string().optional().describe("What feedback you're collecting (e.g. 'NPS', 'event feedback', 'product satisfaction')"),
24121
+ anonymous: external_exports.boolean().optional().default(true).describe("Whether the survey is anonymous (default: true)")
24122
+ }
24101
24123
  },
24102
- async () => {
24124
+ async (args) => {
24103
24125
  const sessionContext = await getSessionContext();
24126
+ const topic = args.topic ? ` for ${args.topic}` : "";
24127
+ const anonymous = args.anonymous ?? true;
24104
24128
  return {
24105
24129
  messages: [
24106
24130
  {
24107
24131
  role: "user",
24108
24132
  content: {
24109
24133
  type: "text",
24110
- text: "I want to collect feedback or run a survey. What's the best approach?"
24134
+ text: `I want to create a survey${topic}. ${anonymous ? "Anonymous" : "Identified"} respondents.`
24111
24135
  }
24112
24136
  },
24137
+ resourceLink("guide-survey", "clipform://guides/survey", "Survey & Feedback Guide"),
24113
24138
  {
24114
24139
  role: "assistant",
24115
24140
  content: {
24116
24141
  type: "text",
24117
- 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.
24142
+ text: `${sessionContext ? sessionContext + "\n\n" : ""}Here's how to build a survey${topic} with Clipform. Read the attached survey guide for craft knowledge on question design and reducing respondent fatigue.
24118
24143
 
24119
24144
  ## Workflow
24120
24145
 
@@ -24124,19 +24149,14 @@ There are NO correct answers. Each option maps to one or more outcome categories
24124
24149
  - disable_back_navigation: false
24125
24150
  3. **Add key metric question first** (type: "choice" or "rating") - put it first while attention is highest
24126
24151
  4. **Add one "why?" follow-up** (type: "open") - "What's the main reason for your score?"
24127
- 5. **Add 2-3 specific questions** (type: "choice") - only ask what you'll act on
24128
- 6. **Contact** (optional) - only if you need to follow up. Many surveys work better anonymous.
24152
+ 5. **Add 2-3 specific questions** (type: "choice") - only ask what you'll act on${!anonymous ? `
24153
+ 6. **Contact** - collect name + email for follow-up` : ""}
24129
24154
  7. **Update end screen** - "Thanks for your feedback!"
24130
24155
  8. **Publish** with clipform_update_form
24131
24156
  9. **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
24157
+ 10. **Log** with clipform_log_generation
24132
24158
 
24133
- ## Key rule: 5 questions max. Every extra question costs completions.
24134
-
24135
- ## Before building, ask
24136
-
24137
- 1. What feedback are you collecting? (NPS, satisfaction, event feedback, product research)
24138
- 2. Anonymous or identified?
24139
- 3. Any specific areas you want to ask about?`
24159
+ ## Key rule: 5 questions max. Every extra question costs completions.`
24140
24160
  }
24141
24161
  }
24142
24162
  ]
@@ -24147,24 +24167,36 @@ There are NO correct answers. Each option maps to one or more outcome categories
24147
24167
  "create-comprehension-quiz",
24148
24168
  {
24149
24169
  title: "Create a YouTube Comprehension Quiz",
24150
- description: "Build a comprehension quiz from a YouTube video - tests whether the viewer actually watched and understood the content"
24170
+ description: "Build a comprehension quiz from a YouTube video - tests whether the viewer actually watched and understood the content",
24171
+ argsSchema: {
24172
+ youtube_url: external_exports.string().optional().describe("YouTube video URL to create the quiz from"),
24173
+ question_count: external_exports.number().optional().default(8).describe("Number of questions (default: 8)"),
24174
+ audience: external_exports.string().optional().describe("Target audience (e.g. 'children aged 5-8', 'university students', 'general')"),
24175
+ media_style: external_exports.enum(MEDIA_STYLE_ENUM).optional().default("video").describe("Media style (default: video)")
24176
+ }
24151
24177
  },
24152
- async () => {
24178
+ async (args) => {
24153
24179
  const sessionContext = await getSessionContext();
24180
+ const count = args.question_count ?? 8;
24181
+ const media = args.media_style ?? "video";
24182
+ const urlNote = args.youtube_url ? ` Start by extracting the transcript from: ${args.youtube_url}` : "";
24183
+ const audienceNote = args.audience ? ` Target audience: ${args.audience}.` : "";
24154
24184
  return {
24155
24185
  messages: [
24156
24186
  {
24157
24187
  role: "user",
24158
24188
  content: {
24159
24189
  type: "text",
24160
- text: "I want to create a comprehension quiz based on a YouTube video. What's the best approach?"
24190
+ text: `I want to create a comprehension quiz based on a YouTube video. ${count} questions, ${media} style.${urlNote}${audienceNote}`
24161
24191
  }
24162
24192
  },
24193
+ resourceLink("guide-quiz", "clipform://guides/quiz", "Quiz Writing Guide"),
24194
+ resourceLink("guide-comprehension-quiz", "clipform://guides/comprehension-quiz", "Comprehension Quiz Guide"),
24163
24195
  {
24164
24196
  role: "assistant",
24165
24197
  content: {
24166
24198
  type: "text",
24167
- text: `${sessionContext ? sessionContext + "\n\n" : ""}Here's how to build a comprehension quiz from a YouTube video. Read the quiz guide (clipform://guides/quiz) for general craft, and the comprehension guide (clipform://guides/comprehension-quiz) for video-specific techniques.
24199
+ text: `${sessionContext ? sessionContext + "\n\n" : ""}Here's how to build a ${count}-question comprehension quiz from a YouTube video. Read the attached quiz and comprehension guides for craft knowledge on question design and distractor techniques.
24168
24200
 
24169
24201
  ## Comprehension Quiz Workflow
24170
24202
 
@@ -24179,7 +24211,7 @@ There are NO correct answers. Each option maps to one or more outcome categories
24179
24211
  - "What example does the video use to illustrate...?"
24180
24212
  - Include 1-2 inference questions: "Based on the video, why does the presenter believe...?"
24181
24213
  - Avoid questions answerable without watching (e.g., common knowledge about the topic)
24182
- 4. **Adapt to the audience** - if specified (e.g., "for a 5-year-old"), simplify language, reduce option count, focus on concrete/visual details rather than abstract arguments
24214
+ 4. **Adapt to the audience**${args.audience ? ` (${args.audience})` : ""} - simplify language for younger audiences, focus on concrete/visual details rather than abstract arguments
24183
24215
  5. **Create the form** with clipform_create_form:
24184
24216
  - show_step_counter: true
24185
24217
  - disable_back_navigation: true
@@ -24188,12 +24220,12 @@ There are NO correct answers. Each option maps to one or more outcome categories
24188
24220
  - randomise_options: true in config
24189
24221
  - score: 1 on correct option, score: 0 on wrong
24190
24222
  - 3-4 wrong answers per question - make distractors plausible (things someone might guess without watching)
24191
- 7. **Generate narration** with clipform_generate_tts - reference the video naturally: "If you watched closely, you'll know this one..." Keep each narration 5-10 seconds.
24223
+ 7. **Generate narration** with clipform_generate_tts - reference the video naturally: "If you watched closely, you'll know this one..." Keep each narration 5-10 seconds.${media !== "text" ? `
24192
24224
  8. **Build video** for each question:
24193
24225
  - clipform_search_media (kind: "image") - 3 images per question
24194
24226
  - clipform_generate_video - Ken Burns video synced to audio
24195
- 9. **Attach media** with clipform_upload_node_media. Include captions, set show_captions: true.
24196
- 10. **Update end screen** with clipform_update_node:
24227
+ 9. **Attach media** with clipform_upload_node_media. Include captions, set show_captions: true.` : ""}
24228
+ ${media !== "text" ? "10" : "8"}. **Update end screen** with clipform_update_node:
24197
24229
  - show_score: true, icon: "trophy"
24198
24230
  - show_share_button: true
24199
24231
  - cta_type: "restart", cta_text: "Rewatch and try again?"
@@ -24203,9 +24235,9 @@ There are NO correct answers. Each option maps to one or more outcome categories
24203
24235
  { "min": 3, "max": 5, "title": "Casual Viewer", "message": "You caught the highlights but missed some details." },
24204
24236
  { "min": 6, "max": 8, "title": "Focused Student", "message": "You were paying attention - impressive." }
24205
24237
  \`\`\`
24206
- 11. **Publish** with clipform_update_form
24207
- 12. **Tag** - tags: ["quiz", "comprehension", "youtube"] + 2-3 topic words from the video
24208
- 13. **Log** with clipform_log_generation - include the YouTube URL, video title, and channel as sources
24238
+ ${media !== "text" ? "11" : "9"}. **Publish** with clipform_update_form
24239
+ ${media !== "text" ? "12" : "10"}. **Tag** - tags: ["quiz", "comprehension", "youtube"] + 2-3 topic words from the video
24240
+ ${media !== "text" ? "13" : "11"}. **Log** with clipform_log_generation - include the YouTube URL, video title, and channel as sources
24209
24241
 
24210
24242
  ## Question Types for Comprehension
24211
24243
 
@@ -24217,14 +24249,7 @@ There are NO correct answers. Each option maps to one or more outcome categories
24217
24249
  | Contrast | "The video compares X and Y. What was the key difference?" | Comprehension depth |
24218
24250
  | Conclusion | "What was the presenter's final point?" | Watched to the end |
24219
24251
 
24220
- Wrong answers should sound right to someone who didn't watch but googled the topic. The quiz should be unfair to non-watchers and fair to watchers.
24221
-
24222
- ## Before building, ask
24223
-
24224
- 1. What's the YouTube URL?
24225
- 2. How many questions? (default: 8)
24226
- 3. Who's the audience? (age, knowledge level)
24227
- 4. Media style: text only, still images, or slideshow video with narration?`
24252
+ Wrong answers should sound right to someone who didn't watch but googled the topic. The quiz should be unfair to non-watchers and fair to watchers.`
24228
24253
  }
24229
24254
  }
24230
24255
  ]
@@ -24235,46 +24260,50 @@ Wrong answers should sound right to someone who didn't watch but googled the top
24235
24260
  "create-funnel",
24236
24261
  {
24237
24262
  title: "Create a Funnel",
24238
- description: "Build a lead qualification funnel or product recommendation quiz with branching logic"
24263
+ description: "Build a lead qualification funnel or product recommendation quiz with branching logic",
24264
+ argsSchema: {
24265
+ outcomes: external_exports.string().optional().describe("What segments or recommendations exist (e.g. 'Basic/Pro/Enterprise', or product names)"),
24266
+ criteria: external_exports.string().optional().describe("What criteria determine routing (e.g. 'budget, team size, use case')"),
24267
+ needs_contact: external_exports.boolean().optional().default(true).describe("Include contact capture (default: true)")
24268
+ }
24239
24269
  },
24240
- async () => {
24270
+ async (args) => {
24241
24271
  const sessionContext = await getSessionContext();
24272
+ const outcomes = args.outcomes ?? "different outcomes";
24273
+ const contact = args.needs_contact ?? true;
24274
+ const criteriaNote = args.criteria ? ` Routing criteria: ${args.criteria}.` : "";
24242
24275
  return {
24243
24276
  messages: [
24244
24277
  {
24245
24278
  role: "user",
24246
24279
  content: {
24247
24280
  type: "text",
24248
- text: "I want to qualify leads or recommend products based on answers. What's the best approach?"
24281
+ text: `I want to qualify leads or recommend products based on answers. Outcomes: ${outcomes}.${criteriaNote}`
24249
24282
  }
24250
24283
  },
24284
+ resourceLink("guide-funnel", "clipform://guides/funnel", "Lead Qualification & Funnel Guide"),
24251
24285
  {
24252
24286
  role: "assistant",
24253
24287
  content: {
24254
24288
  type: "text",
24255
- 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.
24289
+ text: `${sessionContext ? sessionContext + "\n\n" : ""}Here's how to build a qualification funnel with Clipform. Read the attached funnel guide for craft knowledge on branching logic and conversion.
24256
24290
 
24257
24291
  ## Workflow
24258
24292
 
24259
- 1. **Define outcomes** - what segments or recommendations exist? (e.g., Basic/Pro/Enterprise, or product categories)
24293
+ 1. **Define outcomes** - what segments or recommendations exist? (${outcomes})
24260
24294
  2. **Create the form** with clipform_create_form:
24261
24295
  - show_step_counter: false (funnels feel shorter without it)
24262
24296
  - disable_back_navigation: true (prevents answer shopping that breaks scoring)
24263
24297
  3. **Add hook question** (type: "choice") - "What best describes you?" or "What are you looking for?" This segments the user.
24264
24298
  4. **Add qualifying questions** (type: "choice") - 2-3 questions that narrow down the need. Assign scores to each option.
24265
- 5. **Set branching logic** with clipform_set_logic - route based on answers
24266
- 6. **Add contact capture** (type: "contact") - name, email, phone. Place AFTER qualifying questions.
24299
+ 5. **Set branching logic** with clipform_set_logic - route based on answers${contact ? `
24300
+ 6. **Add contact capture** (type: "contact") - name, email, phone. Place AFTER qualifying questions.` : ""}
24267
24301
  7. **Update end screen** with score_ranges for personalised outcomes: "Based on your answers, we recommend..."
24268
24302
  8. **Publish** with clipform_update_form
24269
24303
  9. **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
24304
+ 10. **Log** with clipform_log_generation
24270
24305
 
24271
- ## Key rule: 3-5 questions max. Every extra step loses leads.
24272
-
24273
- ## Before building, ask
24274
-
24275
- 1. What outcomes are you routing to? (products, plans, team members, messages)
24276
- 2. What criteria determine the routing?
24277
- 3. Do you need contact capture?`
24306
+ ## Key rule: 3-5 questions max. Every extra step loses leads.`
24278
24307
  }
24279
24308
  }
24280
24309
  ]
@@ -24328,7 +24357,8 @@ function registerResources(server) {
24328
24357
  "clipform://guides/quiz",
24329
24358
  {
24330
24359
  description: "Craft knowledge for writing engaging quizzes - difficulty curves, question psychology, narration style, scoring",
24331
- mimeType: "text/markdown"
24360
+ mimeType: "text/markdown",
24361
+ annotations: { audience: ["assistant"], priority: 0.8 }
24332
24362
  },
24333
24363
  async () => ({
24334
24364
  contents: [
@@ -24388,6 +24418,11 @@ Inspired by the Color Brain board game - every answer is identified by its colou
24388
24418
  - If two answer options would produce identical swatches, don't use that question.
24389
24419
  - Pair with a reveal composition (FlagReveal, image, or text) for the answer.
24390
24420
 
24421
+ ## Settings
24422
+
24423
+ - show_step_counter: true
24424
+ - disable_back_navigation: true (prevent going back to change answers after seeing feedback)
24425
+
24391
24426
  ## Narration Style
24392
24427
 
24393
24428
  You're a quiz master, not a question reader. Each question's narration should:
@@ -24413,7 +24448,8 @@ ${MEDIA_WORKFLOW}`
24413
24448
  "clipform://guides/personality-quiz",
24414
24449
  {
24415
24450
  description: "Craft knowledge for building personality quizzes - category design, option weighting, outcome writing, no right/wrong answers",
24416
- mimeType: "text/markdown"
24451
+ mimeType: "text/markdown",
24452
+ annotations: { audience: ["assistant"], priority: 0.8 }
24417
24453
  },
24418
24454
  async () => ({
24419
24455
  contents: [
@@ -24463,6 +24499,11 @@ Each category needs a \`scoring_results\` entry on the end screen:
24463
24499
  - **Message**: 2-3 sentences that feel like a personalised insight. Reference specific traits the quiz measured.
24464
24500
  - **Optional CTA**: link to relevant content, product, or next step
24465
24501
 
24502
+ ## Settings
24503
+
24504
+ - show_step_counter: true
24505
+ - disable_back_navigation: true (prevent re-answering which skews category scores)
24506
+
24466
24507
  ## Narration Style
24467
24508
 
24468
24509
  Reflective and curious, not quizmaster-y:
@@ -24484,7 +24525,8 @@ ${MEDIA_WORKFLOW}`
24484
24525
  "clipform://guides/comprehension-quiz",
24485
24526
  {
24486
24527
  description: "Craft knowledge for YouTube comprehension quizzes - extracting questions from transcripts, distractor design, audience adaptation",
24487
- mimeType: "text/markdown"
24528
+ mimeType: "text/markdown",
24529
+ annotations: { audience: ["assistant"], priority: 0.8 }
24488
24530
  },
24489
24531
  async () => ({
24490
24532
  contents: [
@@ -24535,6 +24577,11 @@ Make wrong answers plausible to someone who **didn't watch**:
24535
24577
 
24536
24578
  For young children: focus on "What did you SEE?" and "Who did what?" rather than abstract arguments.
24537
24579
 
24580
+ ## Settings
24581
+
24582
+ - show_step_counter: true
24583
+ - disable_back_navigation: true
24584
+
24538
24585
  ## Narration style
24539
24586
 
24540
24587
  Reference the video naturally but don't spoil:
@@ -24555,7 +24602,8 @@ ${MEDIA_WORKFLOW}`
24555
24602
  "clipform://guides/interview",
24556
24603
  {
24557
24604
  description: "Craft knowledge for building interview and testimonial collection forms - warm-up pacing, open questions, consent, video responses",
24558
- mimeType: "text/markdown"
24605
+ mimeType: "text/markdown",
24606
+ annotations: { audience: ["assistant"], priority: 0.8 }
24559
24607
  },
24560
24608
  async () => ({
24561
24609
  contents: [
@@ -24609,7 +24657,8 @@ ${MEDIA_WORKFLOW}`
24609
24657
  "clipform://guides/survey",
24610
24658
  {
24611
24659
  description: "Craft knowledge for feedback surveys, NPS, and research forms - brevity, rating scales, respondent fatigue",
24612
- mimeType: "text/markdown"
24660
+ mimeType: "text/markdown",
24661
+ annotations: { audience: ["assistant"], priority: 0.8 }
24613
24662
  },
24614
24663
  async () => ({
24615
24664
  contents: [
@@ -24662,7 +24711,8 @@ ${WRITING_PRINCIPLES}`
24662
24711
  "clipform://guides/funnel",
24663
24712
  {
24664
24713
  description: "Craft knowledge for lead qualification funnels and product recommendation quizzes - branching logic, progressive profiling, conversion",
24665
- mimeType: "text/markdown"
24714
+ mimeType: "text/markdown",
24715
+ annotations: { audience: ["assistant"], priority: 0.8 }
24666
24716
  },
24667
24717
  async () => ({
24668
24718
  contents: [
@@ -24794,4 +24844,4 @@ export {
24794
24844
  JSONRPCMessageSchema,
24795
24845
  createServer
24796
24846
  };
24797
- //# sourceMappingURL=chunk-MB6BZ2JN.js.map
24847
+ //# sourceMappingURL=chunk-Y22DYUS3.js.map