@yoryoboy/bi-mcp 1.16.0 → 1.19.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 (158) hide show
  1. package/README.md +12 -0
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/index.js +179 -6
  4. package/dist/index.js.map +2 -2
  5. package/dist/mcp-use.json +3 -6
  6. package/dist/src/config/__tests__/google-store.test.js +30 -0
  7. package/dist/src/config/__tests__/google-store.test.js.map +7 -0
  8. package/dist/src/config/__tests__/mcp-tool-deadline.test.js +64 -0
  9. package/dist/src/config/__tests__/mcp-tool-deadline.test.js.map +7 -0
  10. package/dist/src/config/google-store.js +18 -0
  11. package/dist/src/config/google-store.js.map +2 -2
  12. package/dist/src/config/mcp-tool-deadline-context.js +34 -0
  13. package/dist/src/config/mcp-tool-deadline-context.js.map +7 -0
  14. package/dist/src/config/mcp-tool-deadline.js +67 -0
  15. package/dist/src/config/mcp-tool-deadline.js.map +7 -0
  16. package/dist/src/services/mercadolibre/__tests__/mercadolibre-api.test.js +38 -3
  17. package/dist/src/services/mercadolibre/__tests__/mercadolibre-api.test.js.map +2 -2
  18. package/dist/src/services/mercadolibre/__tests__/mercadolibre-buyer-reconciliation.test.js +226 -0
  19. package/dist/src/services/mercadolibre/__tests__/mercadolibre-buyer-reconciliation.test.js.map +7 -0
  20. package/dist/src/services/mercadolibre/__tests__/mercadolibre-claim-reconciliation.test.js +127 -0
  21. package/dist/src/services/mercadolibre/__tests__/mercadolibre-claim-reconciliation.test.js.map +7 -0
  22. package/dist/src/services/mercadolibre/__tests__/mercadolibre-kits.test.js +103 -0
  23. package/dist/src/services/mercadolibre/__tests__/mercadolibre-kits.test.js.map +7 -0
  24. package/dist/src/services/mercadolibre/__tests__/mercadolibre-order-billing-info.test.js +582 -0
  25. package/dist/src/services/mercadolibre/__tests__/mercadolibre-order-billing-info.test.js.map +7 -0
  26. package/dist/src/services/mercadolibre/__tests__/mercadolibre-orders.test.js +10 -0
  27. package/dist/src/services/mercadolibre/__tests__/mercadolibre-orders.test.js.map +2 -2
  28. package/dist/src/services/mercadolibre/__tests__/mercadolibre-packs.test.js +36 -0
  29. package/dist/src/services/mercadolibre/__tests__/mercadolibre-packs.test.js.map +7 -0
  30. package/dist/src/services/mercadolibre/__tests__/mercadolibre-payments.test.js +137 -0
  31. package/dist/src/services/mercadolibre/__tests__/mercadolibre-payments.test.js.map +7 -0
  32. package/dist/src/services/mercadolibre/__tests__/mercadolibre-product-ads-ad-group-ads.test.js +105 -0
  33. package/dist/src/services/mercadolibre/__tests__/mercadolibre-product-ads-ad-group-ads.test.js.map +7 -0
  34. package/dist/src/services/mercadolibre/__tests__/mercadolibre-product-ads-ad-groups.test.js +143 -0
  35. package/dist/src/services/mercadolibre/__tests__/mercadolibre-product-ads-ad-groups.test.js.map +7 -0
  36. package/dist/src/services/mercadolibre/__tests__/mercadolibre-product-ads-campaigns.test.js +100 -0
  37. package/dist/src/services/mercadolibre/__tests__/mercadolibre-product-ads-campaigns.test.js.map +7 -0
  38. package/dist/src/services/mercadolibre/__tests__/mercadolibre-product-ads.test.js +350 -0
  39. package/dist/src/services/mercadolibre/__tests__/mercadolibre-product-ads.test.js.map +7 -0
  40. package/dist/src/services/mercadolibre/__tests__/mercadolibre-return-reconciliation.test.js +228 -0
  41. package/dist/src/services/mercadolibre/__tests__/mercadolibre-return-reconciliation.test.js.map +7 -0
  42. package/dist/src/services/mercadolibre/__tests__/mercadolibre-shipping.test.js +58 -0
  43. package/dist/src/services/mercadolibre/__tests__/mercadolibre-shipping.test.js.map +7 -0
  44. package/dist/src/services/mercadolibre/mercadolibre-api.js +15 -3
  45. package/dist/src/services/mercadolibre/mercadolibre-api.js.map +2 -2
  46. package/dist/src/services/mercadolibre/mercadolibre-billing.js +110 -3
  47. package/dist/src/services/mercadolibre/mercadolibre-billing.js.map +2 -2
  48. package/dist/src/services/mercadolibre/mercadolibre-buyer-reconciliation.js +368 -0
  49. package/dist/src/services/mercadolibre/mercadolibre-buyer-reconciliation.js.map +7 -0
  50. package/dist/src/services/mercadolibre/mercadolibre-claim-reconciliation.js +399 -0
  51. package/dist/src/services/mercadolibre/mercadolibre-claim-reconciliation.js.map +7 -0
  52. package/dist/src/services/mercadolibre/mercadolibre-kits.js +55 -0
  53. package/dist/src/services/mercadolibre/mercadolibre-kits.js.map +7 -0
  54. package/dist/src/services/mercadolibre/mercadolibre-order-billing-info.js +392 -0
  55. package/dist/src/services/mercadolibre/mercadolibre-order-billing-info.js.map +7 -0
  56. package/dist/src/services/mercadolibre/mercadolibre-orders.js +8 -8
  57. package/dist/src/services/mercadolibre/mercadolibre-orders.js.map +2 -2
  58. package/dist/src/services/mercadolibre/mercadolibre-packs.js +21 -0
  59. package/dist/src/services/mercadolibre/mercadolibre-packs.js.map +7 -0
  60. package/dist/src/services/mercadolibre/mercadolibre-payments.js +60 -0
  61. package/dist/src/services/mercadolibre/mercadolibre-payments.js.map +7 -0
  62. package/dist/src/services/mercadolibre/mercadolibre-product-ads.js +429 -0
  63. package/dist/src/services/mercadolibre/mercadolibre-product-ads.js.map +7 -0
  64. package/dist/src/services/mercadolibre/mercadolibre-return-reconciliation.js +436 -0
  65. package/dist/src/services/mercadolibre/mercadolibre-return-reconciliation.js.map +7 -0
  66. package/dist/src/services/mercadolibre/mercadolibre-shipping.js +35 -0
  67. package/dist/src/services/mercadolibre/mercadolibre-shipping.js.map +7 -0
  68. package/dist/src/services/vtex/__tests__/vtex-api.test.js +67 -0
  69. package/dist/src/services/vtex/__tests__/vtex-api.test.js.map +7 -0
  70. package/dist/src/services/vtex/vtex-api.js +6 -0
  71. package/dist/src/services/vtex/vtex-api.js.map +2 -2
  72. package/dist/src/tools/config/__tests__/list-profiles.test.js +154 -0
  73. package/dist/src/tools/config/__tests__/list-profiles.test.js.map +7 -0
  74. package/dist/src/tools/config/list-profiles.js +39 -3
  75. package/dist/src/tools/config/list-profiles.js.map +2 -2
  76. package/dist/src/tools/mercadolibre/__tests__/get-order-billing-info.test.js +339 -0
  77. package/dist/src/tools/mercadolibre/__tests__/get-order-billing-info.test.js.map +7 -0
  78. package/dist/src/tools/mercadolibre/__tests__/product-ads-ad-group-ads.test.js +225 -0
  79. package/dist/src/tools/mercadolibre/__tests__/product-ads-ad-group-ads.test.js.map +7 -0
  80. package/dist/src/tools/mercadolibre/__tests__/product-ads-ad-groups.test.js +148 -0
  81. package/dist/src/tools/mercadolibre/__tests__/product-ads-ad-groups.test.js.map +7 -0
  82. package/dist/src/tools/mercadolibre/__tests__/product-ads-campaigns.test.js +60 -0
  83. package/dist/src/tools/mercadolibre/__tests__/product-ads-campaigns.test.js.map +7 -0
  84. package/dist/src/tools/mercadolibre/__tests__/product-ads-helpers.test.js +128 -0
  85. package/dist/src/tools/mercadolibre/__tests__/product-ads-helpers.test.js.map +7 -0
  86. package/dist/src/tools/mercadolibre/__tests__/product-ads-tools.test.js +435 -0
  87. package/dist/src/tools/mercadolibre/__tests__/product-ads-tools.test.js.map +7 -0
  88. package/dist/src/tools/mercadolibre/__tests__/reconcile-buyer-data.test.js +31 -0
  89. package/dist/src/tools/mercadolibre/__tests__/reconcile-buyer-data.test.js.map +7 -0
  90. package/dist/src/tools/mercadolibre/__tests__/reconcile-claim-data.test.js +36 -0
  91. package/dist/src/tools/mercadolibre/__tests__/reconcile-claim-data.test.js.map +7 -0
  92. package/dist/src/tools/mercadolibre/__tests__/validate-connection.test.js +205 -0
  93. package/dist/src/tools/mercadolibre/__tests__/validate-connection.test.js.map +7 -0
  94. package/dist/src/tools/mercadolibre/get-billing-provisions-by-order.js +313 -0
  95. package/dist/src/tools/mercadolibre/get-billing-provisions-by-order.js.map +7 -0
  96. package/dist/src/tools/mercadolibre/get-bundle-context-by-item.js +176 -0
  97. package/dist/src/tools/mercadolibre/get-bundle-context-by-item.js.map +7 -0
  98. package/dist/src/tools/mercadolibre/get-full-storage-charges.js +183 -0
  99. package/dist/src/tools/mercadolibre/get-full-storage-charges.js.map +7 -0
  100. package/dist/src/tools/mercadolibre/get-order-billing-info.js +189 -0
  101. package/dist/src/tools/mercadolibre/get-order-billing-info.js.map +7 -0
  102. package/dist/src/tools/mercadolibre/get-pack-context-by-order.js +150 -0
  103. package/dist/src/tools/mercadolibre/get-pack-context-by-order.js.map +7 -0
  104. package/dist/src/tools/mercadolibre/get-payment-details.js +322 -0
  105. package/dist/src/tools/mercadolibre/get-payment-details.js.map +7 -0
  106. package/dist/src/tools/mercadolibre/get-product-ads-ad-group-ads.js +144 -0
  107. package/dist/src/tools/mercadolibre/get-product-ads-ad-group-ads.js.map +7 -0
  108. package/dist/src/tools/mercadolibre/get-product-ads-advertisers.js +59 -0
  109. package/dist/src/tools/mercadolibre/get-product-ads-advertisers.js.map +7 -0
  110. package/dist/src/tools/mercadolibre/get-shipping-quote-by-declared-dimensions.js +104 -0
  111. package/dist/src/tools/mercadolibre/get-shipping-quote-by-declared-dimensions.js.map +7 -0
  112. package/dist/src/tools/mercadolibre/index.js +32 -0
  113. package/dist/src/tools/mercadolibre/index.js.map +2 -2
  114. package/dist/src/tools/mercadolibre/product-ads-helpers.js +130 -0
  115. package/dist/src/tools/mercadolibre/product-ads-helpers.js.map +7 -0
  116. package/dist/src/tools/mercadolibre/reconcile-buyer-data.js +27 -0
  117. package/dist/src/tools/mercadolibre/reconcile-buyer-data.js.map +7 -0
  118. package/dist/src/tools/mercadolibre/reconcile-claim-data.js +46 -0
  119. package/dist/src/tools/mercadolibre/reconcile-claim-data.js.map +7 -0
  120. package/dist/src/tools/mercadolibre/reconcile-return-data.js +25 -0
  121. package/dist/src/tools/mercadolibre/reconcile-return-data.js.map +7 -0
  122. package/dist/src/tools/mercadolibre/search-product-ads-ad-groups.js +162 -0
  123. package/dist/src/tools/mercadolibre/search-product-ads-ad-groups.js.map +7 -0
  124. package/dist/src/tools/mercadolibre/search-product-ads-ads.js +216 -0
  125. package/dist/src/tools/mercadolibre/search-product-ads-ads.js.map +7 -0
  126. package/dist/src/tools/mercadolibre/search-product-ads-campaigns.js +116 -0
  127. package/dist/src/tools/mercadolibre/search-product-ads-campaigns.js.map +7 -0
  128. package/dist/src/tools/mercadolibre/validate-connection.js +40 -12
  129. package/dist/src/tools/mercadolibre/validate-connection.js.map +2 -2
  130. package/dist/tests/meli/mercadolibre-billing-provisions.test.js +378 -0
  131. package/dist/tests/meli/mercadolibre-billing-provisions.test.js.map +2 -2
  132. package/dist/tests/meli/mercadolibre-order-billing-info-surface.test.js +123 -0
  133. package/dist/tests/meli/mercadolibre-order-billing-info-surface.test.js.map +7 -0
  134. package/dist/tests/meli/mercadolibre-payment-details.test.js +356 -0
  135. package/dist/tests/meli/mercadolibre-payment-details.test.js.map +7 -0
  136. package/dist/tests/meli/mercadolibre-payments.test.js +62 -0
  137. package/dist/tests/meli/mercadolibre-payments.test.js.map +7 -0
  138. package/dist/tests/meli/mercadolibre-product-ads-ad-groups-surface.test.js +90 -0
  139. package/dist/tests/meli/mercadolibre-product-ads-ad-groups-surface.test.js.map +7 -0
  140. package/dist/tests/meli/mercadolibre-product-ads-campaigns-surface.test.js +72 -0
  141. package/dist/tests/meli/mercadolibre-product-ads-campaigns-surface.test.js.map +7 -0
  142. package/dist/tests/meli/mercadolibre-tool-handlers-pack-kit-shipping.test.js +400 -0
  143. package/dist/tests/meli/mercadolibre-tool-handlers-pack-kit-shipping.test.js.map +7 -0
  144. package/dist/tests/meli/mercadolibre-tool-handlers-small.test.js +31 -12
  145. package/dist/tests/meli/mercadolibre-tool-handlers-small.test.js.map +2 -2
  146. package/dist/tests/vtex/vtex-commercial-conditions-docs.test.js +1 -1
  147. package/dist/tests/vtex/vtex-commercial-conditions-docs.test.js.map +1 -1
  148. package/package.json +1 -1
  149. package/dist/src/google-ads/report-utils.js +0 -78
  150. package/dist/src/google-ads/report-utils.js.map +0 -7
  151. package/dist/src/search-console/search-console-utils.js +0 -275
  152. package/dist/src/search-console/search-console-utils.js.map +0 -7
  153. package/dist/src/services/vtex/__tests__/vtex-catalog-write-batch.test.js +0 -165
  154. package/dist/src/services/vtex/__tests__/vtex-catalog-write-batch.test.js.map +0 -7
  155. package/dist/src/tools/vtex/__tests__/catalog-admin-batch.test.js +0 -233
  156. package/dist/src/tools/vtex/__tests__/catalog-admin-batch.test.js.map +0 -7
  157. package/dist/src/tools/vtex/catalog-admin-batch.js +0 -298
  158. package/dist/src/tools/vtex/catalog-admin-batch.js.map +0 -7
