@capivv/mcp-server 0.5.9 → 0.5.10

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
@@ -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, 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, IntegrationSummary, ConnectAppleIntegrationRequest, ConnectAppleIntegrationResult, ConnectGoogleIntegrationRequest, ConnectGoogleIntegrationResult, SetSubscriptionReviewScreenshotRequest, SetSubscriptionReviewScreenshotResult, SubscriptionStateInfo, TouchSubscriptionResult } 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, IntegrationSummary, ConnectAppleIntegrationRequest, ConnectAppleIntegrationResult, ConnectGoogleIntegrationRequest, ConnectGoogleIntegrationResult, SetSubscriptionReviewScreenshotRequest, SetSubscriptionReviewScreenshotResult, SubscriptionStateInfo, TouchSubscriptionResult, ProbeSubmissionRequest, ProbeSubmissionResult, SetAppPrivacyUrlRequest, SetAppPrivacyUrlResult, SetIapReviewScreenshotRequest, SetIapReviewScreenshotResult } from './types.js';
3
3
  export declare class ApiError extends Error {
4
4
  status: number;
5
5
  code: string;
@@ -94,4 +94,7 @@ export declare class CapivvClient {
94
94
  setSubscriptionReviewScreenshot(data: SetSubscriptionReviewScreenshotRequest): Promise<SetSubscriptionReviewScreenshotResult>;
95
95
  getSubscriptionState(appleSubscriptionId: string): Promise<SubscriptionStateInfo>;
96
96
  touchSubscription(appleSubscriptionId: string): Promise<TouchSubscriptionResult>;
97
+ probeAppleSubmission(req: ProbeSubmissionRequest): Promise<ProbeSubmissionResult>;
98
+ setAppPrivacyUrl(req: SetAppPrivacyUrlRequest): Promise<SetAppPrivacyUrlResult>;
99
+ setIapReviewScreenshot(req: SetIapReviewScreenshotRequest): Promise<SetIapReviewScreenshotResult>;
97
100
  }
package/dist/client.js CHANGED
@@ -350,4 +350,16 @@ export class CapivvClient {
350
350
  async touchSubscription(appleSubscriptionId) {
351
351
  return this.post(`/dashboard/subscriptions/${encodeURIComponent(appleSubscriptionId)}/touch`);
352
352
  }
353
+ // ---- V0.5.10 — Submission probe / privacy URL / IAP screenshot ----
354
+ async probeAppleSubmission(req) {
355
+ return this.post(`/dashboard/store/apple/${encodeURIComponent(req.product_type)}/${encodeURIComponent(req.apple_product_id)}/probe-submission`);
356
+ }
357
+ async setAppPrivacyUrl(req) {
358
+ const { app_id, ...body } = req;
359
+ return this.post(`/dashboard/apps/${encodeURIComponent(app_id)}/privacy-policy-url`, body);
360
+ }
361
+ async setIapReviewScreenshot(req) {
362
+ const { apple_iap_id, ...body } = req;
363
+ return this.post(`/dashboard/iap/${encodeURIComponent(apple_iap_id)}/review-screenshot`, body);
364
+ }
353
365
  }
@@ -75,6 +75,9 @@ import { registerDisconnectIntegrationTool } from './disconnect-integration.js';
75
75
  import { registerSetSubscriptionReviewScreenshotTool } from './set-subscription-review-screenshot.js';
76
76
  import { registerGetSubscriptionStateTool } from './get-subscription-state.js';
77
77
  import { registerTouchSubscriptionTool } from './touch-subscription.js';
78
+ import { registerProbeSubmissionTool } from './probe-submission.js';
79
+ import { registerSetAppPrivacyUrlTool } from './set-app-privacy-url.js';
80
+ import { registerSetIapReviewScreenshotTool } from './set-iap-review-screenshot.js';
78
81
  export function registerAllTools(server, client) {
79
82
  // Identity — call this first to verify which workspace you're connected to
80
83
  registerWhoamiTool(server, client);
@@ -185,4 +188,14 @@ export function registerAllTools(server, client) {
185
188
  // MISSING_METADATA after a successful create.)
186
189
  registerGetSubscriptionStateTool(server, client);
187
190
  registerTouchSubscriptionTool(server, client);
191
+ // V0.5.10 — diagnostic + app-info + IAP screenshot tools.
192
+ // - Submission probe surfaces Apple's exact "what's still missing"
193
+ // diagnostics so the agent stops surfacing misleading "Permission
194
+ // denied" errors.
195
+ // - App privacy URL fixes ENTITY_ERROR.APP_MISSING_PRIVACY_POLICY_URL
196
+ // without sending the user to ASC.
197
+ // - IAP review screenshot mirrors the subscription helper for IAPs.
198
+ registerProbeSubmissionTool(server, client);
199
+ registerSetAppPrivacyUrlTool(server, client);
200
+ registerSetIapReviewScreenshotTool(server, client);
188
201
  }
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { CapivvClient } from '../client.js';
3
+ export declare function registerProbeSubmissionTool(server: McpServer, client: CapivvClient): void;
@@ -0,0 +1,32 @@
1
+ import { z } from 'zod';
2
+ export function registerProbeSubmissionTool(server, client) {
3
+ server.tool('capivv_probe_submission', [
4
+ 'Probe an Apple subscription or in-app purchase for what is still gating App Store submission.',
5
+ '',
6
+ "Apple's `*Submissions` endpoint reliably returns 409 on a brand-new product with an `errors` body that says exactly what's missing. This tool POSTs to `/v1/subscriptionSubmissions` (or `/v1/inAppPurchaseSubmissions`) and returns a structured result:",
7
+ '- `ready`: submission accepted (rare on first probe; means metadata is complete).',
8
+ '- `missing_pricing_data` with a `territories` list: re-run pricing for those territories.',
9
+ '- `missing_privacy_policy_url`: call `capivv_set_app_privacy_url` to fix.',
10
+ '- `awaiting_first_app_version`: Apple policy — first sub/IAP on a new app must ship with the first version. Not an error from your side.',
11
+ '- `other` with `code` + `detail`: surface verbatim to the customer.',
12
+ '',
13
+ 'Get `apple_product_id` from the `store_create.store_product_id` field of capivv_create_product, or from App Store Connect.',
14
+ ].join(' '), {
15
+ apple_product_id: z
16
+ .string()
17
+ .describe('Apple product ID (e.g. "6764778053") — NOT the Capivv product UUID.'),
18
+ product_type: z
19
+ .enum(['subscription', 'iap'])
20
+ .describe('"subscription" for auto-renewing subscriptions; "iap" for consumables and non-consumables.'),
21
+ }, async (args) => {
22
+ const result = await client.probeAppleSubmission(args);
23
+ return {
24
+ content: [
25
+ {
26
+ type: 'text',
27
+ text: JSON.stringify(result, null, 2),
28
+ },
29
+ ],
30
+ };
31
+ });
32
+ }
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { CapivvClient } from '../client.js';
3
+ export declare function registerSetAppPrivacyUrlTool(server: McpServer, client: CapivvClient): void;
@@ -0,0 +1,25 @@
1
+ import { z } from 'zod';
2
+ export function registerSetAppPrivacyUrlTool(server, client) {
3
+ server.tool('capivv_set_app_privacy_url', [
4
+ "Set the App Store Connect app's privacy policy URL on its in-progress en-US localization.",
5
+ '',
6
+ 'Call this when `capivv_probe_submission` returns `missing_privacy_policy_url`. The backend resolves the app via Capivv `app_id` → bundle id → ASC app, then PATCHes `appInfoLocalizations.privacyPolicyUrl` on the editable appInfo (states: PREPARE_FOR_SUBMISSION, REJECTED, METADATA_REJECTED, DEVELOPER_REJECTED).',
7
+ '',
8
+ 'URL must be HTTPS.',
9
+ ].join(' '), {
10
+ app_id: z.string().describe('Capivv app UUID.'),
11
+ privacy_policy_url: z
12
+ .string()
13
+ .describe('HTTPS URL pointing at the privacy policy.'),
14
+ }, async (args) => {
15
+ const result = await client.setAppPrivacyUrl(args);
16
+ return {
17
+ content: [
18
+ {
19
+ type: 'text',
20
+ text: JSON.stringify(result, null, 2),
21
+ },
22
+ ],
23
+ };
24
+ });
25
+ }
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { CapivvClient } from '../client.js';
3
+ export declare function registerSetIapReviewScreenshotTool(server: McpServer, client: CapivvClient): void;
@@ -0,0 +1,47 @@
1
+ import { z } from 'zod';
2
+ export function registerSetIapReviewScreenshotTool(server, client) {
3
+ server.tool('capivv_set_iap_review_screenshot', [
4
+ 'Upload the App Store review screenshot for an in-app purchase (consumable or non-consumable). Mirrors capivv_set_subscription_review_screenshot but uses the IAP endpoint.',
5
+ '',
6
+ 'Apple expects 640x920 (or larger) PNG / JPEG. Provide either `image_url` (Capivv backend fetches it via HTTPS) or `image_base64` (raw bytes inline). The backend handles the 3-step Apple flow: reserve → PUT bytes to S3 → PATCH uploaded=true with MD5.',
7
+ '',
8
+ 'Get `apple_iap_id` from the `store_create.store_product_id` field of capivv_create_product (when the product type is consumable or non_consumable), or from App Store Connect.',
9
+ ].join(' '), {
10
+ apple_iap_id: z
11
+ .string()
12
+ .describe('Apple in-app purchase ID (e.g. "6765812345") — NOT the Capivv product UUID.'),
13
+ image_url: z
14
+ .string()
15
+ .optional()
16
+ .describe('Public HTTPS URL of the screenshot. Mutually exclusive with image_base64.'),
17
+ image_base64: z
18
+ .string()
19
+ .optional()
20
+ .describe('Base64-encoded raw image bytes. Use for non-HTTPS sources. Mutually exclusive with image_url.'),
21
+ file_name: z
22
+ .string()
23
+ .optional()
24
+ .describe('Filename Apple stores on the screenshot resource. Defaults to "screenshot.png".'),
25
+ }, async (args) => {
26
+ if (!args.image_url && !args.image_base64) {
27
+ return {
28
+ isError: true,
29
+ content: [
30
+ {
31
+ type: 'text',
32
+ text: 'Provide either image_url (HTTPS) or image_base64 (raw bytes).',
33
+ },
34
+ ],
35
+ };
36
+ }
37
+ const result = await client.setIapReviewScreenshot(args);
38
+ return {
39
+ content: [
40
+ {
41
+ type: 'text',
42
+ text: JSON.stringify(result, null, 2),
43
+ },
44
+ ],
45
+ };
46
+ });
47
+ }
@@ -1,11 +1,11 @@
1
1
  import { z } from 'zod';
2
2
  export function registerTouchSubscriptionTool(server, client) {
3
3
  server.tool('capivv_touch_subscription', [
4
- 'BEST-EFFORT workaround for Apple\'s modern-vs-legacy view divergence.',
4
+ 'Nudge Apple to recompute the subscription\'s state after the screenshot has uploaded.',
5
5
  '',
6
- 'After capivv_create_product creates the subscription via Apple\'s /v1/subscriptions endpoint, a legacy /v1/inAppPurchases mirror is also created with its own state machine. The legacy record can stay at WAITING_FOR_SCREENSHOT (which keeps the modern view at MISSING_METADATA) even after the screenshot uploads cleanly, because Apple\'s state recompute pipeline still reads from the legacy view and the modern API doesn\'t reliably trigger that recompute.',
6
+ 'After capivv_create_product creates the subscription via Apple\'s /v1/subscriptions endpoint, a legacy /v1/inAppPurchases mirror is also created with its own state machine. The legacy record can stay at WAITING_FOR_SCREENSHOT (which keeps the modern view at MISSING_METADATA) until something writes to the modern resource. This tool does a no-op PATCH on the subscription (re-set name to its current value), which mirrors clicking "Save" in App Store Connect\'s web UI and reliably triggers the recompute.',
7
7
  '',
8
- 'This tool does a no-op PATCH on the subscription (re-set name to its current value), which mirrors what clicking "Save" in App Store Connect\'s web UI appears to trigger. Whether it actually fires the recompute hasn\'t been confirmed in every state — call capivv_get_subscription_state 30-60 seconds afterwards to check. If state still doesn\'t progress, fall back to manual ASC web UI Save.',
8
+ 'Call capivv_get_subscription_state 30-60 seconds afterwards to confirm the state has progressed.',
9
9
  ].join(' '), {
10
10
  apple_subscription_id: z
11
11
  .string()
package/dist/types.d.ts CHANGED
@@ -600,3 +600,55 @@ export interface TouchSubscriptionResult {
600
600
  touched: boolean;
601
601
  next_action: string;
602
602
  }
603
+ /**
604
+ * Result of POSTing a `*Submissions` record to App Store Connect. Apple
605
+ * reliably 409s on a brand-new product with an `errors` array describing
606
+ * exactly what's still missing — so we map known codes to actionable
607
+ * variants. The backend returns this discriminated union as JSON.
608
+ */
609
+ export type SubmissionProbeResult = {
610
+ status: 'ready';
611
+ } | {
612
+ status: 'missing_pricing_data';
613
+ territories: string[];
614
+ } | {
615
+ status: 'missing_privacy_policy_url';
616
+ } | {
617
+ status: 'awaiting_first_app_version';
618
+ } | {
619
+ status: 'other';
620
+ code: string;
621
+ detail: string;
622
+ };
623
+ export interface ProbeSubmissionRequest {
624
+ apple_product_id: string;
625
+ /** "subscription" or "iap". */
626
+ product_type: 'subscription' | 'iap';
627
+ }
628
+ export interface ProbeSubmissionResult {
629
+ apple_product_id: string;
630
+ product_type: string;
631
+ submission_status: SubmissionProbeResult;
632
+ }
633
+ export interface SetAppPrivacyUrlRequest {
634
+ app_id: string;
635
+ privacy_policy_url: string;
636
+ }
637
+ export interface SetAppPrivacyUrlResult {
638
+ app_id: string;
639
+ bundle_id: string;
640
+ privacy_policy_url: string;
641
+ localization_id: string;
642
+ app_store_state: string;
643
+ }
644
+ export interface SetIapReviewScreenshotRequest {
645
+ apple_iap_id: string;
646
+ image_url?: string;
647
+ image_base64?: string;
648
+ file_name?: string;
649
+ }
650
+ export interface SetIapReviewScreenshotResult {
651
+ apple_iap_id: string;
652
+ screenshot_id: string;
653
+ bytes_uploaded: number;
654
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capivv/mcp-server",
3
- "version": "0.5.9",
3
+ "version": "0.5.10",
4
4
  "description": "MCP server for managing Capivv subscription platform via AI assistants",
5
5
  "type": "module",
6
6
  "bin": {