@productmaker/mcp 8.13.0 → 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`) |
@@ -284,6 +284,10 @@ The `base64` field was removed. MCP JSON-RPC transports truncate large tool argu
284
284
 
285
285
  ## Version history
286
286
 
287
+ ### 8.13.1 — Guías de demostración para single take
288
+
289
+ - Sin nuevas herramientas ni opciones públicas. Actualiza la versión del paquete junto con los contratos internos de preparación de referencias; conserva la edición con IA y sus niveles de 8.13.0.
290
+
287
291
  ### 8.13.0 — Dos niveles de Edición con IA (`generateAiEdit`: `"economy"` | `"pro"`)
288
292
 
289
293
  - `generateAiEdit` acepta `"economy"` (Económica: Sonnet 5.5 en esfuerzo alto, más barata) o `"pro"` (Opus 5.5, mejor calidad, ~10 min), además del booleano de siempre: `true` equivale a `"pro"` y `false`/omitido = sin edición. Aplica a `generate_free_video`, `generate_video_creative`, `create_product_task` y `estimate_market_study_cost` (la cotización cambia con el nivel).
@@ -386,7 +390,7 @@ Release metadata synchronized with per-store Meta controls. MCP tool inputs, res
386
390
 
387
391
  ### 8.3.0 — Idempotencia de tools pagadas + refresh OAuth
388
392
 
389
- - 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.
390
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).
391
395
 
392
396
  ### 8.2.0 — Fase 3 (modelos)
package/dist/http.js CHANGED
@@ -8797,6 +8797,7 @@ var KIE_SUBMIT_IMAGE_TASK_TARGETS = [
8797
8797
  "rapid_master_anchor",
8798
8798
  "clean_product_image",
8799
8799
  "single_call_anchor",
8800
+ "single_take_demo_guide",
8800
8801
  "product_view_reference",
8801
8802
  // Generated service-video presenter (text-to-image portrait). Task-owned, so
8802
8803
  // it lives here and not beside `actor_candidate`; it mirrors that target's
@@ -15273,44 +15274,58 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
15273
15274
  "product"
15274
15275
  ]
15275
15276
  ),
15276
- defineCapability("create_service_video", "c3d81a4f698e01658fa04ebb613a91c8ba43320d21cacda522e72d198036eb21", "credit_consuming", "creative", [
15277
+ defineCapability(
15278
+ "create_service_video",
15279
+ "c3d81a4f698e01658fa04ebb613a91c8ba43320d21cacda522e72d198036eb21",
15277
15280
  "credit_consuming",
15278
- "state_change"
15279
- ], [
15280
- slot("service_landing", true, [
15281
- "landingUrl"
15282
- ]),
15283
- slot("locale", true, [
15284
- "language"
15285
- ]),
15286
- slot("service_context", false, [
15287
- "additionalContext"
15288
- ]),
15289
- slot("voice", false, [
15290
- "voiceId"
15291
- ]),
15292
- slot("brand", false, [
15293
- "brandId"
15294
- ]),
15295
- slot("review_mode", false, [
15296
- "reviewMode"
15297
- ]),
15298
- slot("video_preset", false, [
15299
- "videoPreset"
15300
- ]),
15301
- // MCP-only for now: WhatsApp's service flow keeps the economy default.
15302
- slot("video_quality", false, [
15303
- "videoQuality"
15304
- ], []),
15305
- slot("video_resolution", false, [
15306
- "videoResolution"
15307
- ], [])
15308
- ], [
15309
- "service_context"
15310
- ], [
15311
- "task",
15312
- "video"
15313
- ]),
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
+ ),
15314
15329
  defineCapability("edit_image_creative", "50eca473829328dfb63b9cbae03a9835b79c510e29528563e09b7eb3e5e9bca4", "credit_consuming", "creative", [
15315
15330
  "credit_consuming",
15316
15331
  "state_change"
@@ -19788,7 +19803,7 @@ var ApiClient = class {
19788
19803
  };
19789
19804
 
19790
19805
  // src/index.ts
19791
- var MCP_VERSION = "8.13.0";
19806
+ var MCP_VERSION = "9.0.0";
19792
19807
 
19793
19808
  // src/meta-upload-app.ts
19794
19809
  import { readFileSync } from "fs";
@@ -22337,7 +22352,7 @@ function renderAnimatedVideoStatus(result) {
22337
22352
  __name(renderAnimatedVideoStatus, "renderAnimatedVideoStatus");
22338
22353
  function registerAnimatedVideoTools(server, api) {
22339
22354
  server.registerTool("create_animated_video", {
22340
- 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.`,
22341
22356
  inputSchema: CreateAnimatedVideoInput.shape,
