dtc-mcp 0.2.0 → 1.0.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 (89) hide show
  1. package/README.md +169 -402
  2. package/data/docs.json +4338 -0
  3. package/dist/docs/loader.d.ts +40 -0
  4. package/dist/docs/loader.js +110 -0
  5. package/dist/docs/loader.js.map +1 -0
  6. package/dist/docs/search.d.ts +47 -0
  7. package/dist/docs/search.js +101 -0
  8. package/dist/docs/search.js.map +1 -0
  9. package/dist/index.js +3 -2
  10. package/dist/index.js.map +1 -1
  11. package/dist/sandbox/bridge.d.ts +2 -0
  12. package/dist/sandbox/bridge.js +101 -0
  13. package/dist/sandbox/bridge.js.map +1 -0
  14. package/dist/sandbox/node-discovery.d.ts +7 -0
  15. package/dist/sandbox/node-discovery.js +228 -0
  16. package/dist/sandbox/node-discovery.js.map +1 -0
  17. package/dist/sandbox/protocol.d.ts +76 -0
  18. package/dist/sandbox/protocol.js +20 -0
  19. package/dist/sandbox/protocol.js.map +1 -0
  20. package/dist/sandbox/proxy-template.d.ts +19 -0
  21. package/dist/sandbox/proxy-template.js +83 -0
  22. package/dist/sandbox/proxy-template.js.map +1 -0
  23. package/dist/sandbox/runner.d.ts +20 -0
  24. package/dist/sandbox/runner.js +99 -0
  25. package/dist/sandbox/runner.js.map +1 -0
  26. package/dist/sandbox/sandbox-helpers.d.ts +14 -0
  27. package/dist/sandbox/sandbox-helpers.js +98 -0
  28. package/dist/sandbox/sandbox-helpers.js.map +1 -0
  29. package/dist/sandbox/sidecar/index.d.ts +16 -0
  30. package/dist/sandbox/sidecar/index.js +346 -0
  31. package/dist/sandbox/sidecar/index.js.map +1 -0
  32. package/dist/sandbox/sidecar-runner.d.ts +32 -0
  33. package/dist/sandbox/sidecar-runner.js +325 -0
  34. package/dist/sandbox/sidecar-runner.js.map +1 -0
  35. package/dist/sandbox/timeout.d.ts +16 -0
  36. package/dist/sandbox/timeout.js +38 -0
  37. package/dist/sandbox/timeout.js.map +1 -0
  38. package/dist/sandbox/vm-runner.d.ts +35 -0
  39. package/dist/sandbox/vm-runner.js +182 -0
  40. package/dist/sandbox/vm-runner.js.map +1 -0
  41. package/dist/sdk/klaviyo/host.d.ts +43 -0
  42. package/dist/sdk/klaviyo/host.js +218 -0
  43. package/dist/sdk/klaviyo/host.js.map +1 -0
  44. package/dist/sdk/shopify/host.d.ts +23 -0
  45. package/dist/sdk/shopify/host.js +175 -0
  46. package/dist/sdk/shopify/host.js.map +1 -0
  47. package/dist/server.js +7 -7
  48. package/dist/server.js.map +1 -1
  49. package/dist/shared/errors.d.ts +0 -14
  50. package/dist/shared/errors.js +0 -73
  51. package/dist/shared/errors.js.map +1 -1
  52. package/dist/{platforms/klaviyo/tools.d.ts → tools/execute_code.d.ts} +1 -1
  53. package/dist/tools/execute_code.js +70 -0
  54. package/dist/tools/execute_code.js.map +1 -0
  55. package/dist/{platforms/shopify/tools.d.ts → tools/read_doc.d.ts} +1 -1
  56. package/dist/tools/read_doc.js +70 -0
  57. package/dist/tools/read_doc.js.map +1 -0
  58. package/dist/tools/search_docs.d.ts +2 -0
  59. package/dist/tools/search_docs.js +55 -0
  60. package/dist/tools/search_docs.js.map +1 -0
  61. package/package.json +16 -5
  62. package/dist/cross-platform/correlator.d.ts +0 -10
  63. package/dist/cross-platform/correlator.js +0 -166
  64. package/dist/cross-platform/correlator.js.map +0 -1
  65. package/dist/cross-platform/tools.d.ts +0 -2
  66. package/dist/cross-platform/tools.js +0 -30
  67. package/dist/cross-platform/tools.js.map +0 -1
  68. package/dist/platforms/klaviyo/client.d.ts +0 -91
  69. package/dist/platforms/klaviyo/client.js +0 -389
  70. package/dist/platforms/klaviyo/client.js.map +0 -1
  71. package/dist/platforms/klaviyo/tools.js +0 -363
  72. package/dist/platforms/klaviyo/tools.js.map +0 -1
  73. package/dist/platforms/klaviyo/transforms.d.ts +0 -59
  74. package/dist/platforms/klaviyo/transforms.js +0 -326
  75. package/dist/platforms/klaviyo/transforms.js.map +0 -1
  76. package/dist/platforms/shopify/client.d.ts +0 -51
  77. package/dist/platforms/shopify/client.js +0 -352
  78. package/dist/platforms/shopify/client.js.map +0 -1
  79. package/dist/platforms/shopify/tools.js +0 -368
  80. package/dist/platforms/shopify/tools.js.map +0 -1
  81. package/dist/platforms/shopify/transforms.d.ts +0 -83
  82. package/dist/platforms/shopify/transforms.js +0 -308
  83. package/dist/platforms/shopify/transforms.js.map +0 -1
  84. package/dist/shared/pagination.d.ts +0 -21
  85. package/dist/shared/pagination.js +0 -36
  86. package/dist/shared/pagination.js.map +0 -1
  87. package/dist/shared/types.d.ts +0 -318
  88. package/dist/shared/types.js +0 -3
  89. package/dist/shared/types.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"execute_code.js","sourceRoot":"","sources":["../../src/tools/execute_code.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAEnC,MAAM,SAAS,GAAG;IAChB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CACvB,uZAAuZ,CACxZ;CACF,CAAC;AAEF,MAAM,WAAW,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+BnB,CAAC,IAAI,EAAE,CAAC;AAET,MAAM,UAAU,mBAAmB,CAAC,MAAiB;IACnD,MAAM,CAAC,IAAI,CACT,cAAc,EACd,WAAW,EACX,SAAS,EACT;QACE,KAAK,EAAE,0BAA0B;QACjC,YAAY,EAAE,KAAK;QACnB,eAAe,EAAE,KAAK;QACtB,cAAc,EAAE,KAAK;QACrB,aAAa,EAAE,IAAI;KACpB,EACD,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;QACjB,MAAM,SAAS,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;QACvC,GAAG,CAAC,OAAO,EAAE,cAAc,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;QAEjE,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC;QAErD,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CACzB;YACE,EAAE,EAAE,MAAM,CAAC,EAAE;YACb,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC;YACpE,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,UAAU,EAAE,MAAM,CAAC,UAAU;YAC7B,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,GAAG,CAAC,MAAM,CAAC,YAAY;gBACrB,CAAC,CAAC;oBACE,YAAY,EAAE,IAAI;oBAClB,gBAAgB,EACd,8SAA8S;iBACjT;gBACH,CAAC,CAAC,EAAE,CAAC;SACR,EACD,IAAI,EACJ,CAAC,CACF,CAAC;QAEF,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;YACjC,OAAO,EAAE,CAAC,MAAM,CAAC,EAAE;SACpB,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -1,2 +1,2 @@
1
1
  import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
- export declare function registerShopifyTools(server: McpServer): void;
2
+ export declare function registerReadDoc(server: McpServer): void;
@@ -0,0 +1,70 @@
1
+ import { z } from "zod";
2
+ import { readById, listPaths } from "../docs/search.js";
3
+ const readDocShape = {
4
+ path: z
5
+ .string()
6
+ .optional()
7
+ .describe("Exact chunk ID to fetch (e.g. 'klaviyo.reporting.campaignValues', 'guide.output-discipline'). Omit to list all available paths."),
8
+ platform: z
9
+ .enum(["klaviyo", "shopify", "guide"])
10
+ .optional()
11
+ .describe("When listing (no `path`), filter to one platform's docs only."),
12
+ };
13
+ const description = `
14
+ Fetch a specific SDK docs chunk by exact path, or list all available paths when called with no args.
15
+
16
+ Use this instead of search_docs when you already know the chunk ID — it's cheaper and more deterministic.
17
+ Common patterns:
18
+ • read_doc({}) → list every chunk ID with one-line summaries (use this once at the start of a session to map the SDK surface)
19
+ • read_doc({ path: "klaviyo.reporting.campaignValues" }) → fetch one method's full doc (signature + JSDoc + example) verbatim
20
+ • read_doc({ platform: "shopify" }) → list only Shopify chunk IDs
21
+
22
+ This adopts the "filesystem-as-API" pattern from Anthropic's Code Execution with MCP research: LLMs are faster and more accurate when they can read a typed-source-of-truth doc page directly, rather than re-searching for it on every code generation.
23
+ `.trim();
24
+ export function registerReadDoc(server) {
25
+ server.tool("read_doc", description, readDocShape, {
26
+ title: "Read SDK doc by path",
27
+ readOnlyHint: true,
28
+ destructiveHint: false,
29
+ idempotentHint: true,
30
+ openWorldHint: false,
31
+ }, async ({ path, platform }) => {
32
+ if (path) {
33
+ const { version, found, chunk } = await readById(path);
34
+ const text = JSON.stringify({
35
+ docsVersion: version,
36
+ found,
37
+ chunk: chunk
38
+ ? {
39
+ id: chunk.id,
40
+ title: chunk.title,
41
+ platform: chunk.platform,
42
+ category: chunk.category,
43
+ summary: chunk.summary,
44
+ content: chunk.content,
45
+ tags: chunk.tags,
46
+ }
47
+ : null,
48
+ ...(found
49
+ ? {}
50
+ : {
51
+ hint: "Path not found. Use read_doc({}) to list all paths, or search_docs to find by query.",
52
+ }),
53
+ }, null, 2);
54
+ return {
55
+ content: [{ type: "text", text }],
56
+ isError: !found,
57
+ };
58
+ }
59
+ const { version, count, paths } = await listPaths({ platform });
60
+ const text = JSON.stringify({
61
+ docsVersion: version,
62
+ count,
63
+ paths,
64
+ }, null, 2);
65
+ return {
66
+ content: [{ type: "text", text }],
67
+ };
68
+ });
69
+ }
70
+ //# sourceMappingURL=read_doc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read_doc.js","sourceRoot":"","sources":["../../src/tools/read_doc.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAExD,MAAM,YAAY,GAAG;IACnB,IAAI,EAAE,CAAC;SACJ,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CACP,iIAAiI,CAClI;IACH,QAAQ,EAAE,CAAC;SACR,IAAI,CAAC,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;SACrC,QAAQ,EAAE;SACV,QAAQ,CACP,+DAA+D,CAChE;CACJ,CAAC;AAEF,MAAM,WAAW,GAAG;;;;;;;;;;CAUnB,CAAC,IAAI,EAAE,CAAC;AAET,MAAM,UAAU,eAAe,CAAC,MAAiB;IAC/C,MAAM,CAAC,IAAI,CACT,UAAU,EACV,WAAW,EACX,YAAY,EACZ;QACE,KAAK,EAAE,sBAAsB;QAC7B,YAAY,EAAE,IAAI;QAClB,eAAe,EAAE,KAAK;QACtB,cAAc,EAAE,IAAI;QACpB,aAAa,EAAE,KAAK;KACrB,EACD,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE;QAC3B,IAAI,IAAI,EAAE,CAAC;YACT,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,CAAC;YACvD,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CACzB;gBACE,WAAW,EAAE,OAAO;gBACpB,KAAK;gBACL,KAAK,EAAE,KAAK;oBACV,CAAC,CAAC;wBACE,EAAE,EAAE,KAAK,CAAC,EAAE;wBACZ,KAAK,EAAE,KAAK,CAAC,KAAK;wBAClB,QAAQ,EAAE,KAAK,CAAC,QAAQ;wBACxB,QAAQ,EAAE,KAAK,CAAC,QAAQ;wBACxB,OAAO,EAAE,KAAK,CAAC,OAAO;wBACtB,OAAO,EAAE,KAAK,CAAC,OAAO;wBACtB,IAAI,EAAE,KAAK,CAAC,IAAI;qBACjB;oBACH,CAAC,CAAC,IAAI;gBACR,GAAG,CAAC,KAAK;oBACP,CAAC,CAAC,EAAE;oBACJ,CAAC,CAAC;wBACE,IAAI,EAAE,sFAAsF;qBAC7F,CAAC;aACP,EACD,IAAI,EACJ,CAAC,CACF,CAAC;YACF,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;gBACjC,OAAO,EAAE,CAAC,KAAK;aAChB,CAAC;QACJ,CAAC;QAED,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,MAAM,SAAS,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC;QAChE,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CACzB;YACE,WAAW,EAAE,OAAO;YACpB,KAAK;YACL,KAAK;SACN,EACD,IAAI,EACJ,CAAC,CACF,CAAC;QACF,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;SAClC,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerSearchDocs(server: McpServer): void;
@@ -0,0 +1,55 @@
1
+ import { z } from "zod";
2
+ import { search } from "../docs/search.js";
3
+ const searchShape = {
4
+ query: z.string().describe("Natural-language or keyword query. Examples: 'list campaigns', 'shopifyql sales last 30 days', 'flow reporting', 'get conversion metric id'."),
5
+ platform: z
6
+ .enum(["klaviyo", "shopify"])
7
+ .optional()
8
+ .describe("Filter to one platform's docs."),
9
+ limit: z
10
+ .number()
11
+ .int()
12
+ .min(1)
13
+ .max(20)
14
+ .optional()
15
+ .describe("Max results to return (default 5)."),
16
+ };
17
+ const description = `
18
+ Search the bundled SDK reference docs for Klaviyo and Shopify methods exposed inside the
19
+ execute_code sandbox. Returns ranked markdown chunks: method signatures, parameter
20
+ descriptions, and runnable code examples.
21
+
22
+ Use this BEFORE writing code in execute_code — the SDK surface is constrained to
23
+ registered methods (escape hatches are 'klaviyo.get/post/paginate' and 'shopify.gql/ql').
24
+
25
+ The docs index is refreshed daily from a CDN-backed source repo, so new Klaviyo/Shopify
26
+ API revisions land without requiring a new MCP release.
27
+ `.trim();
28
+ export function registerSearchDocs(server) {
29
+ server.tool("search_docs", description, searchShape, {
30
+ title: "Search SDK docs",
31
+ readOnlyHint: true,
32
+ destructiveHint: false,
33
+ idempotentHint: true,
34
+ openWorldHint: false,
35
+ }, async ({ query, platform, limit }) => {
36
+ const { version, hits } = await search(query, { platform, limit });
37
+ const text = JSON.stringify({
38
+ query,
39
+ docsVersion: version,
40
+ hits: hits.map((h) => ({
41
+ id: h.id,
42
+ title: h.title,
43
+ platform: h.platform,
44
+ category: h.category,
45
+ summary: h.summary,
46
+ content: h.content,
47
+ score: Math.round(h.score * 100) / 100,
48
+ })),
49
+ }, null, 2);
50
+ return {
51
+ content: [{ type: "text", text }],
52
+ };
53
+ });
54
+ }
55
+ //# sourceMappingURL=search_docs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search_docs.js","sourceRoot":"","sources":["../../src/tools/search_docs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3C,MAAM,WAAW,GAAG;IAClB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CACxB,8IAA8I,CAC/I;IACD,QAAQ,EAAE,CAAC;SACR,IAAI,CAAC,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;SAC5B,QAAQ,EAAE;SACV,QAAQ,CAAC,gCAAgC,CAAC;IAC7C,KAAK,EAAE,CAAC;SACL,MAAM,EAAE;SACR,GAAG,EAAE;SACL,GAAG,CAAC,CAAC,CAAC;SACN,GAAG,CAAC,EAAE,CAAC;SACP,QAAQ,EAAE;SACV,QAAQ,CAAC,oCAAoC,CAAC;CAClD,CAAC;AAEF,MAAM,WAAW,GAAG;;;;;;;;;;CAUnB,CAAC,IAAI,EAAE,CAAC;AAET,MAAM,UAAU,kBAAkB,CAAC,MAAiB;IAClD,MAAM,CAAC,IAAI,CACT,aAAa,EACb,WAAW,EACX,WAAW,EACX;QACE,KAAK,EAAE,iBAAiB;QACxB,YAAY,EAAE,IAAI;QAClB,eAAe,EAAE,KAAK;QACtB,cAAc,EAAE,IAAI;QACpB,aAAa,EAAE,KAAK;KACrB,EACD,KAAK,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,EAAE;QACnC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,KAAK,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;QACnE,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CACzB;YACE,KAAK;YACL,WAAW,EAAE,OAAO;YACpB,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBACrB,EAAE,EAAE,CAAC,CAAC,EAAE;gBACR,KAAK,EAAE,CAAC,CAAC,KAAK;gBACd,QAAQ,EAAE,CAAC,CAAC,QAAQ;gBACpB,QAAQ,EAAE,CAAC,CAAC,QAAQ;gBACpB,OAAO,EAAE,CAAC,CAAC,OAAO;gBAClB,OAAO,EAAE,CAAC,CAAC,OAAO;gBAClB,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,GAAG;aACvC,CAAC,CAAC;SACJ,EACD,IAAI,EACJ,CAAC,CACF,CAAC;QACF,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;SAClC,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dtc-mcp",
3
- "version": "0.2.0",
4
- "description": "Context-optimized MCP server for DTC e-commerce brands (Klaviyo + Shopify). 80% less context usage than raw API wrappers.",
3
+ "version": "1.0.0",
4
+ "description": "Code-execution MCP server for Klaviyo + Shopify analytics. The LLM writes TypeScript against typed SDKs in a stateful V8 sandbox — three composable tools instead of dozens.",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "dtc-mcp": "dist/index.js"
@@ -13,7 +13,11 @@
13
13
  "start": "node dist/index.js",
14
14
  "test": "vitest run",
15
15
  "test:watch": "vitest",
16
- "inspect": "npx @modelcontextprotocol/inspector dist/index.js"
16
+ "inspect": "npx @modelcontextprotocol/inspector dist/index.js",
17
+ "codegen:klaviyo": "tsx tools/codegen/klaviyo.ts",
18
+ "codegen:shopify": "tsx tools/codegen/shopify.ts",
19
+ "codegen:docs": "tsx tools/codegen/docs.ts",
20
+ "codegen": "npm run codegen:klaviyo && npm run codegen:shopify && npm run codegen:docs"
17
21
  },
