@apex-inc/mcp-server 0.18.0 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/tools.d.ts +347 -0
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +204 -0
- package/dist/tools.js.map +1 -1
- package/package.json +1 -1
- package/skills/apex-adoption/SKILL.md +35 -0
- package/skills/apex-growth-tracking/SKILL.md +27 -0
- package/skills/apex-spec/SKILL.md +10 -0
package/package.json
CHANGED
|
@@ -29,9 +29,44 @@ The Adoption Engine tracks whether each end-user has adopted each feature, nudge
|
|
|
29
29
|
| `update_adoption_milestone` | Change priority / gap window / turn on/off |
|
|
30
30
|
| `delete_adoption_milestone` | Remove a milestone |
|
|
31
31
|
| `get_adoption_metrics` | Per-milestone funnel + lift-vs-holdout + workspace health |
|
|
32
|
+
| `list_adoption_features` / `create_adoption_feature` | Tenant-owned feature groupings (group your own events) |
|
|
33
|
+
| `list_segments` / `get_segment` / `create_segment` | Saved groups of customers — same grammar as milestones |
|
|
34
|
+
| `define_event` | Register an event's NAME before it fires (define ≠ fire) |
|
|
32
35
|
|
|
33
36
|
Read-only summary resource: `apex://adoption`.
|
|
34
37
|
|
|
38
|
+
## One grammar: define → wire → verify
|
|
39
|
+
|
|
40
|
+
Milestones and segments both describe "people who…" over the workspace's own
|
|
41
|
+
events + traits. The methodology is the same everywhere (dashboard, SDK, MCP):
|
|
42
|
+
|
|
43
|
+
1. **Define** — name the signal. If the event doesn't exist yet, `define_event`
|
|
44
|
+
registers it. Defining does NOT make it fire.
|
|
45
|
+
2. **Wire** — a developer calls `apex.track("your_event")` from the app (or
|
|
46
|
+
sends the trait via `apex.identify`). Until then it shows a "not seen yet"
|
|
47
|
+
dot.
|
|
48
|
+
3. **Verify** — once real events arrive, milestone lift / segment counts fill in.
|
|
49
|
+
|
|
50
|
+
### Segments — `create_segment`
|
|
51
|
+
|
|
52
|
+
Author with the friendly `conditions` grammar (snake_case sub-keys), or pass a
|
|
53
|
+
raw `predicate`:
|
|
54
|
+
|
|
55
|
+
```json
|
|
56
|
+
{
|
|
57
|
+
"name": "Power users who haven't upgraded",
|
|
58
|
+
"conditions": {
|
|
59
|
+
"match": "all",
|
|
60
|
+
"groups": [
|
|
61
|
+
{ "match": "all", "conditions": [
|
|
62
|
+
{ "verb": "has", "event": "report_run", "window_days": 30 },
|
|
63
|
+
{ "attribute": "plan", "op": "is_not", "value": "pro" }
|
|
64
|
+
] }
|
|
65
|
+
]
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
35
70
|
## Tool Invocation Order
|
|
36
71
|
|
|
37
72
|
### "Nudge users who haven't run their first report"
|
|
@@ -39,6 +39,33 @@ When a user was anonymous and then becomes known (signup, login, checkout email)
|
|
|
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
41
|
|
|
42
|
+
## B2B accounts + groups (model the company, not just the seat)
|
|
43
|
+
|
|
44
|
+
For B2B, revenue belongs to the **account** (company), not the individual. Add a nested `account` object to the SAME `identify` you already call at login/signup:
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
identify(user.id, {
|
|
48
|
+
email: user.email,
|
|
49
|
+
account: { id: "acct_acme", name: "Acme Inc", plan: "enterprise", seat_count: 25 },
|
|
50
|
+
});
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Apex upserts the Account, links the user as a member, and rolls every member's revenue into one account LTV (no double counting). `account.id` is required — Apex never infers the company from a shared email domain.
|
|
54
|
+
|
|
55
|
+
If your product has an intermediate org-unit layer (workspaces / teams / projects), assert it with `groups[]` on the same identify — the "model a team/workspace layer" recipe:
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
identify(user.id, {
|
|
59
|
+
account: { id: "acct_acme", name: "Acme Inc" },
|
|
60
|
+
groups: [
|
|
61
|
+
{ id: "ws_prod", name: "Production", kind: "workspace", role: "admin" },
|
|
62
|
+
{ id: "team_growth", name: "Growth Team", kind: "team", parent_id: "acct_acme" },
|
|
63
|
+
],
|
|
64
|
+
});
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Each group becomes a sub-account of `parent_id` (defaults to `account.id`) and the user is linked to it. Read it back with `apex.accounts.list()` / `.subaccounts(id)` / `.people(id)` / `.contactGroups(contactId)` (SDK) or `list_accounts` / `list_sub_accounts` / `get_contact_groups` (MCP). Revenue lands on the billed account; a parent's LTV is its own counters, not the sum of children.
|
|
68
|
+
|
|
42
69
|
## What to measure by loop phase
|
|
43
70
|
|
|
44
71
|
- **Acquisition**: landing views, campaign params (UTM already captured by snippet where configured), signup started.
|
|
@@ -105,6 +105,16 @@ Scan-first additions per vertical — wire where the truth lives:
|
|
|
105
105
|
(monthly|annual|quarterly|weekly) — quarantined for MRR otherwise.
|
|
106
106
|
`seat_count` unlocks seat growth. Account traits: `account_id`,
|
|
107
107
|
`plan`, `mrr`, `arr`, `seat_count` (typed via ApexAccountTraits).
|
|
108
|
+
For account-level rollup (B2B): send a nested `account` object on
|
|
109
|
+
`identify` — `identify(user.id, { account: { id, name, plan,
|
|
110
|
+
seat_count } })` — so revenue rolls up to the company, not the seat.
|
|
111
|
+
For an intermediate org-unit layer (workspaces / teams / projects),
|
|
112
|
+
add `groups[]` on the SAME identify: `groups: [{ id, name, kind,
|
|
113
|
+
parent_id?, role? }]`. Each group becomes a sub-account of `parent_id`
|
|
114
|
+
(defaults to `account.id`) and the user is linked to it. snake_case
|
|
115
|
+
sub-keys; a group only attaches under an account the user is already
|
|
116
|
+
anchored to. Read back via MCP `list_accounts` / `list_sub_accounts`
|
|
117
|
+
/ `get_contact_groups`.
|
|
108
118
|
- **E-commerce**: returns pipeline → `return_requested` / `return_completed`
|
|
109
119
|
(goods back) alongside `purchase_refunded` (money back — now carries
|
|
110
120
|
optional `product_id` for per-SKU attribution). Never conflate the two.
|