@clipform/mcp-server 1.30.0 → 1.32.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 +2 -2
- package/dist/{chunk-J4KJN4C4.js → chunk-B32WK2NQ.js} +3 -3
- package/dist/chunk-B32WK2NQ.js.map +1 -0
- package/dist/{chunk-Y3A5HHT6.js → chunk-HQGYGAE4.js} +53 -12
- package/dist/{chunk-Y3A5HHT6.js.map → chunk-HQGYGAE4.js.map} +1 -1
- package/dist/index.js +2 -2
- package/dist/resources.js +1 -1
- package/dist/server.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-J4KJN4C4.js.map +0 -1
package/README.md
CHANGED
|
@@ -55,7 +55,7 @@ You can also pass the key as a CLI flag: `npx -y @clipform/mcp-server --api-key=
|
|
|
55
55
|
|
|
56
56
|
| Tool | Description |
|
|
57
57
|
|------|-------------|
|
|
58
|
-
| `clipform_create_form` | Create a new form with nodes, theming, and tags in one call |
|
|
58
|
+
| `clipform_create_form` | Create a new form with nodes, theming, and tags in one call. Returns the created node IDs (structured output) so media steps need no follow-up lookup |
|
|
59
59
|
| `clipform_list_forms` | List forms in your workspace with filtering and pagination |
|
|
60
60
|
| `clipform_get_form` | View a form and all its nodes |
|
|
61
61
|
| `clipform_update_form` | Change title, publish status, or settings |
|
|
@@ -82,7 +82,7 @@ You can also pass the key as a CLI flag: `npx -y @clipform/mcp-server --api-key=
|
|
|
82
82
|
| `clipform_generate_slideshow` | Create slideshow videos from images + audio (async - returns job ID) |
|
|
83
83
|
| `clipform_generate_video` | Generate video from images, clips, or both synced to audio (async - returns job ID) |
|
|
84
84
|
| `clipform_check_render` | Check status of an async render job |
|
|
85
|
-
| `clipform_search_media` | Search royalty-free images and videos |
|
|
85
|
+
| `clipform_search_media` | Search royalty-free images and videos, with orientation filter and alt-text descriptions |
|
|
86
86
|
| `clipform_search_music` | Search royalty-free music and ambient sounds |
|
|
87
87
|
| `clipform_list_compositions` | List available video compositions and prop schemas |
|
|
88
88
|
| `clipform_list_assets` | List available sound effects, animations, and fonts |
|
|
@@ -40,8 +40,8 @@ var MEDIA_WORKFLOW = `## Media Workflow
|
|
|
40
40
|
- ALL returned images are pre-cleared for commercial use - pick by visual quality, not by provider or license
|
|
41
41
|
- **Question media must not accidentally reveal the answer.** Unless the media IS the clue (emoji quiz, guess-the-flag - then choose it deliberately for difficulty), search the question's category or scene-setting context, not the answer. Answer-specific media belongs on the reveal. Test: could someone who knows nothing pick the right option just from the media?
|
|
42
42
|
- For non-question media (intros, reveals, surveys), search the specific subject, not generic terms
|
|
43
|
-
- Pick visually distinct images (different angles, colors, subjects)
|
|
44
|
-
-
|
|
43
|
+
- Pick visually distinct images (different angles, colors, subjects) - use each result's description/alt text to judge
|
|
44
|
+
- Portrait images fill the 9:16 frame best and results come portrait-first by default; landscape images get automatic blur-pad framing. Request orientation: "landscape" only when you specifically want wide shots.
|
|
45
45
|
|
|
46
46
|
**Slideshow defaults:**
|
|
47
47
|
- 3 images per question, random_effects: true
|
|
@@ -535,4 +535,4 @@ export {
|
|
|
535
535
|
getGuideUri,
|
|
536
536
|
registerResources
|
|
537
537
|
};
|
|
538
|
-
//# sourceMappingURL=chunk-
|
|
538
|
+
//# sourceMappingURL=chunk-B32WK2NQ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/resources.ts"],"sourcesContent":["import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { getSessionContext } from \"./lib/session-context.js\";\nimport { FORM_TYPE_KEYS, FORM_TYPES, ALL_VARIANTS } from \"@vid-master/config\";\n\nexport const GUIDE_TYPES = FORM_TYPE_KEYS as readonly string[] as readonly [string, ...string[]];\nexport type GuideType = (typeof FORM_TYPE_KEYS)[number];\n\nexport const QUIZ_VARIANTS = ALL_VARIANTS as readonly string[] as readonly [string, ...string[]];\nexport type QuizVariant = (typeof ALL_VARIANTS)[number];\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- ALL returned images are pre-cleared for commercial use - pick by visual quality, not by provider or license\n- **Question media must not accidentally reveal the answer.** Unless the media IS the clue (emoji quiz, guess-the-flag - then choose it deliberately for difficulty), search the question's category or scene-setting context, not the answer. Answer-specific media belongs on the reveal. Test: could someone who knows nothing pick the right option just from the media?\n- For non-question media (intros, reveals, surveys), search the specific subject, not generic terms\n- Pick visually distinct images (different angles, colors, subjects) - use each result's description/alt text to judge\n- Portrait images fill the 9:16 frame best and results come portrait-first by default; landscape images get automatic blur-pad framing. Request orientation: \"landscape\" only when you specifically want wide shots.\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\nconst GUIDE_DESCRIPTIONS: Record<GuideType, string> = {\n \"quiz\": \"Craft knowledge for writing engaging quizzes - difficulty curves, question psychology, narration style, scoring\",\n \"survey\": \"Craft knowledge for feedback surveys, NPS, and research forms - brevity, rating scales, respondent fatigue\",\n \"interview\": \"Craft knowledge for building interview forms - warm-up pacing, open questions, consent, video responses\",\n \"funnel\": \"Craft knowledge for lead qualification funnels - planned feature, conditional routing coming soon\",\n \"testimonial\": \"Craft knowledge for collecting testimonials and customer stories on video - storytelling prompts, comfort techniques, consent\",\n \"application\": \"Craft knowledge for application and evaluation forms - multi-section structure, video responses for behavioural questions, screening\",\n \"booking\": \"Craft knowledge for event registration and booking forms - minimal friction, video welcome, confirmation flow\",\n};\n\nconst QUIZ_VARIANT_DESCRIPTIONS: Record<QuizVariant, string> = {\n \"personality\": \"Addendum for personality quizzes - category design, option weighting, outcome writing, no right/wrong answers\",\n \"comprehension\": \"Addendum for YouTube comprehension quizzes - extracting questions from transcripts, distractor design, audience adaptation\",\n};\n\nconst GUIDE_CONTENT: Record<GuideType, string> = {\n \"quiz\": `# 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- **No guessable answer pattern** - set randomise_options: true and the viewer shuffles options at render time. Do NOT hand-vary correct answer positions; it has no effect once options shuffle.\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## Color Brain Questions (ColorCards composition)\n\nInspired by the Color Brain board game - every answer is identified by its colours. Show flat colour chips, ask \"what has these colours?\". Use the \\`ColorCards\\` composition for the question card.\n\n**Colour palette constraint:** Swatches are solid flat chips. Only use clearly distinguishable basic colours: red, blue, green, yellow, white, black, orange, purple, pink, brown, grey. No navy vs blue, no teal vs cyan - they look the same as flat chips. The skill is picking subjects where a combo of basic colours is unique enough to identify.\n\n**Question categories:**\n- Flags: \"Which country's flag has these colours?\" (pair with FlagReveal for answer)\n- Brand logos: red + yellow = McDonald's, red + white = Coca-Cola\n- Sports teams: red + white = Arsenal, red + blue + white = Barcelona\n- Superheroes/characters: red + blue = Spider-Man, yellow + black = Batman\n- Food: red + green = watermelon, yellow + brown = banana\n\n**Difficulty scaling:**\n- Easy: iconic subjects with unique colour combos (Japan flag: red + white)\n- Medium: common subjects but colours shared with others (Italy vs Ireland: both green + white + one more)\n- Hard: obscure subjects or very common colour combos that fit many answers\n\n**Design rules:**\n- 2-4 colours per question works best. 5+ gets messy and hard to distinguish.\n- If two answer options would produce identical swatches, don't use that question.\n- Pair with a reveal composition (FlagReveal, image, or text) for the answer.\n\n## Settings\n\n- show_step_counter: true\n- disable_back_navigation: true (prevent going back to change answers after seeing feedback)\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 \"survey\": `# 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 \"interview\": `# Interview Guide\n\n## Purpose\n\nCollect responses through structured conversations - journalist callouts, async video interviews, expert input, case study interviews. You're guiding someone through questions, with their answers as structured data or video responses.\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 media use.\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 perspective...\"\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 \"funnel\": `# Lead Qualification Funnel - Coming Soon\n\nFunnel capabilities with conditional routing and branching logic are planned but not yet available. This guide will be expanded when the branching feature launches.\n\nIn the meantime, you can build a simple linear qualification form using the survey or quiz workflows.`,\n\n \"testimonial\": `# Testimonial & Story Collection Guide\n\n## Purpose\n\nCapture authentic stories from customers, users, or participants on camera. The respondent's video IS the deliverable - you're producing content, not collecting data. The questions are storytelling prompts designed to elicit a compelling narrative arc.\n\n## Storytelling Arc\n\nThe best testimonials follow a three-part structure. Each prompt maps to one part:\n\n1. **Before** - \"What was your situation before?\" (establishes the problem)\n2. **During** - \"What was the experience like?\" (the journey)\n3. **After** - \"What's different now?\" (the transformation/result)\n\nThis gives you a complete story you can edit into marketing content.\n\n## Prompt Design\n\n- **Open-ended, video-first.** Every core question should be type \"open\" with video response enabled.\n- **One idea per prompt.** \"Tell us about your experience and what you'd recommend\" is two prompts.\n- **Warm and specific.** \"What surprised you most about working with us?\" beats \"Tell us about your experience.\"\n- **3-5 prompts max.** Fewer = higher completion. The best testimonials come from 3 focused questions.\n- **Don't ask for ratings.** This isn't a survey. You want stories, not numbers.\n\n## Making Respondents Comfortable\n\n- Start with something easy: name, role, how long they've been a customer\n- Narration should feel like a friendly conversation, not a formal interview\n- \"Take your time - there's no rush and no wrong answer\"\n- Keep narration under 8 seconds per prompt - the respondent's answer is the content\n\n## Consent\n\nAlways include a consent node for testimonials. The response will be used in marketing, on your website, or in sales materials. Be explicit about where it may appear.\n\n## Settings\n\n- disable_back_navigation: false (let people re-record if they weren't happy)\n- show_step_counter: true (shows progress, reduces surprise)\n\n## Narration Style\n\nWarm, appreciative, and encouraging:\n- \"We'd love to hear your story...\"\n- \"What you share will help others just like you\"\n- \"There's no script - just speak from the heart\"\n\nDo NOT say \"this will only take a minute\" (it won't) or \"just a quick video\" (undermines the ask).\n\n${WRITING_PRINCIPLES}\n\n${MEDIA_WORKFLOW}`,\n\n \"application\": `# Application & Evaluation Guide\n\n## Purpose\n\nCollect structured applications - job applications, programme admissions, grant proposals, course enrolments. Applications mix structured data (contact, qualifications) with open-ended responses (motivation, experience). Video responses reveal personality and communication skills that text can't capture.\n\n## Structure\n\nApplications have a natural multi-section flow:\n\n1. **Identity** - name, email, phone. Get this first while motivation is highest.\n2. **Qualifications** - role-specific structured questions (experience level, skills, availability). Choice or short text.\n3. **Open responses** - \"Tell us about a time when...\" or \"Why are you interested?\" Video encouraged for behavioural questions.\n4. **Supporting material** (optional) - \"Anything else you'd like to share?\"\n5. **Confirmation** - clear next steps. \"We'll review your application and get back to you within X days.\"\n\n## Question Design\n\n- **Structured for screening, open for depth.** Use choice questions to filter (experience level, availability), open questions to understand (motivation, fit).\n- **Video for behavioural questions.** \"Walk us through how you'd approach...\" is far more revealing on video than in text.\n- **One question per screen.** Applications feel long - keep each step focused.\n- **8-10 questions max.** Even for detailed applications. Every extra question increases abandonment.\n- **Don't duplicate the CV.** Ask for what a resume doesn't show: motivation, culture fit, communication style.\n\n## Narration for Applications\n\nProfessional and welcoming. You're the organisation's first impression.\n\n- \"Thanks for your interest - let's get to know you\"\n- \"Take your time with this one\"\n- Keep narration factual and brief - applicants want to know what's expected, not be entertained\n\n## Settings\n\n- disable_back_navigation: false (applicants need to review and revise)\n- show_step_counter: true (essential - applicants need to know how much is left)\n\n${WRITING_PRINCIPLES}\n\n${MEDIA_WORKFLOW}`,\n\n \"booking\": `# Booking & Registration Guide\n\n## Purpose\n\nEvent registration, course signup, workshop booking, consultation scheduling. The goal is minimal friction to confirmed attendance. Video makes registrations feel personal - a welcome video from the host builds anticipation and reduces no-shows.\n\n## Structure\n\nRegistrations should be fast. Every field you add costs completions.\n\n1. **Welcome** - a short video or narrated intro that sells the event and sets expectations. This is where video adds the most value.\n2. **Essential info** - name, email. Absolute minimum.\n3. **Event-specific details** (if needed) - dietary requirements, session preferences, t-shirt size. Only ask what you'll actually use.\n4. **Confirmation** - \"You're registered! Here's what to expect.\" Include date, time, location/link.\n\n## Question Design\n\n- **3-5 fields maximum.** Name + email + 1-3 event-specific fields. That's it.\n- **Choice questions over open-ended.** \"Which session interests you most?\" not \"What are you hoping to learn?\" You need structured data for logistics.\n- **Contact is mandatory.** This isn't anonymous - you need to confirm their spot.\n- **Don't over-collect.** Phone number, company, job title - only if you genuinely need them for the event.\n\n## Video Welcome\n\nThe registration's killer feature. A 15-30 second video from the host:\n- Who you are and what the event is about\n- What attendees will get out of it\n- Why you're excited about it\n\nThis turns a boring form into a personal invitation. Completion rates go up when people feel welcomed.\n\n## Narration Style\n\nEnthusiastic but efficient. Respect their time.\n- \"We're excited to have you!\"\n- \"Just a few quick details and you're in\"\n- Keep total narration under 20 seconds across the whole form (excluding the welcome video)\n\n## Settings\n\n- disable_back_navigation: false\n- show_step_counter: false (it's so short, a counter adds unnecessary UI)\n\n${WRITING_PRINCIPLES}`,\n};\n\nconst QUIZ_VARIANT_ADDONS: Record<QuizVariant, string> = {\n \"personality\": `---\n\n# Personality Quiz Addendum\n\n> The following sections supplement the base quiz guide above. For personality quizzes, scoring works differently (categories, not right/wrong) and there is no answer feedback. Where guidance below conflicts with the base (e.g., narration style), follow the personality-specific version.\n\n## How Personality Quizzes Work\n\nPersonality quizzes have NO correct answers. Each option should feel equally valid and appealing. The experience is about self-expression and fun, not testing knowledge. Always set show_answer_feedback: false.\n\n**NOTE:** Full category-based scoring (where each option maps to outcome categories via the \\`scores\\` field and the winning category determines a personalised result screen) is coming soon. For now, design personality quizzes as engaging choice-based forms with a single end screen. The questions themselves are the experience.\n\n## Category Design (Conceptual)\n\nEven without automated scoring, design your questions around 3-5 outcome categories:\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- Use categories to guide question and option design, even though automated scoring is not yet available.\n\n## Personality 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## End Screen\n\nWrite a single end screen that feels personal and shareable:\n\n- **Title**: Something warm and inviting, like \"Thanks for playing!\" or \"That was fun!\"\n- **Message**: Encourage sharing - \"Compare your answers with friends!\" Personality quizzes are inherently social.\n- show_score: false (there is no score to show)\n- show_share_button: true (personality results are inherently shareable)\n- NOTE: Automated result screens per category (scoring_results) are coming soon.\n\n## Personality 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 \"comprehension\": `---\n\n# Comprehension Quiz Addendum\n\n> The following sections supplement the base quiz guide above. Comprehension quizzes test whether someone watched a specific piece of content, not general knowledge. Scoring and settings match the base quiz, but question sourcing and distractor design are completely different.\n\n## How Comprehension Differs from Trivia\n\nA trivia quiz tests general knowledge. A comprehension quiz tests whether someone watched a specific piece of content. The questions should be **unfair to non-watchers and fair to watchers**.\n\n| | Trivia Quiz | Comprehension Quiz |\n|---|---|---|\n| Source | Research + your knowledge | The video transcript |\n| Questions | General facts | Specific claims from the video |\n| Wrong answers | Common misconceptions | Things you'd guess without watching |\n| Goal | Entertainment + learning | Proof of watching + retention |\n\n## Extracting Questions from Transcripts\n\nRead the transcript looking for:\n\n1. **Specific numbers or data** - \"The presenter says it takes X days to...\" (detail recall)\n2. **Causal claims** - \"According to the video, this happens because...\" (comprehension)\n3. **Examples used** - \"What example does the presenter use to explain...?\" (attention)\n4. **Sequence of topics** - \"What does the presenter discuss right after...?\" (structure following)\n5. **The main argument** - \"What is the presenter's main point about...?\" (thesis comprehension)\n6. **Counterintuitive points** - anything the presenter says is surprising or commonly misunderstood\n\n## Distractor Design (Wrong Answers)\n\nMake wrong answers plausible to someone who **didn't watch**:\n\n- Use correct facts from other sources about the same topic (tests whether they watched THIS video)\n- Include things that sound likely based on the title alone\n- For number questions, use nearby values that seem reasonable\n- Never include obviously joke answers - every option should feel possible\n\n## Audience Adaptation\n\n| Audience | Question style | Language | Count |\n|----------|---------------|----------|-------|\n| Young children (5-8) | Concrete details, visual moments | Simple, short sentences | 4-6 |\n| Older children (9-12) | Details + basic inference | Clear, direct | 6-8 |\n| Teens (13-17) | Inference + sequence + argument | Natural, conversational | 6-10 |\n| Adults | Full range including critical analysis | Match the video's register | 6-10 |\n\nFor young children: focus on \"What did you SEE?\" and \"Who did what?\" rather than abstract arguments.\n\n## Comprehension Narration Style\n\nReference the video naturally but don't spoil:\n\n- \"If you were paying attention during the bit about...\"\n- \"This is one of those details most people miss...\"\n- \"The presenter made a really specific claim here...\"`,\n};\n\nexport function getGuideContent(type: GuideType, variant?: QuizVariant): string {\n const base = GUIDE_CONTENT[type];\n if (type === \"quiz\" && variant) {\n return base + \"\\n\\n\" + QUIZ_VARIANT_ADDONS[variant];\n }\n return base;\n}\n\nexport function getGuideUri(type: GuideType, variant?: QuizVariant): string {\n if (type === \"quiz\" && variant) {\n return `clipform://guides/quiz/${variant}`;\n }\n return `clipform://guides/${type}`;\n}\n\nexport function registerResources(server: McpServer) {\n for (const type of GUIDE_TYPES) {\n server.registerResource(\n `guide-${type}`,\n getGuideUri(type),\n {\n description: GUIDE_DESCRIPTIONS[type],\n mimeType: \"text/markdown\",\n annotations: { audience: [\"assistant\" as const], priority: 0.8 },\n },\n async () => ({\n contents: [{\n uri: getGuideUri(type),\n mimeType: \"text/markdown\",\n text: getGuideContent(type),\n }],\n }),\n );\n }\n\n for (const variant of QUIZ_VARIANTS) {\n server.registerResource(\n `guide-quiz-${variant}`,\n getGuideUri(\"quiz\", variant),\n {\n description: QUIZ_VARIANT_DESCRIPTIONS[variant],\n mimeType: \"text/markdown\",\n annotations: { audience: [\"assistant\" as const], priority: 0.8 },\n },\n async () => ({\n contents: [{\n uri: getGuideUri(\"quiz\", variant),\n mimeType: \"text/markdown\",\n text: getGuideContent(\"quiz\", variant),\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":[]}
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
getGuideContent,
|
|
14
14
|
getGuideUri,
|
|
15
15
|
registerResources
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-B32WK2NQ.js";
|
|
17
17
|
import {
|
|
18
18
|
BUSINESS,
|
|
19
19
|
CONTACT_FIELDS,
|
|
@@ -17167,6 +17167,13 @@ Example: A form that asks a question, collects contact info, then finishes:
|
|
|
17167
17167
|
font_family: external_exports.string().optional().describe("AI-PROTECTED: Only set when the user explicitly requests a specific font."),
|
|
17168
17168
|
tags: external_exports.array(external_exports.string()).optional().describe("Tags for indexing (e.g. ['quiz', 'trivia', 'arsenal']). Include format, genre, and topics.")
|
|
17169
17169
|
},
|
|
17170
|
+
outputSchema: {
|
|
17171
|
+
form_id: external_exports.string().describe("Form UUID - pass to follow-up tools"),
|
|
17172
|
+
viewer_url: external_exports.string().describe("Live form URL for respondents"),
|
|
17173
|
+
dashboard_url: external_exports.string().optional().describe("Builder URL (sign in to edit)"),
|
|
17174
|
+
nodes: external_exports.array(external_exports.object({ id: external_exports.string(), type: external_exports.string(), prompt: external_exports.string() })).describe("Created nodes in order - IDs for upload_node_media / update_node"),
|
|
17175
|
+
plan: external_exports.object({ name: external_exports.string(), auth_mode: external_exports.string() }).optional().describe("Plan and auth context for this session")
|
|
17176
|
+
},
|
|
17170
17177
|
annotations: {
|
|
17171
17178
|
readOnlyHint: false,
|
|
17172
17179
|
destructiveHint: false,
|
|
@@ -17250,6 +17257,7 @@ Example: A form that asks a question, collects contact info, then finishes:
|
|
|
17250
17257
|
body: settingsBody
|
|
17251
17258
|
});
|
|
17252
17259
|
}
|
|
17260
|
+
const createdNodes = [];
|
|
17253
17261
|
for (const q of nodes) {
|
|
17254
17262
|
applyNodeDefaults(q);
|
|
17255
17263
|
const addResult = await callApi(`/forms/${formId}/nodes`, {
|
|
@@ -17259,6 +17267,11 @@ Example: A form that asks a question, collects contact info, then finishes:
|
|
|
17259
17267
|
if (!addResult.ok) {
|
|
17260
17268
|
return errorResult(`Failed to add node "${q.prompt}": ${addResult.error}`);
|
|
17261
17269
|
}
|
|
17270
|
+
createdNodes.push({
|
|
17271
|
+
id: addResult.data.node_id,
|
|
17272
|
+
type: q.type,
|
|
17273
|
+
prompt: q.prompt
|
|
17274
|
+
});
|
|
17262
17275
|
}
|
|
17263
17276
|
if (tags && tags.length > 0) {
|
|
17264
17277
|
await callApi(`/forms/${formId}/tags`, {
|
|
@@ -17266,13 +17279,16 @@ Example: A form that asks a question, collects contact info, then finishes:
|
|
|
17266
17279
|
body: { tags }
|
|
17267
17280
|
});
|
|
17268
17281
|
}
|
|
17282
|
+
const truncate = (s, n = 60) => s.length > n ? `${s.slice(0, n - 1)}\u2026` : s;
|
|
17269
17283
|
const lines = [
|
|
17270
17284
|
`Form created and live.`,
|
|
17271
17285
|
``,
|
|
17272
17286
|
`Title: ${title}`,
|
|
17273
|
-
`Nodes: ${nodes.length}`,
|
|
17274
17287
|
`Form ID: ${formId}`,
|
|
17275
17288
|
``,
|
|
17289
|
+
`Node IDs (use directly with upload_node_media / update_node - no get_form round-trip needed):`,
|
|
17290
|
+
...createdNodes.map((n) => `- [${n.type}] "${truncate(n.prompt)}": ${n.id}`),
|
|
17291
|
+
``,
|
|
17276
17292
|
`FORM URL (live - share this with respondents): ${data.viewer_url}`
|
|
17277
17293
|
];
|
|
17278
17294
|
if (formUrl) {
|
|
@@ -17281,7 +17297,7 @@ Example: A form that asks a question, collects contact info, then finishes:
|
|
|
17281
17297
|
lines.push(
|
|
17282
17298
|
``,
|
|
17283
17299
|
`The form is live and accessible at the FORM URL above. Continue with media/narration steps if needed - changes appear immediately.`,
|
|
17284
|
-
`
|
|
17300
|
+
`The URLs above are exact values; constructed or guessed URLs return 404. Use the FORM URL and DASHBOARD URL as shown.`,
|
|
17285
17301
|
`Pass form_id on follow-up tools (get_form, add_node, upload_node_media, etc.).`
|
|
17286
17302
|
);
|
|
17287
17303
|
if (planContext) {
|
|
@@ -17300,7 +17316,16 @@ Example: A form that asks a question, collects contact info, then finishes:
|
|
|
17300
17316
|
);
|
|
17301
17317
|
}
|
|
17302
17318
|
}
|
|
17303
|
-
return
|
|
17319
|
+
return {
|
|
17320
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
17321
|
+
structuredContent: {
|
|
17322
|
+
form_id: formId,
|
|
17323
|
+
viewer_url: data.viewer_url,
|
|
17324
|
+
...formUrl ? { dashboard_url: formUrl } : {},
|
|
17325
|
+
nodes: createdNodes,
|
|
17326
|
+
...planContext ? { plan: { name: planContext.plan_name, auth_mode: planContext.auth_mode } } : {}
|
|
17327
|
+
}
|
|
17328
|
+
};
|
|
17304
17329
|
}
|
|
17305
17330
|
);
|
|
17306
17331
|
}
|
|
@@ -17678,6 +17703,10 @@ function registerUpdateNodeTool(server) {
|
|
|
17678
17703
|
if (options !== void 0)
|
|
17679
17704
|
changes.push(`Options \u2192 ${options.map((o) => o.content).join(", ")}`);
|
|
17680
17705
|
allLines.push(`Node ${node_id} updated: ${changes.join(", ")}`);
|
|
17706
|
+
const warnings = result.data.warnings;
|
|
17707
|
+
if (warnings?.length) {
|
|
17708
|
+
for (const w of warnings) allLines.push(`Node ${node_id} warning: ${w}`);
|
|
17709
|
+
}
|
|
17681
17710
|
}
|
|
17682
17711
|
return textResult(allLines.join("\n"));
|
|
17683
17712
|
}
|
|
@@ -18182,13 +18211,16 @@ function registerSearchMediaTool(server) {
|
|
|
18182
18211
|
"clipform_search_media",
|
|
18183
18212
|
{
|
|
18184
18213
|
title: "Search Media",
|
|
18185
|
-
description: `Search images or stock video clips. Pass one query or many (max 10) - multiple queries run in one call instead of separate tool calls. Use results to feed into clipform_generate_video for narrated slideshow videos, or upload directly as still images via clipform_upload_node_media. All results are pre-cleared for commercial use
|
|
18214
|
+
description: `Search images or stock video clips. Pass one query or many (max 10) - multiple queries run in one call instead of separate tool calls. Use results to feed into clipform_generate_video for narrated slideshow videos, or upload directly as still images via clipform_upload_node_media. All results are pre-cleared for commercial use. Results include a description (alt text where the provider has it) - use it to pick visually distinct images.
|
|
18215
|
+
|
|
18216
|
+
Example: { queries: [{ query: "saturn rings" }, { query: "mars surface", count: 3 }] } returns portrait images for both.`,
|
|
18186
18217
|
inputSchema: {
|
|
18187
18218
|
queries: external_exports.array(
|
|
18188
18219
|
external_exports.object({
|
|
18189
18220
|
query: external_exports.string().describe("What to search for (e.g. 'african lion', 'saturn rings')"),
|
|
18190
|
-
kind: external_exports.enum(["image", "video"]).describe("image = stock photos, video = stock clips"),
|
|
18191
|
-
count: external_exports.number().min(1).max(20).default(6).optional().describe("Max results per provider (default 6 for image, 3 for video)")
|
|
18221
|
+
kind: external_exports.enum(["image", "video"]).default("image").optional().describe("image = stock photos (default), video = stock clips"),
|
|
18222
|
+
count: external_exports.number().min(1).max(20).default(6).optional().describe("Max results per provider (default 6 for image, 3 for video)"),
|
|
18223
|
+
orientation: external_exports.enum(["portrait", "landscape", "any"]).default("portrait").optional().describe("portrait (default) fills the 9:16 frame; landscape gets auto blur-pad framing in Ken Burns videos")
|
|
18192
18224
|
})
|
|
18193
18225
|
).min(1).max(10).describe("One or more search queries to run")
|
|
18194
18226
|
},
|
|
@@ -18196,9 +18228,11 @@ function registerSearchMediaTool(server) {
|
|
|
18196
18228
|
},
|
|
18197
18229
|
async ({ queries }) => {
|
|
18198
18230
|
const allLines = [];
|
|
18199
|
-
for (const
|
|
18231
|
+
for (const q of queries) {
|
|
18232
|
+
const { query, count, orientation } = q;
|
|
18233
|
+
const kind = q.kind ?? "image";
|
|
18200
18234
|
const result = await callApi("/internal/search-media", {
|
|
18201
|
-
body: { query, kind, count }
|
|
18235
|
+
body: { query, kind, count, orientation }
|
|
18202
18236
|
});
|
|
18203
18237
|
if (queries.length > 1) allLines.push(`--- "${query}" (${kind}) ---`);
|
|
18204
18238
|
if (!result.ok) {
|
|
@@ -18215,8 +18249,15 @@ function registerSearchMediaTool(server) {
|
|
|
18215
18249
|
for (const item of results.slice(0, 10)) {
|
|
18216
18250
|
allLines.push(`- ${item.title}`);
|
|
18217
18251
|
allLines.push(` URL: ${item.url}`);
|
|
18218
|
-
|
|
18219
|
-
if (
|
|
18252
|
+
const meta = [];
|
|
18253
|
+
if (item.width && item.height) {
|
|
18254
|
+
const ar = item.width / item.height;
|
|
18255
|
+
meta.push(`${item.width}x${item.height} (${ar > 1.1 ? "landscape" : "portrait"})`);
|
|
18256
|
+
}
|
|
18257
|
+
if (kind === "video" && item.duration) meta.push(`${item.duration}s`);
|
|
18258
|
+
if (item.source) meta.push(item.source);
|
|
18259
|
+
if (meta.length) allLines.push(` ${meta.join(" | ")}`);
|
|
18260
|
+
if (item.attribution) allLines.push(` Attribution: ${item.attribution}`);
|
|
18220
18261
|
allLines.push("");
|
|
18221
18262
|
}
|
|
18222
18263
|
}
|
|
@@ -18838,4 +18879,4 @@ export {
|
|
|
18838
18879
|
JSONRPCMessageSchema,
|
|
18839
18880
|
createServer
|
|
18840
18881
|
};
|
|
18841
|
-
//# sourceMappingURL=chunk-
|
|
18882
|
+
//# sourceMappingURL=chunk-HQGYGAE4.js.map
|