@zackbart/connecta 0.32.0 → 0.33.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 +63 -0
- package/README.md +15 -7
- 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/agent-identity.js +47 -0
- package/dist/auth/cloudflare-access.js +13 -5
- package/dist/call-admission-context.js +15 -0
- package/dist/call-admission.js +30 -43
- package/dist/call-recovery.js +6 -2
- package/dist/config-value-sources.js +11 -9
- package/dist/config.d.ts +37 -75
- package/dist/config.js +110 -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 +3 -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 +29 -7
- package/dist/describe-config.js +7 -17
- package/dist/index.d.ts +4 -3
- package/dist/index.js +29 -10
- package/dist/invocation.js +5 -3
- package/dist/membership.d.ts +51 -0
- package/dist/membership.js +121 -0
- package/dist/module-contracts.d.ts +23 -6
- 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/contract.d.ts +149 -28
- package/dist/operator-ui/endpoints.js +192 -0
- package/dist/operator-ui/fix-prompts.js +4 -4
- package/dist/operator-ui/generated.js +5 -4
- package/dist/operator-ui/member-page.js +112 -0
- package/dist/operator-ui/model.d.ts +14 -6
- package/dist/operator-ui/view.d.ts +84 -19
- package/dist/operator-ui/view.js +82 -21
- package/dist/page-styles.js +1 -1
- package/dist/provider.d.ts +61 -8
- package/dist/provider.js +46 -7
- package/dist/providers/_shared/google/workspace.d.ts +53 -16
- package/dist/providers/_shared/google/workspace.js +30 -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 +1 -1
- 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 +3 -3
- package/dist/providers/docs/skill.generated.js +2 -2
- package/dist/providers/drive/index.js +3 -3
- package/dist/providers/drive/skill.generated.js +2 -2
- package/dist/providers/forms/index.js +3 -3
- package/dist/providers/forms/skill.generated.js +2 -2
- package/dist/providers/gmail/index.js +10 -8
- package/dist/providers/gmail/skill.generated.js +2 -2
- package/dist/providers/mixpanel/index.js +1 -1
- 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 +1 -1
- package/dist/providers/planning-center/index.js +1 -1
- package/dist/providers/sheets/index.d.ts +3 -0
- package/dist/providers/sheets/index.js +6 -3
- package/dist/providers/sheets/skill.generated.js +2 -2
- package/dist/providers/slides/index.js +3 -3
- 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/vercel/rest.js +20 -2
- package/dist/providers/vercel/skill.generated.js +1 -1
- package/dist/providers/vercel/value-safety.js +22 -0
- package/dist/registry.d.ts +2 -3
- package/dist/registry.js +8 -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 +145 -95
- package/dist/routes/oauth-management.js +11 -5
- package/dist/routes/oauth.js +3 -9
- 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/storage/keys.js +9 -1
- package/dist/types.d.ts +11 -0
- package/dist/ui.d.ts +1 -1
- package/dist/ui.js +16 -14
- 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 +46 -22
- package/documentation/architecture.md +355 -50
- package/documentation/auth.md +775 -243
- package/documentation/code-mode.md +14 -11
- package/documentation/deploying.md +121 -24
- package/documentation/integrating.md +92 -21
- package/documentation/meta-tools.md +14 -9
- package/documentation/migration-0.33.md +344 -0
- package/documentation/operating.md +3 -1
- package/documentation/operator-tests.md +115 -28
- package/documentation/operator-ui.md +326 -61
- package/documentation/provider-auth-migration.md +37 -23
- package/documentation/provider-migration-0.29.md +2 -2
- package/examples/worker/AGENTS.md +30 -8
- package/examples/worker/README.md +92 -53
- package/examples/worker/src/connecta.config.ts +36 -20
- package/examples/worker/wrangler.jsonc +3 -0
- package/package.json +3 -2
- package/templates/node/.env.example +3 -0
- package/templates/node/AGENTS.md +27 -6
- package/templates/node/Dockerfile +2 -2
- package/templates/node/README.md +67 -42
- 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,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,14 +63,30 @@ 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 Access-authenticated operator page 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 client picks the pool per
|
|
84
|
+
turn: base pool `<agent>` (shared connectors, no `owner`) outside a
|
|
85
|
+
one-on-one, and `<agent>-<user>` (the base plus that user's own connector
|
|
86
|
+
ids, `owner` set to their Workspace address) only with that user. Never list
|
|
87
|
+
another person in a `<agent>-<user>` pool: its per-user connectors act as
|
|
88
|
+
that user for every member. Never add a second Connecta connection or mount
|
|
89
|
+
downstream tools directly.
|
|
68
90
|
- Brand the operator UI in `operatorUi({ branding })`: product and owner names,
|
|
69
91
|
description, favicon, and `theme` (`accent`, `radius`, `fontFamily`,
|
|
70
92
|
`monoFamily`, `colorScheme`). Ask the deployment's owner for their brand
|
|
@@ -81,10 +81,10 @@ attempt and add the narrowest matching entry rather than allowing its entire
|
|
|
81
81
|
origin.
|
|
82
82
|
|
|
83
83
|
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).
|
|
84
|
+
trusted human `ctx.access` identity connecta reads. A cron job or CI client is
|
|
85
|
+
an agent: it uses `/agent/<pool>` with a stored `cta_` bearer as its only
|
|
86
|
+
credential, once [the agent bypass](#let-agents-through-access) exists. An
|
|
87
|
+
Access service identity alone is refused. See [Machine tokens](#machine-tokens).
|
|
88
88
|
|
|
89
89
|
Through the API, the relevant part of the application is:
|
|
90
90
|
|
|
@@ -112,6 +112,33 @@ owns client registration, redirect allowlists, and token lifetimes.
|
|
|
112
112
|
working in a copied deployment. Do not remove the entries there when changing
|
|
113
113
|
the Access policy or application.
|
|
114
114
|
|
|
115
|
+
### Let agents through Access
|
|
116
|
+
|
|
117
|
+
Add one more self-hosted Access application for each hostname agents use (the
|
|
118
|
+
`workers.dev` hostname and each custom domain): domain set to that hostname,
|
|
119
|
+
path `agent/*`, and a single policy whose action is **Bypass** and whose include
|
|
120
|
+
rule is **Everyone**. Keep the Worker-level application; it still protects every
|
|
121
|
+
other path. Through the API:
|
|
122
|
+
|
|
123
|
+
```json
|
|
124
|
+
{
|
|
125
|
+
"type": "self_hosted",
|
|
126
|
+
"name": "connecta agents",
|
|
127
|
+
"destinations": [{ "type": "public", "uri": "connecta.example.com/agent/*" }],
|
|
128
|
+
"policies": [{ "name": "agents bypass", "decision": "bypass", "include": [{ "everyone": {} }] }]
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
It must be a hostname-and-path (`public`) destination: a second Worker
|
|
133
|
+
destination is refused because the Worker-level application owns it. Changes
|
|
134
|
+
took 15–19 seconds to settle when probed, occasionally longer, with transient
|
|
135
|
+
edge errors meanwhile. Do not rely on a fixed wait: verify that `/agent/ci`
|
|
136
|
+
without credentials returns connecta's 401 (`WWW-Authenticate: Bearer`) while
|
|
137
|
+
`/mcp` still returns Access's refusal, several times in a row. Connecta ignores Access
|
|
138
|
+
context on `/agent/*` and refuses every other spelling of that namespace before
|
|
139
|
+
auth. [Deploying Connecta](https://github.com/zackbart/connecta/blob/main/documentation/deploying.md#agent-endpoints-behind-cloudflare-access)
|
|
140
|
+
records the untested cases and the propagation details.
|
|
141
|
+
|
|
115
142
|
The checked-in `access.dev` block gives `wrangler dev` a local operator
|
|
116
143
|
identity. Remove the block to test the missing-Access refusal. It has no effect
|
|
117
144
|
on a deployed Worker's production identity.
|
|
@@ -219,57 +246,63 @@ discover the skew in production ([#376](https://github.com/zackbart/connecta/iss
|
|
|
219
246
|
no Clerk import, secret, package, or fallback provider. Docker deployments keep
|
|
220
247
|
the Clerk path in the Node template.
|
|
221
248
|
|
|
222
|
-
Then
|
|
249
|
+
Then list the maintainers' Access user ids (`user_uuid`, else email) in the
|
|
250
|
+
`CONNECTA_MAINTAINERS` var and point a maintainer's MCP client at
|
|
251
|
+
`<PUBLIC_URL>/mcp`. Other people use `<PUBLIC_URL>/mcp/<pool>`, and agents
|
|
252
|
+
`<PUBLIC_URL>/agent/<pool>`, for a pool that lists them in `members`. The example explicitly enables
|
|
223
253
|
`ui: operatorUi()`; open `<PUBLIC_URL>/` for Connections and each connection's
|
|
224
254
|
authentication controls. The page labels tool safety, offers fixed repair
|
|
225
255
|
prompts for classified failures, and shows client setup commands for endpoints
|
|
226
256
|
the signed-in person may use. Those commands contain no token. There is no
|
|
227
|
-
separate Credentials tab. The Access tokens page
|
|
228
|
-
interactive operators.
|
|
257
|
+
separate Credentials tab. The Access tokens page, listing one token slot per
|
|
258
|
+
declared agent, is available to permitted interactive operators.
|
|
229
259
|
|
|
230
260
|
## Select optional modules
|
|
231
261
|
|
|
232
262
|
`cloudflareAccessAuth()` reads trusted identity after Access admits the Worker
|
|
233
|
-
request.
|
|
234
|
-
|
|
235
|
-
|
|
263
|
+
request. Maintainers use plain `/mcp` and the operator pages; people in a pool
|
|
264
|
+
use `/mcp/<pool>`, and agents in it `/agent/<pool>`, which serve exactly that
|
|
265
|
+
pool's tools. Agents authenticate with `accessTokens(storage)` over the same D1
|
|
266
|
+
database; human endpoints refuse their tokens, and Access service headers alone
|
|
267
|
+
never grant MCP access or interactive authority.
|
|
236
268
|
Keep users, groups, and admission in Access. Connector visibility and management
|
|
237
269
|
permissions belong in `src/connecta.config.ts`.
|
|
238
270
|
|
|
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.
|
|
271
|
+
`maintainers` and each pool's `members` select who reaches which endpoint and
|
|
272
|
+
who manages what. Signed-in maintainers alone administer shared credentials
|
|
273
|
+
and OAuth grants, issue, rotate, and revoke agent tokens, and read activity.
|
|
274
|
+
A pool member connects their own account only on connectors configured with
|
|
275
|
+
`authScope: "personal"` in their pools. Static headers remain deployment
|
|
276
|
+
configuration.
|
|
249
277
|
See [inbound identity](../../documentation/auth.md#principals-visibility-and-operators).
|
|
250
278
|
|
|
251
279
|
### Machine tokens
|
|
252
280
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
281
|
+
Machine clients are agents declared by name in `agents` in
|
|
282
|
+
`src/connecta.config.ts`; this example declares `ci`. Each agent has one
|
|
283
|
+
`cta_` token held by `accessTokens(storage)` over `CONNECTA_DB`, with no new
|
|
284
|
+
binding. An agent with no issued token admits nothing. A human authenticated
|
|
285
|
+
through Access can still sign in and issue the first token. Open
|
|
286
|
+
`<PUBLIC_URL>/`, select Access tokens, and issue the agent's token. Save the
|
|
287
|
+
returned `cta_` secret privately; it is returned once. Rotating replaces it
|
|
288
|
+
immediately: the old secret stops on its next request. An agent has no human
|
|
289
|
+
principal, so personal connectors are absent for it; connector and pool rules
|
|
290
|
+
recognize it by `identity.agent` on every request. It never has interactive
|
|
291
|
+
operator authority. Removing a name from `agents` stops its token on the next
|
|
292
|
+
request.
|
|
293
|
+
|
|
294
|
+
An agent connects to `<PUBLIC_URL>/agent/<pool>` for a pool that lists it and
|
|
295
|
+
sends one header:
|
|
262
296
|
|
|
263
297
|
```text
|
|
264
|
-
CF-Access-Client-Id: <access-service-client-id>
|
|
265
|
-
CF-Access-Client-Secret: <access-service-client-secret>
|
|
266
298
|
Authorization: Bearer <stored-cta-token>
|
|
267
299
|
```
|
|
268
300
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
301
|
+
[The agent bypass](#let-agents-through-access) lets the request past the edge;
|
|
302
|
+
connecta verifies the bearer against D1 and ignores any Access context or
|
|
303
|
+
headers there. `/mcp` and `/mcp/<pool>` refuse the token. Doctor also reads
|
|
304
|
+
`/health`, which stays behind Access, so it needs Access service credentials
|
|
305
|
+
too; see [Client authentication and activity](#client-authentication-and-activity).
|
|
273
306
|
|
|
274
307
|
For programmatic bootstrap, trusted provisioning code that already holds this
|
|
275
308
|
deployment's D1 binding can use the published API against that same storage:
|
|
@@ -278,16 +311,18 @@ deployment's D1 binding can use the published API against that same storage:
|
|
|
278
311
|
import { AccessTokenManager } from "@zackbart/connecta/auth/access-tokens";
|
|
279
312
|
import { d1Storage } from "@zackbart/connecta/d1";
|
|
280
313
|
|
|
281
|
-
const manager = new AccessTokenManager(d1Storage(env.CONNECTA_DB));
|
|
282
|
-
const { token } = await manager.
|
|
314
|
+
const manager = new AccessTokenManager(d1Storage(env.CONNECTA_DB), { agents: ["ci"] });
|
|
315
|
+
const { token } = await manager.rotate("ci", "trusted-provisioning");
|
|
283
316
|
// Deliver token once to the client's secret store, outside logs and source control.
|
|
284
317
|
```
|
|
285
318
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
`
|
|
319
|
+
Provision only through trusted operator tooling; do not expose this code as a
|
|
320
|
+
public route or rotate a token at startup. Tokens issued before agents survive a
|
|
321
|
+
state migration into this same D1 namespace but stop admitting until trusted
|
|
322
|
+
tooling binds each machine's token once with
|
|
323
|
+
`manager.adopt(tokenId, "ci")`, which keeps its secret working. Human-bound
|
|
324
|
+
tokens cannot be adopted; issue the agent a new token instead. Keep
|
|
325
|
+
`accessTokens(storage)` configured over the same storage.
|
|
291
326
|
|
|
292
327
|
### UI and encrypted credentials
|
|
293
328
|
|
|
@@ -323,11 +358,13 @@ does not create credentials or permissions by itself.
|
|
|
323
358
|
|
|
324
359
|
### Client authentication and activity
|
|
325
360
|
|
|
326
|
-
Interactive MCP clients use Access Managed OAuth.
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
and
|
|
330
|
-
Keep
|
|
361
|
+
Interactive MCP clients use Access Managed OAuth. Agents send only a declared
|
|
362
|
+
agent's `cta_` bearer to `/agent/<pool>`, issued as described in
|
|
363
|
+
[Machine tokens](#machine-tokens). `accessTokens(storage)` is always
|
|
364
|
+
enabled, and every signed-in maintainer manages agent tokens.
|
|
365
|
+
Keep maintainers, pools, and their members in deployment code. An agent reaches
|
|
366
|
+
only `/agent/<pool>` for a pool that lists it (the example's `ci` pool lists
|
|
367
|
+
`agent:ci`); `/mcp` and `/mcp/<pool>` refuse its token.
|
|
331
368
|
|
|
332
369
|
Activity uses `activityHistory({ store: d1ActivityStore(env.CONNECTA_DB) })`,
|
|
333
370
|
with `activityHistory` from `@zackbart/connecta/activity` and `d1ActivityStore`
|
|
@@ -335,13 +372,15 @@ from `@zackbart/connecta/d1`. See [Activity history](#activity-history-optional)
|
|
|
335
372
|
Omit the module and store wiring to record no history and show no Activity tab. Diagnostics remain independent; `logger: "silent"` suppresses
|
|
336
373
|
them explicitly.
|
|
337
374
|
|
|
338
|
-
Verify MCP health and the exact six tools with
|
|
375
|
+
Verify MCP health and the exact six tools with the following. Doctor reads
|
|
376
|
+
`/health` through Access with the service credentials, then checks `/agent/ci`
|
|
377
|
+
with the `cta_` token alone:
|
|
339
378
|
|
|
340
379
|
```sh
|
|
341
380
|
CF_ACCESS_CLIENT_ID='REPLACE_WITH_ACCESS_CLIENT_ID' \
|
|
342
381
|
CF_ACCESS_CLIENT_SECRET='REPLACE_WITH_ACCESS_CLIENT_SECRET' \
|
|
343
382
|
CONNECTA_TOKEN='cta_REPLACE_WITH_STORED_SECRET' \
|
|
344
|
-
connecta doctor --url "$PUBLIC_URL"
|
|
383
|
+
connecta doctor --url "$PUBLIC_URL" --pool ci
|
|
345
384
|
```
|
|
346
385
|
|
|
347
386
|
Doctor reports the configured `DynamicWorkerExecutor`, not a presumed Node
|
|
@@ -430,7 +469,7 @@ CREATE INDEX IF NOT EXISTS connecta_kv_expiry ON connecta_kv (expires_at_ms);
|
|
|
430
469
|
- **Workers KV** (`CONNECTA_KV` and `cloudflare-kv.ts`). Workers KV is no longer
|
|
431
470
|
supported: `createConnecta` refuses storage without `compareAndSet` at boot.
|
|
432
471
|
Copy its state into D1 once, as described below, so OAuth grants, vault
|
|
433
|
-
credentials, and `cta_` access
|
|
472
|
+
credentials, and `cta_` access token records carry over.
|
|
434
473
|
|
|
435
474
|
#### Copying Workers KV state into D1
|
|
436
475
|
|
|
@@ -462,7 +501,7 @@ then `wrangler login` and check the prepared deployment with a dry run.
|
|
|
462
501
|
1. Back up KV with a bulk export including values and expiration metadata.
|
|
463
502
|
Export D1 with `wrangler d1 export <db> --remote --output before-cutover.sql`.
|
|
464
503
|
Store backups securely and preserve the exact credential encryption key,
|
|
465
|
-
|
|
504
|
+
whatever secret name the deployment stores it under.
|
|
466
505
|
2. Block traffic using maintenance mode or turn the route off. Stop cron,
|
|
467
506
|
queue consumers, scheduled jobs, and every other KV/D1 writer. Drain all
|
|
468
507
|
in-flight requests, including OAuth callbacks and token refreshes.
|
|
@@ -488,8 +527,8 @@ then `wrangler login` and check the prepared deployment with a dry run.
|
|
|
488
527
|
invalid entry or mismatch. Keep traffic and writers stopped until these
|
|
489
528
|
counts are resolved. A verification pass does not rewrite copied entries.
|
|
490
529
|
5. Deploy the D1 configuration with `wrangler deploy` while maintenance remains.
|
|
491
|
-
Run `connecta doctor
|
|
492
|
-
bearer through `CONNECTA_TOKEN`. Verify an existing
|
|
530
|
+
Run `connecta doctor --pool <pool>` using Access service credentials plus a
|
|
531
|
+
stored `cta_` bearer through `CONNECTA_TOKEN`. Verify an existing
|
|
493
532
|
OAuth connector without re-consent, an existing `cta_` token, a connector
|
|
494
533
|
using a vault credential, and prior activity in the Activity view. Run
|
|
495
534
|
these controlled checks with other traffic and background writers blocked.
|
|
@@ -31,9 +31,15 @@
|
|
|
31
31
|
* Claude's https://claude.ai/api/mcp/auth_callback plus ChatGPT's
|
|
32
32
|
* https://chatgpt.com/connector_platform_oauth_redirect and
|
|
33
33
|
* https://chatgpt.com/connector/oauth/* forms (see ../AGENTS.md).
|
|
34
|
+
* Then add one self-hosted Access application per hostname for
|
|
35
|
+
* `<host>/agent/*` with a single Bypass policy (Everyone), so agents send
|
|
36
|
+
* only their cta_ token (README.md § "Let agents through Access").
|
|
34
37
|
* 5. Use the Workers Paid plan required by the `worker_loaders` binding.
|
|
35
|
-
* 6.
|
|
36
|
-
*
|
|
38
|
+
* 6. List the maintainers' Access user ids (the identity's user_uuid, else
|
|
39
|
+
* its email) in the CONNECTA_MAINTAINERS var, comma-separated.
|
|
40
|
+
* 7. `wrangler deploy` from this folder (examples/worker), where wrangler.jsonc
|
|
41
|
+
* lives. Point a maintainer's MCP client at `<PUBLIC_URL>/mcp`, and an
|
|
42
|
+
* agent's at `<PUBLIC_URL>/agent/ci`.
|
|
37
43
|
*/
|
|
38
44
|
import { api, defineConfig, remoteMcp } from "@zackbart/connecta";
|
|
39
45
|
import { activityHistory } from "@zackbart/connecta/activity";
|
|
@@ -55,6 +61,8 @@ export interface Env {
|
|
|
55
61
|
CREDENTIAL_ENCRYPTION_KEY?: string;
|
|
56
62
|
DOWNSTREAM_TOKEN: string;
|
|
57
63
|
PUBLIC_URL: string;
|
|
64
|
+
/** Comma-separated Access user ids (user_uuid, else email) of the maintainers. */
|
|
65
|
+
CONNECTA_MAINTAINERS: string;
|
|
58
66
|
/** "on" switches on activity history, in CONNECTA_DB. */
|
|
59
67
|
CONNECTA_ACTIVITY?: string;
|
|
60
68
|
/**
|
|
@@ -77,26 +85,34 @@ export default defineConfig((env: Env) => {
|
|
|
77
85
|
// Required adapter owns each run's handles; direct upstream construction throws.
|
|
78
86
|
executor: workerExecutor({ loader: env.LOADER }),
|
|
79
87
|
// Access owns edge admission and proves human identity for MCP and the
|
|
80
|
-
// operator pages.
|
|
81
|
-
//
|
|
88
|
+
// operator pages. Agents use /agent/<pool>, which Access bypasses and
|
|
89
|
+
// connecta authenticates with the cta_ bearer alone; a service identity
|
|
90
|
+
// alone is refused everywhere.
|
|
82
91
|
auth: [cloudflareAccessAuth()],
|
|
83
|
-
//
|
|
84
|
-
//
|
|
92
|
+
// Machine clients are agents declared here by name, each with one cta_
|
|
93
|
+
// token. An Access-authenticated operator issues, rotates, and revokes it
|
|
94
|
+
// in the operator UI; removing a name stops its token on the next request.
|
|
95
|
+
agents: ["ci"],
|
|
96
|
+
// Always installed over the same D1 storage. An agent with no issued token
|
|
97
|
+
// admits nothing.
|
|
85
98
|
accessTokens: accessTokens(storage),
|
|
86
|
-
// Code-owned roster. Access proves the identity;
|
|
87
|
-
//
|
|
88
|
-
//
|
|
89
|
-
//
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
//
|
|
97
|
-
//
|
|
98
|
-
|
|
99
|
-
//
|
|
99
|
+
// Code-owned roster. Access proves the identity; maintainers alone use
|
|
100
|
+
// plain /mcp, which serves every connector, and the operator UI, where they
|
|
101
|
+
// administer shared credentials, manage agent tokens, and read activity.
|
|
102
|
+
// Startup refuses an empty list.
|
|
103
|
+
maintainers: env.CONNECTA_MAINTAINERS.split(",")
|
|
104
|
+
.map((id) => id.trim())
|
|
105
|
+
.filter(Boolean),
|
|
106
|
+
// Everyone else uses a pool that lists them, which serves exactly its
|
|
107
|
+
// tools: people at /mcp/<name>, agents at /agent/<name>. Members are
|
|
108
|
+
// Access user ids or "agent:<name>". The starter pool is the agent's base
|
|
109
|
+
// pool (shared connectors, no owner), named after the agent as the agent
|
|
110
|
+
// pool layout requires.
|
|
111
|
+
pools: { ci: { tools: ["echo"], members: ["agent:ci"] } },
|
|
112
|
+
// Connectors that declare a `credential` slot become editable by a
|
|
113
|
+
// maintainer (shared) or by the member it belongs to (personal),
|
|
114
|
+
// encrypted with this key before anything reaches D1. A saved replacement
|
|
115
|
+
// takes effect on the next call; credentials fail at use.
|
|
100
116
|
vault: env.CREDENTIAL_ENCRYPTION_KEY ? encryptedCredentialVault(storage, env.CREDENTIAL_ENCRYPTION_KEY) : undefined,
|
|
101
117
|
// Payload-free activity at /ui/api/activity in CONNECTA_DB. The shared
|
|
102
118
|
// D1 mapping persists the build version and validated client facts, and
|
|
@@ -13,6 +13,9 @@
|
|
|
13
13
|
"vars": {
|
|
14
14
|
// "CONNECTA_ACTIVITY": "on",
|
|
15
15
|
"PUBLIC_URL": "https://connecta.example.workers.dev",
|
|
16
|
+
// Comma-separated Access user ids (user_uuid, else email) of the
|
|
17
|
+
// maintainers. This one matches the local dev identity below.
|
|
18
|
+
"CONNECTA_MAINTAINERS": "operator@example.com",
|
|
16
19
|
},
|
|
17
20
|
|
|
18
21
|
// Local-only Access identity. Remove this block to exercise the
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zackbart/connecta",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.33.0",
|
|
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 six meta-tools.",
|
|
@@ -263,7 +263,8 @@
|
|
|
263
263
|
"@cloudflare/codemode": "^0.5.0",
|
|
264
264
|
"@cloudflare/vitest-pool-workers": "^0.18.8",
|
|
265
265
|
"@cloudflare/workers-types": "^4.20250101.0 || ^5.0.0",
|
|
266
|
-
"@fontsource-variable/
|
|
266
|
+
"@fontsource-variable/geist": "^5.3.0",
|
|
267
|
+
"@fontsource-variable/geist-mono": "^5.3.0",
|
|
267
268
|
"@playwright/test": "^1.62.0",
|
|
268
269
|
"@radix-ui/react-dialog": "^1.2.0",
|
|
269
270
|
"@radix-ui/react-slot": "^1.4.0",
|
|
@@ -26,6 +26,9 @@ CONNECTA_DATABASE=
|
|
|
26
26
|
# may write a credential; machine access tokens grant no interactive authority.
|
|
27
27
|
CLERK_PUBLISHABLE_KEY=
|
|
28
28
|
CLERK_SECRET_KEY=
|
|
29
|
+
# Required with Clerk: comma-separated Clerk user ids of the maintainers, who
|
|
30
|
+
# alone use plain /mcp and the operator UI.
|
|
31
|
+
CONNECTA_MAINTAINERS=
|
|
29
32
|
|
|
30
33
|
# Credential vault. Base64-encoded 32-byte AES key encrypting the values an
|
|
31
34
|
# operator saves inside a connection on /. Generate one with:
|
package/templates/node/AGENTS.md
CHANGED
|
@@ -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.
|
|
7
13
|
- Keep `executor: quickJsExecutor()` for the prescribed six-tool code-first
|
|
@@ -19,15 +25,30 @@ This repository is deployment configuration, not a copy of Connecta itself.
|
|
|
19
25
|
- Prefer `api()` when the agent must see an exact reviewed capability surface;
|
|
20
26
|
`remoteMcp()` follows the downstream server's evolving tool catalog.
|
|
21
27
|
- Optional modules (Clerk sign-in, credential vault, activity history) are type-checked code in `src/connecta.config.ts`, switched on by
|
|
22
|
-
their environment variables. Follow README "Select optional modules".
|
|
23
|
-
|
|
24
|
-
alone never grants it. Clerk supplies human identity;
|
|
28
|
+
their environment variables. Follow README "Select optional modules". Shared auth management
|
|
29
|
+
requires a signed-in maintainer, and a pool member manages only their own
|
|
30
|
+
account on a personal connector in their pools; visibility alone never grants it. Clerk supplies human identity; machine clients are the
|
|
31
|
+
`agents` declared by name in `src/connecta.config.ts`, each with one `cta_` token.
|
|
25
32
|
Keep `accessTokens(storage)` installed even before the first token exists.
|
|
26
|
-
|
|
27
|
-
the same database the server uses
|
|
28
|
-
|
|
33
|
+
Issue or rotate an agent's token with `npm run --silent rotate-token -- <agent>`
|
|
34
|
+
against the same configuration and database the server uses; bind a token
|
|
35
|
+
from before agents once with `npm run adopt-token -- <token-id> <agent>`.
|
|
36
|
+
Plain `/mcp` serves `maintainers` only; other people reach `/mcp/<pool>` and
|
|
37
|
+
agents `/agent/<pool>` for a pool listing them in `members` (`npm run doctor`
|
|
38
|
+
checks `/agent/local-machine`). Human endpoints refuse `cta_` tokens. `CONNECTA_TOKEN` is only for clients and doctor; never add a configured
|
|
39
|
+
static bearer or an open startup mode.
|
|
29
40
|
All state, activity included, lives in the one SQLite file `CONNECTA_DATABASE`
|
|
30
41
|
names, through `@zackbart/connecta/sqlite`.
|
|
42
|
+
- Organize agent pools by connecta's agent pool layout:
|
|
43
|
+
`node_modules/@zackbart/connecta/documentation/auth.md#organizing-an-agents-pools`
|
|
44
|
+
([online](https://github.com/zackbart/connecta/blob/main/documentation/auth.md#organizing-an-agents-pools)).
|
|
45
|
+
Each agent keeps one Connecta connection whose client picks the pool per
|
|
46
|
+
turn: base pool `<agent>` (shared connectors, no `owner`) outside a
|
|
47
|
+
one-on-one, and `<agent>-<user>` (the base plus that user's own connector
|
|
48
|
+
ids, `owner` set to their Workspace address) only with that user. Never list
|
|
49
|
+
another person in a `<agent>-<user>` pool: its per-user connectors act as
|
|
50
|
+
that user for every member. Never add a second Connecta connection or mount
|
|
51
|
+
downstream tools directly.
|
|
31
52
|
- Brand the operator UI in `operatorUi({ branding })`: product and owner names,
|
|
32
53
|
description, favicon, and `theme` (`accent`, `radius`, `fontFamily`,
|
|
33
54
|
`monoFamily`, `colorScheme`). Ask the deployment's owner for their brand
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
# image installs @zackbart/connecta from the registry exactly like any other
|
|
3
3
|
# consumer, so nothing here depends on the Connecta repository.
|
|
4
4
|
#
|
|
5
|
-
#
|
|
6
|
-
# exact build,
|
|
5
|
+
# Issue a declared agent's token on the volume first; README.md gives the
|
|
6
|
+
# exact build, rotation, and startup commands. Empty storage is fail-closed.
|
|
7
7
|
FROM node:22-slim
|
|
8
8
|
|
|
9
9
|
WORKDIR /app
|