@yoryoboy/bi-mcp 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/README.md +126 -9
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/index.js +30 -0
  4. package/dist/index.js.map +2 -2
  5. package/dist/mcp-use.json +2 -2
  6. package/dist/scripts/_helpers.js +44 -0
  7. package/dist/scripts/_helpers.js.map +7 -0
  8. package/dist/scripts/admin-profile-delete.js +72 -0
  9. package/dist/scripts/admin-profile-delete.js.map +7 -0
  10. package/dist/scripts/admin-profile-list.js +24 -0
  11. package/dist/scripts/admin-profile-list.js.map +7 -0
  12. package/dist/scripts/admin-profile-upsert.js +25 -0
  13. package/dist/scripts/admin-profile-upsert.js.map +7 -0
  14. package/dist/scripts/admin-vtex-list.js +28 -0
  15. package/dist/scripts/admin-vtex-list.js.map +7 -0
  16. package/dist/scripts/admin-vtex-upsert.js +73 -0
  17. package/dist/scripts/admin-vtex-upsert.js.map +7 -0
  18. package/dist/scripts/admin-vtex-validate.js +55 -0
  19. package/dist/scripts/admin-vtex-validate.js.map +7 -0
  20. package/dist/scripts/run-migrations.js +50 -0
  21. package/dist/scripts/run-migrations.js.map +7 -0
  22. package/dist/scripts/test-db-connection.js +19 -0
  23. package/dist/scripts/test-db-connection.js.map +7 -0
  24. package/dist/src/config/profile-store.js +86 -0
  25. package/dist/src/config/profile-store.js.map +7 -0
  26. package/dist/src/config/vtex-crypto.js +43 -0
  27. package/dist/src/config/vtex-crypto.js.map +7 -0
  28. package/dist/src/config/vtex-profile-store.js +132 -0
  29. package/dist/src/config/vtex-profile-store.js.map +7 -0
  30. package/dist/src/config/vtex.js +27 -21
  31. package/dist/src/config/vtex.js.map +2 -2
  32. package/dist/src/db/client.js +58 -0
  33. package/dist/src/db/client.js.map +7 -0
  34. package/dist/src/services/vtex/vtex-api.js +24 -8
  35. package/dist/src/services/vtex/vtex-api.js.map +2 -2
  36. package/dist/src/services/vtex/vtex-catalog.js +5 -3
  37. package/dist/src/services/vtex/vtex-catalog.js.map +2 -2
  38. package/dist/src/services/vtex/vtex-logistics.js +18 -9
  39. package/dist/src/services/vtex/vtex-logistics.js.map +2 -2
  40. package/dist/src/services/vtex/vtex-orders.js +13 -7
  41. package/dist/src/services/vtex/vtex-orders.js.map +2 -2
  42. package/dist/src/services/vtex/vtex-pricing.js +5 -3
  43. package/dist/src/services/vtex/vtex-pricing.js.map +2 -2
  44. package/dist/src/tools/config/check-database-connection.js +59 -0
  45. package/dist/src/tools/config/check-database-connection.js.map +7 -0
  46. package/dist/src/tools/config/index.js +3 -0
  47. package/dist/src/tools/config/index.js.map +7 -0
  48. package/dist/src/tools/config/list-profiles.js +26 -0
  49. package/dist/src/tools/config/list-profiles.js.map +7 -0
  50. package/dist/src/tools/index.js +1 -0
  51. package/dist/src/tools/index.js.map +2 -2
  52. package/dist/src/tools/vtex/computed-price.js +12 -1
  53. package/dist/src/tools/vtex/computed-price.js.map +2 -2
  54. package/dist/src/tools/vtex/index.js +1 -0
  55. package/dist/src/tools/vtex/index.js.map +2 -2
  56. package/dist/src/tools/vtex/inventory-check.js +15 -2
  57. package/dist/src/tools/vtex/inventory-check.js.map +2 -2
  58. package/dist/src/tools/vtex/order-details.js +16 -2
  59. package/dist/src/tools/vtex/order-details.js.map +2 -2
  60. package/dist/src/tools/vtex/orders-summary.js +11 -1
  61. package/dist/src/tools/vtex/orders-summary.js.map +2 -2
  62. package/dist/src/tools/vtex/product-offers.js +15 -2
  63. package/dist/src/tools/vtex/product-offers.js.map +2 -2
  64. package/dist/src/tools/vtex/profile-resolution.js +57 -0
  65. package/dist/src/tools/vtex/profile-resolution.js.map +7 -0
  66. package/dist/src/tools/vtex/sku-offers.js +16 -2
  67. package/dist/src/tools/vtex/sku-offers.js.map +2 -2
  68. package/dist/src/tools/vtex/sku-price.js +12 -2
  69. package/dist/src/tools/vtex/sku-price.js.map +2 -2
  70. package/dist/src/tools/vtex/update-inventory.js +12 -1
  71. package/dist/src/tools/vtex/update-inventory.js.map +2 -2
  72. package/dist/src/tools/vtex/update-lead-time.js +12 -1
  73. package/dist/src/tools/vtex/update-lead-time.js.map +2 -2
  74. package/dist/src/tools/vtex/warehouse-inventory.js +12 -1
  75. package/dist/src/tools/vtex/warehouse-inventory.js.map +2 -2
  76. package/package.json +12 -2
@@ -8,4 +8,5 @@ export * from "./sku-price.js";
8
8
  export * from "./computed-price.js";
9
9
  export * from "./product-offers.js";
10
10
  export * from "./sku-offers.js";
11
+ export * from "./profile-resolution.js";
11
12
  //# sourceMappingURL=index.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/tools/vtex/index.ts"],
4
- "sourcesContent": ["export * from \"./orders-summary.js\";\nexport * from \"./order-details.js\";\nexport * from \"./inventory-check.js\";\nexport * from \"./warehouse-inventory.js\";\nexport * from \"./update-inventory.js\";\nexport * from \"./update-lead-time.js\";\nexport * from \"./sku-price.js\";\nexport * from \"./computed-price.js\";\nexport * from \"./product-offers.js\";\nexport * from \"./sku-offers.js\";\n"],
5
- "mappings": "AAAA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;",
4
+ "sourcesContent": ["export * from \"./orders-summary.js\";\nexport * from \"./order-details.js\";\nexport * from \"./inventory-check.js\";\nexport * from \"./warehouse-inventory.js\";\nexport * from \"./update-inventory.js\";\nexport * from \"./update-lead-time.js\";\nexport * from \"./sku-price.js\";\nexport * from \"./computed-price.js\";\nexport * from \"./product-offers.js\";\nexport * from \"./sku-offers.js\";\nexport * from \"./profile-resolution.js\";\n"],
5
+ "mappings": "AAAA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;",
6
6
  "names": []
7
7
  }
@@ -3,6 +3,7 @@ import { z } from "zod";
3
3
  import { formatVtexError } from "../../services/vtex/vtex-api.js";
4
4
  import { getInventoryBySkuBatch } from "../../services/vtex/vtex-logistics.js";
5
5
  import { stripNulls } from "../../utils/strip-payload.js";
6
+ import { resolveVtexProfileOrSelection } from "./profile-resolution.js";
6
7
  const MAX_SKU_IDS = 50;
7
8
  const MAX_CONCURRENT_REQUESTS = 10;
8
9
  const MAX_RETRIES_PER_SKU = 2;
@@ -36,12 +37,23 @@ function formatCompactUtcDate(dateTime) {
36
37
  return `${match[1]} ${match[2]}`;
37
38
  }
38
39
  const inventoryCheckSchema = z.object({
40
+ profileId: z.string().trim().min(1).optional().describe(
41
+ "Explicit VTEX profile id to use. If omitted, the tool returns a guided selection payload with available active profiles."
42
+ ),
39
43
  skuIds: z.array(z.string().trim().min(1).describe("SKU identifier")).min(1).max(MAX_SKU_IDS).describe("List of SKU identifiers to fetch (up to 50 IDs)")
40
44
  });
