@zackbart/connecta 0.22.1 → 0.22.3

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.
@@ -7,11 +7,13 @@ writes the judgment down so it can be argued with, audited, and reused.
7
7
  There are two genuinely different provider shapes, and one convention set
8
8
  cannot honestly cover both:
9
9
 
10
- - **Hand-written HTTP providers** `api()` surfaces where Connecta owns every
11
- tool name, schema, projection, and error. Today: Cloudflare, Notion, Vercel.
12
- - **Hosted-MCP proxies** — `remoteMcp()` wrappers around a server somebody else
10
+ - **Hand-written HTTP providers**: `api()` surfaces where Connecta owns every
11
+ tool name, schema, projection, and error. Today: Cloudflare, Notion, and the
12
+ Vercel API surface.
13
+ - **Hosted-MCP proxies**: `remoteMcp()` wrappers around a server somebody else
13
14
  operates, where the names, schemas, results, and error prose arrive as they
14
- are. Today: Linear, Stripe, Mixpanel, RevenueCat.
15
+ are. Today: Cloudflare, Linear, Stripe, Mixpanel, Notion, RevenueCat, and
16
+ Vercel MCP interfaces.
15
17
 
16
18
  The governing principle for every convention below is the same: **keep the
17
19
  model that interacts with connecta as efficient as possible.** A convention
@@ -85,8 +87,8 @@ other source with no description or no `inputSchema`.
85
87
  ## Hand-written HTTP providers
86
88
 
87
89
  Connecta owns the whole surface here, which means every miss is ours. These
88
- apply to `api()`-based prebuilt connections (Cloudflare, Notion, Vercel) and are the
89
- bar any future one is written to.
90
+ apply to `api()`-based prebuilt connections (Cloudflare, Notion, and Vercel's
91
+ API surface) and are the bar any future one is written to.
90
92
 
91
93
  None of them asks an author to re-derive transport safety. URL confinement,
92
94
  query and body construction, `ctx.signal`, redirect refusal, credential
