@zackbart/connecta 0.17.0 → 0.18.1
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/CHANGELOG.md +133 -0
- package/README.md +79 -114
- package/dist/catalog-service.d.ts +6 -0
- package/dist/catalog-service.js +69 -4
- package/dist/execute.d.ts +2 -0
- package/dist/execute.js +43 -17
- package/dist/meta-tools.js +9 -9
- package/dist/providers/mixpanel.js +4 -1
- package/dist/providers/revenuecat.d.ts +77 -0
- package/dist/providers/revenuecat.js +314 -0
- package/dist/providers/stripe.d.ts +23 -22
- package/dist/providers/stripe.js +63 -32
- package/dist/routes/ui.js +1 -1
- package/dist/skills.d.ts +1 -1
- package/dist/skills.js +53 -16
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/documentation/architecture.md +1 -1
- package/documentation/code-mode.md +23 -15
- package/documentation/connector-guides.md +7 -10
- package/documentation/connectors.md +1 -0
- package/documentation/meta-tools.md +27 -2
- package/documentation/notion.md +17 -0
- package/documentation/operations.md +11 -10
- package/documentation/provider-audit.md +45 -7
- package/documentation/provider-conventions.md +24 -15
- package/documentation/revenuecat.md +279 -0
- package/documentation/stripe.md +53 -67
- package/documentation/upgrading.md +32 -4
- package/ethos.md +4 -4
- package/package.json +6 -2
- package/templates/node/README.md +7 -0
- package/templates/node/package.json +5 -2
package/dist/meta-tools.js
CHANGED
|
@@ -1044,13 +1044,13 @@ export function createMetaTools(registry, baseUrl, opts = {}) {
|
|
|
1044
1044
|
},
|
|
1045
1045
|
};
|
|
1046
1046
|
}
|
|
1047
|
-
const SEARCH_DESC = `Use top-level search
|
|
1048
|
-
const CALL_DESC = '
|
|
1049
|
-
const CALL_DESTRUCTIVE_DESC = "
|
|
1050
|
-
const GET_RESULT_DESC = "Page a truncated result
|
|
1047
|
+
const SEARCH_DESC = `Use top-level search for one unknown-address read before call_tool, or for approval-required work before call_destructive_tool. Use 2–4 action/object terms and includeSchemas="compact"; the default limit is ${DEFAULT_SEARCH_LIMIT}. Set connector when known. safety="readOnly" finds direct or program calls; "approvalRequired" finds the fail-closed complement. These filters grant no authority. For multiple, dependent, or reduced read-only calls, use one execute_code program instead. Empty query browses.`;
|
|
1048
|
+
const CALL_DESC = 'Call one tool explicitly annotated readOnlyHint: true. Use execute_code for multiple, dependent, or reduced read-only calls. Unannotated or write-capable tools fail closed to call_destructive_tool. fields projects JSON dot-paths; use [] through arrays. A truncated result carries a get_result action.';
|
|
1049
|
+
const CALL_DESTRUCTIVE_DESC = "Call any tool not explicitly annotated readOnlyHint: true. Include a short reason for the human reviewer after checking the schema and consequences. The reason grants no authority and is not sent downstream.";
|
|
1050
|
+
const GET_RESULT_DESC = "Page a truncated direct-call result by id and byte offset. A program result is never paged; reduce it inside execute_code. Returns text, offset, nextOffset when more remains, and totalBytes.";
|
|
1051
1051
|
const AUTHORIZE_DESC = "Use after auth_required. Returns an OAuth or operator-credential handoff, or reports required deployment configuration. force=true restarts OAuth only; this tool never accepts credentials.";
|
|
1052
|
-
const SKILLS_DESC = 'List or fetch
|
|
1053
|
-
const SEARCH_WITH_DESCRIBE_DESC =
|
|
1052
|
+
const SKILLS_DESC = 'List or fetch on-demand guidance. Fetch usage once per task for program syntax, selection, repair, examples, and runtime details.';
|
|
1053
|
+
const SEARCH_WITH_DESCRIBE_DESC = SEARCH_DESC;
|
|
1054
1054
|
/**
|
|
1055
1055
|
* Sentences appended to a meta-tool description only when this connection
|
|
1056
1056
|
* actually has connector guides. Tool descriptions are always-loaded context,
|
|
@@ -1060,9 +1060,9 @@ const SEARCH_WITH_DESCRIBE_DESC = `${SEARCH_DESC} Expand an ambiguous compact sh
|
|
|
1060
1060
|
* Registration is per connection and reads the configured connector set.
|
|
1061
1061
|
*/
|
|
1062
1062
|
const GUIDE_NOTES = {
|
|
1063
|
-
skills: "
|
|
1064
|
-
search: " A result
|
|
1065
|
-
destructive: "
|
|
1063
|
+
skills: " Also lists this deployment's connector guides by exact name.",
|
|
1064
|
+
search: " A result with guideRequired: true requires its exact named connector guide before the call.",
|
|
1065
|
+
destructive: " Fetch any exact connector guide named by discovery before the call.",
|
|
1066
1066
|
};
|
|
1067
1067
|
/** `base`, plus its guide note when any VISIBLE connector carries a guide. */
|
|
1068
1068
|
function describedFor(registry, base, note) {
|
|
@@ -184,7 +184,10 @@ Account purpose: ${purpose}
|
|
|
184
184
|
- \`Get-Business-Context\` requires either \`project_id\` or \`organization_id\`. Its schema marks both optional, but the hosted tool rejects a call with neither.
|
|
185
185
|
- \`Get-Property-Values\` requires \`properties\` or the deprecated \`property\` alias. Event property values also require \`event\`; prefer \`properties\` and never send both property forms with conflicting values.
|
|
186
186
|
- \`List-Properties\` accepts \`names\` or \`query\`, never both. Use exact \`names\` for known properties and \`query\` for substring discovery.
|
|
187
|
-
-
|
|
187
|
+
- One analysis is one \`execute_code\` program: fetch \`Get-Query-Schema\` once, run every \`Run-Query\` of the analysis in that program, and return the reduced table. The schema is tens of kilobytes and the same for every report type, so re-fetching it per query buys nothing. Never return raw \`Run-Query\` output.
|
|
188
|
+
- Insights, funnels, and retention answer aggregate questions. A per-user ordered event timeline, or a sequence question such as "event A with no later event B", is not answerable with \`Run-Query\` in a reasonable number of calls, and this hosted catalog has no per-\`distinct_id\` event timeline — \`Get-User-Replays-Data\` covers one user's replays with their events only where session replay is enabled and present. If the deployment exposes a Mixpanel export or activity-feed connector, use that; if it does not, tell the user the question is out of reach here rather than approximating it with hourly buckets and hundreds of empty rows.
|
|
189
|
+
- \`false\` on a boolean property may be an absent property: Mixpanel renders a missing value as \`false\` in boolean breakdowns, and server-imported events often lack client-side properties entirely. Confirm the property is present with \`List-Properties\` or \`Get-Property-Values\` before treating \`false\` as a signal, and say when a conclusion rests on that ambiguity.
|
|
190
|
+
- Breakdown responses nest \`$overall\` and per-segment series objects. Flatten to one row per complete breakdown combination inside \`execute_code\` before returning, and drop \`$overall\` unless the question asks for the total.
|
|
188
191
|
- Use \`Get-Report\` when the request names an existing saved report. Use \`Run-Query\` for a new question.
|
|
189
192
|
- This account's tool list is not a fixed set. Mixpanel gates parts of its MCP catalog by plan and beta enrollment — experiments, feature flags, session replay, and issue triage are the usual absentees — so search this connector for what it actually exposes rather than assuming a documented tool is here.
|
|
190
193
|
- Mixpanel meters MCP traffic per user per hour, shared with everything else that credential does. Reuse discovery results within a run and avoid speculative fan-out.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { type RemoteMcpAuth } from "../connectors/remote-mcp.js";
|
|
2
|
+
import type { Connector, ConnectorCallAdmissionPolicy } from "../types.js";
|
|
3
|
+
/** RevenueCat publishes one hosted MCP endpoint, streamable HTTP. */
|
|
4
|
+
export declare const REVENUECAT_MCP_ENDPOINT = "https://mcp.revenuecat.ai/mcp";
|
|
5
|
+
export interface RevenueCatOptions {
|
|
6
|
+
/**
|
|
7
|
+
* Human-readable display name; defaults to "RevenueCat" for OAuth and
|
|
8
|
+
* "RevenueCat (single project)" for a static API v2 secret key. The scope
|
|
9
|
+
* shape rides the title because it is the one routing fact connecta can
|
|
10
|
+
* know at construction: an `sk_` key reaches exactly one project, an OAuth
|
|
11
|
+
* session reaches every project the account can. *Which* project a key
|
|
12
|
+
* reaches is not knowable here (P10 — no credential test), so the guide's
|
|
13
|
+
* first line carries the operator's stated purpose instead.
|
|
14
|
+
*/
|
|
15
|
+
title?: string;
|
|
16
|
+
/**
|
|
17
|
+
* Which project this connector is for and what decisions it answers. With
|
|
18
|
+
* headers auth this is the only place the project a key reaches is named,
|
|
19
|
+
* so it goes in the guide's first line and its summary.
|
|
20
|
+
*/
|
|
21
|
+
purpose: string;
|
|
22
|
+
/**
|
|
23
|
+
* OAuth by default; static headers support a RevenueCat API v2 secret key
|
|
24
|
+
* as `Authorization: Bearer sk_…`.
|
|
25
|
+
*/
|
|
26
|
+
auth?: RemoteMcpAuth;
|
|
27
|
+
/** Project-specific conventions appended to the maintained provider guide. */
|
|
28
|
+
instructions?: string;
|
|
29
|
+
/** Connector-specific inline result limit; omit to inherit the deployment. */
|
|
30
|
+
maxResultBytes?: number;
|
|
31
|
+
/**
|
|
32
|
+
* Optional per-runtime call-admission policy. Deliberately not defaulted,
|
|
33
|
+
* even though RevenueCat does publish numbers.
|
|
34
|
+
*
|
|
35
|
+
* API v2 meters per *domain*, and the domains disagree by a factor of
|
|
36
|
+
* nineteen: Customer Information 480/min, Virtual Currencies 480/min,
|
|
37
|
+
* Subscription Transactions Refunds 480/min, Audiences 60/min, Project
|
|
38
|
+
* Configuration 60/min, Charts & Metrics 25/min
|
|
39
|
+
* (https://www.revenuecat.com/docs/api-v2#tag/Rate-Limit, read 2026-08-18).
|
|
40
|
+
* A `ConnectorCallAdmissionPolicy` carries exactly one rule, so a
|
|
41
|
+
* connector-wide budget has to pick one of those six numbers for all ninety-
|
|
42
|
+
* five tools. Transcribing 25 would throttle a customer read loop to a
|
|
43
|
+
* nineteenth of its documented allowance; transcribing 480 would leave a
|
|
44
|
+
* chart sweep unprotected. Neither is the provider's limit, and both would
|
|
45
|
+
* look like RevenueCat being flaky.
|
|
46
|
+
*
|
|
47
|
+
* The metering scope says the same thing again: the limit applies per API
|
|
48
|
+
* key for app-level keys and per *developer* for developer-level keys, so
|
|
49
|
+
* an OAuth session shares one budget with everything else that developer
|
|
50
|
+
* does — which a per-runtime counter cannot approximate in either
|
|
51
|
+
* direction. So the number stays with the operator who knows the account,
|
|
52
|
+
* exactly as P12 prescribes; `documentation/revenuecat.md` shows how to
|
|
53
|
+
* supply one.
|
|
54
|
+
*/
|
|
55
|
+
callAdmission?: ConnectorCallAdmissionPolicy;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* The manifest this release reviewed: both lists in one place, which is what
|
|
59
|
+
* makes the classification the connector applies and the drift check that runs
|
|
60
|
+
* beside it the same fact (P13). Ninety-four of the ninety-five tools
|
|
61
|
+
* RevenueCat's reference lists on 2026-08-18 are classified; the ninety-fifth,
|
|
62
|
+
* `render-paywall-screenshot`, has no access column to classify from and fails
|
|
63
|
+
* closed.
|
|
64
|
+
*
|
|
65
|
+
* No schema digests. No release has read RevenueCat's live schemas and written
|
|
66
|
+
* them down — that needs a live project and a maintainer's own `sk_` key — and
|
|
67
|
+
* an invented digest would report a change that never happened.
|
|
68
|
+
* `npm run drift:check -- --record` reads them from a live catalog and prints
|
|
69
|
+
* the block to paste in
|
|
70
|
+
* ([#351](https://github.com/zackbart/connecta/issues/351)).
|
|
71
|
+
*
|
|
72
|
+
* Exported because the maintainer-run check compares against this manifest and
|
|
73
|
+
* *names* what moved, which the runtime check deliberately cannot.
|
|
74
|
+
*/
|
|
75
|
+
export declare const REVENUECAT_VETTED_CATALOG: import("../catalog-drift.js").VettedCatalog;
|
|
76
|
+
/** A maintained RevenueCat hosted-MCP connection. */
|
|
77
|
+
export declare function revenuecat(id: string, options: RevenueCatOptions): Connector;
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
import { remoteMcp, } from "../connectors/remote-mcp.js";
|
|
2
|
+
import { vettedCatalog, withVettedCatalog } from "../catalog-drift.js";
|
|
3
|
+
/** RevenueCat publishes one hosted MCP endpoint, streamable HTTP. */
|
|
4
|
+
export const REVENUECAT_MCP_ENDPOINT = "https://mcp.revenuecat.ai/mcp";
|
|
5
|
+
/**
|
|
6
|
+
* Tools whose official contract is observational rather than mutating.
|
|
7
|
+
*
|
|
8
|
+
* Every name here carries `Read` in RevenueCat's own tool reference
|
|
9
|
+
* (https://www.revenuecat.com/docs/tools/mcp/tools-reference, read
|
|
10
|
+
* 2026-08-18). The list is a superset by design (P5): a name a project never
|
|
11
|
+
* serves costs nothing, while an unclassified new one fails closed onto
|
|
12
|
+
* `call_destructive_tool`.
|
|
13
|
+
*/
|
|
14
|
+
const READ_ONLY_TOOLS = new Set([
|
|
15
|
+
// Projects and apps
|
|
16
|
+
"get-account-billing",
|
|
17
|
+
"get-app",
|
|
18
|
+
"get-project-ui-config",
|
|
19
|
+
"list-account-billing-invoices",
|
|
20
|
+
"list-app-public-api-keys",
|
|
21
|
+
"list-apps",
|
|
22
|
+
"list-audit-logs",
|
|
23
|
+
"list-collaborators",
|
|
24
|
+
"list-projects",
|
|
25
|
+
// Products and prices
|
|
26
|
+
"get-product",
|
|
27
|
+
"get-product-store-state",
|
|
28
|
+
"get-product-store-state-operation",
|
|
29
|
+
"list-products",
|
|
30
|
+
// Entitlements
|
|
31
|
+
"get-entitlement",
|
|
32
|
+
"get-products-from-entitlement",
|
|
33
|
+
"list-entitlements",
|
|
34
|
+
// Offerings and packages
|
|
35
|
+
"get-offering",
|
|
36
|
+
"get-offering-prices",
|
|
37
|
+
"list-offerings",
|
|
38
|
+
"list-packages",
|
|
39
|
+
// Targeting and audiences
|
|
40
|
+
"get-audience",
|
|
41
|
+
"get-audience-filter-options",
|
|
42
|
+
"get-targeting-rule",
|
|
43
|
+
"list-audiences",
|
|
44
|
+
"list-targeting-rules",
|
|
45
|
+
// Paywalls
|
|
46
|
+
"get-paywall",
|
|
47
|
+
"list-paywalls",
|
|
48
|
+
// Customers and subscriptions
|
|
49
|
+
"get-customer",
|
|
50
|
+
"get-customer-center-config",
|
|
51
|
+
"get-subscription",
|
|
52
|
+
"list-customer-events",
|
|
53
|
+
"list-customers",
|
|
54
|
+
"list-purchases",
|
|
55
|
+
"list-subscriptions",
|
|
56
|
+
"list-virtual-currencies-balances",
|
|
57
|
+
// Virtual currencies
|
|
58
|
+
"get-virtual-currency",
|
|
59
|
+
"list-virtual-currencies",
|
|
60
|
+
// Charts, metrics, and experiments
|
|
61
|
+
"get-benchmarks",
|
|
62
|
+
"get-chart-data",
|
|
63
|
+
"get-chart-options-schema",
|
|
64
|
+
"get-experiment",
|
|
65
|
+
"get-experiment-results",
|
|
66
|
+
"get-overview-metrics",
|
|
67
|
+
"get-revenue-metric",
|
|
68
|
+
"list-experiments",
|
|
69
|
+
// Integrations and webhooks
|
|
70
|
+
"get-webhook-integration",
|
|
71
|
+
"list-webhook-integrations",
|
|
72
|
+
// SDK compatibility
|
|
73
|
+
"list-sdk-feature-gates",
|
|
74
|
+
"list-sdk-versions",
|
|
75
|
+
// Paywall editing. Polling an async task is a read; the two tools that
|
|
76
|
+
// *start* one are writes and sit below.
|
|
77
|
+
"get-paywall-ai-task",
|
|
78
|
+
]);
|
|
79
|
+
/**
|
|
80
|
+
* The maintained write catalog. `"destructive"` tools modify or remove state
|
|
81
|
+
* that already exists; `"additive"` ones only bring something new into being.
|
|
82
|
+
* Both leave the read-only path — the distinction only decides whether the
|
|
83
|
+
* connection asserts `destructiveHint`, which shapes the host's approval copy.
|
|
84
|
+
*
|
|
85
|
+
* Every name here carries `Write` in RevenueCat's tool reference. The mass
|
|
86
|
+
* verdicts follow the verb: `archive-*` and `unarchive-*` flip an existing
|
|
87
|
+
* object's active state, `update-*` and `delete-*` and `publish-*` and
|
|
88
|
+
* `unpublish-*` and `detach-*` change or remove something that already exists,
|
|
89
|
+
* and a plain `create-*` brings a new object into being beside the old ones.
|
|
90
|
+
*
|
|
91
|
+
* Nine verdicts are not decided by the verb, and each is argued where it sits:
|
|
92
|
+
* `create-product-prices`, `equalize-subscription-prices`,
|
|
93
|
+
* `validate-app-credentials`, `upload-product-store-state-screenshot`,
|
|
94
|
+
* `attach-products-to-entitlement`, `attach-products-to-package`,
|
|
95
|
+
* `duplicate-paywall`, `create-paywall-ai`, and `edit-paywall-ai`.
|
|
96
|
+
*
|
|
97
|
+
* `render-paywall-screenshot` is deliberately on neither list. RevenueCat's
|
|
98
|
+
* reference gives it no access column at all, and a tool nobody has classified
|
|
99
|
+
* fails closed (P5) rather than being guessed into the read path because its
|
|
100
|
+
* name sounds harmless.
|
|
101
|
+
*/
|
|
102
|
+
const WRITE_TOOLS = new Map([
|
|
103
|
+
// Projects and apps
|
|
104
|
+
["create-app", "additive"],
|
|
105
|
+
["create-project", "additive"],
|
|
106
|
+
["update-app", "destructive"],
|
|
107
|
+
["update-project-ui-config", "destructive"],
|
|
108
|
+
// "Checks one saved App Store or Google Play credential set." RevenueCat
|
|
109
|
+
// files it Write, so it does not reach the read path — but it leaves the
|
|
110
|
+
// credentials themselves alone and only records the outcome of a check.
|
|
111
|
+
// Additive: a verdict comes into being, nothing existing is overwritten.
|
|
112
|
+
["validate-app-credentials", "additive"],
|
|
113
|
+
// Products and prices
|
|
114
|
+
["archive-product", "destructive"],
|
|
115
|
+
["create-product", "additive"],
|
|
116
|
+
// Named `create-`, described "Configure prices for a product". A product's
|
|
117
|
+
// price set already exists, and configuring it replaces what is there
|
|
118
|
+
// rather than adding a second price beside the first. Money-facing and
|
|
119
|
+
// overwriting, so: destructive, whatever the verb says.
|
|
120
|
+
["create-product-prices", "destructive"],
|
|
121
|
+
// "Fills missing App Store subscription territory prices." By RevenueCat's
|
|
122
|
+
// own word it only writes where a price is absent, so nothing already set
|
|
123
|
+
// is changed. Additive.
|
|
124
|
+
["equalize-subscription-prices", "additive"],
|
|
125
|
+
["set-product-store-state", "destructive"],
|
|
126
|
+
["submit-products-to-store", "destructive"],
|
|
127
|
+
["unarchive-product", "destructive"],
|
|
128
|
+
["update-product", "destructive"],
|
|
129
|
+
// "Reserves an App Store Connect review screenshot slot." A new slot comes
|
|
130
|
+
// into being; no existing screenshot is replaced by the reservation.
|
|
131
|
+
["upload-product-store-state-screenshot", "additive"],
|
|
132
|
+
// Entitlements
|
|
133
|
+
["archive-entitlement", "destructive"],
|
|
134
|
+
// Attach adds a product to a membership set and removes nothing;
|
|
135
|
+
// `detach-products-from-entitlement` is its destructive counterpart. Filing
|
|
136
|
+
// both destructive would make the pair read identically in the approval copy
|
|
137
|
+
// a human is shown, which is exactly the inflation P5 warns about.
|
|
138
|
+
["attach-products-to-entitlement", "additive"],
|
|
139
|
+
["create-entitlement", "additive"],
|
|
140
|
+
["detach-products-from-entitlement", "destructive"],
|
|
141
|
+
["unarchive-entitlement", "destructive"],
|
|
142
|
+
["update-entitlement", "destructive"],
|
|
143
|
+
// Offerings and packages
|
|
144
|
+
["archive-offering", "destructive"],
|
|
145
|
+
// The same attach/detach argument one level down.
|
|
146
|
+
["attach-products-to-package", "additive"],
|
|
147
|
+
["create-offering", "additive"],
|
|
148
|
+
["create-packages", "additive"],
|
|
149
|
+
["delete-package-from-offering", "destructive"],
|
|
150
|
+
["detach-products-from-package", "destructive"],
|
|
151
|
+
["unarchive-offering", "destructive"],
|
|
152
|
+
["update-offering", "destructive"],
|
|
153
|
+
// Targeting and audiences
|
|
154
|
+
["create-audience", "additive"],
|
|
155
|
+
["update-audience", "destructive"],
|
|
156
|
+
// Paywalls
|
|
157
|
+
// "Duplicates an existing paywall's current draft." The original is
|
|
158
|
+
// untouched and a new paywall appears beside it. Additive.
|
|
159
|
+
["duplicate-paywall", "additive"],
|
|
160
|
+
["publish-paywall", "destructive"],
|
|
161
|
+
["unpublish-paywall", "destructive"],
|
|
162
|
+
// Customers and subscriptions. Neither verb is in the mass rule and neither
|
|
163
|
+
// removes anything, so the file's own criterion would read them additive.
|
|
164
|
+
// They are destructive on consequence, the way `create_refund` is in
|
|
165
|
+
// `stripe.ts`: `assign-customer-offering` overrides which offering a live
|
|
166
|
+
// customer's app serves, and `grant-customer-entitlement` opens paid access
|
|
167
|
+
// to a real person without a store purchase (the promotional subscription it
|
|
168
|
+
// creates is the mechanism, not the point). Both change what a customer
|
|
169
|
+
// gets today, and both deserve the destructive approval copy.
|
|
170
|
+
["assign-customer-offering", "destructive"],
|
|
171
|
+
["grant-customer-entitlement", "destructive"],
|
|
172
|
+
// Virtual currencies
|
|
173
|
+
["archive-virtual-currency", "destructive"],
|
|
174
|
+
["create-virtual-currency", "additive"],
|
|
175
|
+
["unarchive-virtual-currency", "destructive"],
|
|
176
|
+
["update-virtual-currency", "destructive"],
|
|
177
|
+
// Integrations and webhooks
|
|
178
|
+
// A new integration is a new object, but one that "starts delivering
|
|
179
|
+
// RevenueCat events to the given url" — with filters omitted, every customer
|
|
180
|
+
// event in the project, to a URL the caller typed. That is customer data
|
|
181
|
+
// leaving the account on consequence, which is the `create_refund` argument
|
|
182
|
+
// again: the verb says additive, the effect says destructive, and the
|
|
183
|
+
// approval copy should say the latter.
|
|
184
|
+
["create-webhook-integration", "destructive"],
|
|
185
|
+
["delete-webhook-integration", "destructive"],
|
|
186
|
+
["update-webhook-integration", "destructive"],
|
|
187
|
+
// Paywall editing. Both start an async task; what the task does decides the
|
|
188
|
+
// verdict. Creating a paywall leaves every existing one alone (additive);
|
|
189
|
+
// editing one rewrites a draft that already exists (destructive).
|
|
190
|
+
["create-paywall-ai", "additive"],
|
|
191
|
+
["edit-paywall-ai", "destructive"],
|
|
192
|
+
]);
|
|
193
|
+
/**
|
|
194
|
+
* The manifest this release reviewed: both lists in one place, which is what
|
|
195
|
+
* makes the classification the connector applies and the drift check that runs
|
|
196
|
+
* beside it the same fact (P13). Ninety-four of the ninety-five tools
|
|
197
|
+
* RevenueCat's reference lists on 2026-08-18 are classified; the ninety-fifth,
|
|
198
|
+
* `render-paywall-screenshot`, has no access column to classify from and fails
|
|
199
|
+
* closed.
|
|
200
|
+
*
|
|
201
|
+
* No schema digests. No release has read RevenueCat's live schemas and written
|
|
202
|
+
* them down — that needs a live project and a maintainer's own `sk_` key — and
|
|
203
|
+
* an invented digest would report a change that never happened.
|
|
204
|
+
* `npm run drift:check -- --record` reads them from a live catalog and prints
|
|
205
|
+
* the block to paste in
|
|
206
|
+
* ([#351](https://github.com/zackbart/connecta/issues/351)).
|
|
207
|
+
*
|
|
208
|
+
* Exported because the maintainer-run check compares against this manifest and
|
|
209
|
+
* *names* what moved, which the runtime check deliberately cannot.
|
|
210
|
+
*/
|
|
211
|
+
export const REVENUECAT_VETTED_CATALOG = vettedCatalog({
|
|
212
|
+
reads: READ_ONLY_TOOLS,
|
|
213
|
+
writes: WRITE_TOOLS,
|
|
214
|
+
});
|
|
215
|
+
/** The catalog's summary bound; a longer declared value throws (`src/registry.ts`). */
|
|
216
|
+
const SUMMARY_BUDGET = 120;
|
|
217
|
+
/**
|
|
218
|
+
* Fit a purpose-bearing summary inside the catalog's bound.
|
|
219
|
+
*
|
|
220
|
+
* Stripe and Mixpanel declare static summaries because their routing fact is
|
|
221
|
+
* an enumerable variant. RevenueCat's is not: two `sk_` connectors have the
|
|
222
|
+
* same title, the same endpoint, and the same catalog, and differ only by the
|
|
223
|
+
* project the operator says each key reaches. So the summary carries that, and
|
|
224
|
+
* clipping is this function's job rather than the operator's.
|
|
225
|
+
*/
|
|
226
|
+
function boundedSummary(prefix, purpose) {
|
|
227
|
+
const full = `${prefix}${purpose}`;
|
|
228
|
+
if (full.length <= SUMMARY_BUDGET)
|
|
229
|
+
return full;
|
|
230
|
+
return `${full.slice(0, SUMMARY_BUDGET - 1).trimEnd()}…`;
|
|
231
|
+
}
|
|
232
|
+
function sharedUsageGuide() {
|
|
233
|
+
return `
|
|
234
|
+
- Resolve ids before acting; never guess one. \`list-projects\` yields the \`project_id\` every project-scoped call takes. \`list-apps\`, \`list-products\`, \`list-entitlements\`, \`list-offerings\`, \`list-paywalls\`, \`list-audiences\`, and \`list-customers\` yield the ids their \`get-\`, \`update-\`, \`archive-\`, and \`delete-\` counterparts expect. A plausible-looking id belongs to another project or to nobody.
|
|
235
|
+
- Customers are addressed by the app user id your SDK set, not by an internal key. Find one with \`list-customers\` before \`get-customer\`, and carry the id it returned unchanged.
|
|
236
|
+
- Customer and subscription objects are large, and a customer's history is larger. Page with the cursor the list returned rather than raising the page size, and reduce inside \`execute_code\` — select the fields the question needs and return those, not the whole object.
|
|
237
|
+
- Whether a customer should have access is \`gives_access\` on each subscription from \`list-subscriptions\`, which RevenueCat calls the authoritative flag. \`status\` and \`expires_date\` describe the store-side state and disagree with it during grace periods, billing retries, and promotional grants — answer access questions from \`gives_access\` and say which subscription it came from.
|
|
238
|
+
- \`get-chart-data\` is the metrics path: read \`get-chart-options-schema\` for the chart you want before calling it, rather than guessing an option name. \`get-overview-metrics\` and \`get-revenue-metric\` answer the summary questions in one call.
|
|
239
|
+
- \`create-paywall-ai\`, \`edit-paywall-ai\`, and \`set-product-store-state\` are asynchronous. They return a task or operation id; poll it with \`get-paywall-ai-task\` or \`get-product-store-state-operation\` rather than assuming the work finished when the call returned.
|
|
240
|
+
- This connection's tool list is not a fixed set. RevenueCat gates parts of its MCP catalog by plan, platform, and beta enrollment — paywall AI editing, benchmarks, experiments, virtual currencies, and the account-billing tools are the usual absentees — so search this connector for what it actually exposes rather than assuming a documented tool is here.
|
|
241
|
+
- \`render-paywall-screenshot\` is unclassified on purpose: RevenueCat's reference gives it no access column, so it fails closed onto \`call_destructive_tool\` until a release reviews it.
|
|
242
|
+
- RevenueCat meters API v2 per minute and per domain, and the domains differ: 480 requests per minute for customer information and virtual currencies, 60 for project configuration and audiences, 25 for charts and metrics. It answers a breach with \`429\`, a \`Retry-After\` header, and a \`backoff_ms\` field. Back off on that rather than retrying immediately, and expect chart sweeps to hit the ceiling long before customer reads do.
|
|
243
|
+
- Treat every create, update, archive, unarchive, attach, detach, delete, publish, unpublish, grant, assign, and submit operation as a write. Connecta routes the maintained write catalog through \`call_destructive_tool\`; newly added tools also fail closed until a release classifies them.
|
|
244
|
+
- An \`auth_required\` failure means this connector's RevenueCat authorization is missing or expired: run \`authorize_connector\` for this connector id, then retry the same call unchanged. A rejected argument, a permission gap, or a plan restriction comes back in RevenueCat's own words instead — read it rather than re-authorizing.
|
|
245
|
+
`;
|
|
246
|
+
}
|
|
247
|
+
function oauthUsageGuide(purpose, instructions) {
|
|
248
|
+
const projectInstructions = instructions?.trim();
|
|
249
|
+
return `# RevenueCat usage
|
|
250
|
+
|
|
251
|
+
Account-scoped connection: this OAuth session reaches every RevenueCat project the account can see. Connector purpose: ${purpose}
|
|
252
|
+
|
|
253
|
+
Call \`list-projects\` first and carry the exact \`project_id\` it returned into every project-scoped call. Connecta does not pick a project, and the connector id, title, and purpose are routing hints rather than proof of which project a call will land in. If more than one project fits the request, stop and ask; never guess a \`project_id\`.
|
|
254
|
+
${sharedUsageGuide()}${projectInstructions
|
|
255
|
+
? `\n## Project instructions\n\n${projectInstructions}\n`
|
|
256
|
+
: ""}`;
|
|
257
|
+
}
|
|
258
|
+
function keyUsageGuide(purpose, instructions) {
|
|
259
|
+
const projectInstructions = instructions?.trim();
|
|
260
|
+
return `# RevenueCat usage
|
|
261
|
+
|
|
262
|
+
Single-project connection: ${purpose}. RevenueCat secret API keys are project-wide, so this key reaches exactly one project and nothing outside it. A second project is a second connector with its own key and its own id — never a \`project_id\` argument pointed somewhere else.
|
|
263
|
+
|
|
264
|
+
Confirm the project on first use: \`list-projects\` returns the one project this key can see, and its \`project_id\` is the one every project-scoped call takes. An empty or unexpected result means wrong connector, not missing data.
|
|
265
|
+
|
|
266
|
+
A RevenueCat secret key is issued read-only or write-enabled, and connecta cannot tell which this one is. It does not filter writes for a read-only key: every write is offered, reaches RevenueCat, and fails there in RevenueCat's own words. Read that refusal as "this key cannot write" rather than as a bad argument, and route the write to a connector configured with a write-enabled key.
|
|
267
|
+
${sharedUsageGuide()}${projectInstructions
|
|
268
|
+
? `\n## Project instructions\n\n${projectInstructions}\n`
|
|
269
|
+
: ""}`;
|
|
270
|
+
}
|
|
271
|
+
/** A maintained RevenueCat hosted-MCP connection. */
|
|
272
|
+
export function revenuecat(id, options) {
|
|
273
|
+
const purpose = options.purpose.trim();
|
|
274
|
+
if (!purpose) {
|
|
275
|
+
throw new Error("revenuecat() requires a non-empty project purpose.");
|
|
276
|
+
}
|
|
277
|
+
const auth = options.auth ?? { type: "oauth" };
|
|
278
|
+
const scoped = auth.type === "headers";
|
|
279
|
+
const connector = remoteMcp(id, {
|
|
280
|
+
url: REVENUECAT_MCP_ENDPOINT,
|
|
281
|
+
// The scope shape rides the title because browse-time discovery renders
|
|
282
|
+
// the title and the guide summary and nothing else, and reaching one
|
|
283
|
+
// project versus every project the account has is the fact an agent must
|
|
284
|
+
// not get wrong between two RevenueCat connections.
|
|
285
|
+
title: options.title ?? (scoped ? "RevenueCat (single project)" : "RevenueCat"),
|
|
286
|
+
description: scoped
|
|
287
|
+
? `RevenueCat subscriptions and revenue (one project, static key) — ${purpose}`
|
|
288
|
+
: `RevenueCat subscriptions and revenue (every project the account can reach) — ${purpose}`,
|
|
289
|
+
auth,
|
|
290
|
+
requireHttps: true,
|
|
291
|
+
usageGuide: {
|
|
292
|
+
content: scoped
|
|
293
|
+
? keyUsageGuide(purpose, options.instructions)
|
|
294
|
+
: oauthUsageGuide(purpose, options.instructions),
|
|
295
|
+
// Explicit rather than derived, and purpose-bearing rather than static:
|
|
296
|
+
// the derived summary would cut the scoping sentence mid-clause at 120
|
|
297
|
+
// characters, and two static summaries would leave two `sk_` connectors
|
|
298
|
+
// indistinguishable in the one field search returns (P3).
|
|
299
|
+
summary: scoped
|
|
300
|
+
? boundedSummary("One project only: ", purpose)
|
|
301
|
+
: boundedSummary("All account projects; list-projects first: ", purpose),
|
|
302
|
+
// Not `required`. RevenueCat's own schemas describe each call; the guide
|
|
303
|
+
// carries the project-resolution sequence, which is worth reading before
|
|
304
|
+
// a run rather than before every call.
|
|
305
|
+
},
|
|
306
|
+
...(options.callAdmission !== undefined
|
|
307
|
+
? { callAdmission: options.callAdmission }
|
|
308
|
+
: {}),
|
|
309
|
+
...(options.maxResultBytes !== undefined
|
|
310
|
+
? { maxResultBytes: options.maxResultBytes }
|
|
311
|
+
: {}),
|
|
312
|
+
});
|
|
313
|
+
return withVettedCatalog(connector, REVENUECAT_VETTED_CATALOG);
|
|
314
|
+
}
|
|
@@ -1,37 +1,37 @@
|
|
|
1
1
|
import { type RemoteMcpAuth } from "../connectors/remote-mcp.js";
|
|
2
2
|
import type { Connector } from "../types.js";
|
|
3
|
-
/**
|
|
4
|
-
* Which Stripe environment this instance speaks to. Required, and deliberately
|
|
5
|
-
* undefaulted: there is no safe guess between an account that moves real money
|
|
6
|
-
* and one that does not.
|
|
7
|
-
*/
|
|
3
|
+
/** Which Stripe environment a static credential reaches. */
|
|
8
4
|
export type StripeMode = "production" | "sandbox";
|
|
9
|
-
/** Stripe publishes one hosted MCP endpoint
|
|
5
|
+
/** Stripe publishes one hosted MCP endpoint for every account and mode. */
|
|
10
6
|
export declare const STRIPE_MCP_ENDPOINT = "https://mcp.stripe.com/";
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Which Stripe environment this connector reaches. Shapes the title,
|
|
14
|
-
* description, guide, and admission budget, and is checked against a
|
|
15
|
-
* recognizable key prefix in `auth` headers.
|
|
16
|
-
*/
|
|
17
|
-
mode: StripeMode;
|
|
18
|
-
/** Human-readable display name; defaults to "Stripe (<mode>)". */
|
|
7
|
+
interface StripeCommonOptions {
|
|
8
|
+
/** Human-readable display name; defaults to "Stripe" for OAuth. */
|
|
19
9
|
title?: string;
|
|
20
10
|
/** Which business purpose and Stripe context this connector is for. */
|
|
21
11
|
purpose: string;
|
|
22
|
-
/** OAuth by default; static headers support restricted API keys. */
|
|
23
|
-
auth?: RemoteMcpAuth;
|
|
24
|
-
/**
|
|
25
|
-
* Connect platform only: act as this connected account (`acct_...`) by
|
|
26
|
-
* sending Stripe's `Stripe-Account` header. Stripe does not support OAuth on
|
|
27
|
-
* connected-account calls, so this requires `headers` auth.
|
|
28
|
-
*/
|
|
29
|
-
connectedAccount?: string;
|
|
30
12
|
/** Connector-specific conventions appended to the maintained provider guide. */
|
|
31
13
|
instructions?: string;
|
|
32
14
|
/** Connector-specific inline result limit; omit to inherit the deployment. */
|
|
33
15
|
maxResultBytes?: number;
|
|
34
16
|
}
|
|
17
|
+
/** OAuth sessions discover account and mode together from Stripe's live tools. */
|
|
18
|
+
export interface StripeOAuthOptions extends StripeCommonOptions {
|
|
19
|
+
auth?: {
|
|
20
|
+
type: "oauth";
|
|
21
|
+
};
|
|
22
|
+
mode?: never;
|
|
23
|
+
connectedAccount?: never;
|
|
24
|
+
}
|
|
25
|
+
/** Static credentials have one fixed mode, including Stripe Connect calls. */
|
|
26
|
+
export interface StripeHeaderOptions extends StripeCommonOptions {
|
|
27
|
+
auth: Extract<RemoteMcpAuth, {
|
|
28
|
+
type: "headers";
|
|
29
|
+
}>;
|
|
30
|
+
mode: StripeMode;
|
|
31
|
+
/** Act as one Connect account by sending Stripe's `Stripe-Account` header. */
|
|
32
|
+
connectedAccount?: string;
|
|
33
|
+
}
|
|
34
|
+
export type StripeOptions = StripeOAuthOptions | StripeHeaderOptions;
|
|
35
35
|
/**
|
|
36
36
|
* The manifest this release reviewed: both lists in one place, which is what
|
|
37
37
|
* makes the classification the connector applies and the drift check that runs
|
|
@@ -47,3 +47,4 @@ export interface StripeOptions {
|
|
|
47
47
|
export declare const STRIPE_VETTED_CATALOG: import("../catalog-drift.js").VettedCatalog;
|
|
48
48
|
/** A maintained Stripe hosted-MCP connection. */
|
|
49
49
|
export declare function stripe(id: string, options: StripeOptions): Connector;
|
|
50
|
+
export {};
|