dtc-mcp 0.2.1 → 1.0.1

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 -406
  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 -31
  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 -364
  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 -369
  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,488 +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`
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
- | 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 |
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
- > "Show me the last 10 orders placed"
99
+ Every `execute_code` result includes `"sandbox": "sidecar"` or `"sandbox": "vm"` so you (and the LLM) can see which mode ran.
256
100
 
257
- ### Shopify Tools
101
+ ### Stateful sessions
258
102
 
259
- #### `shopify_sales_summary`
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
- Revenue (gross + net), orders, AOV for a period with comparison.
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
- | Parameter | Type | Default | Description |
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
- > "What were my sales last month compared to the month before?"
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
- #### `shopify_sales_timeseries`
115
+ ---
273
116
 
274
- Revenue and orders broken down by day, week, or month.
117
+ ## Install
275
118
 
119
+ ### Option A — Claude Desktop one-click
276
120
 
277
- | Parameter | Type | Default | Description |
278
- | ------------- | ------------------------------------ | --------- | --------------- |
279
- | `days` | 1-365 | 30 | Lookback period |
280
- | `granularity` | `"daily"` | `"weekly"` | `"monthly"` | `"daily"` | Bucket size |
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
- > "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.
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
- | 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) |
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
- > "What's my return rate?" or "Which products get returned the most?"
149
+ ```bash
150
+ npm install -g dtc-mcp
151
+ dtc-mcp # runs the MCP server on stdio
152
+ ```
408
153
 
409
- #### `shopify_recent_orders`
154
+ ---
410
155
 
411
- Most recent orders. Quick snapshot of store activity.
156
+ ## Getting credentials
412
157
 
158
+ ### Klaviyo
413
159
 
414
- | Parameter | Type | Default | Description |
415
- | --------- | ---- | ------- | ----------- |
416
- | `limit` | 1-25 | 10 | Max results |
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
- > "Show me the last 10 orders"
167
+ Two auth modes. Use whichever matches your app type.
420
168
 
421
- ### Cross-Platform Tools
169
+ **Dev Dashboard app (recommended, required for apps created after Jan 2026):**
422
170
 
423
- #### `dtc_email_revenue_attribution`
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
- Email/SMS revenue vs total Shopify revenue. Shows email marketing contribution.
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
- | Parameter | Type | Default | Description |
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
- > "What percentage of my revenue came from email?"
188
+ Env vars:
434
189
 
435
- #### `dtc_dashboard`
190
+ ```
191
+ SHOPIFY_STORE=your-store.myshopify.com
192
+ SHOPIFY_ACCESS_TOKEN=shpat_your_token_here
193
+ ```
436
194
 
437
- Complete DTC health dashboard: sales + email + subscriber metrics in one call.
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
- | Parameter | Type | Default | Description |
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
- > "Give me the full business dashboard for last month"
217
+ ---
446
218
 
447
- ## Example Queries
219
+ ## Development
448
220
 
449
- Here are questions you can ask Claude once dtc-mcp is connected:
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
- - "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?"
229
+ ### Building the .mcpb bundle
468
230
 
469
- ## Privacy Policy
231
+ ```bash
232
+ tools/build-mcpb.sh # → dtc-mcp-v<version>.mcpb in repo root
233
+ ```
470
234
 
471
- dtc-mcp runs locally on your machine. It does not collect, store, or transmit any user data. API credentials are stored in your local MCP client configuration and used only to authenticate directly with Klaviyo and Shopify. No analytics, telemetry, or third-party data sharing. See [PRIVACY.md](PRIVACY.md) for full details.
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
- ## Development
237
+ ### Regenerating bundled docs
474
238
 
475
239
  ```bash
476
- git clone https://github.com/rafaelsztutman/dtc-mcp.git
477
- cd dtc-mcp
478
- npm install
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`.