18
22
  "keywords": [
19
23
  "mcp",
@@ -21,8 +25,10 @@
21
25
  "shopify",
22
26
  "dtc",
23
27
  "ecommerce",
24
- "analytics",
25
- "context-optimized"
28
+ "code-execution",
29
+ "sandbox",
30
+ "stainless",
31
+ "code-mode"
26
32
  ],
27
33
  "author": "Rafael Sztutman",
28
34
  "license": "MIT",
@@ -36,6 +42,7 @@
36
42
  },
37
43
  "files": [
38
44
  "dist",
45
+ "data",
39
46
  "README.md",
40
47
  "LICENSE"
41
48
  ],
@@ -45,10 +52,14 @@
45
52
  "dependencies": {
46
53
  "@modelcontextprotocol/sdk": "^1.27.0",
47
54
  "dotenv": "^17.3.1",
55
+ "isolated-vm": "^6.1.2",
56
+ "minisearch": "^7.1.0",
57
+ "sucrase": "^3.35.0",
48
58
  "zod": "^3.23.8"
49
59
  },
50
60
  "devDependencies": {
51
61
  "@types/node": "^20.0.0",
62
+ "tsx": "^4.19.0",
52
63
  "typescript": "^5.5.0",
53
64
  "vitest": "^2.0.0"
54
65
  }
