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
package/README.md CHANGED
@@ -1,484 +1,251 @@
1
1
  # dtc-mcp
2
2
 
3
- Context-optimized MCP server for DTC e-commerce brands. Connect Claude (or any MCP client) to your Klaviyo and Shopify data with 22 pre-built analytics tools.
3
+ **A code-execution MCP server for Klaviyo + Shopify analytics.**
4
4
 
5
- Unlike raw API wrappers, dtc-mcp pre-aggregates data server-side and returns only actionable fields using ~80% less context than dumping raw API responses into your conversation.
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
- Or run directly:
23
-
24
- ```bash
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
- ## Setup with Claude Desktop
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
- 1. Restart Claude Desktop
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
- If you only use Klaviyo (no Shopify), just omit the Shopify variables. The 8 Klaviyo tools and subscriber analytics will work standalone. Shopify tools will return a helpful "not configured" message.
20
+ ---
66
21
 
67
- ## Setup with ChatGPT
22
+ ## The three tools
68
23
 
69
- ChatGPT supports MCP servers via remote connections. Since dtc-mcp uses stdio transport (runs locally), you would need an MCP-to-HTTP bridge to expose it as a remote server. See [OpenAI's MCP documentation](https://platform.openai.com/docs/guides/tools-remote-mcp) for details on connecting remote MCP servers.
24
+ ### `execute_code(code)`
70
25
 
71
- ## Getting Your API Credentials
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
- ### Klaviyo API Key
28
+ **Globals available inside the sandbox:**
74
29
 
75
- 1. Log into [Klaviyo](https://www.klaviyo.com/login)
76
- 2. Go to **Settings** (bottom-left) > **Account** > **Settings**
77
- 3. Click **API Keys** in the left sidebar
78
- 4. Click **Create Private API Key**
79
- 5. Give it a name (e.g., "dtc-mcp")
80
- 6. Select **Read-only** access for these scopes:
81
- - `campaigns:read`
82
- - `flows:read`
83
- - `lists:read`
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
- ### Shopify Credentials
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
- There are two authentication methods. Use whichever matches your app type.
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
- #### Option A: Dev Dashboard App (Recommended)
44
+ ### `search_docs(query, platform?, limit?)`
95
45
 
96
- For apps created in the [Shopify Partners Dashboard](https://partners.shopify.com/) or Shopify CLI (required for new apps since January 2026):
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
- 1. Go to your app in the Partners Dashboard
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
- Set these environment variables:
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
- #### Option B: Legacy Custom App
58
+ ---
114
59
 
115
- For custom apps created directly in Shopify Admin (apps created before January 2026):
60
+ ## Architecture
116
61
 
117
- 1. Go to **Shopify Admin** > **Settings** > **Apps and sales channels**
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
- Set these environment variables:
64
+ ### Preferred: sidecar with isolated-vm
122
65
 
123
66
  ```
124
- SHOPIFY_STORE=your-store.myshopify.com
125
- SHOPIFY_ACCESS_TOKEN=shpat_your_token_here
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
- > Do not set both `SHOPIFY_ACCESS_TOKEN` and `SHOPIFY_CLIENT_ID`/`SHOPIFY_CLIENT_SECRET` at the same time. The server will error if both are present.
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`
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.
243
92
 
244
- Recent events for a metric (e.g., Placed Order, Opened Email).
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.
245
94
 
95
+ ### Fallback: in-process `node:vm`
246
96
 
247
- | Parameter | Type | Default | Description |
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 |
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."
253
98
 
99
+ Every `execute_code` result includes `"sandbox": "sidecar"` or `"sandbox": "vm"` so you (and the LLM) can see which mode ran.
254
100
 
255
- > "Show me the last 10 orders placed"
101
+ ### Stateful sessions
256
102
 
257
- ### Shopify Tools
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.
258
104
 
259
- #### `shopify_sales_summary`
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.
260
106
 
261
- Revenue (gross + net), orders, AOV for a period with comparison.
107
+ ### Output discipline
262
108
 
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.
263
110
 
264
- | Parameter | Type | Default | Description |
265
- | ------------------ | ------- | ------- | ---------------------------------- |
266
- | `days` | 1-90 | 30 | Lookback period |
267
- | `compare_previous` | boolean | true | Include previous period comparison |
111
+ ### Docs delivery
268
112
 
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.
269
114
 
270
- > "What were my sales last month compared to the month before?"
115
+ ---
271
116
 
272
- #### `shopify_sales_timeseries`
117
+ ## Install
273
118
 
274
- Revenue and orders broken down by day, week, or month.
119
+ ### Option A Claude Desktop one-click
275
120
 
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`.
276
125
 
