@fotovid/mcp 0.1.0 → 0.2.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 -1
- package/dist/index.js +100 -1
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# @fotovid/mcp
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@fotovid/mcp)
|
|
4
|
+
|
|
5
|
+
An [MCP](https://modelcontextprotocol.io) server (Model Context Protocol) that exposes the [Fotovid](https://fotovid.co) serverless ffmpeg API as first-class AI agent tools — watermark video and images, trim video and audio, extract audio from video, generate video thumbnails, and probe video metadata, all with a single tool call and no ffmpeg binary anywhere.
|
|
4
6
|
|
|
5
7
|
## Usage
|
|
6
8
|
|
|
@@ -36,6 +38,24 @@ Each media tool returns a URL to the finished file — hosted, time-limited,
|
|
|
36
38
|
opaque; see `expires_at` and store your own copy. Built on
|
|
37
39
|
[`@fotovid/sdk`](../sdk).
|
|
38
40
|
|
|
41
|
+
### Async tools (large or long video)
|
|
42
|
+
|
|
43
|
+
The tools above reject video over ~720p or 15s (a hard sync-API limit). For
|
|
44
|
+
larger input, use the matching `_async` tool — it submits a task and returns
|
|
45
|
+
immediately with a `task_id`, then poll `fotovid_get_task` until it's done:
|
|
46
|
+
|
|
47
|
+
| Tool | Operation |
|
|
48
|
+
| --- | --- |
|
|
49
|
+
| `fotovid_watermark_video_async` | Submit a video watermark task |
|
|
50
|
+
| `fotovid_watermark_image_async` | Submit an image watermark task |
|
|
51
|
+
| `fotovid_trim_video_async` | Submit a video trim task |
|
|
52
|
+
| `fotovid_extract_audio_async` | Submit an audio-extraction task |
|
|
53
|
+
| `fotovid_trim_audio_async` | Submit an audio trim task |
|
|
54
|
+
| `fotovid_video_thumbnail_async` | Submit a video-thumbnail task |
|
|
55
|
+
| `fotovid_get_task` | Check a task's status — `outputs` once succeeded, `error` once failed |
|
|
56
|
+
|
|
57
|
+
There's no async form of `fotovid_probe_video` — probing is sync-only.
|
|
58
|
+
|
|
39
59
|
## License
|
|
40
60
|
|
|
41
61
|
MIT
|
package/dist/index.js
CHANGED
|
@@ -21,6 +21,13 @@ async function run(work) {
|
|
|
21
21
|
};
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
|
+
function submitted(task) {
|
|
25
|
+
return {
|
|
26
|
+
task_id: task.id,
|
|
27
|
+
status: task.status,
|
|
28
|
+
poll_with: "fotovid_get_task"
|
|
29
|
+
};
|
|
30
|
+
}
|
|
24
31
|
var source_url = z.string().url().describe("Public http(s) URL of the source media");
|
|
25
32
|
var position = z.enum(["top-left", "top-right", "bottom-left", "bottom-right", "center"]).describe("Watermark anchor (default bottom-right)");
|
|
26
33
|
var output_format = z.enum(["webp", "jpeg", "jpg", "png"]).describe("Output image format (default webp)");
|
|
@@ -42,7 +49,7 @@ var watermarkShape = {
|
|
|
42
49
|
quality: quality.optional()
|
|
43
50
|
};
|
|
44
51
|
function createServer(fotovid) {
|
|
45
|
-
const server = new McpServer({ name: "fotovid", version: "0.
|
|
52
|
+
const server = new McpServer({ name: "fotovid", version: "0.2.0" });
|
|
46
53
|
server.registerTool(
|
|
47
54
|
"fotovid_watermark_video",
|
|
48
55
|
{
|
|
@@ -133,6 +140,98 @@ function createServer(fotovid) {
|
|
|
133
140
|
},
|
|
134
141
|
(args) => run(() => fotovid.video.probe(args))
|
|
135
142
|
);
|
|
143
|
+
server.registerTool(
|
|
144
|
+
"fotovid_watermark_video_async",
|
|
145
|
+
{
|
|
146
|
+
title: "Watermark a video (async, for large/long video)",
|
|
147
|
+
description: "Submit a video watermark job for input too large or long for the sync tool (over ~720p or 15s). Returns immediately with a task_id \u2014 poll fotovid_get_task for the result, do not wait here.",
|
|
148
|
+
inputSchema: {
|
|
149
|
+
...watermarkShape,
|
|
150
|
+
preset: z.enum([
|
|
151
|
+
"ultrafast",
|
|
152
|
+
"superfast",
|
|
153
|
+
"veryfast",
|
|
154
|
+
"faster",
|
|
155
|
+
"fast",
|
|
156
|
+
"medium",
|
|
157
|
+
"slow",
|
|
158
|
+
"slower",
|
|
159
|
+
"veryslow",
|
|
160
|
+
"placebo"
|
|
161
|
+
]).optional().describe("x264 encode preset (video only)")
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
(args) => run(() => fotovid.tasks.video.watermark(args).then(submitted))
|
|
165
|
+
);
|
|
166
|
+
server.registerTool(
|
|
167
|
+
"fotovid_watermark_image_async",
|
|
168
|
+
{
|
|
169
|
+
title: "Watermark an image (async)",
|
|
170
|
+
description: "Submit an image watermark job. Returns immediately with a task_id \u2014 poll fotovid_get_task for the result, do not wait here.",
|
|
171
|
+
inputSchema: watermarkShape
|
|
172
|
+
},
|
|
173
|
+
(args) => run(() => fotovid.tasks.image.watermark(args).then(submitted))
|
|
174
|
+
);
|
|
175
|
+
server.registerTool(
|
|
176
|
+
"fotovid_trim_video_async",
|
|
177
|
+
{
|
|
178
|
+
title: "Trim a video (async, for large/long video)",
|
|
179
|
+
description: "Submit a video trim job for input too large or long for the sync tool. Returns immediately with a task_id \u2014 poll fotovid_get_task for the result, do not wait here.",
|
|
180
|
+
inputSchema: { source_url, start, end }
|
|
181
|
+
},
|
|
182
|
+
(args) => run(() => fotovid.tasks.video.trim(args).then(submitted))
|
|
183
|
+
);
|
|
184
|
+
server.registerTool(
|
|
185
|
+
"fotovid_extract_audio_async",
|
|
186
|
+
{
|
|
187
|
+
title: "Extract audio from a video (async, for large/long video)",
|
|
188
|
+
description: "Submit an audio-extraction job for input too large or long for the sync tool. Returns immediately with a task_id \u2014 poll fotovid_get_task for the result, do not wait here.",
|
|
189
|
+
inputSchema: { source_url }
|
|
190
|
+
},
|
|
191
|
+
(args) => run(() => fotovid.tasks.video.extractAudio(args).then(submitted))
|
|
192
|
+
);
|
|
193
|
+
server.registerTool(
|
|
194
|
+
"fotovid_trim_audio_async",
|
|
195
|
+
{
|
|
196
|
+
title: "Trim an audio file (async, for large/long audio)",
|
|
197
|
+
description: "Submit an audio trim job for input too large or long for the sync tool. Returns immediately with a task_id \u2014 poll fotovid_get_task for the result, do not wait here.",
|
|
198
|
+
inputSchema: { source_url, start, end }
|
|
199
|
+
},
|
|
200
|
+
(args) => run(() => fotovid.tasks.audio.trim(args).then(submitted))
|
|
201
|
+
);
|
|
202
|
+
server.registerTool(
|
|
203
|
+
"fotovid_video_thumbnail_async",
|
|
204
|
+
{
|
|
205
|
+
title: "Grab a video thumbnail (async, for large/long video)",
|
|
206
|
+
description: "Submit a video-thumbnail job for input too large or long for the sync tool. Returns immediately with a task_id \u2014 poll fotovid_get_task for the result, do not wait here.",
|
|
207
|
+
inputSchema: {
|
|
208
|
+
source_url,
|
|
209
|
+
at: z.number().min(0).optional().describe("Frame timestamp in seconds (default ~1s)"),
|
|
210
|
+
output_format: output_format.optional(),
|
|
211
|
+
quality: quality.optional()
|
|
212
|
+
}
|
|
213
|
+
},
|
|
214
|
+
(args) => run(() => fotovid.tasks.video.thumbnail(args).then(submitted))
|
|
215
|
+
);
|
|
216
|
+
server.registerTool(
|
|
217
|
+
"fotovid_get_task",
|
|
218
|
+
{
|
|
219
|
+
title: "Check an async task",
|
|
220
|
+
description: "Check the status of a task submitted by one of the _async tools. While status is starting/processing, outputs/error are absent \u2014 wait a couple of seconds and call again. Once status is succeeded, outputs has the result(s); once failed, error explains why (this is normal \u2014 not an exception).",
|
|
221
|
+
inputSchema: {
|
|
222
|
+
task_id: z.string().describe("Task id returned by an _async tool")
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
({ task_id }) => run(async () => {
|
|
226
|
+
const task = await fotovid.tasks.get(task_id);
|
|
227
|
+
return {
|
|
228
|
+
task_id: task.id,
|
|
229
|
+
status: task.status,
|
|
230
|
+
outputs: task.outputs,
|
|
231
|
+
error: task.error
|
|
232
|
+
};
|
|
233
|
+
})
|
|
234
|
+
);
|
|
136
235
|
return server;
|
|
137
236
|
}
|
|
138
237
|
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/server.ts"],"sourcesContent":["import { Fotovid } from \"@fotovid/sdk\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { createServer } from \"./server.js\";\n\nasync function main() {\n\tconst apiKey = process.env.FOTOVID_API_KEY;\n\tif (!apiKey) {\n\t\tconsole.error(\n\t\t\t\"@fotovid/mcp: missing FOTOVID_API_KEY environment variable.\",\n\t\t);\n\t\tprocess.exit(1);\n\t}\n\n\tconst fotovid = new Fotovid({\n\t\tapiKey,\n\t\tbaseUrl: process.env.FOTOVID_BASE_URL,\n\t});\n\n\tconst server = createServer(fotovid);\n\tconst transport = new StdioServerTransport();\n\tawait server.connect(transport);\n\n\t// stdout is reserved for the MCP protocol; logs go to stderr.\n\tconsole.error(\"@fotovid/mcp: server running on stdio\");\n}\n\nmain().catch((error) => {\n\tconsole.error(\"@fotovid/mcp: fatal error\", error);\n\tprocess.exit(1);\n});\n","import type { Fotovid } from \"@fotovid/sdk\";\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\n\n/** Run an SDK call and shape it into an MCP tool result. */\nasync function run(work: () => Promise<unknown>) {\n\ttry {\n\t\tconst data = await work();\n\t\treturn {\n\t\t\tcontent: [{ type: \"text\" as const, text: JSON.stringify(data, null, 2) }],\n\t\t};\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\treturn {\n\t\t\tcontent: [{ type: \"text\" as const, text: `Fotovid error: ${message}` }],\n\t\t\tisError: true,\n\t\t};\n\t}\n}\n\n// Shared input pieces (snake_case, 1:1 with the API).\nconst source_url = z\n\t.string()\n\t.url()\n\t.describe(\"Public http(s) URL of the source media\");\nconst position = z\n\t.enum([\"top-left\", \"top-right\", \"bottom-left\", \"bottom-right\", \"center\"])\n\t.describe(\"Watermark anchor (default bottom-right)\");\nconst output_format = z\n\t.enum([\"webp\", \"jpeg\", \"jpg\", \"png\"])\n\t.describe(\"Output image format (default webp)\");\nconst quality = z\n\t.number()\n\t.int()\n\t.min(1)\n\t.max(100)\n\t.describe(\"Lossy quality 1–100 (png ignores it)\");\nconst start = z.number().min(0).describe(\"Window start in seconds (inclusive)\");\nconst end = z\n\t.number()\n\t.min(0)\n\t.describe(\"Window end in seconds (exclusive); must be greater than start\");\n\nconst watermarkShape = {\n\tsource_url,\n\twatermark_type: z\n\t\t.enum([\"text\", \"image\", \"combo\"])\n\t\t.optional()\n\t\t.describe(\"Watermark variant (default text)\"),\n\ttext: z\n\t\t.string()\n\t\t.max(1000)\n\t\t.optional()\n\t\t.describe(\"Overlay text (required for text/combo)\"),\n\tfont_size: z\n\t\t.number()\n\t\t.int()\n\t\t.min(8)\n\t\t.max(200)\n\t\t.optional()\n\t\t.describe(\"Text size in px (text/combo)\"),\n\tfont_color: z\n\t\t.string()\n\t\t.regex(/^(#?[0-9A-Fa-f]{6}([0-9A-Fa-f]{2})?|[A-Za-z]+)$/)\n\t\t.optional()\n\t\t.describe(\"Text color: a name (letters only) or #RRGGBB[AA] (text/combo)\"),\n\twatermark_image_url: z\n\t\t.string()\n\t\t.url()\n\t\t.optional()\n\t\t.describe(\"Logo image URL (required for image/combo)\"),\n\tscale: z\n\t\t.number()\n\t\t.gt(0)\n\t\t.max(1)\n\t\t.optional()\n\t\t.describe(\"Logo width as a fraction of source width (>0–1; image/combo)\"),\n\topacity: z\n\t\t.number()\n\t\t.gt(0)\n\t\t.max(1)\n\t\t.optional()\n\t\t.describe(\"Watermark opacity (>0–1; omit for fully opaque)\"),\n\tposition: position.optional(),\n\tpadding: z\n\t\t.number()\n\t\t.int()\n\t\t.min(0)\n\t\t.max(500)\n\t\t.optional()\n\t\t.describe(\"Edge padding in px\"),\n\toutput_format: output_format.optional(),\n\tquality: quality.optional(),\n};\n\n/** Build an MCP server exposing Fotovid media operations as tools. */\nexport function createServer(fotovid: Fotovid): McpServer {\n\tconst server = new McpServer({ name: \"fotovid\", version: \"0.1.0\" });\n\n\tserver.registerTool(\n\t\t\"fotovid_watermark_video\",\n\t\t{\n\t\t\ttitle: \"Watermark a video\",\n\t\t\tdescription:\n\t\t\t\t\"Overlay text or a logo on a video (position, opacity, scale, padding). Returns a URL to the finished video — hosted, time-limited, opaque; see expires_at, and store your own copy.\",\n\t\t\tinputSchema: {\n\t\t\t\t...watermarkShape,\n\t\t\t\tpreset: z\n\t\t\t\t\t.enum([\n\t\t\t\t\t\t\"ultrafast\",\n\t\t\t\t\t\t\"superfast\",\n\t\t\t\t\t\t\"veryfast\",\n\t\t\t\t\t\t\"faster\",\n\t\t\t\t\t\t\"fast\",\n\t\t\t\t\t\t\"medium\",\n\t\t\t\t\t\t\"slow\",\n\t\t\t\t\t\t\"slower\",\n\t\t\t\t\t\t\"veryslow\",\n\t\t\t\t\t\t\"placebo\",\n\t\t\t\t\t])\n\t\t\t\t\t.optional()\n\t\t\t\t\t.describe(\"x264 encode preset (video only)\"),\n\t\t\t},\n\t\t},\n\t\t(args) => run(() => fotovid.video.watermark(args)),\n\t);\n\n\tserver.registerTool(\n\t\t\"fotovid_watermark_image\",\n\t\t{\n\t\t\ttitle: \"Watermark an image\",\n\t\t\tdescription:\n\t\t\t\t\"Overlay text or a logo on an image. Returns a URL to the finished image — hosted, time-limited, opaque; see expires_at, and store your own copy.\",\n\t\t\tinputSchema: watermarkShape,\n\t\t},\n\t\t(args) => run(() => fotovid.image.watermark(args)),\n\t);\n\n\tserver.registerTool(\n\t\t\"fotovid_trim_video\",\n\t\t{\n\t\t\ttitle: \"Trim a video\",\n\t\t\tdescription:\n\t\t\t\t\"Cut a frame-accurate clip between two timestamps (seconds). Returns a URL to the trimmed video — hosted, time-limited, opaque; see expires_at.\",\n\t\t\tinputSchema: {\n\t\t\t\tsource_url,\n\t\t\t\tstart,\n\t\t\t\tend,\n\t\t\t},\n\t\t},\n\t\t(args) => run(() => fotovid.video.trim(args)),\n\t);\n\n\tserver.registerTool(\n\t\t\"fotovid_extract_audio\",\n\t\t{\n\t\t\ttitle: \"Extract audio from a video\",\n\t\t\tdescription:\n\t\t\t\t\"Pull the audio track out of a video and return it as an MP3 — a hosted, time-limited, opaque URL; see expires_at.\",\n\t\t\tinputSchema: { source_url },\n\t\t},\n\t\t(args) => run(() => fotovid.video.extractAudio(args)),\n\t);\n\n\tserver.registerTool(\n\t\t\"fotovid_trim_audio\",\n\t\t{\n\t\t\ttitle: \"Trim an audio file\",\n\t\t\tdescription:\n\t\t\t\t\"Slice an audio file to a start/end window (seconds) and return it as an MP3 — a hosted, time-limited, opaque URL; see expires_at.\",\n\t\t\tinputSchema: {\n\t\t\t\tsource_url,\n\t\t\t\tstart,\n\t\t\t\tend,\n\t\t\t},\n\t\t},\n\t\t(args) => run(() => fotovid.audio.trim(args)),\n\t);\n\n\tserver.registerTool(\n\t\t\"fotovid_video_thumbnail\",\n\t\t{\n\t\t\ttitle: \"Grab a video thumbnail\",\n\t\t\tdescription:\n\t\t\t\t\"Capture a frame at a given timestamp as an image thumbnail. Returns a URL — hosted, time-limited, opaque; see expires_at.\",\n\t\t\tinputSchema: {\n\t\t\t\tsource_url,\n\t\t\t\tat: z\n\t\t\t\t\t.number()\n\t\t\t\t\t.min(0)\n\t\t\t\t\t.optional()\n\t\t\t\t\t.describe(\"Frame timestamp in seconds (default ~1s)\"),\n\t\t\t\toutput_format: output_format.optional(),\n\t\t\t\tquality: quality.optional(),\n\t\t\t},\n\t\t},\n\t\t(args) => run(() => fotovid.video.thumbnail(args)),\n\t);\n\n\tserver.registerTool(\n\t\t\"fotovid_probe_video\",\n\t\t{\n\t\t\ttitle: \"Probe video metadata\",\n\t\t\tdescription:\n\t\t\t\t\"Return metadata for a video — width, height, duration, fps, codec, and alpha. Does not produce a file.\",\n\t\t\tinputSchema: { source_url },\n\t\t},\n\t\t(args) => run(() => fotovid.video.probe(args)),\n\t);\n\n\treturn server;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/server.ts"],"sourcesContent":["import { Fotovid } from \"@fotovid/sdk\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { createServer } from \"./server.js\";\n\nasync function main() {\n\tconst apiKey = process.env.FOTOVID_API_KEY;\n\tif (!apiKey) {\n\t\tconsole.error(\n\t\t\t\"@fotovid/mcp: missing FOTOVID_API_KEY environment variable.\",\n\t\t);\n\t\tprocess.exit(1);\n\t}\n\n\tconst fotovid = new Fotovid({\n\t\tapiKey,\n\t\tbaseUrl: process.env.FOTOVID_BASE_URL,\n\t});\n\n\tconst server = createServer(fotovid);\n\tconst transport = new StdioServerTransport();\n\tawait server.connect(transport);\n\n\t// stdout is reserved for the MCP protocol; logs go to stderr.\n\tconsole.error(\"@fotovid/mcp: server running on stdio\");\n}\n\nmain().catch((error) => {\n\tconsole.error(\"@fotovid/mcp: fatal error\", error);\n\tprocess.exit(1);\n});\n","import type { Fotovid, Task } from \"@fotovid/sdk\";\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\n\n// Injected at build time from package.json by tsup (see tsup.config.ts).\ndeclare const __MCP_VERSION__: string;\n\n/** Run an SDK call and shape it into an MCP tool result. */\nasync function run(work: () => Promise<unknown>) {\n\ttry {\n\t\tconst data = await work();\n\t\treturn {\n\t\t\tcontent: [{ type: \"text\" as const, text: JSON.stringify(data, null, 2) }],\n\t\t};\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\treturn {\n\t\t\tcontent: [{ type: \"text\" as const, text: `Fotovid error: ${message}` }],\n\t\t\tisError: true,\n\t\t};\n\t}\n}\n\n/**\n * Shape a just-submitted task into what an agent needs next: nothing has run\n * yet, so there's no `outputs`/`error` — just the id and where to check back.\n */\nfunction submitted(task: Task) {\n\treturn {\n\t\ttask_id: task.id,\n\t\tstatus: task.status,\n\t\tpoll_with: \"fotovid_get_task\" as const,\n\t};\n}\n\n// Shared input pieces (snake_case, 1:1 with the API).\nconst source_url = z\n\t.string()\n\t.url()\n\t.describe(\"Public http(s) URL of the source media\");\nconst position = z\n\t.enum([\"top-left\", \"top-right\", \"bottom-left\", \"bottom-right\", \"center\"])\n\t.describe(\"Watermark anchor (default bottom-right)\");\nconst output_format = z\n\t.enum([\"webp\", \"jpeg\", \"jpg\", \"png\"])\n\t.describe(\"Output image format (default webp)\");\nconst quality = z\n\t.number()\n\t.int()\n\t.min(1)\n\t.max(100)\n\t.describe(\"Lossy quality 1–100 (png ignores it)\");\nconst start = z.number().min(0).describe(\"Window start in seconds (inclusive)\");\nconst end = z\n\t.number()\n\t.min(0)\n\t.describe(\"Window end in seconds (exclusive); must be greater than start\");\n\nconst watermarkShape = {\n\tsource_url,\n\twatermark_type: z\n\t\t.enum([\"text\", \"image\", \"combo\"])\n\t\t.optional()\n\t\t.describe(\"Watermark variant (default text)\"),\n\ttext: z\n\t\t.string()\n\t\t.max(1000)\n\t\t.optional()\n\t\t.describe(\"Overlay text (required for text/combo)\"),\n\tfont_size: z\n\t\t.number()\n\t\t.int()\n\t\t.min(8)\n\t\t.max(200)\n\t\t.optional()\n\t\t.describe(\"Text size in px (text/combo)\"),\n\tfont_color: z\n\t\t.string()\n\t\t.regex(/^(#?[0-9A-Fa-f]{6}([0-9A-Fa-f]{2})?|[A-Za-z]+)$/)\n\t\t.optional()\n\t\t.describe(\"Text color: a name (letters only) or #RRGGBB[AA] (text/combo)\"),\n\twatermark_image_url: z\n\t\t.string()\n\t\t.url()\n\t\t.optional()\n\t\t.describe(\"Logo image URL (required for image/combo)\"),\n\tscale: z\n\t\t.number()\n\t\t.gt(0)\n\t\t.max(1)\n\t\t.optional()\n\t\t.describe(\"Logo width as a fraction of source width (>0–1; image/combo)\"),\n\topacity: z\n\t\t.number()\n\t\t.gt(0)\n\t\t.max(1)\n\t\t.optional()\n\t\t.describe(\"Watermark opacity (>0–1; omit for fully opaque)\"),\n\tposition: position.optional(),\n\tpadding: z\n\t\t.number()\n\t\t.int()\n\t\t.min(0)\n\t\t.max(500)\n\t\t.optional()\n\t\t.describe(\"Edge padding in px\"),\n\toutput_format: output_format.optional(),\n\tquality: quality.optional(),\n};\n\n/** Build an MCP server exposing Fotovid media operations as tools. */\nexport function createServer(fotovid: Fotovid): McpServer {\n\tconst server = new McpServer({ name: \"fotovid\", version: __MCP_VERSION__ });\n\n\tserver.registerTool(\n\t\t\"fotovid_watermark_video\",\n\t\t{\n\t\t\ttitle: \"Watermark a video\",\n\t\t\tdescription:\n\t\t\t\t\"Overlay text or a logo on a video (position, opacity, scale, padding). Returns a URL to the finished video — hosted, time-limited, opaque; see expires_at, and store your own copy.\",\n\t\t\tinputSchema: {\n\t\t\t\t...watermarkShape,\n\t\t\t\tpreset: z\n\t\t\t\t\t.enum([\n\t\t\t\t\t\t\"ultrafast\",\n\t\t\t\t\t\t\"superfast\",\n\t\t\t\t\t\t\"veryfast\",\n\t\t\t\t\t\t\"faster\",\n\t\t\t\t\t\t\"fast\",\n\t\t\t\t\t\t\"medium\",\n\t\t\t\t\t\t\"slow\",\n\t\t\t\t\t\t\"slower\",\n\t\t\t\t\t\t\"veryslow\",\n\t\t\t\t\t\t\"placebo\",\n\t\t\t\t\t])\n\t\t\t\t\t.optional()\n\t\t\t\t\t.describe(\"x264 encode preset (video only)\"),\n\t\t\t},\n\t\t},\n\t\t(args) => run(() => fotovid.video.watermark(args)),\n\t);\n\n\tserver.registerTool(\n\t\t\"fotovid_watermark_image\",\n\t\t{\n\t\t\ttitle: \"Watermark an image\",\n\t\t\tdescription:\n\t\t\t\t\"Overlay text or a logo on an image. Returns a URL to the finished image — hosted, time-limited, opaque; see expires_at, and store your own copy.\",\n\t\t\tinputSchema: watermarkShape,\n\t\t},\n\t\t(args) => run(() => fotovid.image.watermark(args)),\n\t);\n\n\tserver.registerTool(\n\t\t\"fotovid_trim_video\",\n\t\t{\n\t\t\ttitle: \"Trim a video\",\n\t\t\tdescription:\n\t\t\t\t\"Cut a frame-accurate clip between two timestamps (seconds). Returns a URL to the trimmed video — hosted, time-limited, opaque; see expires_at.\",\n\t\t\tinputSchema: {\n\t\t\t\tsource_url,\n\t\t\t\tstart,\n\t\t\t\tend,\n\t\t\t},\n\t\t},\n\t\t(args) => run(() => fotovid.video.trim(args)),\n\t);\n\n\tserver.registerTool(\n\t\t\"fotovid_extract_audio\",\n\t\t{\n\t\t\ttitle: \"Extract audio from a video\",\n\t\t\tdescription:\n\t\t\t\t\"Pull the audio track out of a video and return it as an MP3 — a hosted, time-limited, opaque URL; see expires_at.\",\n\t\t\tinputSchema: { source_url },\n\t\t},\n\t\t(args) => run(() => fotovid.video.extractAudio(args)),\n\t);\n\n\tserver.registerTool(\n\t\t\"fotovid_trim_audio\",\n\t\t{\n\t\t\ttitle: \"Trim an audio file\",\n\t\t\tdescription:\n\t\t\t\t\"Slice an audio file to a start/end window (seconds) and return it as an MP3 — a hosted, time-limited, opaque URL; see expires_at.\",\n\t\t\tinputSchema: {\n\t\t\t\tsource_url,\n\t\t\t\tstart,\n\t\t\t\tend,\n\t\t\t},\n\t\t},\n\t\t(args) => run(() => fotovid.audio.trim(args)),\n\t);\n\n\tserver.registerTool(\n\t\t\"fotovid_video_thumbnail\",\n\t\t{\n\t\t\ttitle: \"Grab a video thumbnail\",\n\t\t\tdescription:\n\t\t\t\t\"Capture a frame at a given timestamp as an image thumbnail. Returns a URL — hosted, time-limited, opaque; see expires_at.\",\n\t\t\tinputSchema: {\n\t\t\t\tsource_url,\n\t\t\t\tat: z\n\t\t\t\t\t.number()\n\t\t\t\t\t.min(0)\n\t\t\t\t\t.optional()\n\t\t\t\t\t.describe(\"Frame timestamp in seconds (default ~1s)\"),\n\t\t\t\toutput_format: output_format.optional(),\n\t\t\t\tquality: quality.optional(),\n\t\t\t},\n\t\t},\n\t\t(args) => run(() => fotovid.video.thumbnail(args)),\n\t);\n\n\tserver.registerTool(\n\t\t\"fotovid_probe_video\",\n\t\t{\n\t\t\ttitle: \"Probe video metadata\",\n\t\t\tdescription:\n\t\t\t\t\"Return metadata for a video — width, height, duration, fps, codec, and alpha. Does not produce a file.\",\n\t\t\tinputSchema: { source_url },\n\t\t},\n\t\t(args) => run(() => fotovid.video.probe(args)),\n\t);\n\n\t// —— Async tools ——\n\t// The sync tools above reject inputs above ~720p / 15s with a 400 asking\n\t// for the async endpoint. These submit a task and return immediately —\n\t// they do NOT wait for it to finish. Follow up with fotovid_get_task\n\t// (status starting/processing → check again in a few seconds).\n\n\tserver.registerTool(\n\t\t\"fotovid_watermark_video_async\",\n\t\t{\n\t\t\ttitle: \"Watermark a video (async, for large/long video)\",\n\t\t\tdescription:\n\t\t\t\t\"Submit a video watermark job for input too large or long for the sync tool (over ~720p or 15s). Returns immediately with a task_id — poll fotovid_get_task for the result, do not wait here.\",\n\t\t\tinputSchema: {\n\t\t\t\t...watermarkShape,\n\t\t\t\tpreset: z\n\t\t\t\t\t.enum([\n\t\t\t\t\t\t\"ultrafast\",\n\t\t\t\t\t\t\"superfast\",\n\t\t\t\t\t\t\"veryfast\",\n\t\t\t\t\t\t\"faster\",\n\t\t\t\t\t\t\"fast\",\n\t\t\t\t\t\t\"medium\",\n\t\t\t\t\t\t\"slow\",\n\t\t\t\t\t\t\"slower\",\n\t\t\t\t\t\t\"veryslow\",\n\t\t\t\t\t\t\"placebo\",\n\t\t\t\t\t])\n\t\t\t\t\t.optional()\n\t\t\t\t\t.describe(\"x264 encode preset (video only)\"),\n\t\t\t},\n\t\t},\n\t\t(args) => run(() => fotovid.tasks.video.watermark(args).then(submitted)),\n\t);\n\n\tserver.registerTool(\n\t\t\"fotovid_watermark_image_async\",\n\t\t{\n\t\t\ttitle: \"Watermark an image (async)\",\n\t\t\tdescription:\n\t\t\t\t\"Submit an image watermark job. Returns immediately with a task_id — poll fotovid_get_task for the result, do not wait here.\",\n\t\t\tinputSchema: watermarkShape,\n\t\t},\n\t\t(args) => run(() => fotovid.tasks.image.watermark(args).then(submitted)),\n\t);\n\n\tserver.registerTool(\n\t\t\"fotovid_trim_video_async\",\n\t\t{\n\t\t\ttitle: \"Trim a video (async, for large/long video)\",\n\t\t\tdescription:\n\t\t\t\t\"Submit a video trim job for input too large or long for the sync tool. Returns immediately with a task_id — poll fotovid_get_task for the result, do not wait here.\",\n\t\t\tinputSchema: { source_url, start, end },\n\t\t},\n\t\t(args) => run(() => fotovid.tasks.video.trim(args).then(submitted)),\n\t);\n\n\tserver.registerTool(\n\t\t\"fotovid_extract_audio_async\",\n\t\t{\n\t\t\ttitle: \"Extract audio from a video (async, for large/long video)\",\n\t\t\tdescription:\n\t\t\t\t\"Submit an audio-extraction job for input too large or long for the sync tool. Returns immediately with a task_id — poll fotovid_get_task for the result, do not wait here.\",\n\t\t\tinputSchema: { source_url },\n\t\t},\n\t\t(args) => run(() => fotovid.tasks.video.extractAudio(args).then(submitted)),\n\t);\n\n\tserver.registerTool(\n\t\t\"fotovid_trim_audio_async\",\n\t\t{\n\t\t\ttitle: \"Trim an audio file (async, for large/long audio)\",\n\t\t\tdescription:\n\t\t\t\t\"Submit an audio trim job for input too large or long for the sync tool. Returns immediately with a task_id — poll fotovid_get_task for the result, do not wait here.\",\n\t\t\tinputSchema: { source_url, start, end },\n\t\t},\n\t\t(args) => run(() => fotovid.tasks.audio.trim(args).then(submitted)),\n\t);\n\n\tserver.registerTool(\n\t\t\"fotovid_video_thumbnail_async\",\n\t\t{\n\t\t\ttitle: \"Grab a video thumbnail (async, for large/long video)\",\n\t\t\tdescription:\n\t\t\t\t\"Submit a video-thumbnail job for input too large or long for the sync tool. Returns immediately with a task_id — poll fotovid_get_task for the result, do not wait here.\",\n\t\t\tinputSchema: {\n\t\t\t\tsource_url,\n\t\t\t\tat: z\n\t\t\t\t\t.number()\n\t\t\t\t\t.min(0)\n\t\t\t\t\t.optional()\n\t\t\t\t\t.describe(\"Frame timestamp in seconds (default ~1s)\"),\n\t\t\t\toutput_format: output_format.optional(),\n\t\t\t\tquality: quality.optional(),\n\t\t\t},\n\t\t},\n\t\t(args) => run(() => fotovid.tasks.video.thumbnail(args).then(submitted)),\n\t);\n\n\tserver.registerTool(\n\t\t\"fotovid_get_task\",\n\t\t{\n\t\t\ttitle: \"Check an async task\",\n\t\t\tdescription:\n\t\t\t\t\"Check the status of a task submitted by one of the _async tools. While status is starting/processing, outputs/error are absent — wait a couple of seconds and call again. Once status is succeeded, outputs has the result(s); once failed, error explains why (this is normal — not an exception).\",\n\t\t\tinputSchema: {\n\t\t\t\ttask_id: z.string().describe(\"Task id returned by an _async tool\"),\n\t\t\t},\n\t\t},\n\t\t({ task_id }) =>\n\t\t\trun(async () => {\n\t\t\t\tconst task = await fotovid.tasks.get(task_id);\n\t\t\t\treturn {\n\t\t\t\t\ttask_id: task.id,\n\t\t\t\t\tstatus: task.status,\n\t\t\t\t\toutputs: task.outputs,\n\t\t\t\t\terror: task.error,\n\t\t\t\t};\n\t\t\t}),\n\t);\n\n\treturn server;\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fotovid/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "MCP server exposing the Fotovid media API as first-class agent tools",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"provenance": true
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@fotovid/sdk": "^0.
|
|
22
|
+
"@fotovid/sdk": "^0.2.0",
|
|
23
23
|
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
24
24
|
"zod": "^3.23.8"
|
|
25
25
|
},
|