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.
- package/README.md +169 -402
- package/data/docs.json +4338 -0
- package/dist/docs/loader.d.ts +40 -0
- package/dist/docs/loader.js +110 -0
- package/dist/docs/loader.js.map +1 -0
- package/dist/docs/search.d.ts +47 -0
- package/dist/docs/search.js +101 -0
- package/dist/docs/search.js.map +1 -0
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/sandbox/bridge.d.ts +2 -0
- package/dist/sandbox/bridge.js +101 -0
- package/dist/sandbox/bridge.js.map +1 -0
- package/dist/sandbox/node-discovery.d.ts +7 -0
- package/dist/sandbox/node-discovery.js +228 -0
- package/dist/sandbox/node-discovery.js.map +1 -0
- package/dist/sandbox/protocol.d.ts +76 -0
- package/dist/sandbox/protocol.js +20 -0
- package/dist/sandbox/protocol.js.map +1 -0
- package/dist/sandbox/proxy-template.d.ts +19 -0
- package/dist/sandbox/proxy-template.js +83 -0
- package/dist/sandbox/proxy-template.js.map +1 -0
- package/dist/sandbox/runner.d.ts +20 -0
- package/dist/sandbox/runner.js +99 -0
- package/dist/sandbox/runner.js.map +1 -0
- package/dist/sandbox/sandbox-helpers.d.ts +14 -0
- package/dist/sandbox/sandbox-helpers.js +98 -0
- package/dist/sandbox/sandbox-helpers.js.map +1 -0
- package/dist/sandbox/sidecar/index.d.ts +16 -0
- package/dist/sandbox/sidecar/index.js +346 -0
- package/dist/sandbox/sidecar/index.js.map +1 -0
- package/dist/sandbox/sidecar-runner.d.ts +32 -0
- package/dist/sandbox/sidecar-runner.js +325 -0
- package/dist/sandbox/sidecar-runner.js.map +1 -0
- package/dist/sandbox/timeout.d.ts +16 -0
- package/dist/sandbox/timeout.js +38 -0
- package/dist/sandbox/timeout.js.map +1 -0
- package/dist/sandbox/vm-runner.d.ts +35 -0
- package/dist/sandbox/vm-runner.js +182 -0
- package/dist/sandbox/vm-runner.js.map +1 -0
- package/dist/sdk/klaviyo/host.d.ts +43 -0
- package/dist/sdk/klaviyo/host.js +218 -0
- package/dist/sdk/klaviyo/host.js.map +1 -0
- package/dist/sdk/shopify/host.d.ts +23 -0
- package/dist/sdk/shopify/host.js +175 -0
- package/dist/sdk/shopify/host.js.map +1 -0
- package/dist/server.js +7 -7
- package/dist/server.js.map +1 -1
- package/dist/shared/errors.d.ts +0 -14
- package/dist/shared/errors.js +0 -73
- package/dist/shared/errors.js.map +1 -1
- package/dist/{platforms/klaviyo/tools.d.ts → tools/execute_code.d.ts} +1 -1
- package/dist/tools/execute_code.js +70 -0
- package/dist/tools/execute_code.js.map +1 -0
- package/dist/{platforms/shopify/tools.d.ts → tools/read_doc.d.ts} +1 -1
- package/dist/tools/read_doc.js +70 -0
- package/dist/tools/read_doc.js.map +1 -0
- package/dist/tools/search_docs.d.ts +2 -0
- package/dist/tools/search_docs.js +55 -0
- package/dist/tools/search_docs.js.map +1 -0
- package/package.json +16 -5
- package/dist/cross-platform/correlator.d.ts +0 -10
- package/dist/cross-platform/correlator.js +0 -166
- package/dist/cross-platform/correlator.js.map +0 -1
- package/dist/cross-platform/tools.d.ts +0 -2
- package/dist/cross-platform/tools.js +0 -30
- package/dist/cross-platform/tools.js.map +0 -1
- package/dist/platforms/klaviyo/client.d.ts +0 -91
- package/dist/platforms/klaviyo/client.js +0 -389
- package/dist/platforms/klaviyo/client.js.map +0 -1
- package/dist/platforms/klaviyo/tools.js +0 -363
- package/dist/platforms/klaviyo/tools.js.map +0 -1
- package/dist/platforms/klaviyo/transforms.d.ts +0 -59
- package/dist/platforms/klaviyo/transforms.js +0 -326
- package/dist/platforms/klaviyo/transforms.js.map +0 -1
- package/dist/platforms/shopify/client.d.ts +0 -51
- package/dist/platforms/shopify/client.js +0 -352
- package/dist/platforms/shopify/client.js.map +0 -1
- package/dist/platforms/shopify/tools.js +0 -368
- package/dist/platforms/shopify/tools.js.map +0 -1
- package/dist/platforms/shopify/transforms.d.ts +0 -83
- package/dist/platforms/shopify/transforms.js +0 -308
- package/dist/platforms/shopify/transforms.js.map +0 -1
- package/dist/shared/pagination.d.ts +0 -21
- package/dist/shared/pagination.js +0 -36
- package/dist/shared/pagination.js.map +0 -1
- package/dist/shared/types.d.ts +0 -318
- package/dist/shared/types.js +0 -3
- 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
|
|
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,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.
|
|
4
|
-
"description": "
|
|
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
|
-
"
|
|
25
|
-
"
|
|
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,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
|
-
}>>;
|