@apex-inc/mcp-server 0.38.0 → 0.40.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 (54) hide show
  1. package/dist/api-client.d.ts +2 -0
  2. package/dist/api-client.d.ts.map +1 -1
  3. package/dist/api-client.js +7 -0
  4. package/dist/api-client.js.map +1 -1
  5. package/dist/auth.d.ts +22 -0
  6. package/dist/auth.d.ts.map +1 -1
  7. package/dist/auth.js +69 -4
  8. package/dist/auth.js.map +1 -1
  9. package/dist/letter-blocks.d.ts +17 -0
  10. package/dist/letter-blocks.d.ts.map +1 -1
  11. package/dist/letter-blocks.js +64 -0
  12. package/dist/letter-blocks.js.map +1 -1
  13. package/dist/preview-images.d.ts +9 -0
  14. package/dist/preview-images.d.ts.map +1 -0
  15. package/dist/preview-images.js +29 -0
  16. package/dist/preview-images.js.map +1 -0
  17. package/dist/setup-catchup-tools.d.ts +9 -5
  18. package/dist/setup-catchup-tools.d.ts.map +1 -1
  19. package/dist/setup-catchup-tools.js +32 -7
  20. package/dist/setup-catchup-tools.js.map +1 -1
  21. package/dist/smoke-tools.d.ts.map +1 -1
  22. package/dist/smoke-tools.js +2 -0
  23. package/dist/smoke-tools.js.map +1 -1
  24. package/dist/tool-catalog.d.ts.map +1 -1
  25. package/dist/tool-catalog.js +1 -0
  26. package/dist/tool-catalog.js.map +1 -1
  27. package/dist/tool-groups.d.ts.map +1 -1
  28. package/dist/tool-groups.js +14 -0
  29. package/dist/tool-groups.js.map +1 -1
  30. package/dist/tools/ad-platforms.d.ts +240 -0
  31. package/dist/tools/ad-platforms.d.ts.map +1 -0
  32. package/dist/tools/ad-platforms.js +294 -0
  33. package/dist/tools/ad-platforms.js.map +1 -0
  34. package/dist/tools/adoption.d.ts +24 -2
  35. package/dist/tools/adoption.d.ts.map +1 -1
  36. package/dist/tools/adoption.js +24 -3
  37. package/dist/tools/adoption.js.map +1 -1
  38. package/dist/tools/context.d.ts +10 -0
  39. package/dist/tools/context.d.ts.map +1 -1
  40. package/dist/tools/context.js +23 -0
  41. package/dist/tools/context.js.map +1 -1
  42. package/dist/tools/letters.d.ts +74 -2
  43. package/dist/tools/letters.d.ts.map +1 -1
  44. package/dist/tools/letters.js +98 -5
  45. package/dist/tools/letters.js.map +1 -1
  46. package/dist/tools.d.ts +371 -9
  47. package/dist/tools.d.ts.map +1 -1
  48. package/dist/tools.js +2 -0
  49. package/dist/tools.js.map +1 -1
  50. package/package.json +1 -1
  51. package/skills/apex-communications/SKILL.md +5 -1
  52. package/skills/apex-growth-tracking/SKILL.md +1 -0
  53. package/skills/apex-integration-cookbook/SKILL.md +18 -0
  54. package/skills/apex-journeys/SKILL.md +3 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apex-inc/mcp-server",
3
- "version": "0.38.0",
3
+ "version": "0.40.0",
4
4
  "description": "MCP server for Apex. Your coding agent talks to the same Apex the dashboard uses.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -57,6 +57,10 @@ A comm that's live in a published journey also needs `intent`, whatever its
57
57
  `add_communication_variant`, then `publish_communication` with `intent: "compete"`.
58
58
  Rewriting what's sending is `replace`.
59
59
 
60
+ Publishing switches every journey that sends the letter to the new version.
61
+ When the user wants some journeys to keep today's version, pass their ids in
62
+ `opt_out_journey_ids`.
63
+
60
64
  ### The two intents
61
65
 
62
66
  - **`intent: "compete"`** — *Start an experiment.* What's sending now stays
@@ -202,7 +206,7 @@ When you draft or edit a letter:
202
206
 
203
207
  - `list_communication_themes` before restyling a series.
204
208
  - `create_communication_theme` / `update_communication_theme` to save a look. Style saves do not rewrite other emails.
205
- - `apply_communication_theme` stamps a look onto chosen emails. Default is draft (merchant still publishes). Pass `apply=live` for the next send.
209
+ - `apply_communication_theme` stamps a look onto chosen emails. Default is draft (merchant still publishes). Pass `apply=live` for the next send: it publishes a version with only the look, and other unpublished edits stay drafts. Add `publish_edits_ids` only when the merchant asked to publish those edits too. Emails in a running test are skipped. Emails Apex couldn't check for a running test come back as `unchecked` with nothing changed: retry them, and pass `confirm_not_in_test_ids` only when the merchant says they aren't in a test. `publish_communication` refuses the same way (`test_check_unavailable`).
206
210
  - Never group communications by `experiment-*` catalog id. A shop's "Order updates" series is the same object as Apex's own status emails.
207
211
 
208
212
  ## Exit Rules: The Quiet Half of Lifecycle Messaging
@@ -38,6 +38,7 @@ When a user was anonymous and then becomes known (signup, login, checkout email)
38
38
 
39
39
  - Call **`identify`** with a stable `userId` and pass **`traits.email`** when applicable.
40
40
  - **Server-side** `identify` (webhooks, API routes): pass **`traits.visitorId`** = value of the browser **`apex_vid`** cookie so the stitch links to the real marketing session. Without it, Apex may create a synthetic visitor disconnected from prior events.
