@apex-inc/mcp-server 0.27.1 → 0.27.3

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.
@@ -13,6 +13,17 @@
13
13
  ## Implementation
14
14
  - Resolve the variant with the canonical Apex resolver (`useApexVariant` on web,
15
15
  `Apex.getVariant()` on mobile). Both fire the `experiment_exposure` event.
16
+ - Merchants still write `const variant = useApexVariant("exp_…")` and branch.
17
+ First HTML is flicker-free only when the server already assigned the visitor
18
+ and passed that arm (`initialVariant` or `<ApexProvider assignments>`).
19
+ Mint or read `apex_vid` on the document request and assign with the same
20
+ rules as `GET /api/experiments/{id}/assign`. If you use Next.js,
21
+ `npm install @apex-inc/next @apex-inc/react`, then
22
+ `apexVisitorMiddleware`, `assignExperiments`,
23
+ `<ApexProvider assignments>`. The hook alone is not flicker-free. A
24
+ client-only SPA cannot know the arm before first HTML; do not promise
25
+ no flicker there. Do not hide the page until assign (worse LCP).
26
+ Creating the experiment via MCP does not remove flicker.
16
27
  - The variant must fall back to control on ineligible / error.
17
28
  - For VISUAL changes, confirm the arms actually differ — screenshot both. Class
