@yoryoboy/bi-mcp 1.0.5 → 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 (102) hide show
  1. package/README.md +140 -9
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/index.js +151 -1
  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/meta.js +29 -0
  25. package/dist/src/config/meta.js.map +7 -0
  26. package/dist/src/config/profile-store.js +86 -0
  27. package/dist/src/config/profile-store.js.map +7 -0
  28. package/dist/src/config/vtex-crypto.js +43 -0
  29. package/dist/src/config/vtex-crypto.js.map +7 -0
  30. package/dist/src/config/vtex-profile-store.js +132 -0
  31. package/dist/src/config/vtex-profile-store.js.map +7 -0
  32. package/dist/src/config/vtex.js +27 -21
  33. package/dist/src/config/vtex.js.map +2 -2
  34. package/dist/src/db/client.js +58 -0
  35. package/dist/src/db/client.js.map +7 -0
  36. package/dist/src/meta/meta-utils.js +148 -0
  37. package/dist/src/meta/meta-utils.js.map +7 -0
  38. package/dist/src/services/meta/meta-ads.js +89 -0
  39. package/dist/src/services/meta/meta-ads.js.map +7 -0
  40. package/dist/src/services/meta/meta-api.js +35 -0
  41. package/dist/src/services/meta/meta-api.js.map +7 -0
  42. package/dist/src/services/vtex/vtex-api.js +24 -8
  43. package/dist/src/services/vtex/vtex-api.js.map +2 -2
  44. package/dist/src/services/vtex/vtex-catalog.js +5 -3
  45. package/dist/src/services/vtex/vtex-catalog.js.map +2 -2
  46. package/dist/src/services/vtex/vtex-logistics.js +18 -9
  47. package/dist/src/services/vtex/vtex-logistics.js.map +2 -2
  48. package/dist/src/services/vtex/vtex-orders.js +13 -7
  49. package/dist/src/services/vtex/vtex-orders.js.map +2 -2
  50. package/dist/src/services/vtex/vtex-pricing.js +5 -3
  51. package/dist/src/services/vtex/vtex-pricing.js.map +2 -2
  52. package/dist/src/tools/config/check-database-connection.js +59 -0
  53. package/dist/src/tools/config/check-database-connection.js.map +7 -0
  54. package/dist/src/tools/config/index.js +3 -0
  55. package/dist/src/tools/config/index.js.map +7 -0
  56. package/dist/src/tools/config/list-profiles.js +26 -0
  57. package/dist/src/tools/config/list-profiles.js.map +7 -0
  58. package/dist/src/tools/index.js +2 -0
  59. package/dist/src/tools/index.js.map +2 -2
  60. package/dist/src/tools/meta/account-overview.js +92 -0
  61. package/dist/src/tools/meta/account-overview.js.map +7 -0
  62. package/dist/src/tools/meta/ad-account-info.js +37 -0
  63. package/dist/src/tools/meta/ad-account-info.js.map +7 -0
  64. package/dist/src/tools/meta/ads-performance.js +79 -0
  65. package/dist/src/tools/meta/ads-performance.js.map +7 -0
  66. package/dist/src/tools/meta/campaign-performance.js +81 -0
  67. package/dist/src/tools/meta/campaign-performance.js.map +7 -0
  68. package/dist/src/tools/meta/index.js +9 -0
  69. package/dist/src/tools/meta/index.js.map +7 -0
  70. package/dist/src/tools/meta/list-accessible-ad-accounts.js +44 -0
  71. package/dist/src/tools/meta/list-accessible-ad-accounts.js.map +7 -0
  72. package/dist/src/tools/meta/list-accessible-businesses.js +36 -0
  73. package/dist/src/tools/meta/list-accessible-businesses.js.map +7 -0
  74. package/dist/src/tools/meta/placement-mix.js +67 -0
  75. package/dist/src/tools/meta/placement-mix.js.map +7 -0
  76. package/dist/src/tools/meta/time-series.js +69 -0
  77. package/dist/src/tools/meta/time-series.js.map +7 -0
  78. package/dist/src/tools/vtex/computed-price.js +12 -1
  79. package/dist/src/tools/vtex/computed-price.js.map +2 -2
  80. package/dist/src/tools/vtex/index.js +1 -0
  81. package/dist/src/tools/vtex/index.js.map +2 -2
  82. package/dist/src/tools/vtex/inventory-check.js +15 -2
  83. package/dist/src/tools/vtex/inventory-check.js.map +2 -2
  84. package/dist/src/tools/vtex/order-details.js +16 -2
  85. package/dist/src/tools/vtex/order-details.js.map +2 -2
  86. package/dist/src/tools/vtex/orders-summary.js +11 -1
  87. package/dist/src/tools/vtex/orders-summary.js.map +2 -2
  88. package/dist/src/tools/vtex/product-offers.js +15 -2
  89. package/dist/src/tools/vtex/product-offers.js.map +2 -2
  90. package/dist/src/tools/vtex/profile-resolution.js +57 -0
  91. package/dist/src/tools/vtex/profile-resolution.js.map +7 -0
  92. package/dist/src/tools/vtex/sku-offers.js +16 -2
  93. package/dist/src/tools/vtex/sku-offers.js.map +2 -2
  94. package/dist/src/tools/vtex/sku-price.js +12 -2
  95. package/dist/src/tools/vtex/sku-price.js.map +2 -2
  96. package/dist/src/tools/vtex/update-inventory.js +12 -1
  97. package/dist/src/tools/vtex/update-inventory.js.map +2 -2
  98. package/dist/src/tools/vtex/update-lead-time.js +12 -1
  99. package/dist/src/tools/vtex/update-lead-time.js.map +2 -2
  100. package/dist/src/tools/vtex/warehouse-inventory.js +12 -1
  101. package/dist/src/tools/vtex/warehouse-inventory.js.map +2 -2
  102. package/package.json +12 -2