41
+ - **Sign-out**: call **`reset()`** from `@apex-inc/sdk` (or `window.apex.reset()` on snippet-only sites) in every logout handler. It starts the browser as a fresh anonymous visitor, so a shared computer does not credit the next person's visits to the last one. Without it, Apex still never merges two signed-in people; anonymous visits go to whoever signed in on that browser most recently.
41
42
 
42
43
  ## B2B accounts + groups (model the company, not just the seat)
43
44
 
@@ -369,3 +369,21 @@ const live = await apex.links.list({ enabled: true });
369
369
  ```
370
370
 
371
371
  Experiments live under `apex.experiments.*` (`list`, `get`, `getResults`, `activate`, `promote`, `assignVariant`, `checkConflicts`, `checkLiveTests`). `apex.mobile` is reserved for install attribution and SKAN values.
372
+
373
+ ## Recipe: Buyer lists on ad platforms (MCP)
374
+
375
+ A buyer list is one of the shop's segments, kept on Meta, Google or LinkedIn by Apex and refreshed every day. The shop picks it on an ad set once, to leave buyers out of prospecting or to find more people like them. Same as Attribution → Ad platforms → Who sees your ads.
376
+
377
+ 1. `list_audiences` shows each list, its segment, the goal it was made for, the platforms it goes to, the platforms it actually reached, and how many people it holds back.
378
+ 2. `update_audience` changes where a list goes (`platforms`) or how many people are held back (`holdout_percent`: 0, 5, 10 or 20). 0 stops holding anyone back. Dropping a platform the list already reached deletes the list there, which cannot be undone. Without `confirm_delete: true` the tool changes nothing and lists those platforms in `would_delete_from`; ask the shop, then call again with it. A platform that refuses the delete comes back in `refused`.
379
+ 3. `remove_audience` takes the list off every platform it reached. It cannot be undone and any ad set using it stops using it, so ask the shop first and pass `confirm: true` only after they say yes. A platform that refuses comes back in `refused`; tell the shop to delete it there by hand.
380
+
381
+ A held-back list that belongs to an Ad holdout experiment is the experiment's. These tools refuse it; pause or archive the experiment instead.
382
+
383
+ When someone asks to be deleted or opts out of ads, Apex takes them off every list right away. If a platform refuses or isn't connected, they stay on it, and `list_audience_removals` shows them: how many each list still owes per platform, why, and what the platform said. Apex retries every day for 30 days, then stops (`stopped_retrying`) and waits for the shop. Tell the shop plainly that people who asked to be removed are still being shown ads there. If `why` is `not_connected`, the shop reconnects the platform; then call `retry_audience_removals` with the list's id, which also tries the ones Apex stopped on. Its `still_owed` says who is left.
384
+
385
+ To add a list, start from what the shop wants its ads to do. `list_audience_goals` returns four goals: `win_back` (bought, but not within `window_days`, which comes from the shop's kind of business), `stop_paying` (everyone who ever bought, left out of ads for new people), `interested` (added to cart or started checkout in the last 30 days and never bought; `locked` until those events arrive) and `lookalike` (everyone who bought, with what each spent, for a Meta value-based lookalike). Each says where its list can go now (`networks`) and which lists the shop already made for it (`lists`). If a goal already has a list, ask whether they want another rather than a copy. Tell the shop who goes and where, then call `add_audience` with the goal and `confirm: true`. Apex saves the goal's rule as a segment named after the list, so the shop can change who's on it in Segments, and sends the list right away unless `send_now: false`. The result's `sent` says how many people each platform took. Spend goes only to Meta: neither LinkedIn's nor Google's list upload takes it, so a list that carries spend reaches them as the same people without it. Say so rather than calling a Google or LinkedIn list value-based.
386
+
387
+ Before sending one of the shop's own events (a trial start, a booked demo) to its ad platforms, call `preview_ad_platform_send` with the event name and what it means (`purchase`, `lead`, `signup`, `subscription`, `add_to_cart`, or `something_else`). Show the shop which platforms would hear it, under what name, and which can't and why, plus the `estimate`: how often it happened in the last 30 days and what a month of sends costs at the shop's price. It saves and sends nothing.
388
+
389
+ When the shop says yes, call `add_ad_platform_send` with the same event and meaning and `confirm: true`. It saves the send on the shop's Conversion for that event, so experiments and goals count the same thing. If that Conversion already means something else, the tool is refused; change the meaning on Conversions first rather than picking a different meaning to get around it. For `something_else`, Apex makes the conversion on Meta itself so campaigns can optimize for it; if `couldnt_make` comes back, tell the shop Meta's reason (usually a reconnect). A platform showing `not_agreed` only hears it after the shop agrees on Attribution → Ad platforms; the tool never agrees for them. If `without_consent_answer` is `not_sent`, only events that carry a yes go out. `list_ad_platform_sends` shows what is being sent, and `remove_ad_platform_send` stops one and keeps the Conversion.
@@ -121,6 +121,9 @@ The setup step in the dashboard does steps 1–5 in one click with a reach previ
121
121
  confirm_live_journey unless they picked an out.
122
122
  3. A draft that was never published cannot be archived. Only pass delete_draft:true if they said
123
123
  delete it.
124
+ 4. Letters nothing sends any more: archive_communication({ communication_id }) for each one they
125
+ picked. If a published journey still sends it, the tool names the journey and stops. Archive
126
+ or repoint that journey first. Only pass confirm_journey_refs:true if they said archive anyway.
124
127
  ```
125
128
 
126
129
  ### "Audit my journeys for missing exits"