@clipform/mcp-server 1.0.0 → 1.1.3

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.
Files changed (58) hide show
  1. package/README.md +123 -87
  2. package/dist/lib/api-client.d.ts +5 -0
  3. package/dist/lib/api-client.js +47 -0
  4. package/dist/lib/api-client.js.map +1 -1
  5. package/dist/lib/config.d.ts +1 -0
  6. package/dist/lib/config.js +63 -0
  7. package/dist/lib/config.js.map +1 -1
  8. package/dist/prompts.d.ts +2 -0
  9. package/dist/prompts.js +123 -0
  10. package/dist/prompts.js.map +1 -0
  11. package/dist/server.js +45 -1
  12. package/dist/server.js.map +1 -1
  13. package/dist/tools/attach-question-audio.d.ts +2 -0
  14. package/dist/tools/attach-question-audio.js +37 -0
  15. package/dist/tools/attach-question-audio.js.map +1 -0
  16. package/dist/tools/delete-question-media.d.ts +2 -0
  17. package/dist/tools/delete-question-media.js +29 -0
  18. package/dist/tools/delete-question-media.js.map +1 -0
  19. package/dist/tools/generate-slideshow.d.ts +2 -0
  20. package/dist/tools/generate-slideshow.js +52 -0
  21. package/dist/tools/generate-slideshow.js.map +1 -0
  22. package/dist/tools/generate-tts.d.ts +2 -0
  23. package/dist/tools/generate-tts.js +48 -0
  24. package/dist/tools/generate-tts.js.map +1 -0
  25. package/dist/tools/get-daily-content.d.ts +2 -0
  26. package/dist/tools/get-daily-content.js +66 -0
  27. package/dist/tools/get-daily-content.js.map +1 -0
  28. package/dist/tools/get-question-media.d.ts +2 -0
  29. package/dist/tools/get-question-media.js +39 -0
  30. package/dist/tools/get-question-media.js.map +1 -0
  31. package/dist/tools/get-trivia.d.ts +2 -0
  32. package/dist/tools/get-trivia.js +49 -0
  33. package/dist/tools/get-trivia.js.map +1 -0
  34. package/dist/tools/log-generation.d.ts +2 -0
  35. package/dist/tools/log-generation.js +34 -0
  36. package/dist/tools/log-generation.js.map +1 -0
  37. package/dist/tools/lookup-country.d.ts +2 -0
  38. package/dist/tools/lookup-country.js +38 -0
  39. package/dist/tools/lookup-country.js.map +1 -0
  40. package/dist/tools/search-images.d.ts +2 -0
  41. package/dist/tools/search-images.js +36 -0
  42. package/dist/tools/search-images.js.map +1 -0
  43. package/dist/tools/search-knowledge.d.ts +2 -0
  44. package/dist/tools/search-knowledge.js +40 -0
  45. package/dist/tools/search-knowledge.js.map +1 -0
  46. package/dist/tools/search-news.d.ts +2 -0
  47. package/dist/tools/search-news.js +38 -0
  48. package/dist/tools/search-news.js.map +1 -0
  49. package/dist/tools/search-videos.d.ts +2 -0
  50. package/dist/tools/search-videos.js +37 -0
  51. package/dist/tools/search-videos.js.map +1 -0
  52. package/dist/tools/set-question-logic.d.ts +2 -0
  53. package/dist/tools/set-question-logic.js +54 -0
  54. package/dist/tools/set-question-logic.js.map +1 -0
  55. package/dist/tools/upload-question-media.d.ts +2 -0
  56. package/dist/tools/upload-question-media.js +41 -0
  57. package/dist/tools/upload-question-media.js.map +1 -0
  58. package/package.json +6 -6
