@zackbart/connecta 0.32.0 → 0.34.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 +98 -0
- package/README.md +95 -116
- package/SECURITY.md +1 -1
- package/bin/connecta.mjs +24 -6
- package/bin/version.mjs +1 -1
- package/dist/access-tokens.d.ts +167 -23
- package/dist/access-tokens.js +676 -140
- package/dist/activity.d.ts +3 -0
- package/dist/agent-identity.js +47 -0
- package/dist/auth/cloudflare-access.js +13 -5
- package/dist/branding.d.ts +7 -0
- package/dist/branding.js +76 -9
- package/dist/call-admission-context.js +15 -0
- package/dist/call-admission.js +30 -43
- package/dist/call-recovery.js +6 -2
- package/dist/catalog-service.js +15 -1
- package/dist/config-value-sources.js +16 -9
- package/dist/config.d.ts +48 -75
- package/dist/config.js +144 -36
- package/dist/connector-access.d.ts +4 -34
- package/dist/connector-access.js +15 -99
- package/dist/connector-caller.d.ts +7 -1
- package/dist/connector-caller.js +4 -2
- package/dist/connectors/api-connector.d.ts +27 -4
- package/dist/connectors/api-connector.js +2 -0
- package/dist/connectors/remote-mcp.js +2 -0
- package/dist/describe-config.d.ts +31 -7
- package/dist/describe-config.js +8 -17
- package/dist/execute.js +1 -11
- package/dist/fix-prompt.js +2 -2
- package/dist/index.d.ts +4 -3
- package/dist/index.js +30 -10
- package/dist/invocation.js +5 -3
- package/dist/membership.d.ts +53 -0
- package/dist/membership.js +121 -0
- package/dist/module-contracts.d.ts +23 -6
- package/dist/oauth-callback-outcome.js +2 -2
- package/dist/operator-record.d.ts +2 -2
- package/dist/operator-record.js +2 -4
- package/dist/operator-ui/agents.d.ts +74 -0
- package/dist/operator-ui/agents.js +104 -0
- package/dist/operator-ui/config-summary.js +562 -0
- package/dist/operator-ui/connection-map.js +375 -0
- package/dist/operator-ui/contract.d.ts +149 -28
- package/dist/operator-ui/endpoints.js +221 -0
- package/dist/operator-ui/fix-prompts.js +5 -5
- package/dist/operator-ui/generated.js +5 -4
- package/dist/operator-ui/member-page.js +97 -0
- package/dist/operator-ui/model.d.ts +14 -6
- package/dist/operator-ui/overview.js +134 -0
- package/dist/operator-ui/view.d.ts +107 -37
- package/dist/operator-ui/view.js +163 -86
- package/dist/page-styles.js +5 -3
- package/dist/provider.d.ts +61 -8
- package/dist/provider.js +46 -7
- package/dist/providers/_shared/google/workspace.d.ts +56 -17
- package/dist/providers/_shared/google/workspace.js +34 -8
- package/dist/providers/_shared/rest/tools.js +2 -2
- package/dist/providers/_shared/rest/value-safety.d.ts +50 -0
- package/dist/providers/_shared/rest/value-safety.js +699 -7
- package/dist/providers/ccb/index.js +2 -2
- package/dist/providers/cloudflare/index.js +3 -3
- package/dist/providers/cloudflare/rest.js +25 -3
- package/dist/providers/cloudflare/skill.generated.js +1 -1
- package/dist/providers/cloudflare/value-safety.js +32 -0
- package/dist/providers/docs/index.js +4 -4
- package/dist/providers/docs/skill.generated.js +2 -2
- package/dist/providers/drive/index.js +4 -4
- package/dist/providers/drive/skill.generated.js +2 -2
- package/dist/providers/forms/index.js +4 -4
- package/dist/providers/forms/skill.generated.js +2 -2
- package/dist/providers/gmail/index.js +11 -9
- package/dist/providers/gmail/skill.generated.js +2 -2
- package/dist/providers/mixpanel/index.js +1 -1
- package/dist/providers/mixpanel/skill.generated.js +3 -3
- package/dist/providers/notion/index.d.ts +7 -0
- package/dist/providers/notion/index.js +100 -11
- package/dist/providers/notion/rest.js +45 -5
- package/dist/providers/notion/skill.generated.js +2 -2
- package/dist/providers/notion/value-safety.js +30 -5
- package/dist/providers/overflow/index.js +2 -2
- package/dist/providers/overflow/skill.generated.js +2 -2
- package/dist/providers/planning-center/index.js +2 -2
- package/dist/providers/planning-center/skill.generated.js +4 -4
- package/dist/providers/revenuecat/skill.generated.js +2 -2
- package/dist/providers/sheets/index.d.ts +3 -0
- package/dist/providers/sheets/index.js +7 -4
- package/dist/providers/sheets/skill.generated.js +2 -2
- package/dist/providers/slides/index.js +4 -4
- package/dist/providers/slides/skill.generated.js +2 -2
- package/dist/providers/stripe/rest.js +9 -2
- package/dist/providers/stripe/skill.generated.js +1 -1
- package/dist/providers/stripe/value-safety.js +22 -0
- package/dist/providers/tithely/index.js +1 -1
- package/dist/providers/vercel/index.js +1 -1
- package/dist/providers/vercel/rest.js +20 -2
- package/dist/providers/vercel/skill.generated.js +2 -2
- package/dist/providers/vercel/value-safety.js +22 -0
- package/dist/registry.d.ts +2 -3
- package/dist/registry.js +23 -9
- package/dist/routes/access-tokens.js +82 -75
- package/dist/routes/activity-disclosure.js +17 -18
- package/dist/routes/activity.js +34 -54
- package/dist/routes/actor-labels.js +33 -4
- package/dist/routes/agent-path.js +43 -0
- package/dist/routes/connect.js +16 -12
- package/dist/routes/credentials.js +16 -40
- package/dist/routes/mcp.js +161 -104
- package/dist/routes/oauth-management.js +11 -5
- package/dist/routes/oauth.js +5 -11
- package/dist/routes/operator.js +24 -23
- package/dist/routes/shared.d.ts +60 -20
- package/dist/routes/shared.js +187 -96
- package/dist/routes/ui-config.js +437 -97
- package/dist/routes/ui-data.js +2 -2
- package/dist/routes/ui.js +9 -16
- package/dist/runtime/call-admission.js +9 -0
- package/dist/server.js +5 -0
- package/dist/skills.js +10 -0
- package/dist/storage/keys.js +9 -1
- package/dist/storage/sql.js +5 -1
- package/dist/types.d.ts +29 -7
- package/dist/ui.d.ts +1 -1
- package/dist/ui.js +23 -16
- package/dist/usage-guide.js +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/workspace-address.js +9 -0
- package/dist/workspace-subject.js +23 -0
- package/documentation/README.md +47 -23
- package/documentation/architecture.md +371 -61
- package/documentation/auth.md +897 -249
- package/documentation/code-mode.md +37 -16
- package/documentation/deploying.md +126 -25
- package/documentation/integrating.md +97 -23
- package/documentation/meta-tools.md +50 -31
- package/documentation/migration-0.33.md +352 -0
- package/documentation/migration-0.34.md +67 -0
- package/documentation/operating.md +3 -1
- package/documentation/operator-tests.md +147 -34
- package/documentation/operator-ui.md +519 -64
- package/documentation/provider-auth-migration.md +37 -23
- package/documentation/provider-migration-0.29.md +2 -2
- package/examples/worker/AGENTS.md +37 -9
- package/examples/worker/README.md +127 -61
- package/examples/worker/src/connecta.config.ts +40 -23
- package/examples/worker/wrangler.jsonc +4 -1
- package/package.json +19 -18
- package/templates/node/.env.example +3 -0
- package/templates/node/AGENTS.md +33 -6
- package/templates/node/Dockerfile +2 -2
- package/templates/node/README.md +80 -52
- package/templates/node/docker-compose.yml +3 -2
- package/templates/node/package.json +4 -3
- package/templates/node/src/adopt-token.ts +23 -0
- package/templates/node/src/connecta.config.ts +28 -12
- package/templates/node/src/rotate-token.ts +17 -0
- package/templates/node/src/provision-token.ts +0 -17
|
@@ -2,17 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
Use this upgrade guide when moving a Stripe, Notion, Vercel, or Cloudflare
|
|
4
4
|
deployment from 0.30 to 0.31, where `auth` selects each provider's
|
|
5
|
-
implementation
|
|
6
|
-
The [0.31.0 release notes](https://github.com/zackbart/connecta/blob/main/release-notes/0.31.0.md) summarize the change.
|
|
5
|
+
implementation.
|
|
7
6
|
[Deployment upgrades](./deploying.md#upgrade-an-existing-deployment) cover other
|
|
8
7
|
version changes; [integrating services](./integrating.md) covers new connectors.
|
|
9
8
|
|
|
10
9
|
A dual provider requires `auth`. `{ type: "oauth" }` connects the vendor's
|
|
11
10
|
hosted MCP server, OAuth only. A key type connects Connecta's REST connector
|
|
12
11
|
with an operator-managed credential. There is no default, and one connector id
|
|
13
|
-
uses one implementation: configure two ids for both.
|
|
14
|
-
[decision record](https://github.com/zackbart/connecta/blob/main/decisions/0005-auth-selects-implementation.md)
|
|
15
|
-
explains why.
|
|
12
|
+
uses one implementation: configure two ids for both.
|
|
16
13
|
|
|
17
14
|
## Stripe
|
|
18
15
|
|
|
@@ -62,6 +59,10 @@ contracts: search finds operations in a pinned API index, every call is
|
|
|
62
59
|
checked against that index before it is sent, results arrive as
|
|
63
60
|
`{ status, data, page? }`, and POST writes send the caller's `idempotencyKey`
|
|
64
61
|
or a generated one as `Idempotency-Key` and return it (DELETE sends none).
|
|
62
|
+
Caller-supplied keys may contain up to 255 characters. An ambiguous POST write
|
|
63
|
+
also returns the key in `uncertainCall.recovery.idempotencyKey`, including when
|
|
64
|
+
the call deadline interrupts it. See [argument recovery](./meta-tools.md#argument-recovery)
|
|
65
|
+
before retrying.
|
|
65
66
|
Every request, v1 and v2, sends `Stripe-Version: 2026-09-30.endive`, the
|
|
66
67
|
version of the pinned index, whatever the account's default API version, so
|
|
67
68
|
response shapes and accepted parameters follow that version. Check fields
|
|
@@ -73,9 +74,7 @@ A key whose `sk_live_`/`rk_live_` or `sk_test_`/`rk_test_` prefix contradicts
|
|
|
73
74
|
Lost on the key path: natural-language Sigma (`stripe_analytics`), metrics,
|
|
74
75
|
documentation search, the implementation planner, reports, and feedback exist
|
|
75
76
|
only on the hosted OAuth connection. Programs calling those tools on a key
|
|
76
|
-
connector need an OAuth connector beside it.
|
|
77
|
-
[Stripe skill](https://github.com/zackbart/connecta/blob/main/src/providers/stripe/SKILL.md)
|
|
78
|
-
owns the conventions for both.
|
|
77
|
+
connector need an OAuth connector beside it. Read the connector runtime guide with `connecta.skill("connector:<id>")` in `execute_code` for its usage conventions.
|
|
79
78
|
|
|
80
79
|
## Notion
|
|
81
80
|
|
|
@@ -101,6 +100,15 @@ connectors: [
|
|
|
101
100
|
| `integration_list_comments`, `integration_add_comment` | `notion_api_read` `GET /v1/comments`; `notion_api_write` `POST /v1/comments`. |
|
|
102
101
|
| `integration_update_page_properties`, `integration_trash_page` | `notion_api_write` `PATCH /v1/pages/{page_id}` with `properties`, or `in_trash` to trash or restore. |
|
|
103
102
|
|
|
103
|
+
Both auth variants accept optional `callAdmission`. On a token connector it
|
|
104
|
+
replaces the whole default policy of 180 calls per minute and 3 concurrent
|
|
105
|
+
per runtime. Malformed policies throw at construction. Notion's
|
|
106
|
+
[request limits](https://developers.notion.com/reference/request-limits) allow
|
|
107
|
+
600 requests per minute per connection on Business and Enterprise and 180 on
|
|
108
|
+
other plans, with a separate workspace-wide limit shared by all connections.
|
|
109
|
+
Account for other runtimes and tools that make multiple HTTP requests when
|
|
110
|
+
choosing an override.
|
|
111
|
+
|
|
104
112
|
The token connector gains Connecta's generic REST tools over Notion's pinned
|
|
105
113
|
API index (`notion_api_search`, `notion_api_details`, `notion_api_read`,
|
|
106
114
|
`notion_api_write`), so every public operation is reachable with the bot's
|
|
@@ -119,8 +127,7 @@ duplication, team and skill search, attachment downloads, or page-to-skill
|
|
|
119
127
|
conversion. An OAuth connector acts as the user, and has none of the generic
|
|
120
128
|
REST tools or the `integration_*` projections and authoring helpers. Configure
|
|
121
129
|
both ids when a deployment needs both; a failed call is never retried on the
|
|
122
|
-
other.
|
|
123
|
-
owns the conventions for both.
|
|
130
|
+
other. Read the connector runtime guide with `connecta.skill("connector:<id>")` in `execute_code` for its usage conventions.
|
|
124
131
|
|
|
125
132
|
## Vercel
|
|
126
133
|
|
|
@@ -156,7 +163,7 @@ variable tools (`list_project_env_vars`, `upsert_project_env_var`,
|
|
|
156
163
|
(the runtime stream, stopped after `waitMs` or `maxRows`), and
|
|
157
164
|
`vercel_api_upload`.
|
|
158
165
|
|
|
159
|
-
Value safety follows a reviewed table
|
|
166
|
+
Value safety follows a reviewed table bundled with the connector.
|
|
160
167
|
Every operation whose response schema in the pinned spec may carry a credential
|
|
161
168
|
or a stored secret has a verdict: refused (credential minting, Connect
|
|
162
169
|
authorization, decrypted environment values, Global Config items and tokens,
|
|
@@ -186,9 +193,7 @@ The hosted connection now lists `filter_project_envs`, `get_project_env`,
|
|
|
186
193
|
return decrypted values, so they are reviewed as writes, and a `readOnly`
|
|
187
194
|
endpoint refuses them. Vercel admits only reviewed and approved MCP clients to its
|
|
188
195
|
hosted server; if authorization is refused for that reason, the deployment
|
|
189
|
-
needs Vercel's approval or a token connector.
|
|
190
|
-
[Vercel skill](https://github.com/zackbart/connecta/blob/main/src/providers/vercel/SKILL.md)
|
|
191
|
-
owns the conventions for both.
|
|
196
|
+
needs Vercel's approval or a token connector. Read the connector runtime guide with `connecta.skill("connector:<id>")` in `execute_code` for its usage conventions.
|
|
192
197
|
|
|
193
198
|
## Cloudflare
|
|
194
199
|
|
|
@@ -254,9 +259,7 @@ Lost on each path. OAuth has no index validation, named tools, GraphQL tool,
|
|
|
254
259
|
upload tool, or pin; Cloudflare's OAuth grant is the only boundary. A key has
|
|
255
260
|
no hosted `search` over Cloudflare's live OpenAPI document; the pinned index
|
|
256
261
|
replaces it and `providers:check` reports when it falls behind. A Global API
|
|
257
|
-
Key cannot reach R2, which accepts API tokens only.
|
|
258
|
-
[Cloudflare skill](https://github.com/zackbart/connecta/blob/main/src/providers/cloudflare/SKILL.md)
|
|
259
|
-
owns the conventions for both.
|
|
262
|
+
Key cannot reach R2, which accepts API tokens only. Read the connector runtime guide with `connecta.skill("connector:<id>")` in `execute_code` for its usage conventions.
|
|
260
263
|
|
|
261
264
|
## Value safety on every key connector
|
|
262
265
|
|
|
@@ -289,12 +292,16 @@ one; read or rotate withheld secrets in the vendor's dashboard.
|
|
|
289
292
|
Failures of credential-bearing operations keep Stripe's type, code, and
|
|
290
293
|
param but not its message. Create client-side sessions and links from your
|
|
291
294
|
own server code.
|
|
292
|
-
- **Notion** results withhold the
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
295
|
+
- **Notion** REST results and error text withhold the whole query and
|
|
296
|
+
fragment of canonical Notion file links, including links embedded in
|
|
297
|
+
Markdown and async task results. External proxy URLs keep their bytes;
|
|
298
|
+
AWS and Google signing-parameter values are withheld at any host. Writes
|
|
299
|
+
carrying the plain or encoded `[redacted]` placeholder in a Notion file
|
|
300
|
+
link's own query or fragment are refused before dispatch. See the
|
|
301
|
+
connector runtime guide through `connecta.skill("connector:<id>")` in `execute_code` for recognized hosts and scanning limits. Credential-named fields,
|
|
302
|
+
including database properties named like credentials, read as
|
|
303
|
+
`"[redacted]"`. Failures of the OAuth, file upload, bot user, and agent
|
|
304
|
+
operations keep Notion's code but not its message.
|
|
298
305
|
- **Vercel** replaces environment values with `"[redacted]"` instead of
|
|
299
306
|
dropping the field, and withholds Vercel's error text for every reviewed
|
|
300
307
|
operation and every operation whose request takes a credential-named
|
|
@@ -306,3 +313,10 @@ one; read or rotate withheld secrets in the vendor's dashboard.
|
|
|
306
313
|
destinations to their scheme and host. A credential-named field now loses
|
|
307
314
|
its whole value, not only its strings (a `cookies` list, a variable named
|
|
308
315
|
`API_KEY`).
|
|
316
|
+
|
|
317
|
+
## Contributor reference
|
|
318
|
+
|
|
319
|
+
[Decision 0005](https://github.com/zackbart/connecta/blob/main/decisions/0005-auth-selects-implementation.md)
|
|
320
|
+
explains why auth selects the implementation. Maintained provider source
|
|
321
|
+
skills and review tables live under `src/providers/` in the repository;
|
|
322
|
+
`src/providers/vercel/value-safety.ts` owns Vercel's reviewed table.
|
|
@@ -7,8 +7,8 @@ version changes; [integrating services](./integrating.md) covers new connectors.
|
|
|
7
7
|
|
|
8
8
|
This is the Phase 1 item 5d migration input for [Phase 5 release #709](https://github.com/zackbart/connecta/issues/709).
|
|
9
9
|
Deploy it with the consolidated 0.29 release, not while the rework is in progress.
|
|
10
|
-
|
|
11
|
-
connector ids
|
|
10
|
+
Deployments that use Notion or Cloudflare must check their actual grants and
|
|
11
|
+
connector ids in deployment configuration before that release.
|
|
12
12
|
The provider audit establishes available auth modes, not production OAuth grants.
|
|
13
13
|
|
|
14
14
|
Cloudflare's part of this guide is superseded: `cloudflare()` now selects its
|
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
This repository is deployment configuration, not a copy of Connecta itself.
|
|
4
4
|
|
|
5
|
+
Start every operator task at
|
|
6
|
+
`node_modules/@zackbart/connecta/documentation/README.md#operator-tasks`.
|
|
7
|
+
That installed index routes adding/removing connectors, organizing agent pools,
|
|
8
|
+
adding people, connecting shared credentials, issuing/rotating/revoking agent
|
|
9
|
+
tokens, upgrading, and diagnosis with `connecta doctor` to their procedures.
|
|
10
|
+
|
|
5
11
|
- Edit `src/connecta.config.ts` for connectors, authentication, storage, public
|
|
6
12
|
URL, and optional modules. `src/index.ts` only starts it. Set plain vars
|
|
7
13
|
`CONNECTA_ACTIVITY="on"` for preserved activity.
|
|
@@ -9,8 +15,8 @@ This repository is deployment configuration, not a copy of Connecta itself.
|
|
|
9
15
|
always installed over the same `CONNECTA_DB` for machines. Cloudflare Access
|
|
10
16
|
admits the request before the Worker runs; a service identity alone is
|
|
11
17
|
refused inside connecta. Do not add JWT parsing or another identity gate.
|
|
12
|
-
|
|
13
|
-
|
|
18
|
+
Signed-in maintainers alone manage shared credentials and agent tokens; pool
|
|
19
|
+
members connect only their own accounts on personal connectors in their pools.
|
|
14
20
|
- Attach Access to the Worker itself, not only its hostname. Enable Managed
|
|
15
21
|
OAuth on that Access application. CIMD is the spec's preferred client
|
|
16
22
|
registration; enable DCR as the fallback Access currently requires.
|
|
@@ -57,21 +63,43 @@ This repository is deployment configuration, not a copy of Connecta itself.
|
|
|
57
63
|
Do not copy or modify Connecta package internals here.
|
|
58
64
|
- Prefer `api()` when the agent must see an exact reviewed capability set;
|
|
59
65
|
`remoteMcp()` follows the downstream server's evolving tool catalog.
|
|
60
|
-
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
66
|
+
- Agents (unattended clients) use `<PUBLIC_URL>/agent/<pool>` with a stored
|
|
67
|
+
`cta_` bearer as their only credential. That needs one self-hosted Access
|
|
68
|
+
application per hostname for `<host>/agent/*` with a single Bypass policy,
|
|
69
|
+
beside the Worker-level application (README.md § "Let agents through
|
|
70
|
+
Access"). Never bypass any other path. `/mcp` and `/mcp/<pool>` refuse `cta_`.
|
|
71
|
+
`connecta doctor` also reads `/health` behind Access: set
|
|
72
|
+
`CF_ACCESS_CLIENT_ID`, `CF_ACCESS_CLIENT_SECRET`, and `CONNECTA_TOKEN`
|
|
73
|
+
together, and pass `--pool ci`, a pool that lists the agent.
|
|
74
|
+
Machine clients are the `agents` declared in `src/connecta.config.ts`. Issue
|
|
75
|
+
or rotate a token through the operator Tokens page as a signed-in maintainer or trusted
|
|
76
|
+
`AccessTokenManager.rotate` tooling against this same D1 storage, as README
|
|
65
77
|
"Machine tokens" describes. Never configure a static bearer or open startup.
|
|
66
78
|
UI, vault, and activity use explicit optional imports;
|
|
67
|
-
auth changes require
|
|
79
|
+
auth changes require a maintainer, or a pool member for their own personal account.
|
|
80
|
+
- Organize agent pools by connecta's agent pool layout:
|
|
81
|
+
`node_modules/@zackbart/connecta/documentation/auth.md#organizing-an-agents-pools`
|
|
82
|
+
([online](https://github.com/zackbart/connecta/blob/main/documentation/auth.md#organizing-an-agents-pools)).
|
|
83
|
+
Each agent keeps one Connecta connection whose harness, never the model,
|
|
84
|
+
picks the pool per turn. Tiers are nested pools of shared connectors with
|
|
85
|
+
no `owner`, each spreading the tool list below. Recommended names are
|
|
86
|
+
`<agent>` for the lowest and `<agent>-<tier>` above it; any named pool,
|
|
87
|
+
including an existing `team` or `leadership` pool, may be a tier if all its
|
|
88
|
+
human members are cleared for it. A chat gets the most capable tier everyone
|
|
89
|
+
present is cleared for, and the lowest when anyone present is unknown.
|
|
90
|
+
`<agent>-<user>` (that user's highest tier plus their own connector ids,
|
|
91
|
+
`owner` set to their Workspace address) is used only in a one-on-one with
|
|
92
|
+
that user. List only cleared people in a tier, and never another person in
|
|
93
|
+
a `<agent>-<user>` pool: its per-user connectors act as that user for every
|
|
94
|
+
member. Never add a second Connecta connection or mount downstream tools
|
|
95
|
+
directly.
|
|
68
96
|
- Brand the operator UI in `operatorUi({ branding })`: product and owner names,
|
|
69
97
|
description, favicon, and `theme` (`accent`, `radius`, `fontFamily`,
|
|
70
98
|
`monoFamily`, `colorScheme`). Ask the deployment's owner for their brand
|
|
71
99
|
rather than leaving the default. README "UI and encrypted credentials" shows
|
|
72
100
|
the shape.
|
|
73
101
|
- After configuration changes, typecheck: inside the connecta repository that
|
|
74
|
-
is `
|
|
102
|
+
is `pnpm run check:examples`; a copied deployment runs its own `tsc --noEmit`.
|
|
75
103
|
After deployment, connect both Claude and ChatGPT to `<PUBLIC_URL>/mcp` and
|
|
76
104
|
complete their browser authorization flows before calling setup complete.
|
|
77
105
|
|
|
@@ -11,7 +11,8 @@ A deployable Worker that aggregates a downstream remote MCP and an in-code HTTP
|
|
|
11
11
|
API connector, guarded by Cloudflare Access. It uses three Cloudflare resources
|
|
12
12
|
and nothing else: one D1 database (`CONNECTA_DB`) for every piece of state, the
|
|
13
13
|
Worker Loader binding (`LOADER`) behind the six-tool surface, which requires
|
|
14
|
-
the Workers Paid plan, and
|
|
14
|
+
the Workers Paid plan, and two secrets: `DOWNSTREAM_TOKEN` (the example remote
|
|
15
|
+
MCP connector's token) and `CREDENTIAL_ENCRYPTION_KEY` (the credential vault).
|
|
15
16
|
|
|
16
17
|
This is also the **starting template for a deployment**: a real deployment
|
|
17
18
|
should be its own repository that pins an exact `@zackbart/connecta` version and
|
|
@@ -46,9 +47,11 @@ This example has no `package.json` of its own — it resolves the installed
|
|
|
46
47
|
package from the repository root.
|
|
47
48
|
|
|
48
49
|
```sh
|
|
49
|
-
|
|
50
|
+
pnpm install # from the repository root
|
|
50
51
|
|
|
51
52
|
wrangler d1 create connecta # paste the id into wrangler.jsonc
|
|
53
|
+
# In wrangler.jsonc also set PUBLIC_URL to this Worker's URL and
|
|
54
|
+
# CONNECTA_MAINTAINERS to your Access user ids (user_uuid, else email).
|
|
52
55
|
|
|
53
56
|
cd examples/worker
|
|
54
57
|
wrangler secret put DOWNSTREAM_TOKEN
|
|
@@ -81,10 +84,10 @@ attempt and add the narrowest matching entry rather than allowing its entire
|
|
|
81
84
|
origin.
|
|
82
85
|
|
|
83
86
|
Access then serves OAuth discovery and turns the client's opaque token into the
|
|
84
|
-
trusted human `ctx.access` identity connecta reads. A cron job or CI client
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
See [Machine tokens](#machine-tokens).
|
|
87
|
+
trusted human `ctx.access` identity connecta reads. A cron job or CI client is
|
|
88
|
+
an agent: it uses `/agent/<pool>` with a stored `cta_` bearer as its only
|
|
89
|
+
credential, once [the agent bypass](#let-agents-through-access) exists. An
|
|
90
|
+
Access service identity alone is refused. See [Machine tokens](#machine-tokens).
|
|
88
91
|
|
|
89
92
|
Through the API, the relevant part of the application is:
|
|
90
93
|
|
|
@@ -112,8 +115,36 @@ owns client registration, redirect allowlists, and token lifetimes.
|
|
|
112
115
|
working in a copied deployment. Do not remove the entries there when changing
|
|
113
116
|
the Access policy or application.
|
|
114
117
|
|
|
118
|
+
### Let agents through Access
|
|
119
|
+
|
|
120
|
+
Add one more self-hosted Access application for each hostname agents use (the
|
|
121
|
+
`workers.dev` hostname and each custom domain): domain set to that hostname,
|
|
122
|
+
path `agent/*`, and a single policy whose action is **Bypass** and whose include
|
|
123
|
+
rule is **Everyone**. Keep the Worker-level application; it still protects every
|
|
124
|
+
other path. Through the API:
|
|
125
|
+
|
|
126
|
+
```json
|
|
127
|
+
{
|
|
128
|
+
"type": "self_hosted",
|
|
129
|
+
"name": "connecta agents",
|
|
130
|
+
"destinations": [{ "type": "public", "uri": "connecta.example.com/agent/*" }],
|
|
131
|
+
"policies": [{ "name": "agents bypass", "decision": "bypass", "include": [{ "everyone": {} }] }]
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
It must be a hostname-and-path (`public`) destination: a second Worker
|
|
136
|
+
destination is refused because the Worker-level application owns it. Changes
|
|
137
|
+
took 15–19 seconds to settle when probed, occasionally longer, with transient
|
|
138
|
+
edge errors meanwhile. Do not rely on a fixed wait: verify that `/agent/ci`
|
|
139
|
+
without credentials returns connecta's 401 (`WWW-Authenticate: Bearer`) while
|
|
140
|
+
`/mcp` still returns Access's refusal, several times in a row. Connecta ignores Access
|
|
141
|
+
context on `/agent/*` and refuses every other spelling of that namespace before
|
|
142
|
+
auth. [Deploying Connecta](https://github.com/zackbart/connecta/blob/main/documentation/deploying.md#agent-endpoints-behind-cloudflare-access)
|
|
143
|
+
records the untested cases and the propagation details.
|
|
144
|
+
|
|
115
145
|
The checked-in `access.dev` block gives `wrangler dev` a local operator
|
|
116
|
-
identity
|
|
146
|
+
identity; it requires Wrangler 4.123.0 or later, and earlier versions ignore it
|
|
147
|
+
with an unexpected-field warning. Remove the block to test the missing-Access refusal. It has no effect
|
|
117
148
|
on a deployed Worker's production identity.
|
|
118
149
|
|
|
119
150
|
### Optional resource management with Alchemy
|
|
@@ -201,12 +232,34 @@ Access adoption or preserve production identity.
|
|
|
201
232
|
|
|
202
233
|
### Copied into its own repository
|
|
203
234
|
|
|
204
|
-
The `
|
|
235
|
+
The `pnpm install` above is the connecta repository's, which already has every
|
|
205
236
|
dependency this file imports. A copy with its own `package.json` installs
|
|
206
237
|
Connecta and the separately installed `@cloudflare/codemode` peer:
|
|
207
238
|
|
|
208
239
|
```sh
|
|
209
|
-
npm install @zackbart/connecta
|
|
240
|
+
npm install --save-exact @zackbart/connecta@<version>
|
|
241
|
+
npm install @cloudflare/codemode
|
|
242
|
+
npm install --save-dev wrangler @cloudflare/workers-types typescript @types/node
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
A `tsconfig.json` like the following lets `tsc --noEmit` resolve `D1Database`,
|
|
246
|
+
`WorkerLoader`, and `ExecutionContext`. `wrangler` also serves
|
|
247
|
+
`scripts/copy-kv-to-d1.mjs`.
|
|
248
|
+
|
|
249
|
+
```json
|
|
250
|
+
{
|
|
251
|
+
"compilerOptions": {
|
|
252
|
+
"target": "ES2022",
|
|
253
|
+
"module": "ES2022",
|
|
254
|
+
"moduleResolution": "Bundler",
|
|
255
|
+
"lib": ["ES2022"],
|
|
256
|
+
"types": ["@cloudflare/workers-types", "node"],
|
|
257
|
+
"strict": true,
|
|
258
|
+
"skipLibCheck": true,
|
|
259
|
+
"noEmit": true
|
|
260
|
+
},
|
|
261
|
+
"include": ["src/**/*.ts"]
|
|
262
|
+
}
|
|
210
263
|
```
|
|
211
264
|
|
|
212
265
|
`@cloudflare/codemode` is the optional peer behind `execute_code`, declared in
|
|
@@ -219,57 +272,63 @@ discover the skew in production ([#376](https://github.com/zackbart/connecta/iss
|
|
|
219
272
|
no Clerk import, secret, package, or fallback provider. Docker deployments keep
|
|
220
273
|
the Clerk path in the Node template.
|
|
221
274
|
|
|
222
|
-
Then
|
|
223
|
-
`
|
|
224
|
-
|
|
275
|
+
Then list the maintainers' Access user ids (`user_uuid`, else email) in the
|
|
276
|
+
`CONNECTA_MAINTAINERS` var and point a maintainer's MCP client at
|
|
277
|
+
`<PUBLIC_URL>/mcp`. Other people use `<PUBLIC_URL>/mcp/<pool>`, and agents
|
|
278
|
+
`<PUBLIC_URL>/agent/<pool>`, for a pool that lists them in `members`. The example explicitly enables
|
|
279
|
+
`ui: operatorUi()`; open `<PUBLIC_URL>/` for endpoints, and each connector's Connection tab
|
|
280
|
+
(`/connectors/<id>`) for its authentication controls. The page labels tool safety, offers fixed repair
|
|
225
281
|
prompts for classified failures, and shows client setup commands for endpoints
|
|
226
282
|
the signed-in person may use. Those commands contain no token. There is no
|
|
227
|
-
separate Credentials tab. The
|
|
228
|
-
|
|
283
|
+
separate Credentials tab. The Tokens page, listing one token slot per
|
|
284
|
+
declared agent, is available to signed-in maintainers.
|
|
229
285
|
|
|
230
286
|
## Select optional modules
|
|
231
287
|
|
|
232
288
|
`cloudflareAccessAuth()` reads trusted identity after Access admits the Worker
|
|
233
|
-
request.
|
|
234
|
-
|
|
235
|
-
|
|
289
|
+
request. Maintainers use plain `/mcp` and the operator pages; people in a pool
|
|
290
|
+
use `/mcp/<pool>`, and agents in it `/agent/<pool>`, which serve exactly that
|
|
291
|
+
pool's tools. Agents authenticate with `accessTokens(storage)` over the same D1
|
|
292
|
+
database; human endpoints refuse their tokens, and Access service headers alone
|
|
293
|
+
never grant MCP access or interactive authority.
|
|
236
294
|
Keep users, groups, and admission in Access. Connector visibility and management
|
|
237
295
|
permissions belong in `src/connecta.config.ts`.
|
|
238
296
|
|
|
239
|
-
`
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
remain deployment configuration. `activityAccess` governs global history reads.
|
|
246
|
-
`accessTokenManagement` separately allows interactive operators to create, rename,
|
|
247
|
-
and revoke machine tokens. This example grants that permission to every signed-in
|
|
248
|
-
human, matching its connector-management permissions; narrow all three for a team.
|
|
297
|
+
`maintainers` and each pool's `members` select who reaches which endpoint and
|
|
298
|
+
who manages what. Signed-in maintainers alone administer shared credentials
|
|
299
|
+
and OAuth grants, issue, rotate, and revoke agent tokens, and read activity.
|
|
300
|
+
A pool member connects their own account only on connectors configured with
|
|
301
|
+
`authScope: "personal"` in their pools. Static headers remain deployment
|
|
302
|
+
configuration.
|
|
249
303
|
See [inbound identity](../../documentation/auth.md#principals-visibility-and-operators).
|
|
250
304
|
|
|
251
305
|
### Machine tokens
|
|
252
306
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
307
|
+
Machine clients are agents declared by name in `agents` in
|
|
308
|
+
`src/connecta.config.ts`; this example declares `ci`. Each agent has one
|
|
309
|
+
`cta_` token held by `accessTokens(storage)` over `CONNECTA_DB`, with no new
|
|
310
|
+
binding. An agent with no issued token admits nothing. A maintainer (an Access
|
|
311
|
+
identity listed in `CONNECTA_MAINTAINERS`) signs in and issues the first token.
|
|
312
|
+
Open `<PUBLIC_URL>/`, select Tokens, and issue the agent's token. Save the
|
|
313
|
+
returned `cta_` secret privately; it is returned once. Rotating replaces it
|
|
314
|
+
immediately: the old secret stops on its next request. An agent has no human
|
|
315
|
+
principal, so personal connectors are absent for it; connector and pool rules
|
|
316
|
+
recognize it by `identity.agent` on every request. It never has interactive
|
|
317
|
+
operator authority. Removing a name from `agents` stops its token on the next
|
|
318
|
+
request.
|
|
319
|
+
|
|
320
|
+
An agent connects to `<PUBLIC_URL>/agent/<pool>` for a pool that lists it and
|
|
321
|
+
sends one header:
|
|
262
322
|
|
|
263
323
|
```text
|
|
264
|
-
CF-Access-Client-Id: <access-service-client-id>
|
|
265
|
-
CF-Access-Client-Secret: <access-service-client-secret>
|
|
266
324
|
Authorization: Bearer <stored-cta-token>
|
|
267
325
|
```
|
|
268
326
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
327
|
+
[The agent bypass](#let-agents-through-access) lets the request past the edge;
|
|
328
|
+
connecta verifies the bearer against D1 and ignores any Access context or
|
|
329
|
+
headers there. `/mcp` and `/mcp/<pool>` refuse the token. Doctor also reads
|
|
330
|
+
`/health`, which stays behind Access, so it needs Access service credentials
|
|
331
|
+
too; see [Client authentication and activity](#client-authentication-and-activity).
|
|
273
332
|
|
|
274
333
|
For programmatic bootstrap, trusted provisioning code that already holds this
|
|
275
334
|
deployment's D1 binding can use the published API against that same storage:
|
|
@@ -278,16 +337,18 @@ deployment's D1 binding can use the published API against that same storage:
|
|
|
278
337
|
import { AccessTokenManager } from "@zackbart/connecta/auth/access-tokens";
|
|
279
338
|
import { d1Storage } from "@zackbart/connecta/d1";
|
|
280
339
|
|
|
281
|
-
const manager = new AccessTokenManager(d1Storage(env.CONNECTA_DB));
|
|
282
|
-
const { token } = await manager.
|
|
340
|
+
const manager = new AccessTokenManager(d1Storage(env.CONNECTA_DB), { agents: ["ci"] });
|
|
341
|
+
const { token } = await manager.rotate("ci", "trusted-provisioning");
|
|
283
342
|
// Deliver token once to the client's secret store, outside logs and source control.
|
|
284
343
|
```
|
|
285
344
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
`
|
|
345
|
+
Provision only through trusted operator tooling; do not expose this code as a
|
|
346
|
+
public route or rotate a token at startup. Tokens issued before agents survive a
|
|
347
|
+
state migration into this same D1 namespace but stop admitting until trusted
|
|
348
|
+
tooling binds each machine's token once with
|
|
349
|
+
`manager.adopt(tokenId, "ci")`, which keeps its secret working. Human-bound
|
|
350
|
+
tokens cannot be adopted; issue the agent a new token instead. Keep
|
|
351
|
+
`accessTokens(storage)` configured over the same storage.
|
|
291
352
|
|
|
292
353
|
### UI and encrypted credentials
|
|
293
354
|
|
|
@@ -323,11 +384,13 @@ does not create credentials or permissions by itself.
|
|
|
323
384
|
|
|
324
385
|
### Client authentication and activity
|
|
325
386
|
|
|
326
|
-
Interactive MCP clients use Access Managed OAuth.
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
and
|
|
330
|
-
Keep
|
|
387
|
+
Interactive MCP clients use Access Managed OAuth. Agents send only a declared
|
|
388
|
+
agent's `cta_` bearer to `/agent/<pool>`, issued as described in
|
|
389
|
+
[Machine tokens](#machine-tokens). `accessTokens(storage)` is always
|
|
390
|
+
enabled, and every signed-in maintainer manages agent tokens.
|
|
391
|
+
Keep maintainers, pools, and their members in deployment code. An agent reaches
|
|
392
|
+
only `/agent/<pool>` for a pool that lists it (the example's `ci` pool lists
|
|
393
|
+
`agent:ci`); `/mcp` and `/mcp/<pool>` refuse its token.
|
|
331
394
|
|
|
332
395
|
Activity uses `activityHistory({ store: d1ActivityStore(env.CONNECTA_DB) })`,
|
|
333
396
|
with `activityHistory` from `@zackbart/connecta/activity` and `d1ActivityStore`
|
|
@@ -335,13 +398,15 @@ from `@zackbart/connecta/d1`. See [Activity history](#activity-history-optional)
|
|
|
335
398
|
Omit the module and store wiring to record no history and show no Activity tab. Diagnostics remain independent; `logger: "silent"` suppresses
|
|
336
399
|
them explicitly.
|
|
337
400
|
|
|
338
|
-
Verify MCP health and the exact six tools with
|
|
401
|
+
Verify MCP health and the exact six tools with the following. Doctor reads
|
|
402
|
+
`/health` through Access with the service credentials, then checks `/agent/ci`
|
|
403
|
+
with the `cta_` token alone:
|
|
339
404
|
|
|
340
405
|
```sh
|
|
341
406
|
CF_ACCESS_CLIENT_ID='REPLACE_WITH_ACCESS_CLIENT_ID' \
|
|
342
407
|
CF_ACCESS_CLIENT_SECRET='REPLACE_WITH_ACCESS_CLIENT_SECRET' \
|
|
343
408
|
CONNECTA_TOKEN='cta_REPLACE_WITH_STORED_SECRET' \
|
|
344
|
-
connecta doctor --url
|
|
409
|
+
npx connecta doctor --url https://connecta.example.workers.dev --pool ci
|
|
345
410
|
```
|
|
346
411
|
|
|
347
412
|
Doctor reports the configured `DynamicWorkerExecutor`, not a presumed Node
|
|
@@ -400,7 +465,8 @@ CREATE TABLE IF NOT EXISTS connecta_kv (
|
|
|
400
465
|
);
|
|
401
466
|
CREATE INDEX IF NOT EXISTS connecta_kv_expiry ON connecta_kv (expires_at_ms);
|
|
402
467
|
-- tool_call_activity: one row per completed call, keyset-paged on
|
|
403
|
-
-- (occurred_at_ms, id); see
|
|
468
|
+
-- (occurred_at_ms, id); see
|
|
469
|
+
-- https://github.com/zackbart/connecta/blob/main/src/storage/sql.ts
|
|
404
470
|
```
|
|
405
471
|
|
|
406
472
|
### Upgrading from 0.28
|
|
@@ -430,7 +496,7 @@ CREATE INDEX IF NOT EXISTS connecta_kv_expiry ON connecta_kv (expires_at_ms);
|
|
|
430
496
|
- **Workers KV** (`CONNECTA_KV` and `cloudflare-kv.ts`). Workers KV is no longer
|
|
431
497
|
supported: `createConnecta` refuses storage without `compareAndSet` at boot.
|
|
432
498
|
Copy its state into D1 once, as described below, so OAuth grants, vault
|
|
433
|
-
credentials, and `cta_` access
|
|
499
|
+
credentials, and `cta_` access token records carry over.
|
|
434
500
|
|
|
435
501
|
#### Copying Workers KV state into D1
|
|
436
502
|
|
|
@@ -462,7 +528,7 @@ then `wrangler login` and check the prepared deployment with a dry run.
|
|
|
462
528
|
1. Back up KV with a bulk export including values and expiration metadata.
|
|
463
529
|
Export D1 with `wrangler d1 export <db> --remote --output before-cutover.sql`.
|
|
464
530
|
Store backups securely and preserve the exact credential encryption key,
|
|
465
|
-
|
|
531
|
+
whatever secret name the deployment stores it under.
|
|
466
532
|
2. Block traffic using maintenance mode or turn the route off. Stop cron,
|
|
467
533
|
queue consumers, scheduled jobs, and every other KV/D1 writer. Drain all
|
|
468
534
|
in-flight requests, including OAuth callbacks and token refreshes.
|
|
@@ -488,8 +554,8 @@ then `wrangler login` and check the prepared deployment with a dry run.
|
|
|
488
554
|
invalid entry or mismatch. Keep traffic and writers stopped until these
|
|
489
555
|
counts are resolved. A verification pass does not rewrite copied entries.
|
|
490
556
|
5. Deploy the D1 configuration with `wrangler deploy` while maintenance remains.
|
|
491
|
-
Run `connecta doctor
|
|
492
|
-
bearer through `CONNECTA_TOKEN`. Verify an existing
|
|
557
|
+
Run `connecta doctor --pool <pool>` using Access service credentials plus a
|
|
558
|
+
stored `cta_` bearer through `CONNECTA_TOKEN`. Verify an existing
|
|
493
559
|
OAuth connector without re-consent, an existing `cta_` token, a connector
|
|
494
560
|
using a vault credential, and prior activity in the Activity view. Run
|
|
495
561
|
these controlled checks with other traffic and background writers blocked.
|