@productmaker/mcp 8.13.1 → 9.0.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 CHANGED
@@ -137,7 +137,7 @@ separate release step.
137
137
  | `get_task_status` | Check task progress (optional `waitSeconds` for near-sync polling) |
138
138
  | `list_tasks` | List recent tasks |
139
139
  | `edit_task_draft` | Edit angle / pain point / persona before generation |
140
- | `create_service_video` | Video for a _service_ built from its landing page URL. **Paid action** — `automatic` generates directly, `guided` returns concepts to approve via `resolve_pending_action` |
140
+ | `create_service_video` | **Hidden from the MCP since 9.0.0** (owner decision 2026-10-08, still on WhatsApp): use `create_animated_video` for a service video. |
141
141
  | `create_animated_video` | Animated _service_ video ("Video animado", motion graphics: text, shapes and the site's visual identity, music, no presenter) from its landing page URL. Choose `format` (vertical/square/horizontal), `durationSec` (10/15/30/45/60), `language` (es/en/pt) and optional `notes`. **Paid action** — flat price by duration (listed in the tool description, refunded on failure); takes minutes in a queue. Follow it with `get_task_status` (stage, queue position, render %, activity, preview, final MP4). In closed testing: other accounts get `FEATURE_NOT_AVAILABLE` |
142
142
  | `generate_video_creative` | Standalone UGC video creative |
143
143
  | `generate_free_video` | One free-form video from an exact prompt/script, optionally with a reference image (async: returns a `taskId`) |
@@ -390,7 +390,7 @@ Release metadata synchronized with per-store Meta controls. MCP tool inputs, res
390
390
 
391
391
  ### 8.3.0 — Idempotencia de tools pagadas + refresh OAuth
392
392
 
393
- - Tools pagadas (`create_product_task`, `create_service_video`, `create_animated_video` (sin `notes` en la llave), `generate_video_creative`, `generate_free_video`, `generate_image_creatives`, `generate_landing`, `create_creative_variant`): envían un `Idempotency-Key` derivado de los argumentos semánticos (ventana de 15 min). Un reintento con los mismos argumentos devuelve la misma tarea (`replayed: true`) sin segundo cargo; una tarea en `error` sí se reintenta.
393
+ - Tools pagadas (`create_product_task`, `create_animated_video` (sin `notes` en la llave), `generate_video_creative`, `generate_free_video`, `generate_image_creatives`, `generate_landing`, `create_creative_variant`): envían un `Idempotency-Key` derivado de los argumentos semánticos (ventana de 15 min). Un reintento con los mismos argumentos devuelve la misma tarea (`replayed: true`) sin segundo cargo; una tarea en `error` sí se reintenta.
394
394
  - OAuth alojado: se anuncia `offline_access` + grant `refresh_token`; un token a punto de expirar responde `401` + `WWW-Authenticate` para que el host refresque en silencio (`MCP_SUBJECT_TOKEN_REAUTH_WINDOW_MS`, por defecto 180000; `0` lo desactiva).
395
395
 
396
396
  ### 8.2.0 — Fase 3 (modelos)
package/dist/http.js CHANGED
@@ -15274,44 +15274,58 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
15274
15274
  "product"
15275
15275
  ]
15276
15276
  ),