@@ -1,10 +0,0 @@
1
- import type { RevenueAttribution, Dashboard } from "../shared/types.js";
2
- /**
3
- * Compare Klaviyo attributed revenue vs Shopify total revenue.
4
- */
5
- export declare function computeRevenueAttribution(days: number): Promise<RevenueAttribution>;
6
- /**
7
- * Orchestrate a complete DTC health dashboard.
8
- * Uses cached results from sub-queries to minimize API calls.
9
- */
10
- export declare function computeDashboard(days: number): Promise<Dashboard>;
@@ -1,166 +0,0 @@
1
- import { isShopifyConfigured } from "../config.js";
2
- import { getCampaignReport, getFlowReport } from "../platforms/klaviyo/client.js";
3
- import { getAggregatedSales } from "../platforms/shopify/client.js";
4
- /**
5
- * Compare Klaviyo attributed revenue vs Shopify total revenue.
6
- */
7
- export async function computeRevenueAttribution(days) {
8
- // Fetch Klaviyo campaign + flow revenue (uses cached reporting data)
9
- const [campaignRows, flowRows] = await Promise.all([
10
- getCampaignReport(days),
11
- getFlowReport(days),
12
- ]);
13
- // Sum campaign revenue
14
- let campaignRevenue = 0;
15
- const campaignRevenueMap = new Map();
16
- for (const row of campaignRows) {
17
- const revenue = row.statistics.conversion_value ?? 0;
18
- const id = String(row.groupings.campaign_id ?? "unknown");
19
- campaignRevenue += revenue;
20
- const existing = campaignRevenueMap.get(id);
21
- if (existing) {
22
- existing.revenue += revenue;
23
- }
24
- else {
25
- campaignRevenueMap.set(id, { name: id, revenue });
26
- }
27
- }
28
- // Sum flow revenue
29
- let flowRevenue = 0;
30
- const flowRevenueMap = new Map();
31
- for (const row of flowRows) {
32
- const revenue = row.statistics.conversion_value ?? 0;
33
- const id = String(row.groupings.flow_id ?? "unknown");
34
- flowRevenue += revenue;
35
- const existing = flowRevenueMap.get(id);
36
- if (existing) {
37
- existing.revenue += revenue;
38
- }
39
- else {
40
- flowRevenueMap.set(id, { name: id, revenue });
41
- }
42
- }
43
- const emailTotalRevenue = campaignRevenue + flowRevenue;
44
- // Get Shopify total revenue
45
- let totalRevenue = emailTotalRevenue;
46
- if (isShopifyConfigured()) {
47
- try {
48
- const sales = await getAggregatedSales(days);
49
- totalRevenue = sales.netRevenue || emailTotalRevenue;
50
- }
51
- catch {
52
- // Shopify unavailable — use email revenue as total
53
- }
54
- }
55
- const emailPct = totalRevenue > 0
56
- ? Math.round((emailTotalRevenue / totalRevenue) * 10000) / 100
57
- : 0;
58
- const topCampaigns = Array.from(campaignRevenueMap.values())
59
- .sort((a, b) => b.revenue - a.revenue)
60
- .slice(0, 5);
61
- const topFlows = Array.from(flowRevenueMap.values())
62
- .sort((a, b) => b.revenue - a.revenue)
63
- .slice(0, 5);
64
- return {
65
- period_days: days,
66
- total_revenue: Math.round(totalRevenue * 100) / 100,
67
- email_campaign_revenue: Math.round(campaignRevenue * 100) / 100,
68
- flow_revenue: Math.round(flowRevenue * 100) / 100,
69
- email_total_revenue: Math.round(emailTotalRevenue * 100) / 100,
70
- email_pct_of_total: emailPct,
71
- flow_vs_campaign_split: {
72
- campaign_pct: emailTotalRevenue > 0
73
- ? Math.round((campaignRevenue / emailTotalRevenue) * 10000) / 100
74
- : 0,
75
- flow_pct: emailTotalRevenue > 0
76
- ? Math.round((flowRevenue / emailTotalRevenue) * 10000) / 100
77
- : 0,
78
- },
79
- top_revenue_campaigns: topCampaigns,
80
- top_revenue_flows: topFlows,
81
- note: "Revenue attribution uses Klaviyo's send-date model. Actual overlap with Shopify revenue may vary.",
82
- };
83
- }
84
- /**
85
- * Orchestrate a complete DTC health dashboard.
86
- * Uses cached results from sub-queries to minimize API calls.
87
- */
88
- export async function computeDashboard(days) {
89
- // Run Klaviyo queries in parallel (these hit cache if recent calls were made)
90
- const [campaignRows, flowRows] = await Promise.all([
91
- getCampaignReport(days),
92
- getFlowReport(days),
93
- ]);
94
- // Sum email revenue
95
- let campaignRevenue = 0;
96
- const topCampaigns = [];
97
- const campaignMap = new Map();
98
- for (const row of campaignRows) {
99
- const id = String(row.groupings.campaign_id ?? "");
100
- const existing = campaignMap.get(id) ?? { revenue: 0, opens: 0, recipients: 0 };
101
- existing.revenue += row.statistics.conversion_value ?? 0;
102
- existing.opens += row.statistics.opens_unique ?? row.statistics.opens ?? 0;
103
- existing.recipients += row.statistics.recipients ?? 0;
104
- campaignMap.set(id, existing);
105
- campaignRevenue += row.statistics.conversion_value ?? 0;
106
- }
107
- for (const [name, stats] of campaignMap.entries()) {
108
- topCampaigns.push({
109
- name,
110
- revenue: Math.round(stats.revenue * 100) / 100,
111
- open_rate: stats.recipients > 0
112
- ? Math.round((stats.opens / stats.recipients) * 10000) / 10000
113
- : 0,
114
- });
115
- }
116
- topCampaigns.sort((a, b) => b.revenue - a.revenue);
117
- let flowRevenue = 0;
118
- const topFlows = [];
119
- const flowMap = new Map();
120
- for (const row of flowRows) {
121
- const id = String(row.groupings.flow_id ?? "");
122
- flowMap.set(id, (flowMap.get(id) ?? 0) + (row.statistics.conversion_value ?? 0));
123
- flowRevenue += row.statistics.conversion_value ?? 0;
124
- }
125
- for (const [name, revenue] of flowMap.entries()) {
126
- topFlows.push({ name, revenue: Math.round(revenue * 100) / 100 });
127
- }
128
- topFlows.sort((a, b) => b.revenue - a.revenue);
129
- const emailRevenue = campaignRevenue + flowRevenue;
130
- // Shopify sales
131
- let shopifyRevenue = emailRevenue;
132
- let orderCount = 0;
133
- let aov = 0;
134
- if (isShopifyConfigured()) {
135
- try {
136
- const sales = await getAggregatedSales(days);
137
- shopifyRevenue = sales.netRevenue || emailRevenue;
138
- orderCount = sales.orderCount;
139
- aov = orderCount > 0 ? Math.round((shopifyRevenue / orderCount) * 100) / 100 : 0;
140
- }
141
- catch {
142
- // Shopify unavailable
143
- }
144
- }
145
- return {
146
- period_days: days,
147
- sales: {
148
- revenue: Math.round(shopifyRevenue * 100) / 100,
149
- orders: orderCount,
150
- aov,
151
- },
152
- email: {
153
- email_revenue: Math.round(emailRevenue * 100) / 100,
154
- email_pct_of_total: shopifyRevenue > 0
155
- ? Math.round((emailRevenue / shopifyRevenue) * 10000) / 100
156
- : 0,
157
- top_campaigns: topCampaigns.slice(0, 5),
158
- top_flows: topFlows.slice(0, 5),
159
- },
160
- subscribers: {
161
- total: 0, // Would require a separate API call — omit to save rate limits
162
- list_count: 0,
163
- },
164
- };
165
- }
166
- //# sourceMappingURL=correlator.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"correlator.js","sourceRoot":"","sources":["../../src/cross-platform/correlator.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
- export declare function registerCrossPlatformTools(server: McpServer): void;
@@ -1,30 +0,0 @@
1
- import { z } from "zod";
2
- import { computeRevenueAttribution, computeDashboard } from "./correlator.js";
3
- import { formatError, toolResult } from "../shared/errors.js";
4
- export function registerCrossPlatformTools(server) {
5
- // ---- Tool 15: Email Revenue Attribution ----
6
- server.tool("dtc_email_revenue_attribution", "Email/SMS revenue vs total Shopify revenue. Shows email marketing contribution.", {
7
- days: z.number().min(1).max(365).default(30),
8
- }, async ({ days }) => {
9
- try {
10
- const result = await computeRevenueAttribution(days);
11
- return toolResult(result);
12
- }
13
- catch (error) {
14
- return formatError(error);
15
- }
16
- });
17
- // ---- Tool 16: DTC Dashboard ----
18
- server.tool("dtc_dashboard", "Complete DTC health dashboard: sales + email + subscriber metrics in one call.", {
19
- days: z.number().min(7).max(90).default(30),
20
- }, async ({ days }) => {
21
- try {
22
- const result = await computeDashboard(days);
23
- return toolResult(result);
24
- }
25
- catch (error) {
26
- return formatError(error);
27
- }
28
- });
29
- }
30
- //# sourceMappingURL=tools.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"tools.js","sourceRoot":"","sources":["../../src/cross-platform/tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,yBAAyB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAC9E,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAE9D,MAAM,UAAU,0BAA0B,CAAC,MAAiB;IAC1D,+CAA+C;IAC/C,MAAM,CAAC,IAAI,CACT,+BAA+B,EAC/B,iFAAiF,EACjF;QACE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;KAC7C,EACD,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;QACjB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,yBAAyB,CAAC,IAAI,CAAC,CAAC;YACrD,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC;QAC5B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC,CACF,CAAC;IAEF,mCAAmC;IACnC,MAAM,CAAC,IAAI,CACT,eAAe,EACf,gFAAgF,EAChF;QACE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;KAC5C,EACD,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;QACjB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,IAAI,CAAC,CAAC;YAC5C,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC;QAC5B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -1,91 +0,0 @@
1
- import type { RateLimitTier } from "../../shared/types.js";
2
- /**
3
- * GET request to Klaviyo API with rate limiting and sparse fieldsets.
4
- */
5
- export declare function klaviyoGet(path: string, params?: Record<string, string>, tier?: RateLimitTier): Promise<{
6
- data: Array<{
7
- id: string;
8
- attributes: Record<string, unknown>;
9
- relationships?: Record<string, unknown>;
10
- }>;
11
- links?: {
12
- self?: string;
13
- next?: string;
14
- prev?: string;
15
- };
16
- included?: Array<{
17
- id: string;
18
- type: string;
19
- attributes: Record<string, unknown>;
20
- }>;
21
- }>;
22
- /**
23
- * POST request to Klaviyo API (primarily for reporting endpoints).
24
- * Results are cached with 10-minute TTL for reporting tier.
25
- */
26
- export declare function klaviyoPost(path: string, body: Record<string, unknown>, tier?: RateLimitTier): Promise<{
27
- results: Array<{
28
- groupings: Record<string, unknown>;
29
- statistics: Record<string, number>;
30
- }>;
31
- }>;
32
- /**
33
- * Auto-paginate a Klaviyo GET endpoint.
34
- * Returns all items up to maxPages pages.
35
- */
36
- export declare function klaviyoPaginateAll(path: string, params?: Record<string, string>, maxPages?: number, tier?: RateLimitTier): Promise<Array<{
37
- id: string;
38
- attributes: Record<string, unknown>;
39
- relationships?: Record<string, unknown>;
40
- }>>;
41
- /**
42
- * Fetch a single page with an opaque cursor.
43
- * Used by tools that expose pagination to the LLM.
44
- */
45
- export declare function klaviyoGetPage(path: string, params: Record<string, string>, cursor?: string, tier?: RateLimitTier): Promise<{
46
- data: Array<{
47
- id: string;
48
- attributes: Record<string, unknown>;
49
- relationships?: Record<string, unknown>;
50
- }>;
51
- links?: {
52
- self?: string;
53
- next?: string;
54
- prev?: string;
55
- };
56
- included?: Array<{
57
- id: string;
58
- type: string;
59
- attributes: Record<string, unknown>;
60
- }>;
61
- }>;
62
- /**
63
- * Get the "Placed Order" metric ID for use in reporting requests.
64
- * Cached for server lifetime.
65
- *
66
- * Discovery strategy (name is not filterable in 2026-01-15 revision):
67
- * 1. Check KLAVIYO_CONVERSION_METRIC_ID env var
68
- * 2. Fetch all metrics, search by exact name ("Placed Order", etc.)
69
- * 3. Fuzzy fallback excluding refund/cancel metrics
70
- */
71
- export declare function getConversionMetricId(): Promise<string>;
72
- /**
73
- * Build timeframe object for Klaviyo reporting API.
74
- */
75
- export declare function buildTimeframe(days: number): Record<string, unknown>;
76
- /**
77
- * Fetch campaign reporting data.
78
- * Uses reporting tier rate limiting and caching.
79
- */
80
- export declare function getCampaignReport(days: number, campaignIds?: string[]): Promise<Array<{
81
- groupings: Record<string, unknown>;
82
- statistics: Record<string, number>;
83
- }>>;
84
- /**
85
- * Fetch flow reporting data.
86
- * Uses reporting tier rate limiting and caching.
87
- */
88
- export declare function getFlowReport(days: number, flowIds?: string[]): Promise<Array<{
89
- groupings: Record<string, unknown>;
90
- statistics: Record<string, number>;
91
- }>>;