@@ -513,15 +515,12 @@ credential probe, and no automatic issue filing. Proactive credential liveness
513
515
  stays removed ([#179](https://github.com/zackbart/connecta/issues/179)); this
514
516
  is the shape that does not become it.
515
517
 
516
- **What a manifest holds.** Every tool name a release reviewed, the verdict it
517
- reviewed it as (`read-only`, `additive`, `destructive`), and where a release
518
- actually read them a digest of that tool's input and output schemas. Today
519
- three of the four proxies ship names and verdicts and no digests, because no
520
- release has read a live schema and written it down, and an invented digest reports a
521
- change that never happened. `npm run drift:check -- --record` reads them from a
522
- live catalog and prints the block a release pastes in; until a release does,
523
- a manifest without digests counts no schema changes, which is the honest answer
524
- rather than a silent zero.
518
+ **What a manifest holds.** Every tool name a release reviewed and its verdict
519
+ (`read-only`, `additive`, or `destructive`). A manifest may also carry a schema
520
+ digest from a prior review, but that digest is runtime drift evidence, not a
521
+ schema Connecta serves. The credential-free provider check neither requires nor
522
+ updates schema digests. The live `tools/list` definition always remains the
523
+ agent-facing contract.
525
524
 
526
525
  **What it counts.** Four categories, and only counts:
527
526
 
@@ -547,8 +546,9 @@ One activity event per *change* in the counts — an identical report every TTL
547
546
  is a heartbeat, not news — carrying the connector id and four integers. The
548
547
  event type has nowhere to put a tool name, a schema, an argument, a result, or
549
548
  downstream error prose, which is the same construction guarantee the tool-call
550
- event makes. Which tool drifted is deliberately absent from the runtime: it is
551
- answered by the maintainer-run check, with a live catalog in front of it.
549
+ event makes. Which account-specific tool drifted is deliberately absent from
550
+ this payload-free runtime report. The public check can name documented drift;
551
+ it cannot recover a plan-gated name the provider does not publish.
552
552
 
553
553
  **How far an observation reaches.** One runtime, and no further. The
554
554
  observation lives in the isolate or process that served the refresh; unlike the
@@ -558,8 +558,9 @@ the instance that took the request: on Workers a `connecta doctor` run will
558
558
  usually land on an isolate that has served no refresh and print nothing, and
559
559
  behind more than one process it is a coin flip. Read an empty report as *this
560
560
  runtime has observed nothing*, never as *nothing drifted* — the durable record
561
- of a finding is the activity event a sink already stored, and naming the tool
562
- is still the maintainer-run check's job.
561
+ of a finding is the activity event a sink already stored. The public check can
562
+ name a documented change. Naming an unpublished, account-only tool is outside a
563
+ credential-free checker.
563
564
 
564
565
  **What a finding obliges.** A contradicted vetted verdict — the downstream
565
566
  calling a release-reviewed destructive tool `readOnlyHint: true`, or a vetted
@@ -570,33 +571,43 @@ whether or not anybody noticed it arrived.
570
571
 
571
572
  ## The maintainer-run drift check
572
573
 
573
- `npm run drift:check` is the other half
574
+ `npm run providers:check` is the other half
574
575
  ([#351](https://github.com/zackbart/connecta/issues/351)): a human at a laptop,
575
- before a release, with local credentials and the published specifications in
576
- front of them. It lives in
576
+ before a release, using only published specifications and documentation. It
577
+ lives in
577
578
  [`scripts/drift-check.mjs`](https://github.com/zackbart/connecta/blob/main/scripts/drift-check.mjs) and ships nowhere —
578
579
  `scripts/` is outside the package, no runtime module imports it, and nothing it
579
580
  reads becomes a runtime input.
580
581
 
581
- **Hosted-MCP catalogs.** `--hosted` lists each proxy's live catalog with the
582
- maintainer's own key and diffs it against the same `vettedCatalog()` manifest
583
- the connector classifies from, reporting tools *by name*: added, no longer
584
- served, annotation conflicts with what the downstream actually claimed, and —
585
- once a manifest records schema digests which tool's schemas moved. The names
586
- live here rather than in the runtime because the runtime's counts are
587
- payload-free by construction, and a name has no reader there anyway. It then
588
- compares its own totals against `detectCatalogDrift()`: two readings of one
589
- manifest that disagree mean one of them is lying, which is worth failing over.
590
- One credential per provider comes from the environment
591
- `CONNECTA_DRIFT_LINEAR_KEY`, `CONNECTA_DRIFT_STRIPE_KEY`,
592
- `CONNECTA_DRIFT_MIXPANEL_KEY`, `CONNECTA_DRIFT_REVENUECAT_KEY` and a missing
593
- or dead one stops the run with a message naming it rather than reporting an
594
- empty catalog as mass removal. Linear, bare Stripe, and RevenueCat `sk_` values
595
- use their documented bearer or Basic framing.
596
- Mixpanel's beta service-account form is provider-specific:
597
- `user:secret` becomes `Bearer Basic <base64(user:secret)>`, exactly as its MCP
598
- documentation requires. A value that already includes whitespace is treated
599
- as a complete Authorization value and passes through unchanged.
582
+ **Published MCP references.** `--docs` checks
583
+ the official setup page for each maintained hosted MCP connection, including
584
+ the endpoint and OAuth support. Cloudflare, Stripe, Mixpanel, Notion,
585
+ RevenueCat, and Vercel also publish structured tool inventories. The checker
586
+ compares their documented names with the same vetted manifests the wrappers
587
+ use. Linear's setup page does not enumerate tools, so its result says that only
588
+ setup metadata was checked.
589
+
590
+ A documented addition with no classification is a finding. A classified tool
591
+ missing from public docs is printed but does not fail the run, because account
592
+ scope, staged rollout, and documentation lag can all hide a tool that an
593
+ earlier release reviewed. RevenueCat's `render-paywall-screenshot` is the odd
594
+ one out: the official inventory names it but leaves its Access column blank.
595
+ The checker reports the reviewed exception and Connecta keeps it fail-closed.
596
+
597
+ `npm run providers:check` runs this documentation check for every maintained
598
+ hosted MCP connection and the touched-endpoint OpenAPI check for every
599
+ hand-written HTTP connection. It never reads a provider credential. The network
600
+ keeps it outside `npm run check`; a provider outage must not make the
601
+ deterministic test suite flaky.
602
+
603
+ MCP schema handling needs a different assertion. Connecta does not vendor or
604
+ reconstruct those schemas, so there is no static MCP schema snapshot for this
605
+ command to compare. The live `tools/list` response is passed through at runtime,
606
+ and the deterministic `catalog-drift.test.ts` suite pins that the vetted wrapper
607
+ changes safety annotations only while preserving the provider input schema,
608
+ output schema, and description. A parameter table in a docs page is never
609
+ promoted into a runtime schema. The report states this directly instead of
610
+ printing a misleading authenticated-schema requirement.
600
611
 
601
612
  **Touched endpoints.** A hand-written provider is written against a published
602
613
  OpenAPI document and calls a few dozen of its operations, so
@@ -630,13 +641,16 @@ H11's business, mapped from the status. `--record` rewrites the manifests from
630
641
  the documents on hand; run it when a finding has been reviewed, and read the
631
642
  diff before committing it.
632
643
 
633
- Narrowing is checked against the half being run: `--specs --provider linear`
634
- and `--hosted --provider notion` exit 2 rather than checking nothing and
635
- reporting no drift, because a false green from a plausible typo is the one
636
- failure mode a release-time exit code cannot afford.
644
+ Narrowing is checked against the part being run: `--specs --provider linear`
645
+ and `--specs --provider stripe` exit 2 rather than checking nothing and
646
+ reporting no drift. `npm run providers:check -- --provider vercel` checks the
647
+ REST OpenAPI contract and public MCP documentation without credentials.
648
+ `npm run drift:check` is the lower-level equivalent with the same
649
+ credential-free default plus fixture and recording flags.
637
650
 
638
- **What it never does.** No downstream credential reaches CI. No scheduled job,
639
- no background traffic in a deployment, no automatic issue filing. A finding is
651
+ **What it never does.** No provider credential is read at all. There is no
652
+ scheduled job, background traffic in a deployment, or automatic issue filing.
653
+ Public docs do not generate tools or replace the live MCP catalog. A finding is
640
654
  read by a human and becomes a GitHub issue they wrote, because the decision a
641
655
  finding needs — the provider moved this endpoint, or connecta has to stop
642
656
  calling it — is not one a diff can make. Published specifications remain drift
@@ -218,13 +218,10 @@ benchmarks, experiments, virtual currencies, and the account-billing tools are
218
218
  the usual absentees — so search this connector for what it actually exposes
219
219
  rather than assuming a documented tool is here.
220
220
 
221
- **No schema digests are recorded.** No release has read RevenueCat's live
222
- schemas and written them down; that needs a live project and a maintainer's own
223
- key. The manifest therefore ships names and verdicts only, and the drift check
224
- honestly counts zero schema changes rather than reporting an invented one.
225
- `npm run drift:check -- --record` reads them from a live catalog and prints the
226
- block a release pastes in
227
- ([#351](https://github.com/zackbart/connecta/issues/351)).
221
+ **No schemas are vendored.** The manifest ships names and safety verdicts only.
222
+ The live `tools/list` response remains the schema agents receive; Connecta does
223
+ not replace it with a snapshot or require a maintainer credential to validate
224
+ one.
228
225
 
229
226
  ## Rate limits
230
227
 
@@ -287,12 +284,19 @@ still needs restrained use.
287
284
  additions that catalog serves, including `get-refund-request-preferences`,
288
285
  but cannot prove a globally documented tool was removed. The manifest stays
289
286
  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.
287
+ - **No complete schema set is vendored.** The live review read the new schemas,
288
+ but its scoped catalog omitted many classified writes. Runtime schemas still
289
+ come from the server.
293
290
  - **Whether `render-paywall-screenshot` mutates anything.** It has no access
294
291
  column, and guessing is exactly what P5 exists to prevent.
295
292
 
293
+ `npm run drift:check -- --docs --provider revenuecat` checks the official setup
294
+ page and its 105-row tool reference without a credential. It compares the
295
+ documented names with the release-reviewed classifications. The screenshot
296
+ tool's blank Access column is a manually reviewed exception: the checker
297
+ reports it separately and Connecta keeps it fail-closed. The check reads names,
298
+ not live schemas or machine-interpreted access verdicts.
299
+
296
300
  ## Conventions
297
301
 
298
302
  This connection is audited against
@@ -247,6 +247,13 @@ about rather than read:
247
247
  tools' arguments is not documented. The guide states them because an agent
248
248
  that ignores them is wrong either way.
249
249
 
250
+ `npm run drift:check -- --docs --provider stripe` compares Stripe's official
251
+ 16-tool table with the vetted manifest and checks the hosted endpoint plus OAuth
252
+ support. `list_available_accounts_or_orgs` and `manage_stripe_accounts` remain
253
+ classified from an authenticated review even though the current public table
254
+ does not list them. The command prints that discrepancy without treating docs
255
+ silence as proof that a live account no longer serves them.
256
+
250
257
  ## Conventions
251
258
 
252
259
  This connection is audited against
@@ -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.22.1 | 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 |
60
+ | **B** | 0.16.0 – 0.22.3 | 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.22.1
109
+ npm pkg set dependencies.@zackbart/connecta=0.22.3
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.22.1 init current)
133
+ (cd "$SCRATCH" && npx @zackbart/connecta@0.22.3 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.22.1 init current)` — there is no
189
+ `(cd "$SCRATCH" && npx @zackbart/connecta@0.22.3 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,7 +207,7 @@ 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.21.2 → 0.22.1
210
+ ### 0.21.2 → 0.22.3
211
211
 
212
212
  Connector and user policy remain config-as-code. If `identity.connectorAccess`
213
213
  is configured, every interactive human may now manage the authentication of
@@ -1,44 +1,58 @@
1
1
  # Vercel
2
2
 
3
3
  Import `vercel()` independently from `@zackbart/connecta/providers/vercel`.
4
- It is a hand-written `api()` connection over Vercel's public REST API. The
5
- connection owns 18 named operations and three provider-relative REST hatches.
6
- It adds no provider dependency, imports no `node:` builtin, and is not reachable
7
- from Connecta's root entry.
4
+ It offers two explicit provider surfaces:
5
+
6
+ | `surface` | Contract owner | Authentication | Best fit |
7
+ | --- | --- | --- | --- |
8
+ | `"api"` or omitted | Connecta's hand-written schemas and projections | Vercel access token | Stable named operations, guarded REST hatches, environment variables, domains, and deployment lifecycle |
9
+ | `"mcp"` | Vercel's live MCP catalog and schemas | OAuth | Vercel's newest agent tools, documentation search, observability, purchases, toolbar comments, and direct deployment |
10
+
11
+ The choice belongs to deployment configuration. It never changes during an
12
+ agent run, and neither surface receives different Connecta privileges. Use two
13
+ connector ids when a deployment needs both.
8
14
 
9
15
  ```ts
10
16
  import { vercel } from "@zackbart/connecta/providers/vercel";
11
17
 
12
- const hosting = vercel("hosting", {
18
+ const hostingApi = vercel("hosting_api", {
19
+ surface: "api",
13
20
  purpose: "Production web applications for the product team",
14
21
  teamId: "team_1a2b3c4d5e6f7g8h9i0j1k2l",
15
22
  });
23
+
24
+ const hostingMcp = vercel("hosting_mcp", {
25
+ surface: "mcp",
26
+ purpose: "Production diagnosis and Vercel-native agent workflows",
27
+ });
16
28
  ```
17
29
 
30
+ Omitting `surface` still selects `"api"`, so existing configurations do not
31
+ change behavior.
32
+
33
+ ## API surface
34
+
35
+ The API surface is a hand-written `api()` connection over Vercel's public REST
36
+ API. It owns 18 named operations and three provider-relative REST hatches. It
37
+ adds no provider dependency, imports no `node:` builtin, and is not reachable
38
+ from Connecta's root entry.
39
+
18
40
  The deployment stores one Vercel access token in Connecta's credential vault.
19
41
  Create the token in Vercel Account Settings under Tokens. Scope it to the
20
42
  personal account or team this connection needs and give it an expiration date.
21
43
  The operator UI's Test action calls `GET /v2/user` and reports the authenticated
22
44
  username, email, name, or id. Connecta never probes it in the background.
23
45
 
24
- ## Why this uses REST instead of Vercel MCP
25
-
26
- Vercel MCP provides useful project, deployment, and log reads, but it does not
27
- cover the public API. This connection keeps those common reads and adds project
28
- domains, value-safe environment-variable management, deployment promotion and
29
- deletion, and direct access to versioned REST endpoints. The three hatches mean
30
- a newly published Vercel endpoint does not require a Connecta release before an
31
- agent can use it.
32
-
33
- This is still authored rather than generated. No OpenAPI document creates tools
34
- at runtime. The named operations are reviewed, projected, classified, and
35
- tested by hand. The published OpenAPI document is used only by
36
- `npm run drift:check` to compare the 19 named endpoints this connection calls.
46
+ This surface is authored rather than generated. No OpenAPI document creates
47
+ tools at runtime. The named operations are reviewed, projected, classified,
48
+ and tested by hand. The published OpenAPI document is used only by
49
+ `npm run drift:check` to compare the 19 named endpoints this surface calls.
37
50
 
38
51
  ## Configuration
39
52
 
40
53
  ```ts
41
54
  vercel("hosting", {
55
+ surface: "api",
42
56
  title: "Production hosting",
43
57
  authScope: "shared",
44
58
  purpose: "Customer-facing sites owned by Platform",
@@ -69,7 +83,35 @@ from replacing `Authorization`, passes `ctx.signal`, and stops reading at 8 MiB.
69
83
  The runtime-log read also returns at most 500 rows and stops a stream that stays
70
84
  open past 10 seconds. HTTP is accepted only for a loopback test double.
71
85
 
72
- ## Named tools
86
+ ## MCP surface
87
+
88
+ The MCP surface proxies Vercel's official hosted endpoint at
89
+ `https://mcp.vercel.com` and uses OAuth. Connecta does not copy Vercel's schemas
90
+ into this repository. Each complete `tools/list` response is preserved as the
91
+ live catalog, cached under the connector id, and invalidated when authorization
92
+ changes.
93
+
94
+ Connecta does vendor one thing: the 32 tool names and their release-reviewed
95
+ read, additive-write, or destructive-write verdicts from Vercel's
96
+ [official MCP tool reference](https://vercel.com/docs/agent-resources/vercel-mcp/tools).
97
+ Those verdicts fill in missing annotations and keep reviewed destructive tools
98
+ off the read-only execution path. A new tool remains fail-closed until a release
99
+ classifies it. The provider check needs no schema digest because Connecta does
100
+ not serve a schema snapshot.
101
+
102
+ This separation matters when diagnosing a schema mismatch:
103
+
104
+ - On `surface: "api"`, the schema in `src/providers/vercel.ts` is Connecta's
105
+ contract and its tests must prove the behavior.
106
+ - On `surface: "mcp"`, Vercel's live `tools/list` response is the contract.
107
+ Connecta does not rewrite it. `search_tools` with compact schemas is a lossy
108
+ preview; use `describe` with JSON format when the exact schema matters.
109
+
110
+ [integrations.sh's Vercel record](https://integrations.sh/vercel.com/) remains
111
+ useful discovery evidence. The contract check uses Vercel's official setup and
112
+ tool pages instead. Neither source replaces the live MCP schemas.
113
+
114
+ ## API named tools
73
115
 
74
116
  | Tool | What it does |
75
117
  | --- | --- |
@@ -188,7 +230,12 @@ the REST hatches share one guarded transport.
188
230
 
189
231
  The trade is API drift, handled explicitly. `scripts/drift/vercel-endpoints.json`
190
232
  records the method, versioned path, specification revision, and request/response
191
- digest for every fixed endpoint. Before a release, `npm run drift:check` compares
192
- those rows with Vercel's published OpenAPI document at
193
- `https://openapi.vercel.sh/`. The hatches are intentionally absent from that
194
- list because their endpoint is chosen by deployment code at call time.
233
+ digest for every fixed endpoint. Before a release,
234
+ `npm run providers:check -- --provider vercel` compares those rows with
235
+ Vercel's published OpenAPI document at `https://openapi.vercel.sh/`, compares
236
+ the vendored MCP inventory with Vercel's official tool reference, and checks
237
+ the endpoint and OAuth support in Vercel's setup page. It states that live MCP
238
+ schemas are not vendored and that the live `tools/list` response remains their
239
+ runtime authority. The API hatches are absent from the endpoint manifest
240
+ because deployment code chooses their path at call time. No Vercel credential
241
+ is needed for this check.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zackbart/connecta",
3
- "version": "0.22.1",
3
+ "version": "0.22.3",
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.",
@@ -114,6 +114,7 @@
114
114
  "check:security": "npm audit --omit=dev --audit-level=moderate",
115
115
  "check:package": "node scripts/check-package.mjs",
116
116
  "load:admission": "npm run build && node eval/admission-load.mjs",
117
+ "providers:check": "tsx scripts/drift-check.mjs --specs --docs",
117
118
  "drift:check": "tsx scripts/drift-check.mjs",
118
119
  "check": "npm run check:docs && npm run check:operator-ui && npm run check:lint && npm run check:unused && npm run typecheck && npm run test && npm run build && npm run check:examples",
119
120
  "release:check": "npm run check && npm run check:security && npm run check:package",
@@ -15,7 +15,7 @@
15
15
  "typecheck": "tsc --noEmit"
16
16
  },
17
17
  "dependencies": {
18
- "@zackbart/connecta": "0.22.1",
18
+ "@zackbart/connecta": "0.22.3",
19
19
  "quickjs-emscripten": "0.32.0"
20
20
  },
21
21
  "devDependencies": {