@@ -0,0 +1,81 @@
1
+ import { error, object } from "mcp-use/server";
2
+ import { z } from "zod";
3
+ import {
4
+ getMetaCampaigns,
5
+ getMetaInsights,
6
+ listAccessibleMetaAdAccounts
7
+ } from "../../services/meta/meta-ads.js";
8
+ import {
9
+ dateRegex,
10
+ getMetricBundle,
11
+ normalizeRequestedAccountIds,
12
+ resolveRequestedAccounts
13
+ } from "../../meta/meta-utils.js";
14
+ import { stripNulls } from "../../utils/strip-payload.js";
15
+ const metaCampaignPerformanceSchema = z.object({
16
+ startDate: z.string().regex(dateRegex).describe("Start date in YYYY-MM-DD format."),
17
+ endDate: z.string().regex(dateRegex).describe("End date in YYYY-MM-DD format."),
18
+ adAccountIds: z.array(z.string()).optional().describe(
19
+ "Optional list of Meta ad account IDs. Accepts digits with or without the act_ prefix. If omitted, uses all accessible ad accounts."
20
+ ),
21
+ limit: z.number().int().min(1).max(100).optional().describe("Maximum number of campaigns to return per ad account. Default: 25.")
22
+ });
23
+ async function metaCampaignPerformanceHandler(params) {
24
+ try {
25
+ const accessibleAccounts = (await listAccessibleMetaAdAccounts()).adAccounts;
26
+ const requestedIds = normalizeRequestedAccountIds(params.adAccountIds);
27
+ const accounts = resolveRequestedAccounts(requestedIds, accessibleAccounts);
28
+ const limit = params.limit ?? 25;
29
+ const results = await Promise.all(
30
+ accounts.map(async (account) => {
31
+ const campaigns = await getMetaCampaigns(account.account_id || "", limit);
32
+ const rows = await Promise.all(
33
+ campaigns.map(async (campaign) => {
34
+ const insight = (await getMetaInsights(campaign.id || "", {
35
+ time_range: JSON.stringify({ since: params.startDate, until: params.endDate }),
36
+ level: "campaign"
37
+ }))[0];
38
+ return {
39
+ campaign_id: campaign.id,
40
+ campaign_name: campaign.name,
41
+ status: campaign.status,
42
+ effective_status: campaign.effective_status,
43
+ objective: campaign.objective,
44
+ ...getMetricBundle(insight)
45
+ };
46
+ })
47
+ );
48
+ rows.sort((left, right) => right.spend - left.spend);
49
+ return {
50
+ ad_account_id: account.account_id,
51
+ account_name: account.name,
52
+ currency_code: account.currency,
53
+ campaigns: rows
54
+ };
55
+ })
56
+ );
57
+ return object(
58
+ stripNulls({
59
+ date_range: {
60
+ start_date: params.startDate,
61
+ end_date: params.endDate
62
+ },
63
+ accounts: results,
64
+ metadata: {
65
+ analyzed_accounts: results.length,
66
+ campaigns_per_account_limit: limit,
67
+ note: "Campaigns are ranked inside each ad account to preserve account context and avoid unsafe cross-account aggregation."
68
+ }
69
+ })
70
+ );
71
+ } catch (err) {
72
+ return error(
73
+ err instanceof Error ? err.message : "Failed to fetch Meta campaign performance"
74
+ );
75
+ }
76
+ }
77
+ export {
78
+ metaCampaignPerformanceHandler,
79
+ metaCampaignPerformanceSchema
80
+ };
81
+ //# sourceMappingURL=campaign-performance.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/tools/meta/campaign-performance.ts"],
4
+ "sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\n\nimport {\n getMetaCampaigns,\n getMetaInsights,\n listAccessibleMetaAdAccounts,\n} from \"../../services/meta/meta-ads.js\";\nimport {\n dateRegex,\n getMetricBundle,\n normalizeRequestedAccountIds,\n resolveRequestedAccounts,\n} from \"../../meta/meta-utils.js\";\nimport { stripNulls } from \"../../utils/strip-payload.js\";\n\nexport const metaCampaignPerformanceSchema = 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 adAccountIds: z\n .array(z.string())\n .optional()\n .describe(\n \"Optional list of Meta ad account IDs. Accepts digits with or without the act_ prefix. If omitted, uses all accessible ad accounts.\"\n ),\n limit: z\n .number()\n .int()\n .min(1)\n .max(100)\n .optional()\n .describe(\"Maximum number of campaigns to return per ad account. Default: 25.\"),\n});\n\nexport async function metaCampaignPerformanceHandler(\n params: z.infer<typeof metaCampaignPerformanceSchema>\n) {\n try {\n const accessibleAccounts = (await listAccessibleMetaAdAccounts()).adAccounts;\n const requestedIds = normalizeRequestedAccountIds(params.adAccountIds);\n const accounts = resolveRequestedAccounts(requestedIds, accessibleAccounts);\n const limit = params.limit ?? 25;\n\n const results = await Promise.all(\n accounts.map(async (account) => {\n const campaigns = await getMetaCampaigns(account.account_id || \"\", limit);\n const rows = await Promise.all(\n campaigns.map(async (campaign) => {\n const insight = (\n await getMetaInsights(campaign.id || \"\", {\n time_range: JSON.stringify({ since: params.startDate, until: params.endDate }),\n level: \"campaign\",\n })\n )[0];\n\n return {\n campaign_id: campaign.id,\n campaign_name: campaign.name,\n status: campaign.status,\n effective_status: campaign.effective_status,\n objective: campaign.objective,\n ...getMetricBundle(insight),\n };\n })\n );\n\n rows.sort((left, right) => right.spend - left.spend);\n\n return {\n ad_account_id: account.account_id,\n account_name: account.name,\n currency_code: account.currency,\n campaigns: rows,\n };\n })\n );\n\n return object(\n stripNulls({\n date_range: {\n start_date: params.startDate,\n end_date: params.endDate,\n },\n accounts: results,\n metadata: {\n analyzed_accounts: results.length,\n campaigns_per_account_limit: limit,\n note:\n \"Campaigns are ranked inside each ad account to preserve account context and avoid unsafe cross-account aggregation.\",\n },\n })\n );\n } catch (err) {\n return error(\n err instanceof Error ? err.message : \"Failed to fetch Meta campaign performance\"\n );\n }\n}\n"],
5
+ "mappings": "AAAA,SAAS,OAAO,cAAc;AAC9B,SAAS,SAAS;AAElB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,kBAAkB;AAEpB,MAAM,gCAAgC,EAAE,OAAO;AAAA,EACpD,WAAW,EAAE,OAAO,EAAE,MAAM,SAAS,EAAE,SAAS,kCAAkC;AAAA,EAClF,SAAS,EAAE,OAAO,EAAE,MAAM,SAAS,EAAE,SAAS,gCAAgC;AAAA,EAC9E,cAAc,EACX,MAAM,EAAE,OAAO,CAAC,EAChB,SAAS,EACT;AAAA,IACC;AAAA,EACF;AAAA,EACF,OAAO,EACJ,OAAO,EACP,IAAI,EACJ,IAAI,CAAC,EACL,IAAI,GAAG,EACP,SAAS,EACT,SAAS,oEAAoE;AAClF,CAAC;AAED,eAAsB,+BACpB,QACA;AACA,MAAI;AACF,UAAM,sBAAsB,MAAM,6BAA6B,GAAG;AAClE,UAAM,eAAe,6BAA6B,OAAO,YAAY;AACrE,UAAM,WAAW,yBAAyB,cAAc,kBAAkB;AAC1E,UAAM,QAAQ,OAAO,SAAS;AAE9B,UAAM,UAAU,MAAM,QAAQ;AAAA,MAC5B,SAAS,IAAI,OAAO,YAAY;AAC9B,cAAM,YAAY,MAAM,iBAAiB,QAAQ,cAAc,IAAI,KAAK;AACxE,cAAM,OAAO,MAAM,QAAQ;AAAA,UACzB,UAAU,IAAI,OAAO,aAAa;AAChC,kBAAM,WACJ,MAAM,gBAAgB,SAAS,MAAM,IAAI;AAAA,cACvC,YAAY,KAAK,UAAU,EAAE,OAAO,OAAO,WAAW,OAAO,OAAO,QAAQ,CAAC;AAAA,cAC7E,OAAO;AAAA,YACT,CAAC,GACD,CAAC;AAEH,mBAAO;AAAA,cACL,aAAa,SAAS;AAAA,cACtB,eAAe,SAAS;AAAA,cACxB,QAAQ,SAAS;AAAA,cACjB,kBAAkB,SAAS;AAAA,cAC3B,WAAW,SAAS;AAAA,cACpB,GAAG,gBAAgB,OAAO;AAAA,YAC5B;AAAA,UACF,CAAC;AAAA,QACH;AAEA,aAAK,KAAK,CAAC,MAAM,UAAU,MAAM,QAAQ,KAAK,KAAK;AAEnD,eAAO;AAAA,UACL,eAAe,QAAQ;AAAA,UACvB,cAAc,QAAQ;AAAA,UACtB,eAAe,QAAQ;AAAA,UACvB,WAAW;AAAA,QACb;AAAA,MACF,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,MACL,WAAW;AAAA,QACT,YAAY;AAAA,UACV,YAAY,OAAO;AAAA,UACnB,UAAU,OAAO;AAAA,QACnB;AAAA,QACA,UAAU;AAAA,QACV,UAAU;AAAA,UACR,mBAAmB,QAAQ;AAAA,UAC3B,6BAA6B;AAAA,UAC7B,MACE;AAAA,QACJ;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF,SAAS,KAAK;AACZ,WAAO;AAAA,MACL,eAAe,QAAQ,IAAI,UAAU;AAAA,IACvC;AAAA,EACF;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,9 @@
1
+ export * from "./list-accessible-businesses.js";
2
+ export * from "./list-accessible-ad-accounts.js";
3
+ export * from "./ad-account-info.js";
4
+ export * from "./account-overview.js";
5
+ export * from "./campaign-performance.js";
6
+ export * from "./ads-performance.js";
7
+ export * from "./time-series.js";
8
+ export * from "./placement-mix.js";
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/tools/meta/index.ts"],
4
+ "sourcesContent": ["export * from \"./list-accessible-businesses.js\";\nexport * from \"./list-accessible-ad-accounts.js\";\nexport * from \"./ad-account-info.js\";\nexport * from \"./account-overview.js\";\nexport * from \"./campaign-performance.js\";\nexport * from \"./ads-performance.js\";\nexport * from \"./time-series.js\";\nexport * from \"./placement-mix.js\";\n"],
5
+ "mappings": "AAAA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;",
6
+ "names": []
7
+ }
@@ -0,0 +1,44 @@
1
+ import { error, object } from "mcp-use/server";
2
+ import { z } from "zod";
3
+ import { listAccessibleMetaAdAccounts } from "../../services/meta/meta-ads.js";
4
+ import { getMetaAdAccountStatusLabel } from "../../meta/meta-utils.js";
5
+ import { stripNulls } from "../../utils/strip-payload.js";
6
+ const metaListAccessibleAdAccountsSchema = z.object({
7
+ after: z.string().optional().describe("Optional pagination cursor returned by a previous Meta ad accounts listing.")
8
+ });
9
+ async function metaListAccessibleAdAccountsHandler(params) {
10
+ try {
11
+ const result = await listAccessibleMetaAdAccounts(params.after);
12
+ return object(
13
+ stripNulls({
14
+ ad_accounts: result.adAccounts.map((account) => ({
15
+ id: account.id,
16
+ account_id: account.account_id,
17
+ act_id: account.account_id ? `act_${account.account_id}` : account.id,
18
+ name: account.name,
19
+ currency: account.currency,
20
+ account_status: account.account_status,
21
+ account_status_label: getMetaAdAccountStatusLabel(account.account_status),
22
+ timezone_name: account.timezone_name,
23
+ timezone_offset_hours_utc: account.timezone_offset_hours_utc,
24
+ business: account.business
25
+ })),
26
+ metadata: {
27
+ returned_ad_accounts: result.adAccounts.length,
28
+ pagination: {
29
+ has_more: result.paging.has_more,
30
+ next_after: result.paging.after
31
+ },
32
+ note: result.paging.has_more ? "Partial data. Use metadata.pagination.next_after to request the next page." : "Complete data for the current token and page size."
33
+ }
34
+ })
35
+ );
36
+ } catch (err) {
37
+ return error(err instanceof Error ? err.message : "Failed to list accessible Meta ad accounts");
38
+ }
39
+ }
40
+ export {
41
+ metaListAccessibleAdAccountsHandler,
42
+ metaListAccessibleAdAccountsSchema
43
+ };
44
+ //# sourceMappingURL=list-accessible-ad-accounts.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/tools/meta/list-accessible-ad-accounts.ts"],
4
+ "sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\n\nimport { listAccessibleMetaAdAccounts } from \"../../services/meta/meta-ads.js\";\nimport { getMetaAdAccountStatusLabel } from \"../../meta/meta-utils.js\";\nimport { stripNulls } from \"../../utils/strip-payload.js\";\n\nexport const metaListAccessibleAdAccountsSchema = z.object({\n after: z\n .string()\n .optional()\n .describe(\"Optional pagination cursor returned by a previous Meta ad accounts listing.\"),\n});\n\nexport async function metaListAccessibleAdAccountsHandler(\n params: z.infer<typeof metaListAccessibleAdAccountsSchema>\n) {\n try {\n const result = await listAccessibleMetaAdAccounts(params.after);\n\n return object(\n stripNulls({\n ad_accounts: result.adAccounts.map((account) => ({\n id: account.id,\n account_id: account.account_id,\n act_id: account.account_id ? `act_${account.account_id}` : account.id,\n name: account.name,\n currency: account.currency,\n account_status: account.account_status,\n account_status_label: getMetaAdAccountStatusLabel(account.account_status),\n timezone_name: account.timezone_name,\n timezone_offset_hours_utc: account.timezone_offset_hours_utc,\n business: account.business,\n })),\n metadata: {\n returned_ad_accounts: result.adAccounts.length,\n pagination: {\n has_more: result.paging.has_more,\n next_after: result.paging.after,\n },\n note: result.paging.has_more\n ? \"Partial data. Use metadata.pagination.next_after to request the next page.\"\n : \"Complete data for the current token and page size.\",\n },\n })\n );\n } catch (err) {\n return error(err instanceof Error ? err.message : \"Failed to list accessible Meta ad accounts\");\n }\n}\n"],
5
+ "mappings": "AAAA,SAAS,OAAO,cAAc;AAC9B,SAAS,SAAS;AAElB,SAAS,oCAAoC;AAC7C,SAAS,mCAAmC;AAC5C,SAAS,kBAAkB;AAEpB,MAAM,qCAAqC,EAAE,OAAO;AAAA,EACzD,OAAO,EACJ,OAAO,EACP,SAAS,EACT,SAAS,6EAA6E;AAC3F,CAAC;AAED,eAAsB,oCACpB,QACA;AACA,MAAI;AACF,UAAM,SAAS,MAAM,6BAA6B,OAAO,KAAK;AAE9D,WAAO;AAAA,MACL,WAAW;AAAA,QACT,aAAa,OAAO,WAAW,IAAI,CAAC,aAAa;AAAA,UAC/C,IAAI,QAAQ;AAAA,UACZ,YAAY,QAAQ;AAAA,UACpB,QAAQ,QAAQ,aAAa,OAAO,QAAQ,UAAU,KAAK,QAAQ;AAAA,UACnE,MAAM,QAAQ;AAAA,UACd,UAAU,QAAQ;AAAA,UAClB,gBAAgB,QAAQ;AAAA,UACxB,sBAAsB,4BAA4B,QAAQ,cAAc;AAAA,UACxE,eAAe,QAAQ;AAAA,UACvB,2BAA2B,QAAQ;AAAA,UACnC,UAAU,QAAQ;AAAA,QACpB,EAAE;AAAA,QACF,UAAU;AAAA,UACR,sBAAsB,OAAO,WAAW;AAAA,UACxC,YAAY;AAAA,YACV,UAAU,OAAO,OAAO;AAAA,YACxB,YAAY,OAAO,OAAO;AAAA,UAC5B;AAAA,UACA,MAAM,OAAO,OAAO,WAChB,+EACA;AAAA,QACN;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF,SAAS,KAAK;AACZ,WAAO,MAAM,eAAe,QAAQ,IAAI,UAAU,4CAA4C;AAAA,EAChG;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,36 @@
1
+ import { error, object } from "mcp-use/server";
2
+ import { z } from "zod";
3
+ import { listAccessibleMetaBusinesses } from "../../services/meta/meta-ads.js";
4
+ import { stripNulls } from "../../utils/strip-payload.js";
5
+ const metaListAccessibleBusinessesSchema = z.object({
6
+ after: z.string().optional().describe("Optional pagination cursor returned by a previous Meta businesses listing.")
7
+ });
8
+ async function metaListAccessibleBusinessesHandler(params) {
9
+ try {
10
+ const result = await listAccessibleMetaBusinesses(params.after);
11
+ return object(
12
+ stripNulls({
13
+ businesses: result.businesses.map((business) => ({
14
+ id: business.id,
15
+ name: business.name,
16
+ verification_status: business.verification_status
17
+ })),
18
+ metadata: {
19
+ returned_businesses: result.businesses.length,
20
+ pagination: {
21
+ has_more: result.paging.has_more,
22
+ next_after: result.paging.after
23
+ },
24
+ note: result.paging.has_more ? "Partial data. Use metadata.pagination.next_after to request the next page." : "Complete data for the current token and page size."
25
+ }
26
+ })
27
+ );
28
+ } catch (err) {
29
+ return error(err instanceof Error ? err.message : "Failed to list accessible Meta businesses");
30
+ }
31
+ }
32
+ export {
33
+ metaListAccessibleBusinessesHandler,
34
+ metaListAccessibleBusinessesSchema
35
+ };
36
+ //# sourceMappingURL=list-accessible-businesses.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/tools/meta/list-accessible-businesses.ts"],
4
+ "sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\n\nimport { listAccessibleMetaBusinesses } from \"../../services/meta/meta-ads.js\";\nimport { stripNulls } from \"../../utils/strip-payload.js\";\n\nexport const metaListAccessibleBusinessesSchema = z.object({\n after: z\n .string()\n .optional()\n .describe(\"Optional pagination cursor returned by a previous Meta businesses listing.\"),\n});\n\nexport async function metaListAccessibleBusinessesHandler(\n params: z.infer<typeof metaListAccessibleBusinessesSchema>\n) {\n try {\n const result = await listAccessibleMetaBusinesses(params.after);\n\n return object(\n stripNulls({\n businesses: result.businesses.map((business) => ({\n id: business.id,\n name: business.name,\n verification_status: business.verification_status,\n })),\n metadata: {\n returned_businesses: result.businesses.length,\n pagination: {\n has_more: result.paging.has_more,\n next_after: result.paging.after,\n },\n note: result.paging.has_more\n ? \"Partial data. Use metadata.pagination.next_after to request the next page.\"\n : \"Complete data for the current token and page size.\",\n },\n })\n );\n } catch (err) {\n return error(err instanceof Error ? err.message : \"Failed to list accessible Meta businesses\");\n }\n}\n"],
5
+ "mappings": "AAAA,SAAS,OAAO,cAAc;AAC9B,SAAS,SAAS;AAElB,SAAS,oCAAoC;AAC7C,SAAS,kBAAkB;AAEpB,MAAM,qCAAqC,EAAE,OAAO;AAAA,EACzD,OAAO,EACJ,OAAO,EACP,SAAS,EACT,SAAS,4EAA4E;AAC1F,CAAC;AAED,eAAsB,oCACpB,QACA;AACA,MAAI;AACF,UAAM,SAAS,MAAM,6BAA6B,OAAO,KAAK;AAE9D,WAAO;AAAA,MACL,WAAW;AAAA,QACT,YAAY,OAAO,WAAW,IAAI,CAAC,cAAc;AAAA,UAC/C,IAAI,SAAS;AAAA,UACb,MAAM,SAAS;AAAA,UACf,qBAAqB,SAAS;AAAA,QAChC,EAAE;AAAA,QACF,UAAU;AAAA,UACR,qBAAqB,OAAO,WAAW;AAAA,UACvC,YAAY;AAAA,YACV,UAAU,OAAO,OAAO;AAAA,YACxB,YAAY,OAAO,OAAO;AAAA,UAC5B;AAAA,UACA,MAAM,OAAO,OAAO,WAChB,+EACA;AAAA,QACN;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF,SAAS,KAAK;AACZ,WAAO,MAAM,eAAe,QAAQ,IAAI,UAAU,2CAA2C;AAAA,EAC/F;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,67 @@
1
+ import { error, object } from "mcp-use/server";
2
+ import { z } from "zod";
3
+ import {
4
+ getMetaPlacementInsights,
5
+ listAccessibleMetaAdAccounts
6
+ } from "../../services/meta/meta-ads.js";
7
+ import {
8
+ dateRegex,
9
+ getMetricBundle,
10
+ normalizeRequestedAccountIds,
11
+ resolveRequestedAccounts
12
+ } from "../../meta/meta-utils.js";
13
+ import { stripNulls } from "../../utils/strip-payload.js";
14
+ const metaPlacementMixSchema = z.object({
15
+ startDate: z.string().regex(dateRegex).describe("Start date in YYYY-MM-DD format."),
16
+ endDate: z.string().regex(dateRegex).describe("End date in YYYY-MM-DD format."),
17
+ adAccountIds: z.array(z.string()).optional().describe(
18
+ "Optional list of Meta ad account IDs. Accepts digits with or without the act_ prefix. If omitted, uses all accessible ad accounts."
19
+ )
20
+ });
21
+ async function metaPlacementMixHandler(params) {
22
+ try {
23
+ const accessibleAccounts = (await listAccessibleMetaAdAccounts()).adAccounts;
24
+ const requestedIds = normalizeRequestedAccountIds(params.adAccountIds);
25
+ const accounts = resolveRequestedAccounts(requestedIds, accessibleAccounts);
26
+ const results = await Promise.all(
27
+ accounts.map(async (account) => {
28
+ const rows = await getMetaPlacementInsights(account.account_id || "", {
29
+ time_range: JSON.stringify({ since: params.startDate, until: params.endDate }),
30
+ level: "account",
31
+ breakdowns: "publisher_platform,platform_position,impression_device"
32
+ });
33
+ return {
34
+ ad_account_id: account.account_id,
35
+ account_name: account.name,
36
+ currency_code: account.currency,
37
+ placements: rows.map((row) => ({
38
+ publisher_platform: row.publisher_platform,
39
+ platform_position: row.platform_position,
40
+ impression_device: row.impression_device,
41
+ ...getMetricBundle(row)
42
+ })).sort((left, right) => right.spend - left.spend)
43
+ };
44
+ })
45
+ );
46
+ return object(
47
+ stripNulls({
48
+ date_range: {
49
+ start_date: params.startDate,
50
+ end_date: params.endDate
51
+ },
52
+ accounts: results,
53
+ metadata: {
54
+ analyzed_accounts: results.length,
55
+ note: "Placement mix is returned per ad account. Use this to compare Facebook, Instagram, and placement efficiency inside each account."
56
+ }
57
+ })
58
+ );
59
+ } catch (err) {
60
+ return error(err instanceof Error ? err.message : "Failed to fetch Meta placement mix");
61
+ }
62
+ }
63
+ export {
64
+ metaPlacementMixHandler,
65
+ metaPlacementMixSchema
66
+ };
67
+ //# sourceMappingURL=placement-mix.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/tools/meta/placement-mix.ts"],
4
+ "sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\n\nimport {\n getMetaPlacementInsights,\n listAccessibleMetaAdAccounts,\n} from \"../../services/meta/meta-ads.js\";\nimport {\n dateRegex,\n getMetricBundle,\n normalizeRequestedAccountIds,\n resolveRequestedAccounts,\n} from \"../../meta/meta-utils.js\";\nimport { stripNulls } from \"../../utils/strip-payload.js\";\n\nexport const metaPlacementMixSchema = 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 adAccountIds: z\n .array(z.string())\n .optional()\n .describe(\n \"Optional list of Meta ad account IDs. Accepts digits with or without the act_ prefix. If omitted, uses all accessible ad accounts.\"\n ),\n});\n\nexport async function metaPlacementMixHandler(\n params: z.infer<typeof metaPlacementMixSchema>\n) {\n try {\n const accessibleAccounts = (await listAccessibleMetaAdAccounts()).adAccounts;\n const requestedIds = normalizeRequestedAccountIds(params.adAccountIds);\n const accounts = resolveRequestedAccounts(requestedIds, accessibleAccounts);\n\n const results = await Promise.all(\n accounts.map(async (account) => {\n const rows = await getMetaPlacementInsights(account.account_id || \"\", {\n time_range: JSON.stringify({ since: params.startDate, until: params.endDate }),\n level: \"account\",\n breakdowns: \"publisher_platform,platform_position,impression_device\",\n });\n\n return {\n ad_account_id: account.account_id,\n account_name: account.name,\n currency_code: account.currency,\n placements: rows\n .map((row) => ({\n publisher_platform: row.publisher_platform,\n platform_position: row.platform_position,\n impression_device: row.impression_device,\n ...getMetricBundle(row),\n }))\n .sort((left, right) => right.spend - left.spend),\n };\n })\n );\n\n return object(\n stripNulls({\n date_range: {\n start_date: params.startDate,\n end_date: params.endDate,\n },\n accounts: results,\n metadata: {\n analyzed_accounts: results.length,\n note:\n \"Placement mix is returned per ad account. Use this to compare Facebook, Instagram, and placement efficiency inside each account.\",\n },\n })\n );\n } catch (err) {\n return error(err instanceof Error ? err.message : \"Failed to fetch Meta placement mix\");\n }\n}\n"],
5
+ "mappings": "AAAA,SAAS,OAAO,cAAc;AAC9B,SAAS,SAAS;AAElB;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,kBAAkB;AAEpB,MAAM,yBAAyB,EAAE,OAAO;AAAA,EAC7C,WAAW,EAAE,OAAO,EAAE,MAAM,SAAS,EAAE,SAAS,kCAAkC;AAAA,EAClF,SAAS,EAAE,OAAO,EAAE,MAAM,SAAS,EAAE,SAAS,gCAAgC;AAAA,EAC9E,cAAc,EACX,MAAM,EAAE,OAAO,CAAC,EAChB,SAAS,EACT;AAAA,IACC;AAAA,EACF;AACJ,CAAC;AAED,eAAsB,wBACpB,QACA;AACA,MAAI;AACF,UAAM,sBAAsB,MAAM,6BAA6B,GAAG;AAClE,UAAM,eAAe,6BAA6B,OAAO,YAAY;AACrE,UAAM,WAAW,yBAAyB,cAAc,kBAAkB;AAE1E,UAAM,UAAU,MAAM,QAAQ;AAAA,MAC5B,SAAS,IAAI,OAAO,YAAY;AAC9B,cAAM,OAAO,MAAM,yBAAyB,QAAQ,cAAc,IAAI;AAAA,UACpE,YAAY,KAAK,UAAU,EAAE,OAAO,OAAO,WAAW,OAAO,OAAO,QAAQ,CAAC;AAAA,UAC7E,OAAO;AAAA,UACP,YAAY;AAAA,QACd,CAAC;AAED,eAAO;AAAA,UACL,eAAe,QAAQ;AAAA,UACvB,cAAc,QAAQ;AAAA,UACtB,eAAe,QAAQ;AAAA,UACvB,YAAY,KACT,IAAI,CAAC,SAAS;AAAA,YACb,oBAAoB,IAAI;AAAA,YACxB,mBAAmB,IAAI;AAAA,YACvB,mBAAmB,IAAI;AAAA,YACvB,GAAG,gBAAgB,GAAG;AAAA,UACxB,EAAE,EACD,KAAK,CAAC,MAAM,UAAU,MAAM,QAAQ,KAAK,KAAK;AAAA,QACnD;AAAA,MACF,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,MACL,WAAW;AAAA,QACT,YAAY;AAAA,UACV,YAAY,OAAO;AAAA,UACnB,UAAU,OAAO;AAAA,QACnB;AAAA,QACA,UAAU;AAAA,QACV,UAAU;AAAA,UACR,mBAAmB,QAAQ;AAAA,UAC3B,MACE;AAAA,QACJ;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF,SAAS,KAAK;AACZ,WAAO,MAAM,eAAe,QAAQ,IAAI,UAAU,oCAAoC;AAAA,EACxF;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,69 @@
1
+ import { error, object } from "mcp-use/server";
2
+ import { z } from "zod";
3
+ import {
4
+ getMetaInsights,
5
+ listAccessibleMetaAdAccounts
6
+ } from "../../services/meta/meta-ads.js";
7
+ import {
8
+ dateRegex,
9
+ getMetricBundle,
10
+ normalizeRequestedAccountIds,
11
+ resolveRequestedAccounts
12
+ } from "../../meta/meta-utils.js";
13
+ import { stripNulls } from "../../utils/strip-payload.js";
14
+ const metaTimeSeriesSchema = z.object({
15
+ startDate: z.string().regex(dateRegex).describe("Start date in YYYY-MM-DD format."),
16
+ endDate: z.string().regex(dateRegex).describe("End date in YYYY-MM-DD format."),
17
+ adAccountIds: z.array(z.string()).optional().describe(
18
+ "Optional list of Meta ad account IDs. Accepts digits with or without the act_ prefix. If omitted, uses all accessible ad accounts."
19
+ ),
20
+ timeIncrement: z.enum(["1", "7", "monthly"]).optional().describe("Time increment for the series. Use 1 for daily, 7 for weekly, or monthly.")
21
+ });
22
+ async function metaTimeSeriesHandler(params) {
23
+ try {
24
+ const accessibleAccounts = (await listAccessibleMetaAdAccounts()).adAccounts;
25
+ const requestedIds = normalizeRequestedAccountIds(params.adAccountIds);
26
+ const accounts = resolveRequestedAccounts(requestedIds, accessibleAccounts);
27
+ const timeIncrement = params.timeIncrement ?? "1";
28
+ const results = await Promise.all(
29
+ accounts.map(async (account) => {
30
+ const rows = await getMetaInsights(`act_${account.account_id}`, {
31
+ time_range: JSON.stringify({ since: params.startDate, until: params.endDate }),
32
+ time_increment: timeIncrement,
33
+ level: "account"
34
+ });
35
+ return {
36
+ ad_account_id: account.account_id,
37
+ account_name: account.name,
38
+ currency_code: account.currency,
39
+ series: rows.map((row) => ({
40
+ date_start: row.date_start,
41
+ date_stop: row.date_stop,
42
+ ...getMetricBundle(row)
43
+ }))
44
+ };
45
+ })
46
+ );
47
+ return object(
48
+ stripNulls({
49
+ date_range: {
50
+ start_date: params.startDate,
51
+ end_date: params.endDate
52
+ },
53
+ time_increment: timeIncrement,
54
+ accounts: results,
55
+ metadata: {
56
+ analyzed_accounts: results.length,
57
+ note: "Time series are returned per ad account to preserve currency and account context."
58
+ }
59
+ })
60
+ );
61
+ } catch (err) {
62
+ return error(err instanceof Error ? err.message : "Failed to fetch Meta time series");
63
+ }
64
+ }
65
+ export {
66
+ metaTimeSeriesHandler,
67
+ metaTimeSeriesSchema
68
+ };
69
+ //# sourceMappingURL=time-series.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/tools/meta/time-series.ts"],
4
+ "sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\n\nimport {\n getMetaInsights,\n listAccessibleMetaAdAccounts,\n} from \"../../services/meta/meta-ads.js\";\nimport {\n dateRegex,\n getMetricBundle,\n normalizeRequestedAccountIds,\n resolveRequestedAccounts,\n} from \"../../meta/meta-utils.js\";\nimport { stripNulls } from \"../../utils/strip-payload.js\";\n\nexport const metaTimeSeriesSchema = 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 adAccountIds: z\n .array(z.string())\n .optional()\n .describe(\n \"Optional list of Meta ad account IDs. Accepts digits with or without the act_ prefix. If omitted, uses all accessible ad accounts.\"\n ),\n timeIncrement: z\n .enum([\"1\", \"7\", \"monthly\"])\n .optional()\n .describe(\"Time increment for the series. Use 1 for daily, 7 for weekly, or monthly.\"),\n});\n\nexport async function metaTimeSeriesHandler(\n params: z.infer<typeof metaTimeSeriesSchema>\n) {\n try {\n const accessibleAccounts = (await listAccessibleMetaAdAccounts()).adAccounts;\n const requestedIds = normalizeRequestedAccountIds(params.adAccountIds);\n const accounts = resolveRequestedAccounts(requestedIds, accessibleAccounts);\n const timeIncrement = params.timeIncrement ?? \"1\";\n\n const results = await Promise.all(\n accounts.map(async (account) => {\n const rows = await getMetaInsights(`act_${account.account_id}`, {\n time_range: JSON.stringify({ since: params.startDate, until: params.endDate }),\n time_increment: timeIncrement,\n level: \"account\",\n });\n\n return {\n ad_account_id: account.account_id,\n account_name: account.name,\n currency_code: account.currency,\n series: rows.map((row) => ({\n date_start: row.date_start,\n date_stop: row.date_stop,\n ...getMetricBundle(row),\n })),\n };\n })\n );\n\n return object(\n stripNulls({\n date_range: {\n start_date: params.startDate,\n end_date: params.endDate,\n },\n time_increment: timeIncrement,\n accounts: results,\n metadata: {\n analyzed_accounts: results.length,\n note: \"Time series are returned per ad account to preserve currency and account context.\",\n },\n })\n );\n } catch (err) {\n return error(err instanceof Error ? err.message : \"Failed to fetch Meta time series\");\n }\n}\n"],
5
+ "mappings": "AAAA,SAAS,OAAO,cAAc;AAC9B,SAAS,SAAS;AAElB;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,kBAAkB;AAEpB,MAAM,uBAAuB,EAAE,OAAO;AAAA,EAC3C,WAAW,EAAE,OAAO,EAAE,MAAM,SAAS,EAAE,SAAS,kCAAkC;AAAA,EAClF,SAAS,EAAE,OAAO,EAAE,MAAM,SAAS,EAAE,SAAS,gCAAgC;AAAA,EAC9E,cAAc,EACX,MAAM,EAAE,OAAO,CAAC,EAChB,SAAS,EACT;AAAA,IACC;AAAA,EACF;AAAA,EACF,eAAe,EACZ,KAAK,CAAC,KAAK,KAAK,SAAS,CAAC,EAC1B,SAAS,EACT,SAAS,2EAA2E;AACzF,CAAC;AAED,eAAsB,sBACpB,QACA;AACA,MAAI;AACF,UAAM,sBAAsB,MAAM,6BAA6B,GAAG;AAClE,UAAM,eAAe,6BAA6B,OAAO,YAAY;AACrE,UAAM,WAAW,yBAAyB,cAAc,kBAAkB;AAC1E,UAAM,gBAAgB,OAAO,iBAAiB;AAE9C,UAAM,UAAU,MAAM,QAAQ;AAAA,MAC5B,SAAS,IAAI,OAAO,YAAY;AAC9B,cAAM,OAAO,MAAM,gBAAgB,OAAO,QAAQ,UAAU,IAAI;AAAA,UAC9D,YAAY,KAAK,UAAU,EAAE,OAAO,OAAO,WAAW,OAAO,OAAO,QAAQ,CAAC;AAAA,UAC7E,gBAAgB;AAAA,UAChB,OAAO;AAAA,QACT,CAAC;AAED,eAAO;AAAA,UACL,eAAe,QAAQ;AAAA,UACvB,cAAc,QAAQ;AAAA,UACtB,eAAe,QAAQ;AAAA,UACvB,QAAQ,KAAK,IAAI,CAAC,SAAS;AAAA,YACzB,YAAY,IAAI;AAAA,YAChB,WAAW,IAAI;AAAA,YACf,GAAG,gBAAgB,GAAG;AAAA,UACxB,EAAE;AAAA,QACJ;AAAA,MACF,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,MACL,WAAW;AAAA,QACT,YAAY;AAAA,UACV,YAAY,OAAO;AAAA,UACnB,UAAU,OAAO;AAAA,QACnB;AAAA,QACA,gBAAgB;AAAA,QAChB,UAAU;AAAA,QACV,UAAU;AAAA,UACR,mBAAmB,QAAQ;AAAA,UAC3B,MAAM;AAAA,QACR;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF,SAAS,KAAK;AACZ,WAAO,MAAM,eAAe,QAAQ,IAAI,UAAU,kCAAkC;AAAA,EACtF;AACF;",
6
+ "names": []
7
+ }
@@ -4,7 +4,11 @@ import { formatVtexError } from "../../services/vtex/vtex-api.js";
4
4
  import { getComputedPrice } 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 computedPriceSchema = 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
  priceTableId: z.string().min(1).describe("Price table or trade policy identifier"),