15277
- defineCapability("create_service_video", "c3d81a4f698e01658fa04ebb613a91c8ba43320d21cacda522e72d198036eb21", "credit_consuming", "creative", [
15277
+ defineCapability(
15278
+ "create_service_video",
15279
+ "c3d81a4f698e01658fa04ebb613a91c8ba43320d21cacda522e72d198036eb21",
15278
15280
  "credit_consuming",
15279
- "state_change"
15280
- ], [
15281
- slot("service_landing", true, [
15282
- "landingUrl"
15283
- ]),
15284
- slot("locale", true, [
15285
- "language"
15286
- ]),
15287
- slot("service_context", false, [
15288
- "additionalContext"
15289
- ]),
15290
- slot("voice", false, [
15291
- "voiceId"
15292
- ]),
15293
- slot("brand", false, [
15294
- "brandId"
15295
- ]),
15296
- slot("review_mode", false, [
15297
- "reviewMode"
15298
- ]),
15299
- slot("video_preset", false, [
15300
- "videoPreset"
15301
- ]),
15302
- // MCP-only for now: WhatsApp's service flow keeps the economy default.
15303
- slot("video_quality", false, [
15304
- "videoQuality"
15305
- ], []),
15306
- slot("video_resolution", false, [
15307
- "videoResolution"
15308
- ], [])
15309
- ], [
15310
- "service_context"
15311
- ], [
15312
- "task",
15313
- "video"
15314
- ]),
15281
+ "creative",
15282
+ [
15283
+ "credit_consuming",
15284
+ "state_change"
15285
+ ],
15286
+ [
15287
+ slot("service_landing", true, [
15288
+ "landingUrl"
15289
+ ]),
15290
+ slot("locale", true, [
15291
+ "language"
15292
+ ]),
15293
+ slot("service_context", false, [
15294
+ "additionalContext"
15295
+ ]),
15296
+ slot("voice", false, [
15297
+ "voiceId"
15298
+ ]),
15299
+ slot("brand", false, [
15300
+ "brandId"
15301
+ ]),
15302
+ slot("review_mode", false, [
15303
+ "reviewMode"
15304
+ ]),
15305
+ slot("video_preset", false, [
15306
+ "videoPreset"
15307
+ ]),
15308
+ // MCP-only for now: WhatsApp's service flow keeps the economy default.
15309
+ slot("video_quality", false, [
15310
+ "videoQuality"
15311
+ ], []),
15312
+ slot("video_resolution", false, [
15313
+ "videoResolution"
15314
+ ], [])
15315
+ ],
15316
+ [
15317
+ "service_context"
15318
+ ],
15319
+ [
15320
+ "task",
15321
+ "video"
15322
+ ],
15323
+ // Owner decision 2026-10-08: the presenter service video is hidden from the
15324
+ // MCP for now — dropshipping sellers ordered it for products and cancelled.
15325
+ // MCP clients get `create_animated_video` instead. Flip back to
15326
+ // SHARED_CHANNEL_EXPOSURE to restore it.
15327
+ WHATSAPP_ONLY_CHANNEL_EXPOSURE
15328
+ ),
15315
15329
  defineCapability("edit_image_creative", "50eca473829328dfb63b9cbae03a9835b79c510e29528563e09b7eb3e5e9bca4", "credit_consuming", "creative", [
15316
15330
  "credit_consuming",
15317
15331
  "state_change"
@@ -19789,7 +19803,7 @@ var ApiClient = class {
19789
19803
  };
19790
19804
 
19791
19805
  // src/index.ts
19792
- var MCP_VERSION = "8.13.1";
19806
+ var MCP_VERSION = "9.0.0";
19793
19807
 
19794
19808
  // src/meta-upload-app.ts
19795
19809
  import { readFileSync } from "fs";
@@ -22338,7 +22352,7 @@ function renderAnimatedVideoStatus(result) {
22338
22352
  __name(renderAnimatedVideoStatus, "renderAnimatedVideoStatus");
22339
22353
  function registerAnimatedVideoTools(server, api) {
22340
22354
  server.registerTool("create_animated_video", {
22341
- description: guidance.summary + ` Hace un video animado (motion graphics) de un SERVICIO a partir del enlace de su p\xE1gina: textos, formas y la identidad visual del sitio, con m\xFAsica y efectos, sin presentador ni voz en off. Esta acci\xF3n consume cr\xE9ditos: confirma formato, duraci\xF3n, idioma y precio con el usuario antes de llamarla. Precio fijo por duraci\xF3n: ${describeAnimatedVideoPrices()}; si falla, se devuelve. Tarda varios minutos, m\xE1s si hay otros videos en la cola. Devuelve un taskId: sigue el avance con get_task_status (etapa, posici\xF3n en la cola, % de render, lo que va haciendo y vista previa) hasta done, que trae el enlace del MP4, o error, que trae el motivo. Para un video con presentador usa create_service_video. Puede no estar disponible para todas las cuentas: si responde que la funci\xF3n no est\xE1 disponible, dilo y no ofrezcas alternativas pagadas.`,
22355
+ description: guidance.summary + ` Hace un video animado (motion graphics) de un SERVICIO a partir del enlace de su p\xE1gina: textos, formas y la identidad visual del sitio, con m\xFAsica y efectos, sin presentador ni voz en off. Esta acci\xF3n consume cr\xE9ditos: confirma formato, duraci\xF3n, idioma y precio con el usuario antes de llamarla. Precio fijo por duraci\xF3n: ${describeAnimatedVideoPrices()}; si falla, se devuelve. Tarda varios minutos, m\xE1s si hay otros videos en la cola. Devuelve un taskId: sigue el avance con get_task_status (etapa, posici\xF3n en la cola, % de render, lo que va haciendo y vista previa) hasta done, que trae el enlace del MP4, o error, que trae el motivo. Es el \xFAnico video de servicio disponible por ahora: no ofrezcas un video con presentador. Puede no estar disponible para todas las cuentas: si responde que la funci\xF3n no est\xE1 disponible, dilo y no ofrezcas alternativas pagadas.`,
22342
22356
  inputSchema: CreateAnimatedVideoInput.shape,
22343
22357
  annotations: CREATES_PAID_OPEN_WORLD
22344
22358
  }, async (input) => {
@@ -22443,7 +22457,7 @@ function renderCreateProductTaskAvoidWhenForMcp(fragment) {
22443
22457
  __name(renderCreateProductTaskAvoidWhenForMcp, "renderCreateProductTaskAvoidWhenForMcp");
22444
22458
  var createProductTaskDefaultDescription = renderCreateProductTaskDefaultForMcp(createProductTaskGuidance.defaults[0]);
22445
22459
  var createProductTaskSingleOutputDescription = renderCreateProductTaskAvoidWhenForMcp(createProductTaskGuidance.avoidWhen[0]);
22446
- var createServiceVideoGuidance = getProductMakerCapabilityModelGuidance("create_service_video");
22460
+ var CREATE_SERVICE_VIDEO_ON_MCP = PRODUCTMAKER_MCP_CAPABILITY_NAMES.includes("create_service_video");
22447
22461
  var listTasksGuidance = getProductMakerCapabilityModelGuidance("list_tasks");
22448
22462
  var editTaskDraftGuidance = getProductMakerCapabilityModelGuidance("edit_task_draft");
22449
22463
  var CreateProductTaskInput = z87.object({
@@ -22878,7 +22892,7 @@ async function fetchAnimatedVideoResult(api, taskId, signal, serviceMode = void
22878
22892
  }
22879
22893
  }
22880
22894
  __name(fetchAnimatedVideoResult, "fetchAnimatedVideoResult");
22881
- function registerTaskTools(server, api, { proxyBaseUrl = null, transport = "http" } = {}) {
22895
+ function registerTaskTools(server, api, { proxyBaseUrl = null, transport = "http", serviceVideo = CREATE_SERVICE_VIDEO_ON_MCP } = {}) {
22882
22896
  server.registerTool("create_product_task", {
22883
22897
  description: createProductTaskGuidance.summary + ` ${createProductTaskDefaultDescription} \xDAsala cuando el usuario pide todo o varios outputs, no creando tareas individuales. Usa images para solicitudes directas. Usa projectId \xFAnicamente si el usuario pidi\xF3 expl\xEDcitamente continuar el proyecto guiado que acaba de costear; nunca busques, infieras ni menciones proyectos previos.
22884
22898
 
@@ -23001,97 +23015,100 @@ ANTES de invocar, resume outputs, cantidad de videos y datos comerciales, explic
23001
23015
  throw translateError(e);
23002
23016
  }
23003
23017
  });
23004
- server.registerTool("create_service_video", {
23005
- description: createServiceVideoGuidance.summary + " Esta acci\xF3n consume cr\xE9ditos: confirma la intenci\xF3n del usuario antes de llamarla. `automatic` genera directamente; `guided` devuelve conceptos para que el usuario apruebe uno mediante `resolve_pending_action`. La web tambi\xE9n acepta demos y anuncios de referencia; el transporte MCP de video adjunto todav\xEDa falla cerrado hasta poder subir bytes de forma segura.",
23006
- inputSchema: CreateServiceVideoInput.shape,
23007
- annotations: CREATES_PAID_OPEN_WORLD
23008
- }, async (input) => {
23009
- try {
23010
- if (input.videoQuality === "medium" && input.videoResolution === "720p") {
23011
- throw mcp(McpErrorCode.INVALID_INPUT, 'videoResolution "720p" no est\xE1 disponible con videoQuality "medium" en videos de servicio (Medio = 768P). Usa "480p" o elige "economy"/"pro".');
23012
- }
23013
- await requirePaidCreativeConfirmation(server, `Video de servicio en ${input.language}. Modo: ${input.reviewMode === "automatic" ? "la IA decide todo" : "reviews conversacionales"}.`);
23014
- const created = await api.postJson("/v2/ingest", {
23015
- taskType: "service",
23016
- serviceLandingUrl: input.landingUrl,
23017
- ...input.additionalContext ? {
23018
- additionalContext: input.additionalContext
23019
- } : {},
23020
- lang: input.language,
23021
- ...input.voiceId ? {
23022
- voiceId: input.voiceId
23023
- } : {},
23024
- videoPreset: input.videoPreset,
23025
- videoQuality: input.videoQuality,
23026
- videoResolution: input.videoResolution,
23027
- reviewMode: input.reviewMode,
23028
- ...input.brandId ? {
23029
- brandId: input.brandId
23030
- } : {},
23031
- media: {
23032
- assets: []
23033
- },
23034
- appDemoVideos: []
23035
- }, {
23036
- // The 2026-09-25 incident: four retries of this exact tool created
23037
- // four charged service tasks because the host rephrased
23038
- // `additionalContext` and flipped the landing between `/` and
23039
- // `/es`. The derived key is stable across both rewrites (see
23040
- // request-key.ts).
23041
- idempotencyKey: derivePaidRequestKey({
23042
- fingerprint: api.fingerprint(),
23043
- tool: "create_service_video",
23044
- input,
23045
- nowMs: Date.now()
23046
- })
23047
- });
23048
- const angles = await api.postJson(`/v1/tasks/${encodeURIComponent(created.taskId)}/service-angles`, {});
23049
- const first = angles[0];
23050
- const replayed = created.replayed === true;
23051
- if (input.reviewMode === "automatic") {
23052
- if (!first) throw new Error("ProductMaker no pudo crear un concepto para este servicio.");
23053
- if (!(replayed && created.status !== "queued")) {
23054
- await api.postJson(`/v1/tasks/${encodeURIComponent(created.taskId)}/service-angles/select`, {
23055
- angleIds: [
23056
- first.id
23057
- ]
23018
+ if (serviceVideo) {
23019
+ const createServiceVideoGuidance = getProductMakerCapabilityModelGuidance("create_service_video");
23020
+ server.registerTool("create_service_video", {
23021
+ description: createServiceVideoGuidance.summary + " Esta acci\xF3n consume cr\xE9ditos: confirma la intenci\xF3n del usuario antes de llamarla. `automatic` genera directamente; `guided` devuelve conceptos para que el usuario apruebe uno mediante `resolve_pending_action`. La web tambi\xE9n acepta demos y anuncios de referencia; el transporte MCP de video adjunto todav\xEDa falla cerrado hasta poder subir bytes de forma segura.",
23022
+ inputSchema: CreateServiceVideoInput.shape,
23023
+ annotations: CREATES_PAID_OPEN_WORLD
23024
+ }, async (input) => {
23025
+ try {
23026
+ if (input.videoQuality === "medium" && input.videoResolution === "720p") {
23027
+ throw mcp(McpErrorCode.INVALID_INPUT, 'videoResolution "720p" no est\xE1 disponible con videoQuality "medium" en videos de servicio (Medio = 768P). Usa "480p" o elige "economy"/"pro".');
23028
+ }
23029
+ await requirePaidCreativeConfirmation(server, `Video de servicio en ${input.language}. Modo: ${input.reviewMode === "automatic" ? "la IA decide todo" : "reviews conversacionales"}.`);
23030
+ const created = await api.postJson("/v2/ingest", {
23031
+ taskType: "service",
23032
+ serviceLandingUrl: input.landingUrl,
23033
+ ...input.additionalContext ? {
23034
+ additionalContext: input.additionalContext
23035
+ } : {},
23036
+ lang: input.language,
23037
+ ...input.voiceId ? {
23038
+ voiceId: input.voiceId
23039
+ } : {},
23040
+ videoPreset: input.videoPreset,
23041
+ videoQuality: input.videoQuality,
23042
+ videoResolution: input.videoResolution,
23043
+ reviewMode: input.reviewMode,
23044
+ ...input.brandId ? {
23045
+ brandId: input.brandId
23046
+ } : {},
23047
+ media: {
23048
+ assets: []
23049
+ },
23050
+ appDemoVideos: []
23051
+ }, {
23052
+ // The 2026-09-25 incident: four retries of this exact tool created
23053
+ // four charged service tasks because the host rephrased
23054
+ // `additionalContext` and flipped the landing between `/` and
23055
+ // `/es`. The derived key is stable across both rewrites (see
23056
+ // request-key.ts).
23057
+ idempotencyKey: derivePaidRequestKey({
23058
+ fingerprint: api.fingerprint(),
23059
+ tool: "create_service_video",
23060
+ input,
23061
+ nowMs: Date.now()
23062
+ })
23063
+ });
23064
+ const angles = await api.postJson(`/v1/tasks/${encodeURIComponent(created.taskId)}/service-angles`, {});
23065
+ const first = angles[0];
23066
+ const replayed = created.replayed === true;
23067
+ if (input.reviewMode === "automatic") {
23068
+ if (!first) throw new Error("ProductMaker no pudo crear un concepto para este servicio.");
23069
+ if (!(replayed && created.status !== "queued")) {
23070
+ await api.postJson(`/v1/tasks/${encodeURIComponent(created.taskId)}/service-angles/select`, {
23071
+ angleIds: [
23072
+ first.id
23073
+ ]
23074
+ });
23075
+ }
23076
+ return asText({
23077
+ taskId: created.taskId,
23078
+ status: replayed ? created.status ?? "processing" : "processing",
23079
+ ...replayed ? {
23080
+ replayed: true
23081
+ } : {},
23082
+ reviewMode: input.reviewMode,
23083
+ selectedConcept: first
23084
+ });
23085
+ }
23086
+ if (replayed && created.status !== "queued") {
23087
+ return asText({
23088
+ taskId: created.taskId,
23089
+ status: created.status,
23090
+ replayed: true,
23091
+ reviewMode: input.reviewMode,
23092
+ angles
23058
23093
  });
23059
23094
  }
23060
23095
  return asText({
23061
23096
  taskId: created.taskId,
23062
- status: replayed ? created.status ?? "processing" : "processing",
23097
+ status: "waiting_for_user",
23063
23098
  ...replayed ? {
23064
23099
  replayed: true
23065
23100
  } : {},
23066
23101
  reviewMode: input.reviewMode,
23067
- selectedConcept: first
23068
- });
23069
- }
23070
- if (replayed && created.status !== "queued") {
23071
- return asText({
23072
- taskId: created.taskId,
23073
- status: created.status,
23074
- replayed: true,
23075
- reviewMode: input.reviewMode,
23076
- angles
23102
+ pendingUserAction: {
23103
+ kind: "service_angle_approval",
23104
+ angles
23105
+ }
23077
23106
  });
23107
+ } catch (e) {
23108
+ throw translateError(e);
23078
23109
  }
23079
- return asText({
23080
- taskId: created.taskId,
23081
- status: "waiting_for_user",
23082
- ...replayed ? {
23083
- replayed: true
23084
- } : {},
23085
- reviewMode: input.reviewMode,
23086
- pendingUserAction: {
23087
- kind: "service_angle_approval",
23088
- angles
23089
- }
23090
- });
23091
- } catch (e) {
23092
- throw translateError(e);
23093
- }
23094
- });
23110
+ });
23111
+ }
23095
23112
  server.registerTool("verify_landing_commerce", {
23096
23113
  description: getProductMakerCapabilityModelGuidance("verify_landing_commerce").summary + " Verifica una correcci\xF3n manual de precios, tachados o packs de una landing editable existente. Solo relee Shopify y los recibos externos; no cambia precios, inventario, SKU ni compra una edici\xF3n. Pasa taskId y editId de la edici\xF3n ya conocida; nunca inventes IDs ni pidas repetir el cambio. Devuelve el estado can\xF3nico por proveedor: conserva el aviso pendiente hasta confirmar los valores reales. Solo despu\xE9s de confirmar todos los valores, el servidor puede volver a habilitar la compra. Web guardada no demuestra publicaci\xF3n p\xFAblica ni checkout; muestra las correcciones y enlaces pendientes sin c\xF3digos t\xE9cnicos. La disponibilidad del editor conserva sus permisos actuales.",
23097
23114
  inputSchema: {
package/dist/stdio.js CHANGED
@@ -15296,44 +15296,58 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
15296
15296
  "product"
15297
15297
  ]
15298
15298
  ),
15299
- defineCapability("create_service_video", "c3d81a4f698e01658fa04ebb613a91c8ba43320d21cacda522e72d198036eb21", "credit_consuming", "creative", [
15299
+ defineCapability(
15300
+ "create_service_video",
15301
+ "c3d81a4f698e01658fa04ebb613a91c8ba43320d21cacda522e72d198036eb21",
15300
15302
  "credit_consuming",
15301
- "state_change"
15302
- ], [
15303
- slot("service_landing", true, [
15304
- "landingUrl"
15305
- ]),
15306
- slot("locale", true, [
15307
- "language"
15308
- ]),
15309
- slot("service_context", false, [
15310
- "additionalContext"
15311
- ]),
15312
- slot("voice", false, [
15313
- "voiceId"
15314
- ]),
15315
- slot("brand", false, [
15316
- "brandId"
15317
- ]),
15318
- slot("review_mode", false, [
15319
- "reviewMode"
15320
- ]),
15321
- slot("video_preset", false, [
15322
- "videoPreset"
15323
- ]),
15324
- // MCP-only for now: WhatsApp's service flow keeps the economy default.
15325
- slot("video_quality", false, [
15326
- "videoQuality"
15327
- ], []),
15328
- slot("video_resolution", false, [
15329
- "videoResolution"
15330
- ], [])
15331
- ], [
15332
- "service_context"
15333
- ], [
15334
- "task",
15335
- "video"
15336
- ]),
15303
+ "creative",
15304
+ [
15305
+ "credit_consuming",
15306
+ "state_change"
15307
+ ],
15308
+ [
15309
+ slot("service_landing", true, [
15310
+ "landingUrl"
15311
+ ]),
15312
+ slot("locale", true, [
15313
+ "language"
15314
+ ]),
15315
+ slot("service_context", false, [
15316
+ "additionalContext"
15317
+ ]),
15318
+ slot("voice", false, [
15319
+ "voiceId"
15320
+ ]),
15321
+ slot("brand", false, [
15322
+ "brandId"
15323
+ ]),
15324
+ slot("review_mode", false, [
15325
+ "reviewMode"
15326
+ ]),
15327
+ slot("video_preset", false, [
15328
+ "videoPreset"
15329
+ ]),
15330
+ // MCP-only for now: WhatsApp's service flow keeps the economy default.
15331
+ slot("video_quality", false, [
15332
+ "videoQuality"
15333
+ ], []),
15334
+ slot("video_resolution", false, [
15335
+ "videoResolution"
15336
+ ], [])
15337
+ ],
15338
+ [
15339
+ "service_context"
15340
+ ],
15341
+ [
15342
+ "task",
15343
+ "video"
15344
+ ],
15345
+ // Owner decision 2026-10-08: the presenter service video is hidden from the
15346
+ // MCP for now — dropshipping sellers ordered it for products and cancelled.
15347
+ // MCP clients get `create_animated_video` instead. Flip back to
15348
+ // SHARED_CHANNEL_EXPOSURE to restore it.
15349
+ WHATSAPP_ONLY_CHANNEL_EXPOSURE
15350
+ ),
15337
15351
  defineCapability("edit_image_creative", "50eca473829328dfb63b9cbae03a9835b79c510e29528563e09b7eb3e5e9bca4", "credit_consuming", "creative", [
15338
15352
  "credit_consuming",
15339
15353
  "state_change"
@@ -18121,7 +18135,7 @@ var ApiClient = class {
18121
18135
  };
18122
18136
 
18123
18137
  // src/index.ts
18124
- var MCP_VERSION = "8.13.1";
18138
+ var MCP_VERSION = "9.0.0";
18125
18139
 
18126
18140
  // src/meta-upload-app.ts
18127
18141
  import { readFileSync } from "fs";
@@ -20723,7 +20737,7 @@ function renderAnimatedVideoStatus(result) {
20723
20737
  __name(renderAnimatedVideoStatus, "renderAnimatedVideoStatus");
20724
20738
  function registerAnimatedVideoTools(server, api) {
20725
20739
  server.registerTool("create_animated_video", {
20726
- description: guidance.summary + ` Hace un video animado (motion graphics) de un SERVICIO a partir del enlace de su p\xE1gina: textos, formas y la identidad visual del sitio, con m\xFAsica y efectos, sin presentador ni voz en off. Esta acci\xF3n consume cr\xE9ditos: confirma formato, duraci\xF3n, idioma y precio con el usuario antes de llamarla. Precio fijo por duraci\xF3n: ${describeAnimatedVideoPrices()}; si falla, se devuelve. Tarda varios minutos, m\xE1s si hay otros videos en la cola. Devuelve un taskId: sigue el avance con get_task_status (etapa, posici\xF3n en la cola, % de render, lo que va haciendo y vista previa) hasta done, que trae el enlace del MP4, o error, que trae el motivo. Para un video con presentador usa create_service_video. Puede no estar disponible para todas las cuentas: si responde que la funci\xF3n no est\xE1 disponible, dilo y no ofrezcas alternativas pagadas.`,
20740
+ description: guidance.summary + ` Hace un video animado (motion graphics) de un SERVICIO a partir del enlace de su p\xE1gina: textos, formas y la identidad visual del sitio, con m\xFAsica y efectos, sin presentador ni voz en off. Esta acci\xF3n consume cr\xE9ditos: confirma formato, duraci\xF3n, idioma y precio con el usuario antes de llamarla. Precio fijo por duraci\xF3n: ${describeAnimatedVideoPrices()}; si falla, se devuelve. Tarda varios minutos, m\xE1s si hay otros videos en la cola. Devuelve un taskId: sigue el avance con get_task_status (etapa, posici\xF3n en la cola, % de render, lo que va haciendo y vista previa) hasta done, que trae el enlace del MP4, o error, que trae el motivo. Es el \xFAnico video de servicio disponible por ahora: no ofrezcas un video con presentador. Puede no estar disponible para todas las cuentas: si responde que la funci\xF3n no est\xE1 disponible, dilo y no ofrezcas alternativas pagadas.`,
20727
20741
  inputSchema: CreateAnimatedVideoInput.shape,
20728
20742
  annotations: CREATES_PAID_OPEN_WORLD
20729
20743
  }, async (input) => {
@@ -20828,7 +20842,7 @@ function renderCreateProductTaskAvoidWhenForMcp(fragment) {
20828
20842
  __name(renderCreateProductTaskAvoidWhenForMcp, "renderCreateProductTaskAvoidWhenForMcp");
20829
20843
  var createProductTaskDefaultDescription = renderCreateProductTaskDefaultForMcp(createProductTaskGuidance.defaults[0]);
20830
20844
  var createProductTaskSingleOutputDescription = renderCreateProductTaskAvoidWhenForMcp(createProductTaskGuidance.avoidWhen[0]);
20831
- var createServiceVideoGuidance = getProductMakerCapabilityModelGuidance("create_service_video");
20845
+ var CREATE_SERVICE_VIDEO_ON_MCP = PRODUCTMAKER_MCP_CAPABILITY_NAMES.includes("create_service_video");
20832
20846
  var listTasksGuidance = getProductMakerCapabilityModelGuidance("list_tasks");
20833
20847
  var editTaskDraftGuidance = getProductMakerCapabilityModelGuidance("edit_task_draft");
20834
20848
  var CreateProductTaskInput = z86.object({
@@ -21263,7 +21277,7 @@ async function fetchAnimatedVideoResult(api, taskId, signal, serviceMode = void
21263
21277
  }
21264
21278
  }
21265
21279
  __name(fetchAnimatedVideoResult, "fetchAnimatedVideoResult");
21266
- function registerTaskTools(server, api, { proxyBaseUrl = null, transport = "http" } = {}) {
21280
+ function registerTaskTools(server, api, { proxyBaseUrl = null, transport = "http", serviceVideo = CREATE_SERVICE_VIDEO_ON_MCP } = {}) {
21267
21281
  server.registerTool("create_product_task", {
21268
21282
  description: createProductTaskGuidance.summary + ` ${createProductTaskDefaultDescription} \xDAsala cuando el usuario pide todo o varios outputs, no creando tareas individuales. Usa images para solicitudes directas. Usa projectId \xFAnicamente si el usuario pidi\xF3 expl\xEDcitamente continuar el proyecto guiado que acaba de costear; nunca busques, infieras ni menciones proyectos previos.
21269
21283
 
@@ -21386,97 +21400,100 @@ ANTES de invocar, resume outputs, cantidad de videos y datos comerciales, explic
21386
21400
  throw translateError(e);
21387
21401
  }
21388
21402
  });
21389
- server.registerTool("create_service_video", {
21390
- description: createServiceVideoGuidance.summary + " Esta acci\xF3n consume cr\xE9ditos: confirma la intenci\xF3n del usuario antes de llamarla. `automatic` genera directamente; `guided` devuelve conceptos para que el usuario apruebe uno mediante `resolve_pending_action`. La web tambi\xE9n acepta demos y anuncios de referencia; el transporte MCP de video adjunto todav\xEDa falla cerrado hasta poder subir bytes de forma segura.",
21391
- inputSchema: CreateServiceVideoInput.shape,
21392
- annotations: CREATES_PAID_OPEN_WORLD
21393
- }, async (input) => {
21394
- try {
21395
- if (input.videoQuality === "medium" && input.videoResolution === "720p") {
21396
- throw mcp(McpErrorCode.INVALID_INPUT, 'videoResolution "720p" no est\xE1 disponible con videoQuality "medium" en videos de servicio (Medio = 768P). Usa "480p" o elige "economy"/"pro".');
21397
- }
21398
- await requirePaidCreativeConfirmation(server, `Video de servicio en ${input.language}. Modo: ${input.reviewMode === "automatic" ? "la IA decide todo" : "reviews conversacionales"}.`);
21399
- const created = await api.postJson("/v2/ingest", {
21400
- taskType: "service",
21401
- serviceLandingUrl: input.landingUrl,
21402
- ...input.additionalContext ? {
21403
- additionalContext: input.additionalContext
21404
- } : {},
21405
- lang: input.language,
21406
- ...input.voiceId ? {
21407
- voiceId: input.voiceId
21408
- } : {},
21409
- videoPreset: input.videoPreset,
21410
- videoQuality: input.videoQuality,
21411
- videoResolution: input.videoResolution,
21412
- reviewMode: input.reviewMode,
21413
- ...input.brandId ? {
21414
- brandId: input.brandId
21415
- } : {},
21416
- media: {
21417
- assets: []
21418
- },
21419
- appDemoVideos: []
21420
- }, {
21421
- // The 2026-09-25 incident: four retries of this exact tool created
21422
- // four charged service tasks because the host rephrased
21423
- // `additionalContext` and flipped the landing between `/` and
21424
- // `/es`. The derived key is stable across both rewrites (see
21425
- // request-key.ts).
21426
- idempotencyKey: derivePaidRequestKey({
21427
- fingerprint: api.fingerprint(),
21428
- tool: "create_service_video",
21429
- input,
21430
- nowMs: Date.now()
21431
- })
21432
- });
21433
- const angles = await api.postJson(`/v1/tasks/${encodeURIComponent(created.taskId)}/service-angles`, {});
21434
- const first = angles[0];
21435
- const replayed = created.replayed === true;
21436
- if (input.reviewMode === "automatic") {
21437
- if (!first) throw new Error("ProductMaker no pudo crear un concepto para este servicio.");
21438
- if (!(replayed && created.status !== "queued")) {
21439
- await api.postJson(`/v1/tasks/${encodeURIComponent(created.taskId)}/service-angles/select`, {
21440
- angleIds: [
21441
- first.id
21442
- ]
21403
+ if (serviceVideo) {
21404
+ const createServiceVideoGuidance = getProductMakerCapabilityModelGuidance("create_service_video");
21405
+ server.registerTool("create_service_video", {
21406
+ description: createServiceVideoGuidance.summary + " Esta acci\xF3n consume cr\xE9ditos: confirma la intenci\xF3n del usuario antes de llamarla. `automatic` genera directamente; `guided` devuelve conceptos para que el usuario apruebe uno mediante `resolve_pending_action`. La web tambi\xE9n acepta demos y anuncios de referencia; el transporte MCP de video adjunto todav\xEDa falla cerrado hasta poder subir bytes de forma segura.",
21407
+ inputSchema: CreateServiceVideoInput.shape,
21408
+ annotations: CREATES_PAID_OPEN_WORLD
21409
+ }, async (input) => {
21410
+ try {
21411
+ if (input.videoQuality === "medium" && input.videoResolution === "720p") {
21412
+ throw mcp(McpErrorCode.INVALID_INPUT, 'videoResolution "720p" no est\xE1 disponible con videoQuality "medium" en videos de servicio (Medio = 768P). Usa "480p" o elige "economy"/"pro".');
21413
+ }
21414
+ await requirePaidCreativeConfirmation(server, `Video de servicio en ${input.language}. Modo: ${input.reviewMode === "automatic" ? "la IA decide todo" : "reviews conversacionales"}.`);
21415
+ const created = await api.postJson("/v2/ingest", {
21416
+ taskType: "service",
21417
+ serviceLandingUrl: input.landingUrl,
21418
+ ...input.additionalContext ? {
21419
+ additionalContext: input.additionalContext
21420
+ } : {},
21421
+ lang: input.language,
21422
+ ...input.voiceId ? {
21423
+ voiceId: input.voiceId
21424
+ } : {},
21425
+ videoPreset: input.videoPreset,
21426
+ videoQuality: input.videoQuality,
21427
+ videoResolution: input.videoResolution,
21428
+ reviewMode: input.reviewMode,
21429
+ ...input.brandId ? {
21430
+ brandId: input.brandId
21431
+ } : {},
21432
+ media: {
21433
+ assets: []
21434
+ },
21435
+ appDemoVideos: []
21436
+ }, {
21437
+ // The 2026-09-25 incident: four retries of this exact tool created
21438
+ // four charged service tasks because the host rephrased
21439
+ // `additionalContext` and flipped the landing between `/` and
21440
+ // `/es`. The derived key is stable across both rewrites (see
21441
+ // request-key.ts).
21442
+ idempotencyKey: derivePaidRequestKey({
21443
+ fingerprint: api.fingerprint(),
21444
+ tool: "create_service_video",
21445
+ input,
21446
+ nowMs: Date.now()
21447
+ })
21448
+ });
21449
+ const angles = await api.postJson(`/v1/tasks/${encodeURIComponent(created.taskId)}/service-angles`, {});
21450
+ const first = angles[0];
21451
+ const replayed = created.replayed === true;
21452
+ if (input.reviewMode === "automatic") {
21453
+ if (!first) throw new Error("ProductMaker no pudo crear un concepto para este servicio.");
21454
+ if (!(replayed && created.status !== "queued")) {
21455
+ await api.postJson(`/v1/tasks/${encodeURIComponent(created.taskId)}/service-angles/select`, {
21456
+ angleIds: [
21457
+ first.id
21458
+ ]
21459
+ });
21460
+ }
21461
+ return asText({
21462
+ taskId: created.taskId,
21463
+ status: replayed ? created.status ?? "processing" : "processing",
21464
+ ...replayed ? {
21465
+ replayed: true
21466
+ } : {},
21467
+ reviewMode: input.reviewMode,
21468
+ selectedConcept: first
21469
+ });
21470
+ }
21471
+ if (replayed && created.status !== "queued") {
21472
+ return asText({
21473
+ taskId: created.taskId,
21474
+ status: created.status,
21475
+ replayed: true,
21476
+ reviewMode: input.reviewMode,
21477
+ angles
21443
21478
  });
21444
21479
  }
21445
21480
  return asText({
21446
21481
  taskId: created.taskId,
21447
- status: replayed ? created.status ?? "processing" : "processing",
21482
+ status: "waiting_for_user",
21448
21483
  ...replayed ? {
21449
21484
  replayed: true
21450
21485
  } : {},
21451
21486
  reviewMode: input.reviewMode,
21452
- selectedConcept: first
21453
- });
21454
- }
21455
- if (replayed && created.status !== "queued") {
21456
- return asText({
21457
- taskId: created.taskId,
21458
- status: created.status,
21459
- replayed: true,
21460
- reviewMode: input.reviewMode,
21461
- angles
21487
+ pendingUserAction: {
21488
+ kind: "service_angle_approval",
21489
+ angles
21490
+ }
21462
21491
  });
21492
+ } catch (e) {
21493
+ throw translateError(e);
21463
21494
  }
21464
- return asText({
21465
- taskId: created.taskId,
21466
- status: "waiting_for_user",
21467
- ...replayed ? {
21468
- replayed: true
21469
- } : {},
21470
- reviewMode: input.reviewMode,
21471
- pendingUserAction: {
21472
- kind: "service_angle_approval",
21473
- angles
21474
- }
21475
- });
21476
- } catch (e) {
21477
- throw translateError(e);
21478
- }
21479
- });
21495
+ });
21496
+ }
21480
21497
  server.registerTool("verify_landing_commerce", {
21481
21498
  description: getProductMakerCapabilityModelGuidance("verify_landing_commerce").summary + " Verifica una correcci\xF3n manual de precios, tachados o packs de una landing editable existente. Solo relee Shopify y los recibos externos; no cambia precios, inventario, SKU ni compra una edici\xF3n. Pasa taskId y editId de la edici\xF3n ya conocida; nunca inventes IDs ni pidas repetir el cambio. Devuelve el estado can\xF3nico por proveedor: conserva el aviso pendiente hasta confirmar los valores reales. Solo despu\xE9s de confirmar todos los valores, el servidor puede volver a habilitar la compra. Web guardada no demuestra publicaci\xF3n p\xFAblica ni checkout; muestra las correcciones y enlaces pendientes sin c\xF3digos t\xE9cnicos. La disponibilidad del editor conserva sus permisos actuales.",
21482
21499
  inputSchema: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@productmaker/mcp",
3
- "version": "8.13.1",
3
+ "version": "9.0.0",
4
4
  "type": "module",
5
5
  "private": false,
6
6
  "description": "ProductMaker MCP server — cost products, generate landing pages, UGC videos, and ad creatives, and publish to Shopify, Meta Ads, and TikTok Ads.",