@productmaker/mcp 1.11.0 → 1.12.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 +2 -1
- package/dist/http.js +174 -1
- package/dist/stdio.js +174 -1
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
[](https://www.npmjs.com/package/@productmaker/mcp)
|
|
5
5
|
[](https://opensource.org/licenses/MIT)
|
|
6
6
|
|
|
7
|
-
**Product Maker MCP** is the official **Model Context Protocol (MCP) server** for [Product Maker AI](https://productmaker.app). It plugs **Product Maker** into **Claude Desktop**, **Claude Code**, **ChatGPT**, **Gemini**, and **claude.ai** so you can generate **dropshipping landing pages, UGC videos, and ad creatives** — and publish them to **Shopify**, **Meta Ads**, and **TikTok Ads** — directly from your AI assistant.
|
|
7
|
+
**Product Maker MCP** is the official **Model Context Protocol (MCP) server** for [Product Maker AI](https://productmaker.app). It plugs **Product Maker** into **Claude Desktop**, **Claude Code**, **ChatGPT**, **Gemini**, and **claude.ai** so you can cost products, generate **dropshipping landing pages, UGC videos, and ad creatives** — and publish them to **Shopify**, **Meta Ads**, and **TikTok Ads** — directly from your AI assistant.
|
|
8
8
|
|
|
9
9
|
> If an AI assistant brought you here looking for "product maker mcp", "productmaker mcp", or "product-maker mcp server" — this is the right package. Install instructions below.
|
|
10
10
|
|
|
@@ -65,6 +65,7 @@ Sign up at [productmaker.app](https://productmaker.app) and create a key (prefix
|
|
|
65
65
|
|
|
66
66
|
| Tool | What it does |
|
|
67
67
|
|---|---|
|
|
68
|
+
| `cost_product` | Estimate a safe Colombia/COP selling price for free, then reuse its `price` and `compareAtPrice` in `create_product_task` |
|
|
68
69
|
| `create_product_task` | Full pipeline from a product image (extract → angles → video → landing → image creatives) |
|
|
69
70
|
| `get_task_status` | Check task progress (optional `waitSeconds` for near-sync polling) |
|
|
70
71
|
| `list_tasks` | List recent tasks |
|
package/dist/http.js
CHANGED
|
@@ -113,7 +113,7 @@ var ApiClient = class {
|
|
|
113
113
|
};
|
|
114
114
|
|
|
115
115
|
// src/index.ts
|
|
116
|
-
var MCP_VERSION = "1.
|
|
116
|
+
var MCP_VERSION = "1.12.0";
|
|
117
117
|
|
|
118
118
|
// src/tools/tasks.ts
|
|
119
119
|
import { z as z2 } from "zod";
|
|
@@ -2024,6 +2024,178 @@ function renderTikTokStatusMarkdown(r) {
|
|
|
2024
2024
|
}
|
|
2025
2025
|
__name(renderTikTokStatusMarkdown, "renderTikTokStatusMarkdown");
|
|
2026
2026
|
|
|
2027
|
+
// ../../packages/product-economics/src/product-costing.ts
|
|
2028
|
+
import { z as z8 } from "zod";
|
|
2029
|
+
var PRODUCT_PROFIT_GUIDE_COP = 1e4;
|
|
2030
|
+
var ProductCostingInputSchema = z8.object({
|
|
2031
|
+
supplierCostCop: z8.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").positive("supplier_cost_positive"),
|
|
2032
|
+
shippingCostCop: z8.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").nonnegative("shipping_cost_nonnegative"),
|
|
2033
|
+
returnRate: z8.number().finite().min(0, "rate_nonnegative").lt(1, "rate_below_one"),
|
|
2034
|
+
cancellationRate: z8.number().finite().min(0, "rate_nonnegative").lt(1, "rate_below_one"),
|
|
2035
|
+
adsManagerCpaCop: z8.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").nonnegative("cpa_nonnegative"),
|
|
2036
|
+
desiredMargin: z8.number().finite().min(0, "margin_nonnegative").lt(1, "margin_below_one")
|
|
2037
|
+
}).superRefine(({ returnRate, cancellationRate }, context) => {
|
|
2038
|
+
if (returnRate + cancellationRate >= 1) {
|
|
2039
|
+
context.addIssue({
|
|
2040
|
+
code: z8.ZodIssueCode.custom,
|
|
2041
|
+
message: "delivery_rate_positive",
|
|
2042
|
+
path: [
|
|
2043
|
+
"cancellationRate"
|
|
2044
|
+
]
|
|
2045
|
+
});
|
|
2046
|
+
}
|
|
2047
|
+
});
|
|
2048
|
+
var PRODUCT_COSTING_DEFAULTS = {
|
|
2049
|
+
supplierCostCop: 19990,
|
|
2050
|
+
shippingCostCop: 19e3,
|
|
2051
|
+
returnRate: 0.25,
|
|
2052
|
+
cancellationRate: 0.15,
|
|
2053
|
+
adsManagerCpaCop: 15e3,
|
|
2054
|
+
desiredMargin: 0.1
|
|
2055
|
+
};
|
|
2056
|
+
function assertPositiveFinite(value) {
|
|
2057
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
2058
|
+
throw new RangeError("Commercial pricing requires a positive finite value.");
|
|
2059
|
+
}
|
|
2060
|
+
}
|
|
2061
|
+
__name(assertPositiveFinite, "assertPositiveFinite");
|
|
2062
|
+
function roundToCommercial9990(value) {
|
|
2063
|
+
assertPositiveFinite(value);
|
|
2064
|
+
const tier = Math.max(Math.floor((value + 10) / 1e4 + 0.5), 1);
|
|
2065
|
+
return tier * 1e4 - 10;
|
|
2066
|
+
}
|
|
2067
|
+
__name(roundToCommercial9990, "roundToCommercial9990");
|
|
2068
|
+
function ceilToCommercial9990(value) {
|
|
2069
|
+
assertPositiveFinite(value);
|
|
2070
|
+
const tier = Math.max(Math.ceil((value + 10) / 1e4 - 1e-10), 1);
|
|
2071
|
+
return tier * 1e4 - 10;
|
|
2072
|
+
}
|
|
2073
|
+
__name(ceilToCommercial9990, "ceilToCommercial9990");
|
|
2074
|
+
function calculateProductCosting(rawInput) {
|
|
2075
|
+
const input = ProductCostingInputSchema.parse(rawInput);
|
|
2076
|
+
const deliveryRate = 1 - input.returnRate - input.cancellationRate;
|
|
2077
|
+
const adjustedShippingCostCop = input.shippingCostCop / (1 - input.returnRate);
|
|
2078
|
+
const adjustedCpaCop = input.adsManagerCpaCop / deliveryRate;
|
|
2079
|
+
const totalCostCop = input.supplierCostCop + adjustedShippingCostCop + adjustedCpaCop;
|
|
2080
|
+
const suggestedPriceCop = totalCostCop / (1 - input.desiredMargin);
|
|
2081
|
+
const baseCommercialPriceCop = roundToCommercial9990(suggestedPriceCop);
|
|
2082
|
+
const minimumSafePriceCop = Math.max(suggestedPriceCop, totalCostCop + PRODUCT_PROFIT_GUIDE_COP);
|
|
2083
|
+
const commercialPriceCop = ceilToCommercial9990(minimumSafePriceCop);
|
|
2084
|
+
const comparisonPriceCop = commercialPriceCop * 2;
|
|
2085
|
+
const estimatedProfitCop = commercialPriceCop - totalCostCop;
|
|
2086
|
+
const actualMargin = estimatedProfitCop / commercialPriceCop;
|
|
2087
|
+
const breakEvenAdsManagerCpaCop = Math.max(0, (commercialPriceCop - input.supplierCostCop - adjustedShippingCostCop) * deliveryRate);
|
|
2088
|
+
return {
|
|
2089
|
+
deliveryRate,
|
|
2090
|
+
adjustedShippingCostCop,
|
|
2091
|
+
adjustedCpaCop,
|
|
2092
|
+
totalCostCop,
|
|
2093
|
+
suggestedPriceCop,
|
|
2094
|
+
baseCommercialPriceCop,
|
|
2095
|
+
minimumSafePriceCop,
|
|
2096
|
+
commercialPriceCop,
|
|
2097
|
+
comparisonPriceCop,
|
|
2098
|
+
estimatedProfitCop,
|
|
2099
|
+
actualMargin,
|
|
2100
|
+
breakEvenAdsManagerCpaCop,
|
|
2101
|
+
wasPriceAutoAdjusted: commercialPriceCop > baseCommercialPriceCop,
|
|
2102
|
+
profitabilityStatus: "healthy"
|
|
2103
|
+
};
|
|
2104
|
+
}
|
|
2105
|
+
__name(calculateProductCosting, "calculateProductCosting");
|
|
2106
|
+
|
|
2107
|
+
// src/tools/product-costing.ts
|
|
2108
|
+
import { z as z9 } from "zod";
|
|
2109
|
+
var optionalCopAmount = /* @__PURE__ */ __name((description) => z9.number().finite().max(Number.MAX_SAFE_INTEGER).nonnegative().optional().describe(description), "optionalCopAmount");
|
|
2110
|
+
var optionalPercent = /* @__PURE__ */ __name((description) => z9.number().finite().min(0).lt(100).optional().describe(description), "optionalPercent");
|
|
2111
|
+
var ProductCostingToolInput = z9.object({
|
|
2112
|
+
supplierCostCop: z9.number().finite().max(Number.MAX_SAFE_INTEGER).positive().describe("Costo real de una unidad con el proveedor, en pesos colombianos (COP). Este valor s\xED debe venir del usuario."),
|
|
2113
|
+
shippingCostCop: optionalCopAmount("Costo de un env\xEDo entregado en COP. Omite para usar la referencia editable de Colombia: 19000."),
|
|
2114
|
+
returnRatePercent: optionalPercent("Porcentaje de pedidos devueltos. Ejemplo: 25 significa 25%. Omite para usar la referencia editable de Colombia: 25."),
|
|
2115
|
+
cancellationRatePercent: optionalPercent("Porcentaje de pedidos cancelados antes de entrega. Ejemplo: 15 significa 15%. Omite para usar la referencia editable de Colombia: 15."),
|
|
2116
|
+
adsManagerCpaCop: optionalCopAmount("Costo por compra mostrado en Ads Manager, en COP. Omite para usar la referencia editable de Colombia: 15000."),
|
|
2117
|
+
desiredMarginPercent: optionalPercent("Margen de ganancia deseado. Ejemplo: 10 significa 10%. Omite para usar la referencia editable de Colombia: 10.")
|
|
2118
|
+
});
|
|
2119
|
+
function registerProductCostingTools(server) {
|
|
2120
|
+
server.tool("cost_product", "Calcula GRATIS y sin cr\xE9ditos cu\xE1nto cobrar por un producto de dropshipping en Colombia (COP). Es READ-ONLY: no crea tareas ni publica nada. Pide al usuario \xFAnicamente el costo real del proveedor; si no conoce env\xEDo, devoluciones, cancelaciones, CPA o margen, om\xEDtelos y se usar\xE1n valores gu\xEDa editables de Colombia. Devuelve `price` y `compareAtPrice` listos para `create_product_task`; despu\xE9s puedes generar la tarea y publicarla con `publish_to_shopify`, `publish_to_meta` o `publish_to_tiktok`. No inventes un costo de proveedor.", ProductCostingToolInput.shape, async (input) => {
|
|
2121
|
+
const normalized = normalizeToolInput(input);
|
|
2122
|
+
const parsed = ProductCostingInputSchema.safeParse(normalized.input);
|
|
2123
|
+
if (!parsed.success) {
|
|
2124
|
+
return {
|
|
2125
|
+
isError: true,
|
|
2126
|
+
content: [
|
|
2127
|
+
{
|
|
2128
|
+
type: "text",
|
|
2129
|
+
text: "No puedo calcular con esos porcentajes: devoluciones + cancelaciones deben sumar menos de 100%. Revisa los valores e int\xE9ntalo de nuevo."
|
|
2130
|
+
}
|
|
2131
|
+
]
|
|
2132
|
+
};
|
|
2133
|
+
}
|
|
2134
|
+
return renderProductCosting(parsed.data, calculateProductCosting(parsed.data), normalized.usedReferenceValues);
|
|
2135
|
+
});
|
|
2136
|
+
}
|
|
2137
|
+
__name(registerProductCostingTools, "registerProductCostingTools");
|
|
2138
|
+
function normalizeToolInput(input) {
|
|
2139
|
+
const optionalValues = [
|
|
2140
|
+
input.shippingCostCop,
|
|
2141
|
+
input.returnRatePercent,
|
|
2142
|
+
input.cancellationRatePercent,
|
|
2143
|
+
input.adsManagerCpaCop,
|
|
2144
|
+
input.desiredMarginPercent
|
|
2145
|
+
];
|
|
2146
|
+
return {
|
|
2147
|
+
input: {
|
|
2148
|
+
supplierCostCop: input.supplierCostCop,
|
|
2149
|
+
shippingCostCop: input.shippingCostCop ?? PRODUCT_COSTING_DEFAULTS.shippingCostCop,
|
|
2150
|
+
returnRate: (input.returnRatePercent ?? PRODUCT_COSTING_DEFAULTS.returnRate * 100) / 100,
|
|
2151
|
+
cancellationRate: (input.cancellationRatePercent ?? PRODUCT_COSTING_DEFAULTS.cancellationRate * 100) / 100,
|
|
2152
|
+
adsManagerCpaCop: input.adsManagerCpaCop ?? PRODUCT_COSTING_DEFAULTS.adsManagerCpaCop,
|
|
2153
|
+
desiredMargin: (input.desiredMarginPercent ?? PRODUCT_COSTING_DEFAULTS.desiredMargin * 100) / 100
|
|
2154
|
+
},
|
|
2155
|
+
usedReferenceValues: optionalValues.some((value) => value === void 0)
|
|
2156
|
+
};
|
|
2157
|
+
}
|
|
2158
|
+
__name(normalizeToolInput, "normalizeToolInput");
|
|
2159
|
+
function renderProductCosting(input, result, usedReferenceValues) {
|
|
2160
|
+
const price = formatCop(result.commercialPriceCop);
|
|
2161
|
+
const compareAtPrice = formatCop(result.comparisonPriceCop);
|
|
2162
|
+
const lines = [
|
|
2163
|
+
"\u2705 **Costeo del producto \xB7 Colombia**",
|
|
2164
|
+
"",
|
|
2165
|
+
`Precio recomendado: **${price}**`,
|
|
2166
|
+
`Precio comparado: ~~${compareAtPrice}~~`,
|
|
2167
|
+
`Ganancia estimada por venta entregada: **${formatCop(result.estimatedProfitCop)}**`,
|
|
2168
|
+
`Margen real estimado: **${formatPercent(result.actualMargin)}**`,
|
|
2169
|
+
`Costo total estimado: ${formatCop(result.totalCostCop)}`,
|
|
2170
|
+
`M\xE1ximo sugerido en Ads Manager por compra: **${formatCop(result.breakEvenAdsManagerCpaCop)}**`
|
|
2171
|
+
];
|
|
2172
|
+
if (result.wasPriceAutoAdjusted) {
|
|
2173
|
+
lines.push("", `ProductMaker subi\xF3 autom\xE1ticamente el precio desde ${formatCop(result.baseCommercialPriceCop)} para proteger el margen y una ganancia gu\xEDa m\xEDnima de $10.000 COP.`);
|
|
2174
|
+
}
|
|
2175
|
+
lines.push("", "### Valores listos para crear y publicar", `- \`price\`: "${price}"`, `- \`compareAtPrice\`: "${compareAtPrice}"`, "", "Pasa esos dos valores a `create_product_task`; cuando la tarea termine, usa el tool de publicaci\xF3n que el usuario elija.");
|
|
2176
|
+
if (usedReferenceValues) {
|
|
2177
|
+
lines.push("", "_Se usaron valores gu\xEDa de Colombia para los campos omitidos. Son un punto de partida editable, no promedios oficiales._");
|
|
2178
|
+
}
|
|
2179
|
+
lines.push("", `_Este c\xE1lculo es read-only, no consume cr\xE9ditos y us\xF3 entrega estimada de ${formatPercent(result.deliveryRate)}._`, "", `Supuestos: proveedor ${formatCop(input.supplierCostCop)}, env\xEDo ${formatCop(input.shippingCostCop)}, devoluciones ${formatPercent(input.returnRate)}, cancelaciones ${formatPercent(input.cancellationRate)}, CPA ${formatCop(input.adsManagerCpaCop)}, margen deseado ${formatPercent(input.desiredMargin)}.`);
|
|
2180
|
+
return {
|
|
2181
|
+
content: [
|
|
2182
|
+
{
|
|
2183
|
+
type: "text",
|
|
2184
|
+
text: lines.join("\n")
|
|
2185
|
+
}
|
|
2186
|
+
]
|
|
2187
|
+
};
|
|
2188
|
+
}
|
|
2189
|
+
__name(renderProductCosting, "renderProductCosting");
|
|
2190
|
+
function formatCop(value) {
|
|
2191
|
+
return `$${Math.round(value).toLocaleString("es-CO")} COP`;
|
|
2192
|
+
}
|
|
2193
|
+
__name(formatCop, "formatCop");
|
|
2194
|
+
function formatPercent(value) {
|
|
2195
|
+
return `${(value * 100).toFixed(1).replace(/\.0$/, "")}%`;
|
|
2196
|
+
}
|
|
2197
|
+
__name(formatPercent, "formatPercent");
|
|
2198
|
+
|
|
2027
2199
|
// src/server.ts
|
|
2028
2200
|
function createServer(opts) {
|
|
2029
2201
|
const { apiKey, apiBaseUrl, proxyBaseUrl = null, transport = "http" } = opts;
|
|
@@ -2039,6 +2211,7 @@ function createServer(opts) {
|
|
|
2039
2211
|
}
|
|
2040
2212
|
});
|
|
2041
2213
|
const api = new ApiClient(apiBaseUrl, apiKey);
|
|
2214
|
+
registerProductCostingTools(server);
|
|
2042
2215
|
registerTaskTools(server, api, {
|
|
2043
2216
|
proxyBaseUrl,
|
|
2044
2217
|
transport
|
package/dist/stdio.js
CHANGED
|
@@ -110,7 +110,7 @@ var ApiClient = class {
|
|
|
110
110
|
};
|
|
111
111
|
|
|
112
112
|
// src/index.ts
|
|
113
|
-
var MCP_VERSION = "1.
|
|
113
|
+
var MCP_VERSION = "1.12.0";
|
|
114
114
|
|
|
115
115
|
// src/tools/tasks.ts
|
|
116
116
|
import { z as z2 } from "zod";
|
|
@@ -1980,6 +1980,178 @@ function renderTikTokStatusMarkdown(r) {
|
|
|
1980
1980
|
}
|
|
1981
1981
|
__name(renderTikTokStatusMarkdown, "renderTikTokStatusMarkdown");
|
|
1982
1982
|
|
|
1983
|
+
// ../../packages/product-economics/src/product-costing.ts
|
|
1984
|
+
import { z as z8 } from "zod";
|
|
1985
|
+
var PRODUCT_PROFIT_GUIDE_COP = 1e4;
|
|
1986
|
+
var ProductCostingInputSchema = z8.object({
|
|
1987
|
+
supplierCostCop: z8.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").positive("supplier_cost_positive"),
|
|
1988
|
+
shippingCostCop: z8.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").nonnegative("shipping_cost_nonnegative"),
|
|
1989
|
+
returnRate: z8.number().finite().min(0, "rate_nonnegative").lt(1, "rate_below_one"),
|
|
1990
|
+
cancellationRate: z8.number().finite().min(0, "rate_nonnegative").lt(1, "rate_below_one"),
|
|
1991
|
+
adsManagerCpaCop: z8.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").nonnegative("cpa_nonnegative"),
|
|
1992
|
+
desiredMargin: z8.number().finite().min(0, "margin_nonnegative").lt(1, "margin_below_one")
|
|
1993
|
+
}).superRefine(({ returnRate, cancellationRate }, context) => {
|
|
1994
|
+
if (returnRate + cancellationRate >= 1) {
|
|
1995
|
+
context.addIssue({
|
|
1996
|
+
code: z8.ZodIssueCode.custom,
|
|
1997
|
+
message: "delivery_rate_positive",
|
|
1998
|
+
path: [
|
|
1999
|
+
"cancellationRate"
|
|
2000
|
+
]
|
|
2001
|
+
});
|
|
2002
|
+
}
|
|
2003
|
+
});
|
|
2004
|
+
var PRODUCT_COSTING_DEFAULTS = {
|
|
2005
|
+
supplierCostCop: 19990,
|
|
2006
|
+
shippingCostCop: 19e3,
|
|
2007
|
+
returnRate: 0.25,
|
|
2008
|
+
cancellationRate: 0.15,
|
|
2009
|
+
adsManagerCpaCop: 15e3,
|
|
2010
|
+
desiredMargin: 0.1
|
|
2011
|
+
};
|
|
2012
|
+
function assertPositiveFinite(value) {
|
|
2013
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
2014
|
+
throw new RangeError("Commercial pricing requires a positive finite value.");
|
|
2015
|
+
}
|
|
2016
|
+
}
|
|
2017
|
+
__name(assertPositiveFinite, "assertPositiveFinite");
|
|
2018
|
+
function roundToCommercial9990(value) {
|
|
2019
|
+
assertPositiveFinite(value);
|
|
2020
|
+
const tier = Math.max(Math.floor((value + 10) / 1e4 + 0.5), 1);
|
|
2021
|
+
return tier * 1e4 - 10;
|
|
2022
|
+
}
|
|
2023
|
+
__name(roundToCommercial9990, "roundToCommercial9990");
|
|
2024
|
+
function ceilToCommercial9990(value) {
|
|
2025
|
+
assertPositiveFinite(value);
|
|
2026
|
+
const tier = Math.max(Math.ceil((value + 10) / 1e4 - 1e-10), 1);
|
|
2027
|
+
return tier * 1e4 - 10;
|
|
2028
|
+
}
|
|
2029
|
+
__name(ceilToCommercial9990, "ceilToCommercial9990");
|
|
2030
|
+
function calculateProductCosting(rawInput) {
|
|
2031
|
+
const input = ProductCostingInputSchema.parse(rawInput);
|
|
2032
|
+
const deliveryRate = 1 - input.returnRate - input.cancellationRate;
|
|
2033
|
+
const adjustedShippingCostCop = input.shippingCostCop / (1 - input.returnRate);
|
|
2034
|
+
const adjustedCpaCop = input.adsManagerCpaCop / deliveryRate;
|
|
2035
|
+
const totalCostCop = input.supplierCostCop + adjustedShippingCostCop + adjustedCpaCop;
|
|
2036
|
+
const suggestedPriceCop = totalCostCop / (1 - input.desiredMargin);
|
|
2037
|
+
const baseCommercialPriceCop = roundToCommercial9990(suggestedPriceCop);
|
|
2038
|
+
const minimumSafePriceCop = Math.max(suggestedPriceCop, totalCostCop + PRODUCT_PROFIT_GUIDE_COP);
|
|
2039
|
+
const commercialPriceCop = ceilToCommercial9990(minimumSafePriceCop);
|
|
2040
|
+
const comparisonPriceCop = commercialPriceCop * 2;
|
|
2041
|
+
const estimatedProfitCop = commercialPriceCop - totalCostCop;
|
|
2042
|
+
const actualMargin = estimatedProfitCop / commercialPriceCop;
|
|
2043
|
+
const breakEvenAdsManagerCpaCop = Math.max(0, (commercialPriceCop - input.supplierCostCop - adjustedShippingCostCop) * deliveryRate);
|
|
2044
|
+
return {
|
|
2045
|
+
deliveryRate,
|
|
2046
|
+
adjustedShippingCostCop,
|
|
2047
|
+
adjustedCpaCop,
|
|
2048
|
+
totalCostCop,
|
|
2049
|
+
suggestedPriceCop,
|
|
2050
|
+
baseCommercialPriceCop,
|
|
2051
|
+
minimumSafePriceCop,
|
|
2052
|
+
commercialPriceCop,
|
|
2053
|
+
comparisonPriceCop,
|
|
2054
|
+
estimatedProfitCop,
|
|
2055
|
+
actualMargin,
|
|
2056
|
+
breakEvenAdsManagerCpaCop,
|
|
2057
|
+
wasPriceAutoAdjusted: commercialPriceCop > baseCommercialPriceCop,
|
|
2058
|
+
profitabilityStatus: "healthy"
|
|
2059
|
+
};
|
|
2060
|
+
}
|
|
2061
|
+
__name(calculateProductCosting, "calculateProductCosting");
|
|
2062
|
+
|
|
2063
|
+
// src/tools/product-costing.ts
|
|
2064
|
+
import { z as z9 } from "zod";
|
|
2065
|
+
var optionalCopAmount = /* @__PURE__ */ __name((description) => z9.number().finite().max(Number.MAX_SAFE_INTEGER).nonnegative().optional().describe(description), "optionalCopAmount");
|
|
2066
|
+
var optionalPercent = /* @__PURE__ */ __name((description) => z9.number().finite().min(0).lt(100).optional().describe(description), "optionalPercent");
|
|
2067
|
+
var ProductCostingToolInput = z9.object({
|
|
2068
|
+
supplierCostCop: z9.number().finite().max(Number.MAX_SAFE_INTEGER).positive().describe("Costo real de una unidad con el proveedor, en pesos colombianos (COP). Este valor s\xED debe venir del usuario."),
|
|
2069
|
+
shippingCostCop: optionalCopAmount("Costo de un env\xEDo entregado en COP. Omite para usar la referencia editable de Colombia: 19000."),
|
|
2070
|
+
returnRatePercent: optionalPercent("Porcentaje de pedidos devueltos. Ejemplo: 25 significa 25%. Omite para usar la referencia editable de Colombia: 25."),
|
|
2071
|
+
cancellationRatePercent: optionalPercent("Porcentaje de pedidos cancelados antes de entrega. Ejemplo: 15 significa 15%. Omite para usar la referencia editable de Colombia: 15."),
|
|
2072
|
+
adsManagerCpaCop: optionalCopAmount("Costo por compra mostrado en Ads Manager, en COP. Omite para usar la referencia editable de Colombia: 15000."),
|
|
2073
|
+
desiredMarginPercent: optionalPercent("Margen de ganancia deseado. Ejemplo: 10 significa 10%. Omite para usar la referencia editable de Colombia: 10.")
|
|
2074
|
+
});
|
|
2075
|
+
function registerProductCostingTools(server) {
|
|
2076
|
+
server.tool("cost_product", "Calcula GRATIS y sin cr\xE9ditos cu\xE1nto cobrar por un producto de dropshipping en Colombia (COP). Es READ-ONLY: no crea tareas ni publica nada. Pide al usuario \xFAnicamente el costo real del proveedor; si no conoce env\xEDo, devoluciones, cancelaciones, CPA o margen, om\xEDtelos y se usar\xE1n valores gu\xEDa editables de Colombia. Devuelve `price` y `compareAtPrice` listos para `create_product_task`; despu\xE9s puedes generar la tarea y publicarla con `publish_to_shopify`, `publish_to_meta` o `publish_to_tiktok`. No inventes un costo de proveedor.", ProductCostingToolInput.shape, async (input) => {
|
|
2077
|
+
const normalized = normalizeToolInput(input);
|
|
2078
|
+
const parsed = ProductCostingInputSchema.safeParse(normalized.input);
|
|
2079
|
+
if (!parsed.success) {
|
|
2080
|
+
return {
|
|
2081
|
+
isError: true,
|
|
2082
|
+
content: [
|
|
2083
|
+
{
|
|
2084
|
+
type: "text",
|
|
2085
|
+
text: "No puedo calcular con esos porcentajes: devoluciones + cancelaciones deben sumar menos de 100%. Revisa los valores e int\xE9ntalo de nuevo."
|
|
2086
|
+
}
|
|
2087
|
+
]
|
|
2088
|
+
};
|
|
2089
|
+
}
|
|
2090
|
+
return renderProductCosting(parsed.data, calculateProductCosting(parsed.data), normalized.usedReferenceValues);
|
|
2091
|
+
});
|
|
2092
|
+
}
|
|
2093
|
+
__name(registerProductCostingTools, "registerProductCostingTools");
|
|
2094
|
+
function normalizeToolInput(input) {
|
|
2095
|
+
const optionalValues = [
|
|
2096
|
+
input.shippingCostCop,
|
|
2097
|
+
input.returnRatePercent,
|
|
2098
|
+
input.cancellationRatePercent,
|
|
2099
|
+
input.adsManagerCpaCop,
|
|
2100
|
+
input.desiredMarginPercent
|
|
2101
|
+
];
|
|
2102
|
+
return {
|
|
2103
|
+
input: {
|
|
2104
|
+
supplierCostCop: input.supplierCostCop,
|
|
2105
|
+
shippingCostCop: input.shippingCostCop ?? PRODUCT_COSTING_DEFAULTS.shippingCostCop,
|
|
2106
|
+
returnRate: (input.returnRatePercent ?? PRODUCT_COSTING_DEFAULTS.returnRate * 100) / 100,
|
|
2107
|
+
cancellationRate: (input.cancellationRatePercent ?? PRODUCT_COSTING_DEFAULTS.cancellationRate * 100) / 100,
|
|
2108
|
+
adsManagerCpaCop: input.adsManagerCpaCop ?? PRODUCT_COSTING_DEFAULTS.adsManagerCpaCop,
|
|
2109
|
+
desiredMargin: (input.desiredMarginPercent ?? PRODUCT_COSTING_DEFAULTS.desiredMargin * 100) / 100
|
|
2110
|
+
},
|
|
2111
|
+
usedReferenceValues: optionalValues.some((value) => value === void 0)
|
|
2112
|
+
};
|
|
2113
|
+
}
|
|
2114
|
+
__name(normalizeToolInput, "normalizeToolInput");
|
|
2115
|
+
function renderProductCosting(input, result, usedReferenceValues) {
|
|
2116
|
+
const price = formatCop(result.commercialPriceCop);
|
|
2117
|
+
const compareAtPrice = formatCop(result.comparisonPriceCop);
|
|
2118
|
+
const lines = [
|
|
2119
|
+
"\u2705 **Costeo del producto \xB7 Colombia**",
|
|
2120
|
+
"",
|
|
2121
|
+
`Precio recomendado: **${price}**`,
|
|
2122
|
+
`Precio comparado: ~~${compareAtPrice}~~`,
|
|
2123
|
+
`Ganancia estimada por venta entregada: **${formatCop(result.estimatedProfitCop)}**`,
|
|
2124
|
+
`Margen real estimado: **${formatPercent(result.actualMargin)}**`,
|
|
2125
|
+
`Costo total estimado: ${formatCop(result.totalCostCop)}`,
|
|
2126
|
+
`M\xE1ximo sugerido en Ads Manager por compra: **${formatCop(result.breakEvenAdsManagerCpaCop)}**`
|
|
2127
|
+
];
|
|
2128
|
+
if (result.wasPriceAutoAdjusted) {
|
|
2129
|
+
lines.push("", `ProductMaker subi\xF3 autom\xE1ticamente el precio desde ${formatCop(result.baseCommercialPriceCop)} para proteger el margen y una ganancia gu\xEDa m\xEDnima de $10.000 COP.`);
|
|
2130
|
+
}
|
|
2131
|
+
lines.push("", "### Valores listos para crear y publicar", `- \`price\`: "${price}"`, `- \`compareAtPrice\`: "${compareAtPrice}"`, "", "Pasa esos dos valores a `create_product_task`; cuando la tarea termine, usa el tool de publicaci\xF3n que el usuario elija.");
|
|
2132
|
+
if (usedReferenceValues) {
|
|
2133
|
+
lines.push("", "_Se usaron valores gu\xEDa de Colombia para los campos omitidos. Son un punto de partida editable, no promedios oficiales._");
|
|
2134
|
+
}
|
|
2135
|
+
lines.push("", `_Este c\xE1lculo es read-only, no consume cr\xE9ditos y us\xF3 entrega estimada de ${formatPercent(result.deliveryRate)}._`, "", `Supuestos: proveedor ${formatCop(input.supplierCostCop)}, env\xEDo ${formatCop(input.shippingCostCop)}, devoluciones ${formatPercent(input.returnRate)}, cancelaciones ${formatPercent(input.cancellationRate)}, CPA ${formatCop(input.adsManagerCpaCop)}, margen deseado ${formatPercent(input.desiredMargin)}.`);
|
|
2136
|
+
return {
|
|
2137
|
+
content: [
|
|
2138
|
+
{
|
|
2139
|
+
type: "text",
|
|
2140
|
+
text: lines.join("\n")
|
|
2141
|
+
}
|
|
2142
|
+
]
|
|
2143
|
+
};
|
|
2144
|
+
}
|
|
2145
|
+
__name(renderProductCosting, "renderProductCosting");
|
|
2146
|
+
function formatCop(value) {
|
|
2147
|
+
return `$${Math.round(value).toLocaleString("es-CO")} COP`;
|
|
2148
|
+
}
|
|
2149
|
+
__name(formatCop, "formatCop");
|
|
2150
|
+
function formatPercent(value) {
|
|
2151
|
+
return `${(value * 100).toFixed(1).replace(/\.0$/, "")}%`;
|
|
2152
|
+
}
|
|
2153
|
+
__name(formatPercent, "formatPercent");
|
|
2154
|
+
|
|
1983
2155
|
// src/server.ts
|
|
1984
2156
|
function createServer(opts) {
|
|
1985
2157
|
const { apiKey, apiBaseUrl, proxyBaseUrl = null, transport = "http" } = opts;
|
|
@@ -1995,6 +2167,7 @@ function createServer(opts) {
|
|
|
1995
2167
|
}
|
|
1996
2168
|
});
|
|
1997
2169
|
const api = new ApiClient(apiBaseUrl, apiKey);
|
|
2170
|
+
registerProductCostingTools(server);
|
|
1998
2171
|
registerTaskTools(server, api, {
|
|
1999
2172
|
proxyBaseUrl,
|
|
2000
2173
|
transport
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@productmaker/mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.12.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"private": false,
|
|
6
|
-
"description": "Product Maker MCP server —
|
|
6
|
+
"description": "Product Maker MCP server — cost products, generate dropshipping landing pages, UGC videos, and ad creatives, and publish to Shopify and Meta Ads from Claude, ChatGPT, or Gemini.",
|
|
7
7
|
"keywords": [
|
|
8
8
|
"mcp",
|
|
9
9
|
"mcp-server",
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
"ai",
|
|
19
19
|
"productmaker",
|
|
20
20
|
"dropshipping",
|
|
21
|
+
"product-costing",
|
|
21
22
|
"ecommerce",
|
|
22
23
|
"shopify",
|
|
23
24
|
"meta-ads",
|
|
@@ -62,6 +63,7 @@
|
|
|
62
63
|
"tsx": "^4.16.0",
|
|
63
64
|
"typescript": "^7.0.2",
|
|
64
65
|
"vitest": "^2.1.9",
|
|
66
|
+
"@packages/product-economics": "0.1.0",
|
|
65
67
|
"@packages/types": "0.1.0"
|
|
66
68
|
},
|
|
67
69
|
"publishConfig": {
|