dtc-mcp 0.2.1 → 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 -406
- 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 -31
- 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 -364
- 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 -369
- 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
package/README.md
CHANGED
|
@@ -1,488 +1,251 @@
|
|
|
1
1
|
# dtc-mcp
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**A code-execution MCP server for Klaviyo + Shopify analytics.**
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Three tools. Typed SDKs. A V8 sandbox that keeps state across calls so iterative analyses don't re-fetch. Works inside Claude Desktop, Cursor, or any MCP client.
|
|
6
6
|
|
|
7
|
-
## Features
|
|
8
|
-
|
|
9
|
-
- **8 Klaviyo tools** — campaign performance, flow breakdowns, subscriber health, profile search, event activity
|
|
10
|
-
- **12 Shopify tools** — sales summaries, time series, product performance, inventory alerts, customer cohorts & segments, sales breakdowns by country/channel/vendor, traffic sources, returns analysis, order search
|
|
11
|
-
- **2 cross-platform tools** — email revenue attribution, full DTC health dashboard
|
|
12
|
-
- **Dual revenue metrics** — both gross and net revenue on every sales query
|
|
13
|
-
- **ShopifyQL-powered analytics** — fast aggregated queries for sales, customers, and sessions
|
|
14
|
-
- **Aggressive caching** — respects Klaviyo's strict rate limits (1 req/s on reporting)
|
|
15
|
-
|
|
16
|
-
## Quick Start
|
|
17
|
-
|
|
18
|
-
```bash
|
|
19
|
-
npm install -g dtc-mcp
|
|
20
7
|
```
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
npx dtc-mcp
|
|
8
|
+
LLM asks → execute_code → V8 sandbox ─→ host bridge ─→ Klaviyo / Shopify
|
|
9
|
+
↑ ↓
|
|
10
|
+
globalThis state rate limit + cache
|
|
11
|
+
persists across calls
|
|
26
12
|
```
|
|
27
13
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
### Option A: Desktop Extension (one-click install)
|
|
31
|
-
|
|
32
|
-
1. Download the latest `dtc-mcp.mcpb` from [GitHub Releases](https://github.com/rafaelsztutman/dtc-mcp/releases)
|
|
33
|
-
2. Double-click the `.mcpb` file — Claude Desktop will open an install dialog
|
|
34
|
-
3. Enter your API credentials when prompted (Klaviyo key required, Shopify optional)
|
|
35
|
-
4. The 22 tools will appear in the hammer menu automatically
|
|
36
|
-
|
|
37
|
-
### Option B: Manual Configuration
|
|
38
|
-
|
|
39
|
-
1. Open Claude Desktop
|
|
40
|
-
2. Go to **Settings** (gear icon) > **Developer** > **Edit Config**
|
|
41
|
-
3. Add the following to your `claude_desktop_config.json`:
|
|
42
|
-
|
|
43
|
-
```json
|
|
44
|
-
{
|
|
45
|
-
"mcpServers": {
|
|
46
|
-
"dtc-mcp": {
|
|
47
|
-
"command": "npx",
|
|
48
|
-
"args": ["-y", "dtc-mcp"],
|
|
49
|
-
"env": {
|
|
50
|
-
"KLAVIYO_API_KEY": "pk_your_private_key_here",
|
|
51
|
-
"SHOPIFY_STORE": "your-store.myshopify.com",
|
|
52
|
-
"SHOPIFY_CLIENT_ID": "your_client_id",
|
|
53
|
-
"SHOPIFY_CLIENT_SECRET": "shpss_your_secret"
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
|
14
|
+
```bash
|
|
15
|
+
npm install -g dtc-mcp
|
|
58
16
|
```
|
|
59
17
|
|
|
60
|
-
|
|
61
|
-
2. Look for the hammer icon in the chat input — that confirms the MCP tools are loaded
|
|
62
|
-
|
|
63
|
-
### Klaviyo-only mode
|
|
18
|
+
Or get the one-click [Claude Desktop extension](#install).
|
|
64
19
|
|
|
65
|
-
|
|
20
|
+
---
|
|
66
21
|
|
|
67
|
-
##
|
|
22
|
+
## The three tools
|
|
68
23
|
|
|
69
|
-
|
|
24
|
+
### `execute_code(code)`
|
|
70
25
|
|
|
71
|
-
|
|
26
|
+
Runs JavaScript (TypeScript syntax accepted — type annotations are stripped before execution) inside a constrained V8 sandbox. The sandbox exposes typed Klaviyo and Shopify clients; the host handles auth, rate limiting, and caching invisibly.
|
|
72
27
|
|
|
73
|
-
|
|
28
|
+
**Globals available inside the sandbox:**
|
|
74
29
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
- `segments:read`
|
|
85
|
-
- `profiles:read`
|
|
86
|
-
- `metrics:read`
|
|
87
|
-
- `events:read`
|
|
88
|
-
7. Copy the key (starts with `pk_`)
|
|
30
|
+
| | |
|
|
31
|
+
|---|---|
|
|
32
|
+
| `klaviyo` | `get`, `post`, `paginate`, plus typed namespaces: `campaigns`, `flows`, `lists`, `segments`, `profiles`, `events`, `metrics`, and `reporting.{campaignValues,flowValues}` |
|
|
33
|
+
| `shopify` | `gql`, `ql` (ShopifyQL), `timezone` |
|
|
34
|
+
| `console` | `log` / `error` / `warn` / `info` — captured and returned as `stdout` |
|
|
35
|
+
| `pick(v, schema)` | Deep projection over objects / arrays |
|
|
36
|
+
| `topN(arr, n, by)` | Top-N by numeric key, descending |
|
|
37
|
+
| `summarize(arr, opts)` | Auto-aggregate (count, total, min/max/avg, optional topN) |
|
|
38
|
+
| `globalThis.*` | Assignments persist across `execute_code` calls within the same MCP session |
|
|
89
39
|
|
|
90
|
-
|
|
40
|
+
**Not exposed:** `fetch`, `process`, `require`, `import`, `setTimeout`, the filesystem, or any env var. The only path out of the sandbox is the typed SDK methods, which route through the host's rate limiter and cache.
|
|
91
41
|
|
|
92
|
-
|
|
42
|
+
Defaults: 30s wall-clock per call, 128 MB heap (sidecar), 256 MB total per session. Opt-in `// @timeout 2m` at the top of the code extends the wall-clock up to 5 min.
|
|
93
43
|
|
|
94
|
-
|
|
44
|
+
### `search_docs(query, platform?, limit?)`
|
|
95
45
|
|
|
96
|
-
|
|
46
|
+
Full-text BM25 search over the bundled SDK reference. Returns ranked markdown chunks with signatures and runnable examples. Use this when you're discovering methods by intent ("how do I list flows with their actions?").
|
|
97
47
|
|
|
98
|
-
|
|
99
|
-
2. Navigate to **Configuration** > **Client credentials**
|
|
100
|
-
3. Copy the **Client ID** and **Client Secret**
|
|
101
|
-
4. Your store URL is your `*.myshopify.com` domain
|
|
48
|
+
### `read_doc(path?, platform?)`
|
|
102
49
|
|
|
103
|
-
|
|
50
|
+
Direct fetch of a chunk by exact path, or a full listing when called with no args. Cheaper than `search_docs` once the LLM knows what it wants. Calling `read_doc({})` once at the start of a session is the recommended way to map the whole SDK surface in one shot.
|
|
104
51
|
|
|
52
|
+
```js
|
|
53
|
+
read_doc({}) // list all 332 paths
|
|
54
|
+
read_doc({ path: "klaviyo.reporting.campaignValues" }) // one chunk verbatim
|
|
55
|
+
read_doc({ platform: "shopify" }) // Shopify only
|
|
105
56
|
```
|
|
106
|
-
SHOPIFY_STORE=your-store.myshopify.com
|
|
107
|
-
SHOPIFY_CLIENT_ID=your_client_id
|
|
108
|
-
SHOPIFY_CLIENT_SECRET=shpss_your_secret
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
**Required scopes:** `read_orders`, `read_products`, `read_customers`, `read_inventory`, `read_reports`
|
|
112
57
|
|
|
113
|
-
|
|
58
|
+
---
|
|
114
59
|
|
|
115
|
-
|
|
60
|
+
## Architecture
|
|
116
61
|
|
|
117
|
-
|
|
118
|
-
2. Click **Develop apps** > select your app
|
|
119
|
-
3. Go to **API credentials** and copy the **Admin API access token**
|
|
62
|
+
The sandbox runs in one of two modes, chosen automatically at startup.
|
|
120
63
|
|
|
121
|
-
|
|
64
|
+
### Preferred: sidecar with isolated-vm
|
|
122
65
|
|
|
123
66
|
```
|
|
124
|
-
|
|
125
|
-
|
|
67
|
+
┌─ Claude Desktop (Electron, hardened runtime) ────────────────┐
|
|
68
|
+
│ │
|
|
69
|
+
│ MCP server (Electron's bundled Node) │
|
|
70
|
+
│ ├ execute_code proxies to ↓ │
|
|
71
|
+
│ ├ search_docs MiniSearch BM25 over data/docs.json │
|
|
72
|
+
│ ├ read_doc direct fetch by chunk ID │
|
|
73
|
+
│ ├ host SDK Klaviyo + Shopify (rate limit / cache) │
|
|
74
|
+
│ └ sidecar manager spawn / lifecycle / NDJSON over stdio │
|
|
75
|
+
│ │
|
|
76
|
+
└─────────────────────────────│─────────────────────────────────┘
|
|
77
|
+
│ newline-delimited JSON-RPC
|
|
78
|
+
┌─ Sidecar process (system Node, outside Electron) ────────────┐
|
|
79
|
+
│ │
|
|
80
|
+
│ isolated-vm loads here (no Library Validation restriction) │
|
|
81
|
+
│ │
|
|
82
|
+
│ One long-lived V8 isolate per MCP connection: │
|
|
83
|
+
│ • 256 MB heap, 30 min idle TTL │
|
|
84
|
+
│ • klaviyo/shopify/pick/topN/summarize injected once │
|
|
85
|
+
│ • globalThis state preserved across execute_code calls │
|
|
86
|
+
│ • host-bridge calls round-trip back to the main process │
|
|
87
|
+
│ │
|
|
88
|
+
└───────────────────────────────────────────────────────────────┘
|
|
126
89
|
```
|
|
127
90
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
## Environment Variables
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
| Variable | Required | Description |
|
|
134
|
-
| ------------------------------ | --------------------------- | ----------------------------------------------------- |
|
|
135
|
-
| `KLAVIYO_API_KEY` | Yes | Klaviyo private API key (starts with `pk_`) |
|
|
136
|
-
| `SHOPIFY_STORE` | For Shopify | Your `*.myshopify.com` domain |
|
|
137
|
-
| `SHOPIFY_CLIENT_ID` | For Shopify (Dev Dashboard) | App client ID |
|
|
138
|
-
| `SHOPIFY_CLIENT_SECRET` | For Shopify (Dev Dashboard) | App client secret (starts with `shpss_`) |
|
|
139
|
-
| `SHOPIFY_ACCESS_TOKEN` | For Shopify (Legacy) | Admin API access token (starts with `shpat_`) |
|
|
140
|
-
| `SHOPIFY_API_VERSION` | No | Shopify API version (default: `2026-01`) |
|
|
141
|
-
| `KLAVIYO_CONVERSION_METRIC_ID` | No | Override auto-discovered "Placed Order" metric ID |
|
|
142
|
-
| `LOG_LEVEL` | No | `debug` | `info` | `warn` | `error` (default: `info`) |
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
## Tool Reference
|
|
146
|
-
|
|
147
|
-
### Klaviyo Tools
|
|
148
|
-
|
|
149
|
-
#### `klaviyo_campaign_summary`
|
|
150
|
-
|
|
151
|
-
Top campaigns ranked by metric. Returns name, send date, opens, clicks, revenue.
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
| Parameter | Type | Default | Description |
|
|
155
|
-
| --------- | ------------------------------------------------------------- | ----------- | --------------- |
|
|
156
|
-
| `channel` | `"email"` | `"sms"` | required | Channel filter |
|
|
157
|
-
| `metric` | `"revenue"` | `"open_rate"` | `"click_rate"` | `"recipients"` | `"revenue"` | Rank by |
|
|
158
|
-
| `days` | 1-365 | 30 | Lookback period |
|
|
159
|
-
| `limit` | 1-25 | 10 | Max results |
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
> "Show me my top email campaigns by revenue this month"
|
|
163
|
-
|
|
164
|
-
#### `klaviyo_campaign_detail`
|
|
165
|
-
|
|
166
|
-
Deep dive on one campaign: full metrics, subject line, audiences, send time.
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
| Parameter | Type | Default | Description |
|
|
170
|
-
| ------------- | ------ | -------- | ------------------- |
|
|
171
|
-
| `campaign_id` | string | required | Klaviyo campaign ID |
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
> "Give me the full breakdown on my Black Friday campaign"
|
|
175
|
-
|
|
176
|
-
#### `klaviyo_flow_summary`
|
|
177
|
-
|
|
178
|
-
Top flows by metric. Returns name, status, trigger, message count, revenue.
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
| Parameter | Type | Default | Description |
|
|
182
|
-
| --------- | ------------------------------------------------------------------- | ----------- | ---------------- |
|
|
183
|
-
| `metric` | `"revenue"` | `"click_rate"` | `"conversion_rate"` | `"recipients"` | `"revenue"` | Rank by |
|
|
184
|
-
| `days` | 1-365 | 30 | Lookback period |
|
|
185
|
-
| `status` | `"live"` | `"draft"` | `"manual"` | `"all"` | `"live"` | Filter by status |
|
|
186
|
-
| `limit` | 1-25 | 10 | Max results |
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
> "Which of my flows generates the most revenue?"
|
|
190
|
-
|
|
191
|
-
#### `klaviyo_flow_detail`
|
|
192
|
-
|
|
193
|
-
Deep dive on one flow: per-message performance breakdown.
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
| Parameter | Type | Default | Description |
|
|
197
|
-
| --------- | ------ | -------- | --------------- |
|
|
198
|
-
| `flow_id` | string | required | Klaviyo flow ID |
|
|
199
|
-
| `days` | 1-365 | 30 | Lookback period |
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
> "Show me the per-email breakdown of my welcome flow"
|
|
203
|
-
|
|
204
|
-
#### `klaviyo_subscriber_health`
|
|
205
|
-
|
|
206
|
-
List growth and engagement tier breakdown.
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
| Parameter | Type | Default | Description |
|
|
210
|
-
| --------- | ------ | -------- | --------------------------- |
|
|
211
|
-
| `list_id` | string | optional | Specific list, or all lists |
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
> "What's the health of my email list?"
|
|
215
|
-
|
|
216
|
-
#### `klaviyo_list_segments`
|
|
217
|
-
|
|
218
|
-
All lists and segments with sizes.
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
| Parameter | Type | Default | Description |
|
|
222
|
-
| --------- | ---------------------------------- | -------- | ----------------- |
|
|
223
|
-
| `type` | `"lists"` | `"segments"` | `"all"` | `"all"` | Filter by type |
|
|
224
|
-
| `cursor` | string | optional | Pagination cursor |
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
> "List all my Klaviyo segments and their sizes"
|
|
228
|
-
|
|
229
|
-
#### `klaviyo_search_profiles`
|
|
230
|
-
|
|
231
|
-
Find profiles by email, phone, or name.
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
| Parameter | Type | Default | Description |
|
|
235
|
-
| --------- | ------ | -------- | --------------------- |
|
|
236
|
-
| `query` | string | required | Email, phone, or name |
|
|
237
|
-
| `limit` | 1-10 | 5 | Max results |
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
> "Look up the profile for [john@example.com](mailto:john@example.com)"
|
|
241
|
-
|
|
242
|
-
#### `klaviyo_recent_activity`
|
|
243
|
-
|
|
244
|
-
Recent events for a metric (e.g., Placed Order, Opened Email).
|
|
91
|
+
**Why a sidecar:** Claude Desktop is an Electron app with macOS hardened runtime + Library Validation. Native modules loaded into the Claude Desktop process must share Anthropic's Team ID — which we can't sign with. Spawning the user's `/usr/local/bin/node` as a child process sidesteps the restriction; the child has its own hardened-runtime status, so `isolated-vm` loads cleanly.
|
|
245
92
|
|
|
93
|
+
Node discovery walks: `DTC_MCP_NODE_PATH` env var → `which node` / `where node` → Homebrew (Intel + Apple Silicon) → standard system paths → nvm → Volta → fnm → asdf. Requires Node ≥ 20.
|
|
246
94
|
|
|
247
|
-
|
|
248
|
-
| --------------- | ------ | ---------------- | --------------------- |
|
|
249
|
-
| `metric_name` | string | `"Placed Order"` | Metric name |
|
|
250
|
-
| `days` | 1-90 | 7 | Lookback period |
|
|
251
|
-
| `limit` | 1-25 | 10 | Max events |
|
|
252
|
-
| `profile_email` | string | optional | Filter to one profile |
|
|
95
|
+
### Fallback: in-process `node:vm`
|
|
253
96
|
|
|
97
|
+
If no system Node ≥ 20 is found, or the sidecar fails to start, the server falls back to a `node:vm` runner in the main process. Sandbox surface is identical (same `globalThis`, same helpers, same state semantics), but isolation is weaker — `node:vm` is a mistake fence, not a security boundary, and can be escaped via prototype-chain tricks. Acceptable because the threat model is "the user's own LLM might write buggy code," not "an attacker is trying to escape."
|
|
254
98
|
|
|
255
|
-
|
|
99
|
+
Every `execute_code` result includes `"sandbox": "sidecar"` or `"sandbox": "vm"` so you (and the LLM) can see which mode ran.
|
|
256
100
|
|
|
257
|
-
###
|
|
101
|
+
### Stateful sessions
|
|
258
102
|
|
|
259
|
-
|
|
103
|
+
A single sandbox context lives for the lifetime of the MCP connection. `globalThis.x = ...` in one `execute_code` call is visible in every later call. `const`/`let` declared at the top of a script are scoped to that call only — use `globalThis` for anything you want to carry forward.
|
|
260
104
|
|
|
261
|
-
|
|
105
|
+
The context is recreated on: connection close, 30 min idle, isolate OOM, or first call after a long gap. When that happens the next result includes `"sessionReset": true` so the LLM knows prior state is gone.
|
|
262
106
|
|
|
107
|
+
### Output discipline
|
|
263
108
|
|
|
264
|
-
|
|
265
|
-
| ------------------ | ------- | ------- | ---------------------------------- |
|
|
266
|
-
| `days` | 1-90 | 30 | Lookback period |
|
|
267
|
-
| `compare_previous` | boolean | true | Include previous period comparison |
|
|
109
|
+
Klaviyo and Shopify endpoints return verbose JSON. The host caps any `execute_code` return value at 100 KB (configurable via `DTC_MCP_MAX_RESPONSE_KB`); oversized returns are replaced with `{ truncated: true, preview, instructions }`. The sandbox-side `pick` / `topN` / `summarize` helpers exist so the LLM can stay under the cap by design — see the `guide.output-discipline` doc chunk for examples.
|
|
268
110
|
|
|
111
|
+
### Docs delivery
|
|
269
112
|
|
|
270
|
-
|
|
113
|
+
`search_docs` and `read_doc` query an in-memory MiniSearch index built from `data/docs.json`. The bundled copy ships with ~330 chunks (hand-authored guides + recipes + auto-generated reference for every Klaviyo OpenAPI endpoint). A background fetch on startup pulls a fresher copy from `https://cdn.jsdelivr.net/gh/rafaelsztutman/dtc-mcp-docs@latest/docs.json` (ETag-cached at `~/.cache/dtc-mcp/docs.json`), so new API endpoints land without a new MCP release. Set `DTC_MCP_DOCS_REFRESH=0` for fully offline use.
|
|
271
114
|
|
|
272
|
-
|
|
115
|
+
---
|
|
273
116
|
|
|
274
|
-
|
|
117
|
+
## Install
|
|
275
118
|
|
|
119
|
+
### Option A — Claude Desktop one-click
|
|
276
120
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
121
|
+
1. Download `dtc-mcp.mcpb` from the latest [GitHub release](https://github.com/rafaelsztutman/dtc-mcp/releases).
|
|
122
|
+
2. Double-click the file. Claude Desktop opens an install dialog.
|
|
123
|
+
3. Paste your Klaviyo API key (required) and Shopify credentials (optional).
|
|
124
|
+
4. Restart Claude Desktop. Three tools appear in the hammer menu: `execute_code`, `search_docs`, `read_doc`.
|
|
281
125
|
|
|
126
|
+
### Option B — manual config (`claude_desktop_config.json`, Cursor, etc.)
|
|
282
127
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
#### `shopify_order_search`
|
|
300
|
-
|
|
301
|
-
Find orders by number, email, or status.
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
| Parameter | Type | Default | Description |
|
|
305
|
-
| --------- | ------ | -------- | ----------------------------------------------- |
|
|
306
|
-
| `query` | string | required | Order number, email, or `financial_status:paid` |
|
|
307
|
-
| `limit` | 1-25 | 10 | Max results |
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
> "Find order #1234"
|
|
311
|
-
|
|
312
|
-
#### `shopify_inventory_alerts`
|
|
313
|
-
|
|
314
|
-
Products with low or zero stock, sorted by most urgent.
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
| Parameter | Type | Default | Description |
|
|
318
|
-
| ----------- | ------ | ------- | ------------------------------- |
|
|
319
|
-
| `threshold` | number | 10 | Alert at or below this quantity |
|
|
320
|
-
| `limit` | 1-50 | 20 | Max results |
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
> "Which products are running low on stock?"
|
|
324
|
-
|
|
325
|
-
#### `shopify_customer_cohorts`
|
|
326
|
-
|
|
327
|
-
Monthly or quarterly acquisition cohorts with LTV and retention signals.
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
| Parameter | Type | Default | Description |
|
|
331
|
-
| ------------- | --------------------------- | ----------- | --------------- |
|
|
332
|
-
| `granularity` | `"monthly"` | `"quarterly"` | `"monthly"` | Cohort grouping |
|
|
333
|
-
| `months` | 1-24 | 12 | Lookback period |
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
> "Show me customer cohorts by month — which cohort has the best LTV?"
|
|
337
|
-
|
|
338
|
-
#### `shopify_customer_segments`
|
|
339
|
-
|
|
340
|
-
Customer distribution by RFM group, spend tier, country, or tags.
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
| Parameter | Type | Default | Description |
|
|
344
|
-
| ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ---------------------- |
|
|
345
|
-
| `dimension` | `"rfm_group"` | `"predicted_spend_tier"` | `"customer_email_subscription_status"` | `"customer_sms_subscription_status"` | `"customer_country"` | `"customer_tag"` | `"customer_number_of_orders"` | required | Segmentation dimension |
|
|
346
|
-
| `months` | 1-24 | 12 | Lookback period |
|
|
347
|
-
| `limit` | 1-50 | 20 | Max segments |
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
> "Break down my customers by RFM group — who are my champions vs at-risk?"
|
|
351
|
-
|
|
352
|
-
#### `shopify_sales_breakdown`
|
|
353
|
-
|
|
354
|
-
Revenue and orders broken down by country, channel, vendor, or traffic source.
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
| Parameter | Type | Default | Description |
|
|
358
|
-
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- | ------------------- |
|
|
359
|
-
| `dimension` | `"billing_country"` | `"billing_region"` | `"channel_name"` | `"product_vendor"` | `"referrer_source"` | `"referring_channel"` | `"referring_platform"` | `"traffic_type"` | `"shipping_country"` | required | Breakdown dimension |
|
|
360
|
-
| `days` | 1-365 | 30 | Lookback period |
|
|
361
|
-
| `metric` | `"total_sales"` | `"net_sales"` | `"orders"` | `"average_order_value"` | `"gross_profit"` | `"net_sales"` | Metric to rank by |
|
|
362
|
-
| `limit` | 1-50 | 10 | Max results |
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
> "What are my top countries by revenue?" or "Break down sales by channel"
|
|
366
|
-
|
|
367
|
-
#### `shopify_product_analytics`
|
|
368
|
-
|
|
369
|
-
Product performance with margins, returns, and quantities via ShopifyQL.
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
| Parameter | Type | Default | Description |
|
|
373
|
-
| --------- | --------------------------------------------------------------- | ------------- | ---------------- |
|
|
374
|
-
| `days` | 1-365 | 30 | Lookback period |
|
|
375
|
-
| `metric` | `"net_sales"` | `"gross_sales"` | `"orders"` | `"gross_profit"` | `"net_sales"` | Sort products by |
|
|
376
|
-
| `limit` | 1-50 | 10 | Max results |
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
> "Which products have the best margins?" or "Show product performance with return rates"
|
|
380
|
-
|
|
381
|
-
#### `shopify_traffic_sources`
|
|
382
|
-
|
|
383
|
-
Session analytics by source, landing page, or daily trend.
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
| Parameter | Type | Default | Description |
|
|
387
|
-
| --------- | ------------------------------------------- | ----------- | --------------- |
|
|
388
|
-
| `mode` | `"sources"` | `"landing_pages"` | `"trend"` | `"sources"` | Analysis mode |
|
|
389
|
-
| `days` | 1-365 | 30 | Lookback period |
|
|
390
|
-
| `limit` | 1-50 | 10 | Max results |
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
> "Where is my traffic coming from?" or "What are my top landing pages?"
|
|
394
|
-
|
|
395
|
-
#### `shopify_returns_analysis`
|
|
396
|
-
|
|
397
|
-
Return rates, costs, and most-returned products.
|
|
398
|
-
|
|
128
|
+
```json
|
|
129
|
+
{
|
|
130
|
+
"mcpServers": {
|
|
131
|
+
"dtc-mcp": {
|
|
132
|
+
"command": "npx",
|
|
133
|
+
"args": ["-y", "dtc-mcp"],
|
|
134
|
+
"env": {
|
|
135
|
+
"KLAVIYO_API_KEY": "pk_your_private_key_here",
|
|
136
|
+
"SHOPIFY_STORE": "your-store.myshopify.com",
|
|
137
|
+
"SHOPIFY_CLIENT_ID": "your_client_id",
|
|
138
|
+
"SHOPIFY_CLIENT_SECRET": "shpss_your_secret"
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
```
|
|
399
144
|
|
|
400
|
-
|
|
401
|
-
| --------- | ---------------------------- | ----------- | --------------------------------------- |
|
|
402
|
-
| `mode` | `"summary"` | `"by_product"` | `"summary"` | Summary totals or per-product breakdown |
|
|
403
|
-
| `days` | 1-365 | 30 | Lookback period |
|
|
404
|
-
| `limit` | 1-50 | 10 | Max results (by_product mode) |
|
|
145
|
+
Klaviyo-only mode: omit the `SHOPIFY_*` variables. `shopify.*` calls throw a configuration error; `klaviyo.*` calls work normally.
|
|
405
146
|
|
|
147
|
+
### Option C — npm global install
|
|
406
148
|
|
|
407
|
-
|
|
149
|
+
```bash
|
|
150
|
+
npm install -g dtc-mcp
|
|
151
|
+
dtc-mcp # runs the MCP server on stdio
|
|
152
|
+
```
|
|
408
153
|
|
|
409
|
-
|
|
154
|
+
---
|
|
410
155
|
|
|
411
|
-
|
|
156
|
+
## Getting credentials
|
|
412
157
|
|
|
158
|
+
### Klaviyo
|
|
413
159
|
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
160
|
+
1. Log into Klaviyo. **Settings → Account → API Keys** (left sidebar).
|
|
161
|
+
2. **Create Private API Key**. Name it `dtc-mcp`.
|
|
162
|
+
3. Grant read-only scopes: `campaigns:read`, `flows:read`, `lists:read`, `segments:read`, `profiles:read`, `metrics:read`, `events:read`.
|
|
163
|
+
4. Copy the `pk_...` key.
|
|
417
164
|
|
|
165
|
+
### Shopify
|
|
418
166
|
|
|
419
|
-
|
|
167
|
+
Two auth modes. Use whichever matches your app type.
|
|
420
168
|
|
|
421
|
-
|
|
169
|
+
**Dev Dashboard app (recommended, required for apps created after Jan 2026):**
|
|
422
170
|
|
|
423
|
-
|
|
171
|
+
1. Open your app in the [Shopify Partners Dashboard](https://partners.shopify.com).
|
|
172
|
+
2. **Configuration → Client credentials.** Copy the Client ID and Client Secret.
|
|
173
|
+
3. Required scopes: `read_orders`, `read_products`, `read_customers`, `read_inventory`, `read_reports`.
|
|
424
174
|
|
|
425
|
-
|
|
175
|
+
Env vars:
|
|
426
176
|
|
|
177
|
+
```
|
|
178
|
+
SHOPIFY_STORE=your-store.myshopify.com
|
|
179
|
+
SHOPIFY_CLIENT_ID=your_client_id
|
|
180
|
+
SHOPIFY_CLIENT_SECRET=shpss_your_secret
|
|
181
|
+
```
|
|
427
182
|
|
|
428
|
-
|
|
429
|
-
| --------- | ----- | ------- | --------------- |
|
|
430
|
-
| `days` | 1-365 | 30 | Lookback period |
|
|
183
|
+
**Legacy custom app (apps created before Jan 2026):**
|
|
431
184
|
|
|
185
|
+
1. Shopify Admin → **Settings → Apps and sales channels → Develop apps**, open your app.
|
|
186
|
+
2. **API credentials** → copy the Admin API access token (`shpat_...`).
|
|
432
187
|
|
|
433
|
-
|
|
188
|
+
Env vars:
|
|
434
189
|
|
|
435
|
-
|
|
190
|
+
```
|
|
191
|
+
SHOPIFY_STORE=your-store.myshopify.com
|
|
192
|
+
SHOPIFY_ACCESS_TOKEN=shpat_your_token_here
|
|
193
|
+
```
|
|
436
194
|
|
|
437
|
-
|
|
195
|
+
Do not set both auth modes at once; the server logs a warning and uses Client Credentials if both are present.
|
|
438
196
|
|
|
197
|
+
---
|
|
439
198
|
|
|
440
|
-
|
|
441
|
-
| --------- | ---- | ------- | --------------- |
|
|
442
|
-
| `days` | 7-90 | 30 | Lookback period |
|
|
199
|
+
## Environment
|
|
443
200
|
|
|
201
|
+
| Variable | Required | Description |
|
|
202
|
+
|---|---|---|
|
|
203
|
+
| `KLAVIYO_API_KEY` | Yes | Klaviyo private API key (`pk_...`) |
|
|
204
|
+
| `SHOPIFY_STORE` | For Shopify | `*.myshopify.com` domain |
|
|
205
|
+
| `SHOPIFY_CLIENT_ID` | Dev Dashboard auth | App Client ID |
|
|
206
|
+
| `SHOPIFY_CLIENT_SECRET` | Dev Dashboard auth | App Client Secret (`shpss_...`) |
|
|
207
|
+
| `SHOPIFY_ACCESS_TOKEN` | Legacy custom app | Admin API token (`shpat_...`) |
|
|
208
|
+
| `SHOPIFY_API_VERSION` | No | Default `2026-01` |
|
|
209
|
+
| `KLAVIYO_CONVERSION_METRIC_ID` | No | Override auto-discovered "Placed Order" metric ID |
|
|
210
|
+
| `DTC_MCP_SANDBOX` | No | `auto` (default) \| `sidecar` (require isolated-vm) \| `vm` (force `node:vm`) |
|
|
211
|
+
| `DTC_MCP_NODE_PATH` | No | Absolute path to the Node binary used by the sidecar. Skips discovery. |
|
|
212
|
+
| `DTC_MCP_MAX_RESPONSE_KB` | No | Cap on bytes of `execute_code` return values (default `100`). |
|
|
213
|
+
| `DTC_MCP_DOCS_URL` | No | Override docs source. Default: jsDelivr → `dtc-mcp-docs@latest`. |
|
|
214
|
+
| `DTC_MCP_DOCS_REFRESH` | No | Set to `0` to disable the background docs refresh (offline mode). |
|
|
215
|
+
| `LOG_LEVEL` | No | `debug` \| `info` \| `warn` \| `error` (default `info`) |
|
|
444
216
|
|
|
445
|
-
|
|
217
|
+
---
|
|
446
218
|
|
|
447
|
-
##
|
|
219
|
+
## Development
|
|
448
220
|
|
|
449
|
-
|
|
221
|
+
```bash
|
|
222
|
+
npm install # installs deps, builds isolated-vm via node-gyp
|
|
223
|
+
npm run build # tsc → dist/
|
|
224
|
+
npm run dev # tsc --watch
|
|
225
|
+
npm test # vitest (53 tests)
|
|
226
|
+
npm run inspect # MCP Inspector — connect any client to dist/index.js
|
|
227
|
+
```
|
|
450
228
|
|
|
451
|
-
|
|
452
|
-
- "Which flow is generating the most revenue? Drill into the top one."
|
|
453
|
-
- "Show me daily revenue for this month so I can compare against my Shopify dashboard"
|
|
454
|
-
- "What's my gross vs net revenue for the past 30 days?"
|
|
455
|
-
- "Which products are my best sellers this week?"
|
|
456
|
-
- "Are any products running low on stock?"
|
|
457
|
-
- "What percentage of my revenue comes from email marketing?"
|
|
458
|
-
- "How many new vs returning customers did I have this quarter?"
|
|
459
|
-
- "Show me customer cohorts by month — which has the best LTV?"
|
|
460
|
-
- "Break down my customers by RFM group"
|
|
461
|
-
- "What are my top countries by revenue?"
|
|
462
|
-
- "Where is my traffic coming from?"
|
|
463
|
-
- "What's my return rate? Which products get returned the most?"
|
|
464
|
-
- "Which products have the best margins?"
|
|
465
|
-
- "Give me a complete health dashboard for my business"
|
|
466
|
-
- "Compare this month's sales to last month"
|
|
467
|
-
- "What are my top SMS campaigns by click rate?"
|
|
229
|
+
### Building the .mcpb bundle
|
|
468
230
|
|
|
469
|
-
|
|
231
|
+
```bash
|
|
232
|
+
tools/build-mcpb.sh # → dtc-mcp-v<version>.mcpb in repo root
|
|
233
|
+
```
|
|
470
234
|
|
|
471
|
-
|
|
235
|
+
Stages prod-only dependencies, ad-hoc code-signs native `.node` binaries (macOS requirement), and zips into a `.mcpb` ready for one-click install.
|
|
472
236
|
|
|
473
|
-
|
|
237
|
+
### Regenerating bundled docs
|
|
474
238
|
|
|
475
239
|
```bash
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
npm
|
|
479
|
-
cp .env.example .env # Fill in your API credentials
|
|
480
|
-
npm run build # Compile TypeScript
|
|
481
|
-
npm test # Run tests (46 tests)
|
|
482
|
-
npm run dev # Watch mode
|
|
483
|
-
npm run inspect # Open MCP Inspector for interactive testing
|
|
240
|
+
npm run codegen:klaviyo # download Klaviyo OpenAPI, emit chunk JSON
|
|
241
|
+
npm run codegen:shopify # introspect Shopify GraphQL (needs SHOPIFY_* env), emit chunks
|
|
242
|
+
npm run codegen:docs # merge guides + chunks into data/docs.json
|
|
484
243
|
```
|
|
485
244
|
|
|
245
|
+
In production this runs daily on a GitHub Action in [dtc-mcp-docs](https://github.com/rafaelsztutman/dtc-mcp-docs); the MCP fetches the freshest copy on the next boot.
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
486
249
|
## License
|
|
487
250
|
|
|
488
|
-
MIT
|
|
251
|
+
MIT. See `LICENSE`.
|