@zackbart/connecta 0.34.0 → 0.34.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 +30 -0
- package/README.md +3 -2
- package/bin/version.mjs +1 -1
- package/dist/catalog-drift.d.ts +30 -26
- package/dist/catalog-drift.js +169 -84
- package/dist/catalog-service.js +1 -1
- package/dist/connectors/api-connector.d.ts +3 -0
- package/dist/connectors/api-connector.js +5 -1
- package/dist/connectors/option-shapes.js +1 -1
- package/dist/connectors/remote-mcp.d.ts +2 -0
- package/dist/connectors/remote-mcp.js +5 -1
- package/dist/describe-config.d.ts +2 -0
- package/dist/describe-config.js +1 -0
- package/dist/invocation.js +3 -2
- package/dist/meta-tools.js +3 -2
- package/dist/operator-ui/config-summary.js +3 -0
- package/dist/operator-ui/connection-map.js +2 -1
- package/dist/operator-ui/endpoints.js +1 -1
- package/dist/operator-ui/generated.js +3 -3
- package/dist/operator-ui/health.js +52 -0
- package/dist/operator-ui/overview.js +6 -17
- package/dist/operator-ui/view.d.ts +3 -4
- package/dist/operator-ui/view.js +29 -11
- package/dist/provider.d.ts +6 -1
- package/dist/provider.js +18 -1
- package/dist/providers/_shared/google/workspace.d.ts +3 -0
- package/dist/providers/_shared/google/workspace.js +1 -1
- package/dist/providers/basecamp/index.d.ts +2 -0
- package/dist/providers/breeze/index.d.ts +2 -0
- package/dist/providers/ccb/index.d.ts +2 -0
- package/dist/providers/ccb/index.js +1 -1
- package/dist/providers/cloudflare/index.d.ts +2 -0
- package/dist/providers/cloudflare/index.js +5 -1
- package/dist/providers/cloudflare/openapi.generated.js +3296 -3206
- package/dist/providers/cloudflare/rest.js +19 -0
- package/dist/providers/cloudflare/skill.generated.js +2 -2
- package/dist/providers/cloudflare/value-safety.js +51 -18
- package/dist/providers/intercom/index.d.ts +24 -0
- package/dist/providers/intercom/index.js +121 -0
- package/dist/providers/intercom/skill.generated.js +8 -0
- package/dist/providers/linear/index.js +204 -19
- package/dist/providers/linear/skill.generated.js +2 -2
- package/dist/providers/mixpanel/index.d.ts +2 -0
- package/dist/providers/mixpanel/index.js +21 -17
- package/dist/providers/mixpanel/skill.generated.js +1 -1
- package/dist/providers/notion/index.d.ts +2 -0
- package/dist/providers/notion/index.js +1 -1
- package/dist/providers/overflow/index.d.ts +2 -0
- package/dist/providers/planning-center/index.d.ts +2 -0
- package/dist/providers/revenuecat/index.d.ts +5 -3
- package/dist/providers/revenuecat/index.js +147 -7
- package/dist/providers/revenuecat/skill.generated.js +3 -3
- package/dist/providers/stripe/index.d.ts +2 -0
- package/dist/providers/stripe/index.js +50 -30
- package/dist/providers/stripe/skill.generated.js +2 -1
- package/dist/providers/tithely/index.d.ts +2 -0
- package/dist/providers/vercel/index.d.ts +2 -0
- package/dist/providers/vercel/index.js +1 -1
- package/dist/providers/vercel/openapi.generated.js +391 -374
- package/dist/providers/vercel/skill.generated.js +1 -1
- package/dist/providers/vercel/value-safety.js +14 -4
- package/dist/registry.d.ts +10 -14
- package/dist/registry.js +62 -62
- package/dist/routes/ui-data.js +8 -2
- package/dist/skills.js +8 -2
- package/dist/types.d.ts +18 -4
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/documentation/architecture.md +48 -5
- package/documentation/code-mode.md +7 -5
- package/documentation/integrating.md +55 -1
- package/documentation/meta-tools.md +2 -2
- package/documentation/operating.md +1 -1
- package/documentation/operator-tests.md +8 -2
- package/documentation/operator-ui.md +58 -11
- package/documentation/provider-auth-migration.md +22 -0
- package/package.json +5 -1
- package/templates/node/package.json +1 -1
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
// Generated by scripts/generate-providers.mjs; do not edit.
|
|
2
2
|
export const skill = {
|
|
3
|
-
"content": "\n- Inspect result framing before accessing fields. A text result is not automatically an object; parse it only if the returned text is valid JSON. Do not iterate fields that the response does not contain.\n- 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.\n- 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.\n- 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.\n- 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.\n- `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.\n- `create-paywall-ai` and `edit-paywall-ai` are asynchronous. Poll the task id they return with `get-paywall-ai-task` rather than assuming the work finished when the call returned.\n-
|
|
3
|
+
"content": "\n- Inspect result framing before accessing fields. A text result is not automatically an object; parse it only if the returned text is valid JSON. Do not iterate fields that the response does not contain.\n- 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.\n- 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.\n- 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.\n- 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.\n- `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.\n- `create-paywall-ai` and `edit-paywall-ai` are asynchronous. Poll the task id they return with `get-paywall-ai-task` rather than assuming the work finished when the call returned.\n- The documented `get-product-store-state-operation`, `create-product-prices`, `equalize-subscription-prices`, `set-product-store-state`, and `upload-product-store-state-screenshot` tools are deprecated; they remain supported when the server exposes them. Store changes use the plan workflow: `create-product-store-state-plan`, then `plan-product-store-state-plan`, then `apply-product-store-state-plan`. Every step past the create is asynchronous — read the plan back with `get-product-store-state-plan` between steps instead of assuming the last one finished.\n- This connection's tool list is not a fixed set. The reviewed catalog is a superset, not a promise that every reviewed tool is available. RevenueCat gates parts of its MCP catalog by API key permissions, 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.\n- `list-app-subscription-groups`, `preview-audience`, and `render-paywall-screenshot` are reviewed reads. Audience preview uses an observational POST that returns matching customers without creating an audience; screenshot rendering previews a paywall without editing or publishing it.\n- `validate-app-credentials` stays classified as write conservatively: the MCP reference labels it Read and says credentials are unchanged, but the live annotation says otherwise and the public API v2 app contract does not establish whether validation status or results persist. Do not infer permission to call it from its presence under a read-only API key.\n- 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.\n- Use discovery's effective classification for routing rather than inferring safety from a name or HTTP method. Creates, updates, archives, grants, publishes, and store changes are writes; audience previews and screenshot rendering are reads. For guest calls, classification, and routing, fetch `skills({ name: \"usage\" })`.\n- 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.\n# RevenueCat usage\n\nAccount-scoped connection: this OAuth session reaches every RevenueCat project the account can see. Connector purpose: \n\nCall `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`.\n. 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.\n\nConfirm 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.\n\nA RevenueCat secret key has per-resource permissions. RevenueCat can omit tools this key cannot use from its live catalog; Connecta serves the returned catalog rather than adding missing tools from its reviewed superset. Catalog presence alone does not prove a call is permitted. A served tool can still fail at RevenueCat for missing permissions; read that refusal and route the call to a connector with the required permissions. A read-only Connecta endpoint independently omits and blocks tools classified as writes.\n",
|
|
4
4
|
"instructionsHeading": "Project instructions",
|
|
5
5
|
"fragments": {
|
|
6
|
-
"guide_0": "\n- Inspect result framing before accessing fields. A text result is not automatically an object; parse it only if the returned text is valid JSON. Do not iterate fields that the response does not contain.\n- 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.\n- 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.\n- 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.\n- 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.\n- `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.\n- `create-paywall-ai` and `edit-paywall-ai` are asynchronous. Poll the task id they return with `get-paywall-ai-task` rather than assuming the work finished when the call returned.\n-
|
|
6
|
+
"guide_0": "\n- Inspect result framing before accessing fields. A text result is not automatically an object; parse it only if the returned text is valid JSON. Do not iterate fields that the response does not contain.\n- 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.\n- 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.\n- 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.\n- 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.\n- `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.\n- `create-paywall-ai` and `edit-paywall-ai` are asynchronous. Poll the task id they return with `get-paywall-ai-task` rather than assuming the work finished when the call returned.\n- The documented `get-product-store-state-operation`, `create-product-prices`, `equalize-subscription-prices`, `set-product-store-state`, and `upload-product-store-state-screenshot` tools are deprecated; they remain supported when the server exposes them. Store changes use the plan workflow: `create-product-store-state-plan`, then `plan-product-store-state-plan`, then `apply-product-store-state-plan`. Every step past the create is asynchronous — read the plan back with `get-product-store-state-plan` between steps instead of assuming the last one finished.\n- This connection's tool list is not a fixed set. The reviewed catalog is a superset, not a promise that every reviewed tool is available. RevenueCat gates parts of its MCP catalog by API key permissions, 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.\n- `list-app-subscription-groups`, `preview-audience`, and `render-paywall-screenshot` are reviewed reads. Audience preview uses an observational POST that returns matching customers without creating an audience; screenshot rendering previews a paywall without editing or publishing it.\n- `validate-app-credentials` stays classified as write conservatively: the MCP reference labels it Read and says credentials are unchanged, but the live annotation says otherwise and the public API v2 app contract does not establish whether validation status or results persist. Do not infer permission to call it from its presence under a read-only API key.\n- 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.\n- Use discovery's effective classification for routing rather than inferring safety from a name or HTTP method. Creates, updates, archives, grants, publishes, and store changes are writes; audience previews and screenshot rendering are reads. For guest calls, classification, and routing, fetch `skills({ name: \"usage\" })`.\n- 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.\n",
|
|
7
7
|
"guide_1": "# RevenueCat usage\n\nAccount-scoped connection: this OAuth session reaches every RevenueCat project the account can see. Connector purpose: ",
|
|
8
8
|
"guide_2": "\n\nCall `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`.\n",
|
|
9
|
-
"guide_3": ". 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.\n\nConfirm 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.\n\nA RevenueCat secret key
|
|
9
|
+
"guide_3": ". 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.\n\nConfirm 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.\n\nA RevenueCat secret key has per-resource permissions. RevenueCat can omit tools this key cannot use from its live catalog; Connecta serves the returned catalog rather than adding missing tools from its reviewed superset. Catalog presence alone does not prove a call is permitted. A served tool can still fail at RevenueCat for missing permissions; read that refusal and route the call to a connector with the required permissions. A read-only Connecta endpoint independently omits and blocks tools classified as writes.\n"
|
|
10
10
|
}
|
|
11
11
|
};
|
|
@@ -14,6 +14,8 @@ interface StripeCommonOptions {
|
|
|
14
14
|
instructions?: string;
|
|
15
15
|
/** Connector-specific inline result limit; omit to inherit the deployment. */
|
|
16
16
|
maxResultBytes?: number;
|
|
17
|
+
/** Serve only read-classified tools on every endpoint. Defaults to false. */
|
|
18
|
+
readOnly?: boolean;
|
|
17
19
|
}
|
|
18
20
|
/**
|
|
19
21
|
* Stripe's hosted MCP server over OAuth. One session can reach live and
|
|
@@ -40,77 +40,97 @@ const STRIPE_ADMISSION = {
|
|
|
40
40
|
},
|
|
41
41
|
};
|
|
42
42
|
/**
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
* tool it authors.
|
|
43
|
+
* Re-reviewed for #343 against the hosted OAuth catalog and official MCP and
|
|
44
|
+
* analytics docs on 2026-10-19 (#703). Digests cover the complete describe
|
|
45
|
+
* schemas captured in fixtures.ts, not inferred result shapes. The documented
|
|
46
|
+
* get_stripe_account_info remains reviewed without an uncaptured digest.
|
|
47
|
+
* This review applies only to hosted OAuth; REST annotates its own tools.
|
|
49
48
|
*/
|
|
50
49
|
const STRIPE_CLASSIFICATION = {
|
|
51
|
-
tools: {
|
|
50
|
+
"tools": {
|
|
52
51
|
"stripe_api_search": {
|
|
53
52
|
"verdict": "read",
|
|
54
53
|
"reason": "Searches API method contracts and object records; it does not invoke mutating methods.",
|
|
54
|
+
"schemaDigest": "sha256:1fdb44c12347b21b3896250e2a3c88763b54f4cdfe4fff27f7067d004e3097e4",
|
|
55
55
|
},
|
|
56
56
|
"stripe_api_details": {
|
|
57
57
|
"verdict": "read",
|
|
58
58
|
"reason": "Reads the parameter contract for an API method; it does not execute that method.",
|
|
59
|
+
"schemaDigest": "sha256:a80bf5b685eba9b0cb91df7fa36afac04bcb97a7dcadb3c07bd22f0a4fcc7771",
|
|
59
60
|
},
|
|
60
61
|
"stripe_api_read": {
|
|
61
62
|
"verdict": "read",
|
|
62
63
|
"reason": "The vendor restricts this generic tool to HTTP GET; all mutating methods use stripe_api_write.",
|
|
64
|
+
"schemaDigest": "sha256:90b15c317384e244a19472d2bffcc0da73a1174f16fd89a7562134a3da5d0d53",
|
|
63
65
|
},
|
|
64
|
-
"get_stripe_account_info": {
|
|
65
|
-
"get_balance_summary": {
|
|
66
|
-
"verdict": "read",
|
|
67
|
-
"reason": "Retrieves Stripe balance summary information without changing vendor state.",
|
|
68
|
-
},
|
|
69
|
-
"list_metrics": {
|
|
66
|
+
"get_stripe_account_info": {
|
|
70
67
|
"verdict": "read",
|
|
71
|
-
"reason": "
|
|
68
|
+
"reason": "Reads metadata for the selected Stripe account; still documented although absent from the observed hosted catalog.",
|
|
72
69
|
},
|
|
73
|
-
"
|
|
70
|
+
"get_balance_summary": {
|
|
74
71
|
"verdict": "read",
|
|
75
|
-
"reason": "
|
|
72
|
+
"reason": "Retrieves Stripe balance summary information without changing vendor state.",
|
|
73
|
+
"schemaDigest": "sha256:857973344e59ca7199bc65e62d5e7198332542339f387b7363626ad752437a11",
|
|
76
74
|
},
|
|
77
|
-
"metric_drilldown": { "verdict": "read", "reason": "Reads the breakdown of an existing metric." },
|
|
78
|
-
"show_metric_app": { "verdict": "read", "reason": "Displays an existing metric app without changing its data." },
|
|
79
75
|
"list_available_accounts_or_orgs": {
|
|
80
76
|
"verdict": "read",
|
|
81
|
-
"reason": "
|
|
77
|
+
"reason": "Lists accessible accounts with stripe_context and livemode without changing vendor state; verified in the hosted catalog despite omission from public docs.",
|
|
78
|
+
"schemaDigest": "sha256:5ed608b204ddf3e117f419a0443db5bdc28783133476e953338f525489dd5626",
|
|
82
79
|
},
|
|
83
80
|
"manage_stripe_accounts": {
|
|
84
81
|
"verdict": "read",
|
|
85
|
-
"reason": "
|
|
82
|
+
"reason": "Returns a Dashboard reconsent URL; the tool itself does not add accounts, remove accounts, or change permissions.",
|
|
83
|
+
"schemaDigest": "sha256:abb66368ed8d461b1106eb2257235a5d836f76906674c44be9ac816b6d509cd4",
|
|
86
84
|
},
|
|
87
85
|
"search_stripe_documentation": {
|
|
88
86
|
"verdict": "read",
|
|
89
87
|
"reason": "Searches Stripe reference documentation without accessing payment mutations.",
|
|
88
|
+
"schemaDigest": "sha256:18b5d9f565d28bc4786ba1f657a2c291c43f4c9137e4c5ca5fbbf5dd114eae67",
|
|
90
89
|
},
|
|
91
90
|
"stripe_api_write": {
|
|
92
91
|
"verdict": "destructive",
|
|
93
92
|
"reason": "Can dispatch POST, PATCH, PUT, or DELETE across the Stripe API, including edits and cancellations.",
|
|
93
|
+
"schemaDigest": "sha256:61d1bdc4e6862989c46250bdbea3adfc6169c24dbf6e8b20fc4251108da5c4e7",
|
|
94
|
+
},
|
|
95
|
+
"convert_currency": {
|
|
96
|
+
"verdict": "destructive",
|
|
97
|
+
"reason": "Converts existing funds between currencies in a Financial Account, changing balances.",
|
|
98
|
+
"schemaDigest": "sha256:5a861f71e41b6c680452a5817d7c67c4a708796a4e0dcf7adbd8c4f89c6c99f8",
|
|
94
99
|
},
|
|
95
|
-
"
|
|
100
|
+
"send_money": {
|
|
96
101
|
"verdict": "destructive",
|
|
97
|
-
"reason": "
|
|
102
|
+
"reason": "Sends funds to a third-party recipient through an outbound payment or payout link.",
|
|
103
|
+
"schemaDigest": "sha256:5415856ee7e5073f3e6ea3280c5f17289449ded3dbb92d4a4ab9b52af1ed3049",
|
|
104
|
+
},
|
|
105
|
+
"setup_recipient": {
|
|
106
|
+
"verdict": "destructive",
|
|
107
|
+
"reason": "Creates a recipient account for outbound payments; retain the upstream destructive hint rather than treating setup as a read.",
|
|
108
|
+
"schemaDigest": "sha256:75e0bb1003a3a74badab81d4fb76f4a8481b186f7755b0a7ee73f1623b163457",
|
|
109
|
+
},
|
|
110
|
+
"transfer_money": {
|
|
111
|
+
"verdict": "destructive",
|
|
112
|
+
"reason": "Moves existing funds between Stripe balances or Financial Accounts.",
|
|
113
|
+
"schemaDigest": "sha256:e75be95113883df72577127387cf2a11fae51d2cc01df80a085f4b276bd362d8",
|
|
114
|
+
},
|
|
115
|
+
"atlas_company_formation": {
|
|
116
|
+
"verdict": "destructive",
|
|
117
|
+
"reason": "Creates or advances company formation state; list and retrieve actions share this mutating tool boundary.",
|
|
118
|
+
"schemaDigest": "sha256:648e1faca5f5ac3dc7018890a336081135842d9418ee6df94dcbd81b7d861694",
|
|
98
119
|
},
|
|
99
120
|
"stripe_implementation_planner": {
|
|
100
121
|
"verdict": "write",
|
|
101
122
|
"reason": "Creates or continues provider-side planning state.",
|
|
123
|
+
"schemaDigest": "sha256:284dce4e701ab4cb9b9c9fbf61104cae2eab0b9eef1b986f128fc1bbc42ef185",
|
|
102
124
|
},
|
|
103
125
|
"stripe_analytics": {
|
|
104
126
|
"verdict": "write",
|
|
105
|
-
"reason": "
|
|
106
|
-
|
|
107
|
-
"stripe_report": {
|
|
108
|
-
"verdict": "write",
|
|
109
|
-
"reason": "May create durable report-run state, so retrieval paths cannot make the whole tool read-only.",
|
|
127
|
+
"reason": "The hosted schema includes execute_query_run and execute_query_template alongside retrieval; asynchronous query-run creation makes the whole tool a write even though it analyzes existing data.",
|
|
128
|
+
"schemaDigest": "sha256:c6b22ff19b5fe2d359b20f99b67591ba74cf504870123711579556b6937916b9",
|
|
110
129
|
},
|
|
111
|
-
"
|
|
130
|
+
"send_stripe_feedback": {
|
|
112
131
|
"verdict": "write",
|
|
113
|
-
"reason": "Submits feedback to Stripe, creating provider-side state.",
|
|
132
|
+
"reason": "Submits feedback to Stripe, creating provider-side state; replaces send_stripe_mcp_feedback.",
|
|
133
|
+
"schemaDigest": "sha256:4ac352f04a8d974bdb56503f4826e7fbc19458e0f0d0c369f17e82d5fb6a7a86",
|
|
114
134
|
},
|
|
115
135
|
},
|
|
116
136
|
};
|
|
@@ -152,7 +172,7 @@ Mode: ${mode}. Connector purpose: ${purpose}
|
|
|
152
172
|
${copy.warning}${connect}${key}${shared}${key_limits}${copy.rate}${key_tail}
|
|
153
173
|
${instructionsSection(instructions)}`;
|
|
154
174
|
}
|
|
155
|
-
const COMMON = keys("title", "authScope", "purpose", "instructions", "maxResultBytes");
|
|
175
|
+
const COMMON = keys("title", "authScope", "purpose", "instructions", "maxResultBytes", "readOnly");
|
|
156
176
|
/** The closed options stripe() accepts, selected by `auth.type`; see `assertKnownOptions`. */
|
|
157
177
|
const STRIPE_OPTIONS = variants(["auth", "type"], {
|
|
158
178
|
// The never-typed keys stay out of the shape, so the walk refuses them by name.
|
|
@@ -3,7 +3,8 @@ export const skill = {
|
|
|
3
3
|
"content": "- Lists are cursor-paginated: `limit` defaults to 10 and caps at 100, `starting_after` and `ending_before` take an object id and are mutually exclusive, and `has_more` says whether to continue. Page inside `execute_code`.\n- Search filters on a documented per-resource field set, not on arbitrary attributes. Charges search takes `amount`, `created`, `currency`, `customer`, `status`, `refunded`, `disputed`, `metadata`, `billing_details.address.postal_code`, and `payment_method_details.<source>.*` card fields — there is no `payment_intent` field. When the field you want is not searchable, retrieve the parent object and follow its reference (the PaymentIntent's `latest_charge`) instead of retrying the search with another spelling.\n- The account → `stripe_api_search` → `stripe_api_details` → `stripe_api_read` sequence is one program, not four turns: resolve the method once, then call that method as many times as the investigation needs in the same run.\n- Decline outcomes live on the charge — `outcome`, `failure_code`, `failure_message` — reached from the PaymentIntent's `latest_charge`, so \"why did this payment fail\" is a PaymentIntent read followed by one charge read.\n- Resolve ids before acting; never guess one. Stripe ids are typed prefixes — `cus_` customer, `sub_` subscription, `ch_` charge, `pi_` payment intent, `in_` invoice, `acct_` account — and a plausible-looking id belongs to a different object or to nobody.\n- Amounts are integers in the currency's minor unit: `1099` is 10.99 USD, and zero-decimal currencies like JPY take `10` for 10 JPY. Never send a decimal.\n- Treat every create, update, delete, refund, and report run as a write. For guest calls, classification, and routing, fetch `skills({ name: \"usage\" })`.\n",
|
|
4
4
|
"instructionsHeading": "Account instructions",
|
|
5
5
|
"fragments": {
|
|
6
|
-
"
|
|
6
|
+
"setup": "## Choose OAuth or an API key\n\nImport `stripe` from `@zackbart/connecta/providers/stripe`. Choose one of two setup paths:\n\n```ts\n// OAuth: Stripe's hosted MCP. Authorize the connection with Stripe.\nstripe(\"billing\", { purpose: \"Payments\", auth: { type: \"oauth\" } });\nstripe(\"billing\", { purpose: \"Revenue reports\", auth: { type: \"oauth\" }, readOnly: true });\n\n// API key: Connecta's REST connector. Paste the key into this connection in the operator UI.\nstripe(\"billing\", { purpose: \"Payments\", auth: { type: \"apiKey\" }, mode: \"production\" });\nstripe(\"billing\", { purpose: \"Revenue reports\", auth: { type: \"apiKey\" }, mode: \"production\", readOnly: true });\n```\n\nFor an API key, set `mode` to `\"production\"` or `\"sandbox\"` to match the key.\nUse a secret (`sk_`) or restricted (`rk_`) key. For read-only access, prefer a\nrestricted `rk_` key configured with only read permissions: Stripe enforces\nthose permissions too. Connecta's `readOnly: true` omits non-read tools and\nrefuses their calls on every endpoint. Omit it for the default writable connector;\nendpoint restrictions still apply. OAuth needs no `mode` and can reach both live\nand sandbox accounts through Stripe's account selectors.\n\n",
|
|
7
|
+
"oauth": "\n\nThis OAuth session may expose both live and sandbox Stripe accounts. Discover the live account-selection tools, select the intended account and mode, then carry exact context fields such as `stripe_context` and `livemode` wherever the schema requires them. A live-mode write moves real money; a sandbox write changes test data. Never infer the account or mode from connector metadata.\n\n- Discover account and mode with the live account-selection tools before every account-scoped read or write. The reviewed hosted catalog exposes `list_available_accounts_or_orgs` to return `stripe_context` and `livemode`, and `manage_stripe_accounts` to return a Dashboard URL for managing session access; discover what this session actually exposes. Select the intended result and carry the exact context fields required by the live schema unchanged. If the account, mode, or supported selector is ambiguous, stop and ask; never guess.\n- Organization accounts are not Stripe Connect connected accounts. A Connect call requires a separate API-key connector whose `connectedAccount` sends Stripe's documented `Stripe-Account` header; OAuth does not support that path.\n- Four generic tools reach any Stripe API method. Find the method with `stripe_api_search`, read its parameters with `stripe_api_details`, then call `stripe_api_read` (GET) or `stripe_api_write` (POST/PATCH/PUT/DELETE). Never guess a path or a parameter name — `stripe_api_details` is cheaper than a rejected write.\n- Prefer a dedicated tool when one covers the task: `get_balance_summary` for balances and `stripe_analytics` for Sigma or Metrics reporting. Use `stripe_api_search` for everything else instead of assuming a retired dedicated tool still exists.\n- `stripe_implementation_planner` and the query-execution intents of `stripe_analytics` create provider-side planning or query-run state. Connecta therefore classifies both as writes, which a read-only endpoint refuses; their retrieval paths stay behind the same tool boundary.\n- `convert_currency`, `send_money`, and `transfer_money` move funds. Before dispatch, confirm the intended account and its exact `stripe_context`/`livemode` pair, the source and destination or recipient, the currency, and the amount in minor units. `livemode: true` affects real balances; never switch modes to get past a refusal. `setup_recipient` creates a recipient for outbound payments and is also reviewed as destructive, matching Stripe's hint.\n- Money-movement tools can require Stripe human confirmation. Make the host-approved initial call without `human_confirmation.approval_token`. If Stripe returns an approval request and URL, present that URL as a clickable link and wait for the human to confirm approval. Only then call the same tool with the exact original arguments plus the supplied `human_confirmation.approval_token`; never invent a token, change the amount or recipient, or automatically retry an ambiguous money movement. This Stripe confirmation is separate from the host's tool approval.\n- `atlas_company_formation` creates or advances an Atlas formation application. Its `list` and `retrieve` actions share the same destructive tool boundary as `create` and `advance`; obtain host approval and preserve the selected `stripe_context` and `livemode` for every action.\n- `send_stripe_feedback` submits feedback to Stripe and is a write. Discover that name rather than the retired `send_stripe_mcp_feedback`.\n- `stripe_api_write` carries the blast radius of the entire write API — every POST, PATCH, PUT, and DELETE, from a customer edit to a subscription cancellation. State the method and path explicitly; a read-only endpoint refuses it.\n- Any `stripe_api_read` list or `stripe_api_search` that returns full objects belongs inside `execute_code`, projected to the fields the question needs before `return`. Neither `limit` nor `expand` substitutes for that: an unprojected list of customers or invoices truncates long before it answers, and a projected one keeps the customer's name, email, and address out of the transcript.\n- Find an object with `stripe_api_search` (or a list endpoint through `stripe_api_read`) and carry the `id` it returned into the write.\n- This connection's tool list is not a fixed set. Stripe gates parts of its MCP catalog by account, integration, and beta enrollment, so search this connector for what it actually exposes rather than assuming a documented tool is here.\n- Send an `Idempotency-Key` on every write you might retry, if the tool accepts it, and reuse the same key for the retry. A retry with a fresh key is a second charge, not a second attempt.\n",
|
|
7
8
|
"key": "\n\n- This is Connecta's REST connector to `api.stripe.com`, holding one operator-managed key. It reaches exactly one account in one mode, so there is no account selection and no `stripe_context` or `livemode` argument.\n- `stripe_api_search` finds API operations, not records: it searches the pinned API index and names the tool that calls each operation. `stripe_api_details` returns one operation's parameters with types, enums, and required names. Neither sends a request.\n- `stripe_api_read` calls GET operations, plus `POST /v1/invoices/create_preview`, which only previews. `stripe_api_write` calls every other POST and every DELETE, from a customer edit to a subscription cancellation, with `method` and `path` stated; a read-only endpoint refuses it.\n- Paths are concrete: substitute ids into the template search returned (`/v1/payment_intents/pi_123`). Pass `query` and `body` as JSON objects named as `stripe_api_details` lists them. Connecta form-encodes v1 bodies and query lists (`expand: [\"latest_charge\"]`), sends v2 bodies as JSON, and pins `Stripe-Version` to the index's API version. Send `null` or `\"\"` to unset a field.\n- Every call is checked against the pinned index before it is sent. An unknown path returns the nearest operations; an unknown or missing parameter returns `validation.issues` with the accepted names. Nothing reached Stripe, so fix the call from that answer.\n- Results arrive as `{ status, data, page? }`. On a list, `page.next` is the cursor and `page.param` the query parameter to pass it as: `starting_after`, or `page` for search and v2 lists. Lists belong inside `execute_code`; pass `select` (dot paths such as `data.id` and `data.status`) to keep only the fields the question needs, which also keeps customer names, emails, and addresses out of the transcript.\n- `get_stripe_account_info` confirms the account, mode, and connected account; `get_balance_summary` returns available and pending balances. Use them when they answer the question.\n- Find records with list and search operations through `stripe_api_read` (`GET /v1/customers/search`, `GET /v1/charges` with `customer`) and carry the returned `id` into the write.\n- `stripe_api_write` sends an `Idempotency-Key` on every POST. Pass `idempotencyKey` for anything you might retry, or reuse the generated one the result returns. An ambiguous failure carries it in its message or as `uncertainCall.recovery.idempotencyKey`. Reuse it only with the exact original arguments and within Stripe's retention (v1 keys may be pruned after 24 hours); after that, look the object up before retrying. A retry with a fresh key is a second charge, not a second attempt.\n- Refused by design: operations that hand out a credential (ephemeral keys, Terminal connection tokens, account links (v1 and v2), Terminal onboarding links, Express login links, account sessions, customer sessions, billing portal sessions, file link creation, Financial Connections session creation, and the meter event session), Stripe Apps secret payloads (`expand` of `payload`), Issuing card `number` and `cvc` expansion on any Issuing path, multipart uploads such as `POST /v1/files` (use the Dashboard), and the meter event stream (send single events with `POST /v2/billing/meter_events`). Each refusal names its reason. Quote PDFs arrive from `files.stripe.com` as base64.\n- Secrets read as `\"[redacted]\"` in every result, expansions included: client secrets (PaymentIntents, SetupIntents, Checkout and Identity sessions, Sources, Financial Connections, invoice confirmation secrets), webhook and event destination signing secrets, Apps secret payloads, app-install authorization codes, Terminal Wi-Fi passwords, forwarded request header values, and Issuing card numbers and CVCs. Webhook and event destination URLs, file link URLs (in an expanded File, a list, or an event too), and pre-signed import URLs keep only their scheme and host. Identity verification `url`s come back whole. A Checkout Session's `url` comes back whole only for a guest payment session (`mode: \"payment\"`, no `customer` or `customer_account`, no customer creation, no saved payment method options); any other session returns only its scheme and host, because its page can show, reuse, or remove a customer's saved payment methods. Create those from your own server code, or send a payment link or the invoice's hosted page instead. These rules follow each object wherever it appears, expansions and events included. A `[redacted]` field is never the real value; do not send it back.\n- Failures of credential-bearing operations (webhook endpoints, Apps secrets, Terminal configurations, forwarding) carry Stripe's type, code, decline code, and param, not its message. Payment, billing, and account failures keep Stripe's message.\n- The hosted OAuth connection's natural-language Sigma, metrics, documentation search, implementation planner, and feedback tools do not exist with a key.\n- Embedded URL safety uses reviewed paths plus global signing parameters. Generic credential-named query parameters (`code`, `key`, `token`, `sig`, etc.) and credential-looking fragments withhold the destination's entire query/fragment only in charge `failure_message` and `outcome.seller_message` wherever charge objects appear, including event partial copies and vendor error text. Ordinary `code`/`key` links can therefore be false positives in these diagnostics. Descriptions, metadata, price nicknames, invoice footers and notes keep those ordinary URL parameters byte for byte. Literal AWS SigV4/Google V4 `X-Amz-*`/`X-Goog-*` Signature, Credential and Security-Token values are withheld in every decoded string before projection. A withheld value is not the original: do not write it back. All writes, including named writes and supported raw/base64/multipart uploads, reject URL destinations whose own query/fragment contains the exact `[redacted]` placeholder, plain or encoded, with `invalid_args` before dispatch. Admission iteratively checks every JSON key and value within the host's accepted request size, without separate depth or node-count ceilings; cyclic direct arguments are refused. A marker outside the destination remains ordinary text. Split strings, encoded host/signing names, bare hosts without `//`, and opaque bearer paths remain outside this scan.\n",
|
|
8
9
|
"shared": "- Lists are cursor-paginated: `limit` defaults to 10 and caps at 100, `starting_after` and `ending_before` take an object id and are mutually exclusive, and `has_more` says whether to continue. Page inside `execute_code`.\n- Search filters on a documented per-resource field set, not on arbitrary attributes. Charges search takes `amount`, `created`, `currency`, `customer`, `status`, `refunded`, `disputed`, `metadata`, `billing_details.address.postal_code`, and `payment_method_details.<source>.*` card fields — there is no `payment_intent` field. When the field you want is not searchable, retrieve the parent object and follow its reference (the PaymentIntent's `latest_charge`) instead of retrying the search with another spelling.\n- The account → `stripe_api_search` → `stripe_api_details` → `stripe_api_read` sequence is one program, not four turns: resolve the method once, then call that method as many times as the investigation needs in the same run.\n- Decline outcomes live on the charge — `outcome`, `failure_code`, `failure_message` — reached from the PaymentIntent's `latest_charge`, so \"why did this payment fail\" is a PaymentIntent read followed by one charge read.\n- Resolve ids before acting; never guess one. Stripe ids are typed prefixes — `cus_` customer, `sub_` subscription, `ch_` charge, `pi_` payment intent, `in_` invoice, `acct_` account — and a plausible-looking id belongs to a different object or to nobody.\n- Amounts are integers in the currency's minor unit: `1099` is 10.99 USD, and zero-decimal currencies like JPY take `10` for 10 JPY. Never send a decimal.\n- Treat every create, update, delete, refund, and report run as a write. For guest calls, classification, and routing, fetch `skills({ name: \"usage\" })`.\n",
|
|
9
10
|
"oauth_limits": "- Stripe answers a rate limit with `429` and a `Stripe-Rate-Limited-Reason` header; back off on that rather than retrying immediately. Stripe documents an account ceiling of 100 requests per second in live mode and 25 in sandbox mode, and any single endpoint is capped at 25 per second regardless of mode, so paging one list is the real constraint.\n- Use `search_stripe_documentation` when the shape of an object or a flow is unclear; it is a read and costs nothing but a call.\n- An `auth_required` failure means this connector's Stripe authorization is missing or expired: run `authorize_connector` for this connector id, then retry the same call unchanged. A rejected argument or a plan restriction comes back in Stripe's own words instead — read it rather than re-authorizing.\n",
|
|
@@ -40,6 +40,8 @@ export interface TithelyOptions {
|
|
|
40
40
|
callAdmission?: ConnectorCallAdmissionPolicy;
|
|
41
41
|
/** Connector-specific inline result limit; omit to inherit the deployment. */
|
|
42
42
|
maxResultBytes?: number;
|
|
43
|
+
/** Serve only read-classified tools on every endpoint. Defaults to false. */
|
|
44
|
+
readOnly?: boolean;
|
|
43
45
|
/** Default page size for list tools. Defaults to 25; this connector's cap is 99. */
|
|
44
46
|
defaultPageSize?: number;
|
|
45
47
|
/** API base override for a proxy or test double; replaces the environment's endpoint. */
|
|
@@ -15,6 +15,8 @@ interface VercelCommonOptions {
|
|
|
15
15
|
callAdmission?: ConnectorCallAdmissionPolicy;
|
|
16
16
|
/** Connector-specific inline result limit; omit to inherit the deployment. */
|
|
17
17
|
maxResultBytes?: number;
|
|
18
|
+
/** Serve only read-classified tools on every endpoint. Defaults to false. */
|
|
19
|
+
readOnly?: boolean;
|
|
18
20
|
}
|
|
19
21
|
/**
|
|
20
22
|
* Vercel's hosted MCP server over OAuth. Vercel admits only reviewed and
|
|
@@ -207,7 +207,7 @@ Connecta's REST connector to the Vercel API with one access token. Account purpo
|
|
|
207
207
|
${scope}${key}${shared}${instructionsSection(instructions)}`;
|
|
208
208
|
}
|
|
209
209
|
const COMMON = {
|
|
210
|
-
...keys("title", "authScope", "purpose", "instructions", "maxResultBytes"),
|
|
210
|
+
...keys("title", "authScope", "purpose", "instructions", "maxResultBytes", "readOnly"),
|
|
211
211
|
callAdmission: CALL_ADMISSION,
|
|
212
212
|
};
|
|
213
213
|
/** The closed options vercel() accepts, selected by `auth.type`; see `assertKnownOptions`. */
|