@productmaker/mcp 12.7.0 → 12.8.1
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/dist/http.js +152 -14
- package/dist/stdio.js +152 -14
- package/package.json +1 -1
package/dist/http.js
CHANGED
|
@@ -8352,6 +8352,7 @@ var LandingAssetRequestSchema = z23.discriminatedUnion("kind", [
|
|
|
8352
8352
|
var CodeLandingTypographySchema = z23.object({
|
|
8353
8353
|
googleFamilies: z23.array(z23.string().regex(/^[A-Za-z0-9 ]+(:wght@[0-9;]+)?$/)).max(4)
|
|
8354
8354
|
}).strict();
|
|
8355
|
+
var MAX_CODE_LANDING_AUTHOR_ASSET_REQUESTS = 96;
|
|
8355
8356
|
var CodeLandingAuthorEnvelopeSchema = z23.object({
|
|
8356
8357
|
mode: LandingDocumentModeSchema,
|
|
8357
8358
|
document: CodeLandingDocumentSchema,
|
|
@@ -8359,7 +8360,7 @@ var CodeLandingAuthorEnvelopeSchema = z23.object({
|
|
|
8359
8360
|
anchors: z23.array(CodeLandingAnchorSchema).min(1).max(64),
|
|
8360
8361
|
components: z23.array(ComponentManifestEntrySchema).max(64),
|
|
8361
8362
|
interactions: z23.array(InteractionProgramSchema).max(64),
|
|
8362
|
-
assetRequests: z23.array(LandingAssetRequestSchema).max(
|
|
8363
|
+
assetRequests: z23.array(LandingAssetRequestSchema).max(MAX_CODE_LANDING_AUTHOR_ASSET_REQUESTS),
|
|
8363
8364
|
/** Optional: only the block library authoring path (compose.ts) sets this. */
|
|
8364
8365
|
typography: CodeLandingTypographySchema.optional(),
|
|
8365
8366
|
/**
|
|
@@ -8380,6 +8381,12 @@ var CodeLandingAuthorEnvelopeSchema = z23.object({
|
|
|
8380
8381
|
*/
|
|
8381
8382
|
variantFacts: z23.array(LandingVariantFactSchema).max(16).optional()
|
|
8382
8383
|
});
|
|
8384
|
+
var PreparedLandingAssetRequestSchema = z23.union(LandingAssetRequestSchema.options.map((schema) => schema.shape.kind.value === "generate" || schema.shape.kind.value === "adapt_reference" ? schema.extend({
|
|
8385
|
+
prompt: z23.string().min(1)
|
|
8386
|
+
}) : schema));
|
|
8387
|
+
var CodeLandingPreparedAuthorEnvelopeSchema = CodeLandingAuthorEnvelopeSchema.extend({
|
|
8388
|
+
assetRequests: z23.array(PreparedLandingAssetRequestSchema).max(MAX_CODE_LANDING_AUTHOR_ASSET_REQUESTS)
|
|
8389
|
+
});
|
|
8383
8390
|
var CODE_LANDING_DEFERRED_AUTHOR_PROVIDER_RESULT_KIND = "code_landing_deferred_author_provider_v1";
|
|
8384
8391
|
var CodeLandingDeferredAuthorProviderResultSchema = z23.object({
|
|
8385
8392
|
kind: z23.literal(CODE_LANDING_DEFERRED_AUTHOR_PROVIDER_RESULT_KIND),
|
|
@@ -14140,6 +14147,10 @@ var StatusResponse = z49.object({
|
|
|
14140
14147
|
/** Backend-owned guidance. Render verbatim instead of inspecting provider errors. */
|
|
14141
14148
|
userMessage: z49.string().min(1).max(500).optional()
|
|
14142
14149
|
}).optional(),
|
|
14150
|
+
/** Credits-cents handed back on this task: automatic error/expiry and
|
|
14151
|
+
* partial-delivery refunds from the ledger plus approved quality-report
|
|
14152
|
+
* refunds. Absent when nothing was refunded. Drives «+X créditos devueltos». */
|
|
14153
|
+
refundedCents: BillingNonNegativeAmount.optional(),
|
|
14143
14154
|
/** Persisted target country (ISO 3166-1 alpha-2 or country name) used to pre-fill
|
|
14144
14155
|
* campaign target geo when creating Meta ads from this task. */
|
|
14145
14156
|
targetCountry: z49.string().optional(),
|
|
@@ -14381,6 +14392,9 @@ var TaskSummary = z49.object({
|
|
|
14381
14392
|
* normal users. Multiply by CREDITS_PER_USD_CENT on the client to render
|
|
14382
14393
|
* credits. */
|
|
14383
14394
|
spentCents: BillingNonNegativeAmount.optional(),
|
|
14395
|
+
/** Credits-cents handed back on this task (same source as
|
|
14396
|
+
* `StatusResponse.refundedCents`), for every viewer. Absent when 0. */
|
|
14397
|
+
refundedCents: BillingNonNegativeAmount.optional(),
|
|
14384
14398
|
product: z49.object({
|
|
14385
14399
|
/** Absent for tasks with no scraped Product (free-mode video): those
|
|
14386
14400
|
* carry only a thumbnail. Clients fall back to a "pending" label. */
|
|
@@ -18421,6 +18435,47 @@ var LandingRegenerationStatusResponse = z75.object({
|
|
|
18421
18435
|
updatedAt: z75.string().datetime()
|
|
18422
18436
|
});
|
|
18423
18437
|
|
|
18438
|
+
// ../../packages/types/src/classic-landing-selection.ts
|
|
18439
|
+
function buildClassicLandingSelection(document, gifs, selectedIds, images) {
|
|
18440
|
+
const imageChoices = new Map(images.map((image2) => [
|
|
18441
|
+
classicLandingBlockId({
|
|
18442
|
+
kind: "image",
|
|
18443
|
+
ownerTaskId: image2.ownerTaskId,
|
|
18444
|
+
sourceIndex: image2.sourceIndex
|
|
18445
|
+
}),
|
|
18446
|
+
image2
|
|
18447
|
+
]));
|
|
18448
|
+
let imageCount = 0;
|
|
18449
|
+
const blocks = document.blocks.filter((block) => {
|
|
18450
|
+
if (block.kind === "image") return Boolean(imageChoices.get(classicLandingBlockId(block))?.selected) && imageCount++ < SHOPIFY_MAX_LANDING_IMAGES;
|
|
18451
|
+
const gif = gifs.find((item) => item.gifId === block.gifId && item.ownerTaskId === block.ownerTaskId);
|
|
18452
|
+
return selectedIds.includes(classicLandingBlockId(block)) && Boolean(gif && isDeliverableLandingGif(gif));
|
|
18453
|
+
});
|
|
18454
|
+
return {
|
|
18455
|
+
documentRevision: document.revision,
|
|
18456
|
+
blocks,
|
|
18457
|
+
gifs: blocks.flatMap((block) => block.kind === "gif" ? [
|
|
18458
|
+
{
|
|
18459
|
+
ownerTaskId: block.ownerTaskId,
|
|
18460
|
+
gifId: block.gifId,
|
|
18461
|
+
gifRevision: gifs.find((item) => item.gifId === block.gifId).gifRevision
|
|
18462
|
+
}
|
|
18463
|
+
] : []),
|
|
18464
|
+
images: blocks.flatMap((block) => {
|
|
18465
|
+
if (block.kind !== "image") return [];
|
|
18466
|
+
const choice = imageChoices.get(classicLandingBlockId(block));
|
|
18467
|
+
return [
|
|
18468
|
+
{
|
|
18469
|
+
ownerTaskId: choice.ownerTaskId,
|
|
18470
|
+
sourceIndex: choice.sourceIndex,
|
|
18471
|
+
variantIndex: choice.variantIndex
|
|
18472
|
+
}
|
|
18473
|
+
];
|
|
18474
|
+
})
|
|
18475
|
+
};
|
|
18476
|
+
}
|
|
18477
|
+
__name(buildClassicLandingSelection, "buildClassicLandingSelection");
|
|
18478
|
+
|
|
18424
18479
|
// ../../packages/types/src/shopify-meta-tracking.ts
|
|
18425
18480
|
import * as z76 from "zod";
|
|
18426
18481
|
var MetaTrackingOwnerSchema = z76.enum([
|
|
@@ -24873,7 +24928,7 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
|
|
|
24873
24928
|
], [
|
|
24874
24929
|
"meta_publication"
|
|
24875
24930
|
]),
|
|
24876
|
-
defineCapability("publish_to_shopify", "
|
|
24931
|
+
defineCapability("publish_to_shopify", "655a4e7e2d57493c38972ae31f7fcd0bba154abc7e42f30a74151253cedf59d3", "external_mutation", "publishing", [
|
|
24877
24932
|
"external_mutation",
|
|
24878
24933
|
"state_change"
|
|
24879
24934
|
], [
|
|
@@ -24883,7 +24938,11 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
|
|
|
24883
24938
|
slot("shop", true, [
|
|
24884
24939
|
"shopDomain"
|
|
24885
24940
|
]),
|
|
24941
|
+
// WhatsApp's publish schema has no GIF opt-out; only MCP exposes it.
|
|
24886
24942
|
slot("landing_selection", false, [
|
|
24943
|
+
"numLandingImages",
|
|
24944
|
+
"includeLandingGif"
|
|
24945
|
+
], [
|
|
24887
24946
|
"numLandingImages"
|
|
24888
24947
|
]),
|
|
24889
24948
|
slot("variant_selection", false, [
|
|
@@ -31738,7 +31797,7 @@ var ApiClient = class {
|
|
|
31738
31797
|
};
|
|
31739
31798
|
|
|
31740
31799
|
// src/index.ts
|
|
31741
|
-
var MCP_VERSION = "12.
|
|
31800
|
+
var MCP_VERSION = "12.8.1";
|
|
31742
31801
|
|
|
31743
31802
|
// src/meta-upload-app.ts
|
|
31744
31803
|
import { readFileSync } from "fs";
|
|
@@ -39235,6 +39294,9 @@ var ShopifyInput = z149.object({
|
|
|
39235
39294
|
/** Add an announcement bar text above add-to-cart (optional). */
|
|
39236
39295
|
announcementBarEnabled: z149.boolean().optional(),
|
|
39237
39296
|
announcementBarText: z149.string().trim().min(1).max(SHOPIFY_ANNOUNCEMENT_BAR_MAX_LENGTH).optional(),
|
|
39297
|
+
/** Default true: publish the task's QA-passed landing GIF, as the web
|
|
39298
|
+
* editor does when the seller keeps it selected. false omits it. */
|
|
39299
|
+
includeLandingGif: z149.boolean().optional(),
|
|
39238
39300
|
commerceCorrection: PublishCommerceCorrectionSchema.optional().describe("Complete seller-confirmed commerce values, with the revision and fingerprint returned in recovery. Never invent missing prices or convert currency."),
|
|
39239
39301
|
confirmed: z149.boolean().optional().describe("Required as true only when submitting commerceCorrection, after showing its values and obtaining explicit seller confirmation.")
|
|
39240
39302
|
});
|
|
@@ -39541,7 +39603,7 @@ var TikTokInput = z149.object({
|
|
|
39541
39603
|
function registerPublishTools(server, api, opts = {}) {
|
|
39542
39604
|
const transport = opts.transport ?? "http";
|
|
39543
39605
|
server.registerTool("publish_to_shopify", {
|
|
39544
|
-
description: publishToShopifyGuidance.summary + " Precondici\xF3n: la tarea debe estar en status='complete' \u2014 usa `get_task_status` antes. Por defecto `publicationMode=auto`: si esta tarea ya fue publicada en esa tienda, actualiza ESE MISMO producto y conserva URL, precio, variantes, inventario y SKU; si no, crea uno. Usa `existing` + `targetProductId` cuando el usuario elija otro producto y `new` s\xF3lo si pide crear uno nuevo. ANTES de llamar preg\xFAntale \"\xBFTu producto tiene variantes (talla, color, etc.)?\" y pasa `showVariantPicker: true` si responde que s\xED. Por defecto publica TODAS las im\xE1genes generadas; pasa `numLandingImages` s\xF3lo si el usuario pide menos. En code landings con una oferta expl\xEDcita de packs, ProductMaker s\xF3lo publica el selector si variantes reales de Shopify cobran los totales exactos; la respuesta explica si las cre\xF3, verific\xF3 o descart\xF3 por no existir ahorro. Si devuelve SHOPIFY_PUBLISH_INPUT_REQUIRED, muestra todos los problemas de recovery y solicita los importes faltantes. Solo env\xEDa commerceCorrection con su revisi\xF3n/huella y confirmed:true despu\xE9s de confirmar los valores exactos; nunca inventes importes, conviertas moneda ni elimines ofertas. Si adem\xE1s trae correctionRejected, lo que el vendedor confirm\xF3 fue rechazado: l\xE9ele `reason` ANTES de volver a pedir datos. Un contexto obsoleto requiere volver a revisar; open_editor (incluido SHOPIFY_PUBLISH_CORRECTION_NOT_CONVERGED) requiere el editor de ProductMaker y NO se reenv\xEDa la misma correcci\xF3n. SHOPIFY_PUBLISH_VERIFICATION_FAILED trae en `reason` el siguiente paso: reintenta una vez y si se repite sigue ese paso. Si devuelve SHOPIFY_THEME_SETUP_REQUIRED, el tema de la tienda no tiene el bloque Code Landing y nada se public\xF3: env\xEDa al usuario el themeEditorDeepLink del error para abrir el editor del tema de Shopify, p\xEDdele que agregue el bloque y pulse Guardar (una sola vez por tienda), y reintenta s\xF3lo despu\xE9s. Ante resultado incierto, verifica la tarea/tienda antes de volver a publicar, especialmente con new; commerceCorrectionSaved no prueba publicaci\xF3n. La respuesta es markdown con el link a la landing y al producto.",
|
|
39606
|
+
description: publishToShopifyGuidance.summary + " Precondici\xF3n: la tarea debe estar en status='complete' \u2014 usa `get_task_status` antes. Por defecto `publicationMode=auto`: si esta tarea ya fue publicada en esa tienda, actualiza ESE MISMO producto y conserva URL, precio, variantes, inventario y SKU; si no, crea uno. Usa `existing` + `targetProductId` cuando el usuario elija otro producto y `new` s\xF3lo si pide crear uno nuevo. ANTES de llamar preg\xFAntale \"\xBFTu producto tiene variantes (talla, color, etc.)?\" y pasa `showVariantPicker: true` si responde que s\xED. Por defecto publica TODAS las im\xE1genes generadas; pasa `numLandingImages` s\xF3lo si el usuario pide menos. Tambi\xE9n publica el GIF de la landing si la tarea tiene uno aprobado por QA; pasa `includeLandingGif: false` s\xF3lo si el usuario no lo quiere. En code landings con una oferta expl\xEDcita de packs, ProductMaker s\xF3lo publica el selector si variantes reales de Shopify cobran los totales exactos; la respuesta explica si las cre\xF3, verific\xF3 o descart\xF3 por no existir ahorro. Si devuelve SHOPIFY_PUBLISH_INPUT_REQUIRED, muestra todos los problemas de recovery y solicita los importes faltantes. Solo env\xEDa commerceCorrection con su revisi\xF3n/huella y confirmed:true despu\xE9s de confirmar los valores exactos; nunca inventes importes, conviertas moneda ni elimines ofertas. Si adem\xE1s trae correctionRejected, lo que el vendedor confirm\xF3 fue rechazado: l\xE9ele `reason` ANTES de volver a pedir datos. Un contexto obsoleto requiere volver a revisar; open_editor (incluido SHOPIFY_PUBLISH_CORRECTION_NOT_CONVERGED) requiere el editor de ProductMaker y NO se reenv\xEDa la misma correcci\xF3n. SHOPIFY_PUBLISH_VERIFICATION_FAILED trae en `reason` el siguiente paso: reintenta una vez y si se repite sigue ese paso. Si devuelve SHOPIFY_THEME_SETUP_REQUIRED, el tema de la tienda no tiene el bloque Code Landing y nada se public\xF3: env\xEDa al usuario el themeEditorDeepLink del error para abrir el editor del tema de Shopify, p\xEDdele que agregue el bloque y pulse Guardar (una sola vez por tienda), y reintenta s\xF3lo despu\xE9s. Ante resultado incierto, verifica la tarea/tienda antes de volver a publicar, especialmente con new; commerceCorrectionSaved no prueba publicaci\xF3n. La respuesta es markdown con el link a la landing y al producto.",
|
|
39545
39607
|
inputSchema: ShopifyInput.shape,
|
|
39546
39608
|
// Publication reaches the public storefront, beyond private account data.
|
|
39547
39609
|
annotations: {
|
|
@@ -39563,10 +39625,26 @@ function registerPublishTools(server, api, opts = {}) {
|
|
|
39563
39625
|
};
|
|
39564
39626
|
}
|
|
39565
39627
|
const variantIndex = parsed.variantIndex ?? 0;
|
|
39566
|
-
const
|
|
39628
|
+
const defaults = await fetchLandingPublishDefaults(api, parsed.taskId);
|
|
39629
|
+
const includeLandingGif = parsed.includeLandingGif !== false;
|
|
39630
|
+
if (!defaults && includeLandingGif) {
|
|
39631
|
+
return {
|
|
39632
|
+
isError: true,
|
|
39633
|
+
content: [
|
|
39634
|
+
{
|
|
39635
|
+
type: "text",
|
|
39636
|
+
text: "No pude leer los resultados de la tarea para incluir su GIF; nada se public\xF3. Reintenta, o pasa includeLandingGif: false para publicar sin GIF."
|
|
39637
|
+
}
|
|
39638
|
+
]
|
|
39639
|
+
};
|
|
39640
|
+
}
|
|
39641
|
+
const availableImages = defaults?.imageCount ?? 0;
|
|
39642
|
+
const selectedLandingGif = includeLandingGif ? defaults?.gif ?? null : null;
|
|
39567
39643
|
const effectiveAvailable = availableImages > 0 ? availableImages : 3;
|
|
39568
39644
|
const numImages = Math.min(parsed.numLandingImages ?? effectiveAvailable, effectiveAvailable, SHOPIFY_MAX_LANDING_IMAGES);
|
|
39569
|
-
const
|
|
39645
|
+
const classic = includeLandingGif && defaults && variantIndex === 0 ? buildMcpClassicSelection(defaults, numImages) : null;
|
|
39646
|
+
const classicSelection = classic?.selection ?? null;
|
|
39647
|
+
const selectedLandingImages = classic?.images ?? Array.from({
|
|
39570
39648
|
length: numImages
|
|
39571
39649
|
}, (_, i) => ({
|
|
39572
39650
|
imageIndex: i,
|
|
@@ -39580,6 +39658,15 @@ function registerPublishTools(server, api, opts = {}) {
|
|
|
39580
39658
|
}),
|
|
39581
39659
|
shopDomain: parsed.shopDomain,
|
|
39582
39660
|
selectedLandingImages,
|
|
39661
|
+
// Classic block landings publish their GIF blocks through the
|
|
39662
|
+
// ordered document, exactly like the web editor; the legacy
|
|
39663
|
+
// primary GIF only rides selectedLandingGif.
|
|
39664
|
+
...classicSelection ? {
|
|
39665
|
+
classicSelection,
|
|
39666
|
+
selectedLandingGif: null
|
|
39667
|
+
} : selectedLandingGif ? {
|
|
39668
|
+
selectedLandingGif
|
|
39669
|
+
} : {},
|
|
39583
39670
|
showVariantPicker: parsed.showVariantPicker,
|
|
39584
39671
|
publicationMode: parsed.publicationMode,
|
|
39585
39672
|
targetProductId: parsed.targetProductId,
|
|
@@ -39867,19 +39954,70 @@ function renderBundleMappingMarkdown(mapping) {
|
|
|
39867
39954
|
}
|
|
39868
39955
|
}
|
|
39869
39956
|
__name(renderBundleMappingMarkdown, "renderBundleMappingMarkdown");
|
|
39870
|
-
async function
|
|
39957
|
+
async function fetchLandingPublishDefaults(api, taskId) {
|
|
39871
39958
|
try {
|
|
39872
39959
|
const r = await api.getJson(`/v1/results/${encodeURIComponent(taskId)}`);
|
|
39873
|
-
if (!isRecord3(r)) return
|
|
39874
|
-
|
|
39875
|
-
|
|
39876
|
-
|
|
39877
|
-
|
|
39960
|
+
if (!isRecord3(r) || !isRecord3(r.landing)) return {
|
|
39961
|
+
imageCount: 0,
|
|
39962
|
+
images: [],
|
|
39963
|
+
gif: null,
|
|
39964
|
+
classic: null
|
|
39965
|
+
};
|
|
39966
|
+
const rawImages = Array.isArray(r.landing.images) ? r.landing.images : [];
|
|
39967
|
+
const images = rawImages.map((image2) => {
|
|
39968
|
+
const record = isRecord3(image2) ? image2 : {};
|
|
39969
|
+
return {
|
|
39970
|
+
ownerTaskId: typeof record.variantTaskId === "string" ? record.variantTaskId : taskId,
|
|
39971
|
+
sourceIndex: Number(record.sourceIndex ?? record.index)
|
|
39972
|
+
};
|
|
39973
|
+
});
|
|
39974
|
+
const demo = LandingGifReadableSchema.safeParse(r.landing.demoGif);
|
|
39975
|
+
const gif = demo.success && demo.data.ownerTaskId === taskId && demo.data.quality.verdict === "passed" ? {
|
|
39976
|
+
ownerTaskId: taskId,
|
|
39977
|
+
gifRevision: demo.data.gifRevision
|
|
39978
|
+
} : null;
|
|
39979
|
+
const document = ClassicLandingDocumentSchema.safeParse(r.landing.classicDocument);
|
|
39980
|
+
const gifs = (Array.isArray(r.landing.gifBlocks) ? r.landing.gifBlocks : []).flatMap((entry) => {
|
|
39981
|
+
const parsed = LandingGifItemSchema.safeParse(entry);
|
|
39982
|
+
return parsed.success ? [
|
|
39983
|
+
parsed.data
|
|
39984
|
+
] : [];
|
|
39985
|
+
});
|
|
39986
|
+
return {
|
|
39987
|
+
imageCount: rawImages.length,
|
|
39988
|
+
images,
|
|
39989
|
+
gif,
|
|
39990
|
+
classic: document.success ? {
|
|
39991
|
+
document: document.data,
|
|
39992
|
+
gifs
|
|
39993
|
+
} : null
|
|
39994
|
+
};
|
|
39878
39995
|
} catch {
|
|
39879
|
-
return
|
|
39996
|
+
return null;
|
|
39880
39997
|
}
|
|
39881
39998
|
}
|
|
39882
|
-
__name(
|
|
39999
|
+
__name(fetchLandingPublishDefaults, "fetchLandingPublishDefaults");
|
|
40000
|
+
function buildMcpClassicSelection(defaults, numImages) {
|
|
40001
|
+
if (!defaults.classic) return null;
|
|
40002
|
+
const { document, gifs } = defaults.classic;
|
|
40003
|
+
const gifBlockIds = document.blocks.flatMap((block) => block.kind === "gif" && gifs.some((item) => item.gifId === block.gifId && item.ownerTaskId === block.ownerTaskId && isDeliverableLandingGif(item)) ? [
|
|
40004
|
+
classicLandingBlockId(block)
|
|
40005
|
+
] : []);
|
|
40006
|
+
if (gifBlockIds.length === 0) return null;
|
|
40007
|
+
const selection = buildClassicLandingSelection(document, gifs, gifBlockIds, defaults.images.map((image2, arrayIndex) => ({
|
|
40008
|
+
...image2,
|
|
40009
|
+
selected: arrayIndex < numImages,
|
|
40010
|
+
variantIndex: 0
|
|
40011
|
+
})));
|
|
40012
|
+
return {
|
|
40013
|
+
selection,
|
|
40014
|
+
images: (selection.images ?? []).map((selected) => ({
|
|
40015
|
+
imageIndex: defaults.images.findIndex((image2) => image2.ownerTaskId === selected.ownerTaskId && image2.sourceIndex === selected.sourceIndex),
|
|
40016
|
+
variantIndex: selected.variantIndex
|
|
40017
|
+
}))
|
|
40018
|
+
};
|
|
40019
|
+
}
|
|
40020
|
+
__name(buildMcpClassicSelection, "buildMcpClassicSelection");
|
|
39883
40021
|
function toMetaCampaignOverrides(cfg) {
|
|
39884
40022
|
const out = {};
|
|
39885
40023
|
if (cfg.dailyBudgetUsd !== void 0) out.dailyBudgetUsd = cfg.dailyBudgetUsd;
|
package/dist/stdio.js
CHANGED
|
@@ -8127,6 +8127,7 @@ var LandingAssetRequestSchema = z23.discriminatedUnion("kind", [
|
|
|
8127
8127
|
var CodeLandingTypographySchema = z23.object({
|
|
8128
8128
|
googleFamilies: z23.array(z23.string().regex(/^[A-Za-z0-9 ]+(:wght@[0-9;]+)?$/)).max(4)
|
|
8129
8129
|
}).strict();
|
|
8130
|
+
var MAX_CODE_LANDING_AUTHOR_ASSET_REQUESTS = 96;
|
|
8130
8131
|
var CodeLandingAuthorEnvelopeSchema = z23.object({
|
|
8131
8132
|
mode: LandingDocumentModeSchema,
|
|
8132
8133
|
document: CodeLandingDocumentSchema,
|
|
@@ -8134,7 +8135,7 @@ var CodeLandingAuthorEnvelopeSchema = z23.object({
|
|
|
8134
8135
|
anchors: z23.array(CodeLandingAnchorSchema).min(1).max(64),
|
|
8135
8136
|
components: z23.array(ComponentManifestEntrySchema).max(64),
|
|
8136
8137
|
interactions: z23.array(InteractionProgramSchema).max(64),
|
|
8137
|
-
assetRequests: z23.array(LandingAssetRequestSchema).max(
|
|
8138
|
+
assetRequests: z23.array(LandingAssetRequestSchema).max(MAX_CODE_LANDING_AUTHOR_ASSET_REQUESTS),
|
|
8138
8139
|
/** Optional: only the block library authoring path (compose.ts) sets this. */
|
|
8139
8140
|
typography: CodeLandingTypographySchema.optional(),
|
|
8140
8141
|
/**
|
|
@@ -8155,6 +8156,12 @@ var CodeLandingAuthorEnvelopeSchema = z23.object({
|
|
|
8155
8156
|
*/
|
|
8156
8157
|
variantFacts: z23.array(LandingVariantFactSchema).max(16).optional()
|
|
8157
8158
|
});
|
|
8159
|
+
var PreparedLandingAssetRequestSchema = z23.union(LandingAssetRequestSchema.options.map((schema) => schema.shape.kind.value === "generate" || schema.shape.kind.value === "adapt_reference" ? schema.extend({
|
|
8160
|
+
prompt: z23.string().min(1)
|
|
8161
|
+
}) : schema));
|
|
8162
|
+
var CodeLandingPreparedAuthorEnvelopeSchema = CodeLandingAuthorEnvelopeSchema.extend({
|
|
8163
|
+
assetRequests: z23.array(PreparedLandingAssetRequestSchema).max(MAX_CODE_LANDING_AUTHOR_ASSET_REQUESTS)
|
|
8164
|
+
});
|
|
8158
8165
|
var CODE_LANDING_DEFERRED_AUTHOR_PROVIDER_RESULT_KIND = "code_landing_deferred_author_provider_v1";
|
|
8159
8166
|
var CodeLandingDeferredAuthorProviderResultSchema = z23.object({
|
|
8160
8167
|
kind: z23.literal(CODE_LANDING_DEFERRED_AUTHOR_PROVIDER_RESULT_KIND),
|
|
@@ -13915,6 +13922,10 @@ var StatusResponse = z49.object({
|
|
|
13915
13922
|
/** Backend-owned guidance. Render verbatim instead of inspecting provider errors. */
|
|
13916
13923
|
userMessage: z49.string().min(1).max(500).optional()
|
|
13917
13924
|
}).optional(),
|
|
13925
|
+
/** Credits-cents handed back on this task: automatic error/expiry and
|
|
13926
|
+
* partial-delivery refunds from the ledger plus approved quality-report
|
|
13927
|
+
* refunds. Absent when nothing was refunded. Drives «+X créditos devueltos». */
|
|
13928
|
+
refundedCents: BillingNonNegativeAmount.optional(),
|
|
13918
13929
|
/** Persisted target country (ISO 3166-1 alpha-2 or country name) used to pre-fill
|
|
13919
13930
|
* campaign target geo when creating Meta ads from this task. */
|
|
13920
13931
|
targetCountry: z49.string().optional(),
|
|
@@ -14156,6 +14167,9 @@ var TaskSummary = z49.object({
|
|
|
14156
14167
|
* normal users. Multiply by CREDITS_PER_USD_CENT on the client to render
|
|
14157
14168
|
* credits. */
|
|
14158
14169
|
spentCents: BillingNonNegativeAmount.optional(),
|
|
14170
|
+
/** Credits-cents handed back on this task (same source as
|
|
14171
|
+
* `StatusResponse.refundedCents`), for every viewer. Absent when 0. */
|
|
14172
|
+
refundedCents: BillingNonNegativeAmount.optional(),
|
|
14159
14173
|
product: z49.object({
|
|
14160
14174
|
/** Absent for tasks with no scraped Product (free-mode video): those
|
|
14161
14175
|
* carry only a thumbnail. Clients fall back to a "pending" label. */
|
|
@@ -18196,6 +18210,47 @@ var LandingRegenerationStatusResponse = z75.object({
|
|
|
18196
18210
|
updatedAt: z75.string().datetime()
|
|
18197
18211
|
});
|
|
18198
18212
|
|
|
18213
|
+
// ../../packages/types/src/classic-landing-selection.ts
|
|
18214
|
+
function buildClassicLandingSelection(document, gifs, selectedIds, images) {
|
|
18215
|
+
const imageChoices = new Map(images.map((image2) => [
|
|
18216
|
+
classicLandingBlockId({
|
|
18217
|
+
kind: "image",
|
|
18218
|
+
ownerTaskId: image2.ownerTaskId,
|
|
18219
|
+
sourceIndex: image2.sourceIndex
|
|
18220
|
+
}),
|
|
18221
|
+
image2
|
|
18222
|
+
]));
|
|
18223
|
+
let imageCount = 0;
|
|
18224
|
+
const blocks = document.blocks.filter((block) => {
|
|
18225
|
+
if (block.kind === "image") return Boolean(imageChoices.get(classicLandingBlockId(block))?.selected) && imageCount++ < SHOPIFY_MAX_LANDING_IMAGES;
|
|
18226
|
+
const gif = gifs.find((item) => item.gifId === block.gifId && item.ownerTaskId === block.ownerTaskId);
|
|
18227
|
+
return selectedIds.includes(classicLandingBlockId(block)) && Boolean(gif && isDeliverableLandingGif(gif));
|
|
18228
|
+
});
|
|
18229
|
+
return {
|
|
18230
|
+
documentRevision: document.revision,
|
|
18231
|
+
blocks,
|
|
18232
|
+
gifs: blocks.flatMap((block) => block.kind === "gif" ? [
|
|
18233
|
+
{
|
|
18234
|
+
ownerTaskId: block.ownerTaskId,
|
|
18235
|
+
gifId: block.gifId,
|
|
18236
|
+
gifRevision: gifs.find((item) => item.gifId === block.gifId).gifRevision
|
|
18237
|
+
}
|
|
18238
|
+
] : []),
|
|
18239
|
+
images: blocks.flatMap((block) => {
|
|
18240
|
+
if (block.kind !== "image") return [];
|
|
18241
|
+
const choice = imageChoices.get(classicLandingBlockId(block));
|
|
18242
|
+
return [
|
|
18243
|
+
{
|
|
18244
|
+
ownerTaskId: choice.ownerTaskId,
|
|
18245
|
+
sourceIndex: choice.sourceIndex,
|
|
18246
|
+
variantIndex: choice.variantIndex
|
|
18247
|
+
}
|
|
18248
|
+
];
|
|
18249
|
+
})
|
|
18250
|
+
};
|
|
18251
|
+
}
|
|
18252
|
+
__name(buildClassicLandingSelection, "buildClassicLandingSelection");
|
|
18253
|
+
|
|
18199
18254
|
// ../../packages/types/src/shopify-meta-tracking.ts
|
|
18200
18255
|
import * as z76 from "zod";
|
|
18201
18256
|
var MetaTrackingOwnerSchema = z76.enum([
|
|
@@ -24648,7 +24703,7 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
|
|
|
24648
24703
|
], [
|
|
24649
24704
|
"meta_publication"
|
|
24650
24705
|
]),
|
|
24651
|
-
defineCapability("publish_to_shopify", "
|
|
24706
|
+
defineCapability("publish_to_shopify", "655a4e7e2d57493c38972ae31f7fcd0bba154abc7e42f30a74151253cedf59d3", "external_mutation", "publishing", [
|
|
24652
24707
|
"external_mutation",
|
|
24653
24708
|
"state_change"
|
|
24654
24709
|
], [
|
|
@@ -24658,7 +24713,11 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
|
|
|
24658
24713
|
slot("shop", true, [
|
|
24659
24714
|
"shopDomain"
|
|
24660
24715
|
]),
|
|
24716
|
+
// WhatsApp's publish schema has no GIF opt-out; only MCP exposes it.
|
|
24661
24717
|
slot("landing_selection", false, [
|
|
24718
|
+
"numLandingImages",
|
|
24719
|
+
"includeLandingGif"
|
|
24720
|
+
], [
|
|
24662
24721
|
"numLandingImages"
|
|
24663
24722
|
]),
|
|
24664
24723
|
slot("variant_selection", false, [
|
|
@@ -30065,7 +30124,7 @@ var ApiClient = class {
|
|
|
30065
30124
|
};
|
|
30066
30125
|
|
|
30067
30126
|
// src/index.ts
|
|
30068
|
-
var MCP_VERSION = "12.
|
|
30127
|
+
var MCP_VERSION = "12.8.1";
|
|
30069
30128
|
|
|
30070
30129
|
// src/meta-upload-app.ts
|
|
30071
30130
|
import { readFileSync } from "fs";
|
|
@@ -37720,6 +37779,9 @@ var ShopifyInput = z148.object({
|
|
|
37720
37779
|
/** Add an announcement bar text above add-to-cart (optional). */
|
|
37721
37780
|
announcementBarEnabled: z148.boolean().optional(),
|
|
37722
37781
|
announcementBarText: z148.string().trim().min(1).max(SHOPIFY_ANNOUNCEMENT_BAR_MAX_LENGTH).optional(),
|
|
37782
|
+
/** Default true: publish the task's QA-passed landing GIF, as the web
|
|
37783
|
+
* editor does when the seller keeps it selected. false omits it. */
|
|
37784
|
+
includeLandingGif: z148.boolean().optional(),
|
|
37723
37785
|
commerceCorrection: PublishCommerceCorrectionSchema.optional().describe("Complete seller-confirmed commerce values, with the revision and fingerprint returned in recovery. Never invent missing prices or convert currency."),
|
|
37724
37786
|
confirmed: z148.boolean().optional().describe("Required as true only when submitting commerceCorrection, after showing its values and obtaining explicit seller confirmation.")
|
|
37725
37787
|
});
|
|
@@ -38026,7 +38088,7 @@ var TikTokInput = z148.object({
|
|
|
38026
38088
|
function registerPublishTools(server, api, opts = {}) {
|
|
38027
38089
|
const transport = opts.transport ?? "http";
|
|
38028
38090
|
server.registerTool("publish_to_shopify", {
|
|
38029
|
-
description: publishToShopifyGuidance.summary + " Precondici\xF3n: la tarea debe estar en status='complete' \u2014 usa `get_task_status` antes. Por defecto `publicationMode=auto`: si esta tarea ya fue publicada en esa tienda, actualiza ESE MISMO producto y conserva URL, precio, variantes, inventario y SKU; si no, crea uno. Usa `existing` + `targetProductId` cuando el usuario elija otro producto y `new` s\xF3lo si pide crear uno nuevo. ANTES de llamar preg\xFAntale \"\xBFTu producto tiene variantes (talla, color, etc.)?\" y pasa `showVariantPicker: true` si responde que s\xED. Por defecto publica TODAS las im\xE1genes generadas; pasa `numLandingImages` s\xF3lo si el usuario pide menos. En code landings con una oferta expl\xEDcita de packs, ProductMaker s\xF3lo publica el selector si variantes reales de Shopify cobran los totales exactos; la respuesta explica si las cre\xF3, verific\xF3 o descart\xF3 por no existir ahorro. Si devuelve SHOPIFY_PUBLISH_INPUT_REQUIRED, muestra todos los problemas de recovery y solicita los importes faltantes. Solo env\xEDa commerceCorrection con su revisi\xF3n/huella y confirmed:true despu\xE9s de confirmar los valores exactos; nunca inventes importes, conviertas moneda ni elimines ofertas. Si adem\xE1s trae correctionRejected, lo que el vendedor confirm\xF3 fue rechazado: l\xE9ele `reason` ANTES de volver a pedir datos. Un contexto obsoleto requiere volver a revisar; open_editor (incluido SHOPIFY_PUBLISH_CORRECTION_NOT_CONVERGED) requiere el editor de ProductMaker y NO se reenv\xEDa la misma correcci\xF3n. SHOPIFY_PUBLISH_VERIFICATION_FAILED trae en `reason` el siguiente paso: reintenta una vez y si se repite sigue ese paso. Si devuelve SHOPIFY_THEME_SETUP_REQUIRED, el tema de la tienda no tiene el bloque Code Landing y nada se public\xF3: env\xEDa al usuario el themeEditorDeepLink del error para abrir el editor del tema de Shopify, p\xEDdele que agregue el bloque y pulse Guardar (una sola vez por tienda), y reintenta s\xF3lo despu\xE9s. Ante resultado incierto, verifica la tarea/tienda antes de volver a publicar, especialmente con new; commerceCorrectionSaved no prueba publicaci\xF3n. La respuesta es markdown con el link a la landing y al producto.",
|
|
38091
|
+
description: publishToShopifyGuidance.summary + " Precondici\xF3n: la tarea debe estar en status='complete' \u2014 usa `get_task_status` antes. Por defecto `publicationMode=auto`: si esta tarea ya fue publicada en esa tienda, actualiza ESE MISMO producto y conserva URL, precio, variantes, inventario y SKU; si no, crea uno. Usa `existing` + `targetProductId` cuando el usuario elija otro producto y `new` s\xF3lo si pide crear uno nuevo. ANTES de llamar preg\xFAntale \"\xBFTu producto tiene variantes (talla, color, etc.)?\" y pasa `showVariantPicker: true` si responde que s\xED. Por defecto publica TODAS las im\xE1genes generadas; pasa `numLandingImages` s\xF3lo si el usuario pide menos. Tambi\xE9n publica el GIF de la landing si la tarea tiene uno aprobado por QA; pasa `includeLandingGif: false` s\xF3lo si el usuario no lo quiere. En code landings con una oferta expl\xEDcita de packs, ProductMaker s\xF3lo publica el selector si variantes reales de Shopify cobran los totales exactos; la respuesta explica si las cre\xF3, verific\xF3 o descart\xF3 por no existir ahorro. Si devuelve SHOPIFY_PUBLISH_INPUT_REQUIRED, muestra todos los problemas de recovery y solicita los importes faltantes. Solo env\xEDa commerceCorrection con su revisi\xF3n/huella y confirmed:true despu\xE9s de confirmar los valores exactos; nunca inventes importes, conviertas moneda ni elimines ofertas. Si adem\xE1s trae correctionRejected, lo que el vendedor confirm\xF3 fue rechazado: l\xE9ele `reason` ANTES de volver a pedir datos. Un contexto obsoleto requiere volver a revisar; open_editor (incluido SHOPIFY_PUBLISH_CORRECTION_NOT_CONVERGED) requiere el editor de ProductMaker y NO se reenv\xEDa la misma correcci\xF3n. SHOPIFY_PUBLISH_VERIFICATION_FAILED trae en `reason` el siguiente paso: reintenta una vez y si se repite sigue ese paso. Si devuelve SHOPIFY_THEME_SETUP_REQUIRED, el tema de la tienda no tiene el bloque Code Landing y nada se public\xF3: env\xEDa al usuario el themeEditorDeepLink del error para abrir el editor del tema de Shopify, p\xEDdele que agregue el bloque y pulse Guardar (una sola vez por tienda), y reintenta s\xF3lo despu\xE9s. Ante resultado incierto, verifica la tarea/tienda antes de volver a publicar, especialmente con new; commerceCorrectionSaved no prueba publicaci\xF3n. La respuesta es markdown con el link a la landing y al producto.",
|
|
38030
38092
|
inputSchema: ShopifyInput.shape,
|
|
38031
38093
|
// Publication reaches the public storefront, beyond private account data.
|
|
38032
38094
|
annotations: {
|
|
@@ -38048,10 +38110,26 @@ function registerPublishTools(server, api, opts = {}) {
|
|
|
38048
38110
|
};
|
|
38049
38111
|
}
|
|
38050
38112
|
const variantIndex = parsed.variantIndex ?? 0;
|
|
38051
|
-
const
|
|
38113
|
+
const defaults = await fetchLandingPublishDefaults(api, parsed.taskId);
|
|
38114
|
+
const includeLandingGif = parsed.includeLandingGif !== false;
|
|
38115
|
+
if (!defaults && includeLandingGif) {
|
|
38116
|
+
return {
|
|
38117
|
+
isError: true,
|
|
38118
|
+
content: [
|
|
38119
|
+
{
|
|
38120
|
+
type: "text",
|
|
38121
|
+
text: "No pude leer los resultados de la tarea para incluir su GIF; nada se public\xF3. Reintenta, o pasa includeLandingGif: false para publicar sin GIF."
|
|
38122
|
+
}
|
|
38123
|
+
]
|
|
38124
|
+
};
|
|
38125
|
+
}
|
|
38126
|
+
const availableImages = defaults?.imageCount ?? 0;
|
|
38127
|
+
const selectedLandingGif = includeLandingGif ? defaults?.gif ?? null : null;
|
|
38052
38128
|
const effectiveAvailable = availableImages > 0 ? availableImages : 3;
|
|
38053
38129
|
const numImages = Math.min(parsed.numLandingImages ?? effectiveAvailable, effectiveAvailable, SHOPIFY_MAX_LANDING_IMAGES);
|
|
38054
|
-
const
|
|
38130
|
+
const classic = includeLandingGif && defaults && variantIndex === 0 ? buildMcpClassicSelection(defaults, numImages) : null;
|
|
38131
|
+
const classicSelection = classic?.selection ?? null;
|
|
38132
|
+
const selectedLandingImages = classic?.images ?? Array.from({
|
|
38055
38133
|
length: numImages
|
|
38056
38134
|
}, (_, i) => ({
|
|
38057
38135
|
imageIndex: i,
|
|
@@ -38065,6 +38143,15 @@ function registerPublishTools(server, api, opts = {}) {
|
|
|
38065
38143
|
}),
|
|
38066
38144
|
shopDomain: parsed.shopDomain,
|
|
38067
38145
|
selectedLandingImages,
|
|
38146
|
+
// Classic block landings publish their GIF blocks through the
|
|
38147
|
+
// ordered document, exactly like the web editor; the legacy
|
|
38148
|
+
// primary GIF only rides selectedLandingGif.
|
|
38149
|
+
...classicSelection ? {
|
|
38150
|
+
classicSelection,
|
|
38151
|
+
selectedLandingGif: null
|
|
38152
|
+
} : selectedLandingGif ? {
|
|
38153
|
+
selectedLandingGif
|
|
38154
|
+
} : {},
|
|
38068
38155
|
showVariantPicker: parsed.showVariantPicker,
|
|
38069
38156
|
publicationMode: parsed.publicationMode,
|
|
38070
38157
|
targetProductId: parsed.targetProductId,
|
|
@@ -38352,19 +38439,70 @@ function renderBundleMappingMarkdown(mapping) {
|
|
|
38352
38439
|
}
|
|
38353
38440
|
}
|
|
38354
38441
|
__name(renderBundleMappingMarkdown, "renderBundleMappingMarkdown");
|
|
38355
|
-
async function
|
|
38442
|
+
async function fetchLandingPublishDefaults(api, taskId) {
|
|
38356
38443
|
try {
|
|
38357
38444
|
const r = await api.getJson(`/v1/results/${encodeURIComponent(taskId)}`);
|
|
38358
|
-
if (!isRecord3(r)) return
|
|
38359
|
-
|
|
38360
|
-
|
|
38361
|
-
|
|
38362
|
-
|
|
38445
|
+
if (!isRecord3(r) || !isRecord3(r.landing)) return {
|
|
38446
|
+
imageCount: 0,
|
|
38447
|
+
images: [],
|
|
38448
|
+
gif: null,
|
|
38449
|
+
classic: null
|
|
38450
|
+
};
|
|
38451
|
+
const rawImages = Array.isArray(r.landing.images) ? r.landing.images : [];
|
|
38452
|
+
const images = rawImages.map((image2) => {
|
|
38453
|
+
const record = isRecord3(image2) ? image2 : {};
|
|
38454
|
+
return {
|
|
38455
|
+
ownerTaskId: typeof record.variantTaskId === "string" ? record.variantTaskId : taskId,
|
|
38456
|
+
sourceIndex: Number(record.sourceIndex ?? record.index)
|
|
38457
|
+
};
|
|
38458
|
+
});
|
|
38459
|
+
const demo = LandingGifReadableSchema.safeParse(r.landing.demoGif);
|
|
38460
|
+
const gif = demo.success && demo.data.ownerTaskId === taskId && demo.data.quality.verdict === "passed" ? {
|
|
38461
|
+
ownerTaskId: taskId,
|
|
38462
|
+
gifRevision: demo.data.gifRevision
|
|
38463
|
+
} : null;
|
|
38464
|
+
const document = ClassicLandingDocumentSchema.safeParse(r.landing.classicDocument);
|
|
38465
|
+
const gifs = (Array.isArray(r.landing.gifBlocks) ? r.landing.gifBlocks : []).flatMap((entry) => {
|
|
38466
|
+
const parsed = LandingGifItemSchema.safeParse(entry);
|
|
38467
|
+
return parsed.success ? [
|
|
38468
|
+
parsed.data
|
|
38469
|
+
] : [];
|
|
38470
|
+
});
|
|
38471
|
+
return {
|
|
38472
|
+
imageCount: rawImages.length,
|
|
38473
|
+
images,
|
|
38474
|
+
gif,
|
|
38475
|
+
classic: document.success ? {
|
|
38476
|
+
document: document.data,
|
|
38477
|
+
gifs
|
|
38478
|
+
} : null
|
|
38479
|
+
};
|
|
38363
38480
|
} catch {
|
|
38364
|
-
return
|
|
38481
|
+
return null;
|
|
38365
38482
|
}
|
|
38366
38483
|
}
|
|
38367
|
-
__name(
|
|
38484
|
+
__name(fetchLandingPublishDefaults, "fetchLandingPublishDefaults");
|
|
38485
|
+
function buildMcpClassicSelection(defaults, numImages) {
|
|
38486
|
+
if (!defaults.classic) return null;
|
|
38487
|
+
const { document, gifs } = defaults.classic;
|
|
38488
|
+
const gifBlockIds = document.blocks.flatMap((block) => block.kind === "gif" && gifs.some((item) => item.gifId === block.gifId && item.ownerTaskId === block.ownerTaskId && isDeliverableLandingGif(item)) ? [
|
|
38489
|
+
classicLandingBlockId(block)
|
|
38490
|
+
] : []);
|
|
38491
|
+
if (gifBlockIds.length === 0) return null;
|
|
38492
|
+
const selection = buildClassicLandingSelection(document, gifs, gifBlockIds, defaults.images.map((image2, arrayIndex) => ({
|
|
38493
|
+
...image2,
|
|
38494
|
+
selected: arrayIndex < numImages,
|
|
38495
|
+
variantIndex: 0
|
|
38496
|
+
})));
|
|
38497
|
+
return {
|
|
38498
|
+
selection,
|
|
38499
|
+
images: (selection.images ?? []).map((selected) => ({
|
|
38500
|
+
imageIndex: defaults.images.findIndex((image2) => image2.ownerTaskId === selected.ownerTaskId && image2.sourceIndex === selected.sourceIndex),
|
|
38501
|
+
variantIndex: selected.variantIndex
|
|
38502
|
+
}))
|
|
38503
|
+
};
|
|
38504
|
+
}
|
|
38505
|
+
__name(buildMcpClassicSelection, "buildMcpClassicSelection");
|
|
38368
38506
|
function toMetaCampaignOverrides(cfg) {
|
|
38369
38507
|
const out = {};
|
|
38370
38508
|
if (cfg.dailyBudgetUsd !== void 0) out.dailyBudgetUsd = cfg.dailyBudgetUsd;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@productmaker/mcp",
|
|
3
|
-
"version": "12.
|
|
3
|
+
"version": "12.8.1",
|
|
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.",
|