41
- async function inventoryCheckHandler({ skuIds }) {
45
+ async function inventoryCheckHandler({
46
+ profileId,
47
+ skuIds
48
+ }) {
42
49
  try {
50
+ const profileResolution = await resolveVtexProfileOrSelection(profileId);
51
+ if (!profileResolution.ok) {
52
+ return profileResolution.response;
53
+ }
54
+ const resolvedProfileId = profileResolution.value.profileId;
43
55
  const uniqueSkuIds = Array.from(new Set(skuIds));
44
- const batchResult = await getInventoryBySkuBatch(uniqueSkuIds, {
56
+ const batchResult = await getInventoryBySkuBatch(resolvedProfileId, uniqueSkuIds, {
45
57
  maxConcurrency: MAX_CONCURRENT_REQUESTS,
46
58
  maxRetries: MAX_RETRIES_PER_SKU
47
59
  });
@@ -116,6 +128,7 @@ async function inventoryCheckHandler({ skuIds }) {
116
128
  return object(
117
129
  stripNulls({
118
130
  metadata: {
131
+ profile_id: resolvedProfileId,
119
132
  requested_ids: skuIds.length,
120
133
  unique_ids: uniqueSkuIds.length,
121
134
  max_parallel_requests: MAX_CONCURRENT_REQUESTS,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/tools/vtex/inventory-check.ts"],
4
- "sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\n\nimport { formatVtexError } from \"../../services/vtex/vtex-api.js\";\nimport { getInventoryBySkuBatch } from \"../../services/vtex/vtex-logistics.js\";\nimport { stripNulls } from \"../../utils/strip-payload.js\";\n\ntype HealthStatus = \"HEALTHY\" | \"LOW_STOCK\" | \"CRITICAL_LOW_STOCK\" | \"OUT_OF_STOCK\";\ntype SkuInventoryRow = [string, number, HealthStatus];\ntype WarehouseBalanceBaseRow = [string, number, number, boolean];\ntype WarehouseBalanceWithRefillRow = [...WarehouseBalanceBaseRow, string];\ntype WarehouseBalanceWithDateRow = [...WarehouseBalanceBaseRow, string];\ntype WarehouseBalanceFullRow = [...WarehouseBalanceBaseRow, string, string];\ntype WarehouseBalanceRow =\n | WarehouseBalanceBaseRow\n | WarehouseBalanceWithRefillRow\n | WarehouseBalanceWithDateRow\n | WarehouseBalanceFullRow;\n\nconst MAX_SKU_IDS = 50;\nconst MAX_CONCURRENT_REQUESTS = 10;\nconst MAX_RETRIES_PER_SKU = 2;\n\nfunction inferHealthStatus(globalAvailableQuantity: number, hasUnlimitedQuantity: boolean): HealthStatus {\n if (hasUnlimitedQuantity) {\n return \"HEALTHY\";\n }\n\n if (globalAvailableQuantity <= 0) {\n return \"OUT_OF_STOCK\";\n }\n\n if (globalAvailableQuantity < 5) {\n return \"CRITICAL_LOW_STOCK\";\n }\n\n if (globalAvailableQuantity < 20) {\n return \"LOW_STOCK\";\n }\n\n return \"HEALTHY\";\n}\n\nfunction toNumber(value: unknown): number {\n const parsedValue = Number(value);\n return Number.isFinite(parsedValue) ? parsedValue : 0;\n}\n\nfunction formatCompactUtcDate(dateTime?: string): string {\n if (!dateTime) {\n return \"\";\n }\n\n const match = dateTime.match(/^(\\d{4}-\\d{2}-\\d{2})T(\\d{2}:\\d{2})/);\n if (!match) {\n return dateTime;\n }\n\n return `${match[1]} ${match[2]}`;\n}\n\nexport const inventoryCheckSchema = z.object({\n skuIds: z\n .array(z.string().trim().min(1).describe(\"SKU identifier\"))\n .min(1)\n .max(MAX_SKU_IDS)\n .describe(\"List of SKU identifiers to fetch (up to 50 IDs)\"),\n});\n\nexport async function inventoryCheckHandler({ skuIds }: z.infer<typeof inventoryCheckSchema>) {\n try {\n const uniqueSkuIds = Array.from(new Set(skuIds));\n const batchResult = await getInventoryBySkuBatch(uniqueSkuIds, {\n maxConcurrency: MAX_CONCURRENT_REQUESTS,\n maxRetries: MAX_RETRIES_PER_SKU,\n });\n\n const hasAnyTimeToRefill = batchResult.successful.some(({ document }) =>\n (Array.isArray(document.balance) ? document.balance : []).some(\n (balance) => typeof balance.timeToRefill === \"string\" && balance.timeToRefill.trim().length > 0\n )\n );\n const hasAnyDateOfSupplyUtc = batchResult.successful.some(({ document }) =>\n (Array.isArray(document.balance) ? document.balance : []).some(\n (balance) =>\n typeof balance.dateOfSupplyUtc === \"string\" && balance.dateOfSupplyUtc.trim().length > 0\n )\n );\n\n const warehouseBalanceSchema = [\"warehouseName\", \"totalQuantity\", \"reservedQuantity\", \"hasUnlimitedQuantity\"];\n if (hasAnyTimeToRefill) {\n warehouseBalanceSchema.push(\"timeToRefill\");\n }\n if (hasAnyDateOfSupplyUtc) {\n warehouseBalanceSchema.push(\"dateOfSupplyUtc\");\n }\n\n const inventory = batchResult.successful.map(({ skuId, document }) => {\n const balances = Array.isArray(document.balance) ? document.balance : [];\n const warehouses: WarehouseBalanceRow[] = balances.map((balance) => {\n const totalQuantity = toNumber(balance.totalQuantity);\n const reservedQuantity = toNumber(balance.reservedQuantity);\n const availableQuantityRaw = balance.availableQuantity;\n const availableQuantity =\n availableQuantityRaw === undefined\n ? Math.max(0, totalQuantity - reservedQuantity)\n : toNumber(availableQuantityRaw);\n const hasUnlimitedQuantity = Boolean(\n balance.hasUnlimitedQuantity ?? balance.isUnlimited ?? false\n );\n\n const warehouseBase: WarehouseBalanceBaseRow = [\n balance.warehouseName ?? balance.warehouseId ?? \"unknown\",\n totalQuantity,\n reservedQuantity,\n hasUnlimitedQuantity,\n ];\n\n if (hasAnyTimeToRefill && hasAnyDateOfSupplyUtc) {\n return [\n ...warehouseBase,\n balance.timeToRefill ?? \"\",\n formatCompactUtcDate(balance.dateOfSupplyUtc),\n ];\n }\n\n if (hasAnyTimeToRefill) {\n return [...warehouseBase, balance.timeToRefill ?? \"\"];\n }\n\n if (hasAnyDateOfSupplyUtc) {\n return [...warehouseBase, formatCompactUtcDate(balance.dateOfSupplyUtc)];\n }\n\n return warehouseBase;\n });\n\n const globalAvailableQuantity = balances.reduce((accumulator, balance) => {\n const totalQuantity = toNumber(balance.totalQuantity);\n const reservedQuantity = toNumber(balance.reservedQuantity);\n const availableQuantityRaw = balance.availableQuantity;\n const availableQuantity =\n availableQuantityRaw === undefined\n ? Math.max(0, totalQuantity - reservedQuantity)\n : toNumber(availableQuantityRaw);\n return accumulator + availableQuantity;\n }, 0);\n const hasUnlimitedQuantity = balances.some((balance) =>\n Boolean(balance.hasUnlimitedQuantity ?? balance.isUnlimited ?? false)\n );\n const skuRow: SkuInventoryRow = [\n document.skuId ?? skuId,\n globalAvailableQuantity,\n inferHealthStatus(globalAvailableQuantity, hasUnlimitedQuantity),\n ];\n\n return {\n sku: skuRow,\n warehouses,\n };\n });\n\n return object(\n stripNulls({\n metadata: {\n requested_ids: skuIds.length,\n unique_ids: uniqueSkuIds.length,\n max_parallel_requests: MAX_CONCURRENT_REQUESTS,\n successful_items: batchResult.successful.length,\n failed_items: batchResult.failed.length,\n has_failures: batchResult.failed.length > 0,\n },\n inventory_schema: {\n sku: [\"sku_id\", \"global_available_quantity\", \"health_status\"],\n warehouse_balance: warehouseBalanceSchema,\n },\n inventory,\n failures: batchResult.failed.map((failure) => ({\n sku_id: failure.skuId,\n message: failure.message,\n status_code: failure.statusCode,\n attempts: failure.attempts,\n retryable: failure.retryable,\n })),\n })\n );\n } catch (err) {\n return error(formatVtexError(err, \"Failed to check inventory batch\"));\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\n\nimport { formatVtexError } from \"../../services/vtex/vtex-api.js\";\nimport { getInventoryBySkuBatch } from \"../../services/vtex/vtex-logistics.js\";\nimport { stripNulls } from \"../../utils/strip-payload.js\";\nimport { resolveVtexProfileOrSelection } from \"./profile-resolution.js\";\n\ntype HealthStatus = \"HEALTHY\" | \"LOW_STOCK\" | \"CRITICAL_LOW_STOCK\" | \"OUT_OF_STOCK\";\ntype SkuInventoryRow = [string, number, HealthStatus];\ntype WarehouseBalanceBaseRow = [string, number, number, boolean];\ntype WarehouseBalanceWithRefillRow = [...WarehouseBalanceBaseRow, string];\ntype WarehouseBalanceWithDateRow = [...WarehouseBalanceBaseRow, string];\ntype WarehouseBalanceFullRow = [...WarehouseBalanceBaseRow, string, string];\ntype WarehouseBalanceRow =\n | WarehouseBalanceBaseRow\n | WarehouseBalanceWithRefillRow\n | WarehouseBalanceWithDateRow\n | WarehouseBalanceFullRow;\n\nconst MAX_SKU_IDS = 50;\nconst MAX_CONCURRENT_REQUESTS = 10;\nconst MAX_RETRIES_PER_SKU = 2;\n\nfunction inferHealthStatus(globalAvailableQuantity: number, hasUnlimitedQuantity: boolean): HealthStatus {\n if (hasUnlimitedQuantity) {\n return \"HEALTHY\";\n }\n\n if (globalAvailableQuantity <= 0) {\n return \"OUT_OF_STOCK\";\n }\n\n if (globalAvailableQuantity < 5) {\n return \"CRITICAL_LOW_STOCK\";\n }\n\n if (globalAvailableQuantity < 20) {\n return \"LOW_STOCK\";\n }\n\n return \"HEALTHY\";\n}\n\nfunction toNumber(value: unknown): number {\n const parsedValue = Number(value);\n return Number.isFinite(parsedValue) ? parsedValue : 0;\n}\n\nfunction formatCompactUtcDate(dateTime?: string): string {\n if (!dateTime) {\n return \"\";\n }\n\n const match = dateTime.match(/^(\\d{4}-\\d{2}-\\d{2})T(\\d{2}:\\d{2})/);\n if (!match) {\n return dateTime;\n }\n\n return `${match[1]} ${match[2]}`;\n}\n\nexport const inventoryCheckSchema = z.object({\n profileId: z\n .string()\n .trim()\n .min(1)\n .optional()\n .describe(\n \"Explicit VTEX profile id to use. If omitted, the tool returns a guided selection payload with available active profiles.\"\n ),\n skuIds: z\n .array(z.string().trim().min(1).describe(\"SKU identifier\"))\n .min(1)\n .max(MAX_SKU_IDS)\n .describe(\"List of SKU identifiers to fetch (up to 50 IDs)\"),\n});\n\nexport async function inventoryCheckHandler({\n profileId,\n skuIds,\n}: z.infer<typeof inventoryCheckSchema>) {\n try {\n const profileResolution = await resolveVtexProfileOrSelection(profileId);\n if (!profileResolution.ok) {\n return profileResolution.response;\n }\n\n const resolvedProfileId = profileResolution.value.profileId;\n const uniqueSkuIds = Array.from(new Set(skuIds));\n const batchResult = await getInventoryBySkuBatch(resolvedProfileId, uniqueSkuIds, {\n maxConcurrency: MAX_CONCURRENT_REQUESTS,\n maxRetries: MAX_RETRIES_PER_SKU,\n });\n\n const hasAnyTimeToRefill = batchResult.successful.some(({ document }) =>\n (Array.isArray(document.balance) ? document.balance : []).some(\n (balance) => typeof balance.timeToRefill === \"string\" && balance.timeToRefill.trim().length > 0\n )\n );\n const hasAnyDateOfSupplyUtc = batchResult.successful.some(({ document }) =>\n (Array.isArray(document.balance) ? document.balance : []).some(\n (balance) =>\n typeof balance.dateOfSupplyUtc === \"string\" && balance.dateOfSupplyUtc.trim().length > 0\n )\n );\n\n const warehouseBalanceSchema = [\"warehouseName\", \"totalQuantity\", \"reservedQuantity\", \"hasUnlimitedQuantity\"];\n if (hasAnyTimeToRefill) {\n warehouseBalanceSchema.push(\"timeToRefill\");\n }\n if (hasAnyDateOfSupplyUtc) {\n warehouseBalanceSchema.push(\"dateOfSupplyUtc\");\n }\n\n const inventory = batchResult.successful.map(({ skuId, document }) => {\n const balances = Array.isArray(document.balance) ? document.balance : [];\n const warehouses: WarehouseBalanceRow[] = balances.map((balance) => {\n const totalQuantity = toNumber(balance.totalQuantity);\n const reservedQuantity = toNumber(balance.reservedQuantity);\n const availableQuantityRaw = balance.availableQuantity;\n const availableQuantity =\n availableQuantityRaw === undefined\n ? Math.max(0, totalQuantity - reservedQuantity)\n : toNumber(availableQuantityRaw);\n const hasUnlimitedQuantity = Boolean(\n balance.hasUnlimitedQuantity ?? balance.isUnlimited ?? false\n );\n\n const warehouseBase: WarehouseBalanceBaseRow = [\n balance.warehouseName ?? balance.warehouseId ?? \"unknown\",\n totalQuantity,\n reservedQuantity,\n hasUnlimitedQuantity,\n ];\n\n if (hasAnyTimeToRefill && hasAnyDateOfSupplyUtc) {\n return [\n ...warehouseBase,\n balance.timeToRefill ?? \"\",\n formatCompactUtcDate(balance.dateOfSupplyUtc),\n ];\n }\n\n if (hasAnyTimeToRefill) {\n return [...warehouseBase, balance.timeToRefill ?? \"\"];\n }\n\n if (hasAnyDateOfSupplyUtc) {\n return [...warehouseBase, formatCompactUtcDate(balance.dateOfSupplyUtc)];\n }\n\n return warehouseBase;\n });\n\n const globalAvailableQuantity = balances.reduce((accumulator, balance) => {\n const totalQuantity = toNumber(balance.totalQuantity);\n const reservedQuantity = toNumber(balance.reservedQuantity);\n const availableQuantityRaw = balance.availableQuantity;\n const availableQuantity =\n availableQuantityRaw === undefined\n ? Math.max(0, totalQuantity - reservedQuantity)\n : toNumber(availableQuantityRaw);\n return accumulator + availableQuantity;\n }, 0);\n const hasUnlimitedQuantity = balances.some((balance) =>\n Boolean(balance.hasUnlimitedQuantity ?? balance.isUnlimited ?? false)\n );\n const skuRow: SkuInventoryRow = [\n document.skuId ?? skuId,\n globalAvailableQuantity,\n inferHealthStatus(globalAvailableQuantity, hasUnlimitedQuantity),\n ];\n\n return {\n sku: skuRow,\n warehouses,\n };\n });\n\n return object(\n stripNulls({\n metadata: {\n profile_id: resolvedProfileId,\n requested_ids: skuIds.length,\n unique_ids: uniqueSkuIds.length,\n max_parallel_requests: MAX_CONCURRENT_REQUESTS,\n successful_items: batchResult.successful.length,\n failed_items: batchResult.failed.length,\n has_failures: batchResult.failed.length > 0,\n },\n inventory_schema: {\n sku: [\"sku_id\", \"global_available_quantity\", \"health_status\"],\n warehouse_balance: warehouseBalanceSchema,\n },\n inventory,\n failures: batchResult.failed.map((failure) => ({\n sku_id: failure.skuId,\n message: failure.message,\n status_code: failure.statusCode,\n attempts: failure.attempts,\n retryable: failure.retryable,\n })),\n })\n );\n } catch (err) {\n return error(formatVtexError(err, \"Failed to check inventory batch\"));\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["hasUnlimitedQuantity"]
7
7
  }
@@ -4,17 +4,30 @@ import { getOrderDocumentsBatch } from "../../services/vtex/vtex-orders.js";
4
4
  import { formatVtexError } from "../../services/vtex/vtex-api.js";
5
5
  import { formatOrderDetails } from "../../utils/format-order-details.js";
6
6
  import { stripNulls } from "../../utils/strip-payload.js";
7
+ import { resolveVtexProfileOrSelection } from "./profile-resolution.js";
7
8
  const MAX_ORDER_IDS = 50;
8
9
  const MAX_CONCURRENT_REQUESTS = 10;
9
10
  const MAX_RETRIES_PER_ORDER = 2;
10
11
  const orderDetailsSchema = z.object({
12
+ profileId: z.string().trim().min(1).optional().describe(
13
+ "Explicit VTEX profile id to use. If omitted, the tool returns a guided selection payload with available active profiles."
14
+ ),
11
15
  orderIds: z.array(z.string().trim().min(3).describe("VTEX order identifier")).min(1).max(MAX_ORDER_IDS).describe("List of VTEX order identifiers to fetch (up to 50 IDs)"),
12
16
  reason: z.string().trim().min(1).optional().describe("Optional reason for requesting unmasked PII data when required")
13
17
  });
14
- async function orderDetailsHandler({ orderIds, reason }) {
18
+ async function orderDetailsHandler({
19
+ profileId,
20
+ orderIds,
21
+ reason
22
+ }) {
15
23
  try {
24
+ const profileResolution = await resolveVtexProfileOrSelection(profileId);
25
+ if (!profileResolution.ok) {
26
+ return profileResolution.response;
27
+ }
28
+ const resolvedProfileId = profileResolution.value.profileId;
16
29
  const uniqueOrderIds = Array.from(new Set(orderIds));
17
- const batchResult = await getOrderDocumentsBatch(uniqueOrderIds, {
30
+ const batchResult = await getOrderDocumentsBatch(resolvedProfileId, uniqueOrderIds, {
18
31
  reason,
19
32
  maxConcurrency: MAX_CONCURRENT_REQUESTS,
20
33
  maxRetries: MAX_RETRIES_PER_ORDER
@@ -23,6 +36,7 @@ async function orderDetailsHandler({ orderIds, reason }) {
23
36
  return object(
24
37
  stripNulls({
25
38
  metadata: {
39
+ profile_id: resolvedProfileId,
26
40
  requested: uniqueOrderIds.length,
27
41
  successful: batchResult.successful.length,
28
42
  failed: batchResult.failed.length
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/tools/vtex/order-details.ts"],
4
- "sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\n\nimport { getOrderDocumentsBatch } from \"../../services/vtex/vtex-orders.js\";\nimport { formatVtexError } from \"../../services/vtex/vtex-api.js\";\nimport { formatOrderDetails } from \"../../utils/format-order-details.js\";\nimport { stripNulls } from \"../../utils/strip-payload.js\";\n\nconst MAX_ORDER_IDS = 50;\nconst MAX_CONCURRENT_REQUESTS = 10;\nconst MAX_RETRIES_PER_ORDER = 2;\n\nexport const orderDetailsSchema = z.object({\n orderIds: z\n .array(z.string().trim().min(3).describe(\"VTEX order identifier\"))\n .min(1)\n .max(MAX_ORDER_IDS)\n .describe(\"List of VTEX order identifiers to fetch (up to 50 IDs)\"),\n reason: z\n .string()\n .trim()\n .min(1)\n .optional()\n .describe(\"Optional reason for requesting unmasked PII data when required\"),\n});\n\nexport async function orderDetailsHandler({ orderIds, reason }: z.infer<typeof orderDetailsSchema>) {\n try {\n const uniqueOrderIds = Array.from(new Set(orderIds));\n const batchResult = await getOrderDocumentsBatch(uniqueOrderIds, {\n reason,\n maxConcurrency: MAX_CONCURRENT_REQUESTS,\n maxRetries: MAX_RETRIES_PER_ORDER,\n });\n \n const formattedOrders = batchResult.successful.map(({ document }) => formatOrderDetails(document));\n\n return object(\n stripNulls({\n metadata: {\n requested: uniqueOrderIds.length,\n successful: batchResult.successful.length,\n failed: batchResult.failed.length,\n },\n schemas: {\n item: [\"id\", \"ref\", \"name\", \"qty\", \"price\", \"list\"],\n shipping: [\"carrier\", \"estimate\", \"delivery_date\"],\n payment: [\"system\", \"installments\", \"value\"],\n payment_validation: {\n payments_total: \"Sum of all payment values\",\n payment_delta: \"Difference between payments_total and order total\",\n payment_mismatch: \"True if |payment_delta| > 0.5 (potential issue)\",\n },\n },\n orders: formattedOrders,\n failures: batchResult.failed.map((failure) => ({\n order_id: failure.orderId,\n message: failure.message,\n status_code: failure.statusCode,\n })),\n })\n );\n } catch (err) {\n return error(formatVtexError(err, \"Failed to fetch order details batch\"));\n }\n}\n"],
5
- "mappings": "AAAA,SAAS,OAAO,cAAc;AAC9B,SAAS,SAAS;AAElB,SAAS,8BAA8B;AACvC,SAAS,uBAAuB;AAChC,SAAS,0BAA0B;AACnC,SAAS,kBAAkB;AAE3B,MAAM,gBAAgB;AACtB,MAAM,0BAA0B;AAChC,MAAM,wBAAwB;AAEvB,MAAM,qBAAqB,EAAE,OAAO;AAAA,EACzC,UAAU,EACP,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,SAAS,uBAAuB,CAAC,EAChE,IAAI,CAAC,EACL,IAAI,aAAa,EACjB,SAAS,wDAAwD;AAAA,EACpE,QAAQ,EACL,OAAO,EACP,KAAK,EACL,IAAI,CAAC,EACL,SAAS,EACT,SAAS,gEAAgE;AAC9E,CAAC;AAED,eAAsB,oBAAoB,EAAE,UAAU,OAAO,GAAuC;AAClG,MAAI;AACF,UAAM,iBAAiB,MAAM,KAAK,IAAI,IAAI,QAAQ,CAAC;AACnD,UAAM,cAAc,MAAM,uBAAuB,gBAAgB;AAAA,MAC/D;AAAA,MACA,gBAAgB;AAAA,MAChB,YAAY;AAAA,IACd,CAAC;AAED,UAAM,kBAAkB,YAAY,WAAW,IAAI,CAAC,EAAE,SAAS,MAAM,mBAAmB,QAAQ,CAAC;AAEjG,WAAO;AAAA,MACL,WAAW;AAAA,QACT,UAAU;AAAA,UACR,WAAW,eAAe;AAAA,UAC1B,YAAY,YAAY,WAAW;AAAA,UACnC,QAAQ,YAAY,OAAO;AAAA,QAC7B;AAAA,QACA,SAAS;AAAA,UACP,MAAM,CAAC,MAAM,OAAO,QAAQ,OAAO,SAAS,MAAM;AAAA,UAClD,UAAU,CAAC,WAAW,YAAY,eAAe;AAAA,UACjD,SAAS,CAAC,UAAU,gBAAgB,OAAO;AAAA,UAC3C,oBAAoB;AAAA,YAClB,gBAAgB;AAAA,YAChB,eAAe;AAAA,YACf,kBAAkB;AAAA,UACpB;AAAA,QACF;AAAA,QACA,QAAQ;AAAA,QACR,UAAU,YAAY,OAAO,IAAI,CAAC,aAAa;AAAA,UAC7C,UAAU,QAAQ;AAAA,UAClB,SAAS,QAAQ;AAAA,UACjB,aAAa,QAAQ;AAAA,QACvB,EAAE;AAAA,MACJ,CAAC;AAAA,IACH;AAAA,EACF,SAAS,KAAK;AACZ,WAAO,MAAM,gBAAgB,KAAK,qCAAqC,CAAC;AAAA,EAC1E;AACF;",
4
+ "sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\n\nimport { getOrderDocumentsBatch } from \"../../services/vtex/vtex-orders.js\";\nimport { formatVtexError } from \"../../services/vtex/vtex-api.js\";\nimport { formatOrderDetails } from \"../../utils/format-order-details.js\";\nimport { stripNulls } from \"../../utils/strip-payload.js\";\nimport { resolveVtexProfileOrSelection } from \"./profile-resolution.js\";\n\nconst MAX_ORDER_IDS = 50;\nconst MAX_CONCURRENT_REQUESTS = 10;\nconst MAX_RETRIES_PER_ORDER = 2;\n\nexport const orderDetailsSchema = z.object({\n profileId: z\n .string()\n .trim()\n .min(1)\n .optional()\n .describe(\n \"Explicit VTEX profile id to use. If omitted, the tool returns a guided selection payload with available active profiles.\"\n ),\n orderIds: z\n .array(z.string().trim().min(3).describe(\"VTEX order identifier\"))\n .min(1)\n .max(MAX_ORDER_IDS)\n .describe(\"List of VTEX order identifiers to fetch (up to 50 IDs)\"),\n reason: z\n .string()\n .trim()\n .min(1)\n .optional()\n .describe(\"Optional reason for requesting unmasked PII data when required\"),\n});\n\nexport async function orderDetailsHandler({\n profileId,\n orderIds,\n reason,\n}: z.infer<typeof orderDetailsSchema>) {\n try {\n const profileResolution = await resolveVtexProfileOrSelection(profileId);\n if (!profileResolution.ok) {\n return profileResolution.response;\n }\n\n const resolvedProfileId = profileResolution.value.profileId;\n const uniqueOrderIds = Array.from(new Set(orderIds));\n const batchResult = await getOrderDocumentsBatch(resolvedProfileId, uniqueOrderIds, {\n reason,\n maxConcurrency: MAX_CONCURRENT_REQUESTS,\n maxRetries: MAX_RETRIES_PER_ORDER,\n });\n \n const formattedOrders = batchResult.successful.map(({ document }) => formatOrderDetails(document));\n\n return object(\n stripNulls({\n metadata: {\n profile_id: resolvedProfileId,\n requested: uniqueOrderIds.length,\n successful: batchResult.successful.length,\n failed: batchResult.failed.length,\n },\n schemas: {\n item: [\"id\", \"ref\", \"name\", \"qty\", \"price\", \"list\"],\n shipping: [\"carrier\", \"estimate\", \"delivery_date\"],\n payment: [\"system\", \"installments\", \"value\"],\n payment_validation: {\n payments_total: \"Sum of all payment values\",\n payment_delta: \"Difference between payments_total and order total\",\n payment_mismatch: \"True if |payment_delta| > 0.5 (potential issue)\",\n },\n },\n orders: formattedOrders,\n failures: batchResult.failed.map((failure) => ({\n order_id: failure.orderId,\n message: failure.message,\n status_code: failure.statusCode,\n })),\n })\n );\n } catch (err) {\n return error(formatVtexError(err, \"Failed to fetch order details batch\"));\n }\n}\n"],
5
+ "mappings": "AAAA,SAAS,OAAO,cAAc;AAC9B,SAAS,SAAS;AAElB,SAAS,8BAA8B;AACvC,SAAS,uBAAuB;AAChC,SAAS,0BAA0B;AACnC,SAAS,kBAAkB;AAC3B,SAAS,qCAAqC;AAE9C,MAAM,gBAAgB;AACtB,MAAM,0BAA0B;AAChC,MAAM,wBAAwB;AAEvB,MAAM,qBAAqB,EAAE,OAAO;AAAA,EACzC,WAAW,EACR,OAAO,EACP,KAAK,EACL,IAAI,CAAC,EACL,SAAS,EACT;AAAA,IACC;AAAA,EACF;AAAA,EACF,UAAU,EACP,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,SAAS,uBAAuB,CAAC,EAChE,IAAI,CAAC,EACL,IAAI,aAAa,EACjB,SAAS,wDAAwD;AAAA,EACpE,QAAQ,EACL,OAAO,EACP,KAAK,EACL,IAAI,CAAC,EACL,SAAS,EACT,SAAS,gEAAgE;AAC9E,CAAC;AAED,eAAsB,oBAAoB;AAAA,EACxC;AAAA,EACA;AAAA,EACA;AACF,GAAuC;AACrC,MAAI;AACF,UAAM,oBAAoB,MAAM,8BAA8B,SAAS;AACvE,QAAI,CAAC,kBAAkB,IAAI;AACzB,aAAO,kBAAkB;AAAA,IAC3B;AAEA,UAAM,oBAAoB,kBAAkB,MAAM;AAClD,UAAM,iBAAiB,MAAM,KAAK,IAAI,IAAI,QAAQ,CAAC;AACnD,UAAM,cAAc,MAAM,uBAAuB,mBAAmB,gBAAgB;AAAA,MAClF;AAAA,MACA,gBAAgB;AAAA,MAChB,YAAY;AAAA,IACd,CAAC;AAED,UAAM,kBAAkB,YAAY,WAAW,IAAI,CAAC,EAAE,SAAS,MAAM,mBAAmB,QAAQ,CAAC;AAEjG,WAAO;AAAA,MACL,WAAW;AAAA,QACT,UAAU;AAAA,UACR,YAAY;AAAA,UACZ,WAAW,eAAe;AAAA,UAC1B,YAAY,YAAY,WAAW;AAAA,UACnC,QAAQ,YAAY,OAAO;AAAA,QAC7B;AAAA,QACA,SAAS;AAAA,UACP,MAAM,CAAC,MAAM,OAAO,QAAQ,OAAO,SAAS,MAAM;AAAA,UAClD,UAAU,CAAC,WAAW,YAAY,eAAe;AAAA,UACjD,SAAS,CAAC,UAAU,gBAAgB,OAAO;AAAA,UAC3C,oBAAoB;AAAA,YAClB,gBAAgB;AAAA,YAChB,eAAe;AAAA,YACf,kBAAkB;AAAA,UACpB;AAAA,QACF;AAAA,QACA,QAAQ;AAAA,QACR,UAAU,YAAY,OAAO,IAAI,CAAC,aAAa;AAAA,UAC7C,UAAU,QAAQ;AAAA,UAClB,SAAS,QAAQ;AAAA,UACjB,aAAa,QAAQ;AAAA,QACvB,EAAE;AAAA,MACJ,CAAC;AAAA,IACH;AAAA,EACF,SAAS,KAAK;AACZ,WAAO,MAAM,gBAAgB,KAAK,qCAAqC,CAAC;AAAA,EAC1E;AACF;",
6
6
  "names": []
7
7
  }
@@ -7,6 +7,7 @@ import { moneyFromCents } from "../../utils/money.js";
7
7
  import { normalizeOrderStatus } from "../../utils/order-status.js";
8
8
  import { createPaginationMetadata } from "../../utils/pagination.js";
9
9
  import { stripNulls } from "../../utils/strip-payload.js";
10
+ import { resolveVtexProfileOrSelection } from "./profile-resolution.js";
10
11
  const dateRegex = /^\d{4}-\d{2}-\d{2}$/;
11
12
  function buildDateFilter(startDate, endDate) {
12
13
  return `creationDate:[${startDate}T00:00:00.000Z TO ${endDate}T23:59:59.999Z]`;
@@ -26,6 +27,9 @@ const metricsSchema = {
26
27
  breakdown: ["count", "revenue"]
27
28
  };
28
29
  const ordersSummarySchema = z.object({
30
+ profileId: z.string().trim().min(1).optional().describe(
31
+ "Explicit VTEX profile id to use. If omitted, the tool returns a guided selection payload with available active profiles."
32
+ ),
29
33
  startDate: z.string().regex(dateRegex).describe("Start date in YYYY-MM-DD format"),
30
34
  endDate: z.string().regex(dateRegex).describe("End date in YYYY-MM-DD format"),
31
35
  page: z.number().int().min(1).max(30).optional().describe("Page number (1-30)"),
@@ -38,9 +42,14 @@ const ordersSummarySchema = z.object({
38
42
  });
39
43
  async function ordersSummaryHandler(params) {
40
44
  try {
45
+ const profileResolution = await resolveVtexProfileOrSelection(params.profileId);
46
+ if (!profileResolution.ok) {
47
+ return profileResolution.response;
48
+ }
49
+ const profileId = profileResolution.value.profileId;
41
50
  const page = params.page ?? 1;
42
51
  const perPage = params.perPage ?? 100;
43
- const ordersResponse = await listOrders({
52
+ const ordersResponse = await listOrders(profileId, {
44
53
  page,
45
54
  per_page: perPage,
46
55
  orderBy: params.orderBy,
@@ -66,6 +75,7 @@ async function ordersSummaryHandler(params) {
66
75
  return object(
67
76
  stripNulls({
68
77
  metadata,
78
+ profile_id: profileId,
69
79
  metrics_schema: metricsSchema,
70
80
  metrics,
71
81
  orders_schema: ordersSchema,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/tools/vtex/orders-summary.ts"],
4
- "sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\n\nimport { listOrders } from \"../../services/vtex/vtex-orders.js\";\nimport { formatVtexError } from \"../../services/vtex/vtex-api.js\";\nimport { buildCurrencyMetrics } from \"../../utils/currency.js\";\nimport { moneyFromCents } from \"../../utils/money.js\";\nimport { normalizeOrderStatus } from \"../../utils/order-status.js\";\nimport { createPaginationMetadata } from \"../../utils/pagination.js\";\nimport { stripNulls } from \"../../utils/strip-payload.js\";\n\nconst dateRegex = /^\\d{4}-\\d{2}-\\d{2}$/;\n\nfunction buildDateFilter(startDate: string, endDate: string): string {\n return `creationDate:[${startDate}T00:00:00.000Z TO ${endDate}T23:59:59.999Z]`;\n}\n\nfunction formatCompactDate(dateTime?: string): string {\n if (!dateTime) {\n return \"\";\n }\n\n const match = dateTime.match(/^(\\d{4}-\\d{2}-\\d{2})T(\\d{2}:\\d{2})/);\n if (!match) {\n return dateTime;\n }\n\n return `${match[1]} ${match[2]}`;\n}\n\nconst ordersSchema = [\"id\", \"date\", \"status\", \"value\", \"currency\", \"payment\", \"channel\", \"items\"] as const;\nconst metricsSchema = {\n breakdown: [\"count\", \"revenue\"] as const,\n};\n\nexport const ordersSummarySchema = z.object({\n startDate: z.string().regex(dateRegex).describe(\"Start date in YYYY-MM-DD format\"),\n endDate: z.string().regex(dateRegex).describe(\"End date in YYYY-MM-DD format\"),\n page: z.number().int().min(1).max(30).optional().describe(\"Page number (1-30)\"),\n perPage: z.number().int().min(1).max(100).optional().describe(\"Orders per page (1-100)\"),\n status: z.string().optional().describe(\"Optional VTEX status filter (f_status)\"),\n salesChannel: z.string().optional().describe(\"Optional sales channel filter (f_salesChannel)\"),\n paymentName: z.string().optional().describe(\"Optional payment filter (f_paymentNames)\"),\n utmSource: z.string().optional().describe(\"Optional UTM source filter (f_UtmSource)\"),\n orderBy: z\n .string()\n .optional()\n .describe(\"Sort order in VTEX format, e.g. creationDate,desc\"),\n});\n\nexport async function ordersSummaryHandler(params: z.infer<typeof ordersSummarySchema>) {\n try {\n const page = params.page ?? 1;\n const perPage = params.perPage ?? 100;\n\n const ordersResponse = await listOrders({\n page,\n per_page: perPage,\n orderBy: params.orderBy,\n f_creationDate: buildDateFilter(params.startDate, params.endDate),\n f_status: params.status,\n f_salesChannel: params.salesChannel,\n f_paymentNames: params.paymentName,\n f_UtmSource: params.utmSource,\n });\n\n const orders = Array.isArray(ordersResponse.list) ? ordersResponse.list : [];\n const metadata = createPaginationMetadata(ordersResponse.paging ?? {}, perPage, orders.length);\n const metrics = buildCurrencyMetrics(orders);\n const compactOrders = orders.map((order) => [\n order.orderId,\n formatCompactDate(order.creationDate),\n normalizeOrderStatus(order.status),\n moneyFromCents(order.totalValue),\n order.currencyCode ?? \"\",\n order.paymentNames ?? \"\",\n order.salesChannel ?? \"\",\n Number(order.totalItems ?? 0),\n ]);\n\n return object(\n stripNulls({\n metadata,\n metrics_schema: metricsSchema,\n metrics,\n orders_schema: ordersSchema,\n orders: compactOrders,\n })\n );\n } catch (err) {\n return error(formatVtexError(err, \"Failed to fetch orders summary\"));\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\n\nimport { listOrders } from \"../../services/vtex/vtex-orders.js\";\nimport { formatVtexError } from \"../../services/vtex/vtex-api.js\";\nimport { buildCurrencyMetrics } from \"../../utils/currency.js\";\nimport { moneyFromCents } from \"../../utils/money.js\";\nimport { normalizeOrderStatus } from \"../../utils/order-status.js\";\nimport { createPaginationMetadata } from \"../../utils/pagination.js\";\nimport { stripNulls } from \"../../utils/strip-payload.js\";\nimport { resolveVtexProfileOrSelection } from \"./profile-resolution.js\";\n\nconst dateRegex = /^\\d{4}-\\d{2}-\\d{2}$/;\n\nfunction buildDateFilter(startDate: string, endDate: string): string {\n return `creationDate:[${startDate}T00:00:00.000Z TO ${endDate}T23:59:59.999Z]`;\n}\n\nfunction formatCompactDate(dateTime?: string): string {\n if (!dateTime) {\n return \"\";\n }\n\n const match = dateTime.match(/^(\\d{4}-\\d{2}-\\d{2})T(\\d{2}:\\d{2})/);\n if (!match) {\n return dateTime;\n }\n\n return `${match[1]} ${match[2]}`;\n}\n\nconst ordersSchema = [\"id\", \"date\", \"status\", \"value\", \"currency\", \"payment\", \"channel\", \"items\"] as const;\nconst metricsSchema = {\n breakdown: [\"count\", \"revenue\"] as const,\n};\n\nexport const ordersSummarySchema = z.object({\n profileId: z\n .string()\n .trim()\n .min(1)\n .optional()\n .describe(\n \"Explicit VTEX profile id to use. If omitted, the tool returns a guided selection payload with available active profiles.\"\n ),\n startDate: z.string().regex(dateRegex).describe(\"Start date in YYYY-MM-DD format\"),\n endDate: z.string().regex(dateRegex).describe(\"End date in YYYY-MM-DD format\"),\n page: z.number().int().min(1).max(30).optional().describe(\"Page number (1-30)\"),\n perPage: z.number().int().min(1).max(100).optional().describe(\"Orders per page (1-100)\"),\n status: z.string().optional().describe(\"Optional VTEX status filter (f_status)\"),\n salesChannel: z.string().optional().describe(\"Optional sales channel filter (f_salesChannel)\"),\n paymentName: z.string().optional().describe(\"Optional payment filter (f_paymentNames)\"),\n utmSource: z.string().optional().describe(\"Optional UTM source filter (f_UtmSource)\"),\n orderBy: z\n .string()\n .optional()\n .describe(\"Sort order in VTEX format, e.g. creationDate,desc\"),\n});\n\nexport async function ordersSummaryHandler(params: z.infer<typeof ordersSummarySchema>) {\n try {\n const profileResolution = await resolveVtexProfileOrSelection(params.profileId);\n if (!profileResolution.ok) {\n return profileResolution.response;\n }\n\n const profileId = profileResolution.value.profileId;\n const page = params.page ?? 1;\n const perPage = params.perPage ?? 100;\n\n const ordersResponse = await listOrders(profileId, {\n page,\n per_page: perPage,\n orderBy: params.orderBy,\n f_creationDate: buildDateFilter(params.startDate, params.endDate),\n f_status: params.status,\n f_salesChannel: params.salesChannel,\n f_paymentNames: params.paymentName,\n f_UtmSource: params.utmSource,\n });\n\n const orders = Array.isArray(ordersResponse.list) ? ordersResponse.list : [];\n const metadata = createPaginationMetadata(ordersResponse.paging ?? {}, perPage, orders.length);\n const metrics = buildCurrencyMetrics(orders);\n const compactOrders = orders.map((order) => [\n order.orderId,\n formatCompactDate(order.creationDate),\n normalizeOrderStatus(order.status),\n moneyFromCents(order.totalValue),\n order.currencyCode ?? \"\",\n order.paymentNames ?? \"\",\n order.salesChannel ?? \"\",\n Number(order.totalItems ?? 0),\n ]);\n\n return object(\n stripNulls({\n metadata,\n profile_id: profileId,\n metrics_schema: metricsSchema,\n metrics,\n orders_schema: ordersSchema,\n orders: compactOrders,\n })\n );\n } catch (err) {\n return error(formatVtexError(err, \"Failed to fetch orders summary\"));\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -4,15 +4,28 @@ import { formatVtexError } from "../../services/vtex/vtex-api.js";
4
4
  import { getProductOffers } from "../../services/vtex/vtex-catalog.js";
5
5
  import { toSnakeCaseKeys } from "../../utils/case-conversion.js";
6
6
  import { stripNulls } from "../../utils/strip-payload.js";
7
+ import { resolveVtexProfileOrSelection } from "./profile-resolution.js";
7
8
  const productOffersSchema = z.object({
9
+ profileId: z.string().trim().min(1).optional().describe(
10
+ "Explicit VTEX profile id to use. If omitted, the tool returns a guided selection payload with available active profiles."
11
+ ),
8
12
  productId: z.string().min(1).describe("Product identifier")
9
13
  });
10
- async function productOffersHandler({ productId }) {
14
+ async function productOffersHandler({
15
+ profileId,
16
+ productId
17
+ }) {
11
18
  try {
12
- const offers = await getProductOffers(productId);
19
+ const profileResolution = await resolveVtexProfileOrSelection(profileId);
20
+ if (!profileResolution.ok) {
21
+ return profileResolution.response;
22
+ }
23
+ const resolvedProfileId = profileResolution.value.profileId;
24
+ const offers = await getProductOffers(resolvedProfileId, productId);
13
25
  const normalizedOffers = toSnakeCaseKeys(offers);
14
26
  return object(
15
27
  stripNulls({
28
+ profile_id: resolvedProfileId,
16
29
  product_id: productId,
17
30
  offers: normalizedOffers
18
31
  })
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/tools/vtex/product-offers.ts"],
4
- "sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\n\nimport { formatVtexError } from \"../../services/vtex/vtex-api.js\";\nimport { getProductOffers } from \"../../services/vtex/vtex-catalog.js\";\nimport { toSnakeCaseKeys } from \"../../utils/case-conversion.js\";\nimport { stripNulls } from \"../../utils/strip-payload.js\";\n\nexport const productOffersSchema = z.object({\n productId: z.string().min(1).describe(\"Product identifier\"),\n});\n\nexport async function productOffersHandler({ productId }: z.infer<typeof productOffersSchema>) {\n try {\n const offers = await getProductOffers(productId);\n const normalizedOffers = toSnakeCaseKeys(offers);\n\n return object(\n stripNulls({\n product_id: productId,\n offers: normalizedOffers,\n })\n );\n } catch (err) {\n return error(formatVtexError(err, `Failed to fetch product offers for ${productId}`));\n }\n}\n"],
5
- "mappings": "AAAA,SAAS,OAAO,cAAc;AAC9B,SAAS,SAAS;AAElB,SAAS,uBAAuB;AAChC,SAAS,wBAAwB;AACjC,SAAS,uBAAuB;AAChC,SAAS,kBAAkB;AAEpB,MAAM,sBAAsB,EAAE,OAAO;AAAA,EAC1C,WAAW,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS,oBAAoB;AAC5D,CAAC;AAED,eAAsB,qBAAqB,EAAE,UAAU,GAAwC;AAC7F,MAAI;AACF,UAAM,SAAS,MAAM,iBAAiB,SAAS;AAC/C,UAAM,mBAAmB,gBAAgB,MAAM;AAE/C,WAAO;AAAA,MACL,WAAW;AAAA,QACT,YAAY;AAAA,QACZ,QAAQ;AAAA,MACV,CAAC;AAAA,IACH;AAAA,EACF,SAAS,KAAK;AACZ,WAAO,MAAM,gBAAgB,KAAK,sCAAsC,SAAS,EAAE,CAAC;AAAA,EACtF;AACF;",
4
+ "sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\n\nimport { formatVtexError } from \"../../services/vtex/vtex-api.js\";\nimport { getProductOffers } from \"../../services/vtex/vtex-catalog.js\";\nimport { toSnakeCaseKeys } from \"../../utils/case-conversion.js\";\nimport { stripNulls } from \"../../utils/strip-payload.js\";\nimport { resolveVtexProfileOrSelection } from \"./profile-resolution.js\";\n\nexport const productOffersSchema = z.object({\n profileId: z\n .string()\n .trim()\n .min(1)\n .optional()\n .describe(\n \"Explicit VTEX profile id to use. If omitted, the tool returns a guided selection payload with available active profiles.\"\n ),\n productId: z.string().min(1).describe(\"Product identifier\"),\n});\n\nexport async function productOffersHandler({\n profileId,\n productId,\n}: z.infer<typeof productOffersSchema>) {\n try {\n const profileResolution = await resolveVtexProfileOrSelection(profileId);\n if (!profileResolution.ok) {\n return profileResolution.response;\n }\n\n const resolvedProfileId = profileResolution.value.profileId;\n const offers = await getProductOffers(resolvedProfileId, productId);\n const normalizedOffers = toSnakeCaseKeys(offers);\n\n return object(\n stripNulls({\n profile_id: resolvedProfileId,\n product_id: productId,\n offers: normalizedOffers,\n })\n );\n } catch (err) {\n return error(formatVtexError(err, `Failed to fetch product offers for ${productId}`));\n }\n}\n"],
5
+ "mappings": "AAAA,SAAS,OAAO,cAAc;AAC9B,SAAS,SAAS;AAElB,SAAS,uBAAuB;AAChC,SAAS,wBAAwB;AACjC,SAAS,uBAAuB;AAChC,SAAS,kBAAkB;AAC3B,SAAS,qCAAqC;AAEvC,MAAM,sBAAsB,EAAE,OAAO;AAAA,EAC1C,WAAW,EACR,OAAO,EACP,KAAK,EACL,IAAI,CAAC,EACL,SAAS,EACT;AAAA,IACC;AAAA,EACF;AAAA,EACF,WAAW,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS,oBAAoB;AAC5D,CAAC;AAED,eAAsB,qBAAqB;AAAA,EACzC;AAAA,EACA;AACF,GAAwC;AACtC,MAAI;AACF,UAAM,oBAAoB,MAAM,8BAA8B,SAAS;AACvE,QAAI,CAAC,kBAAkB,IAAI;AACzB,aAAO,kBAAkB;AAAA,IAC3B;AAEA,UAAM,oBAAoB,kBAAkB,MAAM;AAClD,UAAM,SAAS,MAAM,iBAAiB,mBAAmB,SAAS;AAClE,UAAM,mBAAmB,gBAAgB,MAAM;AAE/C,WAAO;AAAA,MACL,WAAW;AAAA,QACT,YAAY;AAAA,QACZ,YAAY;AAAA,QACZ,QAAQ;AAAA,MACV,CAAC;AAAA,IACH;AAAA,EACF,SAAS,KAAK;AACZ,WAAO,MAAM,gBAAgB,KAAK,sCAAsC,SAAS,EAAE,CAAC;AAAA,EACtF;AACF;",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,57 @@
1
+ import { object } from "mcp-use/server";
2
+ import { getProfile, listProfiles } from "../../config/profile-store.js";
3
+ function buildSelectionMessage(reason, profileId) {
4
+ switch (reason) {
5
+ case "missing_profile":
6
+ return "VTEX requiere seleccion explicita de profileId. Reenviar la misma tool con uno de los perfiles activos disponibles.";
7
+ case "profile_not_found":
8
+ return `El profileId "${profileId}" no existe. Reenviar la misma tool con uno de los perfiles activos disponibles.`;
9
+ case "profile_inactive":
10
+ return `El profileId "${profileId}" esta inactivo. Reenviar la misma tool con uno de los perfiles activos disponibles.`;
11
+ }
12
+ }
13
+ async function resolveVtexProfileOrSelection(profileId) {
14
+ const requestedProfileId = profileId?.trim();
15
+ if (!requestedProfileId) {
16
+ return {
17
+ ok: false,
18
+ response: await buildSelectionResponse("missing_profile")
19
+ };
20
+ }
21
+ const profile = await getProfile(requestedProfileId);
22
+ if (!profile) {
23
+ return {
24
+ ok: false,
25
+ response: await buildSelectionResponse("profile_not_found", requestedProfileId)
26
+ };
27
+ }
28
+ if (!profile.isActive) {
29
+ return {
30
+ ok: false,
31
+ response: await buildSelectionResponse("profile_inactive", requestedProfileId)
32
+ };
33
+ }
34
+ return {
35
+ ok: true,
36
+ value: {
37
+ profileId: profile.id
38
+ }
39
+ };
40
+ }
41
+ async function buildSelectionResponse(reason, profileId) {
42
+ const profiles = await listProfiles();
43
+ const availableProfiles = profiles.filter((profile) => profile.isActive).map((profile) => ({
44
+ profile_id: profile.id,
45
+ name: profile.name
46
+ }));
47
+ return object({
48
+ selection_required: true,
49
+ reason,
50
+ message: buildSelectionMessage(reason, profileId),
51
+ available_profiles: availableProfiles
52
+ });
53
+ }
54
+ export {
55
+ resolveVtexProfileOrSelection
56
+ };
57
+ //# sourceMappingURL=profile-resolution.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/tools/vtex/profile-resolution.ts"],
4
+ "sourcesContent": ["import { object } from \"mcp-use/server\";\n\nimport { getProfile, listProfiles } from \"../../config/profile-store.js\";\n\nexport type VtexProfileSelectionReason =\n | \"missing_profile\"\n | \"profile_not_found\"\n | \"profile_inactive\";\n\nexport interface ResolvedVtexProfile {\n profileId: string;\n}\n\ninterface VtexProfileSelectionPayload extends Record<string, unknown> {\n selection_required: boolean;\n reason: VtexProfileSelectionReason;\n message: string;\n available_profiles: Array<{\n profile_id: string;\n name: string;\n }>;\n}\n\nfunction buildSelectionMessage(reason: VtexProfileSelectionReason, profileId?: string): string {\n switch (reason) {\n case \"missing_profile\":\n return \"VTEX requiere seleccion explicita de profileId. Reenviar la misma tool con uno de los perfiles activos disponibles.\";\n case \"profile_not_found\":\n return `El profileId \"${profileId}\" no existe. Reenviar la misma tool con uno de los perfiles activos disponibles.`;\n case \"profile_inactive\":\n return `El profileId \"${profileId}\" esta inactivo. Reenviar la misma tool con uno de los perfiles activos disponibles.`;\n }\n}\n\nexport async function resolveVtexProfileOrSelection(\n profileId?: string\n): Promise<\n | { ok: true; value: ResolvedVtexProfile }\n | { ok: false; response: ReturnType<typeof object<Record<string, unknown>>> }\n> {\n const requestedProfileId = profileId?.trim();\n\n if (!requestedProfileId) {\n return {\n ok: false,\n response: await buildSelectionResponse(\"missing_profile\"),\n };\n }\n\n const profile = await getProfile(requestedProfileId);\n if (!profile) {\n return {\n ok: false,\n response: await buildSelectionResponse(\"profile_not_found\", requestedProfileId),\n };\n }\n\n if (!profile.isActive) {\n return {\n ok: false,\n response: await buildSelectionResponse(\"profile_inactive\", requestedProfileId),\n };\n }\n\n return {\n ok: true,\n value: {\n profileId: profile.id,\n },\n };\n}\n\nasync function buildSelectionResponse(\n reason: VtexProfileSelectionReason,\n profileId?: string\n) {\n const profiles = await listProfiles();\n const availableProfiles = profiles\n .filter((profile) => profile.isActive)\n .map((profile) => ({\n profile_id: profile.id,\n name: profile.name,\n }));\n\n return object({\n selection_required: true,\n reason,\n message: buildSelectionMessage(reason, profileId),\n available_profiles: availableProfiles,\n });\n}\n"],
5
+ "mappings": "AAAA,SAAS,cAAc;AAEvB,SAAS,YAAY,oBAAoB;AAqBzC,SAAS,sBAAsB,QAAoC,WAA4B;AAC7F,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO,iBAAiB,SAAS;AAAA,IACnC,KAAK;AACH,aAAO,iBAAiB,SAAS;AAAA,EACrC;AACF;AAEA,eAAsB,8BACpB,WAIA;AACA,QAAM,qBAAqB,WAAW,KAAK;AAE3C,MAAI,CAAC,oBAAoB;AACvB,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,UAAU,MAAM,uBAAuB,iBAAiB;AAAA,IAC1D;AAAA,EACF;AAEA,QAAM,UAAU,MAAM,WAAW,kBAAkB;AACnD,MAAI,CAAC,SAAS;AACZ,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,UAAU,MAAM,uBAAuB,qBAAqB,kBAAkB;AAAA,IAChF;AAAA,EACF;AAEA,MAAI,CAAC,QAAQ,UAAU;AACrB,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,UAAU,MAAM,uBAAuB,oBAAoB,kBAAkB;AAAA,IAC/E;AAAA,EACF;AAEA,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,OAAO;AAAA,MACL,WAAW,QAAQ;AAAA,IACrB;AAAA,EACF;AACF;AAEA,eAAe,uBACb,QACA,WACA;AACA,QAAM,WAAW,MAAM,aAAa;AACpC,QAAM,oBAAoB,SACvB,OAAO,CAAC,YAAY,QAAQ,QAAQ,EACpC,IAAI,CAAC,aAAa;AAAA,IACjB,YAAY,QAAQ;AAAA,IACpB,MAAM,QAAQ;AAAA,EAChB,EAAE;AAEJ,SAAO,OAAO;AAAA,IACZ,oBAAoB;AAAA,IACpB;AAAA,IACA,SAAS,sBAAsB,QAAQ,SAAS;AAAA,IAChD,oBAAoB;AAAA,EACtB,CAAC;AACH;",
6
+ "names": []
7
+ }
@@ -4,16 +4,30 @@ import { formatVtexError } from "../../services/vtex/vtex-api.js";
4
4
  import { getSkuOffers } from "../../services/vtex/vtex-catalog.js";
5
5
  import { toSnakeCaseKeys } from "../../utils/case-conversion.js";
6
6
  import { stripNulls } from "../../utils/strip-payload.js";
7
+ import { resolveVtexProfileOrSelection } from "./profile-resolution.js";
7
8
  const skuOffersSchema = z.object({
9
+ profileId: z.string().trim().min(1).optional().describe(
10
+ "Explicit VTEX profile id to use. If omitted, the tool returns a guided selection payload with available active profiles."
11
+ ),
8
12
  productId: z.string().min(1).describe("Product identifier"),
9
13
  skuId: z.string().min(1).describe("SKU identifier")
10
14
  });
11
- async function skuOffersHandler({ productId, skuId }) {
15
+ async function skuOffersHandler({
16
+ profileId,
17
+ productId,
18
+ skuId
19
+ }) {
12
20
  try {
13
- const offers = await getSkuOffers(productId, skuId);
21
+ const profileResolution = await resolveVtexProfileOrSelection(profileId);
22
+ if (!profileResolution.ok) {
23
+ return profileResolution.response;
24
+ }
25
+ const resolvedProfileId = profileResolution.value.profileId;
26
+ const offers = await getSkuOffers(resolvedProfileId, productId, skuId);
14
27
  const normalizedOffers = toSnakeCaseKeys(offers);
15
28
  return object(
16
29
  stripNulls({
30
+ profile_id: resolvedProfileId,
17
31
  product_id: productId,
18
32
  sku_id: skuId,
19
33
  offers: normalizedOffers
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/tools/vtex/sku-offers.ts"],
4
- "sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\n\nimport { formatVtexError } from \"../../services/vtex/vtex-api.js\";\nimport { getSkuOffers } from \"../../services/vtex/vtex-catalog.js\";\nimport { toSnakeCaseKeys } from \"../../utils/case-conversion.js\";\nimport { stripNulls } from \"../../utils/strip-payload.js\";\n\nexport const skuOffersSchema = z.object({\n productId: z.string().min(1).describe(\"Product identifier\"),\n skuId: z.string().min(1).describe(\"SKU identifier\"),\n});\n\nexport async function skuOffersHandler({ productId, skuId }: z.infer<typeof skuOffersSchema>) {\n try {\n const offers = await getSkuOffers(productId, skuId);\n const normalizedOffers = toSnakeCaseKeys(offers);\n\n return object(\n stripNulls({\n product_id: productId,\n sku_id: skuId,\n offers: normalizedOffers,\n })\n );\n } catch (err) {\n return error(formatVtexError(err, `Failed to fetch SKU offers for product ${productId} and sku ${skuId}`));\n }\n}\n"],
5
- "mappings": "AAAA,SAAS,OAAO,cAAc;AAC9B,SAAS,SAAS;AAElB,SAAS,uBAAuB;AAChC,SAAS,oBAAoB;AAC7B,SAAS,uBAAuB;AAChC,SAAS,kBAAkB;AAEpB,MAAM,kBAAkB,EAAE,OAAO;AAAA,EACtC,WAAW,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS,oBAAoB;AAAA,EAC1D,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS,gBAAgB;AACpD,CAAC;AAED,eAAsB,iBAAiB,EAAE,WAAW,MAAM,GAAoC;AAC5F,MAAI;AACF,UAAM,SAAS,MAAM,aAAa,WAAW,KAAK;AAClD,UAAM,mBAAmB,gBAAgB,MAAM;AAE/C,WAAO;AAAA,MACL,WAAW;AAAA,QACT,YAAY;AAAA,QACZ,QAAQ;AAAA,QACR,QAAQ;AAAA,MACV,CAAC;AAAA,IACH;AAAA,EACF,SAAS,KAAK;AACZ,WAAO,MAAM,gBAAgB,KAAK,0CAA0C,SAAS,YAAY,KAAK,EAAE,CAAC;AAAA,EAC3G;AACF;",
4
+ "sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\n\nimport { formatVtexError } from \"../../services/vtex/vtex-api.js\";\nimport { getSkuOffers } from \"../../services/vtex/vtex-catalog.js\";\nimport { toSnakeCaseKeys } from \"../../utils/case-conversion.js\";\nimport { stripNulls } from \"../../utils/strip-payload.js\";\nimport { resolveVtexProfileOrSelection } from \"./profile-resolution.js\";\n\nexport const skuOffersSchema = z.object({\n profileId: z\n .string()\n .trim()\n .min(1)\n .optional()\n .describe(\n \"Explicit VTEX profile id to use. If omitted, the tool returns a guided selection payload with available active profiles.\"\n ),\n productId: z.string().min(1).describe(\"Product identifier\"),\n skuId: z.string().min(1).describe(\"SKU identifier\"),\n});\n\nexport async function skuOffersHandler({\n profileId,\n productId,\n skuId,\n}: z.infer<typeof skuOffersSchema>) {\n try {\n const profileResolution = await resolveVtexProfileOrSelection(profileId);\n if (!profileResolution.ok) {\n return profileResolution.response;\n }\n\n const resolvedProfileId = profileResolution.value.profileId;\n const offers = await getSkuOffers(resolvedProfileId, productId, skuId);\n const normalizedOffers = toSnakeCaseKeys(offers);\n\n return object(\n stripNulls({\n profile_id: resolvedProfileId,\n product_id: productId,\n sku_id: skuId,\n offers: normalizedOffers,\n })\n );\n } catch (err) {\n return error(formatVtexError(err, `Failed to fetch SKU offers for product ${productId} and sku ${skuId}`));\n }\n}\n"],
5
+ "mappings": "AAAA,SAAS,OAAO,cAAc;AAC9B,SAAS,SAAS;AAElB,SAAS,uBAAuB;AAChC,SAAS,oBAAoB;AAC7B,SAAS,uBAAuB;AAChC,SAAS,kBAAkB;AAC3B,SAAS,qCAAqC;AAEvC,MAAM,kBAAkB,EAAE,OAAO;AAAA,EACtC,WAAW,EACR,OAAO,EACP,KAAK,EACL,IAAI,CAAC,EACL,SAAS,EACT;AAAA,IACC;AAAA,EACF;AAAA,EACF,WAAW,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS,oBAAoB;AAAA,EAC1D,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS,gBAAgB;AACpD,CAAC;AAED,eAAsB,iBAAiB;AAAA,EACrC;AAAA,EACA;AAAA,EACA;AACF,GAAoC;AAClC,MAAI;AACF,UAAM,oBAAoB,MAAM,8BAA8B,SAAS;AACvE,QAAI,CAAC,kBAAkB,IAAI;AACzB,aAAO,kBAAkB;AAAA,IAC3B;AAEA,UAAM,oBAAoB,kBAAkB,MAAM;AAClD,UAAM,SAAS,MAAM,aAAa,mBAAmB,WAAW,KAAK;AACrE,UAAM,mBAAmB,gBAAgB,MAAM;AAE/C,WAAO;AAAA,MACL,WAAW;AAAA,QACT,YAAY;AAAA,QACZ,YAAY;AAAA,QACZ,QAAQ;AAAA,QACR,QAAQ;AAAA,MACV,CAAC;AAAA,IACH;AAAA,EACF,SAAS,KAAK;AACZ,WAAO,MAAM,gBAAgB,KAAK,0CAA0C,SAAS,YAAY,KAAK,EAAE,CAAC;AAAA,EAC3G;AACF;",
6
6
  "names": []
7
7
  }
@@ -4,14 +4,24 @@ import { formatVtexError } from "../../services/vtex/vtex-api.js";
4
4
  import { getSkuPrice } from "../../services/vtex/vtex-pricing.js";
5
5
  import { moneyFromCentsOptional } from "../../utils/money.js";
6
6
  import { stripNulls } from "../../utils/strip-payload.js";
7
+ import { resolveVtexProfileOrSelection } from "./profile-resolution.js";
7
8
  const skuPriceSchema = z.object({
9
+ profileId: z.string().trim().min(1).optional().describe(
10
+ "Explicit VTEX profile id to use. If omitted, the tool returns a guided selection payload with available active profiles."
11
+ ),
8
12
  itemId: z.string().min(1).describe("SKU item identifier")
9
13
  });
10
- async function skuPriceHandler({ itemId }) {
14
+ async function skuPriceHandler({ profileId, itemId }) {
11
15
  try {
12
- const price = await getSkuPrice(itemId);
16
+ const profileResolution = await resolveVtexProfileOrSelection(profileId);
17
+ if (!profileResolution.ok) {
18
+ return profileResolution.response;
19
+ }
20
+ const resolvedProfileId = profileResolution.value.profileId;
21
+ const price = await getSkuPrice(resolvedProfileId, itemId);
13
22
  return object(
14
23
  stripNulls({
24
+ profile_id: resolvedProfileId,
15
25
  item_id: price.itemId,
16
26
  list_price: moneyFromCentsOptional(price.listPrice),
17
27
  cost_price: moneyFromCentsOptional(price.costPrice),
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/tools/vtex/sku-price.ts"],
4
- "sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\n\nimport { formatVtexError } from \"../../services/vtex/vtex-api.js\";\nimport { getSkuPrice } from \"../../services/vtex/vtex-pricing.js\";\nimport { moneyFromCentsOptional } from \"../../utils/money.js\";\nimport { stripNulls } from \"../../utils/strip-payload.js\";\n\nexport const skuPriceSchema = z.object({\n itemId: z.string().min(1).describe(\"SKU item identifier\"),\n});\n\nexport async function skuPriceHandler({ itemId }: z.infer<typeof skuPriceSchema>) {\n try {\n const price = await getSkuPrice(itemId);\n\n return object(\n stripNulls({\n item_id: price.itemId,\n list_price: moneyFromCentsOptional(price.listPrice),\n cost_price: moneyFromCentsOptional(price.costPrice),\n base_price: moneyFromCentsOptional(price.basePrice),\n markup: price.markup,\n fixed_prices: Array.isArray(price.fixedPrices)\n ? price.fixedPrices.map((fixedPrice) =>\n stripNulls({\n min_quantity: fixedPrice.minQuantity,\n trade_policy_id: fixedPrice.tradePolicyId,\n date_range: fixedPrice.dateRange\n ? {\n from: fixedPrice.dateRange.from,\n to: fixedPrice.dateRange.to,\n }\n : undefined,\n value: moneyFromCentsOptional(fixedPrice.value),\n list_price: moneyFromCentsOptional(fixedPrice.listPrice),\n })\n )\n : undefined,\n })\n );\n } catch (err) {\n return error(formatVtexError(err, `Failed to fetch SKU price for item ${itemId}`));\n }\n}\n"],
5
- "mappings": "AAAA,SAAS,OAAO,cAAc;AAC9B,SAAS,SAAS;AAElB,SAAS,uBAAuB;AAChC,SAAS,mBAAmB;AAC5B,SAAS,8BAA8B;AACvC,SAAS,kBAAkB;AAEpB,MAAM,iBAAiB,EAAE,OAAO;AAAA,EACrC,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS,qBAAqB;AAC1D,CAAC;AAED,eAAsB,gBAAgB,EAAE,OAAO,GAAmC;AAChF,MAAI;AACF,UAAM,QAAQ,MAAM,YAAY,MAAM;AAEtC,WAAO;AAAA,MACL,WAAW;AAAA,QACT,SAAS,MAAM;AAAA,QACf,YAAY,uBAAuB,MAAM,SAAS;AAAA,QAClD,YAAY,uBAAuB,MAAM,SAAS;AAAA,QAClD,YAAY,uBAAuB,MAAM,SAAS;AAAA,QAClD,QAAQ,MAAM;AAAA,QACd,cAAc,MAAM,QAAQ,MAAM,WAAW,IACzC,MAAM,YAAY;AAAA,UAAI,CAAC,eACrB,WAAW;AAAA,YACT,cAAc,WAAW;AAAA,YACzB,iBAAiB,WAAW;AAAA,YAC5B,YAAY,WAAW,YACnB;AAAA,cACE,MAAM,WAAW,UAAU;AAAA,cAC3B,IAAI,WAAW,UAAU;AAAA,YAC3B,IACA;AAAA,YACJ,OAAO,uBAAuB,WAAW,KAAK;AAAA,YAC9C,YAAY,uBAAuB,WAAW,SAAS;AAAA,UACzD,CAAC;AAAA,QACH,IACA;AAAA,MACN,CAAC;AAAA,IACH;AAAA,EACF,SAAS,KAAK;AACZ,WAAO,MAAM,gBAAgB,KAAK,sCAAsC,MAAM,EAAE,CAAC;AAAA,EACnF;AACF;",
4
+ "sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\n\nimport { formatVtexError } from \"../../services/vtex/vtex-api.js\";\nimport { getSkuPrice } from \"../../services/vtex/vtex-pricing.js\";\nimport { moneyFromCentsOptional } from \"../../utils/money.js\";\nimport { stripNulls } from \"../../utils/strip-payload.js\";\nimport { resolveVtexProfileOrSelection } from \"./profile-resolution.js\";\n\nexport const skuPriceSchema = z.object({\n profileId: z\n .string()\n .trim()\n .min(1)\n .optional()\n .describe(\n \"Explicit VTEX profile id to use. If omitted, the tool returns a guided selection payload with available active profiles.\"\n ),\n itemId: z.string().min(1).describe(\"SKU item identifier\"),\n});\n\nexport async function skuPriceHandler({ profileId, itemId }: z.infer<typeof skuPriceSchema>) {\n try {\n const profileResolution = await resolveVtexProfileOrSelection(profileId);\n if (!profileResolution.ok) {\n return profileResolution.response;\n }\n\n const resolvedProfileId = profileResolution.value.profileId;\n const price = await getSkuPrice(resolvedProfileId, itemId);\n\n return object(\n stripNulls({\n profile_id: resolvedProfileId,\n item_id: price.itemId,\n list_price: moneyFromCentsOptional(price.listPrice),\n cost_price: moneyFromCentsOptional(price.costPrice),\n base_price: moneyFromCentsOptional(price.basePrice),\n markup: price.markup,\n fixed_prices: Array.isArray(price.fixedPrices)\n ? price.fixedPrices.map((fixedPrice) =>\n stripNulls({\n min_quantity: fixedPrice.minQuantity,\n trade_policy_id: fixedPrice.tradePolicyId,\n date_range: fixedPrice.dateRange\n ? {\n from: fixedPrice.dateRange.from,\n to: fixedPrice.dateRange.to,\n }\n : undefined,\n value: moneyFromCentsOptional(fixedPrice.value),\n list_price: moneyFromCentsOptional(fixedPrice.listPrice),\n })\n )\n : undefined,\n })\n );\n } catch (err) {\n return error(formatVtexError(err, `Failed to fetch SKU price for item ${itemId}`));\n }\n}\n"],
5
+ "mappings": "AAAA,SAAS,OAAO,cAAc;AAC9B,SAAS,SAAS;AAElB,SAAS,uBAAuB;AAChC,SAAS,mBAAmB;AAC5B,SAAS,8BAA8B;AACvC,SAAS,kBAAkB;AAC3B,SAAS,qCAAqC;AAEvC,MAAM,iBAAiB,EAAE,OAAO;AAAA,EACrC,WAAW,EACR,OAAO,EACP,KAAK,EACL,IAAI,CAAC,EACL,SAAS,EACT;AAAA,IACC;AAAA,EACF;AAAA,EACF,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS,qBAAqB;AAC1D,CAAC;AAED,eAAsB,gBAAgB,EAAE,WAAW,OAAO,GAAmC;AAC3F,MAAI;AACF,UAAM,oBAAoB,MAAM,8BAA8B,SAAS;AACvE,QAAI,CAAC,kBAAkB,IAAI;AACzB,aAAO,kBAAkB;AAAA,IAC3B;AAEA,UAAM,oBAAoB,kBAAkB,MAAM;AAClD,UAAM,QAAQ,MAAM,YAAY,mBAAmB,MAAM;AAEzD,WAAO;AAAA,MACL,WAAW;AAAA,QACT,YAAY;AAAA,QACZ,SAAS,MAAM;AAAA,QACf,YAAY,uBAAuB,MAAM,SAAS;AAAA,QAClD,YAAY,uBAAuB,MAAM,SAAS;AAAA,QAClD,YAAY,uBAAuB,MAAM,SAAS;AAAA,QAClD,QAAQ,MAAM;AAAA,QACd,cAAc,MAAM,QAAQ,MAAM,WAAW,IACzC,MAAM,YAAY;AAAA,UAAI,CAAC,eACrB,WAAW;AAAA,YACT,cAAc,WAAW;AAAA,YACzB,iBAAiB,WAAW;AAAA,YAC5B,YAAY,WAAW,YACnB;AAAA,cACE,MAAM,WAAW,UAAU;AAAA,cAC3B,IAAI,WAAW,UAAU;AAAA,YAC3B,IACA;AAAA,YACJ,OAAO,uBAAuB,WAAW,KAAK;AAAA,YAC9C,YAAY,uBAAuB,WAAW,SAAS;AAAA,UACzD,CAAC;AAAA,QACH,IACA;AAAA,MACN,CAAC;AAAA,IACH;AAAA,EACF,SAAS,KAAK;AACZ,WAAO,MAAM,gBAAgB,KAAK,sCAAsC,MAAM,EAAE,CAAC;AAAA,EACnF;AACF;",
6
6
  "names": []
7
7
  }
@@ -2,7 +2,11 @@ import { error, object } from "mcp-use/server";
2
2
  import { z } from "zod";
3
3
  import { formatVtexError } from "../../services/vtex/vtex-api.js";
4
4
  import { updateInventoryQuantity } from "../../services/vtex/vtex-logistics.js";
5
+ import { resolveVtexProfileOrSelection } from "./profile-resolution.js";
5
6
  const updateInventorySchema = z.object({
7
+ profileId: z.string().trim().min(1).optional().describe(
8
+ "Explicit VTEX profile id to use. If omitted, the tool returns a guided selection payload with available active profiles."
9
+ ),
6
10
  skuId: z.string().min(1).describe("SKU identifier"),
7
11
  warehouseId: z.string().min(1).describe("Warehouse identifier"),
8
12
  quantity: z.number().int().min(0).describe("Inventory quantity to set"),
@@ -10,6 +14,7 @@ const updateInventorySchema = z.object({
10
14
  dateUtcOnBalanceSystem: z.string().optional().describe("Optional UTC timestamp for inventory update synchronization")
11
15
  });
12
16
  async function updateInventoryHandler({
17
+ profileId,
13
18
  skuId,
14
19
  warehouseId,
15
20
  quantity,
@@ -17,13 +22,19 @@ async function updateInventoryHandler({
17
22
  dateUtcOnBalanceSystem
18
23
  }) {
19
24
  try {
20
- await updateInventoryQuantity(skuId, warehouseId, {
25
+ const profileResolution = await resolveVtexProfileOrSelection(profileId);
26
+ if (!profileResolution.ok) {
27
+ return profileResolution.response;
28
+ }
29
+ const resolvedProfileId = profileResolution.value.profileId;
30
+ await updateInventoryQuantity(resolvedProfileId, skuId, warehouseId, {
21
31
  quantity,
22
32
  unlimitedQuantity,
23
33
  dateUtcOnBalanceSystem
24
34
  });
25
35
  return object({
26
36
  success: true,
37
+ profile_id: resolvedProfileId,
27
38
  sku_id: skuId,
28
39
  warehouse_id: warehouseId,
29
40
  quantity,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/tools/vtex/update-inventory.ts"],
4
- "sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\n\nimport { formatVtexError } from \"../../services/vtex/vtex-api.js\";\nimport { updateInventoryQuantity } from \"../../services/vtex/vtex-logistics.js\";\n\nexport const updateInventorySchema = z.object({\n skuId: z.string().min(1).describe(\"SKU identifier\"),\n warehouseId: z.string().min(1).describe(\"Warehouse identifier\"),\n quantity: z.number().int().min(0).describe(\"Inventory quantity to set\"),\n unlimitedQuantity: z\n .boolean()\n .describe(\"When true, SKU remains available regardless of stock quantity\"),\n dateUtcOnBalanceSystem: z\n .string()\n .optional()\n .describe(\"Optional UTC timestamp for inventory update synchronization\"),\n});\n\nexport async function updateInventoryHandler({\n skuId,\n warehouseId,\n quantity,\n unlimitedQuantity,\n dateUtcOnBalanceSystem,\n}: z.infer<typeof updateInventorySchema>) {\n try {\n await updateInventoryQuantity(skuId, warehouseId, {\n quantity,\n unlimitedQuantity,\n dateUtcOnBalanceSystem,\n });\n\n return object({\n success: true,\n sku_id: skuId,\n warehouse_id: warehouseId,\n quantity,\n unlimited_quantity: unlimitedQuantity,\n message: \"Inventory quantity updated successfully\",\n });\n } catch (err) {\n return error(\n formatVtexError(err, `Failed to update inventory quantity for SKU ${skuId} in ${warehouseId}`)\n );\n }\n}\n"],
5
- "mappings": "AAAA,SAAS,OAAO,cAAc;AAC9B,SAAS,SAAS;AAElB,SAAS,uBAAuB;AAChC,SAAS,+BAA+B;AAEjC,MAAM,wBAAwB,EAAE,OAAO;AAAA,EAC5C,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS,gBAAgB;AAAA,EAClD,aAAa,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS,sBAAsB;AAAA,EAC9D,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,SAAS,2BAA2B;AAAA,EACtE,mBAAmB,EAChB,QAAQ,EACR,SAAS,+DAA+D;AAAA,EAC3E,wBAAwB,EACrB,OAAO,EACP,SAAS,EACT,SAAS,6DAA6D;AAC3E,CAAC;AAED,eAAsB,uBAAuB;AAAA,EAC3C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA0C;AACxC,MAAI;AACF,UAAM,wBAAwB,OAAO,aAAa;AAAA,MAChD;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAED,WAAO,OAAO;AAAA,MACZ,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,cAAc;AAAA,MACd;AAAA,MACA,oBAAoB;AAAA,MACpB,SAAS;AAAA,IACX,CAAC;AAAA,EACH,SAAS,KAAK;AACZ,WAAO;AAAA,MACL,gBAAgB,KAAK,+CAA+C,KAAK,OAAO,WAAW,EAAE;AAAA,IAC/F;AAAA,EACF;AACF;",
4
+ "sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\n\nimport { formatVtexError } from \"../../services/vtex/vtex-api.js\";\nimport { updateInventoryQuantity } from \"../../services/vtex/vtex-logistics.js\";\nimport { resolveVtexProfileOrSelection } from \"./profile-resolution.js\";\n\nexport const updateInventorySchema = z.object({\n profileId: z\n .string()\n .trim()\n .min(1)\n .optional()\n .describe(\n \"Explicit VTEX profile id to use. If omitted, the tool returns a guided selection payload with available active profiles.\"\n ),\n skuId: z.string().min(1).describe(\"SKU identifier\"),\n warehouseId: z.string().min(1).describe(\"Warehouse identifier\"),\n quantity: z.number().int().min(0).describe(\"Inventory quantity to set\"),\n unlimitedQuantity: z\n .boolean()\n .describe(\"When true, SKU remains available regardless of stock quantity\"),\n dateUtcOnBalanceSystem: z\n .string()\n .optional()\n .describe(\"Optional UTC timestamp for inventory update synchronization\"),\n});\n\nexport async function updateInventoryHandler({\n profileId,\n skuId,\n warehouseId,\n quantity,\n unlimitedQuantity,\n dateUtcOnBalanceSystem,\n}: z.infer<typeof updateInventorySchema>) {\n try {\n const profileResolution = await resolveVtexProfileOrSelection(profileId);\n if (!profileResolution.ok) {\n return profileResolution.response;\n }\n\n const resolvedProfileId = profileResolution.value.profileId;\n\n await updateInventoryQuantity(resolvedProfileId, skuId, warehouseId, {\n quantity,\n unlimitedQuantity,\n dateUtcOnBalanceSystem,\n });\n\n return object({\n success: true,\n profile_id: resolvedProfileId,\n sku_id: skuId,\n warehouse_id: warehouseId,\n quantity,\n unlimited_quantity: unlimitedQuantity,\n message: \"Inventory quantity updated successfully\",\n });\n } catch (err) {\n return error(\n formatVtexError(err, `Failed to update inventory quantity for SKU ${skuId} in ${warehouseId}`)\n );\n }\n}\n"],
5
+ "mappings": "AAAA,SAAS,OAAO,cAAc;AAC9B,SAAS,SAAS;AAElB,SAAS,uBAAuB;AAChC,SAAS,+BAA+B;AACxC,SAAS,qCAAqC;AAEvC,MAAM,wBAAwB,EAAE,OAAO;AAAA,EAC5C,WAAW,EACR,OAAO,EACP,KAAK,EACL,IAAI,CAAC,EACL,SAAS,EACT;AAAA,IACC;AAAA,EACF;AAAA,EACF,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS,gBAAgB;AAAA,EAClD,aAAa,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS,sBAAsB;AAAA,EAC9D,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,SAAS,2BAA2B;AAAA,EACtE,mBAAmB,EAChB,QAAQ,EACR,SAAS,+DAA+D;AAAA,EAC3E,wBAAwB,EACrB,OAAO,EACP,SAAS,EACT,SAAS,6DAA6D;AAC3E,CAAC;AAED,eAAsB,uBAAuB;AAAA,EAC3C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA0C;AACxC,MAAI;AACF,UAAM,oBAAoB,MAAM,8BAA8B,SAAS;AACvE,QAAI,CAAC,kBAAkB,IAAI;AACzB,aAAO,kBAAkB;AAAA,IAC3B;AAEA,UAAM,oBAAoB,kBAAkB,MAAM;AAElD,UAAM,wBAAwB,mBAAmB,OAAO,aAAa;AAAA,MACnE;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAED,WAAO,OAAO;AAAA,MACZ,SAAS;AAAA,MACT,YAAY;AAAA,MACZ,QAAQ;AAAA,MACR,cAAc;AAAA,MACd;AAAA,MACA,oBAAoB;AAAA,MACpB,SAAS;AAAA,IACX,CAAC;AAAA,EACH,SAAS,KAAK;AACZ,WAAO;AAAA,MACL,gBAAgB,KAAK,+CAA+C,KAAK,OAAO,WAAW,EAAE;AAAA,IAC/F;AAAA,EACF;AACF;",
6
6
  "names": []
7
7
  }
@@ -2,20 +2,31 @@ import { error, object } from "mcp-use/server";
2
2
  import { z } from "zod";
3
3
  import { formatVtexError } from "../../services/vtex/vtex-api.js";
4
4
  import { updateInventoryLeadTime } from "../../services/vtex/vtex-logistics.js";
5
+ import { resolveVtexProfileOrSelection } from "./profile-resolution.js";
5
6
  const updateLeadTimeSchema = z.object({
7
+ profileId: z.string().trim().min(1).optional().describe(
8
+ "Explicit VTEX profile id to use. If omitted, the tool returns a guided selection payload with available active profiles."
9
+ ),
6
10
  skuId: z.string().min(1).describe("SKU identifier"),
7
11
  warehouseId: z.string().min(1).describe("Warehouse identifier"),
8
12
  leadTime: z.string().min(1).describe("Lead time value for the SKU in VTEX expected format (e.g. 1.00:00:00)")
9
13
  });
10
14
  async function updateLeadTimeHandler({
15
+ profileId,
11
16
  skuId,
12
17
  warehouseId,
13
18
  leadTime
14
19
  }) {
15
20
  try {
16
- await updateInventoryLeadTime(skuId, warehouseId, { leadTime });
21
+ const profileResolution = await resolveVtexProfileOrSelection(profileId);
22
+ if (!profileResolution.ok) {
23
+ return profileResolution.response;
24
+ }
25
+ const resolvedProfileId = profileResolution.value.profileId;
26
+ await updateInventoryLeadTime(resolvedProfileId, skuId, warehouseId, { leadTime });
17
27
  return object({
18
28
  success: true,
29
+ profile_id: resolvedProfileId,
19
30
  sku_id: skuId,
20
31
  warehouse_id: warehouseId,
21
32
  lead_time: leadTime,