@productmaker/mcp 0.12.1 → 0.14.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 (3) hide show
  1. package/dist/http.js +18 -12
  2. package/dist/stdio.js +18 -12
  3. package/package.json +1 -1
package/dist/http.js CHANGED
@@ -479,7 +479,7 @@ var VideoTierEnum = z.enum([
479
479
  ]);
480
480
  function resolveVideoTier(tier) {
481
481
  if (!tier) return void 0;
482
- return tier === "basic" ? "grok" : "standard";
482
+ return tier === "basic" ? "single_call" : "standard";
483
483
  }
484
484
  __name(resolveVideoTier, "resolveVideoTier");
485
485
  var VideoResolutionEnum = z.enum([
@@ -1181,7 +1181,8 @@ var CreateProductTaskInput = z2.object({
1181
1181
  "landing",
1182
1182
  "video",
1183
1183
  "image"
1184
- ])).min(2).max(3).optional().describe('Opcional. Qu\xE9 outputs generar. Default: todos ["landing","video","image"]. Para 2 outputs: ["landing","image"] (sin video), ["video","image"] (sin landing), ["landing","video"] (sin imagen). Para 1 solo output, usa generate_landing / generate_video_creative / generate_image_creatives.')
1184
+ ])).min(2).max(3).optional().describe('Opcional. Qu\xE9 outputs generar. Default: todos ["landing","video","image"]. Para 2 outputs: ["landing","image"] (sin video), ["video","image"] (sin landing), ["landing","video"] (sin imagen). Para 1 solo output, usa generate_landing / generate_video_creative / generate_image_creatives.'),
1185
+ competitorScanEnabled: z2.boolean().optional().describe("Opcional. Si true (default), el sistema analiza ads de competencia en Meta Ad Library y enriquece los \xE1ngulos generados con hooks y painPoints validados por el mercado (\u2248$0.20-0.48 extra por task \u2014 var\xEDa con cu\xE1ntas transcripciones de video se capturen). Si false, el pipeline genera \xE1ngulos sin esa se\xF1al \u2014 usa esto SOLO si el usuario ya tiene su propia investigaci\xF3n de mercado o quiere ahorrar costos en productos muy nicho sin presencia en Meta. Default true.")
1185
1186
  }).strict();
