@zackbart/connecta 0.21.1 → 0.22.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 +83 -0
- package/README.md +7 -0
- package/dist/access-tokens.d.ts +2 -2
- package/dist/access-tokens.js +14 -2
- package/dist/auth/downstream-oauth.d.ts +65 -2
- package/dist/auth/downstream-oauth.js +408 -20
- package/dist/connectors/api.d.ts +2 -0
- package/dist/connectors/api.js +1 -0
- package/dist/connectors/remote-mcp.d.ts +2 -0
- package/dist/connectors/remote-mcp.js +14 -4
- package/dist/credentials.d.ts +6 -6
- package/dist/credentials.js +25 -21
- package/dist/executors/quickjs.js +4 -0
- package/dist/identity.d.ts +4 -0
- package/dist/identity.js +17 -0
- package/dist/index.d.ts +16 -2
- package/dist/index.js +6 -1
- package/dist/meta-tools.js +7 -2
- package/dist/operator-ui/generated.js +1 -1
- package/dist/operator-ui/model.d.ts +4 -2
- package/dist/operator-ui/view.js +1 -1
- package/dist/providers/cloudflare.d.ts +2 -0
- package/dist/providers/cloudflare.js +1 -0
- package/dist/providers/linear.d.ts +2 -0
- package/dist/providers/linear.js +1 -0
- package/dist/providers/mixpanel.d.ts +2 -0
- package/dist/providers/mixpanel.js +1 -0
- package/dist/providers/notion.d.ts +2 -0
- package/dist/providers/notion.js +1 -0
- package/dist/providers/revenuecat.d.ts +2 -0
- package/dist/providers/revenuecat.js +1 -0
- package/dist/providers/stripe.d.ts +2 -0
- package/dist/providers/stripe.js +1 -0
- package/dist/registry.d.ts +25 -0
- package/dist/registry.js +200 -4
- package/dist/routes/access-tokens.js +2 -2
- package/dist/routes/activity.js +4 -1
- package/dist/routes/credentials.js +31 -12
- package/dist/routes/mcp.js +17 -2
- package/dist/routes/oauth.js +55 -11
- package/dist/routes/shared.d.ts +20 -4
- package/dist/routes/shared.js +92 -24
- package/dist/routes/ui.js +32 -13
- package/dist/types.d.ts +28 -2
- package/dist/ui.d.ts +3 -3
- package/dist/ui.js +18 -5
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/documentation/architecture.md +31 -8
- package/documentation/auth.md +90 -10
- package/documentation/code-mode.md +4 -4
- package/documentation/connectors.md +13 -0
- package/documentation/meta-tools.md +4 -3
- package/documentation/operations.md +5 -3
- package/documentation/operator-ui.md +13 -4
- package/documentation/request-admission.md +2 -1
- package/documentation/storage-and-credentials.md +77 -4
- package/documentation/upgrading.md +38 -7
- package/ethos.md +8 -8
- package/examples/worker/AGENTS.md +44 -0
- package/examples/worker/README.md +63 -14
- package/examples/worker/src/index.ts +26 -22
- package/package.json +1 -1
- package/templates/node/README.md +7 -0
- package/templates/node/package.json +1 -1
- package/templates/node/src/index.ts +13 -4
|
@@ -46,15 +46,56 @@ wrangler deploy
|
|
|
46
46
|
Cloudflare Access to the Worker itself (the API destination type is `worker`,
|
|
47
47
|
not a hostname application) and choose the account, email-domain, or
|
|
48
48
|
advanced Zero Trust policy that owns admission. Enable **Managed OAuth** on
|
|
49
|
-
that Access application for interactive MCP clients
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
49
|
+
that Access application for interactive MCP clients, turn on Dynamic Client
|
|
50
|
+
Registration, and add these three entries under **Allowed redirect URIs**:
|
|
51
|
+
|
|
52
|
+
```text
|
|
53
|
+
https://claude.ai/api/mcp/auth_callback
|
|
54
|
+
https://chatgpt.com/connector_platform_oauth_redirect
|
|
55
|
+
https://chatgpt.com/connector/oauth/*
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The Claude entry is its fixed hosted-MCP callback. ChatGPT may register either
|
|
59
|
+
its stable callback or a callback-id URL, so both forms are intentional. These
|
|
60
|
+
are Managed OAuth application settings, represented by
|
|
61
|
+
`oauth_configuration.dynamic_client_registration.allowed_uris` in the Access
|
|
62
|
+
API; they do not belong in the Access Allow policy that decides who may sign
|
|
63
|
+
in. Leaving the list empty is a footgun: discovery still works, then Dynamic
|
|
64
|
+
Client Registration fails because the callback is not allowed. If either
|
|
65
|
+
client presents a new redirect URI, copy that exact value from the registration
|
|
66
|
+
attempt and add the narrowest matching entry rather than allowing its entire
|
|
67
|
+
origin.
|
|
68
|
+
|
|
69
|
+
Access then serves OAuth discovery and turns the client's opaque token into the
|
|
70
|
+
trusted `ctx.access` identity connecta reads. A cron job or CI client uses an
|
|
71
|
+
Access service token instead.
|
|
72
|
+
|
|
73
|
+
Through the API, the relevant part of the application is:
|
|
74
|
+
|
|
75
|
+
```json
|
|
76
|
+
{
|
|
77
|
+
"oauth_configuration": {
|
|
78
|
+
"enabled": true,
|
|
79
|
+
"dynamic_client_registration": {
|
|
80
|
+
"enabled": true,
|
|
81
|
+
"allowed_uris": [
|
|
82
|
+
"https://claude.ai/api/mcp/auth_callback",
|
|
83
|
+
"https://chatgpt.com/connector_platform_oauth_redirect",
|
|
84
|
+
"https://chatgpt.com/connector/oauth/*"
|
|
85
|
+
]
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
```
|
|
53
90
|
|
|
54
91
|
Cloudflare's [Worker Access guide](https://developers.cloudflare.com/workers/configuration/cloudflare-access/)
|
|
55
92
|
owns the dashboard/API steps; its [Managed OAuth guide](https://developers.cloudflare.com/cloudflare-one/access-controls/applications/http-apps/managed-oauth/)
|
|
56
93
|
owns client registration, redirect allowlists, and token lifetimes.
|
|
57
94
|
|
|
95
|
+
[`AGENTS.md`](./AGENTS.md) repeats the callback invariant for coding agents
|
|
96
|
+
working in a copied deployment. Do not remove the entries there when changing
|
|
97
|
+
the Access policy or application.
|
|
98
|
+
|
|
58
99
|
The checked-in `access.dev` block gives `wrangler dev` a local operator
|
|
59
100
|
identity. Remove the block to test the missing-Access refusal. It has no effect
|
|
60
101
|
on a deployed Worker's production identity.
|
|
@@ -75,13 +116,9 @@ connecta's manifest but never installed with it, and published as
|
|
|
75
116
|
one outside and npm says so at install time instead of leaving a Worker to
|
|
76
117
|
discover the skew in production ([#376](https://github.com/zackbart/connecta/issues/376)).
|
|
77
118
|
|
|
78
|
-
`cloudflareAccessAuth()` has no dependency of its own.
|
|
79
|
-
Clerk
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
```sh
|
|
83
|
-
npm install @clerk/backend # migration window only
|
|
84
|
-
```
|
|
119
|
+
`cloudflareAccessAuth()` has no dependency of its own. This Worker example has
|
|
120
|
+
no Clerk import, secret, package, or fallback provider. Docker deployments keep
|
|
121
|
+
the Clerk path in the Node template.
|
|
85
122
|
|
|
86
123
|
Then point an MCP client at `<PUBLIC_URL>/mcp`, and open `<PUBLIC_URL>/` for
|
|
87
124
|
Connections. Credentials is at `/credentials`, named MCP access tokens are at
|
|
@@ -96,9 +133,21 @@ as deployed; the fourth needs a database, so it is commented in place.
|
|
|
96
133
|
|
|
97
134
|
**Operator sign-in** is the `cloudflareAccessAuth()` entry in `src/index.ts`.
|
|
98
135
|
Access authenticates before the Worker runs. A human Access identity can use
|
|
99
|
-
MCP and
|
|
100
|
-
credential, run downstream OAuth, or issue a connecta token.
|
|
101
|
-
|
|
136
|
+
MCP and human-management pages; a service-token identity can use MCP but cannot
|
|
137
|
+
write a credential, run downstream OAuth, or issue a connecta token. Cloudflare
|
|
138
|
+
still owns the outer application admission policy, but Connecta's user roster,
|
|
139
|
+
connector access, and deployment roles stay in `src/index.ts`.
|
|
140
|
+
|
|
141
|
+
**Several users** need no second auth system or Connecta account dashboard.
|
|
142
|
+
Uncomment the `identity` block in `src/index.ts` to derive connector ids and
|
|
143
|
+
deployment-operator membership from the Access principal. Connectors remain
|
|
144
|
+
visible to everyone and every human remains an operator when that block is
|
|
145
|
+
absent. A signed-in human may edit auth for every connector their view includes.
|
|
146
|
+
Add `authScope: "personal"` when each user should connect a different downstream
|
|
147
|
+
account; leave it shared only when any user with connector access may rotate the
|
|
148
|
+
deployment-wide grant. Static headers stay shared because their value lives in
|
|
149
|
+
deployment configuration. See [inbound identity](../../documentation/auth.md#principals-visibility-and-operators)
|
|
150
|
+
for the resolver contract.
|
|
102
151
|
|
|
103
152
|
**The credential vault** is `credentials: { encryptionKey: … }`, backed by the
|
|
104
153
|
same KV namespace as everything else and encrypted with the
|
|
@@ -17,15 +17,17 @@
|
|
|
17
17
|
* 1. `npm install` in the connecta package root (../../ from here) so the
|
|
18
18
|
* package import and wrangler resolve. A copy in its own repository
|
|
19
19
|
* installs `@zackbart/connecta @cloudflare/codemode` instead. Codemode is
|
|
20
|
-
* an optional peer
|
|
21
|
-
* until it removes the commented rollback provider below.
|
|
20
|
+
* an optional peer.
|
|
22
21
|
* 2. Create a KV namespace and put its id in wrangler.jsonc under `kv_namespaces`.
|
|
23
22
|
* 3. Set secrets:
|
|
24
23
|
* wrangler secret put DOWNSTREAM_TOKEN
|
|
25
24
|
* wrangler secret put CREDENTIAL_ENCRYPTION_KEY
|
|
26
25
|
* and PUBLIC_URL as a plain var in wrangler.jsonc.
|
|
27
|
-
* 4. Attach Cloudflare Access to this Worker. Enable Managed OAuth
|
|
28
|
-
*
|
|
26
|
+
* 4. Attach Cloudflare Access to this Worker. Enable Managed OAuth and
|
|
27
|
+
* Dynamic Client Registration. Its Allowed redirect URIs must include
|
|
28
|
+
* Claude's https://claude.ai/api/mcp/auth_callback plus ChatGPT's
|
|
29
|
+
* https://chatgpt.com/connector_platform_oauth_redirect and
|
|
30
|
+
* https://chatgpt.com/connector/oauth/* forms (see ../AGENTS.md).
|
|
29
31
|
* 5. Use the Workers Paid plan required by the `worker_loaders` binding.
|
|
30
32
|
* 6. `wrangler deploy` from this folder (examples/worker), where wrangler.jsonc
|
|
31
33
|
* lives. Point your MCP client at `<PUBLIC_URL>/mcp`.
|
|
@@ -37,17 +39,12 @@ import {
|
|
|
37
39
|
remoteMcp,
|
|
38
40
|
} from "@zackbart/connecta";
|
|
39
41
|
import { cloudflareAccessAuth } from "@zackbart/connecta/auth/cloudflare-access";
|
|
40
|
-
// Rollback for a deployment migrating from Clerk:
|
|
41
|
-
// import { clerkAuth } from "@zackbart/connecta/auth/clerk";
|
|
42
42
|
import { cloudflareKvStorage } from "./cloudflare-kv.js";
|
|
43
43
|
// Activity history, off by default because it needs a D1 database.
|
|
44
44
|
// import { d1ActivityStore } from "./d1-activity.js";
|
|
45
45
|
|
|
46
46
|
interface Env {
|
|
47
47
|
CONNECTA_KV: KVNamespace;
|
|
48
|
-
// Keep these during a Clerk migration until Access has been verified:
|
|
49
|
-
// CLERK_PUBLISHABLE_KEY: string;
|
|
50
|
-
// CLERK_SECRET_KEY: string;
|
|
51
48
|
/**
|
|
52
49
|
* Base64 32-byte AES key encrypting operator-managed credentials in KV.
|
|
53
50
|
* Unset means no vault: /credentials stays read-only and connecta says so at
|
|
@@ -75,20 +72,24 @@ function build(env: Env) {
|
|
|
75
72
|
// operator pages; a service token may use MCP but cannot mutate operator
|
|
76
73
|
// state. Neither path asks connecta to parse a JWT.
|
|
77
74
|
cloudflareAccessAuth(),
|
|
78
|
-
// Leave the previous Clerk provider below this entry during migration.
|
|
79
|
-
// It is a rollback path until Worker-level Access is detached; Access
|
|
80
|
-
// itself decides whether a request reaches this array.
|
|
81
|
-
// clerkAuth({
|
|
82
|
-
// publishableKey: env.CLERK_PUBLISHABLE_KEY,
|
|
83
|
-
// secretKey: env.CLERK_SECRET_KEY,
|
|
84
|
-
// publicUrl: env.PUBLIC_URL,
|
|
85
|
-
// allowedDomains: ["acme.com"],
|
|
86
|
-
// }),
|
|
87
75
|
],
|
|
88
|
-
//
|
|
89
|
-
//
|
|
90
|
-
//
|
|
91
|
-
//
|
|
76
|
+
// Optional code-owned roster. Access proves the identity; connecta derives
|
|
77
|
+
// connector visibility and deployment-operator status from the stable id
|
|
78
|
+
// it supplies. A signed-in human may manage auth for every connector this
|
|
79
|
+
// view includes. Omit the block to keep every connector visible and every
|
|
80
|
+
// human a deployment operator.
|
|
81
|
+
// identity: {
|
|
82
|
+
// connectorAccess: ({ principal }) =>
|
|
83
|
+
// principal?.id === "ACCESS_USER_UUID"
|
|
84
|
+
// ? ["notion", "echo"]
|
|
85
|
+
// : ["echo"],
|
|
86
|
+
// operatorAccess: ({ id }) => id === "ACCESS_USER_UUID",
|
|
87
|
+
// },
|
|
88
|
+
// Connectors that declare a `credential` slot become editable by every
|
|
89
|
+
// signed-in human who can see that connector at /credentials, encrypted
|
|
90
|
+
// with this key before anything reaches KV. A saved replacement takes
|
|
91
|
+
// effect on the next call — no redeploy, and no liveness probe:
|
|
92
|
+
// credentials fail at use.
|
|
92
93
|
//
|
|
93
94
|
// The key is the vault, not the page: /credentials is a list of connector
|
|
94
95
|
// slots, so it stays hidden until a connector declares one. Neither
|
|
@@ -123,6 +124,9 @@ function build(env: Env) {
|
|
|
123
124
|
// type: "credential",
|
|
124
125
|
// credential: { label: "Notion internal integration token" },
|
|
125
126
|
},
|
|
127
|
+
// Use `authScope: "personal"` with OAuth or credential auth when each
|
|
128
|
+
// Access user connects their own downstream account. Literal headers
|
|
129
|
+
// are deployment-owned and cannot be personal.
|
|
126
130
|
}),
|
|
127
131
|
api("echo", {
|
|
128
132
|
description: "Echo — text transforms",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zackbart/connecta",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.22.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 seven meta-tools.",
|
package/templates/node/README.md
CHANGED
|
@@ -68,6 +68,13 @@ import, the two `process.env.CLERK_*` reads, and the `clerkAuth({ … })` entry
|
|
|
68
68
|
Applications → DCR) if MCP clients should sign in through it too, and set
|
|
69
69
|
`PUBLIC_URL` first — Clerk redirects back to it.
|
|
70
70
|
|
|
71
|
+
Clerk remains the identity provider when several people share this Docker
|
|
72
|
+
deployment. Uncomment the `identity` block in `src/index.ts` to give each Clerk
|
|
73
|
+
principal a config-derived connector view and to choose operators. Add
|
|
74
|
+
`authScope: "personal"` to a connector when each person should supply their own
|
|
75
|
+
credential or finish their own downstream OAuth flow. Without those options,
|
|
76
|
+
all connectors and auth stay shared exactly as before.
|
|
77
|
+
|
|
71
78
|
**2. Credential vault.** Uncomment `credentials` and set
|
|
72
79
|
`CONNECTA_CREDENTIAL_KEY` to a base64 32-byte AES key:
|
|
73
80
|
|
|
@@ -42,10 +42,10 @@ const stateFile = process.env.CONNECTA_STATE_FILE || "./.connecta-state.json";
|
|
|
42
42
|
const publicUrl = process.env.PUBLIC_URL || `http://localhost:${port}`;
|
|
43
43
|
|
|
44
44
|
// Operator sign-in. A bearer token is a client key: it may call tools and read
|
|
45
|
-
// connector status, but only a Clerk-authenticated
|
|
46
|
-
// credential
|
|
47
|
-
// still render — an operator pastes the
|
|
48
|
-
// and Tokens stay read-only.
|
|
45
|
+
// connector status, but only a Clerk-authenticated human may write a visible
|
|
46
|
+
// connector's credential, and only an operator may issue an access token.
|
|
47
|
+
// Without this block the operator pages still render — an operator pastes the
|
|
48
|
+
// bearer to read them — and Credentials and Tokens stay read-only.
|
|
49
49
|
// const clerkPublishableKey = process.env.CLERK_PUBLISHABLE_KEY;
|
|
50
50
|
// const clerkSecretKey = process.env.CLERK_SECRET_KEY;
|
|
51
51
|
// if (!clerkPublishableKey || !clerkSecretKey) {
|
|
@@ -67,6 +67,15 @@ const connecta = createConnecta({
|
|
|
67
67
|
// // allowedDomains: ["acme.com"],
|
|
68
68
|
// }),
|
|
69
69
|
],
|
|
70
|
+
// Optional member/operator split for Clerk-backed Docker deployments.
|
|
71
|
+
// Connector access is derived from the authenticated identity and cannot be
|
|
72
|
+
// selected by an MCP argument. Omit this block for the legacy all-visible,
|
|
73
|
+
// all-interactive-users-are-operators behavior.
|
|
74
|
+
// identity: {
|
|
75
|
+
// connectorAccess: ({ principal }) =>
|
|
76
|
+
// principal?.id === "user_admin" ? "all" : ["time"],
|
|
77
|
+
// operatorAccess: ({ id }) => id === "user_admin",
|
|
78
|
+
// },
|
|
70
79
|
publicUrl,
|
|
71
80
|
// Required: model-written programs run in a bounded QuickJS child.
|
|
72
81
|
executor: quickJsExecutor(),
|