@clipform/mcp-server 1.5.1 → 1.7.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 +21 -9
- package/dist/lib/api-client.d.ts +1 -1
- package/dist/lib/api-client.js +21 -5
- package/dist/lib/api-client.js.map +1 -1
- package/dist/lib/auth-context.d.ts +17 -0
- package/dist/lib/auth-context.js +9 -0
- package/dist/lib/auth-context.js.map +1 -0
- package/dist/lib/session-context.d.ts +1 -0
- package/dist/lib/session-context.js +32 -0
- package/dist/lib/session-context.js.map +1 -0
- package/dist/prompts.js +241 -125
- package/dist/prompts.js.map +1 -1
- package/dist/resources.d.ts +2 -0
- package/dist/resources.js +336 -0
- package/dist/resources.js.map +1 -0
- package/dist/server.js +6 -2
- package/dist/server.js.map +1 -1
- package/dist/tools/add-question.js +2 -2
- package/dist/tools/add-question.js.map +1 -1
- package/dist/tools/attach-question-audio.js +2 -2
- package/dist/tools/attach-question-audio.js.map +1 -1
- package/dist/tools/create-form.js +65 -12
- package/dist/tools/create-form.js.map +1 -1
- package/dist/tools/delete-form.js +2 -2
- package/dist/tools/delete-form.js.map +1 -1
- package/dist/tools/delete-question-media.js +2 -2
- package/dist/tools/delete-question-media.js.map +1 -1
- package/dist/tools/delete-question.js +2 -2
- package/dist/tools/delete-question.js.map +1 -1
- package/dist/tools/generate-slideshow.js +114 -17
- package/dist/tools/generate-slideshow.js.map +1 -1
- package/dist/tools/generate-tts.js +3 -2
- package/dist/tools/generate-tts.js.map +1 -1
- package/dist/tools/generate-video.d.ts +2 -0
- package/dist/tools/generate-video.js +113 -0
- package/dist/tools/generate-video.js.map +1 -0
- package/dist/tools/get-form.js +1 -1
- package/dist/tools/get-form.js.map +1 -1
- package/dist/tools/get-question-media.js +2 -2
- package/dist/tools/get-question-media.js.map +1 -1
- package/dist/tools/list-assets.js +1 -1
- package/dist/tools/list-assets.js.map +1 -1
- package/dist/tools/list-compositions.js +3 -3
- package/dist/tools/list-compositions.js.map +1 -1
- package/dist/tools/log-generation.js +3 -3
- package/dist/tools/log-generation.js.map +1 -1
- package/dist/tools/render-composition.js +6 -4
- package/dist/tools/render-composition.js.map +1 -1
- package/dist/tools/search-media.js +1 -1
- package/dist/tools/search-media.js.map +1 -1
- package/dist/tools/search-music.js +1 -1
- package/dist/tools/search-music.js.map +1 -1
- package/dist/tools/search-news.js +1 -1
- package/dist/tools/search-news.js.map +1 -1
- package/dist/tools/set-question-logic.js +2 -2
- package/dist/tools/set-question-logic.js.map +1 -1
- package/dist/tools/update-form.js +39 -3
- package/dist/tools/update-form.js.map +1 -1
- package/dist/tools/update-question.js +2 -2
- package/dist/tools/update-question.js.map +1 -1
- package/dist/tools/upload-question-media.js +14 -6
- package/dist/tools/upload-question-media.js.map +1 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -4,19 +4,29 @@ MCP server for [Clipform](https://clipform.io) - build and manage video-style fo
|
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
There are two ways to connect: **remote** (recommended, uses your Clipform account) and **local** (anonymous, free-tier limits).
|
|
8
|
+
|
|
9
|
+
### Remote - claude.ai (recommended)
|
|
10
|
+
|
|
11
|
+
Use this if you have a Clipform account. Forms are created directly in your workspace and your plan tier applies (no 3-question cap on Pro).
|
|
12
|
+
|
|
13
|
+
1. In claude.ai, open **Settings → Connectors → Add custom connector**.
|
|
14
|
+
2. Enter the MCP URL: `https://mcp.clipform.io`
|
|
15
|
+
3. Follow the OAuth prompts. You'll be redirected to Clipform to sign in and pick a workspace.
|
|
10
16
|
|
|
11
|
-
|
|
17
|
+
No install or config file needed - claude.ai handles discovery and registration automatically via OAuth 2.1 + Dynamic Client Registration (RFC 7591).
|
|
18
|
+
|
|
19
|
+
### Local - Claude Code / Claude Desktop
|
|
20
|
+
|
|
21
|
+
Use this for local development or if you don't have a Clipform account. Forms go into a shared anonymous workspace with the free-tier 3-question limit, and you claim them afterwards via the claim URL.
|
|
22
|
+
|
|
23
|
+
**Claude Code:**
|
|
12
24
|
|
|
13
25
|
```bash
|
|
14
26
|
claude mcp add clipform -- npx -y @clipform/mcp-server
|
|
15
27
|
```
|
|
16
28
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
Add to your `claude_desktop_config.json`:
|
|
29
|
+
**Claude Desktop** - add to `claude_desktop_config.json`:
|
|
20
30
|
|
|
21
31
|
```json
|
|
22
32
|
{
|
|
@@ -59,7 +69,7 @@ Add to your `claude_desktop_config.json`:
|
|
|
59
69
|
|------|-------------|
|
|
60
70
|
| `clipform_render_composition` | Render a Remotion composition to MP4, PNG, or GIF |
|
|
61
71
|
| `clipform_generate_tts` | Generate narration audio with word-level captions |
|
|
62
|
-
| `clipform_generate_slideshow` | Create
|
|
72
|
+
| `clipform_generate_slideshow` | Create slideshow videos from images + audio (director props: zoom, pan, easing, blur-pad, vignette, per-image style) |
|
|
63
73
|
| `clipform_search_media` | Search royalty-free images and videos |
|
|
64
74
|
| `clipform_search_music` | Search royalty-free music and ambient sounds |
|
|
65
75
|
| `clipform_list_compositions` | List available Remotion compositions and prop schemas |
|
|
@@ -71,7 +81,9 @@ Add to your `claude_desktop_config.json`:
|
|
|
71
81
|
|
|
72
82
|
## How it works
|
|
73
83
|
|
|
74
|
-
|
|
84
|
+
**Remote (claude.ai):** OAuth Bearer tokens are audience-bound to `https://mcp.clipform.io` (RFC 8707) and scoped to `mcp` only. Forms land directly in the workspace you approved during consent, and plan-tier limits come from that workspace's company.
|
|
85
|
+
|
|
86
|
+
**Local (npx):** When you create a form, you get back an `edit_token` that authorizes all subsequent changes. The token works until the form is claimed by a user via the claim URL.
|
|
75
87
|
|
|
76
88
|
Forms are created with a start node and end screen automatically - you just add the questions in between.
|
|
77
89
|
|
package/dist/lib/api-client.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ type ApiResult = {
|
|
|
15
15
|
export declare function callApi(path: string, options?: ApiOptions): Promise<ApiResult>;
|
|
16
16
|
/**
|
|
17
17
|
* Call an internal API endpoint (formgen, media, etc.)
|
|
18
|
-
* Uses
|
|
18
|
+
* Uses INTERNAL_SECRET for auth and INTERNAL_API_URL as base.
|
|
19
19
|
*/
|
|
20
20
|
export declare function callInternalApi(path: string, options?: Omit<ApiOptions, "token">): Promise<ApiResult>;
|
|
21
21
|
export declare function errorResult(message: string): {
|
package/dist/lib/api-client.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { getMcpAuth } from "./auth-context.js";
|
|
1
2
|
const DASHBOARD_URL = process.env.SERVER_URL || process.env.DASHBOARD_URL || "https://api.clipform.io";
|
|
2
3
|
const API_VERSION = "v1";
|
|
3
4
|
const INTERNAL_API_URL = process.env.INTERNAL_API_URL || DASHBOARD_URL;
|
|
4
|
-
const
|
|
5
|
+
const INTERNAL_SECRET = process.env.INTERNAL_SERVICE_SECRET || "";
|
|
5
6
|
export async function callApi(path, options = {}) {
|
|
6
7
|
const { method = "GET", body, params, token } = options;
|
|
7
8
|
let url = `${DASHBOARD_URL}/${API_VERSION}${path}`;
|
|
@@ -12,7 +13,22 @@ export async function callApi(path, options = {}) {
|
|
|
12
13
|
const headers = {
|
|
13
14
|
"Content-Type": "application/json",
|
|
14
15
|
};
|
|
15
|
-
|
|
16
|
+
// If the MCP server is running in-process inside the API host AND the
|
|
17
|
+
// request has been OAuth-authenticated, forward the end-user identity
|
|
18
|
+
// via internal headers instead of propagating the caller's Bearer.
|
|
19
|
+
//
|
|
20
|
+
// Token passthrough is forbidden by the MCP Authorization spec: the
|
|
21
|
+
// token that claude.ai presented was issued for audience `${api}/mcp`
|
|
22
|
+
// and must not be replayed against downstream routes like /v1/forms/*.
|
|
23
|
+
// Those routes instead trust the INTERNAL_SECRET + X-Mcp-User /
|
|
24
|
+
// X-Mcp-Workspace headers set below.
|
|
25
|
+
const mcpAuth = getMcpAuth();
|
|
26
|
+
if (mcpAuth && INTERNAL_SECRET) {
|
|
27
|
+
headers["Authorization"] = `Bearer ${INTERNAL_SECRET}`;
|
|
28
|
+
headers["X-Mcp-User"] = mcpAuth.user_id;
|
|
29
|
+
headers["X-Mcp-Workspace"] = mcpAuth.workspace_id;
|
|
30
|
+
}
|
|
31
|
+
else if (token) {
|
|
16
32
|
headers["Authorization"] = `Bearer ${token}`;
|
|
17
33
|
}
|
|
18
34
|
const fetchOptions = { method, headers };
|
|
@@ -46,7 +62,7 @@ export async function callApi(path, options = {}) {
|
|
|
46
62
|
}
|
|
47
63
|
/**
|
|
48
64
|
* Call an internal API endpoint (formgen, media, etc.)
|
|
49
|
-
* Uses
|
|
65
|
+
* Uses INTERNAL_SECRET for auth and INTERNAL_API_URL as base.
|
|
50
66
|
*/
|
|
51
67
|
export async function callInternalApi(path, options = {}) {
|
|
52
68
|
const { method = "POST", body, params } = options;
|
|
@@ -58,8 +74,8 @@ export async function callInternalApi(path, options = {}) {
|
|
|
58
74
|
const headers = {
|
|
59
75
|
"Content-Type": "application/json",
|
|
60
76
|
};
|
|
61
|
-
if (
|
|
62
|
-
headers["Authorization"] = `Bearer ${
|
|
77
|
+
if (INTERNAL_SECRET) {
|
|
78
|
+
headers["Authorization"] = `Bearer ${INTERNAL_SECRET}`;
|
|
63
79
|
}
|
|
64
80
|
const fetchOptions = { method, headers };
|
|
65
81
|
if (body && method !== "GET") {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-client.js","sourceRoot":"","sources":["../../src/lib/api-client.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"api-client.js","sourceRoot":"","sources":["../../src/lib/api-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Identity of the end-user a given MCP request is acting on behalf of.
|
|
3
|
+
*
|
|
4
|
+
* Populated by the in-process host (apps/api) after validating an OAuth
|
|
5
|
+
* Bearer on /mcp. The MCP tool layer reads it to decide which workspace
|
|
6
|
+
* forms should land in and which plan tier gates apply.
|
|
7
|
+
*
|
|
8
|
+
* NOT populated when the server runs as a local stdio process (npx) - in
|
|
9
|
+
* that mode tools fall back to edit-token based auth.
|
|
10
|
+
*/
|
|
11
|
+
export interface McpAuthContext {
|
|
12
|
+
user_id: string;
|
|
13
|
+
workspace_id: string;
|
|
14
|
+
scopes: string[];
|
|
15
|
+
}
|
|
16
|
+
export declare function runWithMcpAuth<T>(ctx: McpAuthContext, fn: () => Promise<T> | T): Promise<T> | T;
|
|
17
|
+
export declare function getMcpAuth(): McpAuthContext | undefined;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
const storage = new AsyncLocalStorage();
|
|
3
|
+
export function runWithMcpAuth(ctx, fn) {
|
|
4
|
+
return storage.run(ctx, fn);
|
|
5
|
+
}
|
|
6
|
+
export function getMcpAuth() {
|
|
7
|
+
return storage.getStore();
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=auth-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-context.js","sourceRoot":"","sources":["../../src/lib/auth-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAkBrD,MAAM,OAAO,GAAG,IAAI,iBAAiB,EAAkB,CAAC;AAExD,MAAM,UAAU,cAAc,CAAI,GAAmB,EAAE,EAAwB;IAC7E,OAAO,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,OAAO,OAAO,CAAC,QAAQ,EAAE,CAAC;AAC5B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function getSessionContext(): Promise<string>;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { BUSINESS } from "@vid-master/config";
|
|
2
|
+
import { callApi } from "./api-client.js";
|
|
3
|
+
export async function getSessionContext() {
|
|
4
|
+
const result = await callApi("/me", { method: "GET" });
|
|
5
|
+
if (!result.ok)
|
|
6
|
+
return "";
|
|
7
|
+
const me = result.data;
|
|
8
|
+
const plan = me.plan;
|
|
9
|
+
const lines = [];
|
|
10
|
+
lines.push("## Your Session");
|
|
11
|
+
if (me.auth_mode === "oauth") {
|
|
12
|
+
lines.push(`Workspace: ${me.workspace?.name ?? "Unknown"}`);
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
lines.push("Mode: anonymous (not connected to a Clipform account)");
|
|
16
|
+
}
|
|
17
|
+
lines.push(`Plan: ${plan.name}`);
|
|
18
|
+
if (plan.node_limit !== null) {
|
|
19
|
+
lines.push(`Question limit: ${plan.node_limit} per form`);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
lines.push("Questions: unlimited");
|
|
23
|
+
}
|
|
24
|
+
if (plan.custom_theme === false) {
|
|
25
|
+
lines.push("Custom themes: not available on this plan");
|
|
26
|
+
}
|
|
27
|
+
if (me.auth_mode !== "oauth") {
|
|
28
|
+
lines.push(`\nTo unlock your full plan: connect your Clipform account in Settings > Connectors > ${BUSINESS.urls.mcp}`);
|
|
29
|
+
}
|
|
30
|
+
return lines.join("\n");
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=session-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-context.js","sourceRoot":"","sources":["../../src/lib/session-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAE1C,MAAM,CAAC,KAAK,UAAU,iBAAiB;IACrC,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;IACvD,IAAI,CAAC,MAAM,CAAC,EAAE;QAAE,OAAO,EAAE,CAAC;IAE1B,MAAM,EAAE,GAAG,MAAM,CAAC,IAAW,CAAC;IAC9B,MAAM,IAAI,GAAG,EAAE,CAAC,IAAI,CAAC;IACrB,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,KAAK,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;IAC9B,IAAI,EAAE,CAAC,SAAS,KAAK,OAAO,EAAE,CAAC;QAC7B,KAAK,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC,SAAS,EAAE,IAAI,IAAI,SAAS,EAAE,CAAC,CAAC;IAC9D,CAAC;SAAM,CAAC;QACN,KAAK,CAAC,IAAI,CAAC,uDAAuD,CAAC,CAAC;IACtE,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;IACjC,IAAI,IAAI,CAAC,UAAU,KAAK,IAAI,EAAE,CAAC;QAC7B,KAAK,CAAC,IAAI,CAAC,mBAAmB,IAAI,CAAC,UAAU,WAAW,CAAC,CAAC;IAC5D,CAAC;SAAM,CAAC;QACN,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;IACrC,CAAC;IACD,IAAI,IAAI,CAAC,YAAY,KAAK,KAAK,EAAE,CAAC;QAChC,KAAK,CAAC,IAAI,CAAC,2CAA2C,CAAC,CAAC;IAC1D,CAAC;IACD,IAAI,EAAE,CAAC,SAAS,KAAK,OAAO,EAAE,CAAC;QAC7B,KAAK,CAAC,IAAI,CAAC,wFAAwF,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IAC1H,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
|
package/dist/prompts.js
CHANGED
|
@@ -1,135 +1,251 @@
|
|
|
1
|
+
import { getSessionContext } from "./lib/session-context.js";
|
|
1
2
|
export function registerPrompts(server) {
|
|
2
3
|
server.registerPrompt("create-quiz", {
|
|
3
|
-
title: "
|
|
4
|
-
description: "
|
|
5
|
-
}, async () =>
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
-
|
|
29
|
-
|
|
30
|
-
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
**
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
**
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
1. If your client exposes a native web search or web fetch tool (e.g. WebSearch / WebFetch), use that - it is broader and more current.
|
|
46
|
-
2. Otherwise, use clipform_search_news for structured current-news results.
|
|
47
|
-
3. If neither is available, REFUSE rather than fabricate. Tell the user you cannot verify facts about that topic and suggest they provide the source material.
|
|
48
|
-
|
|
49
|
-
Never invent dates, names, statistics, or event details you are not sure of. It is always better to refuse a question than to ship a hallucinated one.
|
|
50
|
-
|
|
51
|
-
**Narration style:**
|
|
52
|
-
- The TTS narration should only read the question - do NOT repeat the answer options verbally. The options are displayed on screen for the user to read and tap.
|
|
53
|
-
- Keep narration concise and conversational. Add a brief interesting fact or context if it fits naturally.
|
|
54
|
-
|
|
55
|
-
**Audit log (final step):**
|
|
56
|
-
After building the quiz, call clipform_log_generation with:
|
|
57
|
-
- summary of what was built
|
|
58
|
-
- sources used for research (Wikipedia articles, URLs)
|
|
59
|
-
- images used with attribution and license
|
|
60
|
-
|
|
61
|
-
**Before building, ask the user:**
|
|
4
|
+
title: "Create a Quiz",
|
|
5
|
+
description: "Build a scored knowledge quiz with narrated video questions",
|
|
6
|
+
}, async () => {
|
|
7
|
+
const sessionContext = await getSessionContext();
|
|
8
|
+
return {
|
|
9
|
+
messages: [
|
|
10
|
+
{
|
|
11
|
+
role: "user",
|
|
12
|
+
content: {
|
|
13
|
+
type: "text",
|
|
14
|
+
text: "I want to create a quiz. What's the best approach?",
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
role: "assistant",
|
|
19
|
+
content: {
|
|
20
|
+
type: "text",
|
|
21
|
+
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.
|
|
22
|
+
|
|
23
|
+
## Workflow
|
|
24
|
+
|
|
25
|
+
1. **Research** the topic - find surprising facts, common misconceptions, myth-busters
|
|
26
|
+
2. **Write questions** - follow the difficulty curve (easy start, hard middle, satisfying end). Target 5-8 questions.
|
|
27
|
+
3. **Create the form** with clipform_create_form:
|
|
28
|
+
- show_step_counter: true
|
|
29
|
+
- disable_back_navigation: true
|
|
30
|
+
4. **Add questions** with clipform_add_question (type: "choice"):
|
|
31
|
+
- config: { choice: { show_answer_feedback: true } }
|
|
32
|
+
- randomise_options: true in config
|
|
33
|
+
- score: 1 on correct option, score: 0 on wrong
|
|
34
|
+
- 3-4 wrong answers per question
|
|
35
|
+
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.
|
|
36
|
+
6. **Build video** for each question:
|
|
37
|
+
- clipform_search_media (kind: "image") - 3 images per question
|
|
38
|
+
- clipform_generate_video - creates Ken Burns video synced to audio
|
|
39
|
+
7. **Attach media** with clipform_upload_question_media. Include captions, set show_captions: true.
|
|
40
|
+
8. **Update end screen** - set show_score: true, icon: "trophy", and score_ranges for personalised messages
|
|
41
|
+
9. **Publish** with clipform_update_form
|
|
42
|
+
10. **Log** with clipform_log_generation (sources, images, attributions)
|
|
43
|
+
|
|
44
|
+
## Before building, ask
|
|
45
|
+
|
|
62
46
|
1. How many questions?
|
|
63
47
|
2. Media style: text only, still images, or slideshow video with narration?
|
|
64
48
|
3. Any topic or style preferences?`,
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
};
|
|
53
|
+
});
|
|
54
|
+
server.registerPrompt("create-personality-quiz", {
|
|
55
|
+
title: "Create a Personality Quiz",
|
|
56
|
+
description: "Build a 'Which X are you?' personality quiz with category-based scoring and outcome screens",
|
|
57
|
+
}, async () => {
|
|
58
|
+
const sessionContext = await getSessionContext();
|
|
59
|
+
return {
|
|
60
|
+
messages: [
|
|
61
|
+
{
|
|
62
|
+
role: "user",
|
|
63
|
+
content: {
|
|
64
|
+
type: "text",
|
|
65
|
+
text: "I want to create a personality quiz. What's the best approach?",
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
role: "assistant",
|
|
70
|
+
content: {
|
|
71
|
+
type: "text",
|
|
72
|
+
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.
|
|
73
|
+
|
|
74
|
+
## How it differs from a knowledge quiz
|
|
75
|
+
|
|
76
|
+
There are NO correct answers. Each option maps to one or more outcome categories via \`scores\` (not \`score\`). The winning category at the end determines which result screen the respondent sees.
|
|
77
|
+
|
|
78
|
+
## Workflow
|
|
79
|
+
|
|
80
|
+
1. **Define 3-5 outcome categories** - these are the "personalities" (e.g. "Creative", "Analytical", "Leader", "Collaborator"). More than 5 gets muddy.
|
|
81
|
+
2. **Write questions** - each question should feel revealing but fun. Target 5-8 questions.
|
|
82
|
+
3. **Create the form** with clipform_create_form:
|
|
83
|
+
- show_step_counter: true
|
|
84
|
+
- disable_back_navigation: true
|
|
85
|
+
4. **Add questions** with clipform_add_question (type: "choice"):
|
|
86
|
+
- config: { choice: { show_answer_feedback: false } } (no right/wrong!)
|
|
87
|
+
- Do NOT set randomise_options (option order matters for personality quizzes - lead with the most appealing)
|
|
88
|
+
- Each option gets \`scores: { "CategoryA": 2, "CategoryB": 1 }\` - weight towards relevant categories
|
|
89
|
+
- Every option should score in at least one category (no dead options)
|
|
90
|
+
5. **Generate narration** with clipform_generate_tts - conversational, reflective tone. "What does this say about you?" not "Do you know the answer?"
|
|
91
|
+
6. **Build video** + **attach media** (same as knowledge quiz workflow)
|
|
92
|
+
7. **Update end screen** with scoring_results (NOT score_ranges):
|
|
93
|
+
\`\`\`json
|
|
94
|
+
{
|
|
95
|
+
"show_score": false,
|
|
96
|
+
"icon": "star",
|
|
97
|
+
"scoring_results": [
|
|
98
|
+
{ "category": "Creative", "title": "You're a Creative!", "message": "You see the world differently..." },
|
|
99
|
+
{ "category": "Analytical", "title": "You're an Analyst!", "message": "You love digging into the details..." }
|
|
100
|
+
]
|
|
101
|
+
}
|
|
102
|
+
\`\`\`
|
|
103
|
+
8. **Publish** with clipform_update_form
|
|
104
|
+
9. **Log** with clipform_log_generation
|
|
105
|
+
|
|
106
|
+
## Before building, ask
|
|
107
|
+
|
|
108
|
+
1. What are the possible outcomes/personalities? (3-5 categories)
|
|
109
|
+
2. What's the theme? ("Which city are you?", "What's your work style?", "Which character are you?")
|
|
110
|
+
3. Media style: text only, still images, or slideshow video with narration?`,
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
],
|
|
114
|
+
};
|
|
115
|
+
});
|
|
116
|
+
server.registerPrompt("create-interview", {
|
|
117
|
+
title: "Create an Interview",
|
|
118
|
+
description: "Build a form to collect testimonials, case studies, async video interviews, or journalist responses",
|
|
119
|
+
}, async () => {
|
|
120
|
+
const sessionContext = await getSessionContext();
|
|
121
|
+
return {
|
|
122
|
+
messages: [
|
|
123
|
+
{
|
|
124
|
+
role: "user",
|
|
125
|
+
content: {
|
|
126
|
+
type: "text",
|
|
127
|
+
text: "I want to collect responses or testimonials from people. What's the best approach?",
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
role: "assistant",
|
|
132
|
+
content: {
|
|
133
|
+
type: "text",
|
|
134
|
+
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.
|
|
135
|
+
|
|
136
|
+
## Workflow
|
|
137
|
+
|
|
138
|
+
1. **Identify the ask** - what do you need from respondents? Testimonial, case study, expert comment, job application?
|
|
139
|
+
2. **Create the form** with clipform_create_form:
|
|
140
|
+
- show_step_counter: true
|
|
141
|
+
- disable_back_navigation: false
|
|
142
|
+
3. **Add a warm-up question** - something easy: "Tell us your name and role" (type: "open")
|
|
143
|
+
4. **Add core questions** (type: "open") - 2-3 max, one topic per question. Enable text + audio + video responses.
|
|
144
|
+
5. **Add contact collection** (type: "contact") - first name + email minimum
|
|
145
|
+
6. **Add consent** if needed - "I agree that my response may be used in [context]"
|
|
146
|
+
7. **Update end screen** - set expectations: "Thanks! We'll be in touch."
|
|
147
|
+
8. **Optional: add narration** - warm, inviting tone. "We'd love to hear your story..."
|
|
148
|
+
9. **Publish** with clipform_update_form
|
|
149
|
+
|
|
150
|
+
## Before building, ask
|
|
151
|
+
|
|
152
|
+
1. What are you collecting? (testimonial, case study, interview, application)
|
|
153
|
+
2. Should respondents reply with video, audio, text, or all three?
|
|
154
|
+
3. Do you need a consent statement?`,
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
],
|
|
158
|
+
};
|
|
159
|
+
});
|
|
160
|
+
server.registerPrompt("create-survey", {
|
|
161
|
+
title: "Create a Survey",
|
|
162
|
+
description: "Build a feedback survey, NPS form, or research questionnaire",
|
|
163
|
+
}, async () => {
|
|
164
|
+
const sessionContext = await getSessionContext();
|
|
165
|
+
return {
|
|
166
|
+
messages: [
|
|
167
|
+
{
|
|
168
|
+
role: "user",
|
|
169
|
+
content: {
|
|
170
|
+
type: "text",
|
|
171
|
+
text: "I want to collect feedback or run a survey. What's the best approach?",
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
role: "assistant",
|
|
176
|
+
content: {
|
|
177
|
+
type: "text",
|
|
178
|
+
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.
|
|
179
|
+
|
|
180
|
+
## Workflow
|
|
181
|
+
|
|
182
|
+
1. **Define the key metric** - what's the one number you care about? (NPS, satisfaction, likelihood to recommend)
|
|
183
|
+
2. **Create the form** with clipform_create_form:
|
|
184
|
+
- show_step_counter: true
|
|
185
|
+
- disable_back_navigation: false
|
|
186
|
+
3. **Add key metric question first** (type: "choice" or "rating") - put it first while attention is highest
|
|
187
|
+
4. **Add one "why?" follow-up** (type: "open") - "What's the main reason for your score?"
|
|
188
|
+
5. **Add 2-3 specific questions** (type: "choice") - only ask what you'll act on
|
|
189
|
+
6. **Contact** (optional) - only if you need to follow up. Many surveys work better anonymous.
|
|
190
|
+
7. **Update end screen** - "Thanks for your feedback!"
|
|
191
|
+
8. **Publish** with clipform_update_form
|
|
192
|
+
|
|
193
|
+
## Key rule: 5 questions max. Every extra question costs completions.
|
|
194
|
+
|
|
195
|
+
## Before building, ask
|
|
196
|
+
|
|
197
|
+
1. What feedback are you collecting? (NPS, satisfaction, event feedback, product research)
|
|
198
|
+
2. Anonymous or identified?
|
|
199
|
+
3. Any specific areas you want to ask about?`,
|
|
200
|
+
},
|
|
65
201
|
},
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
})
|
|
69
|
-
server.registerPrompt("create-
|
|
70
|
-
title: "
|
|
71
|
-
description: "
|
|
72
|
-
}, async () =>
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
text: `When creating a standard form or survey:
|
|
83
|
-
|
|
84
|
-
**Form settings:**
|
|
85
|
-
- Back navigation is enabled by default (respondents can review answers)
|
|
86
|
-
- Step counter is off by default (optional, enable for longer forms)
|
|
87
|
-
|
|
88
|
-
**Common patterns:**
|
|
89
|
-
- Use "contact" type for collecting user details (name, email, etc.)
|
|
90
|
-
- Use "open" type for free-text responses
|
|
91
|
-
- Use "choice" type for multiple choice / single select
|
|
92
|
-
- End with an "end_screen" type for a thank you message
|
|
93
|
-
|
|
94
|
-
**Media:** Forms can have video or image backgrounds on each question. Use clipform_upload_media to attach media after creation.`,
|
|
202
|
+
],
|
|
203
|
+
};
|
|
204
|
+
});
|
|
205
|
+
server.registerPrompt("create-funnel", {
|
|
206
|
+
title: "Create a Funnel",
|
|
207
|
+
description: "Build a lead qualification funnel or product recommendation quiz with branching logic",
|
|
208
|
+
}, async () => {
|
|
209
|
+
const sessionContext = await getSessionContext();
|
|
210
|
+
return {
|
|
211
|
+
messages: [
|
|
212
|
+
{
|
|
213
|
+
role: "user",
|
|
214
|
+
content: {
|
|
215
|
+
type: "text",
|
|
216
|
+
text: "I want to qualify leads or recommend products based on answers. What's the best approach?",
|
|
217
|
+
},
|
|
95
218
|
},
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
- show_step_counter: true
|
|
124
|
-
|
|
125
|
-
**Two modes:**
|
|
126
|
-
- One-shot: build immediately with sensible defaults when asked directly
|
|
127
|
-
- Dialogue: ask about video-only/format and extra fields, show wireframe preview first
|
|
128
|
-
|
|
129
|
-
Default to dialogue mode unless explicitly asked for one-shot.`,
|
|
219
|
+
{
|
|
220
|
+
role: "assistant",
|
|
221
|
+
content: {
|
|
222
|
+
type: "text",
|
|
223
|
+
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.
|
|
224
|
+
|
|
225
|
+
## Workflow
|
|
226
|
+
|
|
227
|
+
1. **Define outcomes** - what segments or recommendations exist? (e.g., Basic/Pro/Enterprise, or product categories)
|
|
228
|
+
2. **Create the form** with clipform_create_form:
|
|
229
|
+
- show_step_counter: false (funnels feel shorter without it)
|
|
230
|
+
- disable_back_navigation: true (prevents answer shopping that breaks scoring)
|
|
231
|
+
3. **Add hook question** (type: "choice") - "What best describes you?" or "What are you looking for?" This segments the user.
|
|
232
|
+
4. **Add qualifying questions** (type: "choice") - 2-3 questions that narrow down the need. Assign scores to each option.
|
|
233
|
+
5. **Set branching logic** with clipform_set_question_logic - route based on answers
|
|
234
|
+
6. **Add contact capture** (type: "contact") - name, email, phone. Place AFTER qualifying questions.
|
|
235
|
+
7. **Update end screen** with score_ranges for personalised outcomes: "Based on your answers, we recommend..."
|
|
236
|
+
8. **Publish** with clipform_update_form
|
|
237
|
+
|
|
238
|
+
## Key rule: 3-5 questions max. Every extra step loses leads.
|
|
239
|
+
|
|
240
|
+
## Before building, ask
|
|
241
|
+
|
|
242
|
+
1. What outcomes are you routing to? (products, plans, team members, messages)
|
|
243
|
+
2. What criteria determine the routing?
|
|
244
|
+
3. Do you need contact capture?`,
|
|
245
|
+
},
|
|
130
246
|
},
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
})
|
|
247
|
+
],
|
|
248
|
+
};
|
|
249
|
+
});
|
|
134
250
|
}
|
|
135
251
|
//# sourceMappingURL=prompts.js.map
|
package/dist/prompts.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompts.js","sourceRoot":"","sources":["../src/prompts.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"prompts.js","sourceRoot":"","sources":["../src/prompts.ts"],"names":[],"mappings":"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"}
|