@@ -0,0 +1,67 @@
1
+ import { beforeEach, describe, expect, it, vi } from "vitest";
2
+ import { createServer } from "node:http";
3
+ const requestUse = vi.fn();
4
+ vi.mock("axios", async () => {
5
+ const actual = await vi.importActual("axios");
6
+ return {
7
+ ...actual,
8
+ default: {
9
+ ...actual.default,
10
+ create: vi.fn((...args) => {
11
+ const client = actual.default.create(...args);
12
+ const use = client.interceptors.request.use.bind(client.interceptors.request);
13
+ client.interceptors.request.use = (handler, ...rest) => {
14
+ requestUse(handler);
15
+ return use(handler, ...rest);
16
+ };
17
+ return client;
18
+ })
19
+ }
20
+ };
21
+ });
22
+ import axios from "axios";
23
+ import { runWithMcpToolDeadlineContext } from "../../../config/mcp-tool-deadline-context.js";
24
+ import { createVtexClient } from "../vtex-api.js";
25
+ describe("VTEX Axios deadline propagation", () => {
26
+ beforeEach(() => {
27
+ vi.clearAllMocks();
28
+ });
29
+ it("composes the global signal and propagates abort to the Axios request signal", async () => {
30
+ createVtexClient({ apiKey: "key", apiToken: "token" }, "https://vtex.test");
31
+ const requestInterceptor = requestUse.mock.calls[0]?.[0];
32
+ const globalController = new AbortController();
33
+ const requestController = new AbortController();
34
+ const request = await runWithMcpToolDeadlineContext(globalController.signal, async () => requestInterceptor({ signal: requestController.signal }));
35
+ expect(request.signal).toBeDefined();
36
+ expect(request.signal).not.toBe(globalController.signal);
37
+ expect(request.signal).not.toBe(requestController.signal);
38
+ expect(request.signal?.aborted).toBe(false);
39
+ globalController.abort();
40
+ expect(request.signal?.aborted).toBe(true);
41
+ });
42
+ it("keeps the composed signal aborted when the request signal was already aborted", async () => {
43
+ createVtexClient({ apiKey: "key", apiToken: "token" }, "https://vtex.test");
44
+ const requestInterceptor = requestUse.mock.calls[0]?.[0];
45
+ const globalController = new AbortController();
46
+ const requestController = new AbortController();
47
+ requestController.abort();
48
+ const request = await runWithMcpToolDeadlineContext(globalController.signal, async () => requestInterceptor({ signal: requestController.signal }));
49
+ expect(request.signal?.aborted).toBe(true);
50
+ });
51
+ it("keeps the provider request timeout at 30 seconds", () => {
52
+ createVtexClient({ apiKey: "key", apiToken: "token" }, "https://vtex.test");
53
+ expect(vi.mocked(axios.create)).toHaveBeenCalledWith(expect.objectContaining({ timeout: 3e4 }));
54
+ });
55
+ it("aborts an in-flight mutating POST through the instrumented client", async () => {
56
+ const server = createServer((_request, response) => setTimeout(() => response.end('{"Id":801}'), 100));
57
+ await new Promise((resolve) => server.listen(0, resolve));
58
+ const address = server.address();
59
+ const client = createVtexClient({ apiKey: "key", apiToken: "token" }, `http://127.0.0.1:${address.port}`);
60
+ const controller = new AbortController();
61
+ const post = runWithMcpToolDeadlineContext(controller.signal, () => client.post("/api/catalog/pvt/stockkeepingunit", { Name: "SKU" }));
62
+ setTimeout(() => controller.abort(), 10);
63
+ await expect(post).rejects.toMatchObject({ code: "ERR_CANCELED" });
64
+ server.close();
65
+ });
66
+ });
67
+ //# sourceMappingURL=vtex-api.test.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/services/vtex/__tests__/vtex-api.test.ts"],
4
+ "sourcesContent": ["import { beforeEach, describe, expect, it, vi } from \"vitest\";\nimport { createServer } from \"node:http\";\n\nconst requestUse = vi.fn();\nvi.mock(\"axios\", async () => {\n const actual = await vi.importActual<typeof import(\"axios\")>(\"axios\");\n return {\n ...actual,\n default: {\n ...actual.default,\n create: vi.fn((...args: Parameters<typeof actual.default.create>) => {\n const client = actual.default.create(...args);\n const use = client.interceptors.request.use.bind(client.interceptors.request);\n client.interceptors.request.use = (handler, ...rest) => {\n requestUse(handler);\n return use(handler, ...rest);\n };\n return client;\n }),\n },\n };\n});\n\nimport axios from \"axios\";\nimport { runWithMcpToolDeadlineContext } from \"../../../config/mcp-tool-deadline-context.js\";\nimport { createVtexClient } from \"../vtex-api.js\";\n\ndescribe(\"VTEX Axios deadline propagation\", () => {\n beforeEach(() => {\n vi.clearAllMocks();\n });\n\n it(\"composes the global signal and propagates abort to the Axios request signal\", async () => {\n createVtexClient({ apiKey: \"key\", apiToken: \"token\" } as never, \"https://vtex.test\");\n const requestInterceptor = requestUse.mock.calls[0]?.[0] as (config: { signal?: AbortSignal }) => { signal?: AbortSignal };\n const globalController = new AbortController();\n const requestController = new AbortController();\n const request = await runWithMcpToolDeadlineContext(globalController.signal, async () => requestInterceptor({ signal: requestController.signal }));\n expect(request.signal).toBeDefined();\n expect(request.signal).not.toBe(globalController.signal);\n expect(request.signal).not.toBe(requestController.signal);\n expect(request.signal?.aborted).toBe(false);\n\n globalController.abort();\n expect(request.signal?.aborted).toBe(true);\n });\n\n it(\"keeps the composed signal aborted when the request signal was already aborted\", async () => {\n createVtexClient({ apiKey: \"key\", apiToken: \"token\" } as never, \"https://vtex.test\");\n const requestInterceptor = requestUse.mock.calls[0]?.[0] as (config: { signal?: AbortSignal }) => { signal?: AbortSignal };\n const globalController = new AbortController();\n const requestController = new AbortController();\n requestController.abort();\n const request = await runWithMcpToolDeadlineContext(globalController.signal, async () => requestInterceptor({ signal: requestController.signal }));\n expect(request.signal?.aborted).toBe(true);\n });\n\n it(\"keeps the provider request timeout at 30 seconds\", () => {\n createVtexClient({ apiKey: \"key\", apiToken: \"token\" } as never, \"https://vtex.test\");\n expect(vi.mocked(axios.create)).toHaveBeenCalledWith(expect.objectContaining({ timeout: 30000 }));\n });\n\n it(\"aborts an in-flight mutating POST through the instrumented client\", async () => {\n const server = createServer((_request, response) => setTimeout(() => response.end('{\"Id\":801}'), 100));\n await new Promise<void>((resolve) => server.listen(0, resolve));\n const address = server.address();\n const client = createVtexClient({ apiKey: \"key\", apiToken: \"token\" } as never, `http://127.0.0.1:${(address as { port: number }).port}`);\n const controller = new AbortController();\n const post = runWithMcpToolDeadlineContext(controller.signal, () => client.post(\"/api/catalog/pvt/stockkeepingunit\", { Name: \"SKU\" }));\n setTimeout(() => controller.abort(), 10);\n await expect(post).rejects.toMatchObject({ code: \"ERR_CANCELED\" });\n server.close();\n });\n});\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -1,5 +1,6 @@
1
1
  import axios from "axios";
2
2
  import { getVtexConfigForProfile } from "../../config/vtex.js";
3
+ import { composeMcpToolDeadlineSignal } from "../../config/mcp-tool-deadline-context.js";
3
4
  function createVtexClient(config, baseURL) {
4
5
  const client = axios.create({
5
6
  baseURL,
@@ -11,6 +12,11 @@ function createVtexClient(config, baseURL) {
11
12
  },
12
13
  timeout: 3e4
13
14
  });
15
+ client.interceptors.request.use((request) => {
16
+ const signal = composeMcpToolDeadlineSignal(request.signal);
17
+ if (signal) request.signal = signal;
18
+ return request;
19
+ });
14
20
  client.interceptors.response.use(
15
21
  (response) => response,
16
22
  (error) => {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/services/vtex/vtex-api.ts"],
4
- "sourcesContent": ["import axios from \"axios\";\nimport type { AxiosError, AxiosInstance } from \"axios\";\n\nimport { getVtexConfigForProfile, type VtexConfig } from \"../../config/vtex.js\";\n\nexport function createVtexClient(config: VtexConfig, baseURL: string): AxiosInstance {\n const client = axios.create({\n baseURL,\n headers: {\n \"X-VTEX-API-AppKey\": config.apiKey,\n \"X-VTEX-API-AppToken\": config.apiToken,\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n },\n timeout: 30000,\n });\n\n client.interceptors.response.use(\n (response) => response,\n (error: AxiosError) => {\n const method = error.config?.method?.toUpperCase() ?? \"UNKNOWN\";\n const url = error.config?.url ?? \"UNKNOWN_URL\";\n const status = error.response?.status ?? \"NO_STATUS\";\n\n console.error(`[VTEX API ERROR] ${method} ${url} -> ${status}`);\n\n if (error.response?.data) {\n console.error(\"[VTEX API ERROR BODY]\", error.response.data);\n }\n\n return Promise.reject(error);\n }\n );\n\n return client;\n}\n\nexport async function getVtexApiClients(profileId: string) {\n const config = await getVtexConfigForProfile(profileId);\n\n return {\n config,\n vtexApi: createVtexClient(config, config.baseUrl),\n vtexPricingApi: createVtexClient(config, config.pricingBaseUrl),\n };\n}\n\nexport async function validateVtexConfig(config: VtexConfig): Promise<void> {\n const client = createVtexClient(config, config.baseUrl);\n await client.get(\"/api/oms/pvt/orders\", {\n params: {\n page: 1,\n per_page: 1,\n },\n });\n}\n\nexport function formatVtexError(error: unknown, fallback = \"Unexpected VTEX API error\"): string {\n if (axios.isAxiosError(error)) {\n const status = error.response?.status;\n const responseData = error.response?.data;\n const responseMessage =\n typeof responseData === \"object\" && responseData !== null && \"message\" in responseData\n ? String((responseData as { message?: unknown }).message)\n : typeof responseData === \"string\"\n ? responseData\n : undefined;\n\n if (status) {\n return `VTEX API request failed (${status}): ${responseMessage ?? error.message}`;\n }\n\n return `VTEX API request failed: ${responseMessage ?? error.message}`;\n }\n\n if (error instanceof Error) {\n return error.message;\n }\n\n return fallback;\n}\n"],
5
- "mappings": "AAAA,OAAO,WAAW;AAGlB,SAAS,+BAAgD;AAElD,SAAS,iBAAiB,QAAoB,SAAgC;AACnF,QAAM,SAAS,MAAM,OAAO;AAAA,IAC1B;AAAA,IACA,SAAS;AAAA,MACP,qBAAqB,OAAO;AAAA,MAC5B,uBAAuB,OAAO;AAAA,MAC9B,QAAQ;AAAA,MACR,gBAAgB;AAAA,IAClB;AAAA,IACA,SAAS;AAAA,EACX,CAAC;AAED,SAAO,aAAa,SAAS;AAAA,IAC3B,CAAC,aAAa;AAAA,IACd,CAAC,UAAsB;AACrB,YAAM,SAAS,MAAM,QAAQ,QAAQ,YAAY,KAAK;AACtD,YAAM,MAAM,MAAM,QAAQ,OAAO;AACjC,YAAM,SAAS,MAAM,UAAU,UAAU;AAEzC,cAAQ,MAAM,oBAAoB,MAAM,IAAI,GAAG,OAAO,MAAM,EAAE;AAE9D,UAAI,MAAM,UAAU,MAAM;AACxB,gBAAQ,MAAM,yBAAyB,MAAM,SAAS,IAAI;AAAA,MAC5D;AAEA,aAAO,QAAQ,OAAO,KAAK;AAAA,IAC7B;AAAA,EACF;AAEA,SAAO;AACT;AAEA,eAAsB,kBAAkB,WAAmB;AACzD,QAAM,SAAS,MAAM,wBAAwB,SAAS;AAEtD,SAAO;AAAA,IACL;AAAA,IACA,SAAS,iBAAiB,QAAQ,OAAO,OAAO;AAAA,IAChD,gBAAgB,iBAAiB,QAAQ,OAAO,cAAc;AAAA,EAChE;AACF;AAEA,eAAsB,mBAAmB,QAAmC;AAC1E,QAAM,SAAS,iBAAiB,QAAQ,OAAO,OAAO;AACtD,QAAM,OAAO,IAAI,uBAAuB;AAAA,IACtC,QAAQ;AAAA,MACN,MAAM;AAAA,MACN,UAAU;AAAA,IACZ;AAAA,EACF,CAAC;AACH;AAEO,SAAS,gBAAgB,OAAgB,WAAW,6BAAqC;AAC9F,MAAI,MAAM,aAAa,KAAK,GAAG;AAC7B,UAAM,SAAS,MAAM,UAAU;AAC/B,UAAM,eAAe,MAAM,UAAU;AACrC,UAAM,kBACJ,OAAO,iBAAiB,YAAY,iBAAiB,QAAQ,aAAa,eACtE,OAAQ,aAAuC,OAAO,IACtD,OAAO,iBAAiB,WACtB,eACA;AAER,QAAI,QAAQ;AACV,aAAO,4BAA4B,MAAM,MAAM,mBAAmB,MAAM,OAAO;AAAA,IACjF;AAEA,WAAO,4BAA4B,mBAAmB,MAAM,OAAO;AAAA,EACrE;AAEA,MAAI,iBAAiB,OAAO;AAC1B,WAAO,MAAM;AAAA,EACf;AAEA,SAAO;AACT;",
4
+ "sourcesContent": ["import axios from \"axios\";\nimport type { AxiosError, AxiosInstance } from \"axios\";\n\nimport { getVtexConfigForProfile, type VtexConfig } from \"../../config/vtex.js\";\nimport { composeMcpToolDeadlineSignal } from \"../../config/mcp-tool-deadline-context.js\";\n\nexport function createVtexClient(config: VtexConfig, baseURL: string): AxiosInstance {\n const client = axios.create({\n baseURL,\n headers: {\n \"X-VTEX-API-AppKey\": config.apiKey,\n \"X-VTEX-API-AppToken\": config.apiToken,\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n },\n timeout: 30000,\n });\n\n client.interceptors.request.use((request) => {\n const signal = composeMcpToolDeadlineSignal(request.signal);\n if (signal) request.signal = signal;\n return request;\n });\n\n client.interceptors.response.use(\n (response) => response,\n (error: AxiosError) => {\n const method = error.config?.method?.toUpperCase() ?? \"UNKNOWN\";\n const url = error.config?.url ?? \"UNKNOWN_URL\";\n const status = error.response?.status ?? \"NO_STATUS\";\n\n console.error(`[VTEX API ERROR] ${method} ${url} -> ${status}`);\n\n if (error.response?.data) {\n console.error(\"[VTEX API ERROR BODY]\", error.response.data);\n }\n\n return Promise.reject(error);\n }\n );\n\n return client;\n}\n\nexport async function getVtexApiClients(profileId: string) {\n const config = await getVtexConfigForProfile(profileId);\n\n return {\n config,\n vtexApi: createVtexClient(config, config.baseUrl),\n vtexPricingApi: createVtexClient(config, config.pricingBaseUrl),\n };\n}\n\nexport async function validateVtexConfig(config: VtexConfig): Promise<void> {\n const client = createVtexClient(config, config.baseUrl);\n await client.get(\"/api/oms/pvt/orders\", {\n params: {\n page: 1,\n per_page: 1,\n },\n });\n}\n\nexport function formatVtexError(error: unknown, fallback = \"Unexpected VTEX API error\"): string {\n if (axios.isAxiosError(error)) {\n const status = error.response?.status;\n const responseData = error.response?.data;\n const responseMessage =\n typeof responseData === \"object\" && responseData !== null && \"message\" in responseData\n ? String((responseData as { message?: unknown }).message)\n : typeof responseData === \"string\"\n ? responseData\n : undefined;\n\n if (status) {\n return `VTEX API request failed (${status}): ${responseMessage ?? error.message}`;\n }\n\n return `VTEX API request failed: ${responseMessage ?? error.message}`;\n }\n\n if (error instanceof Error) {\n return error.message;\n }\n\n return fallback;\n}\n"],
5
+ "mappings": "AAAA,OAAO,WAAW;AAGlB,SAAS,+BAAgD;AACzD,SAAS,oCAAoC;AAEtC,SAAS,iBAAiB,QAAoB,SAAgC;AACnF,QAAM,SAAS,MAAM,OAAO;AAAA,IAC1B;AAAA,IACA,SAAS;AAAA,MACP,qBAAqB,OAAO;AAAA,MAC5B,uBAAuB,OAAO;AAAA,MAC9B,QAAQ;AAAA,MACR,gBAAgB;AAAA,IAClB;AAAA,IACA,SAAS;AAAA,EACX,CAAC;AAED,SAAO,aAAa,QAAQ,IAAI,CAAC,YAAY;AAC3C,UAAM,SAAS,6BAA6B,QAAQ,MAAM;AAC1D,QAAI,OAAQ,SAAQ,SAAS;AAC7B,WAAO;AAAA,EACT,CAAC;AAED,SAAO,aAAa,SAAS;AAAA,IAC3B,CAAC,aAAa;AAAA,IACd,CAAC,UAAsB;AACrB,YAAM,SAAS,MAAM,QAAQ,QAAQ,YAAY,KAAK;AACtD,YAAM,MAAM,MAAM,QAAQ,OAAO;AACjC,YAAM,SAAS,MAAM,UAAU,UAAU;AAEzC,cAAQ,MAAM,oBAAoB,MAAM,IAAI,GAAG,OAAO,MAAM,EAAE;AAE9D,UAAI,MAAM,UAAU,MAAM;AACxB,gBAAQ,MAAM,yBAAyB,MAAM,SAAS,IAAI;AAAA,MAC5D;AAEA,aAAO,QAAQ,OAAO,KAAK;AAAA,IAC7B;AAAA,EACF;AAEA,SAAO;AACT;AAEA,eAAsB,kBAAkB,WAAmB;AACzD,QAAM,SAAS,MAAM,wBAAwB,SAAS;AAEtD,SAAO;AAAA,IACL;AAAA,IACA,SAAS,iBAAiB,QAAQ,OAAO,OAAO;AAAA,IAChD,gBAAgB,iBAAiB,QAAQ,OAAO,cAAc;AAAA,EAChE;AACF;AAEA,eAAsB,mBAAmB,QAAmC;AAC1E,QAAM,SAAS,iBAAiB,QAAQ,OAAO,OAAO;AACtD,QAAM,OAAO,IAAI,uBAAuB;AAAA,IACtC,QAAQ;AAAA,MACN,MAAM;AAAA,MACN,UAAU;AAAA,IACZ;AAAA,EACF,CAAC;AACH;AAEO,SAAS,gBAAgB,OAAgB,WAAW,6BAAqC;AAC9F,MAAI,MAAM,aAAa,KAAK,GAAG;AAC7B,UAAM,SAAS,MAAM,UAAU;AAC/B,UAAM,eAAe,MAAM,UAAU;AACrC,UAAM,kBACJ,OAAO,iBAAiB,YAAY,iBAAiB,QAAQ,aAAa,eACtE,OAAQ,aAAuC,OAAO,IACtD,OAAO,iBAAiB,WACtB,eACA;AAER,QAAI,QAAQ;AACV,aAAO,4BAA4B,MAAM,MAAM,mBAAmB,MAAM,OAAO;AAAA,IACjF;AAEA,WAAO,4BAA4B,mBAAmB,MAAM,OAAO;AAAA,EACrE;AAEA,MAAI,iBAAiB,OAAO;AAC1B,WAAO,MAAM;AAAA,EACf;AAEA,SAAO;AACT;",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,154 @@
1
+ import { beforeEach, describe, expect, it, vi } from "vitest";
2
+ const objectMock = vi.fn((value) => ({ kind: "object", value }));
3
+ const errorMock = vi.fn((message) => ({ kind: "error", message }));
4
+ const listProfilesMock = vi.fn();
5
+ const listGoogleMappingsMock = vi.fn();
6
+ const listGtmSummariesMock = vi.fn();
7
+ const getGoogleOAuthConnectionMock = vi.fn();
8
+ const listVtexConnectionsMock = vi.fn();
9
+ const listMercadolibreConnectionsMock = vi.fn();
10
+ const listMetaMappingsMock = vi.fn();
11
+ vi.mock("mcp-use/server", () => ({ object: objectMock, error: errorMock }));
12
+ vi.mock("../../../config/profile-store.js", () => ({
13
+ listProfiles: listProfilesMock
14
+ }));
15
+ vi.mock("../../../config/google-store.js", () => ({
16
+ listProfileGoogleServiceMappings: listGoogleMappingsMock,
17
+ listActiveProfileGtmMappingSummaries: listGtmSummariesMock,
18
+ getGoogleOAuthConnection: getGoogleOAuthConnectionMock
19
+ }));
20
+ vi.mock("../../../config/vtex-profile-store.js", () => ({
21
+ listVtexConnections: listVtexConnectionsMock
22
+ }));
23
+ vi.mock("../../../config/mercadolibre-profile-store.js", () => ({
24
+ listMercadoLibreConnections: listMercadolibreConnectionsMock
25
+ }));
26
+ vi.mock("../../../config/meta-store.js", () => ({
27
+ listProfileMetaMappings: listMetaMappingsMock
28
+ }));
29
+ const { listProfilesHandler } = await import("../list-profiles.js");
30
+ const requiredScopes = [
31
+ "tagmanager.manage.accounts",
32
+ "tagmanager.edit.containers",
33
+ "tagmanager.delete.containers",
34
+ "tagmanager.edit.containerversions",
35
+ "tagmanager.manage.users",
36
+ "tagmanager.publish",
37
+ "tagmanager.readonly"
38
+ ].map((scope) => `https://www.googleapis.com/auth/${scope}`);
39
+ function connection(overrides = {}) {
40
+ return {
41
+ id: "global",
42
+ encryptedRefreshToken: "encrypted-token",
43
+ scopes: requiredScopes,
44
+ status: "active",
45
+ googleAccountEmail: null,
46
+ lastValidatedAt: null,
47
+ lastError: null,
48
+ ...overrides
49
+ };
50
+ }
51
+ async function getGtmService() {
52
+ const response = await listProfilesHandler();
53
+ return response.value.profiles[0].services.google.gtm;
54
+ }
55
+ describe("config_list_profiles GTM readiness", () => {
56
+ beforeEach(() => {
57
+ vi.clearAllMocks();
58
+ listProfilesMock.mockResolvedValue([
59
+ {
60
+ id: "profile-1",
61
+ name: "Alpha",
62
+ isActive: true,
63
+ createdAt: /* @__PURE__ */ new Date("2026-01-01T00:00:00.000Z"),
64
+ updatedAt: /* @__PURE__ */ new Date("2026-01-02T00:00:00.000Z")
65
+ }
66
+ ]);
67
+ listGoogleMappingsMock.mockResolvedValue([]);
68
+ listGtmSummariesMock.mockResolvedValue([
69
+ { profileId: "profile-1", activeMappingCount: 2 }
70
+ ]);
71
+ getGoogleOAuthConnectionMock.mockResolvedValue(connection());
72
+ listVtexConnectionsMock.mockResolvedValue([]);
73
+ listMercadolibreConnectionsMock.mockResolvedValue([]);
74
+ listMetaMappingsMock.mockResolvedValue([]);
75
+ });
76
+ it("adds active GTM readiness without leaking mapped resource identifiers", async () => {
77
+ const response = await listProfilesHandler();
78
+ const profile = response.value.profiles[0];
79
+ expect(profile).toMatchObject({
80
+ profile_id: "profile-1",
81
+ name: "Alpha",
82
+ is_active: true,
83
+ created_at: "2026-01-01T00:00:00.000Z",
84
+ updated_at: "2026-01-02T00:00:00.000Z",
85
+ services: {
86
+ google: {
87
+ google_ads: {
88
+ configured: false,
89
+ status: "not_configured",
90
+ raw_status: null
91
+ },
92
+ ga4: {
93
+ configured: false,
94
+ status: "not_configured",
95
+ raw_status: null
96
+ },
97
+ search_console: {
98
+ configured: false,
99
+ status: "not_configured",
100
+ raw_status: null
101
+ }
102
+ },
103
+ vtex: { configured: false, status: "not_configured", raw_status: null },
104
+ mercadolibre: {
105
+ configured: false,
106
+ status: "not_configured",
107
+ raw_status: null
108
+ },
109
+ meta: { configured: false, status: "not_configured", raw_status: null }
110
+ }
111
+ });
112
+ expect(
113
+ profile.services.google.gtm
114
+ ).toEqual({
115
+ configured: true,
116
+ status: "active",
117
+ raw_status: "active"
118
+ });
119
+ expect(JSON.stringify(profile)).not.toContain("account");
120
+ expect(JSON.stringify(profile)).not.toContain("container");
121
+ });
122
+ it("reports not_configured and hides OAuth raw status without active mappings", async () => {
123
+ listGtmSummariesMock.mockResolvedValue([]);
124
+ await expect(getGtmService()).resolves.toEqual({
125
+ configured: false,
126
+ status: "not_configured",
127
+ raw_status: null
128
+ });
129
+ });
130
+ it.each(["disabled", "expired", "pending", "error"])(
131
+ "normalizes an eligible mapping with OAuth status %s",
132
+ async (status) => {
133
+ getGoogleOAuthConnectionMock.mockResolvedValue(connection({ status }));
134
+ await expect(getGtmService()).resolves.toEqual({
135
+ configured: true,
136
+ status,
137
+ raw_status: status
138
+ });
139
+ }
140
+ );
141
+ it.each([
142
+ ["missing connection", null],
143
+ ["missing token", connection({ encryptedRefreshToken: null })],
144
+ ["incomplete scopes", connection({ scopes: requiredScopes.slice(0, -1) })]
145
+ ])("reports error for %s", async (_case, oauthConnection) => {
146
+ getGoogleOAuthConnectionMock.mockResolvedValue(oauthConnection);
147
+ await expect(getGtmService()).resolves.toEqual({
148
+ configured: true,
149
+ status: "error",
150
+ raw_status: oauthConnection ? "active" : null
151
+ });
152
+ });
153
+ });
154
+ //# sourceMappingURL=list-profiles.test.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/tools/config/__tests__/list-profiles.test.ts"],
4
+ "sourcesContent": ["import { beforeEach, describe, expect, it, vi } from \"vitest\";\n\nconst objectMock = vi.fn((value) => ({ kind: \"object\", value }));\nconst errorMock = vi.fn((message) => ({ kind: \"error\", message }));\nconst listProfilesMock = vi.fn();\nconst listGoogleMappingsMock = vi.fn();\nconst listGtmSummariesMock = vi.fn();\nconst getGoogleOAuthConnectionMock = vi.fn();\nconst listVtexConnectionsMock = vi.fn();\nconst listMercadolibreConnectionsMock = vi.fn();\nconst listMetaMappingsMock = vi.fn();\n\nvi.mock(\"mcp-use/server\", () => ({ object: objectMock, error: errorMock }));\nvi.mock(\"../../../config/profile-store.js\", () => ({\n listProfiles: listProfilesMock,\n}));\nvi.mock(\"../../../config/google-store.js\", () => ({\n listProfileGoogleServiceMappings: listGoogleMappingsMock,\n listActiveProfileGtmMappingSummaries: listGtmSummariesMock,\n getGoogleOAuthConnection: getGoogleOAuthConnectionMock,\n}));\nvi.mock(\"../../../config/vtex-profile-store.js\", () => ({\n listVtexConnections: listVtexConnectionsMock,\n}));\nvi.mock(\"../../../config/mercadolibre-profile-store.js\", () => ({\n listMercadoLibreConnections: listMercadolibreConnectionsMock,\n}));\nvi.mock(\"../../../config/meta-store.js\", () => ({\n listProfileMetaMappings: listMetaMappingsMock,\n}));\n\nconst { listProfilesHandler } = await import(\"../list-profiles.js\");\nconst requiredScopes = [\n \"tagmanager.manage.accounts\",\n \"tagmanager.edit.containers\",\n \"tagmanager.delete.containers\",\n \"tagmanager.edit.containerversions\",\n \"tagmanager.manage.users\",\n \"tagmanager.publish\",\n \"tagmanager.readonly\",\n].map((scope) => `https://www.googleapis.com/auth/${scope}`);\n\nfunction connection(overrides: Record<string, unknown> = {}) {\n return {\n id: \"global\",\n encryptedRefreshToken: \"encrypted-token\",\n scopes: requiredScopes,\n status: \"active\",\n googleAccountEmail: null,\n lastValidatedAt: null,\n lastError: null,\n ...overrides,\n };\n}\n\nasync function getGtmService() {\n const response = await listProfilesHandler();\n return (\n response as unknown as {\n value: { profiles: Array<{ services: { google: { gtm: unknown } } }> };\n }\n ).value.profiles[0].services.google.gtm;\n}\n\ndescribe(\"config_list_profiles GTM readiness\", () => {\n beforeEach(() => {\n vi.clearAllMocks();\n listProfilesMock.mockResolvedValue([\n {\n id: \"profile-1\",\n name: \"Alpha\",\n isActive: true,\n createdAt: new Date(\"2026-01-01T00:00:00.000Z\"),\n updatedAt: new Date(\"2026-01-02T00:00:00.000Z\"),\n },\n ]);\n listGoogleMappingsMock.mockResolvedValue([]);\n listGtmSummariesMock.mockResolvedValue([\n { profileId: \"profile-1\", activeMappingCount: 2 },\n ]);\n getGoogleOAuthConnectionMock.mockResolvedValue(connection());\n listVtexConnectionsMock.mockResolvedValue([]);\n listMercadolibreConnectionsMock.mockResolvedValue([]);\n listMetaMappingsMock.mockResolvedValue([]);\n });\n\n it(\"adds active GTM readiness without leaking mapped resource identifiers\", async () => {\n const response = await listProfilesHandler();\n const profile = (\n response as unknown as {\n value: { profiles: Array<Record<string, unknown>> };\n }\n ).value.profiles[0];\n\n expect(profile).toMatchObject({\n profile_id: \"profile-1\",\n name: \"Alpha\",\n is_active: true,\n created_at: \"2026-01-01T00:00:00.000Z\",\n updated_at: \"2026-01-02T00:00:00.000Z\",\n services: {\n google: {\n google_ads: {\n configured: false,\n status: \"not_configured\",\n raw_status: null,\n },\n ga4: {\n configured: false,\n status: \"not_configured\",\n raw_status: null,\n },\n search_console: {\n configured: false,\n status: \"not_configured\",\n raw_status: null,\n },\n },\n vtex: { configured: false, status: \"not_configured\", raw_status: null },\n mercadolibre: {\n configured: false,\n status: \"not_configured\",\n raw_status: null,\n },\n meta: { configured: false, status: \"not_configured\", raw_status: null },\n },\n });\n expect(\n (profile.services as { google: { gtm: unknown } }).google.gtm,\n ).toEqual({\n configured: true,\n status: \"active\",\n raw_status: \"active\",\n });\n expect(JSON.stringify(profile)).not.toContain(\"account\");\n expect(JSON.stringify(profile)).not.toContain(\"container\");\n });\n\n it(\"reports not_configured and hides OAuth raw status without active mappings\", async () => {\n listGtmSummariesMock.mockResolvedValue([]);\n\n await expect(getGtmService()).resolves.toEqual({\n configured: false,\n status: \"not_configured\",\n raw_status: null,\n });\n });\n\n it.each([\"disabled\", \"expired\", \"pending\", \"error\"])(\n \"normalizes an eligible mapping with OAuth status %s\",\n async (status) => {\n getGoogleOAuthConnectionMock.mockResolvedValue(connection({ status }));\n\n await expect(getGtmService()).resolves.toEqual({\n configured: true,\n status,\n raw_status: status,\n });\n },\n );\n\n it.each([\n [\"missing connection\", null],\n [\"missing token\", connection({ encryptedRefreshToken: null })],\n [\"incomplete scopes\", connection({ scopes: requiredScopes.slice(0, -1) })],\n ])(\"reports error for %s\", async (_case, oauthConnection) => {\n getGoogleOAuthConnectionMock.mockResolvedValue(oauthConnection);\n\n await expect(getGtmService()).resolves.toEqual({\n configured: true,\n status: \"error\",\n raw_status: oauthConnection ? \"active\" : null,\n });\n });\n});\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -1,11 +1,31 @@
1
1
  import { error, object } from "mcp-use/server";
2
2
  import { z } from "zod";
3
- import { listProfileGoogleServiceMappings } from "../../config/google-store.js";
3
+ import {
4
+ getGoogleOAuthConnection,
5
+ listActiveProfileGtmMappingSummaries,
6
+ listProfileGoogleServiceMappings
7
+ } from "../../config/google-store.js";
4
8
  import { listMercadoLibreConnections } from "../../config/mercadolibre-profile-store.js";
5
9
  import { listProfileMetaMappings } from "../../config/meta-store.js";
6
10
  import { listProfiles } from "../../config/profile-store.js";
7
11
  import { listVtexConnections } from "../../config/vtex-profile-store.js";
8
12
  const listProfilesSchema = z.object({});
13
+ const REQUIRED_GTM_SCOPES = [
14
+ "https://www.googleapis.com/auth/tagmanager.manage.accounts",
15
+ "https://www.googleapis.com/auth/tagmanager.edit.containers",
16
+ "https://www.googleapis.com/auth/tagmanager.delete.containers",
17
+ "https://www.googleapis.com/auth/tagmanager.edit.containerversions",
18
+ "https://www.googleapis.com/auth/tagmanager.manage.users",
19
+ "https://www.googleapis.com/auth/tagmanager.publish",
20
+ "https://www.googleapis.com/auth/tagmanager.readonly"
21
+ ];
22
+ function getGtmStatus(configured, connection) {
23
+ if (!configured) return "not_configured";
24
+ if (!connection) return "error";
25
+ if (connection.status !== "active") return connection.status;
26
+ if (!connection.encryptedRefreshToken) return "error";
27
+ return REQUIRED_GTM_SCOPES.every((scope) => connection.scopes.includes(scope)) ? "active" : "error";
28
+ }
9
29
  function normalizeVtexStatus(status) {
10
30
  switch (status) {
11
31
  case "valid":
@@ -26,13 +46,17 @@ async function listProfilesHandler() {
26
46
  mappings,
27
47
  vtexConnections,
28
48
  mercadolibreConnections,
29
- metaMappings
49
+ metaMappings,
50
+ gtmMappingSummaries,
51
+ googleOAuthConnection
30
52
  ] = await Promise.all([
31
53
  listProfiles({ activeOnly: true }),
32
54
  listProfileGoogleServiceMappings(),
33
55
  listVtexConnections(),
34
56
  listMercadoLibreConnections(),
35
- listProfileMetaMappings()
57
+ listProfileMetaMappings(),
58
+ listActiveProfileGtmMappingSummaries(),
59
+ getGoogleOAuthConnection()
36
60
  ]);
37
61
  const mappingsByProfileId = new Map(
38
62
  mappings.map((mapping) => [mapping.profileId, mapping])
@@ -49,6 +73,12 @@ async function listProfilesHandler() {
49
73
  const metaByProfileId = new Map(
50
74
  metaMappings.map((mapping) => [mapping.profileId, mapping])
51
75
  );
76
+ const gtmMappingCountByProfileId = new Map(
77
+ gtmMappingSummaries.map((summary) => [
78
+ summary.profileId,
79
+ summary.activeMappingCount
80
+ ])
81
+ );
52
82
  return object({
53
83
  total_profiles: profiles.length,
54
84
  profiles: profiles.map((profile) => {
@@ -59,6 +89,7 @@ async function listProfilesHandler() {
59
89
  const metaConfigured = Boolean(
60
90
  metaMapping?.metaBusinessId && metaMapping.status === "active"
61
91
  );
92
+ const gtmConfigured = (gtmMappingCountByProfileId.get(profile.id) ?? 0) > 0;
62
93
  return {
63
94
  profile_id: profile.id,
64
95
  name: profile.name,
@@ -81,6 +112,11 @@ async function listProfilesHandler() {
81
112
  configured: Boolean(mapping?.searchConsoleSiteUrl),
82
113
  status: mapping?.searchConsoleSiteUrl ? mapping.searchConsoleStatus : "not_configured",
83
114
  raw_status: mapping?.searchConsoleSiteUrl ? mapping.searchConsoleStatus : null
115
+ },
116
+ gtm: {
117
+ configured: gtmConfigured,
118
+ status: getGtmStatus(gtmConfigured, googleOAuthConnection),
119
+ raw_status: gtmConfigured ? googleOAuthConnection?.status ?? null : null
84
120
  }
85
121
  },
86
122
  vtex: {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/tools/config/list-profiles.ts"],
4
- "sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\nimport { listProfileGoogleServiceMappings } from \"../../config/google-store.js\";\nimport { listMercadoLibreConnections } from \"../../config/mercadolibre-profile-store.js\";\nimport { listProfileMetaMappings } from \"../../config/meta-store.js\";\nimport { listProfiles } from \"../../config/profile-store.js\";\nimport { listVtexConnections } from \"../../config/vtex-profile-store.js\";\n\nexport const listProfilesSchema = z.object({});\n\ntype NormalizedServiceStatus =\n\t| \"active\"\n\t| \"disabled\"\n\t| \"expired\"\n\t| \"error\"\n\t| \"pending\"\n\t| \"not_configured\";\n\nfunction normalizeVtexStatus(\n\tstatus: \"pending\" | \"valid\" | \"invalid\" | \"disabled\",\n): Exclude<NormalizedServiceStatus, \"expired\" | \"not_configured\"> {\n\tswitch (status) {\n\t\tcase \"valid\":\n\t\t\treturn \"active\";\n\t\tcase \"invalid\":\n\t\t\treturn \"error\";\n\t\tcase \"disabled\":\n\t\t\treturn \"disabled\";\n\t\tcase \"pending\":\n\t\tdefault:\n\t\t\treturn \"pending\";\n\t}\n}\n\nexport async function listProfilesHandler() {\n\ttry {\n\t\tconst [\n\t\t\tprofiles,\n\t\t\tmappings,\n\t\t\tvtexConnections,\n\t\t\tmercadolibreConnections,\n\t\t\tmetaMappings,\n\t\t] = await Promise.all([\n\t\t\tlistProfiles({ activeOnly: true }),\n\t\t\tlistProfileGoogleServiceMappings(),\n\t\t\tlistVtexConnections(),\n\t\t\tlistMercadoLibreConnections(),\n\t\t\tlistProfileMetaMappings(),\n\t\t]);\n\t\tconst mappingsByProfileId = new Map(\n\t\t\tmappings.map((mapping) => [mapping.profileId, mapping]),\n\t\t);\n\t\tconst vtexByProfileId = new Map(\n\t\t\tvtexConnections.map((connection) => [connection.profileId, connection]),\n\t\t);\n\t\tconst mercadolibreByProfileId = new Map(\n\t\t\tmercadolibreConnections.map((connection) => [\n\t\t\t\tconnection.profileId,\n\t\t\t\tconnection,\n\t\t\t]),\n\t\t);\n\t\tconst metaByProfileId = new Map(\n\t\t\tmetaMappings.map((mapping) => [mapping.profileId, mapping]),\n\t\t);\n\t\treturn object({\n\t\t\ttotal_profiles: profiles.length,\n\t\t\tprofiles: profiles.map((profile) => {\n\t\t\t\tconst mapping = mappingsByProfileId.get(profile.id);\n\t\t\t\tconst vtexConnection = vtexByProfileId.get(profile.id);\n\t\t\t\tconst mercadolibreConnection = mercadolibreByProfileId.get(profile.id);\n\t\t\t\tconst metaMapping = metaByProfileId.get(profile.id);\n\t\t\t\tconst metaConfigured = Boolean(\n\t\t\t\t\tmetaMapping?.metaBusinessId && metaMapping.status === \"active\",\n\t\t\t\t);\n\t\t\t\treturn {\n\t\t\t\t\tprofile_id: profile.id,\n\t\t\t\t\tname: profile.name,\n\t\t\t\t\tis_active: profile.isActive,\n\t\t\t\t\tcreated_at: profile.createdAt.toISOString(),\n\t\t\t\t\tupdated_at: profile.updatedAt.toISOString(),\n\t\t\t\t\tservices: {\n\t\t\t\t\t\tgoogle: {\n\t\t\t\t\t\t\tgoogle_ads: {\n\t\t\t\t\t\t\t\tconfigured: Boolean(mapping?.googleAdsCustomerId),\n\t\t\t\t\t\t\t\tstatus: mapping?.googleAdsCustomerId\n\t\t\t\t\t\t\t\t\t? mapping.googleAdsStatus\n\t\t\t\t\t\t\t\t\t: \"not_configured\",\n\t\t\t\t\t\t\t\traw_status: mapping?.googleAdsCustomerId\n\t\t\t\t\t\t\t\t\t? mapping.googleAdsStatus\n\t\t\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tga4: {\n\t\t\t\t\t\t\t\tconfigured: Boolean(mapping?.ga4PropertyId),\n\t\t\t\t\t\t\t\tstatus: mapping?.ga4PropertyId\n\t\t\t\t\t\t\t\t\t? mapping.ga4Status\n\t\t\t\t\t\t\t\t\t: \"not_configured\",\n\t\t\t\t\t\t\t\traw_status: mapping?.ga4PropertyId ? mapping.ga4Status : null,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tsearch_console: {\n\t\t\t\t\t\t\t\tconfigured: Boolean(mapping?.searchConsoleSiteUrl),\n\t\t\t\t\t\t\t\tstatus: mapping?.searchConsoleSiteUrl\n\t\t\t\t\t\t\t\t\t? mapping.searchConsoleStatus\n\t\t\t\t\t\t\t\t\t: \"not_configured\",\n\t\t\t\t\t\t\t\traw_status: mapping?.searchConsoleSiteUrl\n\t\t\t\t\t\t\t\t\t? mapping.searchConsoleStatus\n\t\t\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tvtex: {\n\t\t\t\t\t\t\tconfigured: Boolean(vtexConnection),\n\t\t\t\t\t\t\tstatus: vtexConnection\n\t\t\t\t\t\t\t\t? normalizeVtexStatus(vtexConnection.status)\n\t\t\t\t\t\t\t\t: \"not_configured\",\n\t\t\t\t\t\t\traw_status: vtexConnection ? vtexConnection.status : null,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tmercadolibre: {\n\t\t\t\t\t\t\tconfigured: Boolean(mercadolibreConnection),\n\t\t\t\t\t\t\tstatus: mercadolibreConnection\n\t\t\t\t\t\t\t\t? mercadolibreConnection.status\n\t\t\t\t\t\t\t\t: \"not_configured\",\n\t\t\t\t\t\t\traw_status: mercadolibreConnection\n\t\t\t\t\t\t\t\t? mercadolibreConnection.status\n\t\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tmeta: {\n\t\t\t\t\t\t\tconfigured: metaConfigured,\n\t\t\t\t\t\t\tstatus: metaConfigured\n\t\t\t\t\t\t\t\t? (metaMapping?.status ?? \"not_configured\")\n\t\t\t\t\t\t\t\t: \"not_configured\",\n\t\t\t\t\t\t\traw_status: metaMapping?.status ?? null,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}),\n\t\t});\n\t} catch (err) {\n\t\treturn error(\n\t\t\terr instanceof Error ? err.message : \"Failed to list profiles\",\n\t\t);\n\t}\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\nimport {\n\tgetGoogleOAuthConnection,\n\tlistActiveProfileGtmMappingSummaries,\n\tlistProfileGoogleServiceMappings,\n\ttype GoogleOAuthConnectionRecord,\n} from \"../../config/google-store.js\";\nimport { listMercadoLibreConnections } from \"../../config/mercadolibre-profile-store.js\";\nimport { listProfileMetaMappings } from \"../../config/meta-store.js\";\nimport { listProfiles } from \"../../config/profile-store.js\";\nimport { listVtexConnections } from \"../../config/vtex-profile-store.js\";\n\nexport const listProfilesSchema = z.object({});\n\ntype NormalizedServiceStatus =\n\t| \"active\"\n\t| \"disabled\"\n\t| \"expired\"\n\t| \"error\"\n\t| \"pending\"\n\t| \"not_configured\";\n\nconst REQUIRED_GTM_SCOPES = [\n\t\"https://www.googleapis.com/auth/tagmanager.manage.accounts\",\n\t\"https://www.googleapis.com/auth/tagmanager.edit.containers\",\n\t\"https://www.googleapis.com/auth/tagmanager.delete.containers\",\n\t\"https://www.googleapis.com/auth/tagmanager.edit.containerversions\",\n\t\"https://www.googleapis.com/auth/tagmanager.manage.users\",\n\t\"https://www.googleapis.com/auth/tagmanager.publish\",\n\t\"https://www.googleapis.com/auth/tagmanager.readonly\",\n] as const;\n\nfunction getGtmStatus(\n\tconfigured: boolean,\n\tconnection: GoogleOAuthConnectionRecord | null,\n): NormalizedServiceStatus {\n\tif (!configured) return \"not_configured\";\n\tif (!connection) return \"error\";\n\tif (connection.status !== \"active\") return connection.status;\n\tif (!connection.encryptedRefreshToken) return \"error\";\n\treturn REQUIRED_GTM_SCOPES.every((scope) => connection.scopes.includes(scope))\n\t\t? \"active\"\n\t\t: \"error\";\n}\n\nfunction normalizeVtexStatus(\n\tstatus: \"pending\" | \"valid\" | \"invalid\" | \"disabled\",\n): Exclude<NormalizedServiceStatus, \"expired\" | \"not_configured\"> {\n\tswitch (status) {\n\t\tcase \"valid\":\n\t\t\treturn \"active\";\n\t\tcase \"invalid\":\n\t\t\treturn \"error\";\n\t\tcase \"disabled\":\n\t\t\treturn \"disabled\";\n\t\tcase \"pending\":\n\t\tdefault:\n\t\t\treturn \"pending\";\n\t}\n}\n\nexport async function listProfilesHandler() {\n\ttry {\n\t\tconst [\n\t\t\tprofiles,\n\t\t\tmappings,\n\t\t\tvtexConnections,\n\t\t\tmercadolibreConnections,\n\t\t\tmetaMappings,\n\t\t\tgtmMappingSummaries,\n\t\t\tgoogleOAuthConnection,\n\t\t] = await Promise.all([\n\t\t\tlistProfiles({ activeOnly: true }),\n\t\t\tlistProfileGoogleServiceMappings(),\n\t\t\tlistVtexConnections(),\n\t\t\tlistMercadoLibreConnections(),\n\t\t\tlistProfileMetaMappings(),\n\t\t\tlistActiveProfileGtmMappingSummaries(),\n\t\t\tgetGoogleOAuthConnection(),\n\t\t]);\n\t\tconst mappingsByProfileId = new Map(\n\t\t\tmappings.map((mapping) => [mapping.profileId, mapping]),\n\t\t);\n\t\tconst vtexByProfileId = new Map(\n\t\t\tvtexConnections.map((connection) => [connection.profileId, connection]),\n\t\t);\n\t\tconst mercadolibreByProfileId = new Map(\n\t\t\tmercadolibreConnections.map((connection) => [\n\t\t\t\tconnection.profileId,\n\t\t\t\tconnection,\n\t\t\t]),\n\t\t);\n\t\tconst metaByProfileId = new Map(\n\t\t\tmetaMappings.map((mapping) => [mapping.profileId, mapping]),\n\t\t);\n\t\tconst gtmMappingCountByProfileId = new Map(\n\t\t\tgtmMappingSummaries.map((summary) => [\n\t\t\t\tsummary.profileId,\n\t\t\t\tsummary.activeMappingCount,\n\t\t\t]),\n\t\t);\n\t\treturn object({\n\t\t\ttotal_profiles: profiles.length,\n\t\t\tprofiles: profiles.map((profile) => {\n\t\t\t\tconst mapping = mappingsByProfileId.get(profile.id);\n\t\t\t\tconst vtexConnection = vtexByProfileId.get(profile.id);\n\t\t\t\tconst mercadolibreConnection = mercadolibreByProfileId.get(profile.id);\n\t\t\t\tconst metaMapping = metaByProfileId.get(profile.id);\n\t\t\t\tconst metaConfigured = Boolean(\n\t\t\t\t\tmetaMapping?.metaBusinessId && metaMapping.status === \"active\",\n\t\t\t\t);\n\t\t\t\tconst gtmConfigured =\n\t\t\t\t\t(gtmMappingCountByProfileId.get(profile.id) ?? 0) > 0;\n\t\t\t\treturn {\n\t\t\t\t\tprofile_id: profile.id,\n\t\t\t\t\tname: profile.name,\n\t\t\t\t\tis_active: profile.isActive,\n\t\t\t\t\tcreated_at: profile.createdAt.toISOString(),\n\t\t\t\t\tupdated_at: profile.updatedAt.toISOString(),\n\t\t\t\t\tservices: {\n\t\t\t\t\t\tgoogle: {\n\t\t\t\t\t\t\tgoogle_ads: {\n\t\t\t\t\t\t\t\tconfigured: Boolean(mapping?.googleAdsCustomerId),\n\t\t\t\t\t\t\t\tstatus: mapping?.googleAdsCustomerId\n\t\t\t\t\t\t\t\t\t? mapping.googleAdsStatus\n\t\t\t\t\t\t\t\t\t: \"not_configured\",\n\t\t\t\t\t\t\t\traw_status: mapping?.googleAdsCustomerId\n\t\t\t\t\t\t\t\t\t? mapping.googleAdsStatus\n\t\t\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tga4: {\n\t\t\t\t\t\t\t\tconfigured: Boolean(mapping?.ga4PropertyId),\n\t\t\t\t\t\t\t\tstatus: mapping?.ga4PropertyId\n\t\t\t\t\t\t\t\t\t? mapping.ga4Status\n\t\t\t\t\t\t\t\t\t: \"not_configured\",\n\t\t\t\t\t\t\t\traw_status: mapping?.ga4PropertyId ? mapping.ga4Status : null,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tsearch_console: {\n\t\t\t\t\t\t\t\tconfigured: Boolean(mapping?.searchConsoleSiteUrl),\n\t\t\t\t\t\t\t\tstatus: mapping?.searchConsoleSiteUrl\n\t\t\t\t\t\t\t\t\t? mapping.searchConsoleStatus\n\t\t\t\t\t\t\t\t\t: \"not_configured\",\n\t\t\t\t\t\t\t\traw_status: mapping?.searchConsoleSiteUrl\n\t\t\t\t\t\t\t\t\t? mapping.searchConsoleStatus\n\t\t\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tgtm: {\n\t\t\t\t\t\t\t\tconfigured: gtmConfigured,\n\t\t\t\t\t\t\t\tstatus: getGtmStatus(gtmConfigured, googleOAuthConnection),\n\t\t\t\t\t\t\t\traw_status: gtmConfigured\n\t\t\t\t\t\t\t\t\t? (googleOAuthConnection?.status ?? null)\n\t\t\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\tvtex: {\n\t\t\t\t\t\t\tconfigured: Boolean(vtexConnection),\n\t\t\t\t\t\t\tstatus: vtexConnection\n\t\t\t\t\t\t\t\t? normalizeVtexStatus(vtexConnection.status)\n\t\t\t\t\t\t\t\t: \"not_configured\",\n\t\t\t\t\t\t\traw_status: vtexConnection ? vtexConnection.status : null,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tmercadolibre: {\n\t\t\t\t\t\t\tconfigured: Boolean(mercadolibreConnection),\n\t\t\t\t\t\t\tstatus: mercadolibreConnection\n\t\t\t\t\t\t\t\t? mercadolibreConnection.status\n\t\t\t\t\t\t\t\t: \"not_configured\",\n\t\t\t\t\t\t\traw_status: mercadolibreConnection\n\t\t\t\t\t\t\t\t? mercadolibreConnection.status\n\t\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tmeta: {\n\t\t\t\t\t\t\tconfigured: metaConfigured,\n\t\t\t\t\t\t\tstatus: metaConfigured\n\t\t\t\t\t\t\t\t? (metaMapping?.status ?? \"not_configured\")\n\t\t\t\t\t\t\t\t: \"not_configured\",\n\t\t\t\t\t\t\traw_status: metaMapping?.status ?? null,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}),\n\t\t});\n\t} catch (err) {\n\t\treturn error(\n\t\t\terr instanceof Error ? err.message : \"Failed to list profiles\",\n\t\t);\n\t}\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }