@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
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
* One MCP endpoint aggregating a downstream remote MCP and an HTTP API, guarded
|
|
5
5
|
* by Cloudflare Access. It needs three resources and nothing else: one D1
|
|
6
6
|
* database (CONNECTA_DB) holding every piece of state, the Worker Loader
|
|
7
|
-
* binding (LOADER) behind execute_code, and
|
|
8
|
-
*
|
|
7
|
+
* binding (LOADER) behind execute_code, and two secrets: DOWNSTREAM_TOKEN for
|
|
8
|
+
* the example Notion connector and CREDENTIAL_ENCRYPTION_KEY sealing
|
|
9
|
+
* credentials in that database. Access
|
|
9
10
|
* admits the request before this Worker runs and supplies trusted human
|
|
10
11
|
* identity through ctx.access. Machines use stored cta_ tokens inside connecta.
|
|
11
12
|
*
|
|
@@ -16,7 +17,7 @@
|
|
|
16
17
|
*
|
|
17
18
|
* Setup (this example has no package.json of its own — it self-references the
|
|
18
19
|
* installed `@zackbart/connecta` package):
|
|
19
|
-
* 1. `
|
|
20
|
+
* 1. `pnpm install` in the connecta repository root (../../ from here) so the
|
|
20
21
|
* package import and wrangler resolve. A copy in its own repository
|
|
21
22
|
* installs `@zackbart/connecta @cloudflare/codemode` instead. Codemode is
|
|
22
23
|
* an optional peer.
|
|
@@ -31,9 +32,15 @@
|
|
|
31
32
|
* Claude's https://claude.ai/api/mcp/auth_callback plus ChatGPT's
|
|
32
33
|
* https://chatgpt.com/connector_platform_oauth_redirect and
|
|
33
34
|
* https://chatgpt.com/connector/oauth/* forms (see ../AGENTS.md).
|
|
35
|
+
* Then add one self-hosted Access application per hostname for
|
|
36
|
+
* `<host>/agent/*` with a single Bypass policy (Everyone), so agents send
|
|
37
|
+
* only their cta_ token (README.md § "Let agents through Access").
|
|
34
38
|
* 5. Use the Workers Paid plan required by the `worker_loaders` binding.
|
|
35
|
-
* 6.
|
|
36
|
-
*
|
|
39
|
+
* 6. List the maintainers' Access user ids (the identity's user_uuid, else
|
|
40
|
+
* its email) in the CONNECTA_MAINTAINERS var, comma-separated.
|
|
41
|
+
* 7. `wrangler deploy` from this folder (examples/worker), where wrangler.jsonc
|
|
42
|
+
* lives. Point a maintainer's MCP client at `<PUBLIC_URL>/mcp`, and an
|
|
43
|
+
* agent's at `<PUBLIC_URL>/agent/ci`.
|
|
37
44
|
*/
|
|
38
45
|
import { api, defineConfig, remoteMcp } from "@zackbart/connecta";
|
|
39
46
|
import { activityHistory } from "@zackbart/connecta/activity";
|
|
@@ -55,6 +62,8 @@ export interface Env {
|
|
|
55
62
|
CREDENTIAL_ENCRYPTION_KEY?: string;
|
|
56
63
|
DOWNSTREAM_TOKEN: string;
|
|
57
64
|
PUBLIC_URL: string;
|
|
65
|
+
/** Comma-separated Access user ids (user_uuid, else email) of the maintainers. */
|
|
66
|
+
CONNECTA_MAINTAINERS: string;
|
|
58
67
|
/** "on" switches on activity history, in CONNECTA_DB. */
|
|
59
68
|
CONNECTA_ACTIVITY?: string;
|
|
60
69
|
/**
|
|
@@ -77,26 +86,34 @@ export default defineConfig((env: Env) => {
|
|
|
77
86
|
// Required adapter owns each run's handles; direct upstream construction throws.
|
|
78
87
|
executor: workerExecutor({ loader: env.LOADER }),
|
|
79
88
|
// Access owns edge admission and proves human identity for MCP and the
|
|
80
|
-
// operator pages.
|
|
81
|
-
//
|
|
89
|
+
// operator pages. Agents use /agent/<pool>, which Access bypasses and
|
|
90
|
+
// connecta authenticates with the cta_ bearer alone; a service identity
|
|
91
|
+
// alone is refused everywhere.
|
|
82
92
|
auth: [cloudflareAccessAuth()],
|
|
83
|
-
//
|
|
84
|
-
//
|
|
93
|
+
// Machine clients are agents declared here by name, each with one cta_
|
|
94
|
+
// token. A signed-in maintainer issues, rotates, and revokes it
|
|
95
|
+
// in the operator UI; removing a name stops its token on the next request.
|
|
96
|
+
agents: ["ci"],
|
|
97
|
+
// Always installed over the same D1 storage. An agent with no issued token
|
|
98
|
+
// admits nothing.
|
|
85
99
|
accessTokens: accessTokens(storage),
|
|
86
|
-
// Code-owned roster. Access proves the identity;
|
|
87
|
-
//
|
|
88
|
-
//
|
|
89
|
-
//
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
//
|
|
97
|
-
//
|
|
98
|
-
|
|
99
|
-
//
|
|
100
|
+
// Code-owned roster. Access proves the identity; maintainers alone use
|
|
101
|
+
// plain /mcp, which serves every connector, and the operator UI, where they
|
|
102
|
+
// administer shared credentials, manage agent tokens, and read activity.
|
|
103
|
+
// Startup refuses an empty list.
|
|
104
|
+
maintainers: env.CONNECTA_MAINTAINERS.split(",")
|
|
105
|
+
.map((id) => id.trim())
|
|
106
|
+
.filter(Boolean),
|
|
107
|
+
// Everyone else uses a pool that lists them, which serves exactly its
|
|
108
|
+
// tools: people at /mcp/<name>, agents at /agent/<name>. Members are
|
|
109
|
+
// Access user ids or "agent:<name>". The starter pool is the agent's base
|
|
110
|
+
// pool (shared connectors, no owner), named after the agent as the agent
|
|
111
|
+
// pool layout requires.
|
|
112
|
+
pools: { ci: { tools: ["echo"], members: ["agent:ci"] } },
|
|
113
|
+
// Connectors that declare a `credential` slot become editable by a
|
|
114
|
+
// maintainer (shared) or by the member it belongs to (personal),
|
|
115
|
+
// encrypted with this key before anything reaches D1. A saved replacement
|
|
116
|
+
// takes effect on the next call; credentials fail at use.
|
|
100
117
|
vault: env.CREDENTIAL_ENCRYPTION_KEY ? encryptedCredentialVault(storage, env.CREDENTIAL_ENCRYPTION_KEY) : undefined,
|
|
101
118
|
// Payload-free activity at /ui/api/activity in CONNECTA_DB. The shared
|
|
102
119
|
// D1 mapping persists the build version and validated client facts, and
|
|
@@ -13,9 +13,12 @@
|
|
|
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
|
-
// Local-only Access identity. Remove this block to exercise the
|
|
21
|
+
// Local-only Access identity (Wrangler 4.123.0 or later). Remove this block to exercise the
|
|
19
22
|
// unauthenticated path in `wrangler dev`; production identity comes from the
|
|
20
23
|
// Worker-level Access application, not from this file.
|
|
21
24
|
"access": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zackbart/connecta",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.34.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.",
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
"engines": {
|
|
9
9
|
"node": ">=22.13.0"
|
|
10
10
|
},
|
|
11
|
+
"packageManager": "pnpm@12.4.2",
|
|
11
12
|
"publishConfig": {
|
|
12
13
|
"access": "public"
|
|
13
14
|
},
|
|
@@ -187,20 +188,20 @@
|
|
|
187
188
|
"build:operator-ui": "node scripts/build-operator-ui.mjs",
|
|
188
189
|
"check:operator-ui": "node scripts/build-operator-ui.mjs --check",
|
|
189
190
|
"check:clerk-sdk": "node scripts/build-clerk-sdk.mjs --check",
|
|
190
|
-
"build": "
|
|
191
|
+
"build": "pnpm run providers:generate && pnpm run clean && tsc -p tsconfig.build.json && node scripts/prune-declarations.mjs",
|
|
191
192
|
"typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.operator-ui.json --noEmit",
|
|
192
193
|
"test": "vitest run",
|
|
193
194
|
"test:browser:install": "playwright install chromium",
|
|
194
195
|
"test:browser": "playwright test",
|
|
195
196
|
"test:browser:snapshots": "node scripts/update-operator-snapshots.mjs",
|
|
196
|
-
"pretest:browser:snapshots": "
|
|
197
|
+
"pretest:browser:snapshots": "pnpm run build:operator-ui",
|
|
197
198
|
"test:node": "vitest run --project node",
|
|
198
199
|
"test:workers": "vitest run --project workers",
|
|
199
200
|
"check:docs": "node scripts/check-doc-links.mjs",
|
|
200
201
|
"check:lint": "oxlint -D correctness --report-unused-disable-directives .",
|
|
201
202
|
"check:unused": "knip --include dependencies,unlisted,exports,nsExports,types,nsTypes",
|
|
202
203
|
"check:examples": "tsc -p tsconfig.template.node.json && tsc -p tsconfig.examples.worker.json",
|
|
203
|
-
"check:security": "
|
|
204
|
+
"check:security": "pnpm audit --prod --audit-level moderate",
|
|
204
205
|
"check:package": "node scripts/check-package.mjs",
|
|
205
206
|
"check:declarations": "node scripts/check-declarations.mjs --dist .",
|
|
206
207
|
"check:bundle": "node scripts/bundle-size.mjs",
|
|
@@ -211,23 +212,23 @@
|
|
|
211
212
|
"eval:smoke": "tsx eval/run-smoke.ts",
|
|
212
213
|
"eval:perf": "tsx eval/run-perf.ts",
|
|
213
214
|
"eval:report": "tsx eval/report.ts",
|
|
214
|
-
"check:core": "
|
|
215
|
+
"check:core": "pnpm run format:check && pnpm run check:providers-generated && pnpm run check:docs && pnpm run check:changes && pnpm run check:operator-ui && pnpm run check:clerk-sdk && pnpm run check:lint && pnpm run check:unused && pnpm run typecheck && pnpm run test && pnpm run build && pnpm run check:declarations && pnpm run check:bundle && pnpm run check:examples",
|
|
215
216
|
"check:fast": "node scripts/check-fast.mjs",
|
|
216
|
-
"check": "
|
|
217
|
-
"release:check": "
|
|
218
|
-
"prepack": "
|
|
217
|
+
"check": "pnpm run check:core && pnpm run test:browser",
|
|
218
|
+
"release:check": "pnpm run check && pnpm run check:security && pnpm run check:package",
|
|
219
|
+
"prepack": "pnpm run check",
|
|
219
220
|
"check:changes": "node scripts/changelog.mjs --check && node scripts/check-node-suites.mjs && node --test scripts/changelog.test.mjs",
|
|
220
221
|
"changelog:assemble": "node scripts/changelog.mjs",
|
|
221
222
|
"providers:generate": "tsx scripts/generate-providers.mjs",
|
|
222
223
|
"check:providers-generated": "tsx scripts/generate-providers.mjs --check",
|
|
223
|
-
"prebuild": "node scripts/generate-version.mjs &&
|
|
224
|
-
"pretest": "node scripts/generate-version.mjs &&
|
|
225
|
-
"pretest:node": "node scripts/generate-version.mjs &&
|
|
226
|
-
"pretest:workers": "node scripts/generate-version.mjs &&
|
|
227
|
-
"pretest:browser": "
|
|
228
|
-
"pretypecheck": "node scripts/generate-version.mjs &&
|
|
229
|
-
"precheck:bundle": "
|
|
230
|
-
"precheck:fast": "
|
|
224
|
+
"prebuild": "node scripts/generate-version.mjs && pnpm run build:operator-ui",
|
|
225
|
+
"pretest": "node scripts/generate-version.mjs && pnpm run build:operator-ui",
|
|
226
|
+
"pretest:node": "node scripts/generate-version.mjs && pnpm run build:operator-ui",
|
|
227
|
+
"pretest:workers": "node scripts/generate-version.mjs && pnpm run build:operator-ui",
|
|
228
|
+
"pretest:browser": "pnpm run build:operator-ui",
|
|
229
|
+
"pretypecheck": "node scripts/generate-version.mjs && pnpm run build:operator-ui",
|
|
230
|
+
"precheck:bundle": "pnpm run build:operator-ui",
|
|
231
|
+
"precheck:fast": "pnpm run check:operator-ui",
|
|
231
232
|
"eval:regrade": "tsx eval/regrade.ts",
|
|
232
233
|
"eval:compare": "tsx eval/compare.ts",
|
|
233
234
|
"format": "oxfmt --write .",
|
|
@@ -263,7 +264,8 @@
|
|
|
263
264
|
"@cloudflare/codemode": "^0.5.0",
|
|
264
265
|
"@cloudflare/vitest-pool-workers": "^0.18.8",
|
|
265
266
|
"@cloudflare/workers-types": "^4.20250101.0 || ^5.0.0",
|
|
266
|
-
"@fontsource-variable/
|
|
267
|
+
"@fontsource-variable/hanken-grotesk": "^5.3.0",
|
|
268
|
+
"@fontsource-variable/jetbrains-mono": "^5.3.0",
|
|
267
269
|
"@playwright/test": "^1.62.0",
|
|
268
270
|
"@radix-ui/react-dialog": "^1.2.0",
|
|
269
271
|
"@radix-ui/react-slot": "^1.4.0",
|
|
@@ -272,7 +274,6 @@
|
|
|
272
274
|
"@tailwindcss/oxide": "^4.3.3",
|
|
273
275
|
"@tanstack/react-query": "^5.104.1",
|
|
274
276
|
"@tanstack/react-router": "^1.170.41",
|
|
275
|
-
"@tanstack/react-table": "^8.21.3",
|
|
276
277
|
"@types/node": "^22.0.0",
|
|
277
278
|
"@types/react": "^19.3.0",
|
|
278
279
|
"@types/react-dom": "^19.3.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,36 @@ 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 harness, never the model,
|
|
46
|
+
picks the pool per turn. Tiers are nested pools of shared connectors with
|
|
47
|
+
no `owner`, each spreading the tool list below. Recommended names are
|
|
48
|
+
`<agent>` for the lowest and `<agent>-<tier>` above it; any named pool,
|
|
49
|
+
including an existing `team` or `leadership` pool, may be a tier if all its
|
|
50
|
+
human members are cleared for it. A chat gets the most capable tier everyone
|
|
51
|
+
present is cleared for, and the lowest when anyone present is unknown.
|
|
52
|
+
`<agent>-<user>` (that user's highest tier plus their own connector ids,
|
|
53
|
+
`owner` set to their Workspace address) is used only in a one-on-one with
|
|
54
|
+
that user. List only cleared people in a tier, and never another person in
|
|
55
|
+
a `<agent>-<user>` pool: its per-user connectors act as that user for every
|
|
56
|
+
member. Never add a second Connecta connection or mount downstream tools
|
|
57
|
+
directly.
|
|
31
58
|
- Brand the operator UI in `operatorUi({ branding })`: product and owner names,
|
|
32
59
|
description, favicon, and `theme` (`accent`, `radius`, `fontFamily`,
|
|
33
60
|
`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
|
package/templates/node/README.md
CHANGED
|
@@ -8,11 +8,12 @@ maintenance. This README and [local agent instructions](./AGENTS.md) own the
|
|
|
8
8
|
runnable steps for a copied Node deployment.
|
|
9
9
|
|
|
10
10
|
This is the prescribed Node deployment. It runs locally from source and as
|
|
11
|
-
a container. Install,
|
|
11
|
+
a container. Install, issue the declared `local-machine` agent's token, then
|
|
12
|
+
start it:
|
|
12
13
|
|
|
13
14
|
```sh
|
|
14
15
|
npm install
|
|
15
|
-
npm run --silent
|
|
16
|
+
npm run --silent rotate-token -- local-machine
|
|
16
17
|
# Save the returned cta_ token privately. It is shown only once.
|
|
17
18
|
npm start
|
|
18
19
|
```
|
|
@@ -24,39 +25,59 @@ warning, and npm 12 does not block the script. A later esbuild version needs a
|
|
|
24
25
|
new explicit review and approval; do not replace the pinned entry with a broad
|
|
25
26
|
package-name approval.
|
|
26
27
|
|
|
27
|
-
Point an MCP client at `http://localhost:8787/
|
|
28
|
-
|
|
28
|
+
Point an agent's MCP client at `http://localhost:8787/agent/local-machine`, the agent
|
|
29
|
+
endpoint of the pool that lists `agent:local-machine`, with
|
|
30
|
+
`Authorization: Bearer <returned-cta-token>`. Agents use only `/agent/<pool>`:
|
|
31
|
+
`/mcp` and `/mcp/<pool>` are for people and refuse `cta_` tokens, and plain
|
|
32
|
+
`/mcp` serves only the `maintainers`. `CONNECTA_TOKEN` is a client and
|
|
29
33
|
doctor variable only. Setting it never configures server authentication.
|
|
30
34
|
|
|
31
|
-
`accessTokens(storage)` is always installed. With no
|
|
32
|
-
Clerk keys, the server can start and answer `/health`, but every MCP
|
|
33
|
-
is refused. There is no open startup or configured static bearer
|
|
35
|
+
`accessTokens(storage)` is always installed. With no issued agent token and
|
|
36
|
+
no Clerk keys, the server can start and answer `/health`, but every MCP
|
|
37
|
+
request is refused. There is no open startup or configured static bearer
|
|
38
|
+
fallback.
|
|
34
39
|
|
|
35
|
-
##
|
|
40
|
+
## Agent tokens
|
|
36
41
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
on
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
Machine clients are agents, declared by name in `agents` in
|
|
43
|
+
`src/connecta.config.ts`; the template declares `local-machine`. Each agent
|
|
44
|
+
has one token. Run `npm run --silent rotate-token -- <agent>` from this
|
|
45
|
+
project on a trusted machine to issue it, or to rotate it: the previous secret
|
|
46
|
+
stops working on its next request. `src/rotate-token.ts` loads the same
|
|
47
|
+
configuration the server does, so it uses the same database and refuses an
|
|
48
|
+
agent the configuration does not declare. If you override the database path,
|
|
49
|
+
use the same `CONNECTA_DATABASE` for rotation and startup:
|
|
43
50
|
|
|
44
51
|
```sh
|
|
45
52
|
export CONNECTA_DATABASE=/absolute/path/connecta.sqlite
|
|
46
|
-
npm run --silent
|
|
53
|
+
npm run --silent rotate-token -- local-machine
|
|
47
54
|
npm start
|
|
48
55
|
```
|
|
49
56
|
|
|
50
57
|
The local commands read the process environment; they do not load `.env`.
|
|
58
|
+
To run them with the values in `.env`, export it into the shell first:
|
|
59
|
+
`set -a; . ./.env; set +a`.
|
|
51
60
|
Compose reads `.env` for the container commands below. Keep the returned
|
|
52
|
-
secret in a client secret store and out of source control and logs.
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
authority
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
storage
|
|
59
|
-
|
|
61
|
+
secret in a client secret store and out of source control and logs. A
|
|
62
|
+
rotation cannot recover an old secret; only the hash persists. An agent has no
|
|
63
|
+
human principal, no personal connectors, and no interactive management
|
|
64
|
+
authority; deployment identity and pool rules decide its access on every
|
|
65
|
+
request through `identity.agent`. To stop an agent, remove its name from
|
|
66
|
+
`agents` and restart, or revoke its token with
|
|
67
|
+
`new AccessTokenManager(storage, { agents }).revoke(name)` against the same
|
|
68
|
+
storage. An explicitly permitted Clerk operator can also issue, rotate, and
|
|
69
|
+
revoke from the operator UI. Never expose these scripts as an HTTP route or
|
|
70
|
+
run them at startup.
|
|
71
|
+
|
|
72
|
+
### Tokens issued before agents
|
|
73
|
+
|
|
74
|
+
Tokens from earlier releases stay in storage but stop admitting until they are
|
|
75
|
+
bound to an agent. Declare the agent, then run `npm run adopt-token` with no
|
|
76
|
+
arguments to list the machine tokens that can be bound, and
|
|
77
|
+
`npm run adopt-token -- <token-id> <agent>` to bind one, so that machine's
|
|
78
|
+
existing secret keeps working. A token binds once, and only to an agent whose
|
|
79
|
+
token was never issued. Human-bound tokens issued from the operator UI cannot
|
|
80
|
+
be adopted and stay refused; issue the agent a new token instead.
|
|
60
81
|
|
|
61
82
|
## Run it in Docker
|
|
62
83
|
|
|
@@ -66,12 +87,12 @@ Same source, same configuration, one long-lived service:
|
|
|
66
87
|
cp .env.example .env
|
|
67
88
|
# edit .env for the database path and any optional modules
|
|
68
89
|
docker compose build
|
|
69
|
-
docker compose run --rm --no-deps connecta npm run --silent
|
|
90
|
+
docker compose run --rm --no-deps connecta npm run --silent rotate-token -- local-machine
|
|
70
91
|
# Save the returned cta_ token privately for clients and doctor.
|
|
71
92
|
docker compose up -d
|
|
72
93
|
```
|
|
73
94
|
|
|
74
|
-
The
|
|
95
|
+
The rotation container writes through the installed package API into the
|
|
75
96
|
same named volume and `CONNECTA_DATABASE` as the service. An empty volume
|
|
76
97
|
admits no machine client. Compose never passes `CONNECTA_TOKEN` to the server;
|
|
77
98
|
no environment value can substitute for a stored token.
|
|
@@ -99,9 +120,9 @@ server, then copy the old file into the database once, before the first start:
|
|
|
99
120
|
npx connecta migrate-state .connecta-state.json .connecta.sqlite
|
|
100
121
|
```
|
|
101
122
|
|
|
102
|
-
In the container,
|
|
103
|
-
|
|
104
|
-
/data/connecta.sqlite`. It copies every live entry with its expiry, keeps any
|
|
123
|
+
In the container, mount the old file and import it into the volume:
|
|
124
|
+
`docker compose run --rm -v "$PWD/.connecta-state.json:/import/state.json:ro"
|
|
125
|
+
connecta npx connecta migrate-state /import/state.json /data/connecta.sqlite`. It copies every live entry with its expiry, keeps any
|
|
105
126
|
key the database already holds, and never changes the old file; delete that
|
|
106
127
|
once the deployment is verified. The 0.28 activity log
|
|
107
128
|
(`.connecta-activity.jsonl`) is not imported; history starts fresh.
|
|
@@ -120,9 +141,9 @@ off. `.env.example` lists each one, and `npm run typecheck` checks every module
|
|
|
120
141
|
whether or not it is switched on.
|
|
121
142
|
|
|
122
143
|
The template explicitly enables `ui: operatorUi()` from
|
|
123
|
-
`@zackbart/connecta/ui`. Open `http://localhost:8787/` and
|
|
124
|
-
|
|
125
|
-
|
|
144
|
+
`@zackbart/connecta/ui`. Open `http://localhost:8787/` and sign in with
|
|
145
|
+
Clerk as a maintainer to inspect Connections and manage connections. Agent
|
|
146
|
+
`cta_` tokens are refused by every human route, the operator UI included. Omit that option and import for an API-only
|
|
126
147
|
server. OAuth callbacks remain in core even with no UI.
|
|
127
148
|
|
|
128
149
|
The page labels each tool as a read or write and each endpoint as writable or
|
|
@@ -144,7 +165,10 @@ Connection management needs an interactive identity. A machine access token
|
|
|
144
165
|
never authorizes browser credential mutations. `@clerk/backend`
|
|
145
166
|
ships as a dependency of this template. To enable Clerk, set both
|
|
146
167
|
`CLERK_PUBLISHABLE_KEY` and `CLERK_SECRET_KEY` (one without the other refuses to
|
|
147
|
-
start) and
|
|
168
|
+
start), set `PUBLIC_URL`, and list your Clerk user id in `CONNECTA_MAINTAINERS`
|
|
169
|
+
(comma-separated; startup refuses Clerk without a maintainer). Maintainers
|
|
170
|
+
alone use plain `/mcp` and the operator UI; add other people to a pool's
|
|
171
|
+
`members` in `src/connecta.config.ts`.
|
|
148
172
|
Enable `aud_claim_enabled: true` in Clerk's instance OAuth application settings
|
|
149
173
|
(`PATCH /v1/instance/oauth_application_settings` in Clerk's Backend API), then
|
|
150
174
|
read the setting back. Both JWT and opaque OAuth tokens are supported.
|
|
@@ -164,18 +188,20 @@ audience. New DCR registrations need new entries, so prefer audience binding
|
|
|
164
188
|
for standard host onboarding. Clerk session tokens work only on operator
|
|
165
189
|
routes. [Inbound auth](https://github.com/zackbart/connecta/blob/main/documentation/auth.md#clerk-oauth-tokens-and-operator-sessions)
|
|
166
190
|
explains configuration, verification, and fixed rejection reason codes.
|
|
167
|
-
Machine clients
|
|
168
|
-
through `accessTokens(storage)`, which `src/connecta.config.ts`
|
|
169
|
-
the database.
|
|
170
|
-
|
|
191
|
+
Machine clients are the declared `agents`, each using a connecta-issued
|
|
192
|
+
`cta_` token through `accessTokens(storage)`, which `src/connecta.config.ts`
|
|
193
|
+
configures on the database. A signed-in maintainer issues, rotates, and
|
|
194
|
+
revokes them from the operator UI. Trusted local rotation above works without
|
|
171
195
|
Clerk and never requires opening the server.
|
|
172
196
|
|
|
173
|
-
Set
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
`
|
|
197
|
+
Set who uses what in code: `maintainers` for plain `/mcp` and the operator UI,
|
|
198
|
+
and each pool's `members` for `/mcp/<pool>` (people) and `/agent/<pool>`
|
|
199
|
+
(agents), which serve exactly that pool's `tools`. Agent endpoints publish no
|
|
200
|
+
protected-resource metadata and accept only `cta_` tokens. Maintainers alone
|
|
201
|
+
administer shared credentials and OAuth grants, manage agent tokens, and read
|
|
202
|
+
activity. Use `authScope: "personal"` for a connector where each person should
|
|
203
|
+
connect their own downstream account: a member connects their own account on
|
|
204
|
+
the personal connectors in their pools.
|
|
179
205
|
|
|
180
206
|
### Credential vault
|
|
181
207
|
|
|
@@ -191,13 +217,13 @@ Keep this key outside the database. Losing it makes saved values unreadable;
|
|
|
191
217
|
upgrades must reuse it. The shipped `time` connector declares no credential
|
|
192
218
|
slot. Add `credential: { label: "API token" }` to an `api()` connector and read
|
|
193
219
|
it through `await ctx.credential?.get()`, or use a Notion
|
|
194
|
-
connector with `auth: { type: "token" }`, which declares its own slot.
|
|
195
|
-
|
|
220
|
+
connector with `auth: { type: "token" }`, which declares its own slot. Maintainers manage the slot on that
|
|
221
|
+
connector's Connection tab (`/connectors/<id>`); there is no separate Credentials tab.
|
|
196
222
|
|
|
197
223
|
In 0.25.0, this vault also seals downstream OAuth tokens on their first read.
|
|
198
224
|
That is a one-way state migration for those tokens: rolling back to 0.24.x
|
|
199
225
|
requires authorizing each OAuth connector again. See the
|
|
200
|
-
[0.25.0 changelog](
|
|
226
|
+
[0.25.0 changelog](https://github.com/zackbart/connecta/blob/main/CHANGELOG.md#0250--2026-09-23) before upgrading a
|
|
201
227
|
deployment with existing OAuth connections.
|
|
202
228
|
|
|
203
229
|
A saved replacement takes effect on the next call. Connecta tests credentials
|
|
@@ -220,7 +246,7 @@ Diagnostics are independent. Keep the default logger or provide your own;
|
|
|
220
246
|
|
|
221
247
|
The UI displays connections and current permissions. Configuration still owns
|
|
222
248
|
the connector set, tool definitions, and access rules. Access token management
|
|
223
|
-
requires
|
|
249
|
+
requires a signed-in Clerk maintainer. There is no team roster or policy editor.
|
|
224
250
|
|
|
225
251
|
## Deployment contract
|
|
226
252
|
|
|
@@ -249,10 +275,11 @@ from `CONNECTA_TOKEN`; it never accepts the secret as a command-line argument.
|
|
|
249
275
|
Remote URLs must use HTTPS.
|
|
250
276
|
|
|
251
277
|
A fully-wired deployment reports exactly the same line as a bare one —
|
|
252
|
-
connector count,
|
|
278
|
+
connector count, the executor, the tool count, the negotiated MCP version, and
|
|
279
|
+
the package version:
|
|
253
280
|
|
|
254
281
|
```text
|
|
255
|
-
Connecta doctor passed: 1 connector(s), QuickJS executed, prescribed
|
|
282
|
+
Connecta doctor passed: 1 connector(s), QuickJS executed, prescribed 6-tool surface, MCP <version>, package <version>.
|
|
256
283
|
```
|
|
257
284
|
|
|
258
285
|
`QuickJS` is this deployment's sandbox, reported by the deployment itself —
|
|
@@ -268,8 +295,9 @@ feature should not leave a tab behind.
|
|
|
268
295
|
Upgrading from v0.23 does not require rotating managed `cta_…` tokens. Import
|
|
269
296
|
`accessTokens` from `@zackbart/connecta/auth/access-tokens`, replace the old
|
|
270
297
|
`accessTokens: true` with `accessTokens: accessTokens(storage)`, and keep the
|
|
271
|
-
same persistent storage namespace and
|
|
272
|
-
`identity.
|
|
273
|
-
|
|
274
|
-
|
|
298
|
+
same persistent storage namespace. From 0.33 `maintainers` and pool `members`
|
|
299
|
+
replace `identity.connectorAccess` and every `grant`, and maintainers replace
|
|
300
|
+
the four `identity` management permissions; delete them and the `identity`
|
|
301
|
+
section, and follow the package's `documentation/migration-0.33.md`. From 0.33 a stored token admits only once it is bound to a
|
|
302
|
+
declared agent: follow "Tokens issued before agents" above. See the package's
|
|
275
303
|
`documentation/auth.md` for the migration and storage requirements.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
#
|
|
3
3
|
# cp .env.example .env
|
|
4
4
|
# docker compose build
|
|
5
|
-
# docker compose run --rm --no-deps connecta npm run --silent
|
|
5
|
+
# docker compose run --rm --no-deps connecta npm run --silent rotate-token -- local-machine
|
|
6
6
|
# docker compose up -d --build
|
|
7
7
|
#
|
|
8
8
|
# Compose reads `.env` from this directory, so one file configures both the
|
|
@@ -16,7 +16,7 @@ services:
|
|
|
16
16
|
ports:
|
|
17
17
|
- "${PORT:-8787}:${PORT:-8787}"
|
|
18
18
|
environment:
|
|
19
|
-
# accessTokens(storage) is always installed; an
|
|
19
|
+
# accessTokens(storage) is always installed; an agent with no issued token is closed.
|
|
20
20
|
# CONNECTA_TOKEN belongs to clients and is never configured on this server.
|
|
21
21
|
PORT: ${PORT:-8787}
|
|
22
22
|
# Downstream OAuth calls back to this origin. Unset is fine until this
|
|
@@ -28,6 +28,7 @@ services:
|
|
|
28
28
|
# on when set and off when empty.
|
|
29
29
|
CLERK_PUBLISHABLE_KEY: ${CLERK_PUBLISHABLE_KEY:-}
|
|
30
30
|
CLERK_SECRET_KEY: ${CLERK_SECRET_KEY:-}
|
|
31
|
+
CONNECTA_MAINTAINERS: ${CONNECTA_MAINTAINERS:-}
|
|
31
32
|
CONNECTA_CREDENTIAL_KEY: ${CONNECTA_CREDENTIAL_KEY:-}
|
|
32
33
|
CONNECTA_ACTIVITY: ${CONNECTA_ACTIVITY:-}
|
|
33
34
|
volumes:
|
|
@@ -10,14 +10,15 @@
|
|
|
10
10
|
"esbuild@0.28.2": true
|
|
11
11
|
},
|
|
12
12
|
"scripts": {
|
|
13
|
-
"
|
|
14
|
-
"
|
|
13
|
+
"adopt-token": "tsx src/adopt-token.ts",
|
|
14
|
+
"doctor": "connecta doctor --pool local-machine",
|
|
15
|
+
"rotate-token": "tsx src/rotate-token.ts",
|
|
15
16
|
"start": "tsx src/index.ts",
|
|
16
17
|
"typecheck": "tsc --noEmit"
|
|
17
18
|
},
|
|
18
19
|
"dependencies": {
|
|
19
20
|
"@clerk/backend": "^3.12.0",
|
|
20
|
-
"@zackbart/connecta": "0.
|
|
21
|
+
"@zackbart/connecta": "0.34.0",
|
|
21
22
|
"quickjs-emscripten": "0.32.0"
|
|
22
23
|
},
|
|
23
24
|
"devDependencies": {
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Trusted one-time migration: bind a machine token issued before agents to a
|
|
3
|
+
* declared agent, so that machine's existing cta_ secret keeps working. Run
|
|
4
|
+
* with no arguments to list the tokens that can be adopted. A token binds
|
|
5
|
+
* once, only to an agent that has never been issued one; human-bound tokens
|
|
6
|
+
* are refused and stop admitting.
|
|
7
|
+
*/
|
|
8
|
+
import { AccessTokenManager } from "@zackbart/connecta/auth/access-tokens";
|
|
9
|
+
import connectaConfig from "./connecta.config.js";
|
|
10
|
+
|
|
11
|
+
const [tokenId, agent] = process.argv.slice(2);
|
|
12
|
+
const { storage, agents } = connectaConfig(process.env);
|
|
13
|
+
const manager = new AccessTokenManager(storage!, { agents: agents ?? [] });
|
|
14
|
+
if (tokenId === undefined) {
|
|
15
|
+
for (const token of await manager.unboundTokens()) {
|
|
16
|
+
process.stdout.write(`${token.id} ${token.createdAt} ${token.name}\n`);
|
|
17
|
+
}
|
|
18
|
+
} else if (!agent || process.argv.length !== 4) {
|
|
19
|
+
throw new Error("Usage: npm run adopt-token -- [<token-id> <agent>]");
|
|
20
|
+
} else {
|
|
21
|
+
await manager.adopt(tokenId, agent);
|
|
22
|
+
process.stdout.write(`${agent} now uses token ${tokenId}\n`);
|
|
23
|
+
}
|