@zackbart/connecta 0.30.0 → 0.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +66 -0
- package/README.md +21 -16
- package/bin/connecta.mjs +1 -0
- package/bin/version.mjs +1 -1
- package/dist/auth-elicitation.js +1 -1
- package/dist/call-recovery.js +25 -0
- package/dist/catalog-service.js +7 -2
- package/dist/config-schema.d.ts +14 -7
- package/dist/config-schema.js +29 -10
- package/dist/config-value-sources.js +6 -3
- package/dist/config.d.ts +26 -8
- package/dist/config.js +38 -16
- package/dist/connector-access.d.ts +2 -1
- package/dist/connectors/guarded-fetch.d.ts +18 -1
- package/dist/connectors/guarded-fetch.js +21 -2
- package/dist/describe-config.d.ts +6 -3
- package/dist/describe-config.js +3 -2
- package/dist/errors.d.ts +3 -1
- package/dist/errors.js +1 -0
- package/dist/execute.js +16 -14
- package/dist/index.js +4 -3
- package/dist/invocation.js +39 -4
- package/dist/meta-tools.js +17 -19
- package/dist/operator-record.d.ts +2 -2
- package/dist/operator-record.js +2 -0
- package/dist/operator-ui/contract.d.ts +5 -4
- package/dist/operator-ui/generated.js +2 -2
- package/dist/operator-ui/model.d.ts +1 -1
- package/dist/operator-ui/view.d.ts +9 -0
- package/dist/operator-ui/view.js +12 -0
- package/dist/program-writes.js +4 -49
- package/dist/provider.d.ts +6 -5
- package/dist/provider.js +3 -4
- package/dist/providers/_shared/google/workspace.js +1 -1
- package/dist/providers/_shared/rest/dispatch.js +41 -0
- package/dist/providers/_shared/rest/operation-index.d.ts +133 -0
- package/dist/providers/_shared/rest/operation-index.js +527 -0
- package/dist/providers/_shared/rest/tools.d.ts +141 -0
- package/dist/providers/_shared/rest/tools.js +569 -0
- package/dist/providers/_shared/rest/value-safety.d.ts +151 -0
- package/dist/providers/_shared/rest/value-safety.js +580 -0
- package/dist/providers/breeze/skill.generated.js +2 -2
- package/dist/providers/cloudflare/graphql.js +385 -0
- package/dist/providers/cloudflare/index.d.ts +47 -51
- package/dist/providers/cloudflare/index.js +188 -1997
- package/dist/providers/cloudflare/openapi.generated.js +3347 -0
- package/dist/providers/cloudflare/rest.d.ts +37 -0
- package/dist/providers/cloudflare/rest.js +1056 -0
- package/dist/providers/cloudflare/skill.generated.js +7 -4
- package/dist/providers/cloudflare/value-safety.js +1247 -0
- package/dist/providers/docs/index.d.ts +1 -1
- package/dist/providers/docs/index.js +2 -2
- package/dist/providers/drive/index.d.ts +1 -1
- package/dist/providers/drive/index.js +1 -1
- package/dist/providers/forms/index.d.ts +1 -1
- package/dist/providers/forms/index.js +2 -2
- package/dist/providers/github/skill.generated.js +2 -2
- package/dist/providers/gmail/index.d.ts +1 -1
- package/dist/providers/gmail/index.js +274 -23
- package/dist/providers/gmail/skill.generated.js +2 -2
- package/dist/providers/linear/index.js +1 -1
- package/dist/providers/mixpanel/index.d.ts +27 -12
- package/dist/providers/mixpanel/index.js +58 -6
- package/dist/providers/mixpanel/operations.js +20 -0
- package/dist/providers/mixpanel/rest.js +603 -0
- package/dist/providers/mixpanel/skill.generated.js +3 -2
- package/dist/providers/mixpanel/value-safety.js +16 -0
- package/dist/providers/notion/index.d.ts +35 -31
- package/dist/providers/notion/index.js +76 -1499
- package/dist/providers/notion/openapi.generated.js +75 -0
- package/dist/providers/notion/rest.d.ts +24 -0
- package/dist/providers/notion/rest.js +1186 -0
- package/dist/providers/notion/skill.generated.js +5 -4
- package/dist/providers/notion/value-safety.js +31 -0
- package/dist/providers/planning-center/index.d.ts +27 -0
- package/dist/providers/planning-center/index.js +286 -24
- package/dist/providers/planning-center/skill.generated.js +24 -4
- package/dist/providers/sheets/index.d.ts +1 -1
- package/dist/providers/sheets/index.js +3 -3
- package/dist/providers/slides/index.d.ts +1 -1
- package/dist/providers/slides/index.js +3 -3
- package/dist/providers/stripe/index.d.ts +26 -20
- package/dist/providers/stripe/index.js +103 -130
- package/dist/providers/stripe/openapi.generated.js +649 -0
- package/dist/providers/stripe/rest.d.ts +14 -0
- package/dist/providers/stripe/rest.js +395 -0
- package/dist/providers/stripe/skill.generated.js +7 -5
- package/dist/providers/stripe/value-safety.js +705 -0
- package/dist/providers/vercel/index.d.ts +31 -22
- package/dist/providers/vercel/index.js +96 -853
- package/dist/providers/vercel/openapi.generated.js +456 -0
- package/dist/providers/vercel/rest.d.ts +20 -0
- package/dist/providers/vercel/rest.js +1002 -0
- package/dist/providers/vercel/skill.generated.js +4 -5
- package/dist/providers/vercel/value-safety.js +328 -0
- package/dist/providers/wispr-flow/index.d.ts +14 -0
- package/dist/providers/wispr-flow/index.js +117 -0
- package/dist/providers/wispr-flow/skill.generated.js +8 -0
- package/dist/routes/mcp.js +30 -10
- package/dist/routes/operator.js +14 -7
- package/dist/routes/ui-config.js +2 -2
- package/dist/server.js +3 -0
- package/dist/skills.js +5 -4
- package/dist/tool-safety.js +13 -5
- package/dist/types.d.ts +1 -1
- package/dist/ui.d.ts +1 -1
- package/dist/ui.js +1 -1
- package/dist/usage-guide.js +3 -3
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/write-outcome.js +47 -0
- package/documentation/README.md +1 -0
- package/documentation/architecture.md +155 -28
- package/documentation/auth.md +86 -27
- package/documentation/code-mode.md +81 -72
- package/documentation/deploying.md +10 -5
- package/documentation/integrating.md +72 -9
- package/documentation/meta-tools.md +52 -38
- package/documentation/operating.md +11 -8
- package/documentation/operator-tests.md +2 -3
- package/documentation/operator-ui.md +9 -3
- package/documentation/provider-auth-migration.md +308 -0
- package/documentation/provider-migration-0.29.md +18 -6
- package/examples/worker/AGENTS.md +5 -0
- package/examples/worker/README.md +2 -2
- package/examples/worker/src/connecta.config.ts +5 -0
- package/package.json +7 -2
- package/templates/node/AGENTS.md +6 -4
- package/templates/node/README.md +6 -4
- package/templates/node/package.json +1 -1
- package/templates/node/src/connecta.config.ts +5 -0
- package/dist/providers/vercel/mcp-ownership.js +0 -212
- package/dist/tool-safety.d.ts +0 -9
|
@@ -1,10 +1,30 @@
|
|
|
1
1
|
// Generated by scripts/generate-providers.mjs; do not edit.
|
|
2
2
|
export const skill = {
|
|
3
|
-
"content": "# Planning Center usage\n\nPlanning Center Online church management — People, Services, Groups, Check-Ins, Calendar, Registrations, Giving, Publishing, Webhooks
|
|
3
|
+
"content": "# Planning Center usage\n\nPlanning Center Online church management — People, Services, Groups, Check-Ins, Calendar, Registrations, Giving, Publishing, Webhooks.\n\n## Identity first\n\n- A person id is the join key across every product: the id `search_people` returns is the `personId` for Services schedules, Groups memberships, Giving donations, and Check-Ins. Resolve ids with list tools; never guess one.\n- A person id that used to resolve and now answers `not_found` was most likely merged. Read `/people/v2/person_mergers` with `where[person_to_remove_id]` and follow `person_to_keep_id`.\n- `get_me` names the user this token acts as. Every read and write runs with that user's permissions, product by product; a `provider_permission_denied` means an administrator must grant that user access to the product or record.\n\n## Results and paging\n\n- Records keep Planning Center's own snake_case attribute names; a relationship appears as `<relationship>_id`. Pass `raw: true` for the untouched JSON:API resources and `included`.\n- Lists page by offset: `perPage` up to 100, then pass `page.nextOffset` back as `offset` while `page.hasMore` is true. `page.totalCount` answers \"how many\" without paging — request `perPage: 1`.\n- A bare date in a date filter is the organization's local day; pass a full timestamp for exact bounds. Name filters are exact; end one with `%` for a prefix match.\n- `get_plan` fetches the plan, its items, and its team in one call and sets `itemsTruncated`/`teamMembersTruncated` past 100 rows; page the rest with `pco_api_get`.\n\n## What each product lets the API write\n\n- People: full read/write. `update_person` with `status: inactive` archives reversibly; a DELETE is permanent and only reachable through `pco_api_mutate`. `run_list` can fire list automations.\n- Services: full read/write. A plan's dates come from its plan times. Scheduling needs a team.\n- Groups: memberships and group settings are writable; groups cannot be created, and events and attendance are read-only.\n- Check-Ins and Registrations: read-only. Nobody can be checked in or registered through the API.\n- Calendar: events, instances, and times are read-only; tags, resources, rooms, and folders are writable through `pco_api_mutate`.\n- Giving: the named tools only read, amounts in integer cents. Creating or editing donations, refunds, and committing a batch move money and go through `pco_api_mutate`.\n- Publishing and the `api` product (organization, OAuth applications, personal access tokens) have no named tools; use the hatches.\n\n## The hatches\n\n- `pco_api_get` reaches any GET; `pco_api_mutate` any POST, PATCH, or DELETE, always approval-gated. Paths start `/<app>/v2`, exactly as Planning Center documents them; the connector owns host, auth, content type, and the `X-PCO-API-Version` header.\n- Bodies are JSON:API documents: `{\"data\":{\"type\":\"Email\",\"attributes\":{...}}}`. `null` clears an attribute; an omitted key is left alone.\n- Each product is pinned to a reviewed API version: people 2026-06-04, services 2018-11-01, groups 2023-07-10, check-ins 2025-05-28, calendar 2026-06-22, registrations 2025-05-01, giving 2019-10-18, publishing 2024-03-25, webhooks 2022-10-20, api 2026-09-24. Pass `version` only for an endpoint those versions lack.\n- Query parameters are name/value pairs with literal brackets: `where[status]`, `include`, `order`, `filter`, `fields[Person]`. Every list response's `meta` names the `can_query_by`, `can_order_by`, and `can_include` values for that endpoint; an unknown `where` key is ignored rather than refused.\n- File uploads go to a separate host (upload.planningcenteronline.com), which this connection does not reach.\n\n## Rate limits\n\nPlanning Center allows 100 requests per 20 seconds per user, shared by every integration running as that user. This connection admits 100 calls per 20 seconds, five at a time, per runtime — an approximation, not a guarantee. A `rate_limited` failure carries Planning Center's wait. Filter server-side and use `totalCount` rather than paging to count.\n",
|
|
4
4
|
"instructionsHeading": "Organization instructions",
|
|
5
5
|
"fragments": {
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
6
|
+
"heading": "# Planning Center usage\n\nPlanning Center Online church management — ",
|
|
7
|
+
"purpose": " — for: ",
|
|
8
|
+
"identity": "\n\n## Identity first\n\n- A person id is the join key across every product: the id `search_people` returns is the `personId` for ",
|
|
9
|
+
"conventions": ". Resolve ids with list tools; never guess one.\n- A person id that used to resolve and now answers `not_found` was most likely merged. Read `/people/v2/person_mergers` with `where[person_to_remove_id]` and follow `person_to_keep_id`.\n- `get_me` names the user this token acts as. Every read and write runs with that user's permissions, product by product; a `provider_permission_denied` means an administrator must grant that user access to the product or record.\n\n## Results and paging\n\n- Records keep Planning Center's own snake_case attribute names; a relationship appears as `<relationship>_id`. Pass `raw: true` for the untouched JSON:API resources and `included`.\n- Lists page by offset: `perPage` up to 100, then pass `page.nextOffset` back as `offset` while `page.hasMore` is true. `page.totalCount` answers \"how many\" without paging — request `perPage: 1`.\n- A bare date in a date filter is the organization's local day; pass a full timestamp for exact bounds. Name filters are exact; end one with `%` for a prefix match.\n",
|
|
10
|
+
"plans": "- `get_plan` fetches the plan, its items, and its team in one call and sets `itemsTruncated`/`teamMembersTruncated` past 100 rows; page the rest with `pco_api_get`.\n",
|
|
11
|
+
"writes": "\n## What each product lets the API write\n\n",
|
|
12
|
+
"people": "- People: full read/write. `update_person` with `status: inactive` archives reversibly; a DELETE is permanent and only reachable through `pco_api_mutate`. `run_list` can fire list automations.\n",
|
|
13
|
+
"people_without_lists": "- People: full read/write, except lists. `update_person` with `status: inactive` archives reversibly; a DELETE is permanent and only reachable through `pco_api_mutate`.\n",
|
|
14
|
+
"services": "- Services: full read/write. A plan's dates come from its plan times. Scheduling needs a team.\n",
|
|
15
|
+
"groups": "- Groups: memberships and group settings are writable; groups cannot be created, and events and attendance are read-only.\n",
|
|
16
|
+
"check_ins_registrations": "- Check-Ins and Registrations: read-only. Nobody can be checked in or registered through the API.\n",
|
|
17
|
+
"check_ins": "- Check-Ins: read-only. Nobody can be checked in through the API.\n",
|
|
18
|
+
"registrations": "- Registrations: read-only. Nobody can be registered through the API.\n",
|
|
19
|
+
"calendar": "- Calendar: events, instances, and times are read-only; tags, resources, rooms, and folders are writable through `pco_api_mutate`.\n",
|
|
20
|
+
"giving": "- Giving: the named tools only read, amounts in integer cents. Creating or editing donations, refunds, and committing a batch move money and go through `pco_api_mutate`.\n",
|
|
21
|
+
"publishing_api": "- Publishing and the `api` product (organization, OAuth applications, personal access tokens) have no named tools; use the hatches.\n",
|
|
22
|
+
"publishing": "- Publishing has no named tools; use the hatches.\n",
|
|
23
|
+
"api": "- The `api` product (organization, OAuth applications, personal access tokens) has no named tools; use the hatches.\n",
|
|
24
|
+
"hatches": "\n## The hatches\n\n- `pco_api_get` reaches any GET; `pco_api_mutate` any POST, PATCH, or DELETE, always approval-gated. Paths start `/<app>/v2`, exactly as Planning Center documents them; the connector owns host, auth, content type, and the `X-PCO-API-Version` header.\n- Bodies are JSON:API documents: `{\"data\":{\"type\":\"Email\",\"attributes\":{...}}}`. `null` clears an attribute; an omitted key is left alone.\n- Each product is pinned to a reviewed API version: ",
|
|
25
|
+
"pins": ". Pass `version` only for an endpoint those versions lack.\n- Query parameters are name/value pairs with literal brackets: `where[status]`, `include`, `order`, `filter`, `fields[Person]`. Every list response's `meta` names the `can_query_by`, `can_order_by`, and `can_include` values for that endpoint; an unknown `where` key is ignored rather than refused.\n- File uploads go to a separate host (upload.planningcenteronline.com), which this connection does not reach.\n",
|
|
26
|
+
"disabled": "- This deployment disables some products, and the hatches refuse their paths before sending. While any product is disabled they also refuse People lists, list results, rules, and conditions, by path or `include`, because a list's conditions can draw on any product; webhook event and delivery payloads; and any change to an existing webhook subscription, whose id does not name its product. A new subscription must name a reachable product's event.\n",
|
|
27
|
+
"limits": "\n## Rate limits\n\nPlanning Center allows 100 requests per 20 seconds per user, shared by every integration running as that user. This connection admits 100 calls per 20 seconds, five at a time, per runtime — an approximation, not a guarantee. A `rate_limited` failure carries Planning Center's wait. Filter server-side and use `totalCount` rather than paging to count.\n",
|
|
28
|
+
"published": "# Planning Center usage\n\nPlanning Center Online church management — People, Services, Groups, Check-Ins, Calendar, Registrations, Giving, Publishing, Webhooks.\n\n## Identity first\n\n- A person id is the join key across every product: the id `search_people` returns is the `personId` for Services schedules, Groups memberships, Giving donations, and Check-Ins. Resolve ids with list tools; never guess one.\n- A person id that used to resolve and now answers `not_found` was most likely merged. Read `/people/v2/person_mergers` with `where[person_to_remove_id]` and follow `person_to_keep_id`.\n- `get_me` names the user this token acts as. Every read and write runs with that user's permissions, product by product; a `provider_permission_denied` means an administrator must grant that user access to the product or record.\n\n## Results and paging\n\n- Records keep Planning Center's own snake_case attribute names; a relationship appears as `<relationship>_id`. Pass `raw: true` for the untouched JSON:API resources and `included`.\n- Lists page by offset: `perPage` up to 100, then pass `page.nextOffset` back as `offset` while `page.hasMore` is true. `page.totalCount` answers \"how many\" without paging — request `perPage: 1`.\n- A bare date in a date filter is the organization's local day; pass a full timestamp for exact bounds. Name filters are exact; end one with `%` for a prefix match.\n- `get_plan` fetches the plan, its items, and its team in one call and sets `itemsTruncated`/`teamMembersTruncated` past 100 rows; page the rest with `pco_api_get`.\n\n## What each product lets the API write\n\n- People: full read/write. `update_person` with `status: inactive` archives reversibly; a DELETE is permanent and only reachable through `pco_api_mutate`. `run_list` can fire list automations.\n- Services: full read/write. A plan's dates come from its plan times. Scheduling needs a team.\n- Groups: memberships and group settings are writable; groups cannot be created, and events and attendance are read-only.\n- Check-Ins and Registrations: read-only. Nobody can be checked in or registered through the API.\n- Calendar: events, instances, and times are read-only; tags, resources, rooms, and folders are writable through `pco_api_mutate`.\n- Giving: the named tools only read, amounts in integer cents. Creating or editing donations, refunds, and committing a batch move money and go through `pco_api_mutate`.\n- Publishing and the `api` product (organization, OAuth applications, personal access tokens) have no named tools; use the hatches.\n\n## The hatches\n\n- `pco_api_get` reaches any GET; `pco_api_mutate` any POST, PATCH, or DELETE, always approval-gated. Paths start `/<app>/v2`, exactly as Planning Center documents them; the connector owns host, auth, content type, and the `X-PCO-API-Version` header.\n- Bodies are JSON:API documents: `{\"data\":{\"type\":\"Email\",\"attributes\":{...}}}`. `null` clears an attribute; an omitted key is left alone.\n- Each product is pinned to a reviewed API version: people 2026-06-04, services 2018-11-01, groups 2023-07-10, check-ins 2025-05-28, calendar 2026-06-22, registrations 2025-05-01, giving 2019-10-18, publishing 2024-03-25, webhooks 2022-10-20, api 2026-09-24. Pass `version` only for an endpoint those versions lack.\n- Query parameters are name/value pairs with literal brackets: `where[status]`, `include`, `order`, `filter`, `fields[Person]`. Every list response's `meta` names the `can_query_by`, `can_order_by`, and `can_include` values for that endpoint; an unknown `where` key is ignored rather than refused.\n- File uploads go to a separate host (upload.planningcenteronline.com), which this connection does not reach.\n\n## Rate limits\n\nPlanning Center allows 100 requests per 20 seconds per user, shared by every integration running as that user. This connection admits 100 calls per 20 seconds, five at a time, per runtime — an approximation, not a guarantee. A `rate_limited` failure carries Planning Center's wait. Filter server-side and use `totalCount` rather than paging to count.\n"
|
|
9
29
|
}
|
|
10
30
|
};
|
|
@@ -48,7 +48,7 @@ export type SheetsOptions = GoogleWorkspaceOptions;
|
|
|
48
48
|
*
|
|
49
49
|
* Reads are read-only. `create_spreadsheet`, `add_sheet`, and `append_values`
|
|
50
50
|
* are additive writes the host approves through call_destructive_tool or a
|
|
51
|
-
*
|
|
51
|
+
* program on a writable endpoint; the value writes, `clear_values`, and the raw
|
|
52
52
|
* `batch_update_spreadsheet` are destructive.
|
|
53
53
|
*/
|
|
54
54
|
export declare const sheets: import("../../provider.js").ProviderFactory<GoogleWorkspaceOptions>;
|
|
@@ -550,8 +550,8 @@ const SPREADSHEET_FIELDS = [
|
|
|
550
550
|
// --- Tools ------------------------------------------------------------------------
|
|
551
551
|
function tools(client) {
|
|
552
552
|
const readOnly = { readOnlyHint: true };
|
|
553
|
-
// Additive: nothing that existed is lost.
|
|
554
|
-
//
|
|
553
|
+
// Additive: nothing that existed is lost. Writes require a writable
|
|
554
|
+
// endpoint: call_destructive_tool or a program. The host controls approval.
|
|
555
555
|
const additive = { readOnlyHint: false, destructiveHint: false };
|
|
556
556
|
const destructive = { readOnlyHint: false, destructiveHint: true };
|
|
557
557
|
const spreadsheetPath = (args) => `/spreadsheets/${encodeURIComponent(String(args["spreadsheetId"]))}`;
|
|
@@ -1188,7 +1188,7 @@ function usageGuide(purpose, instructions) {
|
|
|
1188
1188
|
*
|
|
1189
1189
|
* Reads are read-only. `create_spreadsheet`, `add_sheet`, and `append_values`
|
|
1190
1190
|
* are additive writes the host approves through call_destructive_tool or a
|
|
1191
|
-
*
|
|
1191
|
+
* program on a writable endpoint; the value writes, `clear_values`, and the raw
|
|
1192
1192
|
* `batch_update_spreadsheet` are destructive.
|
|
1193
1193
|
*/
|
|
1194
1194
|
export const sheets = asProviderFactory({
|
|
@@ -45,7 +45,7 @@ export type SlidesOptions = GoogleWorkspaceOptions;
|
|
|
45
45
|
*
|
|
46
46
|
* Reads run in programs. `create_presentation`, `create_slide`,
|
|
47
47
|
* `create_comment`, and `create_comment_reply` are additive writes the host
|
|
48
|
-
* approves through call_destructive_tool or a
|
|
48
|
+
* approves through call_destructive_tool or a program on a writable endpoint;
|
|
49
49
|
* `replace_all_text`, `update_comment_thread`, `update_comment_post`,
|
|
50
50
|
* `delete_comment`, `delete_comment_reply`, and `batch_update_presentation`
|
|
51
51
|
* are destructive.
|
|
@@ -2051,7 +2051,7 @@ function tools(client) {
|
|
|
2051
2051
|
name: "create_presentation",
|
|
2052
2052
|
description: "Create an empty Google Slides deck with one title slide in the user's My Drive root. It cannot place the deck in a folder or copy a template.",
|
|
2053
2053
|
// Additive: a new file changes nothing that existed. Not read-only, so
|
|
2054
|
-
// program calls require a
|
|
2054
|
+
// program calls require a writable endpoint; other writes use
|
|
2055
2055
|
// call_destructive_tool. The host controls approval.
|
|
2056
2056
|
annotations: { readOnlyHint: false, destructiveHint: false },
|
|
2057
2057
|
inputSchema: input({
|
|
@@ -2239,7 +2239,7 @@ function tools(client) {
|
|
|
2239
2239
|
name: "create_comment",
|
|
2240
2240
|
description: "Comment on a slide, a notes page, an element, a range of its text, or a table cell, optionally assigning it. Adds a thread; Slides notifies as in the editor.",
|
|
2241
2241
|
// Additive: a new thread changes nothing that existed. Not read-only,
|
|
2242
|
-
// so program calls require a
|
|
2242
|
+
// so program calls require a writable endpoint; other writes use
|
|
2243
2243
|
// call_destructive_tool. The host controls approval.
|
|
2244
2244
|
annotations: { readOnlyHint: false, destructiveHint: false },
|
|
2245
2245
|
inputSchema: input({
|
|
@@ -2594,7 +2594,7 @@ function usageGuide(purpose, instructions) {
|
|
|
2594
2594
|
*
|
|
2595
2595
|
* Reads run in programs. `create_presentation`, `create_slide`,
|
|
2596
2596
|
* `create_comment`, and `create_comment_reply` are additive writes the host
|
|
2597
|
-
* approves through call_destructive_tool or a
|
|
2597
|
+
* approves through call_destructive_tool or a program on a writable endpoint;
|
|
2598
2598
|
* `replace_all_text`, `update_comment_thread`, `update_comment_post`,
|
|
2599
2599
|
* `delete_comment`, `delete_comment_reply`, and `batch_update_presentation`
|
|
2600
2600
|
* are destructive.
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { type
|
|
2
|
-
|
|
3
|
-
export
|
|
1
|
+
import { type StripeMode } from "./rest.js";
|
|
2
|
+
export type { StripeMode } from "./rest.js";
|
|
3
|
+
export { STRIPE_API_BASE_URL } from "./rest.js";
|
|
4
4
|
/** Stripe publishes one hosted MCP endpoint for every account and mode. */
|
|
5
5
|
export declare const STRIPE_MCP_ENDPOINT = "https://mcp.stripe.com/";
|
|
6
6
|
interface StripeCommonOptions {
|
|
7
|
-
/** Human-readable display name; defaults to "Stripe" for OAuth. */
|
|
7
|
+
/** Human-readable display name; defaults to "Stripe" for OAuth and the mode for a key. */
|
|
8
8
|
title?: string;
|
|
9
9
|
/** Downstream auth ownership. Defaults to one shared deployment grant. */
|
|
10
10
|
authScope?: "shared" | "personal";
|
|
@@ -15,33 +15,39 @@ interface StripeCommonOptions {
|
|
|
15
15
|
/** Connector-specific inline result limit; omit to inherit the deployment. */
|
|
16
16
|
maxResultBytes?: number;
|
|
17
17
|
}
|
|
18
|
-
/**
|
|
18
|
+
/**
|
|
19
|
+
* Stripe's hosted MCP server over OAuth. One session can reach live and
|
|
20
|
+
* sandbox accounts; Stripe returns the mode with each account.
|
|
21
|
+
*/
|
|
19
22
|
export interface StripeOAuthOptions extends StripeCommonOptions {
|
|
20
|
-
auth
|
|
23
|
+
auth: {
|
|
21
24
|
type: "oauth";
|
|
22
25
|
};
|
|
26
|
+
/** Refused: OAuth reaches live and sandbox accounts, and Stripe returns mode with each. */
|
|
23
27
|
mode?: never;
|
|
28
|
+
/** Refused: a Connect account needs an API-key connector. */
|
|
24
29
|
connectedAccount?: never;
|
|
25
30
|
}
|
|
26
31
|
/**
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* Neither can discover its own mode, since a restricted key answers for
|
|
32
|
-
* exactly one, so both declare it.
|
|
32
|
+
* Connecta's REST connector to `api.stripe.com` with one operator-managed
|
|
33
|
+
* secret or restricted key, pasted into the connection in the operator UI.
|
|
34
|
+
* A key reaches exactly one mode, so the connector declares it, and a key
|
|
35
|
+
* whose prefix says otherwise is refused before any request leaves.
|
|
33
36
|
*/
|
|
34
|
-
export interface
|
|
35
|
-
auth:
|
|
36
|
-
type: "
|
|
37
|
-
}
|
|
37
|
+
export interface StripeApiKeyOptions extends StripeCommonOptions {
|
|
38
|
+
auth: {
|
|
39
|
+
type: "apiKey";
|
|
40
|
+
};
|
|
38
41
|
mode: StripeMode;
|
|
39
|
-
/** Act as one Connect account
|
|
42
|
+
/** Act as one Connect account: `Stripe-Account` on v1, `Stripe-Context` on v2. */
|
|
40
43
|
connectedAccount?: string;
|
|
41
44
|
}
|
|
42
|
-
export type StripeOptions = StripeOAuthOptions |
|
|
43
|
-
/**
|
|
45
|
+
export type StripeOptions = StripeOAuthOptions | StripeApiKeyOptions;
|
|
46
|
+
/**
|
|
47
|
+
* A maintained Stripe connection. `auth` selects the implementation: OAuth
|
|
48
|
+
* reaches Stripe's hosted MCP server; an API key reaches Connecta's REST
|
|
49
|
+
* connector to `api.stripe.com`.
|
|
50
|
+
*/
|
|
44
51
|
export declare const stripe: import("../../provider.js").ProviderFactory<StripeOptions>;
|
|
45
52
|
/** @deprecated Read `stripe.definition.classify` instead. Kept for existing imports. */
|
|
46
53
|
export declare const STRIPE_VETTED_CATALOG: import("../../catalog-drift.js").VettedCatalog;
|
|
47
|
-
export {};
|
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
import { skill } from "./skill.generated.js";
|
|
2
|
-
import {
|
|
2
|
+
import { apiConnector } from "../../connectors/api-connector.js";
|
|
3
3
|
import { reviewedCatalog } from "../../catalog-drift.js";
|
|
4
|
-
import { keys, optionsOf,
|
|
5
|
-
import { CREDENTIAL } from "../../connectors/option-shapes.js";
|
|
4
|
+
import { keys, optionsOf, variants } from "../../config-schema.js";
|
|
6
5
|
import { defineProvider } from "../../provider.js";
|
|
6
|
+
import { byAuth, hostedOAuth } from "../_shared/rest/dispatch.js";
|
|
7
|
+
import { restTools } from "../_shared/rest/tools.js";
|
|
8
|
+
import { stripeRest } from "./rest.js";
|
|
9
|
+
export { STRIPE_API_BASE_URL } from "./rest.js";
|
|
7
10
|
/** Stripe publishes one hosted MCP endpoint for every account and mode. */
|
|
8
11
|
export const STRIPE_MCP_ENDPOINT = "https://mcp.stripe.com/";
|
|
9
12
|
/**
|
|
10
13
|
* Stripe documents no MCP-specific limit, so these transcribe the account limit
|
|
11
|
-
*
|
|
12
|
-
* the sandbox rule
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
14
|
+
* every request spends: 100 requests per second live, 25 in a sandbox. OAuth
|
|
15
|
+
* takes the sandbox rule because one session can reach either mode and the
|
|
16
|
+
* policy is fixed before the account-scoped call begins. The `maxConcurrency`
|
|
17
|
+
* figures are Connecta's own choice — Stripe says per-account and per-endpoint
|
|
18
|
+
* concurrency limits exist but publishes no number.
|
|
16
19
|
*/
|
|
17
20
|
const STRIPE_ADMISSION = {
|
|
18
21
|
production: {
|
|
@@ -40,7 +43,9 @@ const STRIPE_ADMISSION = {
|
|
|
40
43
|
* Reviewed in #705's provider audit against https://docs.stripe.com/mcp.
|
|
41
44
|
* Retains the release-reviewed inventory, including names absent from today's
|
|
42
45
|
* public reference. Live annotations were not reverified without credentials.
|
|
43
|
-
* No schema digest is asserted without a captured schema to review.
|
|
46
|
+
* No schema digest is asserted without a captured schema to review. This
|
|
47
|
+
* classifies the hosted OAuth catalog only; the REST connector annotates each
|
|
48
|
+
* tool it authors.
|
|
44
49
|
*/
|
|
45
50
|
const STRIPE_CLASSIFICATION = {
|
|
46
51
|
tools: {
|
|
@@ -109,158 +114,126 @@ const STRIPE_CLASSIFICATION = {
|
|
|
109
114
|
},
|
|
110
115
|
},
|
|
111
116
|
};
|
|
112
|
-
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Refuse a recognizable key/mode mismatch. This is the only mode guard Connecta
|
|
117
|
-
* can offer, and it needs the key as a literal header to read the prefix: an
|
|
118
|
-
* operator-managed key is not in the deployment file, so its declared mode
|
|
119
|
-
* stands alone and a key pointed at the other environment fails at Stripe.
|
|
120
|
-
*/
|
|
121
|
-
function assertModeMatchesKey(id, mode, auth) {
|
|
122
|
-
if (auth.type !== "headers")
|
|
123
|
-
return;
|
|
124
|
-
for (const value of Object.values(auth.headers)) {
|
|
125
|
-
const keyMode = LIVE_KEY.test(value) ? "production" : TEST_KEY.test(value) ? "sandbox" : undefined;
|
|
126
|
-
if (keyMode !== undefined && keyMode !== mode) {
|
|
127
|
-
throw new Error(`stripe("${id}") declares mode "${mode}" but its auth headers carry a ` +
|
|
128
|
-
`${keyMode === "production" ? "live" : "test"}-mode Stripe key.`);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
function resolveAuth(id, options) {
|
|
133
|
-
const auth = withCredentialDefaults(options.auth ?? { type: "oauth" }, {
|
|
134
|
-
credential: {
|
|
135
|
-
label: "Secret or restricted API key",
|
|
136
|
-
description: "A Stripe secret or restricted API key for this connector's declared mode. Stripe sends it as a bearer token; it is stored encrypted and never displayed.",
|
|
137
|
-
placeholder: "sk_… or rk_…",
|
|
138
|
-
},
|
|
139
|
-
});
|
|
140
|
-
const connectedAccount = options.connectedAccount?.trim();
|
|
141
|
-
if (connectedAccount === undefined || connectedAccount === "")
|
|
142
|
-
return auth;
|
|
143
|
-
if (!connectedAccount.startsWith("acct_")) {
|
|
144
|
-
throw new Error(`stripe("${id}") connectedAccount must be a Stripe account id ("acct_...").`);
|
|
145
|
-
}
|
|
146
|
-
if (auth.type === "oauth") {
|
|
147
|
-
throw new Error(`stripe("${id}") cannot reach a connected account over OAuth; Stripe ` +
|
|
148
|
-
`requires a restricted API key for Stripe-Account calls.`);
|
|
149
|
-
}
|
|
150
|
-
if (auth.type === "credential" || auth.type === "request") {
|
|
151
|
-
// `Stripe-Account` is a second header beside the credential's own, and the
|
|
152
|
-
// credential shape assembles exactly one. A Connect connector therefore
|
|
153
|
-
// still takes its restricted key as a literal header.
|
|
154
|
-
throw new Error(`stripe("${id}") cannot reach a connected account with an ` +
|
|
155
|
-
`operator-managed credential; Stripe-Account is a second static ` +
|
|
156
|
-
`header, so declare auth: { type: "headers" } for this connector.`);
|
|
157
|
-
}
|
|
158
|
-
return {
|
|
159
|
-
type: "headers",
|
|
160
|
-
headers: { ...auth.headers, "Stripe-Account": connectedAccount },
|
|
161
|
-
};
|
|
117
|
+
function instructionsSection(instructions) {
|
|
118
|
+
const text = instructions?.trim();
|
|
119
|
+
return text ? `\n## ${skill.instructionsHeading}\n\n${text}\n` : "";
|
|
162
120
|
}
|
|
163
121
|
function oauthUsageGuide(purpose, instructions) {
|
|
164
|
-
const
|
|
122
|
+
const { oauth, shared, oauth_limits } = skill.fragments;
|
|
165
123
|
return `# Stripe usage
|
|
166
124
|
|
|
167
|
-
Scope: live and sandbox accounts. Connector purpose: ${purpose}${
|
|
168
|
-
${
|
|
125
|
+
Scope: live and sandbox accounts. Connector purpose: ${purpose}${oauth}${shared}${oauth_limits}
|
|
126
|
+
${instructionsSection(instructions)}`;
|
|
169
127
|
}
|
|
170
128
|
const MODE_COPY = {
|
|
171
129
|
production: {
|
|
172
130
|
title: "Stripe (production)",
|
|
173
131
|
blurb: "production — live money and real customers",
|
|
174
132
|
warning: "This is a PRODUCTION Stripe connection. Every write moves real money against real customers, and a refund cannot be undone. If a request could plausibly be a rehearsal, route it to a sandbox connector instead.",
|
|
133
|
+
rate: "100 requests per second",
|
|
175
134
|
},
|
|
176
135
|
sandbox: {
|
|
177
136
|
title: "Stripe (sandbox)",
|
|
178
137
|
blurb: "sandbox — test data, no real money",
|
|
179
138
|
warning: "This is a SANDBOX Stripe connection. Nothing here is real money and none of these objects exist in production, so never answer a question about live revenue, payouts, or a named customer from this connector.",
|
|
139
|
+
rate: "25 requests per second",
|
|
180
140
|
},
|
|
181
141
|
};
|
|
182
|
-
function
|
|
142
|
+
function keyUsageGuide(mode, purpose, connectedAccount, instructions) {
|
|
183
143
|
const copy = MODE_COPY[mode];
|
|
184
|
-
const
|
|
144
|
+
const { key, shared, key_limits, key_tail } = skill.fragments;
|
|
145
|
+
const connect = connectedAccount
|
|
146
|
+
? `\n\nConnected account: \`${connectedAccount}\`. Every call acts as this Connect account; the platform account's own objects are out of reach here.`
|
|
147
|
+
: "";
|
|
185
148
|
return `# Stripe usage
|
|
186
149
|
|
|
187
150
|
Mode: ${mode}. Connector purpose: ${purpose}
|
|
188
151
|
|
|
189
|
-
${copy.warning}${
|
|
190
|
-
${
|
|
191
|
-
}
|
|
192
|
-
function sharedUsageGuide(rate) {
|
|
193
|
-
return `${skill.fragments.guide_2}${rate}${skill.fragments.guide_3}`;
|
|
152
|
+
${copy.warning}${connect}${key}${shared}${key_limits}${copy.rate}${key_tail}
|
|
153
|
+
${instructionsSection(instructions)}`;
|
|
194
154
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
155
|
+
const COMMON = keys("title", "authScope", "purpose", "instructions", "maxResultBytes");
|
|
156
|
+
/** The closed options stripe() accepts, selected by `auth.type`; see `assertKnownOptions`. */
|
|
157
|
+
const STRIPE_OPTIONS = variants(["auth", "type"], {
|
|
158
|
+
// The never-typed keys stay out of the shape, so the walk refuses them by name.
|
|
159
|
+
oauth: optionsOf()({
|
|
160
|
+
...COMMON,
|
|
161
|
+
auth: optionsOf()(keys("type")),
|
|
162
|
+
}).shape,
|
|
163
|
+
apiKey: optionsOf()({
|
|
164
|
+
...COMMON,
|
|
165
|
+
...keys("mode", "connectedAccount"),
|
|
166
|
+
auth: optionsOf()(keys("type")),
|
|
167
|
+
}).shape,
|
|
206
168
|
});
|
|
207
|
-
|
|
169
|
+
function stripeOAuth(id, options, provider) {
|
|
170
|
+
return hostedOAuth(id, provider, {
|
|
171
|
+
url: STRIPE_MCP_ENDPOINT,
|
|
172
|
+
title: options.title ?? "Stripe",
|
|
173
|
+
description: `Stripe payments (live and sandbox accounts) — ${options.purpose}`,
|
|
174
|
+
callAdmission: STRIPE_ADMISSION.sandbox,
|
|
175
|
+
usageGuide: {
|
|
176
|
+
content: oauthUsageGuide(options.purpose, options.instructions),
|
|
177
|
+
// Explicit rather than derived: OAuth must lead with its account-scoped selector pair.
|
|
178
|
+
summary: "Live and sandbox Stripe accounts. List accounts; carry the returned stripe_context and livemode before acting.",
|
|
179
|
+
},
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
function stripeApiKey(id, options, provider) {
|
|
183
|
+
const mode = options.mode;
|
|
184
|
+
if (mode !== "production" && mode !== "sandbox") {
|
|
185
|
+
throw new Error(`stripe("${id}") requires mode "production" or "sandbox" with apiKey auth.`);
|
|
186
|
+
}
|
|
187
|
+
let connectedAccount;
|
|
188
|
+
if (options.connectedAccount !== undefined) {
|
|
189
|
+
connectedAccount = typeof options.connectedAccount === "string" ? options.connectedAccount.trim() : "";
|
|
190
|
+
if (!/^acct_[A-Za-z0-9]+$/.test(connectedAccount)) {
|
|
191
|
+
throw new Error(`stripe("${id}") connectedAccount must be a Stripe account id ("acct_...").`);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
const copy = MODE_COPY[mode];
|
|
195
|
+
const live = mode === "production" ? "live" : "test";
|
|
196
|
+
const rest = stripeRest(mode, connectedAccount);
|
|
197
|
+
return apiConnector(id, {
|
|
198
|
+
...provider.connectorOptions,
|
|
199
|
+
title: options.title ?? copy.title,
|
|
200
|
+
description: `Stripe payments (${copy.blurb}) — ${options.purpose}`,
|
|
201
|
+
credential: {
|
|
202
|
+
label: `Stripe ${live}-mode secret or restricted key`,
|
|
203
|
+
description: `A ${live}-mode secret (sk_${live}_…) or restricted (rk_${live}_…) key; prefer a restricted key with only the permissions this connector needs. It is sent only to api.stripe.com and files.stripe.com, stored encrypted, and never displayed.`,
|
|
204
|
+
placeholder: `rk_${live}_…`,
|
|
205
|
+
},
|
|
206
|
+
testCredential: rest.testCredential,
|
|
207
|
+
callAdmission: STRIPE_ADMISSION[mode],
|
|
208
|
+
usageGuide: {
|
|
209
|
+
content: keyUsageGuide(mode, options.purpose, connectedAccount, options.instructions),
|
|
210
|
+
// Explicit rather than derived: a key connector must lead with its one mode.
|
|
211
|
+
summary: mode === "production"
|
|
212
|
+
? "PRODUCTION: real money. One live-mode key over REST; search operations, read details, then read or write."
|
|
213
|
+
: "Sandbox: test data only. One test-mode key over REST; search operations, read details, then read or write.",
|
|
214
|
+
},
|
|
215
|
+
tools: [...restTools(rest.vendor), ...rest.tools],
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* A maintained Stripe connection. `auth` selects the implementation: OAuth
|
|
220
|
+
* reaches Stripe's hosted MCP server; an API key reaches Connecta's REST
|
|
221
|
+
* connector to `api.stripe.com`.
|
|
222
|
+
*/
|
|
208
223
|
export const stripe = defineProvider({
|
|
209
224
|
name: "stripe",
|
|
210
225
|
title: "Stripe",
|
|
211
|
-
kind: "
|
|
226
|
+
kind: "dual",
|
|
212
227
|
readme: "Stripe",
|
|
213
|
-
bundle: {
|
|
228
|
+
bundle: {
|
|
229
|
+
"baselineGzip": 232089,
|
|
230
|
+
"maxGzip": 292089,
|
|
231
|
+
"note": "./providers/stripe remeasures at 232,089 B gzip (#801), from 170,771 B on main: auth now selects the implementation, so the entry carries the hosted MCP client and Connecta's REST connector (api(), the schema validator, guarded transport, the shared REST module) plus the pinned Stripe operation index (638 operations; request details to depth 2, without descriptions or enums over 50 values; 37,918 B gzip as source). Details were shrunk before the cap moved: the first full index measured 81 KB gzip. The cap uses the existing baseline + 60,000 B policy.",
|
|
232
|
+
},
|
|
214
233
|
skill,
|
|
215
234
|
options: STRIPE_OPTIONS,
|
|
216
235
|
classify: STRIPE_CLASSIFICATION,
|
|
217
|
-
create:
|
|
236
|
+
create: byAuth({ oauth: stripeOAuth, apiKey: stripeApiKey }),
|
|
218
237
|
});
|
|
219
|
-
function stripeConnector(id, options, provider) {
|
|
220
|
-
const purpose = options.purpose.trim();
|
|
221
|
-
const auth = resolveAuth(id, options);
|
|
222
|
-
const mode = "mode" in options ? options.mode : undefined;
|
|
223
|
-
if (auth.type === "oauth" && mode !== undefined) {
|
|
224
|
-
throw new Error(`stripe("${id}") cannot declare a connector-wide mode for OAuth; Stripe returns mode with each account.`);
|
|
225
|
-
}
|
|
226
|
-
if (auth.type !== "oauth" && mode !== "production" && mode !== "sandbox") {
|
|
227
|
-
throw new Error(`stripe("${id}") with headers or credential auth requires mode ` + `"production" or "sandbox".`);
|
|
228
|
-
}
|
|
229
|
-
// Only a literal header can be inspected. An operator-managed credential is
|
|
230
|
-
// not readable at construction — there is nothing in the deployment file to
|
|
231
|
-
// read — so the declared mode stands alone, and a key pointed at the other
|
|
232
|
-
// one is Stripe's own refusal to report.
|
|
233
|
-
if (auth.type === "headers") {
|
|
234
|
-
assertModeMatchesKey(id, mode, auth);
|
|
235
|
-
}
|
|
236
|
-
const copy = mode === undefined ? undefined : MODE_COPY[mode];
|
|
237
|
-
const connector = remoteMcp(id, {
|
|
238
|
-
url: STRIPE_MCP_ENDPOINT,
|
|
239
|
-
...provider.connectorOptions,
|
|
240
|
-
title: options.title ?? copy?.title ?? "Stripe",
|
|
241
|
-
description: mode === undefined
|
|
242
|
-
? `Stripe payments (live and sandbox accounts) — ${purpose}`
|
|
243
|
-
: `Stripe payments (${copy?.blurb}) — ${purpose}`,
|
|
244
|
-
auth,
|
|
245
|
-
requireHttps: true,
|
|
246
|
-
classify: provider.classify,
|
|
247
|
-
callAdmission: STRIPE_ADMISSION[mode ?? "sandbox"],
|
|
248
|
-
usageGuide: {
|
|
249
|
-
content: mode === undefined
|
|
250
|
-
? oauthUsageGuide(purpose, options.instructions)
|
|
251
|
-
: fixedModeUsageGuide(mode, purpose, options.instructions),
|
|
252
|
-
// Explicit rather than derived: fixed credentials must lead with mode,
|
|
253
|
-
// while OAuth must lead with its account-scoped selector pair.
|
|
254
|
-
summary: mode === undefined
|
|
255
|
-
? "Live and sandbox Stripe accounts. List accounts; carry the returned stripe_context and livemode before acting."
|
|
256
|
-
: mode === "production"
|
|
257
|
-
? "PRODUCTION: real money. This static credential has one fixed live-mode scope."
|
|
258
|
-
: "Sandbox: test data only. This static credential has one fixed sandbox scope.",
|
|
259
|
-
// Not `required`. The four generic tools are the routing decision; a
|
|
260
|
-
// guide forced into every call would pay for the same prose repeatedly.
|
|
261
|
-
},
|
|
262
|
-
});
|
|
263
|
-
return connector;
|
|
264
|
-
}
|
|
265
238
|
/** @deprecated Read `stripe.definition.classify` instead. Kept for existing imports. */
|
|
266
239
|
export const STRIPE_VETTED_CATALOG = reviewedCatalog(stripe.definition.classify, 'defineProvider("stripe")');
|