22342
22357
  annotations: CREATES_PAID_OPEN_WORLD
22343
22358
  }, async (input) => {
@@ -22442,7 +22457,7 @@ function renderCreateProductTaskAvoidWhenForMcp(fragment) {
22442
22457
  __name(renderCreateProductTaskAvoidWhenForMcp, "renderCreateProductTaskAvoidWhenForMcp");
22443
22458
  var createProductTaskDefaultDescription = renderCreateProductTaskDefaultForMcp(createProductTaskGuidance.defaults[0]);
22444
22459
  var createProductTaskSingleOutputDescription = renderCreateProductTaskAvoidWhenForMcp(createProductTaskGuidance.avoidWhen[0]);
22445
- var createServiceVideoGuidance = getProductMakerCapabilityModelGuidance("create_service_video");
22460
+ var CREATE_SERVICE_VIDEO_ON_MCP = PRODUCTMAKER_MCP_CAPABILITY_NAMES.includes("create_service_video");
22446
22461
  var listTasksGuidance = getProductMakerCapabilityModelGuidance("list_tasks");
22447
22462
  var editTaskDraftGuidance = getProductMakerCapabilityModelGuidance("edit_task_draft");
22448
22463
  var CreateProductTaskInput = z87.object({
@@ -22877,7 +22892,7 @@ async function fetchAnimatedVideoResult(api, taskId, signal, serviceMode = void
22877
22892
  }
22878
22893
  }
22879
22894
  __name(fetchAnimatedVideoResult, "fetchAnimatedVideoResult");
22880
- function registerTaskTools(server, api, { proxyBaseUrl = null, transport = "http" } = {}) {
22895
+ function registerTaskTools(server, api, { proxyBaseUrl = null, transport = "http", serviceVideo = CREATE_SERVICE_VIDEO_ON_MCP } = {}) {
22881
22896
  server.registerTool("create_product_task", {
22882
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.
22883
22898
 
@@ -23000,97 +23015,100 @@ ANTES de invocar, resume outputs, cantidad de videos y datos comerciales, explic
23000
23015
  throw translateError(e);
23001
23016
  }
23002
23017
  });
23003
- server.registerTool("create_service_video", {
23004
- 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.",
23005
- inputSchema: CreateServiceVideoInput.shape,
23006
- annotations: CREATES_PAID_OPEN_WORLD
23007
- }, async (input) => {
23008
- try {
23009
- if (input.videoQuality === "medium" && input.videoResolution === "720p") {
23010
- 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".');
23011
- }
23012
- await requirePaidCreativeConfirmation(server, `Video de servicio en ${input.language}. Modo: ${input.reviewMode === "automatic" ? "la IA decide todo" : "reviews conversacionales"}.`);
23013
- const created = await api.postJson("/v2/ingest", {
23014
- taskType: "service",
23015
- serviceLandingUrl: input.landingUrl,
23016
- ...input.additionalContext ? {
23017
- additionalContext: input.additionalContext
23018
- } : {},
23019
- lang: input.language,
23020
- ...input.voiceId ? {
23021
- voiceId: input.voiceId
23022
- } : {},
23023
- videoPreset: input.videoPreset,
23024
- videoQuality: input.videoQuality,
23025
- videoResolution: input.videoResolution,
23026
- reviewMode: input.reviewMode,
23027
- ...input.brandId ? {
23028
- brandId: input.brandId
23029
- } : {},
23030
- media: {
23031
- assets: []
23032
- },
23033
- appDemoVideos: []
23034
- }, {
23035
- // The 2026-09-25 incident: four retries of this exact tool created
23036
- // four charged service tasks because the host rephrased
23037
- // `additionalContext` and flipped the landing between `/` and
23038
- // `/es`. The derived key is stable across both rewrites (see
23039
- // request-key.ts).
23040
- idempotencyKey: derivePaidRequestKey({
23041
- fingerprint: api.fingerprint(),
23042
- tool: "create_service_video",
23043
- input,
23044
- nowMs: Date.now()
23045
- })
23046
- });
23047
- const angles = await api.postJson(`/v1/tasks/${encodeURIComponent(created.taskId)}/service-angles`, {});
23048
- const first = angles[0];
23049
- const replayed = created.replayed === true;
23050
- if (input.reviewMode === "automatic") {
23051
- if (!first) throw new Error("ProductMaker no pudo crear un concepto para este servicio.");
23052
- if (!(replayed && created.status !== "queued")) {
23053
- await api.postJson(`/v1/tasks/${encodeURIComponent(created.taskId)}/service-angles/select`, {
23054
- angleIds: [
23055
- first.id
23056
- ]
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
23057
23093
  });
23058
23094
  }
23059
23095
  return asText({
23060
23096
  taskId: created.taskId,
23061
- status: replayed ? created.status ?? "processing" : "processing",
23097
+ status: "waiting_for_user",
23062
23098
  ...replayed ? {
23063
23099
  replayed: true
23064
23100
  } : {},
23065
23101
  reviewMode: input.reviewMode,
23066
- selectedConcept: first
23067
- });
23068
- }
23069
- if (replayed && created.status !== "queued") {
23070
- return asText({
23071
- taskId: created.taskId,
23072
- status: created.status,
23073
- replayed: true,
23074
- reviewMode: input.reviewMode,
23075
- angles
23102
+ pendingUserAction: {
23103
+ kind: "service_angle_approval",
23104
+ angles
23105
+ }
23076
23106
  });
23107
+ } catch (e) {
23108
+ throw translateError(e);
23077
23109
  }
23078
- return asText({
23079
- taskId: created.taskId,
23080
- status: "waiting_for_user",
23081
- ...replayed ? {
23082
- replayed: true
23083
- } : {},
23084
- reviewMode: input.reviewMode,
23085
- pendingUserAction: {
23086
- kind: "service_angle_approval",
23087
- angles
23088
- }
23089
- });
23090
- } catch (e) {
23091
- throw translateError(e);
23092
- }
23093
- });
23110
+ });
23111
+ }
23094
23112
  server.registerTool("verify_landing_commerce", {
23095
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.",
23096
23114
  inputSchema: {
package/dist/stdio.js CHANGED
@@ -8819,6 +8819,7 @@ var KIE_SUBMIT_IMAGE_TASK_TARGETS = [
8819
8819
  "rapid_master_anchor",
8820
8820
  "clean_product_image",
8821
8821
  "single_call_anchor",
8822
+ "single_take_demo_guide",
8822
8823
  "product_view_reference",
8823
8824
  // Generated service-video presenter (text-to-image portrait). Task-owned, so
8824
8825
  // it lives here and not beside `actor_candidate`; it mirrors that target's
@@ -15295,44 +15296,58 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
15295
15296
  "product"
15296
15297
  ]
15297
15298
  ),
15298
- defineCapability("create_service_video", "c3d81a4f698e01658fa04ebb613a91c8ba43320d21cacda522e72d198036eb21", "credit_consuming", "creative", [
15299
+ defineCapability(
15300
+ "create_service_video",
15301
+ "c3d81a4f698e01658fa04ebb613a91c8ba43320d21cacda522e72d198036eb21",
15299
15302
  "credit_consuming",
15300
- "state_change"
15301
- ], [
15302
- slot("service_landing", true, [
15303
- "landingUrl"
15304
- ]),
15305
- slot("locale", true, [
15306
- "language"
15307
- ]),
15308
- slot("service_context", false, [
15309
- "additionalContext"
15310
- ]),
15311
- slot("voice", false, [
15312
- "voiceId"
15313
- ]),
15314
- slot("brand", false, [
15315
- "brandId"
15316
- ]),
15317
- slot("review_mode", false, [
15318
- "reviewMode"
15319
- ]),
15320
- slot("video_preset", false, [
15321
- "videoPreset"
15322
- ]),
15323
- // MCP-only for now: WhatsApp's service flow keeps the economy default.
15324
- slot("video_quality", false, [
15325
- "videoQuality"
15326
- ], []),
15327
- slot("video_resolution", false, [
15328
- "videoResolution"
15329
- ], [])
15330
- ], [
15331
- "service_context"
15332
- ], [
15333
- "task",
15334
- "video"
15335
- ]),
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
+ ),
15336
15351
  defineCapability("edit_image_creative", "50eca473829328dfb63b9cbae03a9835b79c510e29528563e09b7eb3e5e9bca4", "credit_consuming", "creative", [
15337
15352
  "credit_consuming",
15338
15353
  "state_change"
@@ -18120,7 +18135,7 @@ var ApiClient = class {
18120
18135
  };
18121
18136
 
18122
18137
  // src/index.ts
18123
- var MCP_VERSION = "8.13.0";
18138
+ var MCP_VERSION = "9.0.0";
18124
18139
 
18125
18140
  // src/meta-upload-app.ts
18126
18141
  import { readFileSync } from "fs";
@@ -20722,7 +20737,7 @@ function renderAnimatedVideoStatus(result) {
20722
20737
  __name(renderAnimatedVideoStatus, "renderAnimatedVideoStatus");
20723
20738
  function registerAnimatedVideoTools(server, api) {
20724
20739
  server.registerTool("create_animated_video", {
20725
- 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.`,
20726
20741
  inputSchema: CreateAnimatedVideoInput.shape,
20727
20742
  annotations: CREATES_PAID_OPEN_WORLD
20728
20743
  }, async (input) => {
@@ -20827,7 +20842,7 @@ function renderCreateProductTaskAvoidWhenForMcp(fragment) {
20827
20842
  __name(renderCreateProductTaskAvoidWhenForMcp, "renderCreateProductTaskAvoidWhenForMcp");
20828
20843
  var createProductTaskDefaultDescription = renderCreateProductTaskDefaultForMcp(createProductTaskGuidance.defaults[0]);
20829
20844
  var createProductTaskSingleOutputDescription = renderCreateProductTaskAvoidWhenForMcp(createProductTaskGuidance.avoidWhen[0]);
20830
- var createServiceVideoGuidance = getProductMakerCapabilityModelGuidance("create_service_video");
20845
+ var CREATE_SERVICE_VIDEO_ON_MCP = PRODUCTMAKER_MCP_CAPABILITY_NAMES.includes("create_service_video");
20831
20846
  var listTasksGuidance = getProductMakerCapabilityModelGuidance("list_tasks");
20832
20847
  var editTaskDraftGuidance = getProductMakerCapabilityModelGuidance("edit_task_draft");
20833
20848
  var CreateProductTaskInput = z86.object({
@@ -21262,7 +21277,7 @@ async function fetchAnimatedVideoResult(api, taskId, signal, serviceMode = void
21262
21277
  }
21263
21278
  }
21264
21279
  __name(fetchAnimatedVideoResult, "fetchAnimatedVideoResult");
21265
- function registerTaskTools(server, api, { proxyBaseUrl = null, transport = "http" } = {}) {
21280
+ function registerTaskTools(server, api, { proxyBaseUrl = null, transport = "http", serviceVideo = CREATE_SERVICE_VIDEO_ON_MCP } = {}) {
21266
21281
  server.registerTool("create_product_task", {
21267
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.
21268
21283
 
@@ -21385,97 +21400,100 @@ ANTES de invocar, resume outputs, cantidad de videos y datos comerciales, explic
21385
21400
  throw translateError(e);
21386
21401
  }
21387
21402
  });
21388
- server.registerTool("create_service_video", {
21389
- 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.",
21390
- inputSchema: CreateServiceVideoInput.shape,
21391
- annotations: CREATES_PAID_OPEN_WORLD
21392
- }, async (input) => {
21393
- try {
21394
- if (input.videoQuality === "medium" && input.videoResolution === "720p") {
21395
- 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".');
21396
- }
21397
- await requirePaidCreativeConfirmation(server, `Video de servicio en ${input.language}. Modo: ${input.reviewMode === "automatic" ? "la IA decide todo" : "reviews conversacionales"}.`);
21398
- const created = await api.postJson("/v2/ingest", {
21399
- taskType: "service",
21400
- serviceLandingUrl: input.landingUrl,
21401
- ...input.additionalContext ? {
21402
- additionalContext: input.additionalContext
21403
- } : {},
21404
- lang: input.language,
21405
- ...input.voiceId ? {
21406
- voiceId: input.voiceId
21407
- } : {},
21408
- videoPreset: input.videoPreset,
21409
- videoQuality: input.videoQuality,
21410
- videoResolution: input.videoResolution,
21411
- reviewMode: input.reviewMode,
21412
- ...input.brandId ? {
21413
- brandId: input.brandId
21414
- } : {},
21415
- media: {
21416
- assets: []
21417
- },
21418
- appDemoVideos: []
21419
- }, {
21420
- // The 2026-09-25 incident: four retries of this exact tool created
21421
- // four charged service tasks because the host rephrased
21422
- // `additionalContext` and flipped the landing between `/` and
21423
- // `/es`. The derived key is stable across both rewrites (see
21424
- // request-key.ts).
21425
- idempotencyKey: derivePaidRequestKey({
21426
- fingerprint: api.fingerprint(),
21427
- tool: "create_service_video",
21428
- input,
21429
- nowMs: Date.now()
21430
- })
21431
- });
21432
- const angles = await api.postJson(`/v1/tasks/${encodeURIComponent(created.taskId)}/service-angles`, {});
21433
- const first = angles[0];
21434
- const replayed = created.replayed === true;
21435
- if (input.reviewMode === "automatic") {
21436
- if (!first) throw new Error("ProductMaker no pudo crear un concepto para este servicio.");
21437
- if (!(replayed && created.status !== "queued")) {
21438
- await api.postJson(`/v1/tasks/${encodeURIComponent(created.taskId)}/service-angles/select`, {
21439
- angleIds: [
21440
- first.id
21441
- ]
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
21442
21478
  });
21443
21479
  }
21444
21480
  return asText({
21445
21481
  taskId: created.taskId,
21446
- status: replayed ? created.status ?? "processing" : "processing",
21482
+ status: "waiting_for_user",
21447
21483
  ...replayed ? {
21448
21484
  replayed: true
21449
21485
  } : {},
21450
21486
  reviewMode: input.reviewMode,
21451
- selectedConcept: first
21452
- });
21453
- }
21454
- if (replayed && created.status !== "queued") {
21455
- return asText({
21456
- taskId: created.taskId,
21457
- status: created.status,
21458
- replayed: true,
21459
- reviewMode: input.reviewMode,
21460
- angles
21487
+ pendingUserAction: {
21488
+ kind: "service_angle_approval",
21489
+ angles
21490
+ }
21461
21491
  });
21492
+ } catch (e) {
21493
+ throw translateError(e);
21462
21494
  }
21463
- return asText({
21464
- taskId: created.taskId,
21465
- status: "waiting_for_user",
21466
- ...replayed ? {
21467
- replayed: true
21468
- } : {},
21469
- reviewMode: input.reviewMode,
21470
- pendingUserAction: {
21471
- kind: "service_angle_approval",
21472
- angles
21473
- }
21474
- });
21475
- } catch (e) {
21476
- throw translateError(e);
21477
- }
21478
- });
21495
+ });
21496
+ }
21479
21497
  server.registerTool("verify_landing_commerce", {
21480
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.",
21481
21499
  inputSchema: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@productmaker/mcp",
3
- "version": "8.13.0",
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.",