@productmaker/mcp 0.15.1 → 0.15.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.
- package/README.md +4 -0
- package/dist/http.js +5 -6
- package/dist/stdio.js +5 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -61,6 +61,10 @@ Sign up at [productmaker.app](https://productmaker.app) and create a key (prefix
|
|
|
61
61
|
| `generate_video_creative` | Standalone UGC video creative |
|
|
62
62
|
| `generate_image_creatives` | Standalone image creatives (multiple variants) |
|
|
63
63
|
| `generate_landing` | Standalone landing page |
|
|
64
|
+
| `get_video_script` | Read the pending video script when a task was created with script review paused (returns scenes + per-scene word limits) |
|
|
65
|
+
| `approve_video_script` | Approve the video script (with optional per-scene edits); render starts and consumes credits |
|
|
66
|
+
| `regenerate_video_script` | Re-roll the pending video script (optionally with a different narrative style) |
|
|
67
|
+
| `resolve_pending_action` | Resolve a gate the pipeline is waiting on (product-reference confirmation or angle-review approval) when `get_task_status` returns `pendingUserAction` |
|
|
64
68
|
| `list_shopify_shops` | List connected Shopify stores |
|
|
65
69
|
| `list_meta_ad_accounts` | List connected Meta ad accounts |
|
|
66
70
|
| `list_tiktok_advertisers` | List connected TikTok Ads advertiser accounts |
|
package/dist/http.js
CHANGED
|
@@ -113,7 +113,7 @@ var ApiClient = class {
|
|
|
113
113
|
};
|
|
114
114
|
|
|
115
115
|
// src/index.ts
|
|
116
|
-
var MCP_VERSION = "0.3
|
|
116
|
+
var MCP_VERSION = "0.15.3";
|
|
117
117
|
|
|
118
118
|
// src/tools/tasks.ts
|
|
119
119
|
import { z as z2 } from "zod";
|
|
@@ -358,13 +358,13 @@ async function pollStatus(fetcher, waitSeconds, signal, opts = {}) {
|
|
|
358
358
|
const effective = Math.min(Math.max(0, waitSeconds), maxWait);
|
|
359
359
|
let snapshot = await fetcher();
|
|
360
360
|
if (effective === 0) return snapshot;
|
|
361
|
-
if (TERMINAL.has(snapshot.status) || snapshot.status === "awaiting_review") return snapshot;
|
|
361
|
+
if (TERMINAL.has(snapshot.status) || snapshot.status === "awaiting_review" || snapshot.pendingUserAction != null) return snapshot;
|
|
362
362
|
const deadline = Date.now() + effective * 1e3;
|
|
363
363
|
while (Date.now() < deadline) {
|
|
364
364
|
if (signal?.aborted) throw new Error("aborted");
|
|
365
365
|
await sleep(intervalMs, signal);
|
|
366
366
|
const next = await fetcher();
|
|
367
|
-
if (next.status !== snapshot.status || next.phase !== snapshot.phase || TERMINAL.has(next.status) || next.status === "awaiting_review") {
|
|
367
|
+
if (next.status !== snapshot.status || next.phase !== snapshot.phase || TERMINAL.has(next.status) || next.status === "awaiting_review" || next.pendingUserAction != null) {
|
|
368
368
|
return next;
|
|
369
369
|
}
|
|
370
370
|
snapshot = next;
|
|
@@ -511,7 +511,6 @@ var VideoModelEnum = z.enum([
|
|
|
511
511
|
"wan",
|
|
512
512
|
"bytedance",
|
|
513
513
|
"seedance",
|
|
514
|
-
"infinitalk",
|
|
515
514
|
"grok",
|
|
516
515
|
"kling"
|
|
517
516
|
]);
|
|
@@ -1285,7 +1284,7 @@ function registerTaskTools(server, api, { proxyBaseUrl = null, transport = "http
|
|
|
1285
1284
|
throw translateError(e);
|
|
1286
1285
|
}
|
|
1287
1286
|
});
|
|
1288
|
-
server.tool("get_task_status", 'Devuelve el estado y URLs de outputs de una tarea. Si waitSeconds>0, hace polling hasta que cambie la fase o llegue al timeout (max 120s). Cuando la tarea queda en `done`, la respuesta incluye un segundo bloque markdown con previews inline de las im\xE1genes, links descargables al video MP4 y un enlace a Product Maker para ver el resultado completo.\n\nIMPORTANTE \u2014 `pendingUserAction`: si est\xE1 presente, el pipeline est\xE1 PARADO esperando que el usuario decida algo. Mira el `kind`
|
|
1287
|
+
server.tool("get_task_status", 'Devuelve el estado y URLs de outputs de una tarea. Si waitSeconds>0, hace polling hasta que cambie la fase, aparezca `pendingUserAction`, o llegue al timeout (max 120s). Cuando la tarea queda en `done`, la respuesta incluye un segundo bloque markdown con previews inline de las im\xE1genes, links descargables al video MP4 y un enlace a Product Maker para ver el resultado completo.\n\nIMPORTANTE \u2014 `pendingUserAction`: si est\xE1 presente, el pipeline est\xE1 PARADO esperando que el usuario decida algo. Mira el `kind` y llama `resolve_pending_action` con `action: { kind: <mismo kind>, ... }`; sin esto la tarea NUNCA avanza por m\xE1s que esperes. Kinds actuales:\n- `product_reference_confirmation`: el clasificador no est\xE1 seguro si las fotos son variantes del mismo producto o productos distintos. Mu\xE9strale al usuario `targetProductLabel` + `reason`, recoge su respuesta, y usa SOLO valores presentes en `options`.\n- `angle_review_approval`: la IA ya gener\xF3 el \xE1ngulo/revisi\xF3n antes de renderizar. Mu\xE9strale `customAngleDraft`, `painPointsDraft`, `benefitsDraft`, `featuresDraft` si vienen; si no vienen, puedes pedir aprobaci\xF3n general y llamar `resolve_pending_action` con solo `{ kind: "angle_review_approval" }` para aprobar tal cual.\nUse this to check on a task progress; pass waitSeconds for a near-synchronous response.', GetTaskStatusInput.shape, async (input, extra) => {
|
|
1289
1288
|
try {
|
|
1290
1289
|
const fetcher = /* @__PURE__ */ __name(() => api.getJson(`/v1/status/${encodeURIComponent(input.taskId)}`), "fetcher");
|
|
1291
1290
|
const signal = extra?.signal;
|
|
@@ -1430,7 +1429,7 @@ var VideoInput = z3.object({
|
|
|
1430
1429
|
durationSeconds: z3.number().int().min(5).max(60).optional().describe("Opcional. Duraci\xF3n del video en segundos (5-60). Default 15s. Para hooks cortos usa 8, para storytelling usa 30."),
|
|
1431
1430
|
videoPreset: VideoPresetEnum.default("auto").describe('Opcional. Tipo/narrativa del video \u2014 \xFAnico campo de "estilo" que el usuario controla (en la web es el \xFAnico dropdown). Default "auto" (la IA escoge tras analizar el producto). Opciones: "auto", "ugc_dynamic" (UGC cl\xE1sico testimonial multi-hook), "ugc_unboxing_chaos" (unboxing agresivo), "ugc_curiosity_reveal" (hook con producto oculto), "ugc_listicle_3" (3 razones numeradas, recomendado 30s), "ugc_skeptic_confession" (esc\xE9ptico\u2192conversi\xF3n, recomendado 30s), "ugc_demo_review" (demo en uso a lo largo de d\xEDas), "problem_solution" (problema\u2192producto\u2192CTA), "pixar_problem" (problema animado 3D estilo Pixar), "pixar_sassy" (producto que habla con personalidad), "product_showcase" (sin actor, solo producto), "wearable_showcase" (ropa/accesorios puestos).'),
|
|
1432
1431
|
videoTier: VideoTierEnum.optional().describe('Opcional. Estilo del video (en la web la etiqueta es "\xBFCalidad de video?", 2 opciones \u2014 sin escalera de calidad, son ESTILOS distintos). "basic" = "Realista" (RECOMENDADO por la web): render de 15s con audio nativo, el m\xE1s natural \u2014 S\xD3LO v\xE1lido cuando durationSeconds \u2264 15 (el handler lo valida). "standard" = "Multiescena": m\xFAltiples tomas, hasta 30s. Si la duraci\xF3n es 30s, s\xF3lo aplica "standard". Si el usuario no menciona estilo, OMITE este campo y el backend usa su default.'),
|
|
1433
|
-
videoResolution: VideoResolutionEnum.optional().describe('Opcional. Resoluci\xF3n del render \u2014 aplica S\xD3LO al tier "basic" (Realista); el tier "standard" la deriva solo. En la web se pregunta "\xBFResoluci\xF3n del video?" tras elegir "basic". "
|
|
1432
|
+
videoResolution: VideoResolutionEnum.optional().describe('Opcional. Resoluci\xF3n del render \u2014 aplica S\xD3LO al tier "basic" (Realista); el tier "standard" la deriva solo. En la web se pregunta "\xBFResoluci\xF3n del video?" tras elegir "basic". "720p" = m\xE1xima nitidez (RECOMENDADO, default si se omite); "480p" = render m\xE1s econ\xF3mico. Si el usuario no menciona resoluci\xF3n, OMITE este campo (el backend usa 720p para basic).'),
|
|
1434
1433
|
features: z3.array(z3.string()).optional().describe('Opcional. Lista de features/beneficios clave a mencionar. Ej. ["resistente al agua", "bater\xEDa 24h", "carga inal\xE1mbrica"].'),
|
|
1435
1434
|
price: CreativeRefs.price,
|
|
1436
1435
|
offer: CreativeRefs.offer,
|
package/dist/stdio.js
CHANGED
|
@@ -110,7 +110,7 @@ var ApiClient = class {
|
|
|
110
110
|
};
|
|
111
111
|
|
|
112
112
|
// src/index.ts
|
|
113
|
-
var MCP_VERSION = "0.3
|
|
113
|
+
var MCP_VERSION = "0.15.3";
|
|
114
114
|
|
|
115
115
|
// src/tools/tasks.ts
|
|
116
116
|
import { z as z2 } from "zod";
|
|
@@ -355,13 +355,13 @@ async function pollStatus(fetcher, waitSeconds, signal, opts = {}) {
|
|
|
355
355
|
const effective = Math.min(Math.max(0, waitSeconds), maxWait);
|
|
356
356
|
let snapshot = await fetcher();
|
|
357
357
|
if (effective === 0) return snapshot;
|
|
358
|
-
if (TERMINAL.has(snapshot.status) || snapshot.status === "awaiting_review") return snapshot;
|
|
358
|
+
if (TERMINAL.has(snapshot.status) || snapshot.status === "awaiting_review" || snapshot.pendingUserAction != null) return snapshot;
|
|
359
359
|
const deadline = Date.now() + effective * 1e3;
|
|
360
360
|
while (Date.now() < deadline) {
|
|
361
361
|
if (signal?.aborted) throw new Error("aborted");
|
|
362
362
|
await sleep(intervalMs, signal);
|
|
363
363
|
const next = await fetcher();
|
|
364
|
-
if (next.status !== snapshot.status || next.phase !== snapshot.phase || TERMINAL.has(next.status) || next.status === "awaiting_review") {
|
|
364
|
+
if (next.status !== snapshot.status || next.phase !== snapshot.phase || TERMINAL.has(next.status) || next.status === "awaiting_review" || next.pendingUserAction != null) {
|
|
365
365
|
return next;
|
|
366
366
|
}
|
|
367
367
|
snapshot = next;
|
|
@@ -508,7 +508,6 @@ var VideoModelEnum = z.enum([
|
|
|
508
508
|
"wan",
|
|
509
509
|
"bytedance",
|
|
510
510
|
"seedance",
|
|
511
|
-
"infinitalk",
|
|
512
511
|
"grok",
|
|
513
512
|
"kling"
|
|
514
513
|
]);
|
|
@@ -1241,7 +1240,7 @@ function registerTaskTools(server, api, { proxyBaseUrl = null, transport = "http
|
|
|
1241
1240
|
throw translateError(e);
|
|
1242
1241
|
}
|
|
1243
1242
|
});
|
|
1244
|
-
server.tool("get_task_status", 'Devuelve el estado y URLs de outputs de una tarea. Si waitSeconds>0, hace polling hasta que cambie la fase o llegue al timeout (max 120s). Cuando la tarea queda en `done`, la respuesta incluye un segundo bloque markdown con previews inline de las im\xE1genes, links descargables al video MP4 y un enlace a Product Maker para ver el resultado completo.\n\nIMPORTANTE \u2014 `pendingUserAction`: si est\xE1 presente, el pipeline est\xE1 PARADO esperando que el usuario decida algo. Mira el `kind`
|
|
1243
|
+
server.tool("get_task_status", 'Devuelve el estado y URLs de outputs de una tarea. Si waitSeconds>0, hace polling hasta que cambie la fase, aparezca `pendingUserAction`, o llegue al timeout (max 120s). Cuando la tarea queda en `done`, la respuesta incluye un segundo bloque markdown con previews inline de las im\xE1genes, links descargables al video MP4 y un enlace a Product Maker para ver el resultado completo.\n\nIMPORTANTE \u2014 `pendingUserAction`: si est\xE1 presente, el pipeline est\xE1 PARADO esperando que el usuario decida algo. Mira el `kind` y llama `resolve_pending_action` con `action: { kind: <mismo kind>, ... }`; sin esto la tarea NUNCA avanza por m\xE1s que esperes. Kinds actuales:\n- `product_reference_confirmation`: el clasificador no est\xE1 seguro si las fotos son variantes del mismo producto o productos distintos. Mu\xE9strale al usuario `targetProductLabel` + `reason`, recoge su respuesta, y usa SOLO valores presentes en `options`.\n- `angle_review_approval`: la IA ya gener\xF3 el \xE1ngulo/revisi\xF3n antes de renderizar. Mu\xE9strale `customAngleDraft`, `painPointsDraft`, `benefitsDraft`, `featuresDraft` si vienen; si no vienen, puedes pedir aprobaci\xF3n general y llamar `resolve_pending_action` con solo `{ kind: "angle_review_approval" }` para aprobar tal cual.\nUse this to check on a task progress; pass waitSeconds for a near-synchronous response.', GetTaskStatusInput.shape, async (input, extra) => {
|
|
1245
1244
|
try {
|
|
1246
1245
|
const fetcher = /* @__PURE__ */ __name(() => api.getJson(`/v1/status/${encodeURIComponent(input.taskId)}`), "fetcher");
|
|
1247
1246
|
const signal = extra?.signal;
|
|
@@ -1386,7 +1385,7 @@ var VideoInput = z3.object({
|
|
|
1386
1385
|
durationSeconds: z3.number().int().min(5).max(60).optional().describe("Opcional. Duraci\xF3n del video en segundos (5-60). Default 15s. Para hooks cortos usa 8, para storytelling usa 30."),
|
|
1387
1386
|
videoPreset: VideoPresetEnum.default("auto").describe('Opcional. Tipo/narrativa del video \u2014 \xFAnico campo de "estilo" que el usuario controla (en la web es el \xFAnico dropdown). Default "auto" (la IA escoge tras analizar el producto). Opciones: "auto", "ugc_dynamic" (UGC cl\xE1sico testimonial multi-hook), "ugc_unboxing_chaos" (unboxing agresivo), "ugc_curiosity_reveal" (hook con producto oculto), "ugc_listicle_3" (3 razones numeradas, recomendado 30s), "ugc_skeptic_confession" (esc\xE9ptico\u2192conversi\xF3n, recomendado 30s), "ugc_demo_review" (demo en uso a lo largo de d\xEDas), "problem_solution" (problema\u2192producto\u2192CTA), "pixar_problem" (problema animado 3D estilo Pixar), "pixar_sassy" (producto que habla con personalidad), "product_showcase" (sin actor, solo producto), "wearable_showcase" (ropa/accesorios puestos).'),
|
|
1388
1387
|
videoTier: VideoTierEnum.optional().describe('Opcional. Estilo del video (en la web la etiqueta es "\xBFCalidad de video?", 2 opciones \u2014 sin escalera de calidad, son ESTILOS distintos). "basic" = "Realista" (RECOMENDADO por la web): render de 15s con audio nativo, el m\xE1s natural \u2014 S\xD3LO v\xE1lido cuando durationSeconds \u2264 15 (el handler lo valida). "standard" = "Multiescena": m\xFAltiples tomas, hasta 30s. Si la duraci\xF3n es 30s, s\xF3lo aplica "standard". Si el usuario no menciona estilo, OMITE este campo y el backend usa su default.'),
|
|
1389
|
-
videoResolution: VideoResolutionEnum.optional().describe('Opcional. Resoluci\xF3n del render \u2014 aplica S\xD3LO al tier "basic" (Realista); el tier "standard" la deriva solo. En la web se pregunta "\xBFResoluci\xF3n del video?" tras elegir "basic". "
|
|
1388
|
+
videoResolution: VideoResolutionEnum.optional().describe('Opcional. Resoluci\xF3n del render \u2014 aplica S\xD3LO al tier "basic" (Realista); el tier "standard" la deriva solo. En la web se pregunta "\xBFResoluci\xF3n del video?" tras elegir "basic". "720p" = m\xE1xima nitidez (RECOMENDADO, default si se omite); "480p" = render m\xE1s econ\xF3mico. Si el usuario no menciona resoluci\xF3n, OMITE este campo (el backend usa 720p para basic).'),
|
|
1390
1389
|
features: z3.array(z3.string()).optional().describe('Opcional. Lista de features/beneficios clave a mencionar. Ej. ["resistente al agua", "bater\xEDa 24h", "carga inal\xE1mbrica"].'),
|
|
1391
1390
|
price: CreativeRefs.price,
|
|
1392
1391
|
offer: CreativeRefs.offer,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@productmaker/mcp",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"private": false,
|
|
6
6
|
"description": "Product Maker MCP server — connect Claude Desktop, Claude Code, ChatGPT, or Gemini to Product Maker AI to generate dropshipping landing pages, UGC videos, and ad creatives, and publish to Shopify and Meta Ads from your AI assistant.",
|