@capivv/mcp-server 0.1.3 → 0.5.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 (141) hide show
  1. package/README.md +73 -2
  2. package/dist/client.d.ts +62 -3
  3. package/dist/client.js +220 -5
  4. package/dist/config.js +1 -1
  5. package/dist/http.d.ts +12 -0
  6. package/dist/http.js +102 -0
  7. package/dist/resources/guides.d.ts +2 -0
  8. package/dist/resources/guides.js +81 -0
  9. package/dist/resources/index.js +4 -0
  10. package/dist/resources/quickstart.d.ts +2 -0
  11. package/dist/resources/quickstart.js +173 -0
  12. package/dist/resources/rules.js +8 -2
  13. package/dist/tools/activate-rule.d.ts +3 -0
  14. package/dist/tools/activate-rule.js +9 -0
  15. package/dist/tools/api-key-usage.d.ts +3 -0
  16. package/dist/tools/api-key-usage.js +70 -0
  17. package/dist/tools/apply-rule.js +54 -13
  18. package/dist/tools/approve-change-request.d.ts +3 -0
  19. package/dist/tools/approve-change-request.js +16 -0
  20. package/dist/tools/archive-app.d.ts +3 -0
  21. package/dist/tools/archive-app.js +9 -0
  22. package/dist/tools/autopilot-status.d.ts +3 -0
  23. package/dist/tools/autopilot-status.js +117 -0
  24. package/dist/tools/check-drift.d.ts +3 -0
  25. package/dist/tools/check-drift.js +21 -0
  26. package/dist/tools/create-app.d.ts +3 -0
  27. package/dist/tools/create-app.js +13 -0
  28. package/dist/tools/create-entitlement.d.ts +3 -0
  29. package/dist/tools/create-entitlement.js +11 -0
  30. package/dist/tools/create-experiment.d.ts +3 -0
  31. package/dist/tools/create-experiment.js +43 -0
  32. package/dist/tools/create-paywall.d.ts +3 -0
  33. package/dist/tools/create-paywall.js +18 -0
  34. package/dist/tools/create-pricing-strategy.d.ts +3 -0
  35. package/dist/tools/create-pricing-strategy.js +49 -0
  36. package/dist/tools/create-product.d.ts +3 -0
  37. package/dist/tools/create-product.js +77 -0
  38. package/dist/tools/create-promotion.d.ts +3 -0
  39. package/dist/tools/create-promotion.js +35 -0
  40. package/dist/tools/create-rescue-flow.d.ts +3 -0
  41. package/dist/tools/create-rescue-flow.js +20 -0
  42. package/dist/tools/delete-app.d.ts +3 -0
  43. package/dist/tools/delete-app.js +9 -0
  44. package/dist/tools/delete-entitlement.d.ts +3 -0
  45. package/dist/tools/delete-entitlement.js +11 -0
  46. package/dist/tools/delete-paywall.d.ts +3 -0
  47. package/dist/tools/delete-paywall.js +16 -0
  48. package/dist/tools/delete-product.d.ts +3 -0
  49. package/dist/tools/delete-product.js +9 -0
  50. package/dist/tools/delete-promotion.d.ts +3 -0
  51. package/dist/tools/delete-promotion.js +11 -0
  52. package/dist/tools/delete-rescue-flow.d.ts +3 -0
  53. package/dist/tools/delete-rescue-flow.js +11 -0
  54. package/dist/tools/delete-rule.d.ts +3 -0
  55. package/dist/tools/delete-rule.js +9 -0
  56. package/dist/tools/get-entitlement.d.ts +3 -0
  57. package/dist/tools/get-entitlement.js +9 -0
  58. package/dist/tools/get-experiment-summary.d.ts +3 -0
  59. package/dist/tools/get-experiment-summary.js +9 -0
  60. package/dist/tools/get-offering.d.ts +3 -0
  61. package/dist/tools/get-offering.js +9 -0
  62. package/dist/tools/get-paywall-stats.d.ts +3 -0
  63. package/dist/tools/get-paywall-stats.js +6 -0
  64. package/dist/tools/get-product.d.ts +3 -0
  65. package/dist/tools/get-product.js +9 -0
  66. package/dist/tools/get-rescue-stats.d.ts +3 -0
  67. package/dist/tools/get-rescue-stats.js +12 -0
  68. package/dist/tools/get-rule.d.ts +3 -0
  69. package/dist/tools/get-rule.js +9 -0
  70. package/dist/tools/import-products.js +7 -5
  71. package/dist/tools/index.js +143 -1
  72. package/dist/tools/list-change-requests.d.ts +3 -0
  73. package/dist/tools/list-change-requests.js +14 -0
  74. package/dist/tools/list-entitlements.d.ts +3 -0
  75. package/dist/tools/list-entitlements.js +6 -0
  76. package/dist/tools/list-paywalls.d.ts +3 -0
  77. package/dist/tools/list-paywalls.js +6 -0
  78. package/dist/tools/list-pricing-strategies.d.ts +3 -0
  79. package/dist/tools/list-pricing-strategies.js +8 -0
  80. package/dist/tools/list-promotions.d.ts +3 -0
  81. package/dist/tools/list-promotions.js +6 -0
  82. package/dist/tools/list-rescue-flows.d.ts +3 -0
  83. package/dist/tools/list-rescue-flows.js +6 -0
  84. package/dist/tools/list-rule-versions.d.ts +3 -0
  85. package/dist/tools/list-rule-versions.js +9 -0
  86. package/dist/tools/list-rules.js +4 -2
  87. package/dist/tools/next-step.d.ts +3 -0
  88. package/dist/tools/next-step.js +123 -0
  89. package/dist/tools/preview-pricing.d.ts +3 -0
  90. package/dist/tools/preview-pricing.js +13 -0
  91. package/dist/tools/push-prices-to-stores.d.ts +3 -0
  92. package/dist/tools/push-prices-to-stores.js +9 -0
  93. package/dist/tools/recompute-prices.d.ts +3 -0
  94. package/dist/tools/recompute-prices.js +24 -0
  95. package/dist/tools/resolve-drift.d.ts +3 -0
  96. package/dist/tools/resolve-drift.js +15 -0
  97. package/dist/tools/restore-app.d.ts +3 -0
  98. package/dist/tools/restore-app.js +9 -0
  99. package/dist/tools/revert-app-autopilot.d.ts +3 -0
  100. package/dist/tools/revert-app-autopilot.js +9 -0
  101. package/dist/tools/rollback-rule.d.ts +3 -0
  102. package/dist/tools/rollback-rule.js +10 -0
  103. package/dist/tools/run-app-autopilot.d.ts +3 -0
  104. package/dist/tools/run-app-autopilot.js +9 -0
  105. package/dist/tools/set-country-price-override.d.ts +3 -0
  106. package/dist/tools/set-country-price-override.js +13 -0
  107. package/dist/tools/setup-wizard.d.ts +3 -0
  108. package/dist/tools/setup-wizard.js +259 -0
  109. package/dist/tools/start-experiment.d.ts +3 -0
  110. package/dist/tools/start-experiment.js +9 -0
  111. package/dist/tools/status.js +25 -1
  112. package/dist/tools/stop-experiment.d.ts +3 -0
  113. package/dist/tools/stop-experiment.js +9 -0
  114. package/dist/tools/sync-suggestions-count.d.ts +3 -0
  115. package/dist/tools/sync-suggestions-count.js +6 -0
  116. package/dist/tools/trigger-sync.d.ts +3 -0
  117. package/dist/tools/trigger-sync.js +6 -0
  118. package/dist/tools/update-app.d.ts +3 -0
  119. package/dist/tools/update-app.js +19 -0
  120. package/dist/tools/update-entitlement.d.ts +3 -0
  121. package/dist/tools/update-entitlement.js +13 -0
  122. package/dist/tools/update-experiment.d.ts +3 -0
  123. package/dist/tools/update-experiment.js +22 -0
  124. package/dist/tools/update-offering.d.ts +3 -0
  125. package/dist/tools/update-offering.js +31 -0
  126. package/dist/tools/update-paywall.d.ts +3 -0
  127. package/dist/tools/update-paywall.js +23 -0
  128. package/dist/tools/update-product.d.ts +3 -0
  129. package/dist/tools/update-product.js +16 -0
  130. package/dist/tools/update-promotion.d.ts +3 -0
  131. package/dist/tools/update-promotion.js +20 -0
  132. package/dist/tools/update-rescue-flow.d.ts +3 -0
  133. package/dist/tools/update-rescue-flow.js +27 -0
  134. package/dist/tools/verify-setup.d.ts +3 -0
  135. package/dist/tools/verify-setup.js +200 -0
  136. package/dist/tools/whoami.d.ts +3 -0
  137. package/dist/tools/whoami.js +31 -0
  138. package/dist/types.d.ts +417 -79
  139. package/dist/types.js +0 -2
  140. package/mcp.json +89 -0
  141. package/package.json +8 -2
