@vprop/mcp 1.0.4 → 1.0.6
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 +1 -0
- package/dist/index.js +16 -12
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -237,6 +237,7 @@ When calling `create_project`, you can customize:
|
|
|
237
237
|
| `theme` | `modern` `classic` `bold` `elegant` | `modern` |
|
|
238
238
|
| `resolution` | `portrait` (9:16) `landscape` (16:9) | `portrait` |
|
|
239
239
|
| `caption` | `none` `keyword` `description` | `keyword` |
|
|
240
|
+
| `language` | `en` `es` `ko` `zh-Hans` | `en` |
|
|
240
241
|
| `voice_id` | ID from `list_voices` | agent default |
|
|
241
242
|
| `bgm_id` | ID from `list_bgms` | theme default |
|
|
242
243
|
| `use_agent_avatar` | `true` `false` | `true` |
|
package/dist/index.js
CHANGED
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
3
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
4
|
import { readFileSync } from "node:fs";
|
|
5
|
-
import { extname } from "node:path";
|
|
6
|
-
import { randomUUID } from "node:crypto";
|
|
5
|
+
import { extname, basename } from "node:path";
|
|
7
6
|
import { z } from "zod";
|
|
8
7
|
const BASE_URL = process.env.VPROP_BASE_URL ?? "https://vprop.ai/api/v1";
|
|
9
8
|
function getApiKey() {
|
|
@@ -169,7 +168,7 @@ server.registerTool("upload_listing_image", {
|
|
|
169
168
|
if (!content_type) {
|
|
170
169
|
throw new Error(`Unsupported extension '${ext}'. Use .jpg, .jpeg, .png, or .webp`);
|
|
171
170
|
}
|
|
172
|
-
const filename = file_path
|
|
171
|
+
const filename = basename(file_path) || "image.jpg";
|
|
173
172
|
// Read file before any API call — if the file is missing or unreadable
|
|
174
173
|
// we fail here without touching remote state.
|
|
175
174
|
const fileData = readFileSync(file_path);
|
|
@@ -184,11 +183,16 @@ server.registerTool("upload_listing_image", {
|
|
|
184
183
|
await uploadBuffer(upload_url, fileData, content_type);
|
|
185
184
|
}
|
|
186
185
|
catch (err) {
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
186
|
+
let cleanedUp = false;
|
|
187
|
+
try {
|
|
188
|
+
await vpropFetch(`/listings/${listing_id}/images/${image_id}`, { method: "DELETE" });
|
|
189
|
+
cleanedUp = true;
|
|
190
|
+
}
|
|
191
|
+
catch { }
|
|
190
192
|
throw new Error(`Upload failed: ${err instanceof Error ? err.message : String(err)}. ` +
|
|
191
|
-
|
|
193
|
+
(cleanedUp
|
|
194
|
+
? `The image record (${image_id}) has been cleaned up.`
|
|
195
|
+
: `The image record (${image_id}) may still exist — call delete_listing_image to remove it.`));
|
|
192
196
|
}
|
|
193
197
|
return toText({ image_id, image_url, expires_at });
|
|
194
198
|
});
|
|
@@ -274,7 +278,7 @@ server.registerTool("upload_agent_photo", {
|
|
|
274
278
|
if (!content_type) {
|
|
275
279
|
throw new Error(`Unsupported extension '${ext}'. Use .jpg, .jpeg, .png, or .webp`);
|
|
276
280
|
}
|
|
277
|
-
const filename = file_path
|
|
281
|
+
const filename = basename(file_path) || "photo.jpg";
|
|
278
282
|
// Read file before any API call — the presigned-URL endpoint immediately
|
|
279
283
|
// stamps agents.photo in the DB, so a missing/unreadable file must be
|
|
280
284
|
// caught here before we mutate remote state.
|
|
@@ -308,19 +312,19 @@ server.registerTool("create_project", {
|
|
|
308
312
|
theme: z.enum(["modern", "classic", "bold", "elegant"]).optional().describe("Visual theme (default: modern)"),
|
|
309
313
|
resolution: z.enum(["portrait", "landscape"]).optional().describe("Video orientation (default: portrait/9:16)"),
|
|
310
314
|
caption: z.enum(["none", "keyword", "description"]).optional().describe("Caption style (default: keyword)"),
|
|
315
|
+
language: z.enum(["en", "es", "ko", "zh-Hans"]).optional().describe("Narration + caption language (default: en). Use list_voices to find a voice whose verified_languages includes your chosen language."),
|
|
311
316
|
voice_id: z.string().optional().describe("Per-project voice override (from list_voices)"),
|
|
312
317
|
bgm_id: z.string().optional().describe("Background music ID (from list_bgms)"),
|
|
313
318
|
use_agent_avatar: z.boolean().optional().describe("Show animated agent avatar (default: true, needs agent photo)"),
|
|
314
319
|
use_lipsync: z.boolean().optional().describe("Lipsync the avatar (default: false)"),
|
|
315
320
|
metadata: z.record(z.string(), z.unknown()).optional(),
|
|
316
321
|
},
|
|
317
|
-
}, async ({ listing_id, agent_id, title, cta, theme, resolution, caption, voice_id, bgm_id, use_agent_avatar, use_lipsync, metadata, }) => {
|
|
318
|
-
const options = theme || resolution || caption || voice_id || bgm_id || use_agent_avatar !== undefined || use_lipsync !== undefined
|
|
319
|
-
? { theme, resolution, caption, voice_id, bgm_id, use_agent_avatar, use_lipsync }
|
|
322
|
+
}, async ({ listing_id, agent_id, title, cta, theme, resolution, caption, language, voice_id, bgm_id, use_agent_avatar, use_lipsync, metadata, }) => {
|
|
323
|
+
const options = theme || resolution || caption || language || voice_id || bgm_id || use_agent_avatar !== undefined || use_lipsync !== undefined
|
|
324
|
+
? { theme, resolution, caption, language, voice_id, bgm_id, use_agent_avatar, use_lipsync }
|
|
320
325
|
: undefined;
|
|
321
326
|
return toText(await vpropFetch("/projects", {
|
|
322
327
|
method: "POST",
|
|
323
|
-
headers: { "Idempotency-Key": randomUUID() },
|
|
324
328
|
body: JSON.stringify({ listing_id, agent_id, title, cta, options, metadata }),
|
|
325
329
|
}));
|
|
326
330
|
});
|
package/package.json
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vprop/mcp",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.6",
|
|
4
4
|
"description": "MCP server for the vProp Public API — generate real-estate listing videos with AI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
|
+
"mcp": "dist/index.js",
|
|
7
8
|
"vprop-mcp": "dist/index.js"
|
|
8
9
|
},
|
|
9
10
|
"files": [
|
|
@@ -11,7 +12,7 @@
|
|
|
11
12
|
],
|
|
12
13
|
"scripts": {
|
|
13
14
|
"build": "tsc",
|
|
14
|
-
"
|
|
15
|
+
"prepack": "tsc",
|
|
15
16
|
"dev": "node --experimental-strip-types src/index.ts",
|
|
16
17
|
"start": "node dist/index.js"
|
|
17
18
|
},
|