@clipform/mcp-server 1.37.0 → 1.39.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 +6 -4
- package/dist/chunk-4DWK5GA5.js +139 -0
- package/dist/chunk-4DWK5GA5.js.map +1 -0
- package/dist/{chunk-5L2KPKOE.js → chunk-IBTTDNN6.js} +48 -12
- package/dist/{chunk-5L2KPKOE.js.map → chunk-IBTTDNN6.js.map} +1 -1
- package/dist/{chunk-XOYZMNJD.js → chunk-IXQRUFZM.js} +2 -2
- package/dist/{chunk-UA3MYEUA.js → chunk-MESJBHZL.js} +8 -5
- package/dist/chunk-MESJBHZL.js.map +1 -0
- package/dist/index.js +4 -4
- package/dist/prompts.js +2 -2
- package/dist/resources.d.ts +1 -2
- package/dist/resources.js +2 -4
- package/dist/server.d.ts +7 -0
- package/dist/server.js +4 -4
- package/package.json +3 -2
- package/dist/chunk-AZ33QQ4H.js +0 -601
- package/dist/chunk-AZ33QQ4H.js.map +0 -1
- package/dist/chunk-UA3MYEUA.js.map +0 -1
- /package/dist/{chunk-XOYZMNJD.js.map → chunk-IXQRUFZM.js.map} +0 -0
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# @clipform/mcp-server
|
|
1
|
+
# @clipform/mcp-server
|
|
2
2
|
|
|
3
3
|
MCP server for [Clipform](https://clipform.io) - build and manage video-style forms from any MCP client (Claude, ChatGPT, Cursor, Windsurf, etc.).
|
|
4
4
|
|
|
@@ -10,9 +10,9 @@ There are two ways to connect: **remote** (recommended, uses your Clipform accou
|
|
|
10
10
|
|
|
11
11
|
Use this if you have a Clipform account. Forms are created directly in your workspace and your plan tier applies (no 3-node cap on Pro).
|
|
12
12
|
|
|
13
|
-
**Claude (claude.ai):** Settings
|
|
13
|
+
**Claude (claude.ai):** Settings → Connectors → Add custom connector → enter `https://mcp.clipform.io`
|
|
14
14
|
|
|
15
|
-
**ChatGPT:** Settings
|
|
15
|
+
**ChatGPT:** Settings → Connectors → Advanced → enable Developer Mode → Create connector → enter `https://mcp.clipform.io` (requires Pro/Team/Enterprise)
|
|
16
16
|
|
|
17
17
|
**Any MCP client with OAuth:** Point it at `https://mcp.clipform.io` - discovery, registration, and auth are handled automatically via OAuth 2.1 + Dynamic Client Registration (RFC 7591).
|
|
18
18
|
|
|
@@ -87,7 +87,7 @@ You can also pass the key as a CLI flag: `npx -y @clipform/mcp-server --api-key=
|
|
|
87
87
|
| `clipform_render_composition` | Render a video composition to MP4 or PNG - flag reveals, emoji puzzles, grids, timelines, map motion and more. Pass `wait: false` to fire renders in parallel and poll for results |
|
|
88
88
|
| `clipform_generate_tts` | Generate narration audio with word-level captions |
|
|
89
89
|
| `clipform_generate_slideshow` | Create slideshow videos from images + audio (waits, returns URL) |
|
|
90
|
-
| `clipform_generate_video` | Generate video from images, clips, or both synced to audio. Pass `wait: false` to fire renders in parallel and poll for results |
|
|
90
|
+
| `clipform_generate_video` | Generate video from images, clips, or both synced to audio. Supports a looping background-audio bed (crowd noise, ambience) and print-style texture overlays. Pass `wait: false` to fire renders in parallel and poll for results |
|
|
91
91
|
| `clipform_check_render` | Check status of a render started with `wait: false` |
|
|
92
92
|
| `clipform_search_media` | Search royalty-free images and videos, with orientation filter and alt-text descriptions |
|
|
93
93
|
| `clipform_search_music` | Search royalty-free music and ambient sounds |
|
|
@@ -113,3 +113,5 @@ Forms are created with a start node and end screen automatically - you just add
|
|
|
113
113
|
|
|
114
114
|
- [Clipform](https://clipform.io) - Create interactive video forms
|
|
115
115
|
- [Documentation](https://clipform.io/docs/guides/mcp) - Full guide with node types, scoring, and more
|
|
116
|
+
|
|
117
|
+
> Craft guides (`clipform://guides/*`, `clipform_get_guide`) are fetched from the Clipform API at runtime, so the server needs a reachable `API_URL` and valid `CLIPFORM_API_KEY` to serve them.
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ALL_VARIANTS,
|
|
3
|
+
FORM_TYPE_KEYS,
|
|
4
|
+
callApi,
|
|
5
|
+
getSessionContext
|
|
6
|
+
} from "./chunk-MESJBHZL.js";
|
|
7
|
+
|
|
8
|
+
// src/lib/guides.ts
|
|
9
|
+
var guidesPromise = null;
|
|
10
|
+
async function loadGuides() {
|
|
11
|
+
const result = await callApi("/internal/mcp/guides", { method: "GET" });
|
|
12
|
+
if (!result.ok) {
|
|
13
|
+
throw new Error(`Failed to load guides: ${result.error}`);
|
|
14
|
+
}
|
|
15
|
+
const guides = result.data.guides ?? [];
|
|
16
|
+
return new Map(guides.map((g) => [g.uri, g]));
|
|
17
|
+
}
|
|
18
|
+
async function fetchGuideText(uri) {
|
|
19
|
+
if (!guidesPromise) {
|
|
20
|
+
guidesPromise = loadGuides();
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
const guides = await guidesPromise;
|
|
24
|
+
return guides.get(uri)?.text ?? null;
|
|
25
|
+
} catch (err) {
|
|
26
|
+
guidesPromise = null;
|
|
27
|
+
console.error(`[guides] Failed to fetch ${uri}: ${err instanceof Error ? err.message : String(err)}`);
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function guideFallbackText(uri) {
|
|
32
|
+
return [
|
|
33
|
+
`# Guide unavailable`,
|
|
34
|
+
``,
|
|
35
|
+
`The craft guide (${uri}) could not be loaded from the Clipform API.`,
|
|
36
|
+
`Guides are served at runtime and need a reachable API with a valid key -`,
|
|
37
|
+
`check API_URL and CLIPFORM_API_KEY, then try again.`,
|
|
38
|
+
``,
|
|
39
|
+
`General principles in the meantime: write narration for the ear (short,`,
|
|
40
|
+
`conversational), never reveal answers in narration or media, and keep`,
|
|
41
|
+
`forms tight - every question must earn its place.`
|
|
42
|
+
].join("\n");
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// src/resources.ts
|
|
46
|
+
var GUIDE_TYPES = FORM_TYPE_KEYS;
|
|
47
|
+
var QUIZ_VARIANTS = ALL_VARIANTS;
|
|
48
|
+
var GUIDE_DESCRIPTIONS = {
|
|
49
|
+
"quiz": "Craft knowledge for writing engaging quizzes - difficulty curves, question psychology, narration style, scoring",
|
|
50
|
+
"survey": "Craft knowledge for feedback surveys, NPS, and research forms - brevity, rating scales, respondent fatigue",
|
|
51
|
+
"interview": "Craft knowledge for building interview forms - warm-up pacing, open questions, consent, video responses",
|
|
52
|
+
"funnel": "Craft knowledge for lead qualification funnels - planned feature, conditional routing coming soon",
|
|
53
|
+
"testimonial": "Craft knowledge for collecting testimonials and customer stories on video - storytelling prompts, comfort techniques, consent",
|
|
54
|
+
"application": "Craft knowledge for application and evaluation forms - multi-section structure, video responses for behavioural questions, screening",
|
|
55
|
+
"booking": "Craft knowledge for event registration and booking forms - minimal friction, video welcome, confirmation flow"
|
|
56
|
+
};
|
|
57
|
+
var QUIZ_VARIANT_DESCRIPTIONS = {
|
|
58
|
+
"personality": "Addendum for personality quizzes - category design, option weighting, outcome writing, no right/wrong answers",
|
|
59
|
+
"comprehension": "Addendum for YouTube comprehension quizzes - extracting questions from transcripts, distractor design, audience adaptation",
|
|
60
|
+
"composition": "Addendum for composition quizzes - guess-and-reveal formats built from rendered compositions: mechanic selection, the clue/reveal node pair, difficulty design"
|
|
61
|
+
};
|
|
62
|
+
function getGuideUri(type, variant) {
|
|
63
|
+
if (type === "quiz" && variant) {
|
|
64
|
+
return `clipform://guides/quiz/${variant}`;
|
|
65
|
+
}
|
|
66
|
+
return `clipform://guides/${type}`;
|
|
67
|
+
}
|
|
68
|
+
async function readGuide(uri) {
|
|
69
|
+
return await fetchGuideText(uri) ?? guideFallbackText(uri);
|
|
70
|
+
}
|
|
71
|
+
function registerResources(server) {
|
|
72
|
+
for (const type of GUIDE_TYPES) {
|
|
73
|
+
server.registerResource(
|
|
74
|
+
`guide-${type}`,
|
|
75
|
+
getGuideUri(type),
|
|
76
|
+
{
|
|
77
|
+
description: GUIDE_DESCRIPTIONS[type],
|
|
78
|
+
mimeType: "text/markdown",
|
|
79
|
+
annotations: { audience: ["assistant"], priority: 0.8 }
|
|
80
|
+
},
|
|
81
|
+
async () => ({
|
|
82
|
+
contents: [{
|
|
83
|
+
uri: getGuideUri(type),
|
|
84
|
+
mimeType: "text/markdown",
|
|
85
|
+
text: await readGuide(getGuideUri(type))
|
|
86
|
+
}]
|
|
87
|
+
})
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
for (const variant of QUIZ_VARIANTS) {
|
|
91
|
+
server.registerResource(
|
|
92
|
+
`guide-quiz-${variant}`,
|
|
93
|
+
getGuideUri("quiz", variant),
|
|
94
|
+
{
|
|
95
|
+
description: QUIZ_VARIANT_DESCRIPTIONS[variant],
|
|
96
|
+
mimeType: "text/markdown",
|
|
97
|
+
annotations: { audience: ["assistant"], priority: 0.8 }
|
|
98
|
+
},
|
|
99
|
+
async () => ({
|
|
100
|
+
contents: [{
|
|
101
|
+
uri: getGuideUri("quiz", variant),
|
|
102
|
+
mimeType: "text/markdown",
|
|
103
|
+
text: await readGuide(getGuideUri("quiz", variant))
|
|
104
|
+
}]
|
|
105
|
+
})
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
server.registerResource(
|
|
109
|
+
"context-session",
|
|
110
|
+
"clipform://context/session",
|
|
111
|
+
{
|
|
112
|
+
description: "Current session info: auth mode, workspace, plan tier, node limits, feature flags. Read this before planning content to know your constraints.",
|
|
113
|
+
mimeType: "text/markdown",
|
|
114
|
+
annotations: { audience: ["assistant"], priority: 1 }
|
|
115
|
+
},
|
|
116
|
+
async () => {
|
|
117
|
+
const text = await getSessionContext();
|
|
118
|
+
return {
|
|
119
|
+
contents: [
|
|
120
|
+
{
|
|
121
|
+
uri: "clipform://context/session",
|
|
122
|
+
mimeType: "text/markdown",
|
|
123
|
+
text: text || "Session context unavailable - API may not be reachable."
|
|
124
|
+
}
|
|
125
|
+
]
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export {
|
|
132
|
+
fetchGuideText,
|
|
133
|
+
guideFallbackText,
|
|
134
|
+
GUIDE_TYPES,
|
|
135
|
+
QUIZ_VARIANTS,
|
|
136
|
+
getGuideUri,
|
|
137
|
+
registerResources
|
|
138
|
+
};
|
|
139
|
+
//# sourceMappingURL=chunk-4DWK5GA5.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/guides.ts","../src/resources.ts"],"sourcesContent":["import { callApi } from \"./api-client.js\";\n\n/**\n * Craft guide bodies live server-side (#470) - the npm package is a shim\n * that fetches them at runtime instead of bundling them in the tarball.\n * One fetch per process (all ~30KB of guides in a single response), cached;\n * a failed fetch is NOT cached so the next read retries.\n */\n\nexport interface RemoteGuide {\n type: string;\n variant: string | null;\n uri: string;\n mimeType: string;\n text: string;\n}\n\nlet guidesPromise: Promise<Map<string, RemoteGuide>> | null = null;\n\nasync function loadGuides(): Promise<Map<string, RemoteGuide>> {\n const result = await callApi(\"/internal/mcp/guides\", { method: \"GET\" });\n if (!result.ok) {\n throw new Error(`Failed to load guides: ${result.error}`);\n }\n const guides = (result.data as { guides?: RemoteGuide[] }).guides ?? [];\n return new Map(guides.map((g) => [g.uri, g]));\n}\n\n/** Fetch a guide body by its clipform:// URI. Returns null when unavailable. */\nexport async function fetchGuideText(uri: string): Promise<string | null> {\n if (!guidesPromise) {\n guidesPromise = loadGuides();\n }\n try {\n const guides = await guidesPromise;\n return guides.get(uri)?.text ?? null;\n } catch (err) {\n guidesPromise = null; // don't cache failures - retry on the next read\n // Loud, not silent: a misconfigured API_URL/key otherwise degrades every\n // guide to the stub with nothing in the logs.\n console.error(`[guides] Failed to fetch ${uri}: ${err instanceof Error ? err.message : String(err)}`);\n return null;\n }\n}\n\n/** Shown in place of a guide when the API is unreachable or unauthenticated. */\nexport function guideFallbackText(uri: string): string {\n return [\n `# Guide unavailable`,\n ``,\n `The craft guide (${uri}) could not be loaded from the Clipform API.`,\n `Guides are served at runtime and need a reachable API with a valid key -`,\n `check API_URL and CLIPFORM_API_KEY, then try again.`,\n ``,\n `General principles in the meantime: write narration for the ear (short,`,\n `conversational), never reveal answers in narration or media, and keep`,\n `forms tight - every question must earn its place.`,\n ].join(\"\\n\");\n}\n","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// Guide BODIES are not bundled here (#470): the npm tarball ships only this\n// registration metadata. Text is fetched from the API at runtime - see\n// lib/guides.ts (cached per process, stub fallback when unreachable).\nimport { fetchGuideText, guideFallbackText } from \"./lib/guides.js\";\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 \"composition\": \"Addendum for composition quizzes - guess-and-reveal formats built from rendered compositions: mechanic selection, the clue/reveal node pair, difficulty design\",\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\nasync function readGuide(uri: string): Promise<string> {\n return (await fetchGuideText(uri)) ?? guideFallbackText(uri);\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: await readGuide(getGuideUri(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: await readGuide(getGuideUri(\"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":[]}
|
|
@@ -6,14 +6,15 @@ import {
|
|
|
6
6
|
getWorkflowText,
|
|
7
7
|
objectType,
|
|
8
8
|
registerPrompts
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-IXQRUFZM.js";
|
|
10
10
|
import {
|
|
11
11
|
GUIDE_TYPES,
|
|
12
12
|
QUIZ_VARIANTS,
|
|
13
|
-
|
|
13
|
+
fetchGuideText,
|
|
14
14
|
getGuideUri,
|
|
15
|
+
guideFallbackText,
|
|
15
16
|
registerResources
|
|
16
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-4DWK5GA5.js";
|
|
17
18
|
import {
|
|
18
19
|
BUSINESS,
|
|
19
20
|
CONTACT_FIELDS,
|
|
@@ -22,6 +23,7 @@ import {
|
|
|
22
23
|
KEN_BURNS_EFFECTS,
|
|
23
24
|
KEN_BURNS_FIT_MODES,
|
|
24
25
|
KEN_BURNS_PRESETS,
|
|
26
|
+
MCP_TOOL_TIERS,
|
|
25
27
|
NODE_TYPES,
|
|
26
28
|
NON_COUNTABLE_TYPES,
|
|
27
29
|
SLIDESHOW_TRANSITIONS,
|
|
@@ -29,7 +31,7 @@ import {
|
|
|
29
31
|
errorResult,
|
|
30
32
|
resolveFormType,
|
|
31
33
|
textResult
|
|
32
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-MESJBHZL.js";
|
|
33
35
|
import {
|
|
34
36
|
__commonJS,
|
|
35
37
|
__export,
|
|
@@ -16984,7 +16986,6 @@ var END_SCREEN_ICONS = _endScreen.icon.enum;
|
|
|
16984
16986
|
var END_SCREEN_CTA_TYPES = _endScreen.cta_type.enum;
|
|
16985
16987
|
var PUBLIC_COMPOSITIONS = [
|
|
16986
16988
|
"Map",
|
|
16987
|
-
"MapPin",
|
|
16988
16989
|
"Grid",
|
|
16989
16990
|
"GridList",
|
|
16990
16991
|
"ObscuredReveal",
|
|
@@ -17005,9 +17006,21 @@ var PUBLIC_COMPOSITIONS = [
|
|
|
17005
17006
|
];
|
|
17006
17007
|
var LABS_COMPOSITIONS = [
|
|
17007
17008
|
"StatCounter",
|
|
17008
|
-
"ListReveal"
|
|
17009
|
+
"ListReveal",
|
|
17010
|
+
"Scene",
|
|
17011
|
+
"Spin3D"
|
|
17012
|
+
];
|
|
17013
|
+
var SOCIAL_COMPOSITIONS = [
|
|
17014
|
+
"ShortFormQuiz",
|
|
17015
|
+
"ScorecardQuiz",
|
|
17016
|
+
"ScorecardGK",
|
|
17017
|
+
"CountrySilhouetteQuiz"
|
|
17018
|
+
];
|
|
17019
|
+
var EXPOSED_COMPOSITIONS = [
|
|
17020
|
+
...PUBLIC_COMPOSITIONS,
|
|
17021
|
+
...process.env.CLIPFORM_LABS === "1" ? LABS_COMPOSITIONS : [],
|
|
17022
|
+
...process.env.CLIPFORM_SOCIAL === "1" ? SOCIAL_COMPOSITIONS : []
|
|
17009
17023
|
];
|
|
17010
|
-
var EXPOSED_COMPOSITIONS = process.env.CLIPFORM_LABS === "1" ? [...PUBLIC_COMPOSITIONS, ...LABS_COMPOSITIONS] : PUBLIC_COMPOSITIONS;
|
|
17011
17024
|
|
|
17012
17025
|
// src/lib/schemas.ts
|
|
17013
17026
|
var ACTIVE_NODE_TYPES = Object.entries(NODE_TYPES).filter(([, def]) => def.is_active && !def.is_system).map(([type]) => type);
|
|
@@ -18381,7 +18394,7 @@ For multi-render builds (e.g. composition quizzes with a clue + reveal clip per
|
|
|
18381
18394
|
inputSchema: {
|
|
18382
18395
|
compositionId: external_exports.string().describe(`The composition ID. Call clipform_list_compositions to see available options (e.g. ${EXPOSED_COMPOSITIONS.map((id) => `'${id}'`).join(", ")})`),
|
|
18383
18396
|
outputFormat: external_exports.enum(["mp4", "png"]).default("mp4").describe("Output format (default: mp4)"),
|
|
18384
|
-
inputProps: external_exports.record(external_exports.unknown()).optional().describe("Props object matching the composition's schema from clipform_list_compositions. Validated STRICTLY - unknown or missing props fail with the schema in the error, nothing renders silently with defaults. For map compositions (Map), round lat/lng to 1 decimal place
|
|
18397
|
+
inputProps: external_exports.record(external_exports.unknown()).optional().describe("Props object matching the composition's schema from clipform_list_compositions. Validated STRICTLY - unknown or missing props fail with the schema in the error, nothing renders silently with defaults. For map compositions (Map), wide shots (camera.zoom < 9) may round lat/lng to 1 decimal place to improve cache hit rates; close shots and pin drops should keep full precision \u2014 the pin lands exactly on `target`."),
|
|
18385
18398
|
wait: external_exports.boolean().optional().default(true).describe("true (default) blocks until the render is ready and returns its URL. false returns a job ID immediately - fire all renders first, then poll clipform_check_render. Use false whenever rendering more than one clip.")
|
|
18386
18399
|
},
|
|
18387
18400
|
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false }
|
|
@@ -18594,6 +18607,8 @@ For multi-question builds, pass wait: false on every render: each call returns a
|
|
|
18594
18607
|
})
|
|
18595
18608
|
).min(1).max(20).describe("Media items (images, video clips, or a mix)"),
|
|
18596
18609
|
audio_url: external_exports.string().url().optional().describe("Audio track URL. Video duration matches audio duration."),
|
|
18610
|
+
background_audio_url: external_exports.string().url().optional().describe("Ambience/music bed under the narration (crowd noise, room tone). Loops to fill the video. Find tracks with clipform_search_music."),
|
|
18611
|
+
background_audio_volume: external_exports.number().min(0).max(1).optional().describe("Background bed volume 0-1 (default 0.15 - sits under speech)"),
|
|
18597
18612
|
duration_seconds: external_exports.number().positive().optional().describe("Video duration in seconds (required if no audio_url)"),
|
|
18598
18613
|
random_effects: external_exports.boolean().optional().default(true).describe("Shuffle Ken Burns effects across image items (default: true)"),
|
|
18599
18614
|
transition: external_exports.object({
|
|
@@ -18601,23 +18616,40 @@ For multi-question builds, pass wait: false on every render: each call returns a
|
|
|
18601
18616
|
duration: external_exports.number().optional().default(1).describe("Transition duration in seconds (default: 1)")
|
|
18602
18617
|
}).optional(),
|
|
18603
18618
|
style_preset: STYLE_PRESET_ENUM.optional(),
|
|
18619
|
+
texture: external_exports.object({
|
|
18620
|
+
type: external_exports.enum(["checker", "halftone", "scanlines"]).describe("checker = square dither mesh, halftone = dot grid, scanlines = horizontal lines"),
|
|
18621
|
+
sizePx: external_exports.number().positive().optional().describe("Pattern cell size in px (default 4)"),
|
|
18622
|
+
opacity: external_exports.number().min(0).max(1).optional().describe("Pattern darkness 0-1 (default 0.35)")
|
|
18623
|
+
}).optional().describe("Print-style pattern overlay on image items - makes stock imagery read as designed (screen-print dither look)"),
|
|
18624
|
+
duotone: external_exports.object({
|
|
18625
|
+
shadow: external_exports.string().describe("Darker tone (maps to image shadows), e.g. '#1a1633'"),
|
|
18626
|
+
highlight: external_exports.string().describe("Lighter tone (maps to image highlights), e.g. '#f5c542'"),
|
|
18627
|
+
contrast: external_exports.number().positive().optional().describe("Contrast boost before mapping (default 1.1)")
|
|
18628
|
+
}).optional().describe("Two-tone editorial recolour on image items - desaturates then maps to a shadow->highlight palette. Pair with a halftone texture for a screen-print poster look."),
|
|
18604
18629
|
background_color: external_exports.string().optional().describe("Background color (default '#000')"),
|
|
18605
18630
|
wait: external_exports.boolean().optional().default(true).describe("true (default) blocks until the video is ready and returns its URL. false returns a job ID immediately - fire all renders first, then poll clipform_check_render. Use false whenever rendering more than one video.")
|
|
18606
18631
|
},
|
|
18607
18632
|
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true }
|
|
18608
18633
|
},
|
|
18609
|
-
async ({ items, audio_url, duration_seconds, random_effects, transition, style_preset, background_color, wait }) => {
|
|
18634
|
+
async ({ items, audio_url, background_audio_url, background_audio_volume, duration_seconds, random_effects, transition, style_preset, texture, duotone, background_color, wait }) => {
|
|
18610
18635
|
const workspace_id = getMcpAuth()?.workspace_id;
|
|
18636
|
+
const default_style = style_preset || texture || duotone ? {
|
|
18637
|
+
...style_preset ? { preset: style_preset } : {},
|
|
18638
|
+
...texture ? { texture } : {},
|
|
18639
|
+
...duotone ? { duotone } : {}
|
|
18640
|
+
} : void 0;
|
|
18611
18641
|
const apiCall = () => callApi("/internal/generate-video", {
|
|
18612
18642
|
timeoutMs: 3e5,
|
|
18613
18643
|
// local renders pay a cold webpack bundle; Lambda is fast but bursty
|
|
18614
18644
|
body: {
|
|
18615
18645
|
items,
|
|
18616
18646
|
audio_url,
|
|
18647
|
+
background_audio_url,
|
|
18648
|
+
background_audio_volume,
|
|
18617
18649
|
duration_seconds,
|
|
18618
18650
|
random_effects: random_effects ?? true,
|
|
18619
18651
|
transition: transition ?? { type: "fade", duration: 1 },
|
|
18620
|
-
default_style
|
|
18652
|
+
default_style,
|
|
18621
18653
|
background_color,
|
|
18622
18654
|
workspace_id
|
|
18623
18655
|
}
|
|
@@ -18845,8 +18877,8 @@ Quiz variants (optional): ${QUIZ_VARIANTS.join(", ")} - appends variant-specific
|
|
|
18845
18877
|
}
|
|
18846
18878
|
const type = resolved;
|
|
18847
18879
|
const validVariant = type === "quiz" ? variant : void 0;
|
|
18848
|
-
const content = getGuideContent(type, validVariant);
|
|
18849
18880
|
const uri = getGuideUri(type, validVariant);
|
|
18881
|
+
const content = await fetchGuideText(uri) ?? guideFallbackText(uri);
|
|
18850
18882
|
return {
|
|
18851
18883
|
content: [{
|
|
18852
18884
|
type: "resource",
|
|
@@ -18954,6 +18986,10 @@ function createServer(options) {
|
|
|
18954
18986
|
);
|
|
18955
18987
|
const _registerTool = server.registerTool.bind(server);
|
|
18956
18988
|
server.registerTool = (name, config2, handler) => {
|
|
18989
|
+
const requiredTier = MCP_TOOL_TIERS[name] ?? 0;
|
|
18990
|
+
if (options?.planTier !== void 0 && requiredTier > options.planTier) {
|
|
18991
|
+
return void 0;
|
|
18992
|
+
}
|
|
18957
18993
|
return _registerTool(
|
|
18958
18994
|
name,
|
|
18959
18995
|
config2,
|
|
@@ -19004,4 +19040,4 @@ export {
|
|
|
19004
19040
|
JSONRPCMessageSchema,
|
|
19005
19041
|
createServer
|
|
19006
19042
|
};
|
|
19007
|
-
//# sourceMappingURL=chunk-
|
|
19043
|
+
//# sourceMappingURL=chunk-IBTTDNN6.js.map
|