package/README.md CHANGED
@@ -20,7 +20,7 @@ The server requires an API key from your Capivv dashboard.
20
20
  | Environment Variable | Required | Description |
21
21
  |---------------------|----------|-------------|
22
22
  | `CAPIVV_API_KEY` | Yes | API key from Settings > Developer > API Keys |
23
- | `CAPIVV_API_URL` | No | API base URL (default: `https://api.capivv.com`) |
23
+ | `CAPIVV_API_URL` | No | API base URL (default: `https://app.capivv.com`) |
24
24
  | `CAPIVV_ORG_ID` | No | Organization ID for multi-org accounts |
25
25
 
26
26
  ## Setup
@@ -85,25 +85,96 @@ The server uses stdio transport. Start it with:
85
85
  CAPIVV_API_KEY=your-api-key npx @capivv/mcp-server
86
86
  ```
87
87
 
88
+ ## Getting Started
89
+
90
+ After installing, ask your AI assistant:
91
+
92
+ > "Set up Capivv for my iOS app com.mycompany.myapp with a monthly ($7.99) and annual ($49.99) subscription"
93
+
94
+ The assistant will use `capivv_setup_wizard` to create everything in one shot. Or go step-by-step:
95
+
96
+ 1. **`capivv_next_step`** — tells you exactly what to do next based on your current setup
97
+ 2. **`capivv_setup_wizard`** — creates app + entitlement + products + offering in one call
98
+ 3. **`capivv_verify_setup`** — checks everything is configured correctly
99
+
100
+ Read the `capivv://docs/quickstart` resource for a full walkthrough.
101
+
88
102
  ## Available Tools
89
103
 
104
+ ### Identity
105
+
106
+ | Tool | Description |
107
+ |------|-------------|
108
+ | `capivv_whoami` | Show which workspace (org) and apps your API key reaches. Call this first if anything looks wrong |
109
+
110
+ ### Onboarding & Guidance
111
+
112
+ | Tool | Description |
113
+ |------|-------------|
114
+ | `capivv_next_step` | Analyze your setup and get exact instructions for the next step |
115
+ | `capivv_setup_wizard` | One-shot setup: app + entitlement + products + offering in one call |
116
+ | `capivv_verify_setup` | Pass/fail checklist verifying your entire setup with fix instructions |
117
+
118
+ ### Status & Analytics
119
+
90
120
  | Tool | Description |