18
29
  overrides can silently no-op (e.g. when the codebase doesn't tailwind-merge),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apex-inc/mcp-server",
3
- "version": "0.27.1",
3
+ "version": "0.27.3",
4
4
  "description": "MCP server for Apex \u2014 currently in private beta.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -137,7 +137,7 @@ Read these resources before suggesting communications-related actions to underst
137
137
  1. list_communications(pipeline="transactional", channel="email")
138
138
  → narrow to the pipeline + channel the step needs. 'transactional'
139
139
  bypasses opt-out and is ONLY valid after a recipient-initiated trigger
140
- (user_signup, password_reset_requested). 'marketing' is consent-gated.
140
+ (user_signed_up, password_reset_requested). 'marketing' is consent-gated.
141
141
  2. Read each row's subject + one-line body preview to disambiguate similar
142
142
  titles — you do NOT need to preview_communication every candidate.
143
143
  3. Pick by `id` (+ its version) and attach it to the send step.
@@ -153,7 +153,7 @@ hard-block**. For those journeys, filter to `pipeline="marketing"`.
153
153
  2. generate_communications with the welcome entry ID
154
154
  3. edit_communication to customize copy
155
155
  4. send_test_communication to preview
156
- 5. Show user the apex.track("user_signup") call to add
156
+ 5. Show user the apex.track("user_signed_up") call to add
157
157
  ```
158
158
 
159
159
  ### "My churn rate is high"
@@ -73,7 +73,13 @@ Interactive flows: MCP prompts `new-experiment` and `experiment-review` orchestr
73
73
  - **Target URL is this workspace.** `target_url` must be a host named on the **active** workspace (`list_workspace_environments` + the workspace site). If the merchant already named a workspace, switch to it — do not ask which workspace again. If they have multiple hosts on that workspace, ask which URL. Never guess `apex.inc` or any other workspace's domain.
74
74
  - **Mobile/Capacitor experiments capture on-device.** When the experiment runs on an authed in-app screen (servers can't reach it), tell the dev to call `Apex.captureVariantScreenshot({ experimentId, variantKey })` on the variant's screen, keyed to the resolved variant in a `useEffect`, in a debug build (`Apex.initialize({ ..., debug: true })`). It no-ops in production and lands the shot on the dashboard card + gallery like web/agent captures.
75
75
  - **Exposure auto-fires.** When a variant resolves via `useApexVariant` (web) or `Apex.getVariant()` (mobile), the SDK fires the canonical `experiment_exposure` event — the denominator for results. You don't fire it manually.
76
- - **Preview on Next.js.** `useApexVariant` cannot read `window` during SSR. Pass the request search string (`useApexVariant(id, { search })` from `searchParams`, or `<ApexProvider search>`) so the first HTML matches `_apex_preview`. Without it the server renders control and the arm only appears after hydrate.
76
+ - **First HTML / flicker.** Merchants still write `const variant = useApexVariant("exp_…")` and branch in React. That hook is not flicker-free by itself. First HTML is flicker-free only when it is already the assigned arm.
77
+ - **SSR (Next, Remix):** on the document request, mint or read the `apex_vid` cookie. Assign with the same rules as `GET /api/experiments/{id}/assign`. Pass that arm: `useApexVariant(id, { initialVariant, search })` or `<ApexProvider assignments={{ [id]: variant }}>`. `{ search }` also makes `_apex_preview` match on first HTML. Without the server arm, the first HTML is control; after `/assign` returns, React swaps. That swap is the flicker.
78
+ - **If you use Next.js:** `npm install @apex-inc/next` (visitor middleware + `assignExperiments`). Pass the result to `<ApexProvider assignments>`.
79
+ - **Client-only SPA:** the hook cannot know the arm before first HTML. Do not promise no flicker.
80
+ - **Snippet mode** (Apex mutates the DOM) is a different path. Do not conflate. Do not hide the page until `/assign` returns as the React-hook promise (worse LCP).
81
+ - **MCP does not serve the visitor page.** `create_experiment` / `activate_experiment` do not remove flicker. The merchant app must still pass the server arm.
82
+ - Pass the server arm into the hook or provider. `@apex-inc/react@0.4.3` accepts `initialVariant` and `ApexProvider assignments`.
77
83
  - **Don't launch a dead experiment.** `activate_experiment` is gated on `verify_experiment_wiring`. Code-wired (SDK-hook) web experiments are safe to activate before their code ships: the server holds them in `pending_deployment` ("Waiting on deploy"). The 14-day clock starts at the first **recorded** visit (a tester on a named Beta site, or a live visit) — not merge, not activate. Testers on a named Beta site count in the winner. Localhost/dev is recorded as Dev and does not start the window or decide the winner. Assign with no Origin is Unclassified (no enrollment). Backend assign must send `environment` or `x-apex-web-environment`. Non-SDK experiments with unwired arms are refused (pass `force: true` to override). Run `verify_experiment_wiring({ experimentId })` after the deploy lands to confirm both arms are live.
78
84
 
79
85
  ### Journey-arm experiments (any surface)
@@ -126,6 +132,8 @@ Omitting `intent` when it's required returns 409 `intent_required` naming both.
126
132
 
127
133
  `GET /api/experiments/{experimentId}/assign` returns `{ variant, experimentId, visitorId }`. Assignment is **deterministic** from a stable visitor id (cookie `apex_vid` in browsers).
128
134
 
135
+ The same assign call is how a Next/Remix document request gets flicker-free first HTML: read or mint `apex_vid`, assign, pass the arm into `useApexVariant` / `ApexProvider`. If you use Next.js, `@apex-inc/next` does that. See First HTML / flicker above.
136
+
129
137
  For **server-side** sends (e.g. PLG email or API-triggered notifications):
130
138
 
131
139
  1. Use a **stable string per recipient** as the visitor id (e.g. hashed user id). Reuse the same id for every assignment call for that user for that experiment.
@@ -137,7 +145,7 @@ Then branch notification copy or UI on `variant` (`control` vs `variant_b`).
137
145
  ## Instrumentation checklist
138
146
 
139
147
  1. **Create and activate** the experiment in Apex (UI or MCP).
140
- 2. **Assign variant** before rendering the experience.
148
+ 2. **Assign variant** before rendering the experience. On SSR, that means on the document request, then pass the arm into the hook or provider.
141
149
  3. **Track primary metric** events with consistent names (e.g. `notification_sent`, `notification_opened`, `goal_completed`) and include `experimentId` and `variant` in properties when possible.
142
150
  4. **Log a prediction** before launch when using the full intelligence loop (calibration).
143
151
  5. **Decide** with `get_results` / dashboard — avoid peeking without a rule (pre-registered sample size, Bayesian policy, or fixed run duration).
@@ -152,6 +160,8 @@ Match Apex UI terminology in user-facing copy: e.g. **Adaptive traffic allocatio
152
160
  - Declaring an SDK / Cursor draft ready from hosted screenshots of a public URL. The variant is local until deploy — attach localhost shots with `attach_experiment_asset`.
153
161
  - Starting an experiment without a **clear primary metric** tied to the belief.
154
162
  - Using different visitor ids for the same user across channels (breaks consistent assignment).
163
+ - Promising no flicker from `useApexVariant` without passing a server arm. Creating the experiment via MCP does not remove flicker.
164
+ - Hiding the page until `/assign` returns (worse LCP; not the React-hook promise).
155
165
  - Changing variant implementation mid-flight without versioning (invalidates analysis).
156
166
  - Only using p-values without effect size or business context.
157
167
 
@@ -27,7 +27,7 @@ Events are batched and sent to `POST /api/events` automatically. Call `flush()`
27
27
 
28
28
  ```typescript
29
29
  // On signup
30
- track("signup_completed", { method: "email", plan: "free" });
30
+ track("user_signed_up", { method: "email", plan: "free" });
31
31
  identify(user.id, {
32
32
  email: user.email,
33
33
  name: user.name,
@@ -117,7 +117,7 @@ For agent-driven testing through MCP, use the **`send_server_event`** tool — s
117
117
 
118
118
  ## Event naming conventions
119
119
 
120
- - **snake_case**: `signup_completed`, `feature_used`, `invoice_paid`
120
+ - **snake_case**: `user_signed_up`, `feature_used`, `invoice_paid`
121
121
  - Context in **properties**: `track("ui_action", { action: "click", name: "Start trial", location: "pricing" })`
122
122
  - For experiments, include `experimentId` and `variant` in properties
123
123
  - One primary metric per experiment; secondary metrics as properties