277
- | Parameter | Type | Default | Description |
278
- | ------------- | ------------------------------------ | --------- | --------------- |
279
- | `days` | 1-365 | 30 | Lookback period |
280
- | `granularity` | `"daily"` | `"weekly"` | `"monthly"` | `"daily"` | Bucket size |
126
+ ### Option B manual config (`claude_desktop_config.json`, Cursor, etc.)
281
127
 
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
+ ```
282
144
 
283
- > "Show me daily revenue for this month"
284
-
285
- #### `shopify_product_performance`
286
-
287
- Top products by revenue or units sold.
288
-
289
-
290
- | Parameter | Type | Default | Description |
291
- | --------- | ----------------------- | ----------- | --------------- |
292
- | `days` | 1-90 | 7 | Lookback period |
293
- | `metric` | `"revenue"` | `"units"` | `"revenue"` | Rank by |
294
- | `limit` | 1-25 | 10 | Max results |
295
-
296
-
297
- > "Which products sold the most units this week?"
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.
145
+ Klaviyo-only mode: omit the `SHOPIFY_*` variables. `shopify.*` calls throw a configuration error; `klaviyo.*` calls work normally.
398
146
 
147
+ ### Option C — npm global install
399
148
 
400
- | Parameter | Type | Default | Description |
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) |
149
+ ```bash
150
+ npm install -g dtc-mcp
151
+ dtc-mcp # runs the MCP server on stdio
152
+ ```
405
153
 
154
+ ---
406
155
 
407
- > "What's my return rate?" or "Which products get returned the most?"
156
+ ## Getting credentials
408
157
 
409
- #### `shopify_recent_orders`
158
+ ### Klaviyo
410
159
 
411
- Most recent orders. Quick snapshot of store activity.
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.
412
164
 
165
+ ### Shopify
413
166
 
414
- | Parameter | Type | Default | Description |
415
- | --------- | ---- | ------- | ----------- |
416
- | `limit` | 1-25 | 10 | Max results |
167
+ Two auth modes. Use whichever matches your app type.
417
168
 
169
+ **Dev Dashboard app (recommended, required for apps created after Jan 2026):**
418
170
 
419
- > "Show me the last 10 orders"
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`.
420
174
 
421
- ### Cross-Platform Tools
175
+ Env vars:
422
176
 
423
- #### `dtc_email_revenue_attribution`
177
+ ```
178
+ SHOPIFY_STORE=your-store.myshopify.com
179
+ SHOPIFY_CLIENT_ID=your_client_id
180
+ SHOPIFY_CLIENT_SECRET=shpss_your_secret
181
+ ```
424
182
 
425
- Email/SMS revenue vs total Shopify revenue. Shows email marketing contribution.
183
+ **Legacy custom app (apps created before Jan 2026):**
426
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_...`).
427
187
 
428
- | Parameter | Type | Default | Description |
429
- | --------- | ----- | ------- | --------------- |
430
- | `days` | 1-365 | 30 | Lookback period |
188
+ Env vars:
431
189
 
190
+ ```
191
+ SHOPIFY_STORE=your-store.myshopify.com
192
+ SHOPIFY_ACCESS_TOKEN=shpat_your_token_here
193
+ ```
432
194
 
433
- > "What percentage of my revenue came from email?"
195
+ Do not set both auth modes at once; the server logs a warning and uses Client Credentials if both are present.
434
196
 
435
- #### `dtc_dashboard`
197
+ ---
436
198
 
437
- Complete DTC health dashboard: sales + email + subscriber metrics in one call.
199
+ ## Environment
438
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`) |
439
216
 
440
- | Parameter | Type | Default | Description |
441
- | --------- | ---- | ------- | --------------- |
442
- | `days` | 7-90 | 30 | Lookback period |
217
+ ---
443
218
 
219
+ ## Development
444
220
 
445
- > "Give me the full business dashboard for last month"
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
+ ```
446
228
 
447
- ## Example Queries
229
+ ### Building the .mcpb bundle
448
230
 
449
- Here are questions you can ask Claude once dtc-mcp is connected:
231
+ ```bash
232
+ tools/build-mcpb.sh # → dtc-mcp-v<version>.mcpb in repo root
233
+ ```
450
234
 
451
- - "How did my email campaigns perform this month?"
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?"
235
+ Stages prod-only dependencies, ad-hoc code-signs native `.node` binaries (macOS requirement), and zips into a `.mcpb` ready for one-click install.
468
236
 
469
- ## Development
237
+ ### Regenerating bundled docs
470
238
 
471
239
  ```bash
472
- git clone https://github.com/rafaelsztutman/dtc-mcp.git
473
- cd dtc-mcp
474
- npm install
475
- cp .env.example .env # Fill in your API credentials
476
- npm run build # Compile TypeScript
477
- npm test # Run tests (44 tests)
478
- npm run dev # Watch mode
479
- 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
480
243
  ```
481
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
+
482
249
  ## License
483
250
 
484
- MIT
251
+ MIT. See `LICENSE`.