91
121
  |------|-------------|
92
122
  | `capivv_status` | Get setup progress, resource counts, and key metrics |
123
+ | `capivv_get_analytics` | Get MRR, ARR, churn rate, ARPU, and period comparison |
124
+
125
+ ### Apps
126
+
127
+ | Tool | Description |
128
+ |------|-------------|
93
129
  | `capivv_list_apps` | List all apps with platform and bundle ID |
130
+ | `capivv_create_app` | Register a new app (iOS, Android, or Web) |
131
+
132
+ ### Entitlements
133
+
134
+ | Tool | Description |
135
+ |------|-------------|
136
+ | `capivv_list_entitlements` | List all entitlements (feature access identifiers) |
137
+ | `capivv_create_entitlement` | Create a new entitlement |
138
+
139
+ ### Products
140
+
141
+ | Tool | Description |
142
+ |------|-------------|
94
143
  | `capivv_list_products` | List products with store IDs and entitlements (optional `app_id` filter) |
144
+ | `capivv_create_product` | Create a subscription, consumable, or non-consumable product |
145
+ | `capivv_update_product` | Update product fields (name, entitlements, external ID) |
146
+ | `capivv_delete_product` | Delete a product (irreversible) |
95
147
  | `capivv_import_products` | Preview store product import from App Store Connect / Google Play |
148
+
149
+ ### Offerings
150
+
151
+ | Tool | Description |
152
+ |------|-------------|
96
153
  | `capivv_list_offerings` | List offerings with packages and products |
97
154
  | `capivv_create_offering` | Create a new offering with packages |
155
+
156
+ ### Rules
157
+
158
+ | Tool | Description |
159
+ |------|-------------|
98
160
  | `capivv_list_rules` | List YAML business rules with status and priority |
99
161
  | `capivv_apply_rule` | Validate and apply a YAML rule configuration |
162
+ | `capivv_activate_rule` | Activate an existing rule |
163
+ | `capivv_delete_rule` | Delete a rule (irreversible) |
164
+
165
+ ### Experiments
166
+
167
+ | Tool | Description |
168
+ |------|-------------|
100
169
  | `capivv_list_experiments` | List A/B experiments with results and confidence |
101
- | `capivv_get_analytics` | Get MRR, ARR, churn rate, ARPU, and period comparison |
102
170
 
103
171
  ## Available Resources
104
172
 
105
173
  | URI | Description |
106
174
  |-----|-------------|
175
+ | `capivv://docs/quickstart` | Step-by-step setup guide — **start here** |
176
+ | `capivv://docs/guides/ios` | Complete iOS integration guide with code examples |
177
+ | `capivv://docs/guides/ai-prompts` | Ready-to-use prompts for AI code generators (Lovable, Bolt, Cursor) |
107
178
  | `capivv://status` | Current platform status as JSON |
108
179
  | `capivv://rules/{ruleId}` | Individual rule YAML content |
109
180
  | `capivv://docs/concepts` | Glossary of subscription platform concepts |
