@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
|
@@ -80,7 +80,7 @@ and cleanup at budget exhaustion, cancellation, and deadlines; the wrapper only
|
|
|
80
80
|
|
|
81
81
|
## What an executor must implement
|
|
82
82
|
|
|
83
|
-
The Promise provider/result seam
|
|
83
|
+
The Promise provider/result seam is declared in the installed `dist/types.d.ts`. Custom implementations
|
|
84
84
|
also need the lifecycle wrapper above; structural compatibility alone is insufficient.
|
|
85
85
|
|
|
86
86
|
```ts
|
|
@@ -481,9 +481,9 @@ argument to the configured endpoint. It never fetches that
|
|
|
481
481
|
URI or creates a connector from it.
|
|
482
482
|
|
|
483
483
|
Resources are protocol reads on read-only and writable endpoints alike. A read
|
|
484
|
-
requires
|
|
485
|
-
|
|
486
|
-
resources. An absent, hidden, tool-restricted or resource-incapable connector
|
|
484
|
+
requires the whole connector on the endpoint: plain `/mcp`, or a pool whose
|
|
485
|
+
`tools` list the connector id. A pool listing only exact `connector.tool`
|
|
486
|
+
addresses authorizes no resources. An absent, hidden, tool-restricted or resource-incapable connector
|
|
487
487
|
fails with `unknown_address`. The URI and extra arguments cannot select a
|
|
488
488
|
different credential owner or downstream subject. Personal credentials come
|
|
489
489
|
from the admitted principal, just as they do for tool calls.
|
|
@@ -737,9 +737,6 @@ and nonzero pad bits are rejected before collection. Size budgets still apply.
|
|
|
737
737
|
MCP-native output a return value cannot carry: base64 is not projectable, so a
|
|
738
738
|
block that fits the inline call limit (`S5`, `L6`) can use the separate
|
|
739
739
|
emission transport budget instead of the `R2` return guard.
|
|
740
|
-
The earlier alternatives are in [decision history](https://github.com/zackbart/connecta/blob/main/decisions/0001-ethos-verdict-table.md)
|
|
741
|
-
([#267](https://github.com/zackbart/connecta/issues/267),
|
|
742
|
-
[#270](https://github.com/zackbart/connecta/issues/270)).
|
|
743
740
|
|
|
744
741
|
**M1.** `connecta.emit(result)` accepts a rich result from this program's
|
|
745
742
|
`connecta.call` and forwards its original native content blocks, including
|
|
@@ -861,7 +858,7 @@ Programs and direct calls use the same invocation deadline and stages. A call's
|
|
|
861
858
|
`timeoutMs` wins, then `calls.defaultTimeoutMs`, then `execute.hostCallTimeoutMs`
|
|
862
859
|
(default 15,000). A guest may request a longer individual call, but the sandbox
|
|
863
860
|
and request ceilings still bound the whole run. Timeout details are agent-facing;
|
|
864
|
-
|
|
861
|
+
operator records retain only checked classifications and numeric facts.
|
|
865
862
|
A dispatched write timeout becomes `write_outcome_unknown` and retains its
|
|
866
863
|
deadline details even when the program catches the failure. The final program
|
|
867
864
|
error includes the first timeout in `details`; multiple write timeouts also
|
|
@@ -1018,7 +1015,7 @@ createConnecta({
|
|
|
1018
1015
|
connectors, executor,
|
|
1019
1016
|
readOnly: false, // required: false writes, true refuses every write call
|
|
1020
1017
|
pools: {
|
|
1021
|
-
reporting: { tools: ["posthog"], readOnly: true,
|
|
1018
|
+
reporting: { tools: ["posthog"], readOnly: true, members: analysts },
|
|
1022
1019
|
},
|
|
1023
1020
|
classification: {
|
|
1024
1021
|
posthog: { exec: "read" }, // only for a deployment with a read-only exec contract
|
|
@@ -1028,7 +1025,7 @@ createConnecta({
|
|
|
1028
1025
|
```
|
|
1029
1026
|
|
|
1030
1027
|
The removed `trust` option, on the deployment or a pool, fails construction
|
|
1031
|
-
with a message naming `readOnly
|
|
1028
|
+
with a message naming `readOnly`.
|
|
1032
1029
|
|
|
1033
1030
|
The registry computes one `classifyTool` verdict on each request-scoped
|
|
1034
1031
|
published catalog entry. It caches and persists only raw downstream facts.
|
|
@@ -1194,7 +1191,13 @@ brand check and reads only own string data descriptors for diagnostics; guest
|
|
|
1194
1191
|
accessors, serialization hooks, and Proxy traps do not run. Other thrown objects
|
|
1195
1192
|
receive a fixed description.
|
|
1196
1193
|
|
|
1197
|
-
##
|
|
1194
|
+
## Contributor reference
|
|
1195
|
+
|
|
1196
|
+
### Verification
|
|
1197
|
+
|
|
1198
|
+
The earlier alternatives are in [decision history](https://github.com/zackbart/connecta/blob/main/decisions/0001-ethos-verdict-table.md)
|
|
1199
|
+
([#267](https://github.com/zackbart/connecta/issues/267),
|
|
1200
|
+
[#270](https://github.com/zackbart/connecta/issues/270)).
|
|
1198
1201
|
|
|
1199
1202
|
`test/guest-contract-cases.ts` runs on QuickJS in `test/guest-api-contract-quickjs.node.test.ts`
|
|
1200
1203
|
and on the Worker adapter with a real Miniflare Loader in `test/guest-api-contract.test.ts`.
|
|
@@ -27,20 +27,25 @@ path and pins the generated project's Connecta dependency to the CLI version:
|
|
|
27
27
|
npx @zackbart/connecta init my-connecta
|
|
28
28
|
cd my-connecta
|
|
29
29
|
npm install
|
|
30
|
-
npm run --silent
|
|
30
|
+
npm run --silent rotate-token -- local-machine
|
|
31
31
|
# Save the returned cta_ token privately. It is shown only once.
|
|
32
32
|
npm start
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
-
The
|
|
36
|
-
`
|
|
37
|
-
|
|
38
|
-
|
|
35
|
+
The agent connects to its pool's agent endpoint,
|
|
36
|
+
`http://localhost:8787/agent/local-machine`, with
|
|
37
|
+
`Authorization: Bearer <returned-cta-token>`. People use `/mcp` and
|
|
38
|
+
`/mcp/<pool>`, which refuse `cta_` tokens. Machine clients are the agents
|
|
39
|
+
declared in `agents` in `src/connecta.config.ts`; the generated project declares
|
|
40
|
+
`local-machine` and always installs `accessTokens(storage)`. An agent with no
|
|
41
|
+
issued token admits no MCP caller even though `/health` works. Rotating with the
|
|
42
|
+
same command replaces the token immediately. `CONNECTA_TOKEN` is only a client/doctor variable;
|
|
39
43
|
it never configures server authentication. The local commands read the process
|
|
40
44
|
environment and do not load `.env`; Docker Compose does.
|
|
41
45
|
|
|
42
|
-
Edit `src/connecta.config.ts` for connectors, public URL, auth,
|
|
43
|
-
and optional modules.
|
|
46
|
+
Edit `src/connecta.config.ts` for connectors, public URL, auth, maintainers,
|
|
47
|
+
agents, pools, and optional modules. Lay out each agent's pools by
|
|
48
|
+
[Organizing an agent's pools](./auth.md#organizing-an-agents-pools). `src/index.ts` only constructs and starts the deployment.
|
|
44
49
|
Follow the [template README](../templates/node/README.md) for storage paths,
|
|
45
50
|
backups, Docker provisioning, secrets, and optional modules. Run the deployment's
|
|
46
51
|
`npm run typecheck` after configuration changes.
|
|
@@ -56,12 +61,74 @@ must be installed for the Worker executor.
|
|
|
56
61
|
|
|
57
62
|
Attach Cloudflare Access to the Worker destination. Interactive MCP clients
|
|
58
63
|
need Managed OAuth, Dynamic Client Registration, and the documented redirect
|
|
59
|
-
allowlist. Machines
|
|
60
|
-
`cta_` bearer
|
|
64
|
+
allowlist. Machines are declared agents: they use `/agent/<pool>` with the
|
|
65
|
+
agent's `cta_` bearer as their only credential, once the
|
|
66
|
+
[agent bypass application](#agent-endpoints-behind-cloudflare-access) exists;
|
|
67
|
+
Access service identity alone is refused. Keep
|
|
61
68
|
`enable_request_signal`, construct Connecta once per isolate, and pass `ctx`
|
|
62
69
|
through to `fetch`. The example owns those details and
|
|
63
70
|
[the machine-token procedure](../examples/worker/README.md#machine-tokens).
|
|
64
71
|
|
|
72
|
+
## Agent endpoints behind Cloudflare Access
|
|
73
|
+
|
|
74
|
+
Agents use `/agent/<pool>`, which connecta authenticates with the `cta_` token
|
|
75
|
+
alone and which ignores Access context entirely
|
|
76
|
+
([agent endpoints](./auth.md#agent-endpoints)). Behind Access, the edge must
|
|
77
|
+
let those requests through without an Access login or service token. The P0
|
|
78
|
+
probe ([observations](./architecture.md#production-access-bypass-for-agent-endpoints))
|
|
79
|
+
verified this shape on 2026-10-15:
|
|
80
|
+
|
|
81
|
+
1. Keep the Worker-level application, whose destination is
|
|
82
|
+
`{ "type": "worker", "worker_id": "<the Worker script tag>" }`, exactly as
|
|
83
|
+
[Cloudflare Access on Workers](./auth.md#cloudflare-access-on-workers)
|
|
84
|
+
describes. It still protects every other path and supplies `ctx.access` to
|
|
85
|
+
human routes.
|
|
86
|
+
2. For each hostname agents use (the `workers.dev` hostname, each Custom
|
|
87
|
+
Domain, each route host), add one more **self-hosted** Access application.
|
|
88
|
+
In the dashboard, set the domain to that hostname and the path to
|
|
89
|
+
`agent/*`. Give it a single policy whose action is **Bypass** and whose
|
|
90
|
+
include rule is **Everyone**. Through the API:
|
|
91
|
+
|
|
92
|
+
```json
|
|
93
|
+
{
|
|
94
|
+
"type": "self_hosted",
|
|
95
|
+
"name": "connecta agents",
|
|
96
|
+
"destinations": [{ "type": "public", "uri": "connecta.example.com/agent/*" }],
|
|
97
|
+
"policies": [{ "name": "agents bypass", "decision": "bypass", "include": [{ "everyone": {} }] }]
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
The more specific hostname-and-path application takes precedence over the
|
|
102
|
+
Worker-level one on matching paths only. Do not use a Worker destination
|
|
103
|
+
for it: a Worker destination belongs to one application, and a second one
|
|
104
|
+
is refused with 409 `destination belongs to another application`. For the
|
|
105
|
+
same reason a second hostname without Access is not an alternative.
|
|
106
|
+
|
|
107
|
+
3. Point each agent at `https://<host>/agent/<pool>` with
|
|
108
|
+
`Authorization: Bearer cta_…` and drop its `CF-Access-Client-Id` and
|
|
109
|
+
`CF-Access-Client-Secret` headers. The pool must list `"agent:<name>"`.
|
|
110
|
+
4. Verify after the change has settled. Access changes took 15–19 seconds to
|
|
111
|
+
settle in the probe, and while they propagate the edge can answer with
|
|
112
|
+
transient 500 (`error code: 1104`) or 404 (`error code: 1042` or `1043`)
|
|
113
|
+
responses, and in one round a 403 on a bypassed path after more than 30
|
|
114
|
+
seconds. Do not rely on a fixed wait: repeat these checks until they agree
|
|
115
|
+
for several consecutive rounds. Without credentials, `/agent/<pool>`
|
|
116
|
+
reaches connecta (its 401 carries `WWW-Authenticate: Bearer`, not Access's
|
|
117
|
+
403 page), while `/mcp` and `/` still get Access's refusal. Then run
|
|
118
|
+
`connecta doctor --pool <pool>` with the agent's token.
|
|
119
|
+
|
|
120
|
+
The bypass makes `/agent/*` reachable from the internet without Access.
|
|
121
|
+
Connecta answers there only an issued token of an agent listed in the pool,
|
|
122
|
+
and gives every other spelling of the agent namespace a 404 before auth,
|
|
123
|
+
because Access matches `/agent/*` after resolving dot segments, folding case,
|
|
124
|
+
decoding unreserved escapes, and collapsing a leading `//`, while the Worker
|
|
125
|
+
sees the raw path. Two cases were not tested: a human's `CF_Authorization`
|
|
126
|
+
cookie on a bypassed path, whose `ctx.access` identity is unknown (connecta
|
|
127
|
+
never reads it at `/agent/*`), and Custom Domains, which use the same
|
|
128
|
+
documented hostname-and-path form but were not observed; only `workers.dev`
|
|
129
|
+
was probed. Pinning the Worker-level application's AUD on human routes is
|
|
130
|
+
recommended hardening that connecta does not yet do.
|
|
131
|
+
|
|
65
132
|
## Compose capabilities and access
|
|
66
133
|
|
|
67
134
|
Both configurations use `defineConfig((env) => …)`, a required executor, and a required `readOnly` choice.
|
|
@@ -90,9 +157,13 @@ outside the database and source control, and preserve it across upgrades.
|
|
|
90
157
|
existing-record migration.
|
|
91
158
|
|
|
92
159
|
One deployment serves one tenant and may admit several people. Node uses Clerk
|
|
93
|
-
for human auth; Access is Workers-only.
|
|
94
|
-
|
|
95
|
-
|
|
160
|
+
for human auth; Access is Workers-only. With inbound auth, `maintainers` is
|
|
161
|
+
required: only they reach plain `/mcp` and the operator UI. Everyone else
|
|
162
|
+
reaches a pool that lists them in `members`: people at `/mcp/<pool>`, agents
|
|
163
|
+
at `/agent/<pool>`. Maintainers alone administer shared credentials, manage
|
|
164
|
+
agent tokens, and read activity; members connect their own accounts on
|
|
165
|
+
personal connectors in their pools.
|
|
166
|
+
[Auth](./auth.md#principals-visibility-and-operators) owns maintainers and members;
|
|
96
167
|
[Clerk setup](./auth.md#clerk-oauth-tokens-and-operator-sessions) owns resource-bound
|
|
97
168
|
tokens and `aud_claim_enabled`. A person's operator session is not an MCP token.
|
|
98
169
|
|
|
@@ -102,44 +173,70 @@ inherits that value unless it sets its own. A writable endpoint (`false`) allows
|
|
|
102
173
|
writes through `call_destructive_tool` and programs and marks `execute_code` as
|
|
103
174
|
a write; the client decides what to approve. A read-only endpoint (`true`) omits
|
|
104
175
|
write tools from search and describe and refuses every write call; provider
|
|
105
|
-
guides may still name those tools.
|
|
106
|
-
|
|
107
|
-
changing `readOnly`.
|
|
176
|
+
guides may still name those tools. A pool serves exactly its `tools` to its
|
|
177
|
+
`members`. See [pools](./auth.md#pools) before changing `readOnly`.
|
|
108
178
|
|
|
109
179
|
## Verify and diagnose
|
|
110
180
|
|
|
111
|
-
With the deployment running, replace the placeholder with its saved
|
|
112
|
-
token and run doctor:
|
|
181
|
+
With the deployment running, replace the placeholder with its saved agent
|
|
182
|
+
token and run doctor against a pool that lists the agent:
|
|
183
|
+
|
|
184
|
+
```sh
|
|
185
|
+
CONNECTA_TOKEN='<stored-cta-token>' npx connecta doctor --url http://localhost:8787 --pool local-machine
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Doctor checks health, the required executor, and the current six-tool set. A
|
|
189
|
+
`cta_` token is checked at `/agent/<pool>` and needs `--pool`.
|
|
190
|
+
For a Worker protected by Access, `/health` still needs edge admission even
|
|
191
|
+
though `/agent/*` bypasses Access. Use an Access service token admitted by the
|
|
192
|
+
Worker-level policy for that check, alongside the agent token:
|
|
113
193
|
|
|
114
194
|
```sh
|
|
115
|
-
CONNECTA_TOKEN='<stored-cta-token>' npx connecta doctor --url
|
|
195
|
+
CF_ACCESS_CLIENT_ID='<access-service-id>' CF_ACCESS_CLIENT_SECRET='<access-service-secret>' CONNECTA_TOKEN='<stored-cta-token>' npx connecta doctor --url https://connecta.example.com --pool assistant
|
|
116
196
|
```
|
|
117
197
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
and service-header setup. If the operator UI is enabled, authenticated
|
|
198
|
+
The service headers admit the health probe at the edge; only the `cta_` token
|
|
199
|
+
authenticates the agent endpoint inside Connecta. If the operator UI is enabled, maintainer-authenticated
|
|
121
200
|
`connecta doctor --config --url <public-url>` prints the caller-scoped
|
|
122
201
|
configuration snapshot as JSON. It runs no diagnostic program and prints no
|
|
123
202
|
raw HTTP failure body. [Operator UI](./operator-ui.md) describes the returned
|
|
124
|
-
configuration, live facts, and permission rules.
|
|
203
|
+
configuration, live facts, and permission rules. The config route is a human
|
|
204
|
+
endpoint: an agent token cannot authenticate it.
|
|
125
205
|
|
|
126
206
|
Health success alone does not prove a client can authenticate or reach an
|
|
127
207
|
integration. Check client connection and a bounded read through a chosen
|
|
128
208
|
connector; resolve credentials using [authorization recovery](./meta-tools.md#authorization-recovery).
|
|
129
209
|
|
|
210
|
+
Use the failed check to choose the next step:
|
|
211
|
+
|
|
212
|
+
| Symptom | Action |
|
|
213
|
+
| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
214
|
+
| Connection refused or timeout | Check the public URL, listening process/port, proxy, and Worker deployment. |
|
|
215
|
+
| `/health` fails behind Access | Check the Worker-level Access policy and the two service headers above. Do not broaden the agent bypass. |
|
|
216
|
+
| Executor check fails | Retain `quickJsExecutor()` and its peer on Node, or `workerExecutor({ loader })`, the codemode peer, and `LOADER` on Workers. |
|
|
217
|
+
| MCP 401 | Check the saved token, declared agent, and slot state; rotated/revoked tokens refuse. Use `/agent/<pool>` with `--pool`. |
|
|
218
|
+
| MCP 404 | Check the pool name and `members: ["agent:assistant"]`; an existing but inaccessible pool is deliberately indistinguishable from a missing one. |
|
|
219
|
+
| Doctor passes but a connector fails | Discover its tools in that pool, check credential status/account ownership, and perform a bounded read. Doctor does not prove downstream access. |
|
|
220
|
+
|
|
221
|
+
After a fix, repeat doctor with the same client credentials and pool. Never
|
|
222
|
+
paste a token or raw downstream failure body into a committed diagnostic log.
|
|
223
|
+
|
|
130
224
|
## Upgrade an existing deployment
|
|
131
225
|
|
|
132
226
|
Bump the exact package pin, read the [changelog](../CHANGELOG.md) for every
|
|
133
227
|
intervening release, and apply the relevant migration before startup. `init`
|
|
134
228
|
does not merge changes into an existing deployment.
|
|
135
229
|
|
|
136
|
-
- [
|
|
230
|
+
- [Migration to 0.33](./migration-0.33.md) maps every removed access option to `maintainers`, pool `members`, and `agents`, moves agents to `/agent/<pool>`, and covers pool owners, token revisions, operator contract v2 with its operator route changes, and the pre-auth listen fix.
|
|
231
|
+
- [Tokens issued before agents](./auth.md#agent-tokens-and-upgrading-from-earlier-tokens) stop admitting until each machine's token is bound once to a declared agent with `npm run adopt-token -- <token-id> <agent>` (Node) or `AccessTokenManager.adopt`, which keeps its secret. Human-bound tokens stay refused; issue those agents new tokens. Pool members name `"agent:<name>"` instead of matching token record ids.
|
|
137
232
|
- [Node storage from 0.28](../templates/node/README.md#storage) uses `connecta migrate-state` to copy the JSON state into SQLite. Activity JSONL is not imported.
|
|
138
233
|
- [Worker storage from 0.28](../examples/worker/README.md#upgrading-from-028) copies KV into D1 with a one-shot migration.
|
|
139
234
|
- [Notion, Vercel, and Cloudflare for 0.29](./provider-migration-0.29.md) change defaults and retained API tool names.
|
|
140
235
|
- [Executor wiring](./code-mode.md#deploy-time-capability) requires branded shipped executors or a self-managed custom executor.
|
|
141
236
|
|
|
142
|
-
##
|
|
237
|
+
## Contributor reference
|
|
238
|
+
|
|
239
|
+
### Implementation and evidence
|
|
143
240
|
|
|
144
241
|
Check the [CLI](https://github.com/zackbart/connecta/blob/main/bin/connecta.mjs),
|
|
145
242
|
[Node configuration](../templates/node/src/connecta.config.ts), and
|
|
@@ -1,16 +1,62 @@
|
|
|
1
1
|
# Integrating services
|
|
2
2
|
|
|
3
|
-
Use this guide to
|
|
4
|
-
new maintained provider in Connecta itself, follow the repository's
|
|
5
|
-
[add-provider skill](https://github.com/zackbart/connecta/blob/main/.claude/skills/add-provider/SKILL.md)
|
|
6
|
-
and [AGENTS.md](https://github.com/zackbart/connecta/blob/main/AGENTS.md).
|
|
3
|
+
Use this guide to change connectors in deployment configuration.
|
|
7
4
|
[All agent routes](./README.md) are in the index.
|
|
8
5
|
|
|
6
|
+
## Add or remove a connector
|
|
7
|
+
|
|
8
|
+
Connectors are code-owned. Edit the deployment's `src/connecta.config.ts`;
|
|
9
|
+
there is no install button or runtime registration API.
|
|
10
|
+
|
|
11
|
+
To add one:
|
|
12
|
+
|
|
13
|
+
1. Choose a maintained provider, `remoteMcp()`, or `api()` using the sections
|
|
14
|
+
below. Give it a unique, stable id such as `crm`; renaming an id selects
|
|
15
|
+
different stored credentials and changes every tool address.
|
|
16
|
+
2. Put the constructed connector in `connectors`. Keep secrets in environment
|
|
17
|
+
variables or the encrypted vault. Choose shared or personal auth explicitly
|
|
18
|
+
for the intended audience; agents cannot see personal-auth connectors.
|
|
19
|
+
3. Add the id (all its tools) or exact `id.tool` addresses to the intended
|
|
20
|
+
pools' `tools`. Maintainers at plain `/mcp` already see the whole catalog.
|
|
21
|
+
Follow [the agent pool layout](./auth.md#organizing-an-agents-pools) for an
|
|
22
|
+
agent: shared connectors go in its base constant, per-user connectors only
|
|
23
|
+
in that user's pool.
|
|
24
|
+
4. Run the deployment's `npm run typecheck` (Worker copies: `tsc --noEmit`),
|
|
25
|
+
restart Node or redeploy the Worker, and
|
|
26
|
+
[connect its credential](./auth.md#connect-a-shared-credential) if needed.
|
|
27
|
+
Run [doctor](./deploying.md#verify-and-diagnose), discover its tools from
|
|
28
|
+
the intended pool, and perform a bounded read. Check an excluded pool too.
|
|
29
|
+
|
|
30
|
+
For example, merge this fragment into the existing configuration, retaining
|
|
31
|
+
its storage, executor, auth, and `readOnly` settings:
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
import { remoteMcp } from "@zackbart/connecta";
|
|
35
|
+
|
|
36
|
+
const crm = remoteMcp("crm", {
|
|
37
|
+
url: "https://crm.example.com/mcp",
|
|
38
|
+
authScope: "shared",
|
|
39
|
+
auth: { type: "credential", credential: { label: "CRM API token" } },
|
|
40
|
+
});
|
|
41
|
+
const assistant = { tools: ["crm", "tickets"], members: ["agent:assistant"] };
|
|
42
|
+
// connectors: [crm, tickets], agents: ["assistant"], pools: { assistant }
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
To remove `crm`, first disconnect its OAuth grant or delete its saved
|
|
46
|
+
credential while the connector still exists, using a signed-in maintainer
|
|
47
|
+
for shared auth. Each person disconnects their own personal account. Remove
|
|
48
|
+
`crm` and all `crm.*` addresses from every pool (including base constants),
|
|
49
|
+
then remove its entry from `connectors`, unused imports, and unused secret
|
|
50
|
+
configuration. Remove any pools left with no tools (empty `tools` fails
|
|
51
|
+
construction), and update or retire clients pointing at those pools. Typecheck, restart/redeploy, run doctor, and confirm discovery
|
|
52
|
+
and calls no longer find it. Removing configuration alone does not revoke a
|
|
53
|
+
credential at the downstream service; revoke unused credentials there too.
|
|
54
|
+
|
|
9
55
|
## Choose a connector
|
|
10
56
|
|
|
11
57
|
| Need | Configuration path | Check before using |
|
|
12
58
|
| -------------------------------- | ------------------------------------------------- | ------------------------------------------------------------------------------------- |
|
|
13
|
-
| A maintained integration | Its `@zackbart/connecta/providers/<name>` factory |
|
|
59
|
+
| A maintained integration | Its `@zackbart/connecta/providers/<name>` factory | Published factory declarations, auth ownership, supported tools |
|
|
14
60
|
| Another hosted remote MCP server | `remoteMcp()` from the root package | Endpoint, authentication, current catalog, and read/write annotations |
|
|
15
61
|
| A selected HTTP API capability | `api()` from the root package | Input/output schemas, explicit read/write hints, bounded handler, credential handling |
|
|
16
62
|
|
|
@@ -19,6 +65,14 @@ registry enforcement, caller grants, result bounds, and activity paths. There
|
|
|
19
65
|
is no runtime installation or registration. Keep connector IDs unique and
|
|
20
66
|
stable because they prefix canonical `<connectorId>.<toolName>` addresses.
|
|
21
67
|
|
|
68
|
+
`callAdmission` is optional on `remoteMcp()`, `api()`, custom connectors, and
|
|
69
|
+
provider variants that expose an override. Only omission or `undefined` uses
|
|
70
|
+
the connector's documented default, which may be no admission. Every defined
|
|
71
|
+
value is validated at construction. Malformed policies, including `false`,
|
|
72
|
+
`null`, `0`, and `""`, throw before serving requests; they never disable
|
|
73
|
+
admission or select a default. Custom connector policies are validated when
|
|
74
|
+
the deployment constructs its registry.
|
|
75
|
+
|
|
22
76
|
## Maintained integrations
|
|
23
77
|
|
|
24
78
|
Import a provider individually. For example, Linear requires an explicit
|
|
@@ -35,25 +89,26 @@ const tracker = linear("tracker", {
|
|
|
35
89
|
```
|
|
36
90
|
|
|
37
91
|
Linear defaults to OAuth; its read-only endpoint requests only the downstream
|
|
38
|
-
read scope. That is separate from a Connecta `readOnly` endpoint. Read the
|
|
39
|
-
|
|
40
|
-
and [factory options](https://github.com/zackbart/connecta/blob/main/src/providers/linear/index.ts)
|
|
41
|
-
for API-key framing, workspace instructions, and admission choices.
|
|
92
|
+
read scope. That is separate from a Connecta `readOnly` endpoint. Read the installed `dist/providers/linear/index.d.ts` for API-key framing,
|
|
93
|
+
workspace instructions, and admission choices.
|
|
42
94
|
|
|
43
95
|
The [human README](../README.md#what-you-can-do-with-it) lists available
|
|
44
|
-
integrations.
|
|
45
|
-
|
|
46
|
-
|
|
96
|
+
integrations. In the installed package, `dist/providers/<name>/index.d.ts`
|
|
97
|
+
and its imported declarations describe each factory's options. After adding
|
|
98
|
+
a connector, use `search_tools` to discover its current tools and `connecta.skill("connector:<id>")` in `execute_code`
|
|
99
|
+
to read its runtime guide; provider source skills are not installed files.
|
|
100
|
+
Google Workspace
|
|
47
101
|
providers require administrator-managed domain-wide delegation and a deployment
|
|
48
|
-
mapping from admitted identity to the downstream account;
|
|
49
|
-
|
|
102
|
+
mapping from admitted identity to the downstream account; an agent acts as its
|
|
103
|
+
pool's `owner` instead ([auth guide](auth.md#pool-owners-for-google-workspace)).
|
|
104
|
+
A request must not choose its own account. Gmail never sends mail, and Drive never permanently
|
|
50
105
|
deletes files.
|
|
51
106
|
|
|
52
107
|
Wispr Flow uses OAuth only through `wisprFlow()` from
|
|
53
108
|
`@zackbart/connecta/providers/wispr-flow`. It reaches the authorized account's
|
|
54
109
|
Notetaker content, with personal and work accounts holding separate data.
|
|
55
|
-
Its
|
|
56
|
-
|
|
110
|
+
Its runtime guide, available through `connecta.skill("connector:<id>")` in `execute_code`, describes account access,
|
|
111
|
+
search limits, transcript permissions and paging. The
|
|
57
112
|
reviewed classification includes task writes listed in Claude's directory even
|
|
58
113
|
though Wispr's public help describes read-only access; discover the account's
|
|
59
114
|
actual tools before assuming those writes exist.
|
|
@@ -75,6 +130,16 @@ MCP clients to its hosted server, an operational gate outside Connecta. See the
|
|
|
75
130
|
To use both implementations of one provider, configure two connector ids with
|
|
76
131
|
independent credentials.
|
|
77
132
|
|
|
133
|
+
Both Notion auth variants accept optional `callAdmission`. For a token
|
|
134
|
+
connector it replaces the whole per-runtime default of 180 calls per minute
|
|
135
|
+
and 3 concurrent. Notion's [request limits](https://developers.notion.com/reference/request-limits)
|
|
136
|
+
allow 600 requests per minute per connection on Business and Enterprise and
|
|
137
|
+
180 on other plans. A separate workspace-wide limit is shared by all
|
|
138
|
+
connections. Size an override for other runtime traffic and tools that make
|
|
139
|
+
multiple HTTP requests. Only an omitted or `undefined` policy selects the
|
|
140
|
+
default; malformed policies, including `false`, `null`, `0`, and `""`, throw
|
|
141
|
+
at construction on both auth variants.
|
|
142
|
+
|
|
78
143
|
Planning Center's `excludeApps` removes whole products from a connection, for
|
|
79
144
|
example `planningCenter("pco", { purpose, excludeApps: ["giving"] })` for a
|
|
80
145
|
deployment that keeps agents away from donor and financial data. Excluded
|
|
@@ -130,8 +195,8 @@ const service = remoteMcp("service", {
|
|
|
130
195
|
description: "Our team's hosted service",
|
|
131
196
|
auth: { type: "credential" },
|
|
132
197
|
});
|
|
133
|
-
// Add service to connectors. Configure the vault
|
|
134
|
-
//
|
|
198
|
+
// Add service to connectors. Configure the vault; a signed-in maintainer
|
|
199
|
+
// supplies its credential through the operator UI.
|
|
135
200
|
```
|
|
136
201
|
|
|
137
202
|
Credential auth defaults to an `Authorization: Bearer` header. Choose framing
|
|
@@ -198,10 +263,10 @@ schemas when known; runtime observations cannot replace them.
|
|
|
198
263
|
|
|
199
264
|
`authScope: "shared"` uses deployment-owned downstream auth; `"personal"` uses
|
|
200
265
|
the admitted principal's partition. Visibility is a different decision,
|
|
201
|
-
controlled by
|
|
266
|
+
controlled by maintainers and pool membership. A personal connector must not close
|
|
202
267
|
over a shared secret or derive its owner from arguments. Remote MCP refuses
|
|
203
268
|
literal header credentials with personal scope. Review
|
|
204
|
-
[
|
|
269
|
+
[maintainers and members](./auth.md#principals-visibility-and-operators) and
|
|
205
270
|
[management permissions](./auth.md#management-permissions) before exposing a
|
|
206
271
|
new integration or its authentication controls.
|
|
207
272
|
|
|
@@ -210,7 +275,13 @@ perform a bounded read. Add negative checks for target restrictions and writes
|
|
|
210
275
|
when authoring a handler or provider. Follow repository verification policy
|
|
211
276
|
when changing package code.
|
|
212
277
|
|
|
213
|
-
##
|
|
278
|
+
## Contributor reference
|
|
279
|
+
|
|
280
|
+
### Implementation and evidence
|
|
281
|
+
|
|
282
|
+
To implement a maintained provider in Connecta itself, follow the repository's
|
|
283
|
+
[add-provider skill](https://github.com/zackbart/connecta/blob/main/.claude/skills/add-provider/SKILL.md)
|
|
284
|
+
and [AGENTS.md](https://github.com/zackbart/connecta/blob/main/AGENTS.md).
|
|
214
285
|
|
|
215
286
|
Factory contracts live in [remote MCP](https://github.com/zackbart/connecta/blob/main/src/connectors/remote-mcp.ts),
|
|
216
287
|
[API connector](https://github.com/zackbart/connecta/blob/main/src/connectors/api-connector.ts),
|
|
@@ -194,8 +194,7 @@ discovery made the same bet).
|
|
|
194
194
|
```
|
|
195
195
|
|
|
196
196
|
It is something to read, not something that runs: programs stay JavaScript,
|
|
197
|
-
and `execute_code` accepts no erasable TypeScript
|
|
198
|
-
([decision history](https://github.com/zackbart/connecta/blob/main/decisions/0001-ethos-verdict-table.md)). The output half is the provider's declared
|
|
197
|
+
and `execute_code` accepts no erasable TypeScript. The output half is the provider's declared
|
|
199
198
|
schema, else an `S9` observation that opens with the
|
|
200
199
|
`/* observed, not declared */` marker and keeps the `outputSchemaSource`
|
|
201
200
|
field, else `unknown` — runtime evidence never reads as a contract, even when
|
|
@@ -282,7 +281,7 @@ is its slug; other IDs use `connector-` followed by a stable SHA-256 prefix.
|
|
|
282
281
|
The suffix makes each
|
|
283
282
|
document a valid Agent Skills file; the roots `skill://connecta/usage` and
|
|
284
283
|
`skill://connecta/connectors/<connector-id>` also resolve. Provider guides are
|
|
285
|
-
built from
|
|
284
|
+
built from maintained provider guides with the existing
|
|
286
285
|
connection context and deployment instructions. Local manifests contain a
|
|
287
286
|
SHA-256 digest and UTF-8 byte size of the complete document. `usage` and
|
|
288
287
|
`investigate` remain compatibility names; `connector:<id>` remains a
|
|
@@ -598,8 +597,8 @@ same when no visible connector ID or title names that service. This service-name
|
|
|
598
597
|
vocabulary is query interpretation, not an inventory of configured providers.
|
|
599
598
|
For other service names, use the explicit `connector` scope. An unavailable
|
|
600
599
|
catalog is a catalog failure, never an absence. Absence records and catalog
|
|
601
|
-
errors use only the endpoint
|
|
602
|
-
|
|
600
|
+
errors use only the endpoint's tools; a connector the endpoint does not serve
|
|
601
|
+
is indistinguishable from an unconfigured one.
|
|
603
602
|
|
|
604
603
|
If no tool covers every search term, wider any-term fallback remains available
|
|
605
604
|
for ordinary action/object searches and the page carries `matchMode: "partial"`.
|
|
@@ -933,9 +932,13 @@ list connectors from another pool or identity's grants.
|
|
|
933
932
|
A write that times out after dispatch returns `write_outcome_unknown` with
|
|
934
933
|
`retryable: false` and an agent-only `uncertainCall: { address, args?, argsOmitted?, argsRedacted?, recovery? }`.
|
|
935
934
|
No write is automatically replayed. `recovery` carries facts the connector
|
|
936
|
-
recorded before dispatch
|
|
937
|
-
|
|
938
|
-
|
|
935
|
+
recorded before dispatch, such as a REST connector's
|
|
936
|
+
generated or caller-supplied `idempotencyKey`. Recovery accepts keys up to 255
|
|
937
|
+
characters, matching the REST write schema. Other recovery values remain capped
|
|
938
|
+
at 128 characters, with at most four facts per call and camelCase names of at
|
|
939
|
+
most 32 characters. Values outside these bounds are dropped whole. A deliberate
|
|
940
|
+
retry that reuses the key with the exact original arguments cannot repeat the
|
|
941
|
+
write while the vendor retains the key
|
|
939
942
|
(Stripe may prune v1 keys after 24 hours). After that, look the object up before
|
|
940
943
|
retrying. When a connector recorded such facts, any other dispatched write whose
|
|
941
944
|
outcome is unknown (a lost response body, a 5xx) also carries `uncertainCall`
|
|
@@ -954,7 +957,9 @@ SDK timeout classes, and runtime network codes. Untyped prose is non-retryable:
|
|
|
954
957
|
name, or URL never changes the verdict. JSON-RPC `ProtocolError.data` is dropped
|
|
955
958
|
at the downstream boundary, even when the agent may see the error's message.
|
|
956
959
|
|
|
957
|
-
##
|
|
960
|
+
## Contributor reference
|
|
961
|
+
|
|
962
|
+
### Source and tests
|
|
958
963
|
|
|
959
964
|
Handlers and schemas live in [meta-tools.ts](https://github.com/zackbart/connecta/blob/main/src/meta-tools.ts).
|
|
960
965
|
[Catalog service](https://github.com/zackbart/connecta/blob/main/src/catalog-service.ts)
|