10
14
  categoryId: z.number().int().positive().describe("Category identifier"),
@@ -12,6 +16,7 @@ const computedPriceSchema = z.object({
12
16
  quantity: z.number().int().positive().describe("SKU quantity context")
13
17
  });
14
18
  async function computedPriceHandler({
19
+ profileId,
15
20
  itemId,
16
21
  priceTableId,
17
22
  categoryId,
@@ -19,13 +24,19 @@ async function computedPriceHandler({
19
24
  quantity
20
25
  }) {
21
26
  try {
22
- const computedPrice = await getComputedPrice(itemId, priceTableId, {
27
+ const profileResolution = await resolveVtexProfileOrSelection(profileId);
28
+ if (!profileResolution.ok) {
29
+ return profileResolution.response;
30
+ }
31
+ const resolvedProfileId = profileResolution.value.profileId;
32
+ const computedPrice = await getComputedPrice(resolvedProfileId, itemId, priceTableId, {
23
33
  categoryId,
24
34
  brandId,
25
35
  quantity
26
36
  });
27
37
  return object(
28
38
  stripNulls({
39
+ profile_id: resolvedProfileId,
29
40
  item_id: itemId,
30
41
  price_table_id: priceTableId,
31
42
  trade_policy_id: computedPrice.tradePolicyId,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/tools/vtex/computed-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 { getComputedPrice } from \"../../services/vtex/vtex-pricing.js\";\nimport { moneyFromCentsOptional } from \"../../utils/money.js\";\nimport { stripNulls } from \"../../utils/strip-payload.js\";\n\nexport const computedPriceSchema = z.object({\n itemId: z.string().min(1).describe(\"SKU item identifier\"),\n priceTableId: z.string().min(1).describe(\"Price table or trade policy identifier\"),\n categoryId: z.number().int().positive().describe(\"Category identifier\"),\n brandId: z.number().int().positive().describe(\"Brand identifier\"),\n quantity: z.number().int().positive().describe(\"SKU quantity context\"),\n});\n\nexport async function computedPriceHandler({\n itemId,\n priceTableId,\n categoryId,\n brandId,\n quantity,\n}: z.infer<typeof computedPriceSchema>) {\n try {\n const computedPrice = await getComputedPrice(itemId, priceTableId, {\n categoryId,\n brandId,\n quantity,\n });\n\n return object(\n stripNulls({\n item_id: itemId,\n price_table_id: priceTableId,\n trade_policy_id: computedPrice.tradePolicyId,\n list_price: moneyFromCentsOptional(computedPrice.listPrice),\n cost_price: moneyFromCentsOptional(computedPrice.costPrice),\n selling_price: moneyFromCentsOptional(computedPrice.sellingPrice),\n price_valid_until: computedPrice.priceValidUntil,\n })\n );\n } catch (err) {\n return error(\n formatVtexError(err, `Failed to fetch computed price for item ${itemId} and table ${priceTableId}`)\n );\n }\n}\n"],
5
- "mappings": "AAAA,SAAS,OAAO,cAAc;AAC9B,SAAS,SAAS;AAElB,SAAS,uBAAuB;AAChC,SAAS,wBAAwB;AACjC,SAAS,8BAA8B;AACvC,SAAS,kBAAkB;AAEpB,MAAM,sBAAsB,EAAE,OAAO;AAAA,EAC1C,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS,qBAAqB;AAAA,EACxD,cAAc,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS,wCAAwC;AAAA,EACjF,YAAY,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,qBAAqB;AAAA,EACtE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,kBAAkB;AAAA,EAChE,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,sBAAsB;AACvE,CAAC;AAED,eAAsB,qBAAqB;AAAA,EACzC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAwC;AACtC,MAAI;AACF,UAAM,gBAAgB,MAAM,iBAAiB,QAAQ,cAAc;AAAA,MACjE;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAED,WAAO;AAAA,MACL,WAAW;AAAA,QACT,SAAS;AAAA,QACT,gBAAgB;AAAA,QAChB,iBAAiB,cAAc;AAAA,QAC/B,YAAY,uBAAuB,cAAc,SAAS;AAAA,QAC1D,YAAY,uBAAuB,cAAc,SAAS;AAAA,QAC1D,eAAe,uBAAuB,cAAc,YAAY;AAAA,QAChE,mBAAmB,cAAc;AAAA,MACnC,CAAC;AAAA,IACH;AAAA,EACF,SAAS,KAAK;AACZ,WAAO;AAAA,MACL,gBAAgB,KAAK,2CAA2C,MAAM,cAAc,YAAY,EAAE;AAAA,IACpG;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 { getComputedPrice } 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 computedPriceSchema = 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 priceTableId: z.string().min(1).describe(\"Price table or trade policy identifier\"),\n categoryId: z.number().int().positive().describe(\"Category identifier\"),\n brandId: z.number().int().positive().describe(\"Brand identifier\"),\n quantity: z.number().int().positive().describe(\"SKU quantity context\"),\n});\n\nexport async function computedPriceHandler({\n profileId,\n itemId,\n priceTableId,\n categoryId,\n brandId,\n quantity,\n}: z.infer<typeof computedPriceSchema>) {\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 computedPrice = await getComputedPrice(resolvedProfileId, itemId, priceTableId, {\n categoryId,\n brandId,\n quantity,\n });\n\n return object(\n stripNulls({\n profile_id: resolvedProfileId,\n item_id: itemId,\n price_table_id: priceTableId,\n trade_policy_id: computedPrice.tradePolicyId,\n list_price: moneyFromCentsOptional(computedPrice.listPrice),\n cost_price: moneyFromCentsOptional(computedPrice.costPrice),\n selling_price: moneyFromCentsOptional(computedPrice.sellingPrice),\n price_valid_until: computedPrice.priceValidUntil,\n })\n );\n } catch (err) {\n return error(\n formatVtexError(err, `Failed to fetch computed price for item ${itemId} and table ${priceTableId}`)\n );\n }\n}\n"],
5
+ "mappings": "AAAA,SAAS,OAAO,cAAc;AAC9B,SAAS,SAAS;AAElB,SAAS,uBAAuB;AAChC,SAAS,wBAAwB;AACjC,SAAS,8BAA8B;AACvC,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,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS,qBAAqB;AAAA,EACxD,cAAc,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS,wCAAwC;AAAA,EACjF,YAAY,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,qBAAqB;AAAA,EACtE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,kBAAkB;AAAA,EAChE,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,sBAAsB;AACvE,CAAC;AAED,eAAsB,qBAAqB;AAAA,EACzC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;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,gBAAgB,MAAM,iBAAiB,mBAAmB,QAAQ,cAAc;AAAA,MACpF;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAED,WAAO;AAAA,MACL,WAAW;AAAA,QACT,YAAY;AAAA,QACZ,SAAS;AAAA,QACT,gBAAgB;AAAA,QAChB,iBAAiB,cAAc;AAAA,QAC/B,YAAY,uBAAuB,cAAc,SAAS;AAAA,QAC1D,YAAY,uBAAuB,cAAc,SAAS;AAAA,QAC1D,eAAe,uBAAuB,cAAc,YAAY;AAAA,QAChE,mBAAmB,cAAc;AAAA,MACnC,CAAC;AAAA,IACH;AAAA,EACF,SAAS,KAAK;AACZ,WAAO;AAAA,MACL,gBAAgB,KAAK,2CAA2C,MAAM,cAAc,YAAY,EAAE;AAAA,IACpG;AAAA,EACF;AACF;",
6
6
  "names": []
7
7
  }
@@ -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