package/dist/client.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { Config } from './config.js';
2
- import type { App, Product, Entitlement, Offering, Rule, Experiment, ExperimentSummary, AnalyticsOverview, OnboardingResponse, ImportPreviewResponse, CreateOfferingRequest, CreateRuleRequest, ValidateRuleResponse } from './types.js';
2
+ import type { App, Product, Entitlement, Offering, Rule, Experiment, ExperimentSummary, AnalyticsOverview, OnboardingResponse, ImportPreviewResponse, CreateAppRequest, CreateEntitlementRequest, CreateProductRequest, CreateOfferingRequest, CreateRuleRequest, ValidateRuleRequest, ValidateRuleResponse, WhoamiResponse, ApiKeyUsageResponse, Paywall, CreatePaywallRequest, UpdatePaywallRequest, PaywallStats, Promotion, CreatePromotionRequest, UpdatePromotionRequest, RescueFlow, CreateRescueFlowRequest, UpdateRescueFlowRequest, RescueStats, PricingStrategy, CreatePricingStrategyRequest, PricingPreviewResult, PricingRecomputeRequest, PricingRecomputeResult, PricingPushResult, PricingChangeRequest, SetCountryPriceOverrideRequest, ExperimentWithVariants, CreateExperimentRequest, UpdateExperimentRequest, UpdateAppRequest, UpdateEntitlementRequest, UpdateOfferingRequest, AutopilotRunResult, SyncSuggestion, SyncSuggestionsCount, TriggerSyncResult } from './types.js';
3
3
  export declare class ApiError extends Error {
4
4
  status: number;
5
5
  code: string;
@@ -14,6 +14,8 @@ export declare class CapivvClient {
14
14
  private get;
15
15
  private post;
16
16
  healthCheck(): Promise<boolean>;
17
+ whoami(): Promise<WhoamiResponse>;
18
+ getApiKeyUsage(apiKeyId: string, hours?: number): Promise<ApiKeyUsageResponse>;
17
19
  listApps(): Promise<App[]>;
18
20
  listProducts(appId?: string): Promise<Product[]>;
19
21
  listEntitlements(): Promise<Entitlement[]>;
@@ -21,11 +23,68 @@ export declare class CapivvClient {
21
23
  createOffering(data: CreateOfferingRequest): Promise<Offering>;
22
24
  listRules(): Promise<Rule[]>;
23
25
  getRule(id: string): Promise<Rule>;
24
- upsertRule(data: CreateRuleRequest): Promise<Rule>;
25
- validateRule(content: string): Promise<ValidateRuleResponse>;
26
+ createRule(data: CreateRuleRequest): Promise<Rule>;
27
+ validateRule(data: ValidateRuleRequest): Promise<ValidateRuleResponse>;
26
28
  listExperiments(): Promise<Experiment[]>;
27
29
  getExperimentSummaries(): Promise<ExperimentSummary[]>;
28
30
  getAnalyticsOverview(): Promise<AnalyticsOverview>;
29
31
  getOnboarding(): Promise<OnboardingResponse>;
30
32
  getImportPreview(appId: string): Promise<ImportPreviewResponse>;
33
+ createApp(data: CreateAppRequest): Promise<App>;
34
+ createEntitlement(data: CreateEntitlementRequest): Promise<Entitlement>;
35
+ createProduct(data: CreateProductRequest): Promise<Product>;
36
+ private patch;
37
+ private delete;
38
+ updateProduct(id: string, data: Partial<Omit<CreateProductRequest, 'app_id'>>): Promise<Product>;
39
+ deleteProduct(id: string): Promise<void>;
40
+ deleteRule(id: string): Promise<void>;
41
+ activateRule(id: string): Promise<Rule>;
42
+ deactivateRule(id: string): Promise<Rule>;
43
+ listPaywalls(): Promise<Paywall[]>;
44
+ createPaywall(data: CreatePaywallRequest): Promise<Paywall>;
45
+ updatePaywall(id: string, data: UpdatePaywallRequest): Promise<Paywall>;
46
+ deletePaywall(id: string): Promise<void>;
47
+ getPaywallStats(): Promise<PaywallStats>;
48
+ listPromotions(): Promise<Promotion[]>;
49
+ createPromotion(data: CreatePromotionRequest): Promise<Promotion>;
50
+ updatePromotion(id: string, data: UpdatePromotionRequest): Promise<Promotion>;
51
+ deletePromotion(id: string): Promise<void>;
52
+ listRescueFlows(): Promise<RescueFlow[]>;
53
+ createRescueFlow(data: CreateRescueFlowRequest): Promise<RescueFlow>;
54
+ updateRescueFlow(id: string, data: UpdateRescueFlowRequest): Promise<RescueFlow>;
55
+ deleteRescueFlow(id: string): Promise<void>;
56
+ getRescueStats(days?: number): Promise<RescueStats>;
57
+ listPricingStrategies(): Promise<PricingStrategy[]>;
58
+ createPricingStrategy(data: CreatePricingStrategyRequest): Promise<PricingStrategy>;
59
+ previewPricing(productId: string, strategyId?: string): Promise<PricingPreviewResult>;
60
+ recomputePrices(data: PricingRecomputeRequest): Promise<PricingRecomputeResult>;
61
+ pushPricesToStores(productId: string): Promise<PricingPushResult>;
62
+ listPricingChangeRequests(appId: string, status?: string, productId?: string): Promise<PricingChangeRequest[]>;
63
+ approvePricingChangeRequest(id: string): Promise<void>;
64
+ setCountryPriceOverride(data: SetCountryPriceOverrideRequest): Promise<unknown>;
65
+ createExperiment(data: CreateExperimentRequest): Promise<ExperimentWithVariants>;
66
+ getExperiment(id: string): Promise<ExperimentWithVariants>;
67
+ updateExperiment(id: string, data: UpdateExperimentRequest): Promise<ExperimentWithVariants>;
68
+ startExperiment(id: string): Promise<ExperimentWithVariants>;
69
+ stopExperiment(id: string): Promise<ExperimentWithVariants>;
70
+ getApp(id: string): Promise<App>;
71
+ updateApp(id: string, data: UpdateAppRequest): Promise<App>;
72
+ deleteApp(id: string): Promise<void>;
73
+ archiveApp(id: string): Promise<App>;
74
+ restoreApp(id: string): Promise<App>;
75
+ runAppAutopilot(id: string): Promise<AutopilotRunResult>;
76
+ revertAppAutopilot(id: string): Promise<AutopilotRunResult>;
77
+ getEntitlement(id: string): Promise<Entitlement>;
78
+ updateEntitlement(id: string, data: UpdateEntitlementRequest): Promise<Entitlement>;
79
+ deleteEntitlement(id: string): Promise<void>;
80
+ getProduct(id: string): Promise<Product>;
81
+ getRuleById(id: string): Promise<Rule>;
82
+ listRuleVersions(id: string): Promise<unknown>;
83
+ rollbackRule(id: string, version: number): Promise<Rule>;
84
+ getOffering(id: string): Promise<Offering>;
85
+ updateOffering(id: string, data: UpdateOfferingRequest): Promise<Offering>;
86
+ listSyncSuggestions(appId?: string, status?: string): Promise<SyncSuggestion[]>;
87
+ getSyncSuggestionsCount(): Promise<SyncSuggestionsCount>;
88
+ resolveSyncSuggestion(id: string, action: 'accept' | 'dismiss'): Promise<SyncSuggestion>;
89
+ triggerSync(): Promise<TriggerSyncResult>;
31
90
  }
package/dist/client.js CHANGED
@@ -53,13 +53,21 @@ export class CapivvClient {
53
53
  }
54
54
  async healthCheck() {
55
55
  try {
56
- await this.get('/health');
57
- return true;
56
+ // Health endpoint is at root, not under /v1
57
+ const url = this.baseUrl.replace(/\/v1$/, '') + '/health';
58
+ const response = await fetch(url);
59
+ return response.ok;
58
60
  }
59
61
  catch {
60
62
  return false;
61
63
  }
62
64
  }
65
+ async whoami() {
66
+ return this.get('/dashboard/whoami');
67
+ }
68
+ async getApiKeyUsage(apiKeyId, hours = 24) {
69
+ return this.get(`/dashboard/settings/api-keys/${encodeURIComponent(apiKeyId)}/usage?hours=${hours}`);
70
+ }
63
71
  async listApps() {
64
72
  const resp = await this.get('/dashboard/apps');
65
73
  return resp.apps;
@@ -87,11 +95,11 @@ export class CapivvClient {
87
95
  async getRule(id) {
88
96
  return this.get(`/dashboard/rules/${encodeURIComponent(id)}`);
89
97
  }
90
- async upsertRule(data) {
98
+ async createRule(data) {
91
99
  return this.post('/dashboard/rules', data);
92
100
  }
93
- async validateRule(content) {
94
- return this.post('/dashboard/rules/validate', { content });
101
+ async validateRule(data) {
102
+ return this.post('/dashboard/rules/validate', data);
95
103
  }
96
104
  async listExperiments() {
97
105
  const resp = await this.get('/dashboard/experiments/active');
@@ -110,4 +118,211 @@ export class CapivvClient {
110
118
  async getImportPreview(appId) {
111
119
  return this.get(`/dashboard/onboarding/import-preview?app_id=${encodeURIComponent(appId)}`);
112
120
  }
121
+ // ---- Create methods ----
122
+ async createApp(data) {
123
+ return this.post('/dashboard/apps', data);
124
+ }
125
+ async createEntitlement(data) {
126
+ return this.post('/dashboard/entitlements', data);
127
+ }
128
+ async createProduct(data) {
129
+ return this.post('/dashboard/products', data);
130
+ }
131
+ // ---- Update methods ----
132
+ patch(path, body) {
133
+ return this.request('PATCH', path, body);
134
+ }
135
+ delete(path) {
136
+ return this.request('DELETE', path);
137
+ }
138
+ async updateProduct(id, data) {
139
+ return this.patch(`/dashboard/products/${encodeURIComponent(id)}`, data);
140
+ }
141
+ async deleteProduct(id) {
142
+ await this.delete(`/dashboard/products/${encodeURIComponent(id)}`);
143
+ }
144
+ async deleteRule(id) {
145
+ await this.delete(`/dashboard/rules/${encodeURIComponent(id)}`);
146
+ }
147
+ async activateRule(id) {
148
+ return this.post(`/dashboard/rules/${encodeURIComponent(id)}/activate`);
149
+ }
150
+ async deactivateRule(id) {
151
+ return this.post(`/dashboard/rules/${encodeURIComponent(id)}/deactivate`);
152
+ }
153
+ // ---- Paywalls (V8 Phase B.1) ----
154
+ async listPaywalls() {
155
+ const resp = await this.get('/dashboard/paywalls');
156
+ return resp.paywalls;
157
+ }
158
+ async createPaywall(data) {
159
+ return this.post('/dashboard/paywalls', data);
160
+ }
161
+ async updatePaywall(id, data) {
162
+ return this.patch(`/dashboard/paywalls/${encodeURIComponent(id)}`, data);
163
+ }
164
+ async deletePaywall(id) {
165
+ await this.delete(`/dashboard/paywalls/${encodeURIComponent(id)}`);
166
+ }
167
+ async getPaywallStats() {
168
+ return this.get('/dashboard/paywalls/stats');
169
+ }
170
+ // ---- Promotions (V8 Phase B.2) ----
171
+ async listPromotions() {
172
+ const resp = await this.get('/dashboard/promotions');
173
+ return resp.promotions;
174
+ }
175
+ async createPromotion(data) {
176
+ return this.post('/dashboard/promotions', data);
177
+ }
178
+ async updatePromotion(id, data) {
179
+ return this.patch(`/dashboard/promotions/${encodeURIComponent(id)}`, data);
180
+ }
181
+ async deletePromotion(id) {
182
+ await this.delete(`/dashboard/promotions/${encodeURIComponent(id)}`);
183
+ }
184
+ // ---- Rescue Flows (V8 Phase B.3) ----
185
+ async listRescueFlows() {
186
+ const resp = await this.get('/dashboard/rescue-flows');
187
+ return resp.flows;
188
+ }
189
+ async createRescueFlow(data) {
190
+ return this.post('/dashboard/rescue-flows', data);
191
+ }
192
+ async updateRescueFlow(id, data) {
193
+ return this.patch(`/dashboard/rescue-flows/${encodeURIComponent(id)}`, data);
194
+ }
195
+ async deleteRescueFlow(id) {
196
+ await this.delete(`/dashboard/rescue-flows/${encodeURIComponent(id)}`);
197
+ }
198
+ async getRescueStats(days = 30) {
199
+ return this.get(`/dashboard/rescue-flows/stats?days=${days}`);
200
+ }
201
+ // ---- Pricing (V8 Phase B.4) ----
202
+ async listPricingStrategies() {
203
+ const resp = await this.get('/dashboard/pricing/strategies');
204
+ return resp.strategies;
205
+ }
206
+ async createPricingStrategy(data) {
207
+ const resp = await this.post('/dashboard/pricing/strategies', data);
208
+ return resp.strategy;
209
+ }
210
+ async previewPricing(productId, strategyId) {
211
+ return this.post('/dashboard/pricing/preview', {
212
+ product_id: productId,
213
+ strategy_id: strategyId,
214
+ });
215
+ }
216
+ async recomputePrices(data) {
217
+ return this.post('/dashboard/pricing/recompute', data);
218
+ }
219
+ async pushPricesToStores(productId) {
220
+ return this.post('/dashboard/pricing/push', { product_id: productId });
221
+ }
222
+ async listPricingChangeRequests(appId, status, productId) {
223
+ const params = new URLSearchParams({ app_id: appId });
224
+ if (status)
225
+ params.set('status', status);
226
+ if (productId)
227
+ params.set('product_id', productId);
228
+ const resp = await this.get(`/dashboard/pricing/change-requests?${params.toString()}`);
229
+ return resp.change_requests;
230
+ }
231
+ async approvePricingChangeRequest(id) {
232
+ await this.post(`/dashboard/pricing/change-requests/${encodeURIComponent(id)}/approve`);
233
+ }
234
+ async setCountryPriceOverride(data) {
235
+ const { product_id, country_code, ...body } = data;
236
+ return this.request('PUT', `/dashboard/products/${encodeURIComponent(product_id)}/prices/${encodeURIComponent(country_code)}`, body);
237
+ }
238
+ // ---- Experiment writes (V8 Phase B.5) ----
239
+ async createExperiment(data) {
240
+ return this.post('/dashboard/experiments', data);
241
+ }
242
+ async getExperiment(id) {
243
+ return this.get(`/dashboard/experiments/${encodeURIComponent(id)}`);
244
+ }
245
+ async updateExperiment(id, data) {
246
+ return this.patch(`/dashboard/experiments/${encodeURIComponent(id)}`, data);
247
+ }
248
+ async startExperiment(id) {
249
+ return this.post(`/dashboard/experiments/${encodeURIComponent(id)}/start`);
250
+ }
251
+ async stopExperiment(id) {
252
+ return this.post(`/dashboard/experiments/${encodeURIComponent(id)}/stop`);
253
+ }
254
+ // ---- Apps gap-fillers (V8 Phase B.6) ----
255
+ async getApp(id) {
256
+ return this.get(`/dashboard/apps/${encodeURIComponent(id)}`);
257
+ }
258
+ async updateApp(id, data) {
259
+ return this.patch(`/dashboard/apps/${encodeURIComponent(id)}`, data);
260
+ }
261
+ async deleteApp(id) {
262
+ await this.delete(`/dashboard/apps/${encodeURIComponent(id)}`);
263
+ }
264
+ async archiveApp(id) {
265
+ return this.post(`/dashboard/apps/${encodeURIComponent(id)}/archive`);
266
+ }
267
+ async restoreApp(id) {
268
+ return this.post(`/dashboard/apps/${encodeURIComponent(id)}/restore`);
269
+ }
270
+ async runAppAutopilot(id) {
271
+ return this.post(`/dashboard/apps/${encodeURIComponent(id)}/autopilot/run`);
272
+ }
273
+ async revertAppAutopilot(id) {
274
+ return this.post(`/dashboard/apps/${encodeURIComponent(id)}/autopilot/revert`);
275
+ }
276
+ // ---- Entitlements gap-fillers (V8 Phase B.7) ----
277
+ async getEntitlement(id) {
278
+ return this.get(`/dashboard/entitlements/${encodeURIComponent(id)}`);
279
+ }
280
+ async updateEntitlement(id, data) {
281
+ return this.patch(`/dashboard/entitlements/${encodeURIComponent(id)}`, data);
282
+ }
283
+ async deleteEntitlement(id) {
284
+ await this.delete(`/dashboard/entitlements/${encodeURIComponent(id)}`);
285
+ }
286
+ // ---- Products gap-filler (V8 Phase B.8) ----
287
+ async getProduct(id) {
288
+ return this.get(`/dashboard/products/${encodeURIComponent(id)}`);
289
+ }
290
+ // ---- Rules gap-fillers (V8 Phase B.9) ----
291
+ async getRuleById(id) {
292
+ return this.get(`/dashboard/rules/${encodeURIComponent(id)}`);
293
+ }
294
+ async listRuleVersions(id) {
295
+ return this.get(`/dashboard/rules/${encodeURIComponent(id)}/versions`);
296
+ }
297
+ async rollbackRule(id, version) {
298
+ return this.post(`/dashboard/rules/${encodeURIComponent(id)}/rollback`, { version });
299
+ }
300
+ // ---- Offerings gap-fillers (V8 Phase B.10) ----
301
+ async getOffering(id) {
302
+ return this.get(`/dashboard/offerings/${encodeURIComponent(id)}`);
303
+ }
304
+ async updateOffering(id, data) {
305
+ return this.patch(`/dashboard/offerings/${encodeURIComponent(id)}`, data);
306
+ }
307
+ // ---- Drift detection (V8 Phase C) ----
308
+ async listSyncSuggestions(appId, status) {
309
+ const params = new URLSearchParams();
310
+ if (appId)
311
+ params.set('app_id', appId);
312
+ if (status)
313
+ params.set('status', status);
314
+ const qs = params.toString();
315
+ return this.get(`/dashboard/sync/suggestions${qs ? `?${qs}` : ''}`);
316
+ }
317
+ async getSyncSuggestionsCount() {
318
+ return this.get('/dashboard/sync/suggestions/count');
319
+ }
320
+ async resolveSyncSuggestion(id, action) {
321
+ return this.post(`/dashboard/sync/suggestions/${encodeURIComponent(id)}/resolve`, {
322
+ action,
323
+ });
324
+ }
325
+ async triggerSync() {
326
+ return this.post('/dashboard/sync/trigger');
327
+ }
113
328
  }
package/dist/config.js CHANGED
@@ -10,7 +10,7 @@ export function loadConfig() {
10
10
  throw new ConfigError('CAPIVV_API_KEY environment variable is required. ' +
11
11
  'Create an API key in the Capivv dashboard under Settings > Developer > API Keys.');
12
12
  }
13
- const apiUrl = (process.env.CAPIVV_API_URL || 'https://api.capivv.com').replace(/\/+$/, '');
13
+ const apiUrl = (process.env.CAPIVV_API_URL || 'https://app.capivv.com').replace(/\/+$/, '');
14
14
  const orgId = process.env.CAPIVV_ORG_ID || undefined;
15
15
  return { apiKey, apiUrl, orgId };
16
16
  }
package/dist/http.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * MCP Remote HTTP Server
4
+ *
5
+ * Exposes the Capivv MCP server over Streamable HTTP transport.
6
+ * Clients authenticate with their Capivv API key as a Bearer token.
7
+ *
8
+ * Usage in Lovable / other MCP clients:
9
+ * Server URL: https://app.capivv.com/mcp
10
+ * Auth: Bearer token → paste your Capivv secret API key
11
+ */
12
+ export {};
package/dist/http.js ADDED
@@ -0,0 +1,102 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * MCP Remote HTTP Server
4
+ *
5
+ * Exposes the Capivv MCP server over Streamable HTTP transport.
6
+ * Clients authenticate with their Capivv API key as a Bearer token.
7
+ *
8
+ * Usage in Lovable / other MCP clients:
9
+ * Server URL: https://app.capivv.com/mcp
10
+ * Auth: Bearer token → paste your Capivv secret API key
11
+ */
12
+ import express from 'express';
13
+ import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
14
+ import { createServer } from './server.js';
15
+ const PORT = parseInt(process.env.MCP_PORT || '3100', 10);
16
+ const HOST = process.env.MCP_HOST || '0.0.0.0';
17
+ const API_URL = (process.env.CAPIVV_API_URL || 'https://app.capivv.com').replace(/\/+$/, '');
18
+ const app = express();
19
+ app.use(express.json());
20
+ // Health check
21
+ app.get('/health', (_req, res) => {
22
+ res.json({ status: 'ok', service: 'capivv-mcp' });
23
+ });
24
+ // Public origin used in the WWW-Authenticate header so OAuth-aware MCP clients
25
+ // (Cursor, Claude Desktop) can discover our authorization server. Falls back to
26
+ // CAPIVV_API_URL because in production the MCP and API share the same hostname
27
+ // behind Caddy.
28
+ const PUBLIC_URL = (process.env.CAPIVV_PUBLIC_URL || API_URL).replace(/\/+$/, '');
29
+ function unauthorized(res, description) {
30
+ // RFC 9728: point the client at the protected-resource metadata so it can
31
+ // discover our authorization server and start the OAuth flow.
32
+ res.setHeader('WWW-Authenticate', `Bearer realm="capivv-mcp", error="invalid_token", error_description="${description}", resource_metadata="${PUBLIC_URL}/.well-known/oauth-protected-resource"`);
33
+ res.status(401).json({
34
+ jsonrpc: '2.0',
35
+ error: { code: -32000, message: description },
36
+ id: null,
37
+ });
38
+ }
39
+ // MCP endpoint — Streamable HTTP
40
+ app.post('/mcp', async (req, res) => {
41
+ try {
42
+ // Extract API key from Authorization header
43
+ const authHeader = req.headers.authorization;
44
+ if (!authHeader) {
45
+ unauthorized(res, 'Missing Authorization header. Sign in via your MCP client or set Bearer <your-capivv-api-key>.');
46
+ return;
47
+ }
48
+ const apiKey = authHeader.startsWith('Bearer ')
49
+ ? authHeader.slice(7).trim()
50
+ : authHeader.trim();
51
+ if (!apiKey) {
52
+ unauthorized(res, 'Empty bearer token.');
53
+ return;
54
+ }
55
+ // Create a config using the client's API key
56
+ const config = {
57
+ apiKey,
58
+ apiUrl: API_URL,
59
+ orgId: undefined,
60
+ };
61
+ // Create a fresh server + transport per request (stateless)
62
+ const server = createServer(config);
63
+ const transport = new StreamableHTTPServerTransport({
64
+ sessionIdGenerator: undefined, // stateless — no session tracking
65
+ });
66
+ await server.connect(transport);
67
+ await transport.handleRequest(req, res, req.body);
68
+ }
69
+ catch (error) {
70
+ console.error('[mcp-http] Error handling request:', error);
71
+ if (!res.headersSent) {
72
+ res.status(500).json({
73
+ jsonrpc: '2.0',
74
+ error: { code: -32603, message: 'Internal server error' },
75
+ id: null,
76
+ });
77
+ }
78
+ }
79
+ });
80
+ // Handle GET for SSE streams (server-initiated messages)
81
+ app.get('/mcp', async (_req, res) => {
82
+ // In stateless mode, we don't support server-initiated SSE
83
+ res.status(405).json({
84
+ jsonrpc: '2.0',
85
+ error: { code: -32000, message: 'Server-initiated SSE not supported in stateless mode. Use POST.' },
86
+ id: null,
87
+ });
88
+ });
89
+ // Handle DELETE for session termination
90
+ app.delete('/mcp', async (_req, res) => {
91
+ // Stateless — no sessions to terminate
92
+ res.status(405).json({
93
+ jsonrpc: '2.0',
94
+ error: { code: -32000, message: 'No sessions to terminate (stateless server).' },
95
+ id: null,
96
+ });
97
+ });
98
+ app.listen(PORT, HOST, () => {
99
+ console.log(`[capivv-mcp] HTTP server listening on http://${HOST}:${PORT}/mcp`);
100
+ console.log(`[capivv-mcp] API URL: ${API_URL}`);
101
+ console.log(`[capivv-mcp] Auth: Bearer token (use your Capivv API key)`);
102
+ });
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerGuideResources(server: McpServer): void;
@@ -0,0 +1,81 @@
1
+ import { readFile } from 'fs/promises';
2
+ import { resolve, dirname } from 'path';
3
+ import { fileURLToPath } from 'url';
4
+ // Resolve path to the docs/ directory relative to the package root
5
+ function docsDir() {
6
+ // packages/mcp-server/src/resources/guides.ts → packages/mcp-server/
7
+ const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..', '..');
8
+ // packages/mcp-server/ → project root docs/
9
+ return resolve(packageRoot, '..', '..', 'docs');
10
+ }
11
+ const GUIDES = [
12
+ {
13
+ name: 'guide-ios',
14
+ uri: 'capivv://docs/guides/ios',
15
+ file: 'IOS_INTEGRATION_GUIDE.md',
16
+ description: 'Step-by-step iOS integration guide: App Store Connect setup, SDK installation, purchases, entitlements, testing, and troubleshooting.',
17
+ },
18
+ {
19
+ name: 'guide-ai-prompts',
20
+ uri: 'capivv://docs/guides/ai-prompts',
21
+ file: 'AI_INTEGRATION_PROMPTS.md',
22
+ description: 'Ready-to-use prompts for AI code generators (Lovable, Bolt, Cursor) to integrate Capivv on iOS, Android, Flutter, Web, and Ionic.',
23
+ },
24
+ ];
25
+ // Fallback content if the file can't be read (e.g., when running from npm package without docs/)
26
+ const FALLBACK = {
27
+ 'IOS_INTEGRATION_GUIDE.md': `# iOS Integration Guide
28
+
29
+ This guide is available at https://docs.capivv.com/guides/ios
30
+
31
+ ## Quick Steps
32
+
33
+ 1. **App Store Connect**: Create subscription products, set pricing, enable Server Notifications V2 pointing to \`https://app.capivv.com/v1/webhooks/apple\`
34
+ 2. **Capivv Dashboard**: Create app (iOS, your bundle ID), create entitlements (e.g., "pro"), create products matching your store IDs, link products to entitlements
35
+ 3. **Install SDK**: Add \`https://github.com/capivv/capivv-ios\` via Swift Package Manager
36
+ 4. **Initialize**: Call \`Capivv.shared.configure(apiKey: "capivv_pk_...")\` in your App.init()
37
+ 5. **Identify users**: Call \`Capivv.shared.login(userId: "...")\` after authentication
38
+ 6. **Check entitlements**: Use \`Capivv.shared.hasEntitlement("pro")\` to gate features
39
+ 7. **Show paywall**: Use \`PaywallView(identifier: "default")\` or build a custom one with \`Capivv.shared.getOfferings()\`
40
+ 8. **Test**: Use StoreKit Configuration files in Xcode, sandbox Apple IDs
41
+
42
+ For the full guide with code examples, read capivv://docs/quickstart or visit https://docs.capivv.com/guides/ios`,
43
+ 'AI_INTEGRATION_PROMPTS.md': `# AI Integration Prompts
44
+
45
+ Ready-to-use prompts for AI code generators are available at https://docs.capivv.com/guides/ai-prompts
46
+
47
+ Supported platforms: iOS (Swift), Android (Kotlin), Flutter, Web (React), Ionic/Capacitor
48
+
49
+ For each platform, the prompt covers:
50
+ 1. SDK installation
51
+ 2. Initialization with API key
52
+ 3. User identification
53
+ 4. Entitlement checking
54
+ 5. Paywall display
55
+ 6. Purchase processing
56
+ 7. Sync on launch
57
+
58
+ Visit https://docs.capivv.com/guides/ai-prompts for the full prompts.`,
59
+ };
60
+ export function registerGuideResources(server) {
61
+ for (const guide of GUIDES) {
62
+ server.resource(guide.name, guide.uri, { mimeType: 'text/markdown' }, async (uri) => {
63
+ let content;
64
+ try {
65
+ const filePath = resolve(docsDir(), guide.file);
66
+ content = await readFile(filePath, 'utf-8');
67
+ }
68
+ catch {
69
+ content = FALLBACK[guide.file] ?? `Guide not found. Visit https://docs.capivv.com for documentation.`;
70
+ }
71
+ return {
72
+ contents: [
73
+ {
74
+ uri: uri.href,
75
+ text: content,
76
+ },
77
+ ],
78
+ };
79
+ });
80
+ }
81
+ }
@@ -1,8 +1,12 @@
1
1
  import { registerStatusResource } from './status.js';
2
2
  import { registerRulesResource } from './rules.js';
3
3
  import { registerConceptsResource } from './concepts.js';
4
+ import { registerQuickstartResource } from './quickstart.js';
5
+ import { registerGuideResources } from './guides.js';
4
6
  export function registerAllResources(server, client) {
5
7
  registerStatusResource(server, client);
6
8
  registerRulesResource(server, client);
7
9
  registerConceptsResource(server);
10
+ registerQuickstartResource(server);
11
+ registerGuideResources(server);
8
12
  }
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerQuickstartResource(server: McpServer): void;