@capivv/mcp-server 0.5.50 → 0.5.53

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/client.d.ts CHANGED
@@ -65,6 +65,29 @@ export declare class CapivvClient {
65
65
  prior_alpha?: number;
66
66
  prior_beta?: number;
67
67
  }): Promise<unknown>;
68
+ /**
69
+ * V0.5.52 — issue #18 CUPED. Bayesian posterior with variance
70
+ * reduction using a named pre-experiment covariate.
71
+ */
72
+ getExperimentPosteriorCuped(input: {
73
+ experiment_id: string;
74
+ covariate_name: string;
75
+ decision_threshold_pct?: number;
76
+ prior_alpha?: number;
77
+ prior_beta?: number;
78
+ }): Promise<unknown>;
79
+ /**
80
+ * V0.5.53 — issue #18 slice 5. Revenue posterior with optional
81
+ * trim/winsorize for heavy-tailed ARPU distributions.
82
+ */
83
+ getExperimentPosteriorRevenue(input: {
84
+ experiment_id: string;
85
+ decision_threshold?: number;
86
+ prior_alpha?: number;
87
+ prior_beta?: number;
88
+ trim_top_pct?: number;
89
+ winsorize_top_pct?: number;
90
+ }): Promise<unknown>;
68
91
  /**
69
92
  * V0.5.48 — issue #18 Primitive 3 follow-up. Upload the Apple
70
93
  * promotional-offer signing key. Distinct from the ASC API key
package/dist/client.js CHANGED
@@ -170,6 +170,38 @@ export class CapivvClient {
170
170
  const qs = params.toString() ? `?${params.toString()}` : '';
171
171
  return this.get(`/dashboard/experiments/${encodeURIComponent(input.experiment_id)}/posterior${qs}`);
172
172
  }
173
+ /**
174
+ * V0.5.52 — issue #18 CUPED. Bayesian posterior with variance
175
+ * reduction using a named pre-experiment covariate.
176
+ */
177
+ async getExperimentPosteriorCuped(input) {
178
+ const params = new URLSearchParams({ covariate_name: input.covariate_name });
179
+ if (input.decision_threshold_pct !== undefined) {
180
+ params.set('decision_threshold_pct', String(input.decision_threshold_pct));
181
+ }
182
+ if (input.prior_alpha !== undefined) {
183
+ params.set('prior_alpha', String(input.prior_alpha));
184
+ }
185
+ if (input.prior_beta !== undefined) {
186
+ params.set('prior_beta', String(input.prior_beta));
187
+ }
188
+ return this.get(`/dashboard/experiments/${encodeURIComponent(input.experiment_id)}/posterior/cuped?${params.toString()}`);
189
+ }
190
+ /**
191
+ * V0.5.53 — issue #18 slice 5. Revenue posterior with optional
192
+ * trim/winsorize for heavy-tailed ARPU distributions.
193
+ */
194
+ async getExperimentPosteriorRevenue(input) {
195
+ const params = new URLSearchParams();
196
+ for (const [k, v] of Object.entries(input)) {
197
+ if (k === 'experiment_id')
198
+ continue;
199
+ if (v !== undefined)
200
+ params.set(k, String(v));
201
+ }
202
+ const qs = params.toString() ? `?${params.toString()}` : '';
203
+ return this.get(`/dashboard/experiments/${encodeURIComponent(input.experiment_id)}/posterior/revenue${qs}`);
204
+ }
173
205
  /**
174
206
  * V0.5.48 — issue #18 Primitive 3 follow-up. Upload the Apple
175
207
  * promotional-offer signing key. Distinct from the ASC API key
@@ -0,0 +1,23 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { CapivvClient } from '../client.js';
3
+ /**
4
+ * V0.5.52 — CUPED-adjusted Bayesian posterior. Issue #18 analysis
5
+ * surface slice 4.
6
+ *
7
+ * Variance reduction using a per-user pre-experiment covariate
8
+ * ingested via `Capivv.identify({ preExperimentCovariates: {...} })`
9
+ * (the v0.5.51 ingest surface). When the covariate is predictive of
10
+ * the outcome, CUPED produces tighter posterior credible intervals
11
+ * for the same N — "free power" for small-N mobile experiments.
12
+ *
13
+ * Math: subtract the regression-estimated contribution of the
14
+ * covariate from each user's outcome, then run a Normal-Normal
15
+ * posterior on the difference of adjusted means. Falls back to the
16
+ * unadjusted binary posterior when < 30 users have the covariate
17
+ * (not enough data to fit a stable regression coefficient).
18
+ *
19
+ * Response includes the per-arm count of users with covariate
20
+ * observations so the operator can see how much CUPED actually had
21
+ * to work with.
22
+ */
23
+ export declare function registerGetExperimentPosteriorCupedTool(server: McpServer, client: CapivvClient): void;
@@ -0,0 +1,48 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * V0.5.52 — CUPED-adjusted Bayesian posterior. Issue #18 analysis
4
+ * surface slice 4.
5
+ *
6
+ * Variance reduction using a per-user pre-experiment covariate
7
+ * ingested via `Capivv.identify({ preExperimentCovariates: {...} })`
8
+ * (the v0.5.51 ingest surface). When the covariate is predictive of
9
+ * the outcome, CUPED produces tighter posterior credible intervals
10
+ * for the same N — "free power" for small-N mobile experiments.
11
+ *
12
+ * Math: subtract the regression-estimated contribution of the
13
+ * covariate from each user's outcome, then run a Normal-Normal
14
+ * posterior on the difference of adjusted means. Falls back to the
15
+ * unadjusted binary posterior when < 30 users have the covariate
16
+ * (not enough data to fit a stable regression coefficient).
17
+ *
18
+ * Response includes the per-arm count of users with covariate
19
+ * observations so the operator can see how much CUPED actually had
20
+ * to work with.
21
+ */
22
+ export function registerGetExperimentPosteriorCupedTool(server, client) {
23
+ server.tool('capivv_get_experiment_posterior_cuped', "CUPED-adjusted Bayesian posterior. Pass the same covariate_name you use in Capivv.identify({ preExperimentCovariates: {...} }) — capivv joins each variant's assignments against your covariate data and returns the variance-reduced posterior. Use this when a pre-experiment baseline (e.g. lifetime_revenue_28d) is predictive of conversion.", {
24
+ experiment_id: z.string().uuid().describe('The experiment to analyze'),
25
+ covariate_name: z
26
+ .string()
27
+ .min(1)
28
+ .describe('The name of the covariate to adjust against. Must match what the SDK has been writing via `preExperimentCovariates`. Common names: "lifetime_revenue_28d", "session_count_7d", "previous_purchase_count".'),
29
+ decision_threshold_pct: z
30
+ .number()
31
+ .min(0)
32
+ .optional()
33
+ .describe('Minimum lift in percentage points to count as "worth shipping." Default 0.'),
34
+ prior_alpha: z
35
+ .number()
36
+ .positive()
37
+ .optional()
38
+ .describe('Beta prior α₀. Default 1 (uniform).'),
39
+ prior_beta: z
40
+ .number()
41
+ .positive()
42
+ .optional()
43
+ .describe('Beta prior β₀. Default 1 (uniform).'),
44
+ }, async (args) => {
45
+ const result = await client.getExperimentPosteriorCuped(args);
46
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
47
+ });
48
+ }
@@ -0,0 +1,23 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { CapivvClient } from '../client.js';
3
+ /**
4
+ * V0.5.53 — Bayesian posterior on revenue outcomes with optional
5
+ * trim/winsorize for heavy-tailed ARPU distributions. Issue #18
6
+ * analysis surface slice 5.
7
+ *
8
+ * Revenue is dominated by whales — standard variance estimators
9
+ * assume thin tails and produce nonsense credible intervals on
10
+ * small-N mobile data. Trimming (drop top K%) or winsorization (cap
11
+ * top K% at the threshold percentile) lets the posterior reflect
12
+ * the typical user without one whale skewing the entire arm.
13
+ *
14
+ * Reads conversion_value_micros per user from experiment_assignments.
15
+ * Non-converters contribute 0 micros (this is the per-user ARPU
16
+ * metric, not converters-only revenue). All thresholds and outputs
17
+ * are in micros (1 USD = 1_000_000 micros).
18
+ *
19
+ * Recommendation: trim_top_pct=5 or winsorize_top_pct=5 is a
20
+ * reasonable starting point for typical mobile-subscription revenue.
21
+ * Set both to 0 for the unadjusted posterior.
22
+ */
23
+ export declare function registerGetExperimentPosteriorRevenueTool(server: McpServer, client: CapivvClient): void;
@@ -0,0 +1,48 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * V0.5.53 — Bayesian posterior on revenue outcomes with optional
4
+ * trim/winsorize for heavy-tailed ARPU distributions. Issue #18
5
+ * analysis surface slice 5.
6
+ *
7
+ * Revenue is dominated by whales — standard variance estimators
8
+ * assume thin tails and produce nonsense credible intervals on
9
+ * small-N mobile data. Trimming (drop top K%) or winsorization (cap
10
+ * top K% at the threshold percentile) lets the posterior reflect
11
+ * the typical user without one whale skewing the entire arm.
12
+ *
13
+ * Reads conversion_value_micros per user from experiment_assignments.
14
+ * Non-converters contribute 0 micros (this is the per-user ARPU
15
+ * metric, not converters-only revenue). All thresholds and outputs
16
+ * are in micros (1 USD = 1_000_000 micros).
17
+ *
18
+ * Recommendation: trim_top_pct=5 or winsorize_top_pct=5 is a
19
+ * reasonable starting point for typical mobile-subscription revenue.
20
+ * Set both to 0 for the unadjusted posterior.
21
+ */
22
+ export function registerGetExperimentPosteriorRevenueTool(server, client) {
23
+ server.tool('capivv_get_experiment_posterior_revenue', 'Bayesian posterior on revenue per assigned user (ARPU). Optional trim or winsorize handles whale-skew. Input + output are in micros (1 USD = 1_000_000 micros). Use trim_top_pct=5 or winsorize_top_pct=5 as a robust default for small-N mobile experiments.', {
24
+ experiment_id: z.string().uuid().describe('The experiment to analyze'),
25
+ decision_threshold: z
26
+ .number()
27
+ .min(0)
28
+ .optional()
29
+ .describe('Minimum lift in micros to count as "worth shipping." Default 0.'),
30
+ prior_alpha: z.number().positive().optional().describe('Beta prior α₀. Default 1.'),
31
+ prior_beta: z.number().positive().optional().describe('Beta prior β₀. Default 1.'),
32
+ trim_top_pct: z
33
+ .number()
34
+ .min(0)
35
+ .max(50)
36
+ .optional()
37
+ .describe('Drop the top K% by revenue before computing means. Default 0 (no trim). Mutually exclusive with winsorize_top_pct — trim wins if both set.'),
38
+ winsorize_top_pct: z
39
+ .number()
40
+ .min(0)
41
+ .max(50)
42
+ .optional()
43
+ .describe('Cap the top K% at the percentile threshold (preserves N). Default 0 (no winsorize). Use when sample size matters more than tail-handling.'),
44
+ }, async (args) => {
45
+ const result = await client.getExperimentPosteriorRevenue(args);
46
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
47
+ });
48
+ }
@@ -54,6 +54,8 @@ import { registerStartExperimentTool } from './start-experiment.js';
54
54
  import { registerStopExperimentTool } from './stop-experiment.js';
