@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
|
@@ -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.
|
|
@@ -555,6 +555,15 @@ URL-elicitation hosts retain their existing flow.
|
|
|
555
555
|
**E2.** The taxonomy: `retryable` is what connecta reports, `Y3` what a program
|
|
556
556
|
may do. A provider maps each downstream failure to the code that tells the
|
|
557
557
|
caller what to do next, and never invents a cause it was not told.
|
|
558
|
+
The table lists the codes a program commonly sees. Codes owned by one
|
|
559
|
+
mechanism are specified with it: `resource_template_ambiguous` and
|
|
560
|
+
`resource_match_budget_exceeded` with resource reads above; the
|
|
561
|
+
`executor_*` admission codes in `E5`; `destructive_tool_requires_approval` with
|
|
562
|
+
direct calls; and `input_required_invalid`, `input_required_limit`,
|
|
563
|
+
`downstream_oauth_required`, `oauth_revocation_failed`,
|
|
564
|
+
`provider_permission_denied`, and `auth_replay_refused` in
|
|
565
|
+
[meta-tools](./meta-tools.md). Each of those is non-retryable except
|
|
566
|
+
`executor_overloaded`.
|
|
558
567
|
|
|
559
568
|
| Code | Raised when | `retryable` |
|
|
560
569
|
| ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
|
|
@@ -577,6 +586,7 @@ caller what to do next, and never invents a cause it was not told.
|
|
|
577
586
|
| `result_too_large` | a discovery response exceeded its byte bound | false |
|
|
578
587
|
| `budget_exceeded` | the run exhausted a host-call, write, or emitted-output budget | false |
|
|
579
588
|
| `write_outcome_unknown` | a program write was sent and no answer came back; it is never sent again (`W9`) | false |
|
|
589
|
+
| `executor_failed` | the executor returned a malformed result or failed outside the guest program | false |
|
|
580
590
|
|
|
581
591
|
**E3.** `auth_required` carries the same recovery envelope as `call_tool`:
|
|
582
592
|
`connector`, `operation`, `recovery` (`oauth`, `operator_config`, or
|
|
@@ -685,6 +695,12 @@ when the metadata describes a write on a read-only endpoint.
|
|
|
685
695
|
Caught call failures retain that connector visibility when catalog loading or
|
|
686
696
|
tool resolution fails. Recovery messages listing configured connectors or
|
|
687
697
|
local guides retain visibility of those contributors too.
|
|
698
|
+
Search guidance retains its referenced connectors even when no tool matches,
|
|
699
|
+
including connectors named by id or title and identities summarized as an
|
|
700
|
+
additional count. Scoped guides and summaries, absence rosters, and catalog
|
|
701
|
+
errors retain their contributing connectors as well.
|
|
702
|
+
Search counts, ranking, and term analysis retain every searched connector,
|
|
703
|
+
including matches outside the returned page or beyond the requested offset.
|
|
688
704
|
Each page rechecks current auth,
|
|
689
705
|
grants, pool membership, and the endpoint's `readOnly`. Reading a stash inside a program carries
|
|
690
706
|
its dependencies forward to any new return stash. The page cap is the smallest
|
|
@@ -711,7 +727,7 @@ has no host log stream and cannot supply logs from its suspended guest (`L4`).
|
|
|
711
727
|
|
|
712
728
|
**R6.** Every run returns `hostCalls: { attempted, admitted, succeeded, failed }`,
|
|
713
729
|
including admission failure, cancellation, budget refusal, and code-size refusal.
|
|
714
|
-
Calls include search, describe, call, result, and skill. `emit` has separate budgets.
|
|
730
|
+
Calls include search, describe, call, read, result, and skill. `emit` has separate budgets.
|
|
715
731
|
An abandoned host call counts as failed when the run ends; guest catches do not
|
|
716
732
|
change the counts. These numbers are outside the program's returned `result`.
|
|
717
733
|
`diagnostics: true` adds the existing payload-free timing block. Emitting adds
|
|
@@ -737,9 +753,6 @@ and nonzero pad bits are rejected before collection. Size budgets still apply.
|
|
|
737
753
|
MCP-native output a return value cannot carry: base64 is not projectable, so a
|
|
738
754
|
block that fits the inline call limit (`S5`, `L6`) can use the separate
|
|
739
755
|
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
756
|
|
|
744
757
|
**M1.** `connecta.emit(result)` accepts a rich result from this program's
|
|
745
758
|
`connecta.call` and forwards its original native content blocks, including
|
|
@@ -773,7 +786,8 @@ a successful result, appended to `content` after the JSON envelope, which gains
|
|
|
773
786
|
response (`R6`). `structuredContent` stays the envelope alone — emission is
|
|
774
787
|
presentation, not a second data channel.
|
|
775
788
|
|
|
776
|
-
**M3.** Text emission shares `R2`'s 24,000 serialized-character cap
|
|
789
|
+
**M3.** Text emission shares `R2`'s 24,000 serialized-character cap, less 512
|
|
790
|
+
characters reserved for the envelope (23,488 for emitted text). Its
|
|
777
791
|
serialized block size reduces the return budget, and oversized text fails with
|
|
778
792
|
`result_too_large`. Image/audio blocks use the separate transport budget and
|
|
779
793
|
reach the model as real MCP media content, including when `emit` is not awaited.
|
|
@@ -861,7 +875,7 @@ Programs and direct calls use the same invocation deadline and stages. A call's
|
|
|
861
875
|
`timeoutMs` wins, then `calls.defaultTimeoutMs`, then `execute.hostCallTimeoutMs`
|
|
862
876
|
(default 15,000). A guest may request a longer individual call, but the sandbox
|
|
863
877
|
and request ceilings still bound the whole run. Timeout details are agent-facing;
|
|
864
|
-
|
|
878
|
+
operator records retain only checked classifications and numeric facts.
|
|
865
879
|
A dispatched write timeout becomes `write_outcome_unknown` and retains its
|
|
866
880
|
deadline details even when the program catches the failure. The final program
|
|
867
881
|
error includes the first timeout in `details`; multiple write timeouts also
|
|
@@ -884,7 +898,7 @@ because connecta enforces them above the sandbox:
|
|
|
884
898
|
|
|
885
899
|
| Bound | Value |
|
|
886
900
|
| --------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
|
|
887
|
-
| Host calls per execution, shared by
|
|
901
|
+
| Host calls per execution, shared by every guest call except `emit` | 20 by default, `execute.maxHostCalls` |
|
|
888
902
|
| Writes per run on a writable endpoint, on top of the host calls they also spend (`W10`) | 10 by default, `execute.maxWrites` |
|
|
889
903
|
| Deadline per host call | 15 s, `execute.hostCallTimeoutMs`; one deadline covers catalog resolution, admission, and the connector call |
|
|
890
904
|
| Discovery page | ≤ 100 tools, ≤ 256,000 serialized bytes |
|
|
@@ -894,8 +908,9 @@ because connecta enforces them above the sandbox:
|
|
|
894
908
|
| Result | 24,000 serialized characters |
|
|
895
909
|
| Logs presented to the model | 4,000 characters |
|
|
896
910
|
|
|
897
|
-
Every `call`, `read`, `search`, and `
|
|
898
|
-
resolution, validation, or dispatch
|
|
911
|
+
Every `call`, `read`, `search`, `describe`, `result`, and `skill` spends one host
|
|
912
|
+
call on entry, before resolution, validation, or dispatch; automatic transfer
|
|
913
|
+
pages of a paged result do not. Catching a local refusal refunds nothing.
|
|
899
914
|
The first call beyond the budget ends the host run with one non-retryable
|
|
900
915
|
`budget_exceeded` (`E2`). Its bridge stays pending until lease disposal so guest
|
|
901
916
|
`try/catch` cannot swallow it. Later host access, including `emit`, stops; pending
|
|
@@ -1018,7 +1033,7 @@ createConnecta({
|
|
|
1018
1033
|
connectors, executor,
|
|
1019
1034
|
readOnly: false, // required: false writes, true refuses every write call
|
|
1020
1035
|
pools: {
|
|
1021
|
-
reporting: { tools: ["posthog"], readOnly: true,
|
|
1036
|
+
reporting: { tools: ["posthog"], readOnly: true, members: analysts },
|
|
1022
1037
|
},
|
|
1023
1038
|
classification: {
|
|
1024
1039
|
posthog: { exec: "read" }, // only for a deployment with a read-only exec contract
|
|
@@ -1028,7 +1043,7 @@ createConnecta({
|
|
|
1028
1043
|
```
|
|
1029
1044
|
|
|
1030
1045
|
The removed `trust` option, on the deployment or a pool, fails construction
|
|
1031
|
-
with a message naming `readOnly
|
|
1046
|
+
with a message naming `readOnly`.
|
|
1032
1047
|
|
|
1033
1048
|
The registry computes one `classifyTool` verdict on each request-scoped
|
|
1034
1049
|
published catalog entry. It caches and persists only raw downstream facts.
|
|
@@ -1194,7 +1209,13 @@ brand check and reads only own string data descriptors for diagnostics; guest
|
|
|
1194
1209
|
accessors, serialization hooks, and Proxy traps do not run. Other thrown objects
|
|
1195
1210
|
receive a fixed description.
|
|
1196
1211
|
|
|
1197
|
-
##
|
|
1212
|
+
## Contributor reference
|
|
1213
|
+
|
|
1214
|
+
### Verification
|
|
1215
|
+
|
|
1216
|
+
The earlier alternatives are in [decision history](https://github.com/zackbart/connecta/blob/main/decisions/0001-ethos-verdict-table.md)
|
|
1217
|
+
([#267](https://github.com/zackbart/connecta/issues/267),
|
|
1218
|
+
[#270](https://github.com/zackbart/connecta/issues/270)).
|
|
1198
1219
|
|
|
1199
1220
|
`test/guest-contract-cases.ts` runs on QuickJS in `test/guest-api-contract-quickjs.node.test.ts`
|
|
1200
1221
|
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,74 @@ 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
|
-
|
|
121
|
-
|
|
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
|
|
200
|
+
`connecta doctor --config --url <public-url>` (on Node, `CONNECTA_TOKEN` set to a
|
|
201
|
+
maintainer's current Clerk session token issued for this deployment's origin;
|
|
202
|
+
Clerk OAuth access tokens are refused here, and Access on Workers has no
|
|
203
|
+
non-browser maintainer credential, so otherwise use the UI's Settings page) prints the caller-scoped
|
|
122
204
|
configuration snapshot as JSON. It runs no diagnostic program and prints no
|
|
123
205
|
raw HTTP failure body. [Operator UI](./operator-ui.md) describes the returned
|
|
124
|
-
configuration, live facts, and permission rules.
|
|
206
|
+
configuration, live facts, and permission rules. The config route is a human
|
|
207
|
+
endpoint: an agent token cannot authenticate it.
|
|
125
208
|
|
|
126
209
|
Health success alone does not prove a client can authenticate or reach an
|
|
127
210
|
integration. Check client connection and a bounded read through a chosen
|
|
128
211
|
connector; resolve credentials using [authorization recovery](./meta-tools.md#authorization-recovery).
|
|
129
212
|
|
|
213
|
+
Use the failed check to choose the next step:
|
|
214
|
+
|
|
215
|
+
| Symptom | Action |
|
|
216
|
+
| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
217
|
+
| Connection refused or timeout | Check the public URL, listening process/port, proxy, and Worker deployment. |
|
|
218
|
+
| `/health` fails behind Access | Check the Worker-level Access policy and the two service headers above. Do not broaden the agent bypass. |
|
|
219
|
+
| Executor check fails | Retain `quickJsExecutor()` and its peer on Node, or `workerExecutor({ loader })`, the codemode peer, and `LOADER` on Workers. |
|
|
220
|
+
| MCP 401 | Check the saved token, declared agent, and slot state; rotated/revoked tokens refuse. Use `/agent/<pool>` with `--pool`. |
|
|
221
|
+
| MCP 404 | Check the pool name and `members: ["agent:assistant"]`; an existing but inaccessible pool is deliberately indistinguishable from a missing one. |
|
|
222
|
+
| 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. |
|
|
223
|
+
|
|
224
|
+
After a fix, repeat doctor with the same client credentials and pool. Never
|
|
225
|
+
paste a token or raw downstream failure body into a committed diagnostic log.
|
|
226
|
+
|
|
130
227
|
## Upgrade an existing deployment
|
|
131
228
|
|
|
132
229
|
Bump the exact package pin, read the [changelog](../CHANGELOG.md) for every
|
|
133
230
|
intervening release, and apply the relevant migration before startup. `init`
|
|
134
231
|
does not merge changes into an existing deployment.
|
|
135
232
|
|
|
136
|
-
- [
|
|
233
|
+
- [Migration to 0.34](./migration-0.34.md) covers the Overview landing page, Endpoints at `/endpoints`, default browser titles, and Workspace discovery in owner-less agent pools. No storage migration or token rotation is needed from 0.33.
|
|
234
|
+
- [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.
|
|
235
|
+
- [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
236
|
- [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
237
|
- [Worker storage from 0.28](../examples/worker/README.md#upgrading-from-028) copies KV into D1 with a one-shot migration.
|
|
139
238
|
- [Notion, Vercel, and Cloudflare for 0.29](./provider-migration-0.29.md) change defaults and retained API tool names.
|
|
140
239
|
- [Executor wiring](./code-mode.md#deploy-time-capability) requires branded shipped executors or a self-managed custom executor.
|
|
141
240
|
|
|
142
|
-
##
|
|
241
|
+
## Contributor reference
|
|
242
|
+
|
|
243
|
+
### Implementation and evidence
|
|
143
244
|
|
|
144
245
|
Check the [CLI](https://github.com/zackbart/connecta/blob/main/bin/connecta.mjs),
|
|
145
246
|
[Node configuration](../templates/node/src/connecta.config.ts), and
|
|
@@ -1,16 +1,65 @@
|
|
|
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: a shared connector goes in the tool list of the lowest tier whose
|
|
23
|
+
entire audience is authorized to use it (billing restricted to leads goes
|
|
24
|
+
in the leads tier); per-user connectors and Workspace connectors with a
|
|
25
|
+
mapping `subject` go only in personal pools.
|
|
26
|
+
4. Run the deployment's `npm run typecheck` (Worker copies: `tsc --noEmit`),
|
|
27
|
+
restart Node or redeploy the Worker, and
|
|
28
|
+
[connect its credential](./auth.md#connect-a-shared-credential) if needed.
|
|
29
|
+
Run [doctor](./deploying.md#verify-and-diagnose), discover its tools from
|
|
30
|
+
the intended pool, and perform a bounded read. Check an excluded pool too.
|
|
31
|
+
|
|
32
|
+
For example, merge this fragment into the existing configuration, retaining
|
|
33
|
+
its storage, executor, auth, and `readOnly` settings:
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
import { remoteMcp } from "@zackbart/connecta";
|
|
37
|
+
|
|
38
|
+
const crm = remoteMcp("crm", {
|
|
39
|
+
url: "https://crm.example.com/mcp",
|
|
40
|
+
authScope: "shared",
|
|
41
|
+
auth: { type: "credential", credential: { label: "CRM API token" } },
|
|
42
|
+
});
|
|
43
|
+
const base = ["crm", "tickets"]; // the agent's lowest tier
|
|
44
|
+
// connectors: [crm, tickets], agents: ["assistant"],
|
|
45
|
+
// pools: { assistant: { tools: base, members: ["agent:assistant"] } }
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
To remove `crm`, first disconnect its OAuth grant or delete its saved
|
|
49
|
+
credential while the connector still exists, using a signed-in maintainer
|
|
50
|
+
for shared auth. Each person disconnects their own personal account. Remove
|
|
51
|
+
`crm` and all `crm.*` addresses from every pool (including tier tool lists),
|
|
52
|
+
then remove its entry from `connectors`, unused imports, and unused secret
|
|
53
|
+
configuration. Remove any pools left with no tools (empty `tools` fails
|
|
54
|
+
construction), and update or retire clients pointing at those pools. Typecheck, restart/redeploy, run doctor, and confirm discovery
|
|
55
|
+
and calls no longer find it. Removing configuration alone does not revoke a
|
|
56
|
+
credential at the downstream service; revoke unused credentials there too.
|
|
57
|
+
|
|
9
58
|
## Choose a connector
|
|
10
59
|
|
|
11
60
|
| Need | Configuration path | Check before using |
|
|
12
61
|
| -------------------------------- | ------------------------------------------------- | ------------------------------------------------------------------------------------- |
|
|
13
|
-
| A maintained integration | Its `@zackbart/connecta/providers/<name>` factory |
|
|
62
|
+
| A maintained integration | Its `@zackbart/connecta/providers/<name>` factory | Published factory declarations, auth ownership, supported tools |
|
|
14
63
|
| Another hosted remote MCP server | `remoteMcp()` from the root package | Endpoint, authentication, current catalog, and read/write annotations |
|
|
15
64
|
| A selected HTTP API capability | `api()` from the root package | Input/output schemas, explicit read/write hints, bounded handler, credential handling |
|
|
16
65
|
|
|
@@ -19,6 +68,14 @@ registry enforcement, caller grants, result bounds, and activity paths. There
|
|
|
19
68
|
is no runtime installation or registration. Keep connector IDs unique and
|
|
20
69
|
stable because they prefix canonical `<connectorId>.<toolName>` addresses.
|
|
21
70
|
|
|
71
|
+
`callAdmission` is optional on `remoteMcp()`, `api()`, custom connectors, and
|
|
72
|
+
provider variants that expose an override. Only omission or `undefined` uses
|
|
73
|
+
the connector's documented default, which may be no admission. Every defined
|
|
74
|
+
value is validated at construction. Malformed policies, including `false`,
|
|
75
|
+
`null`, `0`, and `""`, throw before serving requests; they never disable
|
|
76
|
+
admission or select a default. Custom connector policies are validated when
|
|
77
|
+
the deployment constructs its registry.
|
|
78
|
+
|
|
22
79
|
## Maintained integrations
|
|
23
80
|
|
|
24
81
|
Import a provider individually. For example, Linear requires an explicit
|
|
@@ -35,25 +92,26 @@ const tracker = linear("tracker", {
|
|
|
35
92
|
```
|
|
36
93
|
|
|
37
94
|
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
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
95
|
+
read scope. That is separate from a Connecta `readOnly` endpoint. Read the installed `dist/providers/linear/index.d.ts` for API-key framing,
|
|
96
|
+
workspace instructions, and admission choices.
|
|
97
|
+
|
|
98
|
+
The [human README](../README.md#what-you-can-connect) lists available
|
|
99
|
+
integrations. In the installed package, `dist/providers/<name>/index.d.ts`
|
|
100
|
+
and its imported declarations describe each factory's options. After adding
|
|
101
|
+
a connector, use `search_tools` to discover its current tools and `connecta.skill("connector:<id>")` in `execute_code`
|
|
102
|
+
to read its runtime guide; provider source skills are not installed files.
|
|
103
|
+
Google Workspace
|
|
47
104
|
providers require administrator-managed domain-wide delegation and a deployment
|
|
48
|
-
mapping from admitted identity to the downstream account;
|
|
49
|
-
|
|
105
|
+
mapping from admitted identity to the downstream account; an agent acts as its
|
|
106
|
+
pool's `owner` instead ([auth guide](auth.md#pool-owners-for-google-workspace)).
|
|
107
|
+
A request must not choose its own account. Gmail never sends mail, and Drive never permanently
|
|
50
108
|
deletes files.
|
|
51
109
|
|
|
52
110
|
Wispr Flow uses OAuth only through `wisprFlow()` from
|
|
53
111
|
`@zackbart/connecta/providers/wispr-flow`. It reaches the authorized account's
|
|
54
112
|
Notetaker content, with personal and work accounts holding separate data.
|
|
55
|
-
Its
|
|
56
|
-
|
|
113
|
+
Its runtime guide, available through `connecta.skill("connector:<id>")` in `execute_code`, describes account access,
|
|
114
|
+
search limits, transcript permissions and paging. The
|
|
57
115
|
reviewed classification includes task writes listed in Claude's directory even
|
|
58
116
|
though Wispr's public help describes read-only access; discover the account's
|
|
59
117
|
actual tools before assuming those writes exist.
|
|
@@ -75,6 +133,16 @@ MCP clients to its hosted server, an operational gate outside Connecta. See the
|
|
|
75
133
|
To use both implementations of one provider, configure two connector ids with
|
|
76
134
|
independent credentials.
|
|
77
135
|
|
|
136
|
+
Both Notion auth variants accept optional `callAdmission`. For a token
|
|
137
|
+
connector it replaces the whole per-runtime default of 180 calls per minute
|
|
138
|
+
and 3 concurrent. Notion's [request limits](https://developers.notion.com/reference/request-limits)
|
|
139
|
+
allow 600 requests per minute per connection on Business and Enterprise and
|
|
140
|
+
180 on other plans. A separate workspace-wide limit is shared by all
|
|
141
|
+
connections. Size an override for other runtime traffic and tools that make
|
|
142
|
+
multiple HTTP requests. Only an omitted or `undefined` policy selects the
|
|
143
|
+
default; malformed policies, including `false`, `null`, `0`, and `""`, throw
|
|
144
|
+
at construction on both auth variants.
|
|
145
|
+
|
|
78
146
|
Planning Center's `excludeApps` removes whole products from a connection, for
|
|
79
147
|
example `planningCenter("pco", { purpose, excludeApps: ["giving"] })` for a
|
|
80
148
|
deployment that keeps agents away from donor and financial data. Excluded
|
|
@@ -130,8 +198,8 @@ const service = remoteMcp("service", {
|
|
|
130
198
|
description: "Our team's hosted service",
|
|
131
199
|
auth: { type: "credential" },
|
|
132
200
|
});
|
|
133
|
-
// Add service to connectors. Configure the vault
|
|
134
|
-
//
|
|
201
|
+
// Add service to connectors. Configure the vault; a signed-in maintainer
|
|
202
|
+
// supplies its credential through the operator UI.
|
|
135
203
|
```
|
|
136
204
|
|
|
137
205
|
Credential auth defaults to an `Authorization: Bearer` header. Choose framing
|
|
@@ -198,10 +266,10 @@ schemas when known; runtime observations cannot replace them.
|
|
|
198
266
|
|
|
199
267
|
`authScope: "shared"` uses deployment-owned downstream auth; `"personal"` uses
|
|
200
268
|
the admitted principal's partition. Visibility is a different decision,
|
|
201
|
-
controlled by
|
|
269
|
+
controlled by maintainers and pool membership. A personal connector must not close
|
|
202
270
|
over a shared secret or derive its owner from arguments. Remote MCP refuses
|
|
203
271
|
literal header credentials with personal scope. Review
|
|
204
|
-
[
|
|
272
|
+
[maintainers and members](./auth.md#principals-visibility-and-operators) and
|
|
205
273
|
[management permissions](./auth.md#management-permissions) before exposing a
|
|
206
274
|
new integration or its authentication controls.
|
|
207
275
|
|
|
@@ -210,7 +278,13 @@ perform a bounded read. Add negative checks for target restrictions and writes
|
|
|
210
278
|
when authoring a handler or provider. Follow repository verification policy
|
|
211
279
|
when changing package code.
|
|
212
280
|
|
|
213
|
-
##
|
|
281
|
+
## Contributor reference
|
|
282
|
+
|
|
283
|
+
### Implementation and evidence
|
|
284
|
+
|
|
285
|
+
To implement a maintained provider in Connecta itself, follow the repository's
|
|
286
|
+
[add-provider skill](https://github.com/zackbart/connecta/blob/main/.claude/skills/add-provider/SKILL.md)
|
|
287
|
+
and [AGENTS.md](https://github.com/zackbart/connecta/blob/main/AGENTS.md).
|
|
214
288
|
|
|
215
289
|
Factory contracts live in [remote MCP](https://github.com/zackbart/connecta/blob/main/src/connectors/remote-mcp.ts),
|
|
216
290
|
[API connector](https://github.com/zackbart/connecta/blob/main/src/connectors/api-connector.ts),
|