freebeat-mcp 0.1.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.
Files changed (78) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +210 -0
  3. package/dist/capabilities/assets/register.d.ts +3 -0
  4. package/dist/capabilities/assets/register.js +7 -0
  5. package/dist/capabilities/assets/register.js.map +1 -0
  6. package/dist/capabilities/assets/tools/upload-audio.d.ts +3 -0
  7. package/dist/capabilities/assets/tools/upload-audio.js +70 -0
  8. package/dist/capabilities/assets/tools/upload-audio.js.map +1 -0
  9. package/dist/capabilities/assets/tools/upload-image.d.ts +3 -0
  10. package/dist/capabilities/assets/tools/upload-image.js +67 -0
  11. package/dist/capabilities/assets/tools/upload-image.js.map +1 -0
  12. package/dist/capabilities/effects/register.d.ts +3 -0
  13. package/dist/capabilities/effects/register.js +7 -0
  14. package/dist/capabilities/effects/register.js.map +1 -0
  15. package/dist/capabilities/effects/task-type.d.ts +1 -0
  16. package/dist/capabilities/effects/task-type.js +2 -0
  17. package/dist/capabilities/effects/task-type.js.map +1 -0
  18. package/dist/capabilities/effects/tools/generate-effect.d.ts +3 -0
  19. package/dist/capabilities/effects/tools/generate-effect.js +81 -0
  20. package/dist/capabilities/effects/tools/generate-effect.js.map +1 -0
  21. package/dist/capabilities/effects/tools/list-effects.d.ts +3 -0
  22. package/dist/capabilities/effects/tools/list-effects.js +55 -0
  23. package/dist/capabilities/effects/tools/list-effects.js.map +1 -0
  24. package/dist/capabilities/mv/register.d.ts +3 -0
  25. package/dist/capabilities/mv/register.js +5 -0
  26. package/dist/capabilities/mv/register.js.map +1 -0
  27. package/dist/capabilities/mv/task-type.d.ts +1 -0
  28. package/dist/capabilities/mv/task-type.js +2 -0
  29. package/dist/capabilities/mv/task-type.js.map +1 -0
  30. package/dist/capabilities/mv/tools/generate-music-video.d.ts +3 -0
  31. package/dist/capabilities/mv/tools/generate-music-video.js +116 -0
  32. package/dist/capabilities/mv/tools/generate-music-video.js.map +1 -0
  33. package/dist/capabilities/tasks/register.d.ts +3 -0
  34. package/dist/capabilities/tasks/register.js +7 -0
  35. package/dist/capabilities/tasks/register.js.map +1 -0
  36. package/dist/capabilities/tasks/task-type.d.ts +1 -0
  37. package/dist/capabilities/tasks/task-type.js +2 -0
  38. package/dist/capabilities/tasks/task-type.js.map +1 -0
  39. package/dist/capabilities/tasks/tools/get-task-result.d.ts +3 -0
  40. package/dist/capabilities/tasks/tools/get-task-result.js +93 -0
  41. package/dist/capabilities/tasks/tools/get-task-result.js.map +1 -0
  42. package/dist/capabilities/tasks/tools/get-task-status.d.ts +3 -0
  43. package/dist/capabilities/tasks/tools/get-task-status.js +63 -0
  44. package/dist/capabilities/tasks/tools/get-task-status.js.map +1 -0
  45. package/dist/core/config.d.ts +4 -0
  46. package/dist/core/config.js +11 -0
  47. package/dist/core/config.js.map +1 -0
  48. package/dist/core/errors.d.ts +6 -0
  49. package/dist/core/errors.js +35 -0
  50. package/dist/core/errors.js.map +1 -0
  51. package/dist/core/prompt.d.ts +1 -0
  52. package/dist/core/prompt.js +12 -0
  53. package/dist/core/prompt.js.map +1 -0
  54. package/dist/core/response.d.ts +14 -0
  55. package/dist/core/response.js +26 -0
  56. package/dist/core/response.js.map +1 -0
  57. package/dist/core/task-types.d.ts +6 -0
  58. package/dist/core/task-types.js +20 -0
  59. package/dist/core/task-types.js.map +1 -0
  60. package/dist/core/tasks.d.ts +1 -0
  61. package/dist/core/tasks.js +2 -0
  62. package/dist/core/tasks.js.map +1 -0
  63. package/dist/core/tool-schemas.d.ts +7 -0
  64. package/dist/core/tool-schemas.js +64 -0
  65. package/dist/core/tool-schemas.js.map +1 -0
  66. package/dist/index.d.ts +2 -0
  67. package/dist/index.js +26 -0
  68. package/dist/index.js.map +1 -0
  69. package/dist/services/freebeat-api.d.ts +117 -0
  70. package/dist/services/freebeat-api.js +188 -0
  71. package/dist/services/freebeat-api.js.map +1 -0
  72. package/dist/services/upload-service.d.ts +13 -0
  73. package/dist/services/upload-service.js +22 -0
  74. package/dist/services/upload-service.js.map +1 -0
  75. package/dist/utils/file.d.ts +5 -0
  76. package/dist/utils/file.js +69 -0
  77. package/dist/utils/file.js.map +1 -0
  78. package/package.json +48 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Freebeat
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,210 @@
1
+ # freebeat-mcp
2
+
3
+ MCP server for Freebeat creative workflows.
4
+
5
+ Use it from MCP clients such as Claude Desktop and Cursor through `npx freebeat-mcp`.
6
+
7
+ It currently supports audio and image upload, effect template discovery, AI effect generation, AI music video generation, and async task polling.
8
+
9
+ ## Features
10
+
11
+ - Local audio upload or source URL import
12
+ - Image upload for workflows that accept reference images
13
+ - Supported effect template listing
14
+ - AI effect generation
15
+ - AI music video generation
16
+ - Generic task polling and result retrieval
17
+
18
+ ## Installation
19
+
20
+ Run the server through npm without a separate install step:
21
+
22
+ ```bash
23
+ npx -y freebeat-mcp
24
+ ```
25
+
26
+ ## Prerequisites
27
+
28
+ - Get your API key from [freebeat.ai](https://freebeat.ai).
29
+ - Use an MCP client such as Claude Desktop or Cursor.
30
+
31
+ ## Configuration
32
+
33
+ ### Claude Desktop
34
+
35
+ ```json
36
+ {
37
+ "mcpServers": {
38
+ "freebeat": {
39
+ "command": "npx",
40
+ "args": ["-y", "freebeat-mcp"],
41
+ "env": {
42
+ "FREEBEAT_API_KEY": "your-api-key-here"
43
+ }
44
+ }
45
+ }
46
+ }
47
+ ```
48
+
49
+ ### Cursor
50
+
51
+ ```json
52
+ {
53
+ "mcpServers": {
54
+ "freebeat": {
55
+ "command": "npx",
56
+ "args": ["-y", "freebeat-mcp"],
57
+ "env": {
58
+ "FREEBEAT_API_KEY": "your-api-key-here"
59
+ }
60
+ }
61
+ }
62
+ }
63
+ ```
64
+
65
+ ## Environment Variables
66
+
67
+ | Variable | Required | Description |
68
+ | --- | --- | --- |
69
+ | `FREEBEAT_API_KEY` | Yes | API authentication key |
70
+
71
+ This package depends on Freebeat online services. Available source platforms, effect templates, and generation capabilities may change with backend updates.
72
+
73
+ ## Tools
74
+
75
+ ### `upload_audio`
76
+
77
+ Upload a local audio file or import from a music platform URL.
78
+
79
+ Currently supported platforms:
80
+
81
+ - SoundCloud
82
+ - YouTube
83
+ - Suno
84
+ - Udio
85
+ - TikTok
86
+ - Stable Audio
87
+ - Riffusion
88
+
89
+ Provide exactly one of `file_path` or `url`.
90
+
91
+ Returns a `music_id` that can be used by either `generate_music_video` or `generate_effect`.
92
+
93
+ ### `upload_image`
94
+
95
+ Upload one or two images and receive `image_urls`.
96
+
97
+ For MV generation, pass the returned `image_urls` into `generate_music_video.reference_image_urls`.
98
+
99
+ For effect generation, the default recommendation is still `list_effects.image_url`, but you can also upload one image and pass `image_urls[0]` into `generate_effect.reference_image_urls`.
100
+
101
+ ### `list_effects`
102
+
103
+ List supported effects with:
104
+
105
+ - `effect_id`
106
+ - `display_name`
107
+ - `image_url`
108
+ - `preview_video_url`
109
+ - `default_music_id`
110
+ - `default_music_name`
111
+ - `aspect_ratio`
112
+
113
+ For effect generation, pass:
114
+
115
+ - `effect_id` into `generate_effect.effect_id`
116
+ - `default_music_id` into `generate_effect.music_id`
117
+ - `image_url` as the default single entry in `generate_effect.reference_image_urls`
118
+
119
+ You can use the built-in effect image directly, or replace it with a single uploaded image URL from `upload_image`.
120
+
121
+ ### `generate_effect`
122
+
123
+ Start an async effect generation task.
124
+
125
+ Recommended flow:
126
+
127
+ - `list_effects`
128
+ - optional `upload_audio` if you want to replace the effect's default music
129
+ - optional `upload_image` if you want to replace the effect's default image
130
+ - `generate_effect`
131
+ - `get_task_status`
132
+ - `get_task_result` only after status is `completed`
133
+
134
+ Parameters:
135
+
136
+ - `effect_id` required
137
+ - `music_id` required, usually `default_music_id` from `list_effects`, or a `music_id` from `upload_audio` if you want to replace it
138
+ - `prompt` required, trimmed length must be `1` to `2000`
139
+ - `watermark` optional, default `false`
140
+ - `reference_image_urls` required and must contain exactly one image URL; recommended default is `list_effects.image_url`, but you can also use `upload_image.image_urls[0]`
141
+
142
+ Returns a task envelope with:
143
+
144
+ - `task_id`
145
+ - `task_type` currently `effect_generation`
146
+ - `status`
147
+
148
+ ### `generate_music_video`
149
+
150
+ Start an async MV generation task from a `music_id` returned by `upload_audio`.
151
+
152
+ Recommended flow:
153
+
154
+ - `upload_audio`
155
+ - optional `upload_image`
156
+ - `generate_music_video`
157
+ - `get_task_status`
158
+ - `get_task_result` only after status is `completed`
159
+
160
+ Parameters:
161
+
162
+ - `music_id` required, from `upload_audio`
163
+ - `prompt` required, trimmed length must be `1` to `2000`
164
+ - `mv_type` optional, default `abstract`
165
+ - `style` optional
166
+ - `aspect_ratio` optional, default `16:9`
167
+ - `resolution` optional, default `720`
168
+ - `watermark` optional, default `false`
169
+ - `start_ms` optional
170
+ - `end_ms` optional
171
+ - `reference_image_urls` optional
172
+
173
+ Returns a task envelope with:
174
+
175
+ - `task_id`
176
+ - `task_type` currently `music_video_generation`
177
+ - `status`
178
+
179
+ ### `get_task_status`
180
+
181
+ Poll a Freebeat async task until it reaches a terminal status. Current MCP endpoints return lowercase status values such as `pending`, `completed`, and `failed`; older backends may still return uppercase variants.
182
+
183
+ Continue polling while the status is still in progress. Only call `get_task_result` after the status is `completed`.
184
+
185
+ Returns a stable task envelope including:
186
+
187
+ - `task_id`
188
+ - `task_type`
189
+ - `status`
190
+ - `error_message` optional, present when backend reports a failed task
191
+ - `error_code` optional, present when backend reports a failed task
192
+ - `message` optional, present when status is `completed` or `failed`
193
+
194
+ ### `get_task_result`
195
+
196
+ Retrieve the output for a completed task. Only call this after `get_task_status` returns `completed`. The response uses a stable envelope with `task_id`, `task_type`, `status`, and `result`.
197
+
198
+ If the task is not completed yet, this tool returns error code `TASK_NOT_COMPLETED`.
199
+
200
+ If the task has failed, this tool surfaces the backend failure as an error.
201
+
202
+ For current supported completed MV tasks, `result` is an object containing:
203
+
204
+ - `video_url`
205
+ - `cover_url`
206
+
207
+ Completed effect generation results use the same `result` object fields:
208
+
209
+ - `video_url`
210
+ - `cover_url`
@@ -0,0 +1,3 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { FreebeatApiClient } from "../../services/freebeat-api.js";
3
+ export declare function registerAssetTools(server: McpServer, client: FreebeatApiClient): void;
@@ -0,0 +1,7 @@
1
+ import { registerUploadAudioTool } from "./tools/upload-audio.js";
2
+ import { registerUploadImageTool } from "./tools/upload-image.js";
3
+ export function registerAssetTools(server, client) {
4
+ registerUploadAudioTool(server, client);
5
+ registerUploadImageTool(server, client);
6
+ }
7
+ //# sourceMappingURL=register.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register.js","sourceRoot":"","sources":["../../../src/capabilities/assets/register.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAElE,MAAM,UAAU,kBAAkB,CAChC,MAAiB,EACjB,MAAyB;IAEzB,uBAAuB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,uBAAuB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAC1C,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { FreebeatApiClient } from "../../../services/freebeat-api.js";
3
+ export declare function registerUploadAudioTool(server: McpServer, client: Pick<FreebeatApiClient, "createUploadUrl" | "uploadToPreSignedUrl" | "saveMusicSource">): void;
@@ -0,0 +1,70 @@
1
+ import { z } from "zod";
2
+ import { AppError } from "../../../core/errors.js";
3
+ import { formatToolError, jsonContent } from "../../../core/response.js";
4
+ import { UploadService } from "../../../services/upload-service.js";
5
+ import { detectAudioMimeType, validateAudioFile, } from "../../../utils/file.js";
6
+ export function registerUploadAudioTool(server, client) {
7
+ const uploadService = new UploadService(client);
8
+ server.registerTool("upload_audio", {
9
+ description: "Upload a local audio file or import from a supported music URL. Supported platforms: SoundCloud, YouTube, Suno, Udio, TikTok, Stable Audio, and Riffusion. Provide exactly one of file_path or url. Returns a music_id for generate_music_video or generate_effect.",
10
+ outputSchema: {
11
+ success: z
12
+ .literal(true)
13
+ .describe("Whether the audio upload or import completed successfully."),
14
+ music_id: z
15
+ .number()
16
+ .describe("The audio asset ID to pass into generate_music_video or generate_effect."),
17
+ message: z
18
+ .string()
19
+ .describe("A human-readable summary of the audio source preparation result."),
20
+ },
21
+ inputSchema: {
22
+ file_path: z
23
+ .string()
24
+ .optional()
25
+ .describe("Local audio file path. Set this or url, not both."),
26
+ url: z
27
+ .string()
28
+ .optional()
29
+ .describe("Supported music source URL from SoundCloud, YouTube, Suno, Udio, TikTok, Stable Audio, or Riffusion. Set this or file_path, not both."),
30
+ },
31
+ }, async ({ file_path, url }) => {
32
+ try {
33
+ if ((!file_path && !url) || (file_path && url)) {
34
+ return formatToolError(new AppError("Exactly one of file_path or url must be provided", "INVALID_PARAMS"));
35
+ }
36
+ let musicId;
37
+ if (file_path) {
38
+ validateAudioFile(file_path);
39
+ const finalStaticUrl = await uploadService.uploadLocalFile({
40
+ filePath: file_path,
41
+ keyPrefix: "dance/music",
42
+ contentType: detectAudioMimeType(file_path),
43
+ });
44
+ try {
45
+ musicId = await client.saveMusicSource(finalStaticUrl);
46
+ }
47
+ catch (error) {
48
+ console.error(`File uploaded (${finalStaticUrl}) but saveMusicSource failed. Orphan file may exist.`);
49
+ throw error;
50
+ }
51
+ }
52
+ else {
53
+ if (!url) {
54
+ return formatToolError(new AppError("Exactly one of file_path or url must be provided", "INVALID_PARAMS"));
55
+ }
56
+ musicId = await client.saveMusicSource(url);
57
+ }
58
+ return jsonContent({
59
+ success: true,
60
+ music_id: musicId,
61
+ message: `Audio source ready. Use music_id=${musicId} with ` +
62
+ "generate_music_video or generate_effect.",
63
+ });
64
+ }
65
+ catch (error) {
66
+ return formatToolError(error);
67
+ }
68
+ });
69
+ }
70
+ //# sourceMappingURL=upload-audio.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upload-audio.js","sourceRoot":"","sources":["../../../../src/capabilities/assets/tools/upload-audio.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAEzE,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AACpE,OAAO,EACL,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,wBAAwB,CAAC;AAEhC,MAAM,UAAU,uBAAuB,CACrC,MAAiB,EACjB,MAGC;IAED,MAAM,aAAa,GAAG,IAAI,aAAa,CAAC,MAAM,CAAC,CAAC;IAEhD,MAAM,CAAC,YAAY,CACjB,cAAc,EACd;QACE,WAAW,EACT,qQAAqQ;QACvQ,YAAY,EAAE;YACZ,OAAO,EAAE,CAAC;iBACP,OAAO,CAAC,IAAI,CAAC;iBACb,QAAQ,CAAC,4DAA4D,CAAC;YACzE,QAAQ,EAAE,CAAC;iBACR,MAAM,EAAE;iBACR,QAAQ,CAAC,0EAA0E,CAAC;YACvF,OAAO,EAAE,CAAC;iBACP,MAAM,EAAE;iBACR,QAAQ,CAAC,kEAAkE,CAAC;SAChF;QACD,WAAW,EAAE;YACX,SAAS,EAAE,CAAC;iBACT,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CACP,mDAAmD,CACpD;YACH,GAAG,EAAE,CAAC;iBACH,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CACP,uIAAuI,CACxI;SACJ;KACF,EACD,KAAK,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,EAAE,EAAE;QAC3B,IAAI,CAAC;YACH,IAAI,CAAC,CAAC,SAAS,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,IAAI,GAAG,CAAC,EAAE,CAAC;gBAC/C,OAAO,eAAe,CACpB,IAAI,QAAQ,CAAC,kDAAkD,EAAE,gBAAgB,CAAC,CACnF,CAAC;YACJ,CAAC;YAED,IAAI,OAAe,CAAC;YAEpB,IAAI,SAAS,EAAE,CAAC;gBACd,iBAAiB,CAAC,SAAS,CAAC,CAAC;gBAE7B,MAAM,cAAc,GAAG,MAAM,aAAa,CAAC,eAAe,CAAC;oBACzD,QAAQ,EAAE,SAAS;oBACnB,SAAS,EAAE,aAAa;oBACxB,WAAW,EAAE,mBAAmB,CAAC,SAAS,CAAC;iBAC5C,CAAC,CAAC;gBAEH,IAAI,CAAC;oBACH,OAAO,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,cAAc,CAAC,CAAC;gBACzD,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,OAAO,CAAC,KAAK,CACX,kBAAkB,cAAc,sDAAsD,CACvF,CAAC;oBACF,MAAM,KAAK,CAAC;gBACd,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,GAAG,EAAE,CAAC;oBACT,OAAO,eAAe,CACpB,IAAI,QAAQ,CAAC,kDAAkD,EAAE,gBAAgB,CAAC,CACnF,CAAC;gBACJ,CAAC;gBAED,OAAO,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;YAC9C,CAAC;YAED,OAAO,WAAW,CAAC;gBACjB,OAAO,EAAE,IAAI;gBACb,QAAQ,EAAE,OAAO;gBACjB,OAAO,EACL,oCAAoC,OAAO,QAAQ;oBACnD,0CAA0C;aAC7C,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,OAAO,eAAe,CAAC,KAAK,CAAC,CAAC;QAChC,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { FreebeatApiClient } from "../../../services/freebeat-api.js";
3
+ export declare function registerUploadImageTool(server: McpServer, client: Pick<FreebeatApiClient, "createUploadUrl" | "uploadToPreSignedUrl">): void;
@@ -0,0 +1,67 @@
1
+ import { z } from "zod";
2
+ import { formatToolError, jsonContent } from "../../../core/response.js";
3
+ import { UploadService } from "../../../services/upload-service.js";
4
+ import { detectImageMimeType, validateImageFile, } from "../../../utils/file.js";
5
+ export function registerUploadImageTool(server, client) {
6
+ const uploadService = new UploadService(client);
7
+ server.registerTool("upload_image", {
8
+ description: "Upload one or two image files (PNG/JPG/JPEG, max 10MB each) for Freebeat workflows. Use returned image_urls in generate_music_video.reference_image_urls, or pass a single uploaded image URL to generate_effect.reference_image_urls to replace the default list_effects.image_url.",
9
+ outputSchema: {
10
+ success: z
11
+ .literal(true)
12
+ .describe("Whether the image upload completed successfully."),
13
+ image_urls: z
14
+ .array(z
15
+ .string()
16
+ .describe("A static URL for an uploaded image."))
17
+ .describe("The uploaded image URLs returned by Freebeat."),
18
+ message: z
19
+ .string()
20
+ .describe("A human-readable summary of the upload result."),
21
+ },
22
+ inputSchema: {
23
+ file_paths: z
24
+ .array(z.string())
25
+ .min(1)
26
+ .max(2)
27
+ .describe("Local image file paths to upload. Provide 1 to 2 image files."),
28
+ },
29
+ }, async ({ file_paths }) => {
30
+ try {
31
+ for (const filePath of file_paths) {
32
+ validateImageFile(filePath);
33
+ }
34
+ const imageUrls = [];
35
+ for (let index = 0; index < file_paths.length; index += 1) {
36
+ const filePath = file_paths[index];
37
+ try {
38
+ const finalStaticUrl = await uploadService.uploadLocalFile({
39
+ filePath,
40
+ keyPrefix: "agent/character",
41
+ contentType: detectImageMimeType(filePath),
42
+ keySuffix: String(index),
43
+ });
44
+ imageUrls.push(finalStaticUrl);
45
+ }
46
+ catch (error) {
47
+ if (imageUrls.length > 0) {
48
+ console.error(`Image upload failed at file ${index + 1}/${file_paths.length}. ` +
49
+ `${imageUrls.length} previously uploaded image(s) may be orphaned on S3: ${imageUrls.join(", ")}`);
50
+ }
51
+ throw error;
52
+ }
53
+ }
54
+ return jsonContent({
55
+ success: true,
56
+ image_urls: imageUrls,
57
+ message: `Uploaded ${imageUrls.length} image(s). Use image_urls with ` +
58
+ "generate_music_video.reference_image_urls, or use one uploaded image URL in " +
59
+ "generate_effect.reference_image_urls to replace the default effect image.",
60
+ });
61
+ }
62
+ catch (error) {
63
+ return formatToolError(error);
64
+ }
65
+ });
66
+ }
67
+ //# sourceMappingURL=upload-image.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upload-image.js","sourceRoot":"","sources":["../../../../src/capabilities/assets/tools/upload-image.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAEzE,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AACpE,OAAO,EACL,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,wBAAwB,CAAC;AAEhC,MAAM,UAAU,uBAAuB,CACrC,MAAiB,EACjB,MAA2E;IAE3E,MAAM,aAAa,GAAG,IAAI,aAAa,CAAC,MAAM,CAAC,CAAC;IAEhD,MAAM,CAAC,YAAY,CACjB,cAAc,EACd;QACE,WAAW,EACT,sRAAsR;QACxR,YAAY,EAAE;YACZ,OAAO,EAAE,CAAC;iBACP,OAAO,CAAC,IAAI,CAAC;iBACb,QAAQ,CAAC,kDAAkD,CAAC;YAC/D,UAAU,EAAE,CAAC;iBACV,KAAK,CACJ,CAAC;iBACE,MAAM,EAAE;iBACR,QAAQ,CAAC,qCAAqC,CAAC,CACnD;iBACA,QAAQ,CAAC,+CAA+C,CAAC;YAC5D,OAAO,EAAE,CAAC;iBACP,MAAM,EAAE;iBACR,QAAQ,CAAC,gDAAgD,CAAC;SAC9D;QACD,WAAW,EAAE;YACX,UAAU,EAAE,CAAC;iBACV,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;iBACjB,GAAG,CAAC,CAAC,CAAC;iBACN,GAAG,CAAC,CAAC,CAAC;iBACN,QAAQ,CAAC,+DAA+D,CAAC;SAC7E;KACF,EACD,KAAK,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE;QACvB,IAAI,CAAC;YACH,KAAK,MAAM,QAAQ,IAAI,UAAU,EAAE,CAAC;gBAClC,iBAAiB,CAAC,QAAQ,CAAC,CAAC;YAC9B,CAAC;YAED,MAAM,SAAS,GAAa,EAAE,CAAC;YAC/B,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,UAAU,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;gBAC1D,MAAM,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;gBAEnC,IAAI,CAAC;oBACH,MAAM,cAAc,GAAG,MAAM,aAAa,CAAC,eAAe,CAAC;wBACzD,QAAQ;wBACR,SAAS,EAAE,iBAAiB;wBAC5B,WAAW,EAAE,mBAAmB,CAAC,QAAQ,CAAC;wBAC1C,SAAS,EAAE,MAAM,CAAC,KAAK,CAAC;qBACzB,CAAC,CAAC;oBACH,SAAS,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;gBACjC,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;wBACzB,OAAO,CAAC,KAAK,CACX,+BAA+B,KAAK,GAAG,CAAC,IAAI,UAAU,CAAC,MAAM,IAAI;4BAC/D,GAAG,SAAS,CAAC,MAAM,wDAAwD,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACpG,CAAC;oBACJ,CAAC;oBACD,MAAM,KAAK,CAAC;gBACd,CAAC;YACH,CAAC;YAED,OAAO,WAAW,CAAC;gBACjB,OAAO,EAAE,IAAI;gBACb,UAAU,EAAE,SAAS;gBACrB,OAAO,EACL,YAAY,SAAS,CAAC,MAAM,iCAAiC;oBAC7D,8EAA8E;oBAC9E,2EAA2E;aAC9E,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,OAAO,eAAe,CAAC,KAAK,CAAC,CAAC;QAChC,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { FreebeatApiClient } from "../../services/freebeat-api.js";
3
+ export declare function registerEffectTools(server: McpServer, client: FreebeatApiClient): void;
@@ -0,0 +1,7 @@
1
+ import { registerGenerateEffectTool } from "./tools/generate-effect.js";
2
+ import { registerListEffectsTool } from "./tools/list-effects.js";
3
+ export function registerEffectTools(server, client) {
4
+ registerListEffectsTool(server, client);
5
+ registerGenerateEffectTool(server, client);
6
+ }
7
+ //# sourceMappingURL=register.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register.js","sourceRoot":"","sources":["../../../src/capabilities/effects/register.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,0BAA0B,EAAE,MAAM,4BAA4B,CAAC;AACxE,OAAO,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAElE,MAAM,UAAU,mBAAmB,CACjC,MAAiB,EACjB,MAAyB;IAEzB,uBAAuB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,0BAA0B,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAC7C,CAAC"}
@@ -0,0 +1 @@
1
+ export { EFFECT_TASK_TYPE } from "../../core/task-types.js";
@@ -0,0 +1,2 @@
1
+ export { EFFECT_TASK_TYPE } from "../../core/task-types.js";
2
+ //# sourceMappingURL=task-type.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task-type.js","sourceRoot":"","sources":["../../../src/capabilities/effects/task-type.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { FreebeatApiClient } from "../../../services/freebeat-api.js";
3
+ export declare function registerGenerateEffectTool(server: McpServer, client: Pick<FreebeatApiClient, "generateEffect">): void;
@@ -0,0 +1,81 @@
1
+ import { z } from "zod";
2
+ import { AppError } from "../../../core/errors.js";
3
+ import { normalizeGenerationPrompt } from "../../../core/prompt.js";
4
+ import { formatToolError, jsonContent } from "../../../core/response.js";
5
+ export function registerGenerateEffectTool(server, client) {
6
+ server.registerTool("generate_effect", {
7
+ description: "Start AI effect generation from an effect template, a music_id, and exactly one reference image URL. Recommended flow: list_effects -> optional upload_audio -> optional upload_image -> generate_effect -> get_task_status -> get_task_result. By default, use list_effects.image_url. You can also use a single uploaded image URL from upload_image. Only call get_task_result after get_task_status returns completed.",
8
+ outputSchema: {
9
+ success: z
10
+ .literal(true)
11
+ .describe("Whether the effect task was created successfully."),
12
+ task_id: z
13
+ .string()
14
+ .describe("The asynchronous task ID for status and result lookups."),
15
+ task_type: z
16
+ .string()
17
+ .describe("The task category returned by Freebeat."),
18
+ status: z
19
+ .string()
20
+ .describe("The initial task status, typically pending."),
21
+ message: z
22
+ .string()
23
+ .describe("A human-readable summary of the task creation result."),
24
+ },
25
+ inputSchema: {
26
+ effect_id: z.number().int().describe("Effect ID returned by list_effects."),
27
+ music_id: z
28
+ .number()
29
+ .int()
30
+ .describe("Music ID to use for the effect. Usually default_music_id from list_effects, or a music_id from upload_audio if you want to replace it."),
31
+ prompt: z
32
+ .string()
33
+ .trim()
34
+ .min(1, "prompt must not be empty or whitespace only")
35
+ .max(2000, "prompt must be at most 2000 characters after trimming")
36
+ .describe("Required task instruction. After trimming whitespace it must be 1 to 2000 characters and should describe how you want the effect task to be done."),
37
+ watermark: z
38
+ .boolean()
39
+ .optional()
40
+ .default(false)
41
+ .describe("Whether to apply a watermark to the generated effect video."),
42
+ reference_image_urls: z
43
+ .array(z
44
+ .string()
45
+ .describe("Single image URL. Recommended: list_effects.image_url. You may also use a single uploaded image URL from upload_image."))
46
+ .length(1, "reference_image_urls must contain exactly one image URL")
47
+ .describe("Exactly one image URL. Recommended: use list_effects.image_url. You may also use a single uploaded image URL from upload_image."),
48
+ },
49
+ }, async ({ effect_id, music_id, prompt, watermark, reference_image_urls, }) => {
50
+ try {
51
+ const normalizedPrompt = normalizeGenerationPrompt(prompt);
52
+ if (!Number.isInteger(effect_id)) {
53
+ return formatToolError(new AppError("effect_id must be an integer", "INVALID_PARAMS"));
54
+ }
55
+ if (!Number.isInteger(music_id)) {
56
+ return formatToolError(new AppError("music_id must be an integer", "INVALID_PARAMS"));
57
+ }
58
+ if (reference_image_urls.length !== 1) {
59
+ return formatToolError(new AppError("reference_image_urls must contain exactly one image URL", "INVALID_PARAMS"));
60
+ }
61
+ const result = await client.generateEffect({
62
+ effect_id,
63
+ music_id,
64
+ prompt: normalizedPrompt,
65
+ watermark: watermark ?? false,
66
+ reference_image_urls,
67
+ });
68
+ return jsonContent({
69
+ success: true,
70
+ task_id: result.task_id,
71
+ task_type: result.task_type,
72
+ status: result.status,
73
+ message: `Effect generation queued. Use get_task_status with task_id="${result.task_id}" to check status.`,
74
+ });
75
+ }
76
+ catch (error) {
77
+ return formatToolError(error);
78
+ }
79
+ });
80
+ }
81
+ //# sourceMappingURL=generate-effect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate-effect.js","sourceRoot":"","sources":["../../../../src/capabilities/effects/tools/generate-effect.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { FreebeatApiClient } from "../../../services/freebeat-api.js";
3
+ export declare function registerListEffectsTool(server: McpServer, client: Pick<FreebeatApiClient, "listEffects">): void;
@@ -0,0 +1,55 @@
1
+ import { z } from "zod";
2
+ import { formatToolError, jsonContent } from "../../../core/response.js";
3
+ function normalizeEffect(effect) {
4
+ return {
5
+ effect_id: effect.effectsTypeId,
6
+ display_name: effect.effectsDisplayName,
7
+ image_url: effect.coverUrl,
8
+ preview_video_url: effect.videoUrl,
9
+ default_music_id: effect.musicId,
10
+ default_music_name: effect.musicName,
11
+ aspect_ratio: effect.aspectRatio,
12
+ };
13
+ }
14
+ export function registerListEffectsTool(server, client) {
15
+ server.registerTool("list_effects", {
16
+ description: "List supported effects with the metadata needed to select an effect and create an effect task. Each effect includes a default image_url and default_music_id you can use directly.",
17
+ outputSchema: {
18
+ success: z
19
+ .literal(true)
20
+ .describe("Whether the effects list was retrieved successfully."),
21
+ effects: z
22
+ .array(z.object({
23
+ effect_id: z.number().describe("Effect ID for generate_effect.effect_id."),
24
+ display_name: z.string().describe("Human-readable effect name."),
25
+ image_url: z
26
+ .string()
27
+ .describe("Default cover image URL for generate_effect.reference_image_urls[0]. You may also replace it with a single uploaded image URL from upload_image."),
28
+ preview_video_url: z.string().describe("Preview video URL for the effect."),
29
+ default_music_id: z
30
+ .number()
31
+ .describe("Default music ID to pass to generate_effect.music_id."),
32
+ default_music_name: z.string().describe("Default music display name."),
33
+ aspect_ratio: z.string().describe("Preview aspect ratio."),
34
+ }))
35
+ .describe("Supported effects with the metadata needed to create an effect task."),
36
+ message: z
37
+ .string()
38
+ .describe("A human-readable summary of the retrieved effects."),
39
+ },
40
+ inputSchema: {},
41
+ }, async () => {
42
+ try {
43
+ const effects = await client.listEffects();
44
+ return jsonContent({
45
+ success: true,
46
+ effects: effects.map(normalizeEffect),
47
+ message: `Retrieved ${effects.length} effect(s).`,
48
+ });
49
+ }
50
+ catch (error) {
51
+ return formatToolError(error);
52
+ }
53
+ });
54
+ }
55
+ //# sourceMappingURL=list-effects.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-effects.js","sourceRoot":"","sources":["../../../../src/capabilities/effects/tools/list-effects.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAGzE,SAAS,eAAe,CAAC,MAAsB;IAC7C,OAAO;QACL,SAAS,EAAE,MAAM,CAAC,aAAa;QAC/B,YAAY,EAAE,MAAM,CAAC,kBAAkB;QACvC,SAAS,EAAE,MAAM,CAAC,QAAQ;QAC1B,iBAAiB,EAAE,MAAM,CAAC,QAAQ;QAClC,gBAAgB,EAAE,MAAM,CAAC,OAAO;QAChC,kBAAkB,EAAE,MAAM,CAAC,SAAS;QACpC,YAAY,EAAE,MAAM,CAAC,WAAW;KACjC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,uBAAuB,CACrC,MAAiB,EACjB,MAA8C;IAE9C,MAAM,CAAC,YAAY,CACjB,cAAc,EACd;QACE,WAAW,EACT,oLAAoL;QACtL,YAAY,EAAE;YACZ,OAAO,EAAE,CAAC;iBACP,OAAO,CAAC,IAAI,CAAC;iBACb,QAAQ,CAAC,sDAAsD,CAAC;YACnE,OAAO,EAAE,CAAC;iBACP,KAAK,CACJ,CAAC,CAAC,MAAM,CAAC;gBACP,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,0CAA0C,CAAC;gBAC1E,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,6BAA6B,CAAC;gBAChE,SAAS,EAAE,CAAC;qBACT,MAAM,EAAE;qBACR,QAAQ,CAAC,kJAAkJ,CAAC;gBAC/J,iBAAiB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,mCAAmC,CAAC;gBAC3E,gBAAgB,EAAE,CAAC;qBAChB,MAAM,EAAE;qBACR,QAAQ,CAAC,uDAAuD,CAAC;gBACpE,kBAAkB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,6BAA6B,CAAC;gBACtE,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,uBAAuB,CAAC;aAC3D,CAAC,CACH;iBACA,QAAQ,CAAC,sEAAsE,CAAC;YACnF,OAAO,EAAE,CAAC;iBACP,MAAM,EAAE;iBACR,QAAQ,CAAC,oDAAoD,CAAC;SAClE;QACD,WAAW,EAAE,EAAE;KAChB,EACD,KAAK,IAAI,EAAE;QACT,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,WAAW,EAAE,CAAC;YAE3C,OAAO,WAAW,CAAC;gBACjB,OAAO,EAAE,IAAI;gBACb,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;gBACrC,OAAO,EAAE,aAAa,OAAO,CAAC,MAAM,aAAa;aAClD,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,OAAO,eAAe,CAAC,KAAK,CAAC,CAAC;QAChC,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { FreebeatApiClient } from "../../services/freebeat-api.js";
3
+ export declare function registerMvTools(server: McpServer, client: FreebeatApiClient): void;
@@ -0,0 +1,5 @@
1
+ import { registerGenerateMusicVideoTool } from "./tools/generate-music-video.js";
2
+ export function registerMvTools(server, client) {
3
+ registerGenerateMusicVideoTool(server, client);
4
+ }
5
+ //# sourceMappingURL=register.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register.js","sourceRoot":"","sources":["../../../src/capabilities/mv/register.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,8BAA8B,EAAE,MAAM,iCAAiC,CAAC;AAEjF,MAAM,UAAU,eAAe,CAC7B,MAAiB,EACjB,MAAyB;IAEzB,8BAA8B,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AACjD,CAAC"}
@@ -0,0 +1 @@
1
+ export { MUSIC_VIDEO_TASK_TYPE } from "../../core/task-types.js";
@@ -0,0 +1,2 @@
1
+ export { MUSIC_VIDEO_TASK_TYPE } from "../../core/task-types.js";
2
+ //# sourceMappingURL=task-type.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task-type.js","sourceRoot":"","sources":["../../../src/capabilities/mv/task-type.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { FreebeatApiClient } from "../../../services/freebeat-api.js";
3
+ export declare function registerGenerateMusicVideoTool(server: McpServer, client: Pick<FreebeatApiClient, "generateMusicVideo">): void;