55
55
  import { registerGetExperimentSummaryTool } from './get-experiment-summary.js';
56
56
  import { registerGetExperimentPosteriorTool } from './get-experiment-posterior.js';
57
+ import { registerGetExperimentPosteriorCupedTool } from './get-experiment-posterior-cuped.js';
58
+ import { registerGetExperimentPosteriorRevenueTool } from './get-experiment-posterior-revenue.js';
57
59
  import { registerUpdateAppTool } from './update-app.js';
58
60
  import { registerDeleteAppTool } from './delete-app.js';
59
61
  import { registerArchiveAppTool } from './archive-app.js';
@@ -172,6 +174,8 @@ export function registerAllTools(server, client) {
172
174
  registerStopExperimentTool(server, client);
173
175
  registerGetExperimentSummaryTool(server, client);
174
176
  registerGetExperimentPosteriorTool(server, client);
177
+ registerGetExperimentPosteriorCupedTool(server, client);
178
+ registerGetExperimentPosteriorRevenueTool(server, client);
175
179
  // Apps gap-fillers (V8 Phase B.6)
176
180
  registerUpdateAppTool(server, client);
177
181
  registerDeleteAppTool(server, client);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capivv/mcp-server",
3
- "version": "0.5.50",
3
+ "version": "0.5.53",
4
4
  "description": "MCP server for managing Capivv subscription platform via AI assistants",
5
5
  "type": "module",
6
6
  "bin": {