1186
1187
  var GetTaskStatusInput = z2.object({
1187
1188
  taskId: z2.string().min(1),
@@ -1259,14 +1260,15 @@ function registerTaskTools(server, api, { proxyBaseUrl = null, transport = "http
1259
1260
  "options.videoStyle": resolved?.videoStyle,
1260
1261
  "options.narrativeStyle": resolved?.narrativeStyle,
1261
1262
  "options.videoTier": wireTier,
1262
- // Resolution is meaningful ONLY for the basic/grok tier; for every
1263
- // other tier the backend derives it. Forward it ONLY for grok so the
1264
- // MCP never presents a "user choice where there is none" (the web has
1265
- // no resolution knob for standard) — for non-grok it's dropped.
1266
- "options.videoResolution": wireTier === "grok" ? input.videoResolution : void 0,
1263
+ // Resolution is meaningful ONLY for the basic/single_call tier; for every
1264
+ // other tier the backend derives it. Forward it ONLY for single_call so
1265
+ // the MCP never presents a "user choice where there is none" (the web
1266
+ // has no resolution knob for standard) — for non-single_call it's dropped.
1267
+ "options.videoResolution": wireTier === "single_call" ? input.videoResolution : void 0,
1267
1268
  "options.multiAngleVideos": input.multiAngleVideos,
1268
1269
  "options.angleNarratives": input.angleNarratives,
1269
1270
  "options.selectedOutputs": input.outputs,
1271
+ "options.competitorScanEnabled": input.competitorScanEnabled,
1270
1272
  url: input.productUrl
1271
1273
  });
1272
1274
  const r = await api.postMultipart("/v1/ingest", {
@@ -1406,7 +1408,8 @@ var CreativeRefs = {
1406
1408
  price: z3.string().optional().describe('Precio en formato libre \u2014 ej. "$89.900", "USD 29.99". Opcional pero MUY IMPACTANTE para conversi\xF3n: si el usuario no lo mencion\xF3, PREG\xDANTALE antes de invocar. Si el usuario te dice "t\xFA elige", omite el campo y la IA del backend sugiere uno.'),
1407
1409
  offer: z3.string().optional().describe('Oferta a destacar \u2014 ej. "2x1", "Env\xEDo gratis", "50% OFF". Opcional pero MUY IMPACTANTE: si el usuario no lo mencion\xF3, PREG\xDANTALE antes de invocar (es v\xE1lido que diga "sin oferta"). Si el usuario te dice "t\xFA elige", omite el campo.'),
1408
1410
  buyerPersona: z3.string().optional().describe('Opcional. Descripci\xF3n del comprador objetivo. Ej. "Mujeres 35-50, profesionales urbanas". Si se omite, la IA infiere desde el \xE1ngulo y producto.'),
1409
- isCombo: z3.boolean().optional().describe("Opcional. Si true, el creativo presenta el producto como combo/pack. Default false.")
1411
+ isCombo: z3.boolean().optional().describe("Opcional. Si true, el creativo presenta el producto como combo/pack. Default false."),
1412
+ competitorScanEnabled: z3.boolean().optional().describe("Opcional. Si true (default), el sistema analiza ads de competencia en Meta Ad Library y enriquece los \xE1ngulos generados con hooks y painPoints validados por el mercado (\u2248$0.20-0.48 extra por task \u2014 var\xEDa con cu\xE1ntas transcripciones de video se capturen). Si false, el pipeline genera \xE1ngulos sin esa se\xF1al \u2014 usa esto SOLO si el usuario ya tiene su propia investigaci\xF3n de mercado o quiere ahorrar costos en productos muy nicho sin presencia en Meta. Default true.")
1410
1413
  };
1411
1414
  var VideoInput = z3.object({
1412
1415
  images: CreativeRefs.images,
@@ -1428,7 +1431,8 @@ var VideoInput = z3.object({
1428
1431
  offer: CreativeRefs.offer,
1429
1432
  cta: z3.string().optional().describe('Opcional. Call-to-action final del video. Ej. "Compra ahora", "Pide el tuyo hoy", "Link en bio". Si se omite, la IA escribe uno.'),
1430
1433
  scriptNotes: z3.string().optional().describe('Opcional. Notas/restricciones para el guion (la IA las usa al redactar). Ej. "No mencionar la marca X", "Tono divertido, no cl\xEDnico", "Mencionar 2x1". NO es el guion literal \u2014 para editar el guion palabra-por-palabra, pasa `pauseForVideoScriptReview: true` y usa get_video_script / approve_video_script tras la pausa.'),
1431
- pauseForVideoScriptReview: z3.boolean().optional().describe("Opcional. Si true, la tarea pausa despu\xE9s de generar el guion y antes de renderizar. \xDAsalo cuando el usuario quiera editar el guion antes de gastar cr\xE9ditos en el video. Tras la pausa: get_video_script para leerlo, approve_video_script para aprobar (con o sin ediciones). Default false.")
1434
+ pauseForVideoScriptReview: z3.boolean().optional().describe("Opcional. Si true, la tarea pausa despu\xE9s de generar el guion y antes de renderizar. \xDAsalo cuando el usuario quiera editar el guion antes de gastar cr\xE9ditos en el video. Tras la pausa: get_video_script para leerlo, approve_video_script para aprobar (con o sin ediciones). Default false."),
1435
+ competitorScanEnabled: CreativeRefs.competitorScanEnabled
1432
1436
  }).strict();
1433
1437
  var imageStyleList = ImageCreativeStyleEnum.options.join(" | ");
1434
1438
  var archetypeList = ImageCreativeArchetypeEnum.options.join(" | ");
@@ -1455,7 +1459,8 @@ var ImageInput = z3.object({
1455
1459
  price: CreativeRefs.price,
1456
1460
  compareAtPrice: z3.string().optional().describe('Opcional. Precio "antes" de la oferta \u2014 solo para im\xE1genes con descuento. Ej. "$129.000" cuando price="$89.900". \xDAtil con creativeArchetype="offer_value_prop".'),
1457
1461
  offer: CreativeRefs.offer,
1458
- isCombo: CreativeRefs.isCombo
1462
+ isCombo: CreativeRefs.isCombo,
1463
+ competitorScanEnabled: CreativeRefs.competitorScanEnabled
1459
1464
  });
1460
1465
  var LandingInput = z3.object({
1461
1466
  images: CreativeRefs.images,
@@ -1466,7 +1471,8 @@ var LandingInput = z3.object({
1466
1471
  price: CreativeRefs.price,
1467
1472
  offer: CreativeRefs.offer,
1468
1473
  paymentMethods: z3.string().optional().describe('Opcional. M\xE9todos de pago a mostrar (lista libre). Ej. "Tarjeta, PSE, Nequi, Contraentrega". Si se omite, la IA usa los m\xE1s comunes del pa\xEDs.'),
1469
- isCombo: CreativeRefs.isCombo
1474
+ isCombo: CreativeRefs.isCombo,
1475
+ competitorScanEnabled: CreativeRefs.competitorScanEnabled
1470
1476
  });
1471
1477
  function registerCreativeTools(server, api, { transport = "http" } = {}) {
1472
1478
  server.tool("generate_video_creative", 'Genera UN video creativo independiente. Devuelve un taskId.\n\nREQUERIDOS: images (array de 1-5 fotos), title, primaryAngle, language, country, aspectRatio.\n\nANTES de invocar, PREG\xDANTALE al usuario por price y offer si no los mencion\xF3 \u2014 son los inputs de mayor impacto en conversi\xF3n y nunca debes asumirlos. NO defaultes country/language desde el contexto: preg\xFAntale expl\xEDcitamente. Si el usuario te dice "t\xFA elige" para price/offer, om\xEDtelos.\n\nOTROS OPCIONALES (puedes invocar sin ellos y dejar que la IA elija defaults sensatos): durationSeconds, videoPreset (tipo/narrativa del video), videoTier (estilo: basic="Realista"/standard="Multiescena"), features, cta, scriptNotes.\n\nGUION: el usuario NO escribe el guion desde cero \u2014 la IA lo redacta. Si quiere REVISARLO/EDITARLO antes de renderizar (igual que en la web), pasa `pauseForVideoScriptReview: true`; cuando la tarea quede pausada, usa get_video_script para leer las escenas, ofr\xE9celas al usuario, y llama approve_video_script con las ediciones. Para dirigir el guion ANTES de generar (sin pausar), usa scriptNotes.', VideoInput.shape, async (input) => {
@@ -1485,7 +1491,7 @@ function registerCreativeTools(server, api, { transport = "http" } = {}) {
1485
1491
  wirePayload.narrativeStyle = resolved.narrativeStyle;
1486
1492
  }
1487
1493
  if (wireTier !== void 0) wirePayload.videoTier = wireTier;
1488
- if (wireTier === "grok" && input.videoResolution) wirePayload.videoResolution = input.videoResolution;
1494
+ if (wireTier === "single_call" && input.videoResolution) wirePayload.videoResolution = input.videoResolution;
1489
1495
  return await submitCreative(api, {
1490
1496
  path: "/v1/creatives/videos",
1491
1497
  estimatedSeconds: 300,
package/dist/stdio.js CHANGED
@@ -476,7 +476,7 @@ var VideoTierEnum = z.enum([
476
476
  ]);
477
477
  function resolveVideoTier(tier) {
478
478
  if (!tier) return void 0;
479
- return tier === "basic" ? "grok" : "standard";
479
+ return tier === "basic" ? "single_call" : "standard";
480
480
  }
481
481
  __name(resolveVideoTier, "resolveVideoTier");
482
482
  var VideoResolutionEnum = z.enum([
@@ -1137,7 +1137,8 @@ var CreateProductTaskInput = z2.object({
1137
1137
  "landing",
1138
1138
  "video",
1139
1139
  "image"
1140
- ])).min(2).max(3).optional().describe('Opcional. Qu\xE9 outputs generar. Default: todos ["landing","video","image"]. Para 2 outputs: ["landing","image"] (sin video), ["video","image"] (sin landing), ["landing","video"] (sin imagen). Para 1 solo output, usa generate_landing / generate_video_creative / generate_image_creatives.')
1140
+ ])).min(2).max(3).optional().describe('Opcional. Qu\xE9 outputs generar. Default: todos ["landing","video","image"]. Para 2 outputs: ["landing","image"] (sin video), ["video","image"] (sin landing), ["landing","video"] (sin imagen). Para 1 solo output, usa generate_landing / generate_video_creative / generate_image_creatives.'),
1141
+ competitorScanEnabled: z2.boolean().optional().describe("Opcional. Si true (default), el sistema analiza ads de competencia en Meta Ad Library y enriquece los \xE1ngulos generados con hooks y painPoints validados por el mercado (\u2248$0.20-0.48 extra por task \u2014 var\xEDa con cu\xE1ntas transcripciones de video se capturen). Si false, el pipeline genera \xE1ngulos sin esa se\xF1al \u2014 usa esto SOLO si el usuario ya tiene su propia investigaci\xF3n de mercado o quiere ahorrar costos en productos muy nicho sin presencia en Meta. Default true.")
1141
1142
  }).strict();
1142
1143
  var GetTaskStatusInput = z2.object({
1143
1144
  taskId: z2.string().min(1),
@@ -1215,14 +1216,15 @@ function registerTaskTools(server, api, { proxyBaseUrl = null, transport = "http
1215
1216
  "options.videoStyle": resolved?.videoStyle,
1216
1217
  "options.narrativeStyle": resolved?.narrativeStyle,
1217
1218
  "options.videoTier": wireTier,
1218
- // Resolution is meaningful ONLY for the basic/grok tier; for every
1219
- // other tier the backend derives it. Forward it ONLY for grok so the
1220
- // MCP never presents a "user choice where there is none" (the web has
1221
- // no resolution knob for standard) — for non-grok it's dropped.
1222
- "options.videoResolution": wireTier === "grok" ? input.videoResolution : void 0,
1219
+ // Resolution is meaningful ONLY for the basic/single_call tier; for every
1220
+ // other tier the backend derives it. Forward it ONLY for single_call so
1221
+ // the MCP never presents a "user choice where there is none" (the web
1222
+ // has no resolution knob for standard) — for non-single_call it's dropped.
1223
+ "options.videoResolution": wireTier === "single_call" ? input.videoResolution : void 0,
1223
1224
  "options.multiAngleVideos": input.multiAngleVideos,
1224
1225
  "options.angleNarratives": input.angleNarratives,
1225
1226
  "options.selectedOutputs": input.outputs,
1227
+ "options.competitorScanEnabled": input.competitorScanEnabled,
1226
1228
  url: input.productUrl
1227
1229
  });
1228
1230
  const r = await api.postMultipart("/v1/ingest", {
@@ -1362,7 +1364,8 @@ var CreativeRefs = {
1362
1364
  price: z3.string().optional().describe('Precio en formato libre \u2014 ej. "$89.900", "USD 29.99". Opcional pero MUY IMPACTANTE para conversi\xF3n: si el usuario no lo mencion\xF3, PREG\xDANTALE antes de invocar. Si el usuario te dice "t\xFA elige", omite el campo y la IA del backend sugiere uno.'),
1363
1365
  offer: z3.string().optional().describe('Oferta a destacar \u2014 ej. "2x1", "Env\xEDo gratis", "50% OFF". Opcional pero MUY IMPACTANTE: si el usuario no lo mencion\xF3, PREG\xDANTALE antes de invocar (es v\xE1lido que diga "sin oferta"). Si el usuario te dice "t\xFA elige", omite el campo.'),
1364
1366
  buyerPersona: z3.string().optional().describe('Opcional. Descripci\xF3n del comprador objetivo. Ej. "Mujeres 35-50, profesionales urbanas". Si se omite, la IA infiere desde el \xE1ngulo y producto.'),
1365
- isCombo: z3.boolean().optional().describe("Opcional. Si true, el creativo presenta el producto como combo/pack. Default false.")
1367
+ isCombo: z3.boolean().optional().describe("Opcional. Si true, el creativo presenta el producto como combo/pack. Default false."),
1368
+ competitorScanEnabled: z3.boolean().optional().describe("Opcional. Si true (default), el sistema analiza ads de competencia en Meta Ad Library y enriquece los \xE1ngulos generados con hooks y painPoints validados por el mercado (\u2248$0.20-0.48 extra por task \u2014 var\xEDa con cu\xE1ntas transcripciones de video se capturen). Si false, el pipeline genera \xE1ngulos sin esa se\xF1al \u2014 usa esto SOLO si el usuario ya tiene su propia investigaci\xF3n de mercado o quiere ahorrar costos en productos muy nicho sin presencia en Meta. Default true.")
1366
1369
  };
1367
1370
  var VideoInput = z3.object({
1368
1371
  images: CreativeRefs.images,
@@ -1384,7 +1387,8 @@ var VideoInput = z3.object({
1384
1387
  offer: CreativeRefs.offer,
1385
1388
  cta: z3.string().optional().describe('Opcional. Call-to-action final del video. Ej. "Compra ahora", "Pide el tuyo hoy", "Link en bio". Si se omite, la IA escribe uno.'),
1386
1389
  scriptNotes: z3.string().optional().describe('Opcional. Notas/restricciones para el guion (la IA las usa al redactar). Ej. "No mencionar la marca X", "Tono divertido, no cl\xEDnico", "Mencionar 2x1". NO es el guion literal \u2014 para editar el guion palabra-por-palabra, pasa `pauseForVideoScriptReview: true` y usa get_video_script / approve_video_script tras la pausa.'),
1387
- pauseForVideoScriptReview: z3.boolean().optional().describe("Opcional. Si true, la tarea pausa despu\xE9s de generar el guion y antes de renderizar. \xDAsalo cuando el usuario quiera editar el guion antes de gastar cr\xE9ditos en el video. Tras la pausa: get_video_script para leerlo, approve_video_script para aprobar (con o sin ediciones). Default false.")
1390
+ pauseForVideoScriptReview: z3.boolean().optional().describe("Opcional. Si true, la tarea pausa despu\xE9s de generar el guion y antes de renderizar. \xDAsalo cuando el usuario quiera editar el guion antes de gastar cr\xE9ditos en el video. Tras la pausa: get_video_script para leerlo, approve_video_script para aprobar (con o sin ediciones). Default false."),
1391
+ competitorScanEnabled: CreativeRefs.competitorScanEnabled
1388
1392
  }).strict();
1389
1393
  var imageStyleList = ImageCreativeStyleEnum.options.join(" | ");
1390
1394
  var archetypeList = ImageCreativeArchetypeEnum.options.join(" | ");
@@ -1411,7 +1415,8 @@ var ImageInput = z3.object({
1411
1415
  price: CreativeRefs.price,
1412
1416
  compareAtPrice: z3.string().optional().describe('Opcional. Precio "antes" de la oferta \u2014 solo para im\xE1genes con descuento. Ej. "$129.000" cuando price="$89.900". \xDAtil con creativeArchetype="offer_value_prop".'),
1413
1417
  offer: CreativeRefs.offer,
1414
- isCombo: CreativeRefs.isCombo
1418
+ isCombo: CreativeRefs.isCombo,
1419
+ competitorScanEnabled: CreativeRefs.competitorScanEnabled
1415
1420
  });
1416
1421
  var LandingInput = z3.object({
1417
1422
  images: CreativeRefs.images,
@@ -1422,7 +1427,8 @@ var LandingInput = z3.object({
1422
1427
  price: CreativeRefs.price,
1423
1428
  offer: CreativeRefs.offer,
1424
1429
  paymentMethods: z3.string().optional().describe('Opcional. M\xE9todos de pago a mostrar (lista libre). Ej. "Tarjeta, PSE, Nequi, Contraentrega". Si se omite, la IA usa los m\xE1s comunes del pa\xEDs.'),
1425
- isCombo: CreativeRefs.isCombo
1430
+ isCombo: CreativeRefs.isCombo,
1431
+ competitorScanEnabled: CreativeRefs.competitorScanEnabled
1426
1432
  });
1427
1433
  function registerCreativeTools(server, api, { transport = "http" } = {}) {
1428
1434
  server.tool("generate_video_creative", 'Genera UN video creativo independiente. Devuelve un taskId.\n\nREQUERIDOS: images (array de 1-5 fotos), title, primaryAngle, language, country, aspectRatio.\n\nANTES de invocar, PREG\xDANTALE al usuario por price y offer si no los mencion\xF3 \u2014 son los inputs de mayor impacto en conversi\xF3n y nunca debes asumirlos. NO defaultes country/language desde el contexto: preg\xFAntale expl\xEDcitamente. Si el usuario te dice "t\xFA elige" para price/offer, om\xEDtelos.\n\nOTROS OPCIONALES (puedes invocar sin ellos y dejar que la IA elija defaults sensatos): durationSeconds, videoPreset (tipo/narrativa del video), videoTier (estilo: basic="Realista"/standard="Multiescena"), features, cta, scriptNotes.\n\nGUION: el usuario NO escribe el guion desde cero \u2014 la IA lo redacta. Si quiere REVISARLO/EDITARLO antes de renderizar (igual que en la web), pasa `pauseForVideoScriptReview: true`; cuando la tarea quede pausada, usa get_video_script para leer las escenas, ofr\xE9celas al usuario, y llama approve_video_script con las ediciones. Para dirigir el guion ANTES de generar (sin pausar), usa scriptNotes.', VideoInput.shape, async (input) => {
@@ -1441,7 +1447,7 @@ function registerCreativeTools(server, api, { transport = "http" } = {}) {
1441
1447
  wirePayload.narrativeStyle = resolved.narrativeStyle;
1442
1448
  }
1443
1449
  if (wireTier !== void 0) wirePayload.videoTier = wireTier;
1444
- if (wireTier === "grok" && input.videoResolution) wirePayload.videoResolution = input.videoResolution;
1450
+ if (wireTier === "single_call" && input.videoResolution) wirePayload.videoResolution = input.videoResolution;
1445
1451
  return await submitCreative(api, {
1446
1452
  path: "/v1/creatives/videos",
1447
1453
  estimatedSeconds: 300,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@productmaker/mcp",
3
- "version": "0.12.1",
3
+ "version": "0.14.0",
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.",