@zackbart/connecta 0.21.0 → 0.21.2
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 +74 -0
- package/dist/auth/downstream-oauth.d.ts +65 -2
- package/dist/auth/downstream-oauth.js +408 -20
- package/dist/connectors/remote-mcp.js +8 -4
- package/dist/executors/quickjs.js +4 -0
- package/dist/providers/cloudflare.js +233 -61
- package/dist/providers/linear.js +7 -0
- package/dist/providers/mixpanel.js +6 -4
- package/dist/providers/revenuecat.js +2 -1
- package/dist/providers/stripe.js +7 -6
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/documentation/architecture.md +17 -0
- package/documentation/auth.md +1 -1
- package/documentation/cloudflare.md +19 -1
- package/documentation/code-mode.md +2 -2
- package/documentation/linear.md +6 -4
- package/documentation/mixpanel.md +5 -3
- package/documentation/operations.md +7 -7
- package/documentation/provider-conventions.md +4 -2
- package/documentation/revenuecat.md +21 -21
- package/documentation/storage-and-credentials.md +35 -0
- package/documentation/stripe.md +14 -13
- package/documentation/upgrading.md +8 -7
- package/package.json +1 -1
- package/templates/node/package.json +1 -1
|
@@ -41,6 +41,7 @@ const READ_ONLY_TOOLS = new Set([
|
|
|
41
41
|
// Customers and subscriptions
|
|
42
42
|
"get-customer",
|
|
43
43
|
"get-customer-center-config",
|
|
44
|
+
"get-refund-request-preferences",
|
|
44
45
|
"get-subscription",
|
|
45
46
|
"list-customer-events",
|
|
46
47
|
"list-customers",
|
|
@@ -157,7 +158,7 @@ function sharedUsageGuide() {
|
|
|
157
158
|
- \`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.
|
|
158
159
|
- \`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.
|
|
159
160
|
- 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.
|
|
160
|
-
- \`render-paywall-screenshot\` is unclassified on purpose
|
|
161
|
+
- \`render-paywall-screenshot\` is unclassified on purpose because RevenueCat's reference gives it no access column. The current server marks it read-only, which Connecta preserves; without that annotation it fails closed onto \`call_destructive_tool\`.
|
|
161
162
|
- 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.
|
|
162
163
|
- 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.
|
|
163
164
|
- 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.
|
package/dist/providers/stripe.js
CHANGED
|
@@ -37,16 +37,16 @@ const READ_ONLY_TOOLS = new Set([
|
|
|
37
37
|
"stripe_api_search",
|
|
38
38
|
"stripe_api_details",
|
|
39
39
|
"stripe_api_read",
|
|
40
|
-
"get_stripe_account_info",
|
|
41
40
|
"get_balance_summary",
|
|
41
|
+
"list_available_accounts_or_orgs",
|
|
42
|
+
"manage_stripe_accounts",
|
|
42
43
|
"search_stripe_documentation",
|
|
43
|
-
"stripe_implementation_planner",
|
|
44
44
|
]);
|
|
45
|
-
/** Reviewed writes, including
|
|
45
|
+
/** Reviewed writes, including mixed read/create tools: `documentation/stripe.md`. */
|
|
46
46
|
const WRITE_TOOLS = new Map([
|
|
47
47
|
["stripe_api_write", "destructive"],
|
|
48
|
-
["
|
|
49
|
-
["
|
|
48
|
+
["stripe_implementation_planner", "additive"],
|
|
49
|
+
["stripe_analytics", "additive"],
|
|
50
50
|
["send_stripe_mcp_feedback", "additive"],
|
|
51
51
|
]);
|
|
52
52
|
/** Release-reviewed manifest; see provider conventions P5 and P13. */
|
|
@@ -149,7 +149,8 @@ ${accountInstructions
|
|
|
149
149
|
function sharedUsageGuide(rate) {
|
|
150
150
|
return `
|
|
151
151
|
- 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.
|
|
152
|
-
- Prefer a dedicated tool when one covers the task: \`
|
|
152
|
+
- 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.
|
|
153
|
+
- \`stripe_implementation_planner\` and the query-execution intents of \`stripe_analytics\` create provider-side planning or query-run state. Connecta therefore routes both through \`call_destructive_tool\` as non-destructive writes; their retrieval paths stay behind the same tool boundary.
|
|
153
154
|
- \`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; expect approval on every call.
|
|
154
155
|
- 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\`.
|
|
155
156
|
- 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.
|
package/dist/version.d.ts
CHANGED
package/dist/version.js
CHANGED
|
@@ -20,6 +20,23 @@ isolate or process —
|
|
|
20
20
|
on Workers that means a lazy module-scope singleton, which is why both
|
|
21
21
|
deployment shapes build it outside the request handler.
|
|
22
22
|
|
|
23
|
+
An OAuth `remoteMcp()` connector also owns a runtime-local refresh completion
|
|
24
|
+
gate. It coordinates credential mutation across concurrent request scopes but
|
|
25
|
+
never shares their clients, transports, or responses, and never lets a follower
|
|
26
|
+
cancel the owner. Every participant still awaits the refresh inside its own
|
|
27
|
+
request lifetime; a cancelled follower leaves the shared owner untouched and
|
|
28
|
+
removes only its own wait. The owner's request signal belongs to its token
|
|
29
|
+
fetch. Cancelling that owner fails current joiners too because promoting one
|
|
30
|
+
could replay a refresh token the authorization server already consumed.
|
|
31
|
+
|
|
32
|
+
The coordinator retains the owner's abort signal only through one temporary
|
|
33
|
+
listener on the exact active refresh. Save, failure, cancellation, or
|
|
34
|
+
generation retirement removes it along with the map entry. It never retains a
|
|
35
|
+
token response, client, or transport. If cancellation lands after a valid
|
|
36
|
+
response while its credential write is still running, a generation-keyed
|
|
37
|
+
identity marker rejects new owners until that exact write finishes. The marker
|
|
38
|
+
contains no promise and generation retirement removes it.
|
|
39
|
+
|
|
23
40
|
**Per request, and no longer.** The MCP server, its transport, downstream MCP
|
|
24
41
|
clients, abort signals, and the connector scope a probe opens all belong to the
|
|
25
42
|
request that created them. `Nothing request-bound survives a request` is an
|
package/documentation/auth.md
CHANGED
|
@@ -65,7 +65,7 @@ Worker-level Access runs before every connecta route. Consequently:
|
|
|
65
65
|
OAuth discovery paths when Managed OAuth is enabled.
|
|
66
66
|
|
|
67
67
|
The [Worker example](../examples/worker/) carries the complete deployment shape
|
|
68
|
-
and the [upgrade guide](./upgrading.md#0200--
|
|
68
|
+
and the [upgrade guide](./upgrading.md#0200--0212) gives the reversible Clerk
|
|
69
69
|
migration.
|
|
70
70
|
|
|
71
71
|
## Clerk configuration is checked at construction
|
|
@@ -153,6 +153,18 @@ every constrained field, endpoint-specific pagination bounds, and a description
|
|
|
153
153
|
on every property. `test/cloudflare-provider.test.ts` walks the surface and
|
|
154
154
|
asserts those properties rather than leaving them as a claim.
|
|
155
155
|
|
|
156
|
+
The per-setting zone tools accept Cloudflare's current non-empty setting ids,
|
|
157
|
+
including `webmcp_enabled` and `webmcp_packs`. Cloudflare's
|
|
158
|
+
[rendered setting reference](https://developers.cloudflare.com/api/resources/zones/subresources/settings/)
|
|
159
|
+
and current OpenAPI now agree on both beta ids. Results preserve the value and
|
|
160
|
+
the actual `editable` flag Cloudflare returned; Connecta does not apply the
|
|
161
|
+
document's defaults locally.
|
|
162
|
+
|
|
163
|
+
KV namespace jurisdiction is creation-only. `create_kv_namespace` accepts
|
|
164
|
+
`eu`, `fedramp`, or `us`, and namespace reads preserve the returned value.
|
|
165
|
+
R2 uses a different enum: `default`, `eu`, `us`, or `fedramp`, sent through
|
|
166
|
+
`cf-r2-jurisdiction` by all eight named R2 operations.
|
|
167
|
+
|
|
156
168
|
### What the named surface deliberately leaves out
|
|
157
169
|
|
|
158
170
|
A named tool is a permanent line item in every deployment's catalog, so the
|
|
@@ -206,7 +218,7 @@ connection *calls*, dropping the tool drops the row — so
|
|
|
206
218
|
rather than by a recorded exception. A path reached only through a hatch is
|
|
207
219
|
named by the caller, so it was never a touched endpoint.
|
|
208
220
|
|
|
209
|
-
The surviving
|
|
221
|
+
The surviving 48 named tools all refuse malformed arguments locally, which is
|
|
210
222
|
the one thing no escape hatch can do: a hatch's path is an opaque string, so it
|
|
211
223
|
can only check that a path is a path.
|
|
212
224
|
|
|
@@ -318,6 +330,12 @@ renamed to `camelCase`. A zone comes back as `id`, `name`, `status`, `paused`,
|
|
|
318
330
|
`type`, `accountId`, `accountName`, `plan`, `nameServers`, and timestamps —
|
|
319
331
|
not the forty-field object Cloudflare sends.
|
|
320
332
|
|
|
333
|
+
Every named tool declares useful top-level output keys. Zone settings, Worker
|
|
334
|
+
settings and deployments, KV namespaces and bulk operations, rulesets, R2 CORS,
|
|
335
|
+
and Pages resources use maintained result schemas instead of an open
|
|
336
|
+
"Cloudflare object" declaration. The three raw escape hatches remain open by
|
|
337
|
+
design because their result fields depend on the caller-supplied endpoint.
|
|
338
|
+
|
|
321
339
|
Paginated lists add a `page` object derived from `result_info`:
|
|
322
340
|
`{ page, perPage, count, totalCount, totalPages, hasMore }`. `hasMore` is the
|
|
323
341
|
field to branch on.
|
|
@@ -746,7 +746,7 @@ Worker renders arguments with `String()` (so an object logs as
|
|
|
746
746
|
latter two. Only the three captured everywhere are contract (`R5`); rendering is
|
|
747
747
|
not.
|
|
748
748
|
|
|
749
|
-
**X5. Leftover authority.** QuickJS blocks imports and has no `fetch`, `process`, timers, `crypto`, or `WebSocket`. A Dynamic Worker has those globals plus a non-contract set of runtime builtins through `import()` and `process.getBuiltinModule()`, including `node:path`, `node:crypto`, `node:net`, `node:tls`, `node:dns`, `node:module`, and `cloudflare:workers`. The upstream set can drift; this list is not an allowlist.
|
|
749
|
+
**X5. Leftover authority.** QuickJS blocks imports and has no `fetch`, `process`, timers, `crypto`, or `WebSocket`. Its Node child starts with an explicitly empty process environment rather than inheriting deployment variables or `NODE_OPTIONS`. A Dynamic Worker has those globals plus a non-contract set of runtime builtins through `import()` and `process.getBuiltinModule()`, including `node:path`, `node:crypto`, `node:net`, `node:tls`, `node:dns`, `node:module`, and `cloudflare:workers`. The upstream set can drift; this list is not an allowlist.
|
|
750
750
|
The supported Worker construction is exactly `new DynamicWorkerExecutor({ loader })`. Do not pass `bindings`, `modules`, or `globalOutbound`: each can grant ambient configuration, code, or egress. Under it, `process.env`, lexical `this.env`, and `cloudflare:workers.env` are empty; `node:fs`, `node:http`, and `node:https` are unavailable through either access route; external `fetch`, `WebSocket`, `node:net`, and `node:tls` fail with workerd's outbound-denial error; DNS lookup ends unresolved; and `fetch("data:...")` resolves locally.
|
|
751
751
|
`P2` is the portable contract. Programs use none of this runtime-only authority, including timers and `crypto`, because the same code fails on QuickJS. The `execute_code` description and served `usage` skill say so before an agent writes code.
|
|
752
752
|
|
|
@@ -832,7 +832,7 @@ the upstream `Executor` shape assignable.
|
|
|
832
832
|
| Clauses | Test |
|
|
833
833
|
| --- | --- |
|
|
834
834
|
| `P1`, `P5` | `test/guest-api-contract.test.ts` (TypeScript syntax), `test/quickjs-executor.test.ts` (`normalizeCode`) |
|
|
835
|
-
| `P2`, `X5` | `test/guest-api-contract.test.ts` (Dynamic globals plus loader-only filesystem, HTTP, environment, egress, DNS, and local `data:` boundaries), `test/guest-api-contract-quickjs.test.ts` (exact absent globals and blocked imports), `test/deployment-shapes.test.ts` (loader-only Worker construction) |
|
|
835
|
+
| `P2`, `X5` | `test/guest-api-contract.test.ts` (Dynamic globals plus loader-only filesystem, HTTP, environment, egress, DNS, and local `data:` boundaries), `test/guest-api-contract-quickjs.test.ts` (exact absent globals and blocked imports), `test/quickjs-child-stderr.test.ts` (empty child-process environment), `test/deployment-shapes.test.ts` (loader-only Worker construction) |
|
|
836
836
|
| `P3`, `X9` | `test/guest-api-contract.test.ts`, `test/execute.test.ts` |
|
|
837
837
|
| `P4` | `test/guest-api-contract.test.ts` (no cross-run leakage), `test/execute.test.ts` (one catalog load per connector per execution) |
|
|
838
838
|
| `A1`, `A2` | `test/guest-api-contract.test.ts`, `test/execute.test.ts` (sanitizing), `test/server.test.ts` (bounded live connector inventory) |
|
package/documentation/linear.md
CHANGED
|
@@ -110,9 +110,10 @@ the connector is present and reports `auth_required`. See
|
|
|
110
110
|
|
|
111
111
|
The wrapper classifies Linear's documented `list_*`, `get_*`, and
|
|
112
112
|
`search_documentation` tools as reads, and its `save_*`, `create_*`, `delete_*`,
|
|
113
|
-
`resolve_*`, `submit_*`, and `
|
|
114
|
-
|
|
115
|
-
|
|
113
|
+
`resolve_*`, `submit_*`, `merge_*`, `share_issue`, and `unshare_issue` tools as
|
|
114
|
+
writes. Sharing changes an existing issue's access, so both halves are
|
|
115
|
+
destructive. An unfamiliar tool the downstream leaves unannotated fails closed
|
|
116
|
+
onto `call_destructive_tool` until a Connecta release reviews it.
|
|
116
117
|
|
|
117
118
|
That classification fills in downstream silence and otherwise preserves
|
|
118
119
|
explicit annotations. A tool on the read allowlist arriving with
|
|
@@ -136,7 +137,8 @@ though some calls only create. The genuine creates are `create_issue_label` and
|
|
|
136
137
|
## The catalog is not a fixed set
|
|
137
138
|
|
|
138
139
|
Linear's hosted `tools/list` varies by workspace plan and enabled features:
|
|
139
|
-
customer requests, releases,
|
|
140
|
+
customer requests, releases, code review, templates, and explicit issue sharing
|
|
141
|
+
do not appear in every workspace.
|
|
140
142
|
The maintained allowlists are therefore a superset — a classified name a
|
|
141
143
|
workspace never returns costs nothing, and a genuinely new tool fails closed.
|
|
142
144
|
Agents should search this connector's catalog for what the workspace actually
|
|
@@ -84,7 +84,7 @@ the maintained guide carries the missing call guidance:
|
|
|
84
84
|
A read-only live audit on 2026-08-13 confirmed all three refusals against the
|
|
85
85
|
US hosted endpoint. They are reported upstream as
|
|
86
86
|
[`mixpanel/mixpanel-headless#202`](https://github.com/mixpanel/mixpanel-headless/issues/202).
|
|
87
|
-
The vetted catalog records
|
|
87
|
+
The vetted catalog records current schema digests for all 64 tools,
|
|
88
88
|
so a later schema correction or regression appears by tool name in the
|
|
89
89
|
maintainer drift check. The guide can then shrink when the downstream schema
|
|
90
90
|
becomes complete; Connecta does not absorb the defect permanently.
|
|
@@ -110,8 +110,10 @@ rest) leave `destructiveHint` unset; `readOnlyHint: false` already routes them
|
|
|
110
110
|
through the destructive path, and asserting destruction only inflates the
|
|
111
111
|
approval copy the host shows a human.
|
|
112
112
|
|
|
113
|
-
Experiments and Feature Flags
|
|
114
|
-
|
|
113
|
+
Experiments and Feature Flags are Mixpanel beta surfaces. Their three changed
|
|
114
|
+
schemas were reviewed again on 2026-08-30. The same review added
|
|
115
|
+
`Fill-Event-Metadata` as a destructive write because it applies generated names
|
|
116
|
+
and descriptions to existing Lexicon events.
|
|
115
117
|
|
|
116
118
|
## Rate limits
|
|
117
119
|
|
|
@@ -233,13 +233,13 @@ in.
|
|
|
233
233
|
| `catalog.test.ts` | lexical ranking and the compact schema renderer — `const`, `allOf` beside siblings, `$ref`, the depth limit, per-schema caching, and 2020-12 keyword compatibility |
|
|
234
234
|
| `clerk.test.ts` | protected-resource metadata, the browser sign-in config, OAuth and session tokens, cached best-effort activity labels with their caps, the hand-applied `azp` rejection, and the `allowedDomains` allowlist including every lookalike that must not be repaired into a match |
|
|
235
235
|
| `cloudflare-access-auth.test.ts` | trusted `ctx.access` human and service identities, absent/error fail-closed behavior, service-token MCP admission without operator mutation, human same-origin mutation, and the Clerk-to-ambient shell switch |
|
|
236
|
-
| `cloudflare-provider.test.ts` | `cloudflare()` construction, tool surface, request building, projections, typed failures, and credential test |
|
|
236
|
+
| `cloudflare-provider.test.ts` | `cloudflare()` construction, tool surface, current R2 and KV jurisdictions, useful output declarations, request building, projections including additive provider fields, typed failures, and credential test |
|
|
237
237
|
| `code-first-surface.test.ts` | the seven-tool surface itself — an executor required, every removed option and top-level tool refused, compact always-loaded routing pinned below 1,000 characters, complete on-demand usage served, and `connecta.ui` findable before connector search |
|
|
238
238
|
| `codemode-compat.test.ts` | the `Executor` seam staying structurally compatible with `@cloudflare/codemode`'s `DynamicWorkerExecutor`, enforced by `tsc` |
|
|
239
239
|
| `config.test.ts` | the grouped `ConnectaConfig` boundary — each group forwarding to its internals, malformed admission bounds failing construction, and unknown own-properties rejected by their complete path before construction does work |
|
|
240
240
|
| `credentials.test.ts` | the pure stored-shape classifier (containment, not equality) and the AES-GCM vault: round-trip, ciphertext bound to its connector id, named field sets, masked metadata, wrong-key rejection, deletion, coexistence with OAuth keys |
|
|
241
241
|
| `d1-activity-example.test.ts` | the Worker example's deployment-owned D1 activity store: actor namespace round-trip, payload-free friction reconstructed from the persisted code, and agreement with the package's friction table |
|
|
242
|
-
| `downstream-oauth.test.ts` | `KvOAuthProvider` round-trips and races, `auth_required` versus `error`, `startAuth`/`finishAuth`, callback refusal equality, bounded diagnostics, and HTML escaping |
|
|
242
|
+
| `downstream-oauth.test.ts` | `KvOAuthProvider` round-trips and generation races, runtime-local rotating-token refresh coordination across request scopes, refresh failure/retry, `auth_required` versus `error`, `startAuth`/`finishAuth`, callback refusal equality, bounded diagnostics, and HTML escaping |
|
|
243
243
|
| `errors.test.ts` | `ConnectorCallError` codes, retryable defaults and overrides, `retryAfterMs` round-trip, typed-over-heuristic classification, `AbortError` as a retryable timeout, and framing errors |
|
|
244
244
|
| `execute.test.ts` | the code-mode host bridge: identifier sanitization, MCP-result unwrapping, sandbox provider construction, authenticated thrown-failure framing, fail-closed filtering of destructive and unannotated tools, MCP/code-mode invocation parity, and payload-free describe diagnostics |
|
|
245
245
|
| `execute-emit.test.ts` | `connecta.emit` (M1–M10) — block validation, budgets, the provider, delivery after the result envelope on success only, and the defaults |
|
|
@@ -247,11 +247,11 @@ in.
|
|
|
247
247
|
| `executor-admission.test.ts` | the portable bounded FIFO both pools use: active and queue ceilings, stable retryable overload, queue timeout, cancellation removal, idempotent release, shutdown |
|
|
248
248
|
| `guarded-fetch.test.ts` | the guarded transport — construction, request building, destination confinement, and response handling |
|
|
249
249
|
| `guest-api-contract.test.ts` | the shared guest contract on the Dynamic Worker, including caught call, typed inline describe recovery, discovery, utility, batch, and budget failure codes; plus the real authority boundary — local `data:` fetch, denied egress, unresolved DNS, empty environment paths, unavailable filesystem/HTTP builtins, and present runtime globals |
|
|
250
|
-
| `linear-provider.test.ts` | the Linear proxy's construction,
|
|
250
|
+
| `linear-provider.test.ts` | the Linear proxy's construction, guide, plan-aware catalog superset, and current workspace, template, and issue-sharing classifications |
|
|
251
251
|
| `meta-tools-call.test.ts` | registry-backed calls: structured errors, truncation and `get_result`, per-connector result bounds, JSON representation failures, MCP content bounds, and offset alignment |
|
|
252
252
|
| `meta-tools-search.test.ts` | registry-backed discovery: bounded search with page and address maxima, compact and JSON schemas with constraints, typed describe recovery and suggestions, and structured-result compatibility |
|
|
253
253
|
| `meta-tools.test.ts` | the remaining registry-backed meta-tools: the complete on-demand usage skill, connector-guide selection and summary bounds, stored-credential drift, catalog health, authorization, probe timeouts, and unavailable or unknown browse recovery |
|
|
254
|
-
| `mixpanel-provider.test.ts` | the Mixpanel proxy, its conditional-input guide and complete
|
|
254
|
+
| `mixpanel-provider.test.ts` | the Mixpanel proxy, its conditional-input guide, destructive metadata fill, and complete 64-tool schema-digest manifest |
|
|
255
255
|
| `notion-provider.test.ts` | Notion's deliberate tool surface, including declined expanded page inputs, request construction, lean projections, both pagination conventions, error mapping, and writes |
|
|
256
256
|
| `operator-boundary.test.ts` | the operator row of the decisions table, after every mutation route: authentication material managed without moving a declared structure, and the one honest exception — a credential write making a remote catalog appear, which is discovery arriving, not an operator editing the deployment |
|
|
257
257
|
| `operator-store.test.ts` | `src/operator-ui/app/store.ts` against a fake browser: the Clerk listener, ambient Access requests without a browser-readable token, `gate()`, the generation fence, and the request path |
|
|
@@ -263,11 +263,11 @@ in.
|
|
|
263
263
|
| `remote-mcp-pagination.test.ts` | the `tools/list` cursor chain in both directions — exact cursor handoff, first-wins dedup, a failed later page rejecting rather than returning its prefix, the runaway backstops, the tool-metadata re-prime across pages, and paginated catalogs reaching the discovery path |
|
|
264
264
|
| `request-admission.test.ts` | `/mcp` bounded before auth, the stable 503 and `Retry-After`, health and operator responsiveness under saturation, payload-free counters, queued cancellation, shutdown rejection while active work drains, and the separate fallback code pool |
|
|
265
265
|
| `result-shapes.test.ts` | passive output-shape learning: value-free bounded inference, merging, 256-entry LRU eviction, 24-hour expiry, runtime isolation, read-only admission, declared-schema precedence, definition-change invalidation, discovery provenance, and failure isolation |
|
|
266
|
-
| `revenuecat-provider.test.ts` | the RevenueCat proxy's per-project key scoping and account-wide OAuth guides, its purpose-bearing summary, the argued borderline verdicts in its digest-free manifest, and the deliberately unclassified `render-paywall-screenshot` |
|
|
266
|
+
| `revenuecat-provider.test.ts` | the RevenueCat proxy's per-project key scoping and account-wide OAuth guides, its purpose-bearing summary, the refund-preference read and argued borderline verdicts in its digest-free manifest, and the deliberately unclassified `render-paywall-screenshot` |
|
|
267
267
|
| `server.test.ts` | end-to-end `/mcp` (401 → compact initialize instructions → seven compact definitions with bounded connector inventory and exact model-only Apps metadata → complete usage skill → `call_tool`), conditional guide pointers, open routes, Clerk `.well-known` metadata without network, code mode, and deferred catalog reads through both discovery surfaces |
|
|
268
268
|
| `server-route-contracts.test.ts` | the route contracts `server.ts` must keep byte-identical: every built-in answered ahead of connector routes inside the security wrapper, open data-free shells with framing denied, per-route auth and same-origin requirements with exact 401/403/405 bodies, and OAuth `verifyState`-before-`finishAuth` ordering |
|
|
269
269
|
| `startup-warnings.test.ts` | every construction-time `logger.warn` and, as importantly, the conditions that must *not* trigger one: open mode with a credential or OAuth connector, `publicUrl` unset beside OAuth, dropped branding and `uiAuth` URLs, a missing `verifyState`, a credential test-hook mismatch, and an unusable `calls.maxResultBytes` |
|
|
270
|
-
| `stripe-provider.test.ts` | the Stripe proxy's mixed-mode OAuth and fixed-mode header contracts, admission, exact account selectors, and no-guess rule |
|
|
270
|
+
| `stripe-provider.test.ts` | the Stripe proxy's mixed-mode OAuth and fixed-mode header contracts, current eleven-tool classifications, admission, exact account selectors, and no-guess rule |
|
|
271
271
|
| `operator-view.test.ts` | the app's pure state rules from `view.ts`: filtering, page routing, capability states, activity summaries, drift display, and identity reset |
|
|
272
272
|
| `ui-credentials.test.ts` | credential-management routes: save, test, delete, validation, authentication, same-origin checks, and multi-field credential shapes |
|
|
273
273
|
| `ui.test.ts` | the server shell and remaining `/ui/*` routes: gated `/ui/data` with broken-connector isolation and registry-owned catalog-observation containment, plus the URL safety gates |
|
|
@@ -291,7 +291,7 @@ justification for *not* re-running it in workerd, so "it was easier" is not one.
|
|
|
291
291
|
| `package-surface.test.ts` | the published boundary — built output shipped, the `exports` map carrying exactly the documented subpaths plus `./package.json`, only generic factories, platform storage kept in examples, Clerk and QuickJS behind optional subpaths, dependency-free Cloudflare Access behind its Worker subpath, every provider independently importable, and the Cloudflare API provider free of bare specifiers | walks the package tree with Node filesystem APIs |
|
|
292
292
|
| `purity.test.ts` | the import-graph guardrail ([architecture](./architecture.md#import-graph-purity)) — the core stays Workers-clean | walks the source import graph with Node filesystem APIs |
|
|
293
293
|
| `quickjs-child-entry.test.ts` | a missing QuickJS child entry failing before `fork()`, with the expected path and the bundler-externalization constraint | mocks Node child-process and filesystem APIs |
|
|
294
|
-
| `quickjs-child-stderr.test.ts` |
|
|
294
|
+
| `quickjs-child-stderr.test.ts` | the QuickJS child-process boundary: an explicitly empty environment despite parent secrets and `NODE_OPTIONS`, plus abnormal exits retaining only an 8 KiB stderr tail in the parent-side diagnostic | mocks Node child-process streams |
|
|
295
295
|
| `quickjs-executor.test.ts` | the child-process sandbox — code normalization, lazy namespace proxies, bounded IPC, separate guest-CPU and wall budgets, saturation, cancellation and shutdown, crash and OOM recovery, host-call hangs, stalled-promise detection | runs the Node QuickJS child-process executor |
|
|
296
296
|
| `quickjs-log-limits.test.ts` | bounded `console.*` capture — per-entry cut, cumulative character and transport budgets, escape-heavy floods preserving the guest result | runs the Node QuickJS child-process executor |
|
|
297
297
|
| `suite-partition.test.ts` | this partition, including itself: every `*.test.ts` in exactly one list, stale entries and empty reasons refused | walks the test directory to guard the partition |
|
|
@@ -693,8 +693,10 @@ Cloudflare keep/prune half of that judgment was made in
|
|
|
693
693
|
[#350](https://github.com/zackbart/connecta/issues/350): 30 keep, 18 improve,
|
|
694
694
|
3 prune, measured per tool in
|
|
695
695
|
[`eval/current-version/results/issue-350-evidence.md`](https://github.com/zackbart/connecta/blob/main/eval/current-version/results/issue-350-evidence.md).
|
|
696
|
-
Its eighteen `improve` rows
|
|
697
|
-
their place
|
|
696
|
+
Its eighteen `improve` rows were H8 and H9 misses on tools that clearly earned
|
|
697
|
+
their place. Issue #488 resolved them with useful output keys and maintained
|
|
698
|
+
projections; the measurements remain the reason those tools stayed rather than
|
|
699
|
+
a second removal argument.
|
|
698
700
|
|
|
699
701
|
Each provider's own guide ([Cloudflare](./cloudflare.md),
|
|
700
702
|
[Linear](./linear.md), [Mixpanel](./mixpanel.md), [Notion](./notion.md),
|
|
@@ -152,17 +152,18 @@ names the `authorize_connector` recovery. A permission gap, a plan restriction,
|
|
|
152
152
|
or a rejected argument arrives as RevenueCat wrote it and is not an
|
|
153
153
|
authorization problem.
|
|
154
154
|
|
|
155
|
-
## The ninety-
|
|
155
|
+
## The ninety-six tools, and what they are classified as
|
|
156
156
|
|
|
157
157
|
RevenueCat's
|
|
158
158
|
[tool reference](https://www.revenuecat.com/docs/tools/mcp/tools-reference),
|
|
159
|
-
read on **2026-08-
|
|
160
|
-
|
|
161
|
-
|
|
159
|
+
read on **2026-08-30**, documents ninety-six tools. Ninety-five carry an access
|
|
160
|
+
column and are classified here: **51 read-only, 15 additive writes, 29
|
|
161
|
+
destructive writes.**
|
|
162
162
|
|
|
163
163
|
Reads are every `Read` row, verbatim — the nine project and app reads, the four
|
|
164
164
|
product reads, the entitlement, offering, targeting, paywall, customer, virtual
|
|
165
|
-
currency, chart, webhook, and SDK reads,
|
|
165
|
+
currency, chart, webhook, and SDK reads, `get-paywall-ai-task`, and
|
|
166
|
+
`get-refund-request-preferences`.
|
|
166
167
|
|
|
167
168
|
Writes follow the verb where the verb is honest: `archive-*` and `unarchive-*`
|
|
168
169
|
flip an existing object's active state, `update-*`, `delete-*`, `publish-*`,
|
|
@@ -191,14 +192,15 @@ beside the row:
|
|
|
191
192
|
`create-webhook-integration` deserves a sentence too. No existing integration
|
|
192
193
|
changes, so the verb reads additive — but with filters omitted the new one
|
|
193
194
|
"starts delivering" every customer event in the project to a URL the caller
|
|
194
|
-
typed. Customer data leaving the account
|
|
195
|
-
|
|
195
|
+
typed. Customer data leaving the account makes it destructive on consequence,
|
|
196
|
+
so the approval copy says what is at stake.
|
|
196
197
|
|
|
197
198
|
**`render-paywall-screenshot` is deliberately unclassified.** RevenueCat's
|
|
198
|
-
reference gives it no access column
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
199
|
+
reference gives it no access column. The current live server explicitly marks
|
|
200
|
+
it read-only, so that catalog keeps it callable from `execute_code`; if a later
|
|
201
|
+
catalog omits the annotation, it fails closed onto `call_destructive_tool`.
|
|
202
|
+
Connecta preserves the provider's current annotation without inventing a
|
|
203
|
+
release classification from the tool's harmless-sounding name (P5).
|
|
202
204
|
|
|
203
205
|
That classification fills in downstream silence and otherwise preserves explicit
|
|
204
206
|
annotations. A tool on the read allowlist arriving with `destructiveHint: true`
|
|
@@ -242,7 +244,7 @@ API v2 meters per minute and **per domain**
|
|
|
242
244
|
| Charts & Metrics | 25 |
|
|
243
245
|
|
|
244
246
|
A `ConnectorCallAdmissionPolicy` carries exactly one rule, so a connector-wide
|
|
245
|
-
budget has to pick one of those six numbers for all ninety-
|
|
247
|
+
budget has to pick one of those six numbers for all ninety-six tools.
|
|
246
248
|
Transcribing 25 would throttle a customer read loop to a nineteenth of its
|
|
247
249
|
documented allowance; transcribing 480 would leave a chart sweep unprotected.
|
|
248
250
|
Neither is the provider's limit, and both would look like RevenueCat being
|
|
@@ -281,15 +283,13 @@ still needs restrained use.
|
|
|
281
283
|
|
|
282
284
|
## What is not verified
|
|
283
285
|
|
|
284
|
-
- **
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
- **No input or output schema has been read**, which is why the manifest
|
|
292
|
-
carries no digests.
|
|
286
|
+
- **The 2026-08-30 live review used a project-scoped catalog.** It proves the
|
|
287
|
+
additions that catalog serves, including `get-refund-request-preferences`,
|
|
288
|
+
but cannot prove a globally documented tool was removed. The manifest stays
|
|
289
|
+
a superset because plan, platform, and credential scope hide tools.
|
|
290
|
+
- **No complete schema set has been recorded**, which is why the manifest
|
|
291
|
+
carries no digests. The review read the new live schemas, but its scoped
|
|
292
|
+
catalog omitted many classified writes.
|
|
293
293
|
- **Whether `render-paywall-screenshot` mutates anything.** It has no access
|
|
294
294
|
column, and guessing is exactly what P5 exists to prevent.
|
|
295
295
|
|
|
@@ -107,3 +107,38 @@ the retired grant.
|
|
|
107
107
|
The OAuth callback verifies the one-shot `state` first, then hands the complete
|
|
108
108
|
query string—including RFC 9207 `iss`—to the SDK transport. One-shot state,
|
|
109
109
|
verifier, and pending URL are cleared only after a successful exchange.
|
|
110
|
+
|
|
111
|
+
Within one `remoteMcp()` runtime, one request scope owns refresh-token
|
|
112
|
+
redemption for an OAuth generation. Concurrent scopes wait for the owner's
|
|
113
|
+
token save or bounded failure, then either read storage again or receive that
|
|
114
|
+
failure. A scope that had already read the retired refresh token reuses the
|
|
115
|
+
newly stored rotating token locally instead of sending the retired value
|
|
116
|
+
upstream. Force reauthorization retires the old generation's gate, and a
|
|
117
|
+
failed flow releases ownership for a later attempt. The coordinator retains
|
|
118
|
+
only a completion signal and one temporary owner-abort listener until that
|
|
119
|
+
exact flight settles, never the token response or downstream transport. A
|
|
120
|
+
follower may stop waiting when its own request is cancelled without cancelling
|
|
121
|
+
the owner or poisoning the generation for later callers. If the owner's
|
|
122
|
+
credential mutation fails, joined callers receive that same bounded failure
|
|
123
|
+
instead of waking to redeem the unchanged token; a later independent call may
|
|
124
|
+
retry. Non-success and malformed token responses settle current waiters at the
|
|
125
|
+
fetch boundary, before any later authorization callback can itself fail.
|
|
126
|
+
Cancelling the owner aborts its fetch and fails current joiners rather than
|
|
127
|
+
promoting one: once a request reaches the authorization server, repeating its
|
|
128
|
+
old refresh token is not known to be safe. If that cancellation lands while
|
|
129
|
+
the valid response's credential write is already running, a same-generation
|
|
130
|
+
attempt receives `temporarily_unavailable` until the exact write succeeds or
|
|
131
|
+
fails. This mutation marker contains no retained promise; force
|
|
132
|
+
reauthorization removes it when the old generation becomes unreadable.
|
|
133
|
+
An additional opaque success identity lets a request recognize a refresh that
|
|
134
|
+
completed after its issuer-aware token read even when the authorization server
|
|
135
|
+
returned byte-identical credentials. The identity is generation-scoped and is
|
|
136
|
+
discarded with the retired generation. Every authoritative storage-generation
|
|
137
|
+
read also retires coordinator state from other epochs, so an externally
|
|
138
|
+
advanced generation cannot be overwritten in runtime state by late old work.
|
|
139
|
+
|
|
140
|
+
This guarantee is runtime-local. `KVStorage` has no atomic lock or
|
|
141
|
+
compare-and-set operation, so separate processes or Worker isolates can still
|
|
142
|
+
redeem the same refresh token concurrently. Generation envelopes continue to
|
|
143
|
+
fence their writes, but Connecta does not claim cross-isolate exactly-once
|
|
144
|
+
refresh.
|
package/documentation/stripe.md
CHANGED
|
@@ -139,38 +139,39 @@ boots but cannot list tools is usually a dashboard toggle, not a bad key.
|
|
|
139
139
|
|
|
140
140
|
## The eleven tools, and what they are classified as
|
|
141
141
|
|
|
142
|
-
Stripe
|
|
142
|
+
Stripe currently serves eleven tools. Seven are reads:
|
|
143
143
|
|
|
144
144
|
`stripe_api_search`, `stripe_api_details`, `stripe_api_read`,
|
|
145
|
-
`
|
|
146
|
-
`
|
|
145
|
+
`get_balance_summary`, `list_available_accounts_or_orgs`,
|
|
146
|
+
`manage_stripe_accounts`, and `search_stripe_documentation`.
|
|
147
147
|
|
|
148
148
|
Four are writes:
|
|
149
149
|
|
|
150
|
-
`stripe_api_write`
|
|
151
|
-
`
|
|
150
|
+
`stripe_api_write` is destructive. `stripe_implementation_planner`,
|
|
151
|
+
`stripe_analytics`, and `send_stripe_mcp_feedback` are additive.
|
|
152
152
|
|
|
153
153
|
Two of those deserve a sentence. `stripe_api_read` is a read because Stripe
|
|
154
154
|
documents it as the `GET` half of a generic pair — the tool is the read
|
|
155
155
|
boundary, not whichever endpoint an agent names inside it, and its sibling
|
|
156
156
|
`stripe_api_write` carries every `POST`, `PATCH`, `PUT`, and `DELETE`.
|
|
157
|
-
`
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
157
|
+
`stripe_implementation_planner` creates and continues provider-side guide
|
|
158
|
+
state. `stripe_analytics` combines retrieval with query-run creation behind one
|
|
159
|
+
tool. Stripe marks both not read-only and not destructive, so Connecta records
|
|
160
|
+
them as additive writes. They leave `destructiveHint` unset. Their explicit
|
|
161
161
|
`readOnlyHint: false` already routes them through `call_destructive_tool`, and
|
|
162
|
-
asserting destruction
|
|
162
|
+
asserting destruction would misstate their effect.
|
|
163
163
|
|
|
164
164
|
That classification fills in downstream silence and otherwise preserves
|
|
165
|
-
explicit annotations.
|
|
166
|
-
|
|
165
|
+
explicit annotations. The current server annotates all eleven tools, while the
|
|
166
|
+
manifest records what this release reviewed and exposes later contradictions.
|
|
167
|
+
A tool on the read allowlist arriving with
|
|
167
168
|
`destructiveHint: true` or `readOnlyHint: false` keeps exactly what the
|
|
168
169
|
downstream said and stays behind `call_destructive_tool`. A tool on neither
|
|
169
170
|
maintained list arriving with `readOnlyHint: true` keeps that too, and stays
|
|
170
171
|
callable from `execute_code`. Both are the downstream telling you this release's
|
|
171
172
|
allowlist is stale, and on a name no release has reviewed its word is the only
|
|
172
173
|
evidence there is. One narrow fail-closed exception applies to a name this
|
|
173
|
-
release reviewed and filed destructive:
|
|
174
|
+
release reviewed and filed destructive: `stripe_api_write` claiming
|
|
174
175
|
`readOnlyHint: true` is a downstream bug rather than news, and stays on the
|
|
175
176
|
approval path.
|
|
176
177
|
|
|
@@ -57,7 +57,7 @@ exist so far:
|
|
|
57
57
|
| --- | --- | --- |
|
|
58
58
|
| **pre-template** | before 0.10.2 | no `connecta init` existed; hand-written, or copied from the retired `examples/node` |
|
|
59
59
|
| **A** | 0.10.2 – 0.15.1 | `.env.example`, `.gitignore`, `AGENTS.md`, `CLAUDE.md`, `README.md`, `package.json`, `src/index.ts`, `tsconfig.json` |
|
|
60
|
-
| **B** | 0.16.0 – 0.21.
|
|
60
|
+
| **B** | 0.16.0 – 0.21.2 | adds `.dockerignore`, `Dockerfile`, `docker-compose.yml`, and `src/file-activity.ts`; `src/index.ts` grows the four commented operator blocks; `.env.example` ships `CONNECTA_TOKEN=` empty |
|
|
61
61
|
|
|
62
62
|
Generation A is a decade in template years and identifying it precisely does
|
|
63
63
|
not matter, because you are about to reconstruct it exactly rather than guess
|
|
@@ -106,7 +106,7 @@ know what to preserve, once to know what to re-verify at the end.
|
|
|
106
106
|
### Bump the pin and install
|
|
107
107
|
|
|
108
108
|
```sh
|
|
109
|
-
npm pkg set dependencies.@zackbart/connecta=0.21.
|
|
109
|
+
npm pkg set dependencies.@zackbart/connecta=0.21.2
|
|
110
110
|
npm install
|
|
111
111
|
```
|
|
112
112
|
|
|
@@ -130,7 +130,7 @@ Generate the *current* template beside the base you already made, into the same
|
|
|
130
130
|
`$SCRATCH`:
|
|
131
131
|
|
|
132
132
|
```sh
|
|
133
|
-
(cd "$SCRATCH" && npx @zackbart/connecta@0.21.
|
|
133
|
+
(cd "$SCRATCH" && npx @zackbart/connecta@0.21.2 init current)
|
|
134
134
|
```
|
|
135
135
|
|
|
136
136
|
You now have a three-way merge with a real base: `$SCRATCH/base` is what this
|
|
@@ -186,7 +186,7 @@ A deployment older than 0.10.2 has no base to diff against. Do not try to
|
|
|
186
186
|
manufacture one. Instead:
|
|
187
187
|
|
|
188
188
|
1. `SCRATCH=$(mktemp -d)`, then
|
|
189
|
-
`(cd "$SCRATCH" && npx @zackbart/connecta@0.21.
|
|
189
|
+
`(cd "$SCRATCH" && npx @zackbart/connecta@0.21.2 init current)` — there is no
|
|
190
190
|
`base` leg here, only the current template to read from.
|
|
191
191
|
2. Copy `$SCRATCH/current` into the deployment file by file, **skipping
|
|
192
192
|
`src/index.ts`**.
|
|
@@ -207,9 +207,10 @@ first, so cross them bottom-up: start at the oldest one still above this
|
|
|
207
207
|
deployment's pin and work back up the page, because each boundary assumes the
|
|
208
208
|
older ones are already done.
|
|
209
209
|
|
|
210
|
-
### 0.20.0 → 0.21.
|
|
210
|
+
### 0.20.0 → 0.21.2
|
|
211
211
|
|
|
212
|
-
|
|
212
|
+
0.21.2 adds no deployment migration beyond 0.21.0. The boundary is additive
|
|
213
|
+
for Node and existing Clerk deployments. The new Worker path
|
|
213
214
|
uses Cloudflare Access identity directly and removes Clerk only after the edge
|
|
214
215
|
cutover has been verified. An agent can perform every repository edit; a human
|
|
215
216
|
must attach Access, choose its policy, create service credentials, and enable
|
|
@@ -217,7 +218,7 @@ Managed OAuth in the Cloudflare dashboard.
|
|
|
217
218
|
|
|
218
219
|
For a Worker currently using Clerk, keep rollback live through the cutover:
|
|
219
220
|
|
|
220
|
-
1. Bump and install 0.21.
|
|
221
|
+
1. Bump and install 0.21.2. Add the new provider **before** the existing Clerk
|
|
221
222
|
provider, but remove nothing:
|
|
222
223
|
|
|
223
224
|
```ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zackbart/connecta",
|
|
3
|
-
"version": "0.21.
|
|
3
|
+
"version": "0.21.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"description": "One MCP to rule them all — a single MCP endpoint aggregating many downstream connectors behind a code-first surface of seven meta-tools.",
|