@@ -0,0 +1,37 @@
1
+ import { z } from "zod";
2
+ import { callApi, errorResult, textResult } from "../lib/api-client.js";
3
+ export function registerAttachQuestionAudioTool(server) {
4
+ server.registerTool("clipform_attach_audio", {
5
+ title: "Attach Audio to Question",
6
+ description: `Attach a sound effect or audio file to a question with existing media (stills only). The audio auto-plays once when a respondent reaches this question. Provide a public URL to the audio file (WAV, MP3, or OGG). The question must already have media uploaded (use clipform_upload_question_media first).`,
7
+ inputSchema: {
8
+ form_id: z.string().describe("The form ID"),
9
+ edit_token: z.string().describe("The edit token"),
10
+ question_id: z
11
+ .string()
12
+ .describe("The question ID (must already have media attached)"),
13
+ url: z
14
+ .string()
15
+ .url()
16
+ .describe("Public URL to the audio file (WAV, MP3, or OGG)"),
17
+ },
18
+ annotations: {
19
+ readOnlyHint: false,
20
+ destructiveHint: false,
21
+ idempotentHint: true,
22
+ openWorldHint: true,
23
+ },
24
+ }, async ({ form_id, edit_token, question_id, url }) => {
25
+ const result = await callApi(`/forms/${form_id}/questions/${question_id}/audio`, {
26
+ method: "PUT",
27
+ token: edit_token,
28
+ body: { url },
29
+ });
30
+ if (!result.ok) {
31
+ return errorResult(result.error);
32
+ }
33
+ return textResult(`Audio attached to question ${question_id}.\n` +
34
+ `Audio path: ${result.data.audio_storage_path}`);
35
+ });
36
+ }
37
+ //# sourceMappingURL=attach-question-audio.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attach-question-audio.js","sourceRoot":"","sources":["../../src/tools/attach-question-audio.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAExE,MAAM,UAAU,+BAA+B,CAAC,MAAiB;IAC/D,MAAM,CAAC,YAAY,CACjB,uBAAuB,EACvB;QACE,KAAK,EAAE,0BAA0B;QACjC,WAAW,EAAE,8SAA8S;QAC3T,WAAW,EAAE;YACX,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,aAAa,CAAC;YAC3C,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,gBAAgB,CAAC;YACjD,WAAW,EAAE,CAAC;iBACX,MAAM,EAAE;iBACR,QAAQ,CAAC,oDAAoD,CAAC;YACjE,GAAG,EAAE,CAAC;iBACH,MAAM,EAAE;iBACR,GAAG,EAAE;iBACL,QAAQ,CAAC,iDAAiD,CAAC;SAC/D;QACD,WAAW,EAAE;YACX,YAAY,EAAE,KAAK;YACnB,eAAe,EAAE,KAAK;YACtB,cAAc,EAAE,IAAI;YACpB,aAAa,EAAE,IAAI;SACpB;KACF,EACD,KAAK,EAAE,EAAE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,GAAG,EAAE,EAAE,EAAE;QAClD,MAAM,MAAM,GAAG,MAAM,OAAO,CAC1B,UAAU,OAAO,cAAc,WAAW,QAAQ,EAClD;YACE,MAAM,EAAE,KAAK;YACb,KAAK,EAAE,UAAU;YACjB,IAAI,EAAE,EAAE,GAAG,EAAE;SACd,CACF,CAAC;QAEF,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;YACf,OAAO,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACnC,CAAC;QAED,OAAO,UAAU,CACf,8BAA8B,WAAW,KAAK;YAC5C,eAAe,MAAM,CAAC,IAAI,CAAC,kBAAkB,EAAE,CAClD,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerDeleteQuestionMediaTool(server: McpServer): void;
@@ -0,0 +1,29 @@
1
+ import { z } from "zod";
2
+ import { callApi, errorResult, textResult } from "../lib/api-client.js";
3
+ export function registerDeleteQuestionMediaTool(server) {
4
+ server.registerTool("clipform_delete_question_media", {
5
+ title: "Delete Question Media",
6
+ description: `Remove media from a question. Deletes the media record and cleans up external resources (Mux video asset, storage file).`,
7
+ inputSchema: {
8
+ form_id: z.string().describe("The form ID"),
9
+ edit_token: z.string().describe("The edit token"),
10
+ question_id: z.string().describe("The question ID"),
11
+ },
12
+ annotations: {
13
+ readOnlyHint: false,
14
+ destructiveHint: true,
15
+ idempotentHint: false,
16
+ openWorldHint: true,
17
+ },
18
+ }, async ({ form_id, edit_token, question_id }) => {
19
+ const result = await callApi(`/forms/${form_id}/questions/${question_id}/media`, {
20
+ method: "DELETE",
21
+ token: edit_token,
22
+ });
23
+ if (!result.ok) {
24
+ return errorResult(result.error);
25
+ }
26
+ return textResult("Media removed from question.");
27
+ });
28
+ }
29
+ //# sourceMappingURL=delete-question-media.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delete-question-media.js","sourceRoot":"","sources":["../../src/tools/delete-question-media.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAExE,MAAM,UAAU,+BAA+B,CAAC,MAAiB;IAC/D,MAAM,CAAC,YAAY,CACjB,gCAAgC,EAChC;QACE,KAAK,EAAE,uBAAuB;QAC9B,WAAW,EAAE,0HAA0H;QACvI,WAAW,EAAE;YACX,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,aAAa,CAAC;YAC3C,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,gBAAgB,CAAC;YACjD,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,iBAAiB,CAAC;SACpD;QACD,WAAW,EAAE;YACX,YAAY,EAAE,KAAK;YACnB,eAAe,EAAE,IAAI;YACrB,cAAc,EAAE,KAAK;YACrB,aAAa,EAAE,IAAI;SACpB;KACF,EACD,KAAK,EAAE,EAAE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,EAAE,EAAE;QAC7C,MAAM,MAAM,GAAG,MAAM,OAAO,CAC1B,UAAU,OAAO,cAAc,WAAW,QAAQ,EAClD;YACE,MAAM,EAAE,QAAQ;YAChB,KAAK,EAAE,UAAU;SAClB,CACF,CAAC;QAEF,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;YACf,OAAO,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACnC,CAAC;QAED,OAAO,UAAU,CAAC,8BAA8B,CAAC,CAAC;IACpD,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerGenerateSlideshowTool(server: McpServer): void;
@@ -0,0 +1,52 @@
1
+ import { z } from "zod";
2
+ import { callInternalApi, errorResult, textResult } from "../lib/api-client.js";
3
+ export function registerGenerateSlideshowTool(server) {
4
+ server.registerTool("clipform_generate_slideshow", {
5
+ title: "Generate Ken Burns Slideshow",
6
+ description: `Generate a Ken Burns slideshow video from images and audio. Uses FFmpeg to create a video with pan/zoom effects and crossfade transitions. The video is uploaded to storage and a public URL is returned.
7
+
8
+ Workflow:
9
+ 1. Find images (use formgen_search_images or provide URLs)
10
+ 2. Provide an audio track URL (e.g. TTS narration from clipform_generate_tts)
11
+ 3. This tool creates a video with Ken Burns pan/zoom effects over the images, synced to the audio duration
12
+ 4. Attach the resulting public URL to a question using clipform_upload_media with media_type "video"
13
+
14
+ Effects: zoom-in, zoom-out, pan-left, pan-right, pan-up, pan-down, zoom-in-pan-left, zoom-in-pan-right, random, static.
15
+ Transitions: fade, fadeblack, fadewhite, slideleft, slideright, circlecrop, circleopen, circleclose, dissolve, pixelize, radial, smoothleft, smoothright.`,
16
+ inputSchema: {
17
+ images: z.array(z.object({
18
+ url: z.string().url().describe("Image URL"),
19
+ effect: z.string().optional().describe("Ken Burns effect (e.g. 'zoom-in', 'pan-left', 'random'). Default: random"),
20
+ })).min(1).max(20).describe("Images for the slideshow (1-20)"),
21
+ audio_url: z.string().url().describe("URL of the audio track (mp3/wav)"),
22
+ random_effects: z.boolean().optional().default(true).describe("Randomise effects (default: true)"),
23
+ transition: z.object({
24
+ type: z.string().optional().default("fade").describe("Transition type (default: 'fade')"),
25
+ duration: z.number().optional().default(1).describe("Transition duration in seconds (default: 1)"),
26
+ }).optional().describe("Transition settings"),
27
+ },
28
+ annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true },
29
+ }, async ({ images, audio_url, random_effects, transition }) => {
30
+ const result = await callInternalApi("/internal/media/slideshow", {
31
+ body: {
32
+ images,
33
+ audio_url,
34
+ random_effects: random_effects ?? true,
35
+ transition: transition ?? { type: "fade", duration: 1 },
36
+ },
37
+ });
38
+ if (!result.ok)
39
+ return errorResult(result.error);
40
+ const data = result.data;
41
+ return textResult([
42
+ `Slideshow generated successfully!`,
43
+ ``,
44
+ `Storage path: ${data.storage_path}`,
45
+ `Public URL: ${data.public_url}`,
46
+ `Duration: ${data.duration_seconds}s`,
47
+ ``,
48
+ `Use clipform_upload_media with the public URL to attach this video to a question.`,
49
+ ].join("\n"));
50
+ });
51
+ }
52
+ //# sourceMappingURL=generate-slideshow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate-slideshow.js","sourceRoot":"","sources":["../../src/tools/generate-slideshow.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEhF,MAAM,UAAU,6BAA6B,CAAC,MAAiB;IAC7D,MAAM,CAAC,YAAY,CACjB,6BAA6B,EAC7B;QACE,KAAK,EAAE,8BAA8B;QACrC,WAAW,EAAE;;;;;;;;;0JASuI;QACpJ,WAAW,EAAE;YACX,MAAM,EAAE,CAAC,CAAC,KAAK,CACb,CAAC,CAAC,MAAM,CAAC;gBACP,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;gBAC3C,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,0EAA0E,CAAC;aACnH,CAAC,CACH,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,iCAAiC,CAAC;YAC5D,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,kCAAkC,CAAC;YACxE,cAAc,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,mCAAmC,CAAC;YAClG,UAAU,EAAE,CAAC,CAAC,MAAM,CAAC;gBACnB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,mCAAmC,CAAC;gBACzF,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,6CAA6C,CAAC;aACnG,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,qBAAqB,CAAC;SAC9C;QACD,WAAW,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE;KACzG,EACD,KAAK,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,cAAc,EAAE,UAAU,EAAE,EAAE,EAAE;QAC1D,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,2BAA2B,EAAE;YAChE,IAAI,EAAE;gBACJ,MAAM;gBACN,SAAS;gBACT,cAAc,EAAE,cAAc,IAAI,IAAI;gBACtC,UAAU,EAAE,UAAU,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,EAAE;aACxD;SACF,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,EAAE;YAAE,OAAO,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAEjD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAW,CAAC;QAChC,OAAO,UAAU,CACf;YACE,mCAAmC;YACnC,EAAE;YACF,iBAAiB,IAAI,CAAC,YAAY,EAAE;YACpC,eAAe,IAAI,CAAC,UAAU,EAAE;YAChC,aAAa,IAAI,CAAC,gBAAgB,GAAG;YACrC,EAAE;YACF,mFAAmF;SACpF,CAAC,IAAI,CAAC,IAAI,CAAC,CACb,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerGenerateTtsTool(server: McpServer): void;
@@ -0,0 +1,48 @@
1
+ import { z } from "zod";
2
+ import { callInternalApi, errorResult, textResult } from "../lib/api-client.js";
3
+ export function registerGenerateTtsTool(server) {
4
+ server.registerTool("clipform_generate_tts", {
5
+ title: "Generate Text-to-Speech",
6
+ description: `Generate narration audio from text using Edge TTS (free) with ElevenLabs fallback. The audio is uploaded to storage and a public URL is returned.
7
+
8
+ Use this to create narration for slideshow videos. Workflow:
9
+ 1. Generate TTS audio with this tool
10
+ 2. Search for images with formgen_search_images
11
+ 3. Create a slideshow with clipform_generate_slideshow (pass the audio URL + image URLs)
12
+ 4. Attach the video to a question with clipform_upload_media
13
+
14
+ Available voices:
15
+ - ryan: British male (default)
16
+ - sonia: British female
17
+ - andrew: American male
18
+ - ava: American female
19
+ - guy: American male (casual)
20
+
21
+ Returns the audio public URL and word-level captions for subtitle display.`,
22
+ inputSchema: {
23
+ text: z.string().min(1).max(5000).describe("The narration text to convert to speech"),
24
+ voice: z.enum(["ryan", "sonia", "andrew", "ava", "guy"]).optional().default("ryan").describe("TTS voice (default: ryan)"),
25
+ },
26
+ annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true },
27
+ }, async ({ text, voice }) => {
28
+ const result = await callInternalApi("/internal/formgen/generate-tts", {
29
+ body: { text, voice },
30
+ });
31
+ if (!result.ok)
32
+ return errorResult(result.error);
33
+ const data = result.data;
34
+ return textResult([
35
+ `TTS audio generated successfully!`,
36
+ ``,
37
+ `Voice: ${data.voice}`,
38
+ `Audio URL: ${data.audioUrl}`,
39
+ `Storage path: ${data.storagePath}`,
40
+ `Captions: ${data.captions.length} segments`,
41
+ `Captions JSON: ${JSON.stringify(data.captions)}`,
42
+ ``,
43
+ `Use the Audio URL with clipform_generate_slideshow to create a video.`,
44
+ `Pass the Captions JSON to clipform_upload_media to enable subtitles.`,
45
+ ].join("\n"));
46
+ });
47
+ }
48
+ //# sourceMappingURL=generate-tts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate-tts.js","sourceRoot":"","sources":["../../src/tools/generate-tts.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEhF,MAAM,UAAU,uBAAuB,CAAC,MAAiB;IACvD,MAAM,CAAC,YAAY,CACjB,uBAAuB,EACvB;QACE,KAAK,EAAE,yBAAyB;QAChC,WAAW,EAAE;;;;;;;;;;;;;;;2EAewD;QACrE,WAAW,EAAE;YACX,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,yCAAyC,CAAC;YACrF,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,2BAA2B,CAAC;SAC1H;QACD,WAAW,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE;KACzG,EACD,KAAK,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE;QACxB,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,gCAAgC,EAAE;YACrE,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE;SACtB,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,EAAE;YAAE,OAAO,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAEjD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAW,CAAC;QAChC,OAAO,UAAU,CACf;YACE,mCAAmC;YACnC,EAAE;YACF,UAAU,IAAI,CAAC,KAAK,EAAE;YACtB,cAAc,IAAI,CAAC,QAAQ,EAAE;YAC7B,iBAAiB,IAAI,CAAC,WAAW,EAAE;YACnC,aAAa,IAAI,CAAC,QAAQ,CAAC,MAAM,WAAW;YAC5C,kBAAkB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE;YACjD,EAAE;YACF,uEAAuE;YACvE,sEAAsE;SACvE,CAAC,IAAI,CAAC,IAAI,CAAC,CACb,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerGetDailyContentTool(server: McpServer): void;
@@ -0,0 +1,66 @@
1
+ import { callInternalApi, errorResult, textResult } from "../lib/api-client.js";
2
+ function truncate(text, maxLength = 500) {
3
+ if (text.length <= maxLength)
4
+ return text;
5
+ return text.slice(0, maxLength - 3) + "...";
6
+ }
7
+ export function registerGetDailyContentTool(server) {
8
+ server.registerTool("formgen_get_daily_content", {
9
+ title: "Get Daily Content",
10
+ description: `Get today's rotating content for quiz generation. Returns NASA's Astronomy Picture of the Day and Wikipedia's featured content (featured article, "on this day" events, most-read articles, current news). Great for generating daily quizzes with fresh content.`,
11
+ inputSchema: {},
12
+ annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: false, openWorldHint: true },
13
+ }, async () => {
14
+ const result = await callInternalApi("/internal/formgen/get-daily-content", {});
15
+ if (!result.ok)
16
+ return errorResult(result.error);
17
+ const daily = result.data.daily;
18
+ const lines = [];
19
+ if (daily.nasaApod) {
20
+ const a = daily.nasaApod;
21
+ lines.push("## NASA Astronomy Picture of the Day");
22
+ lines.push(`Title: ${a.title}`);
23
+ lines.push(`Date: ${a.date}`);
24
+ lines.push(`Type: ${a.mediaType}`);
25
+ lines.push(`URL: ${a.url}`);
26
+ if (a.hdUrl)
27
+ lines.push(`HD URL: ${a.hdUrl}`);
28
+ lines.push(`Explanation: ${truncate(a.explanation, 400)}`);
29
+ if (a.copyright)
30
+ lines.push(`Copyright: ${a.copyright}`);
31
+ lines.push("");
32
+ }
33
+ if (daily.wikipedia) {
34
+ const w = daily.wikipedia;
35
+ if (w.todaysFeaturedArticle) {
36
+ lines.push("## Wikipedia Featured Article");
37
+ lines.push(`Title: ${w.todaysFeaturedArticle.title}`);
38
+ lines.push(truncate(w.todaysFeaturedArticle.extract, 300));
39
+ lines.push("");
40
+ }
41
+ if (w.onThisDay?.length > 0) {
42
+ lines.push(`## On This Day (${w.onThisDay.length} events)`);
43
+ for (const event of w.onThisDay.slice(0, 8)) {
44
+ lines.push(`- ${event.year}: ${event.text}`);
45
+ }
46
+ lines.push("");
47
+ }
48
+ if (w.mostRead?.length > 0) {
49
+ lines.push(`## Most Read Today (top 10)`);
50
+ for (const article of w.mostRead.slice(0, 10)) {
51
+ lines.push(`- ${article.title}: ${truncate(article.extract, 100)}`);
52
+ }
53
+ lines.push("");
54
+ }
55
+ if (w.newsItems?.length > 0) {
56
+ lines.push(`## In The News`);
57
+ for (const item of w.newsItems.slice(0, 5)) {
58
+ lines.push(`- ${item.story}`);
59
+ }
60
+ lines.push("");
61
+ }
62
+ }
63
+ return textResult(lines.join("\n"));
64
+ });
65
+ }
66
+ //# sourceMappingURL=get-daily-content.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-daily-content.js","sourceRoot":"","sources":["../../src/tools/get-daily-content.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerGetQuestionMediaTool(server: McpServer): void;
@@ -0,0 +1,39 @@
1
+ import { z } from "zod";
2
+ import { callApi, errorResult, textResult } from "../lib/api-client.js";
3
+ export function registerGetQuestionMediaTool(server) {
4
+ server.registerTool("clipform_get_question_media", {
5
+ title: "Get Question Media",
6
+ description: `Get the media attached to a question, including processing status. Useful for checking if a video upload has finished processing.`,
7
+ inputSchema: {
8
+ form_id: z.string().describe("The form ID"),
9
+ edit_token: z.string().describe("The edit token"),
10
+ question_id: z.string().describe("The question ID"),
11
+ },
12
+ annotations: {
13
+ readOnlyHint: true,
14
+ destructiveHint: false,
15
+ idempotentHint: true,
16
+ openWorldHint: true,
17
+ },
18
+ }, async ({ form_id, edit_token, question_id }) => {
19
+ const result = await callApi(`/forms/${form_id}/questions/${question_id}/media`, {
20
+ method: "GET",
21
+ token: edit_token,
22
+ });
23
+ if (!result.ok) {
24
+ return errorResult(result.error);
25
+ }
26
+ const media = result.data.media;
27
+ if (!media) {
28
+ return textResult("No media attached to this question.");
29
+ }
30
+ return textResult(`Media ID: ${media.id}\n` +
31
+ `Type: ${media.media_type}\n` +
32
+ `Status: ${media.status}\n` +
33
+ (media.playback_id ? `Playback ID: ${media.playback_id}\n` : "") +
34
+ (media.storage_path ? `Storage path: ${media.storage_path}\n` : "") +
35
+ (media.duration ? `Duration: ${media.duration}s\n` : "") +
36
+ `Transcription: ${media.transcription_status}`);
37
+ });
38
+ }
39
+ //# sourceMappingURL=get-question-media.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-question-media.js","sourceRoot":"","sources":["../../src/tools/get-question-media.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAExE,MAAM,UAAU,4BAA4B,CAAC,MAAiB;IAC5D,MAAM,CAAC,YAAY,CACjB,6BAA6B,EAC7B;QACE,KAAK,EAAE,oBAAoB;QAC3B,WAAW,EAAE,mIAAmI;QAChJ,WAAW,EAAE;YACX,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,aAAa,CAAC;YAC3C,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,gBAAgB,CAAC;YACjD,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,iBAAiB,CAAC;SACpD;QACD,WAAW,EAAE;YACX,YAAY,EAAE,IAAI;YAClB,eAAe,EAAE,KAAK;YACtB,cAAc,EAAE,IAAI;YACpB,aAAa,EAAE,IAAI;SACpB;KACF,EACD,KAAK,EAAE,EAAE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,EAAE,EAAE;QAC7C,MAAM,MAAM,GAAG,MAAM,OAAO,CAC1B,UAAU,OAAO,cAAc,WAAW,QAAQ,EAClD;YACE,MAAM,EAAE,KAAK;YACb,KAAK,EAAE,UAAU;SAClB,CACF,CAAC;QAEF,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;YACf,OAAO,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACnC,CAAC;QAED,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,KAAuC,CAAC;QAClE,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,UAAU,CAAC,qCAAqC,CAAC,CAAC;QAC3D,CAAC;QAED,OAAO,UAAU,CACf,aAAa,KAAK,CAAC,EAAE,IAAI;YACvB,SAAS,KAAK,CAAC,UAAU,IAAI;YAC7B,WAAW,KAAK,CAAC,MAAM,IAAI;YAC3B,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,gBAAgB,KAAK,CAAC,WAAW,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;YAChE,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,iBAAiB,KAAK,CAAC,YAAY,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;YACnE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,aAAa,KAAK,CAAC,QAAQ,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;YACxD,kBAAkB,KAAK,CAAC,oBAAoB,EAAE,CACjD,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerGetTriviaTool(server: McpServer): void;
@@ -0,0 +1,49 @@
1
+ import { z } from "zod";
2
+ import { callInternalApi, errorResult, textResult } from "../lib/api-client.js";
3
+ const CATEGORIES = [
4
+ "General Knowledge", "Entertainment: Books", "Entertainment: Film",
5
+ "Entertainment: Music", "Entertainment: Musicals & Theatres",
6
+ "Entertainment: Television", "Entertainment: Video Games",
7
+ "Entertainment: Board Games", "Science & Nature", "Science: Computers",
8
+ "Science: Mathematics", "Science: Gadgets", "Mythology", "Sports",
9
+ "Geography", "History", "Politics", "Art", "Celebrities", "Animals",
10
+ "Vehicles", "Entertainment: Comics", "Entertainment: Japanese Anime & Manga",
11
+ "Entertainment: Cartoon & Animations",
12
+ ];
13
+ export function registerGetTriviaTool(server) {
14
+ server.registerTool("formgen_get_trivia", {
15
+ title: "Get Trivia Questions",
16
+ description: `Get ready-made trivia questions from the Open Trivia Database (4,000+ questions across 24 categories). NOT keyword-searchable - works by category and difficulty only. Each question includes the correct answer, incorrect answers, category, and difficulty level.
17
+
18
+ Available categories: ${CATEGORIES.join(", ")}`,
19
+ inputSchema: {
20
+ amount: z.number().min(1).max(50).default(10).optional()
21
+ .describe("Number of questions (default 10)"),
22
+ category: z.string().optional()
23
+ .describe("Category name (must match exactly from the list)"),
24
+ difficulty: z.enum(["easy", "medium", "hard"]).optional()
25
+ .describe("Difficulty level"),
26
+ },
27
+ annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: false, openWorldHint: true },
28
+ }, async ({ amount, category, difficulty }) => {
29
+ const result = await callInternalApi("/internal/formgen/get-trivia", {
30
+ body: { amount, category, difficulty },
31
+ });
32
+ if (!result.ok)
33
+ return errorResult(result.error);
34
+ const results = result.data.results;
35
+ if (!results.length)
36
+ return textResult("No trivia questions returned. Try a different category or fewer questions.");
37
+ const lines = [`${results.length} trivia questions:\n`];
38
+ for (let i = 0; i < results.length; i++) {
39
+ const q = results[i];
40
+ lines.push(`${i + 1}. [${q.difficulty}] ${q.question}`);
41
+ lines.push(` Correct: ${q.correctAnswer}`);
42
+ lines.push(` Wrong: ${q.incorrectAnswers.join(", ")}`);
43
+ lines.push(` Category: ${q.category}`);
44
+ lines.push("");
45
+ }
46
+ return textResult(lines.join("\n"));
47
+ });
48
+ }
49
+ //# sourceMappingURL=get-trivia.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-trivia.js","sourceRoot":"","sources":["../../src/tools/get-trivia.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerLogGenerationTool(server: McpServer): void;
@@ -0,0 +1,34 @@
1
+ import { z } from "zod";
2
+ import { callInternalApi, errorResult, textResult } from "../lib/api-client.js";
3
+ export function registerLogGenerationTool(server) {
4
+ server.registerTool("clipform_log_generation", {
5
+ title: "Log Form Generation Audit",
6
+ description: `Save an audit trail for a generated form. Records where content came from - the sources and image attributions. Call this as the final step after building a form or quiz.`,
7
+ inputSchema: {
8
+ form_id: z.string().describe("The form ID"),
9
+ edit_token: z.string().describe("The edit token"),
10
+ summary: z.string().describe("Short description of what was generated"),
11
+ details: z.object({
12
+ sources: z.array(z.object({
13
+ title: z.string(),
14
+ url: z.string().optional(),
15
+ type: z.string().optional(),
16
+ })).optional().describe("Knowledge sources used"),
17
+ images: z.array(z.object({
18
+ url: z.string(),
19
+ attribution: z.string().optional(),
20
+ license: z.string().optional(),
21
+ })).optional().describe("Images used with attribution"),
22
+ }).describe("Content sources and attributions"),
23
+ },
24
+ annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false },
25
+ }, async ({ form_id, edit_token, summary, details }) => {
26
+ const result = await callInternalApi("/internal/formgen/log-generation", {
27
+ body: { form_id, summary, details },
28
+ });
29
+ if (!result.ok)
30
+ return errorResult(result.error);
31
+ return textResult(`Audit log saved for form ${form_id}\nSummary: ${summary}`);
32
+ });
33
+ }
34
+ //# sourceMappingURL=log-generation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log-generation.js","sourceRoot":"","sources":["../../src/tools/log-generation.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEhF,MAAM,UAAU,yBAAyB,CAAC,MAAiB;IACzD,MAAM,CAAC,YAAY,CACjB,yBAAyB,EACzB;QACE,KAAK,EAAE,2BAA2B;QAClC,WAAW,EAAE,4KAA4K;QACzL,WAAW,EAAE;YACX,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,aAAa,CAAC;YAC3C,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,gBAAgB,CAAC;YACjD,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,yCAAyC,CAAC;YACvE,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC;gBAChB,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;oBACxB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;oBACjB,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;oBAC1B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;iBAC5B,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,wBAAwB,CAAC;gBACjD,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;oBACvB,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE;oBACf,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;oBAClC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;iBAC/B,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,8BAA8B,CAAC;aACxD,CAAC,CAAC,QAAQ,CAAC,kCAAkC,CAAC;SAChD;QACD,WAAW,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE;KAC1G,EACD,KAAK,EAAE,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE;QAClD,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,kCAAkC,EAAE;YACvE,IAAI,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE;SACpC,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,EAAE;YAAE,OAAO,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAEjD,OAAO,UAAU,CAAC,4BAA4B,OAAO,cAAc,OAAO,EAAE,CAAC,CAAC;IAChF,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerLookupCountryTool(server: McpServer): void;
@@ -0,0 +1,38 @@
1
+ import { z } from "zod";
2
+ import { callInternalApi, errorResult, textResult } from "../lib/api-client.js";
3
+ export function registerLookupCountryTool(server) {
4
+ server.registerTool("formgen_lookup_country", {
5
+ title: "Lookup Country",
6
+ description: `Look up country data by name. Returns structured info including capital, population, languages, currencies, flag URLs, borders, and timezones. Partial name matching works (e.g. "united" returns United Kingdom, United States, etc.). Useful for geography quiz questions.`,
7
+ inputSchema: {
8
+ name: z.string().describe("Country name or partial name (e.g. 'France', 'united', 'japan')"),
9
+ },
10
+ annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
11
+ }, async ({ name }) => {
12
+ const result = await callInternalApi("/internal/formgen/lookup-country", {
13
+ body: { name },
14
+ });
15
+ if (!result.ok)
16
+ return errorResult(result.error);
17
+ const country = result.data.country;
18
+ if (!country)
19
+ return textResult(`No country found for "${name}".`);
20
+ const lines = [
21
+ `Country: ${country.name}`,
22
+ `Official name: ${country.officialName}`,
23
+ `Capital: ${country.capital || "N/A"}`,
24
+ `Region: ${country.region}${country.subregion ? ` (${country.subregion})` : ""}`,
25
+ `Population: ${Number(country.population).toLocaleString()}`,
26
+ `Area: ${country.area ? `${Number(country.area).toLocaleString()} km²` : "N/A"}`,
27
+ `Languages: ${country.languages?.join(", ") || "N/A"}`,
28
+ `Currencies: ${country.currencies?.map((c) => `${c.name} (${c.symbol})`).join(", ") || "N/A"}`,
29
+ `Timezones: ${country.timezones?.join(", ")}`,
30
+ `Borders: ${country.borders?.join(", ") || "None (island/isolated)"}`,
31
+ `Flag (PNG): ${country.flagPng}`,
32
+ `Flag (SVG): ${country.flagSvg}`,
33
+ country.coatOfArmsUrl ? `Coat of arms: ${country.coatOfArmsUrl}` : "",
34
+ ].filter(Boolean);
35
+ return textResult(lines.join("\n"));
36
+ });
37
+ }
38
+ //# sourceMappingURL=lookup-country.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lookup-country.js","sourceRoot":"","sources":["../../src/tools/lookup-country.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEhF,MAAM,UAAU,yBAAyB,CAAC,MAAiB;IACzD,MAAM,CAAC,YAAY,CACjB,wBAAwB,EACxB;QACE,KAAK,EAAE,gBAAgB;QACvB,WAAW,EAAE,8QAA8Q;QAC3R,WAAW,EAAE;YACX,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,iEAAiE,CAAC;SAC7F;QACD,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE;KACvG,EACD,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;QACjB,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,kCAAkC,EAAE;YACvE,IAAI,EAAE,EAAE,IAAI,EAAE;SACf,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,EAAE;YAAE,OAAO,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAEjD,MAAM,OAAO,GAAI,MAAM,CAAC,IAAY,CAAC,OAAO,CAAC;QAC7C,IAAI,CAAC,OAAO;YAAE,OAAO,UAAU,CAAC,yBAAyB,IAAI,IAAI,CAAC,CAAC;QAEnE,MAAM,KAAK,GAAG;YACZ,YAAY,OAAO,CAAC,IAAI,EAAE;YAC1B,kBAAkB,OAAO,CAAC,YAAY,EAAE;YACxC,YAAY,OAAO,CAAC,OAAO,IAAI,KAAK,EAAE;YACtC,WAAW,OAAO,CAAC,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YAChF,eAAe,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,cAAc,EAAE,EAAE;YAC5D,SAAS,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,EAAE;YAChF,cAAc,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,EAAE;YACtD,eAAe,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,EAAE;YACnG,cAAc,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE;YAC7C,YAAY,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,wBAAwB,EAAE;YACrE,eAAe,OAAO,CAAC,OAAO,EAAE;YAChC,eAAe,OAAO,CAAC,OAAO,EAAE;YAChC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,iBAAiB,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE;SACtE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAElB,OAAO,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IACtC,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerSearchImagesTool(server: McpServer): void;
@@ -0,0 +1,36 @@
1
+ import { z } from "zod";
2
+ import { callInternalApi, errorResult, textResult } from "../lib/api-client.js";
3
+ export function registerSearchImagesTool(server) {
4
+ server.registerTool("formgen_search_images", {
5
+ title: "Search Images",
6
+ description: `Search for royalty-free images across multiple providers (Pexels, Unsplash, Pixabay, Wikimedia Commons, NASA, iNaturalist). Automatically routes to the most relevant providers based on the query topic. Returns image URLs you can use with clipform_upload_media or clipform_generate_slideshow.`,
7
+ inputSchema: {
8
+ query: z.string().describe("Search query (e.g. 'komodo dragon', 'saturn rings', 'french cuisine')"),
9
+ count: z.number().min(1).max(20).default(6).optional()
10
+ .describe("Max results per provider (default 6)"),
11
+ },
12
+ annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
13
+ }, async ({ query, count }) => {
14
+ const result = await callInternalApi("/internal/formgen/search-images", {
15
+ body: { query, count },
16
+ });
17
+ if (!result.ok)
18
+ return errorResult(result.error);
19
+ const results = result.data.results;
20
+ if (!results.length)
21
+ return textResult(`No images found for "${query}".`);
22
+ const lines = [`Found ${results.length} images for "${query}":\n`];
23
+ for (const img of results.slice(0, 15)) {
24
+ lines.push(`- [${img.source}] ${img.title}`);
25
+ lines.push(` URL: ${img.url}`);
26
+ if (img.width && img.height)
27
+ lines.push(` Size: ${img.width}x${img.height}`);
28
+ if (img.attribution)
29
+ lines.push(` Attribution: ${img.attribution}`);
30
+ lines.push(` License: ${img.license}`);
31
+ lines.push("");
32
+ }
33
+ return textResult(lines.join("\n"));
34
+ });
35
+ }
36
+ //# sourceMappingURL=search-images.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-images.js","sourceRoot":"","sources":["../../src/tools/search-images.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEhF,MAAM,UAAU,wBAAwB,CAAC,MAAiB;IACxD,MAAM,CAAC,YAAY,CACjB,uBAAuB,EACvB;QACE,KAAK,EAAE,eAAe;QACtB,WAAW,EAAE,qSAAqS;QAClT,WAAW,EAAE;YACX,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,uEAAuE,CAAC;YACnG,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;iBACnD,QAAQ,CAAC,sCAAsC,CAAC;SACpD;QACD,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE;KACvG,EACD,KAAK,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE;QACzB,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,iCAAiC,EAAE;YACtE,IAAI,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE;SACvB,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,EAAE;YAAE,OAAO,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAEjD,MAAM,OAAO,GAAI,MAAM,CAAC,IAAY,CAAC,OAAgB,CAAC;QACtD,IAAI,CAAC,OAAO,CAAC,MAAM;YAAE,OAAO,UAAU,CAAC,wBAAwB,KAAK,IAAI,CAAC,CAAC;QAE1E,MAAM,KAAK,GAAG,CAAC,SAAS,OAAO,CAAC,MAAM,gBAAgB,KAAK,MAAM,CAAC,CAAC;QACnE,KAAK,MAAM,GAAG,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;YACvC,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,MAAM,KAAK,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC;YAC7C,KAAK,CAAC,IAAI,CAAC,UAAU,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC;YAChC,IAAI,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,MAAM;gBAAE,KAAK,CAAC,IAAI,CAAC,WAAW,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;YAC9E,IAAI,GAAG,CAAC,WAAW;gBAAE,KAAK,CAAC,IAAI,CAAC,kBAAkB,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC;YACrE,KAAK,CAAC,IAAI,CAAC,cAAc,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;YACxC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACjB,CAAC;QACD,OAAO,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IACtC,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerSearchKnowledgeTool(server: McpServer): void;
@@ -0,0 +1,40 @@
1
+ import { z } from "zod";
2
+ import { callInternalApi, errorResult, textResult } from "../lib/api-client.js";
3
+ function truncate(text, maxLength = 500) {
4
+ if (text.length <= maxLength)
5
+ return text;
6
+ return text.slice(0, maxLength - 3) + "...";
7
+ }
8
+ export function registerSearchKnowledgeTool(server) {
9
+ server.registerTool("formgen_search_knowledge", {
10
+ title: "Search Knowledge",
11
+ description: `Search Wikipedia for encyclopaedia-quality information about a topic. Returns article summaries with thumbnails. Use this to research a topic before crafting quiz questions.`,
12
+ inputSchema: {
13
+ query: z.string().describe("Topic to research (e.g. 'komodo dragon', 'black holes', 'French Revolution')"),
14
+ count: z.number().min(1).max(10).default(3).optional()
15
+ .describe("Number of articles to return (default 3)"),
16
+ },
17
+ annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
18
+ }, async ({ query, count }) => {
19
+ const result = await callInternalApi("/internal/formgen/search-knowledge", {
20
+ body: { query, count },
21
+ });
22
+ if (!result.ok)
23
+ return errorResult(result.error);
24
+ const results = result.data.results;
25
+ if (!results.length)
26
+ return textResult(`No knowledge articles found for "${query}".`);
27
+ const lines = [`Found ${results.length} articles for "${query}":\n`];
28
+ for (const article of results) {
29
+ lines.push(`## ${article.title}`);
30
+ lines.push(truncate(article.summary, 600));
31
+ if (article.thumbnailUrl)
32
+ lines.push(`Thumbnail: ${article.thumbnailUrl}`);
33
+ if (article.sourceUrl)
34
+ lines.push(`Source: ${article.sourceUrl}`);
35
+ lines.push("");
36
+ }
37
+ return textResult(lines.join("\n"));
38
+ });
39
+ }
40
+ //# sourceMappingURL=search-knowledge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-knowledge.js","sourceRoot":"","sources":["../../src/tools/search-knowledge.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEhF,SAAS,QAAQ,CAAC,IAAY,EAAE,SAAS,GAAG,GAAG;IAC7C,IAAI,IAAI,CAAC,MAAM,IAAI,SAAS;QAAE,OAAO,IAAI,CAAC;IAC1C,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC;AAC9C,CAAC;AAED,MAAM,UAAU,2BAA2B,CAAC,MAAiB;IAC3D,MAAM,CAAC,YAAY,CACjB,0BAA0B,EAC1B;QACE,KAAK,EAAE,kBAAkB;QACzB,WAAW,EAAE,+KAA+K;QAC5L,WAAW,EAAE;YACX,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,8EAA8E,CAAC;YAC1G,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;iBACnD,QAAQ,CAAC,0CAA0C,CAAC;SACxD;QACD,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE;KACvG,EACD,KAAK,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE;QACzB,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,oCAAoC,EAAE;YACzE,IAAI,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE;SACvB,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,EAAE;YAAE,OAAO,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAEjD,MAAM,OAAO,GAAI,MAAM,CAAC,IAAY,CAAC,OAAgB,CAAC;QACtD,IAAI,CAAC,OAAO,CAAC,MAAM;YAAE,OAAO,UAAU,CAAC,oCAAoC,KAAK,IAAI,CAAC,CAAC;QAEtF,MAAM,KAAK,GAAG,CAAC,SAAS,OAAO,CAAC,MAAM,kBAAkB,KAAK,MAAM,CAAC,CAAC;QACrE,KAAK,MAAM,OAAO,IAAI,OAAO,EAAE,CAAC;YAC9B,KAAK,CAAC,IAAI,CAAC,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;YAClC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;YAC3C,IAAI,OAAO,CAAC,YAAY;gBAAE,KAAK,CAAC,IAAI,CAAC,cAAc,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;YAC3E,IAAI,OAAO,CAAC,SAAS;gBAAE,KAAK,CAAC,IAAI,CAAC,WAAW,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;YAClE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACjB,CAAC;QACD,OAAO,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IACtC,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerSearchNewsTool(server: McpServer): void;