@zackbart/connecta 0.31.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 +97 -0
- package/README.md +30 -20
- package/bin/connecta.mjs +25 -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/auth-elicitation.js +1 -1
- 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 +7 -2
- package/dist/config-value-sources.js +14 -9
- package/dist/config.d.ts +58 -78
- package/dist/config.js +143 -47
- package/dist/connector-access.d.ts +4 -33
- 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/guarded-fetch.d.ts +9 -0
- package/dist/connectors/guarded-fetch.js +7 -0
- package/dist/connectors/remote-mcp.js +2 -0
- package/dist/describe-config.d.ts +32 -7
- package/dist/describe-config.js +9 -18
- package/dist/errors.d.ts +1 -1
- package/dist/errors.js +1 -0
- package/dist/execute.js +16 -14
- package/dist/index.d.ts +4 -3
- package/dist/index.js +30 -10
- package/dist/invocation.js +12 -7
- package/dist/membership.d.ts +51 -0
- package/dist/membership.js +121 -0
- package/dist/meta-tools.js +17 -19
- package/dist/module-contracts.d.ts +23 -6
- package/dist/operator-record.d.ts +2 -2
- package/dist/operator-record.js +2 -2
- package/dist/operator-ui/agents.d.ts +74 -0
- package/dist/operator-ui/agents.js +104 -0
- package/dist/operator-ui/contract.d.ts +151 -29
- 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 +15 -7
- package/dist/operator-ui/view.d.ts +84 -19
- package/dist/operator-ui/view.js +83 -21
- package/dist/page-styles.js +1 -1
- package/dist/program-writes.js +2 -2
- package/dist/provider.d.ts +63 -11
- package/dist/provider.js +46 -7
- package/dist/providers/_shared/google/workspace.d.ts +53 -16
- package/dist/providers/_shared/google/workspace.js +31 -9
- 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/breeze/skill.generated.js +2 -2
- 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 +2 -2
- package/dist/providers/cloudflare/value-safety.js +32 -0
- package/dist/providers/docs/index.d.ts +1 -1
- package/dist/providers/docs/index.js +5 -5
- package/dist/providers/docs/skill.generated.js +2 -2
- package/dist/providers/drive/index.d.ts +1 -1
- package/dist/providers/drive/index.js +4 -4
- package/dist/providers/drive/skill.generated.js +2 -2
- package/dist/providers/forms/index.d.ts +1 -1
- package/dist/providers/forms/index.js +5 -5
- package/dist/providers/forms/skill.generated.js +2 -2
- package/dist/providers/github/skill.generated.js +2 -2
- package/dist/providers/gmail/index.d.ts +1 -1
- package/dist/providers/gmail/index.js +279 -26
- package/dist/providers/gmail/skill.generated.js +2 -2
- package/dist/providers/linear/index.js +1 -1
- package/dist/providers/mixpanel/index.d.ts +27 -12
- package/dist/providers/mixpanel/index.js +58 -6
- package/dist/providers/mixpanel/operations.js +20 -0
- package/dist/providers/mixpanel/rest.js +603 -0
- package/dist/providers/mixpanel/skill.generated.js +3 -2
- package/dist/providers/mixpanel/value-safety.js +16 -0
- package/dist/providers/notion/index.d.ts +7 -0
- package/dist/providers/notion/index.js +116 -11
- package/dist/providers/notion/rest.js +183 -24
- package/dist/providers/notion/skill.generated.js +4 -4
- package/dist/providers/notion/value-safety.js +30 -5
- package/dist/providers/overflow/index.js +1 -1
- package/dist/providers/planning-center/index.d.ts +27 -0
- package/dist/providers/planning-center/index.js +287 -25
- package/dist/providers/planning-center/skill.generated.js +24 -4
- package/dist/providers/sheets/index.d.ts +4 -1
- package/dist/providers/sheets/index.js +9 -6
- package/dist/providers/sheets/skill.generated.js +2 -2
- package/dist/providers/slides/index.d.ts +1 -1
- package/dist/providers/slides/index.js +6 -6
- package/dist/providers/slides/skill.generated.js +2 -2
- package/dist/providers/stripe/rest.js +9 -2
- package/dist/providers/stripe/skill.generated.js +2 -2
- package/dist/providers/stripe/value-safety.js +22 -0
- package/dist/providers/vercel/index.js +2 -2
- 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/providers/wispr-flow/index.d.ts +14 -0
- package/dist/providers/wispr-flow/index.js +117 -0
- package/dist/providers/wispr-flow/skill.generated.js +8 -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 +155 -85
- package/dist/routes/oauth-management.js +11 -5
- package/dist/routes/oauth.js +3 -9
- package/dist/routes/operator.js +25 -17
- 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 +8 -0
- package/dist/skills.js +5 -4
- package/dist/storage/keys.js +9 -1
- package/dist/tool-safety.js +13 -5
- package/dist/types.d.ts +12 -1
- package/dist/ui.d.ts +2 -2
- package/dist/ui.js +17 -15
- package/dist/usage-guide.js +3 -3
- 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 +378 -58
- package/documentation/auth.md +806 -215
- package/documentation/code-mode.md +93 -81
- package/documentation/deploying.md +128 -26
- package/documentation/integrating.md +145 -22
- package/documentation/meta-tools.md +58 -46
- package/documentation/migration-0.33.md +344 -0
- package/documentation/operating.md +14 -9
- package/documentation/operator-tests.md +117 -31
- package/documentation/operator-ui.md +326 -55
- package/documentation/provider-auth-migration.md +42 -27
- package/documentation/provider-migration-0.29.md +3 -3
- package/examples/worker/AGENTS.md +35 -8
- package/examples/worker/README.md +92 -53
- package/examples/worker/src/connecta.config.ts +41 -20
- package/examples/worker/wrangler.jsonc +3 -0
- package/package.json +7 -2
- package/templates/node/.env.example +3 -0
- package/templates/node/AGENTS.md +33 -10
- package/templates/node/Dockerfile +2 -2
- package/templates/node/README.md +71 -44
- 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 +33 -12
- package/templates/node/src/rotate-token.ts +17 -0
- package/dist/tool-safety.d.ts +0 -9
- package/templates/node/src/provision-token.ts +0 -17
|
@@ -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,20 +89,30 @@ 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 Connecta
|
|
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
|
|
|
107
|
+
Wispr Flow uses OAuth only through `wisprFlow()` from
|
|
108
|
+
`@zackbart/connecta/providers/wispr-flow`. It reaches the authorized account's
|
|
109
|
+
Notetaker content, with personal and work accounts holding separate data.
|
|
110
|
+
Its runtime guide, available through `connecta.skill("connector:<id>")` in `execute_code`, describes account access,
|
|
111
|
+
search limits, transcript permissions and paging. The
|
|
112
|
+
reviewed classification includes task writes listed in Claude's directory even
|
|
113
|
+
though Wispr's public help describes read-only access; discover the account's
|
|
114
|
+
actual tools before assuming those writes exist.
|
|
115
|
+
|
|
52
116
|
Stripe requires `auth`: `{ type: "oauth" }` reaches Stripe's hosted MCP
|
|
53
117
|
server, and `{ type: "apiKey" }` with `mode` reaches Connecta's REST connector
|
|
54
118
|
with an operator-managed key. Notion requires `auth` the same way:
|
|
@@ -66,6 +130,58 @@ MCP clients to its hosted server, an operational gate outside Connecta. See the
|
|
|
66
130
|
To use both implementations of one provider, configure two connector ids with
|
|
67
131
|
independent credentials.
|
|
68
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
|
+
|
|
143
|
+
Planning Center's `excludeApps` removes whole products from a connection, for
|
|
144
|
+
example `planningCenter("pco", { purpose, excludeApps: ["giving"] })` for a
|
|
145
|
+
deployment that keeps agents away from donor and financial data. Excluded
|
|
146
|
+
products lose their named tools, guide text, and version pins, and the
|
|
147
|
+
`pco_api_get` and `pco_api_mutate` hatches refuse their paths before sending.
|
|
148
|
+
The check reads the exact URL the transport would fetch, and while any product
|
|
149
|
+
is excluded a hatch path must be literal: dot segments, empty segments,
|
|
150
|
+
backslashes, whitespace, and percent-encoded `/`, `\`, `?`, `#`, or `%` are
|
|
151
|
+
refused rather than normalized.
|
|
152
|
+
|
|
153
|
+
Exclusion also closes the routes through which the excluded product's data is
|
|
154
|
+
reachable through another product. While any product is excluded the connection removes
|
|
155
|
+
`list_lists`, `list_list_people`, and `run_list` and refuses every People list,
|
|
156
|
+
list result, rule, and condition, by path or `include`, because a list's
|
|
157
|
+
conditions can draw on any product, such as a donor list built from Giving
|
|
158
|
+
donations, and lists can depend on other lists. Planning Center publishes a
|
|
159
|
+
list's conditions, but a reliable check would have to follow every nested list,
|
|
160
|
+
so the connection does not attempt one. It refuses webhook event and delivery
|
|
161
|
+
payloads, since a payload can carry any product's records, and every change to
|
|
162
|
+
an existing webhook subscription by id, since the id does not name its product.
|
|
163
|
+
A new subscription must name a reachable product's event. People cannot be
|
|
164
|
+
excluded.
|
|
165
|
+
|
|
166
|
+
What exclusion guarantees is that agents reach none of the excluded product's
|
|
167
|
+
endpoints, no live cross-product query such as a People list, and no webhook
|
|
168
|
+
payload or change to an existing subscription. It does not hide records that the church's own
|
|
169
|
+
automations or staff have copied into a reachable product. A
|
|
170
|
+
[Giving automation](https://help.planningcenter.com/en/144355-automations-in-giving.html)
|
|
171
|
+
can add first-time donors to a People workflow, and those workflow cards stay
|
|
172
|
+
readable, as do donor details recorded in notes, custom fields, or form
|
|
173
|
+
answers. Those are People data once written, so the connection does not refuse
|
|
174
|
+
them by guessing at their origin.
|
|
175
|
+
|
|
176
|
+
For a hard boundary, give the connection a personal access token belonging to a
|
|
177
|
+
Planning Center user with No Access in the excluded product. Planning Center
|
|
178
|
+
sets permissions per product for each user, does not grant Giving to
|
|
179
|
+
organization administrators automatically, and lets People workflows be shared
|
|
180
|
+
per workflow; a token carries its user's permissions, so Planning Center itself
|
|
181
|
+
refuses what that user cannot see. `excludeApps` is defense in depth on top of
|
|
182
|
+
that boundary: it narrows what Connecta exposes, not what the token can do
|
|
183
|
+
elsewhere.
|
|
184
|
+
|
|
69
185
|
## Another remote MCP server
|
|
70
186
|
|
|
71
187
|
Declare its endpoint and intended auth mode. This fragment uses a server-stored
|
|
@@ -79,8 +195,8 @@ const service = remoteMcp("service", {
|
|
|
79
195
|
description: "Our team's hosted service",
|
|
80
196
|
auth: { type: "credential" },
|
|
81
197
|
});
|
|
82
|
-
// Add service to connectors. Configure the vault
|
|
83
|
-
//
|
|
198
|
+
// Add service to connectors. Configure the vault; a signed-in maintainer
|
|
199
|
+
// supplies its credential through the operator UI.
|
|
84
200
|
```
|
|
85
201
|
|
|
86
202
|
Credential auth defaults to an `Authorization: Bearer` header. Choose framing
|
|
@@ -137,19 +253,20 @@ which binds the grant to configured API origins and manages authentication.
|
|
|
137
253
|
[Downstream OAuth on api()](./auth.md#downstream-oauth-on-api) owns a concrete
|
|
138
254
|
HTTP example and the client setup contract.
|
|
139
255
|
|
|
140
|
-
Mark every side-effecting tool `readOnlyHint: false`. On
|
|
141
|
-
writes use `call_destructive_tool
|
|
142
|
-
|
|
256
|
+
Mark every side-effecting tool `readOnlyHint: false`. On a writable endpoint
|
|
257
|
+
writes use `call_destructive_tool` or a program, within the caller's grants; a
|
|
258
|
+
`readOnly` endpoint refuses them and omits them from search. Client approval is independent of
|
|
259
|
+
tool definition. Use declared output
|
|
143
260
|
schemas when known; runtime observations cannot replace them.
|
|
144
261
|
|
|
145
262
|
## Separate ownership from visibility
|
|
146
263
|
|
|
147
264
|
`authScope: "shared"` uses deployment-owned downstream auth; `"personal"` uses
|
|
148
265
|
the admitted principal's partition. Visibility is a different decision,
|
|
149
|
-
controlled by
|
|
266
|
+
controlled by maintainers and pool membership. A personal connector must not close
|
|
150
267
|
over a shared secret or derive its owner from arguments. Remote MCP refuses
|
|
151
268
|
literal header credentials with personal scope. Review
|
|
152
|
-
[
|
|
269
|
+
[maintainers and members](./auth.md#principals-visibility-and-operators) and
|
|
153
270
|
[management permissions](./auth.md#management-permissions) before exposing a
|
|
154
271
|
new integration or its authentication controls.
|
|
155
272
|
|
|
@@ -158,7 +275,13 @@ perform a bounded read. Add negative checks for target restrictions and writes
|
|
|
158
275
|
when authoring a handler or provider. Follow repository verification policy
|
|
159
276
|
when changing package code.
|
|
160
277
|
|
|
161
|
-
##
|
|
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).
|
|
162
285
|
|
|
163
286
|
Factory contracts live in [remote MCP](https://github.com/zackbart/connecta/blob/main/src/connectors/remote-mcp.ts),
|
|
164
287
|
[API connector](https://github.com/zackbart/connecta/blob/main/src/connectors/api-connector.ts),
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Connecta keeps one small tool surface in model context and resolves downstream
|
|
4
4
|
tools behind it. `search_tools` finds addresses, the call tools enforce the
|
|
5
|
-
stored classification, `execute_code` runs programs
|
|
5
|
+
stored classification, `execute_code` runs programs on a writable or read-only endpoint, and `connecta.result` inside programs
|
|
6
6
|
pages bounded results.
|
|
7
7
|
|
|
8
8
|
This guide is the contract an MCP client sees. The in-program `connecta.*` API
|
|
@@ -31,10 +31,13 @@ configuration adds a seventh or removes one, so a client's cached tool list
|
|
|
31
31
|
never depends on the storage behind the deployment. There was an eighth,
|
|
32
32
|
`resume_execution`, while programs paused at writes; it left with pausing
|
|
33
33
|
([#672](https://github.com/zackbart/connecta/issues/672)). `execute_code`
|
|
34
|
-
is annotated `readOnlyHint: true, destructiveHint: false` on a
|
|
35
|
-
endpoint, and `readOnlyHint: false, destructiveHint: true` on a
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
is annotated `readOnlyHint: true, destructiveHint: false` on a read-only
|
|
35
|
+
endpoint, and `readOnlyHint: false, destructiveHint: true` on a writable one.
|
|
36
|
+
Approval belongs to the client. A read-only endpoint keeps all six tools, omits
|
|
37
|
+
write tools from `search_tools` results and describe, and refuses every write
|
|
38
|
+
call; `readOnly` never changes connector visibility or read grants. Guides
|
|
39
|
+
(`queryAnalysis.guideSummary`, `skills`, `connecta.skill`, skill
|
|
40
|
+
`resources/read`) are documentation and may name tools the endpoint refuses. The four tools with structured-only success results
|
|
38
41
|
advertise `outputSchema`. The two direct-call tools omit it because their default
|
|
39
42
|
mode returns native `content`. Default-mode successes declare
|
|
40
43
|
`_meta["dev.connecta/format"]: "json" | "text"`; value mode places the value in
|
|
@@ -70,9 +73,11 @@ credentials, logs, or raw error text.
|
|
|
70
73
|
|
|
71
74
|
Connecta's discovery tools carry read-only hints. `authorize_connector`
|
|
72
75
|
requests interactive authentication changes; `call_destructive_tool` sends
|
|
73
|
-
writes and is annotated destructive. `execute_code`
|
|
74
|
-
|
|
75
|
-
program
|
|
76
|
+
writes and is annotated destructive. `execute_code` states whether the endpoint
|
|
77
|
+
is read-only or writable in its description and annotations. On a writable
|
|
78
|
+
endpoint the client may approve the whole program as a write. On a read-only
|
|
79
|
+
endpoint, the `call_tool`, `call_destructive_tool`, and `search_tools`
|
|
80
|
+
descriptions say so too; `call_destructive_tool` still runs reads there. `call_destructive_tool.reason` is dropped before
|
|
76
81
|
anything runs.
|
|
77
82
|
|
|
78
83
|
## Routing between the call surfaces
|
|
@@ -93,12 +98,16 @@ page the completed direct-call result or oversized program return with
|
|
|
93
98
|
`connecta.result` after the write runs once. Sampling or slicing a write's output
|
|
94
99
|
inside the program can still discard the answer.
|
|
95
100
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
`
|
|
100
|
-
|
|
101
|
-
|
|
101
|
+
On a writable endpoint the same program discovers and dispatches writes, capped
|
|
102
|
+
by `execute.maxWrites`, and `call_destructive_tool` sends one known write. On a
|
|
103
|
+
read-only endpoint nothing writes: `search_tools`, `connecta.search`, and
|
|
104
|
+
`connecta.describe` omit write tools as if the connector lacked them, and
|
|
105
|
+
every write call through `call_tool`, `call_destructive_tool`, or a program is
|
|
106
|
+
refused before validation or dispatch with `read_only_endpoint`,
|
|
107
|
+
`retryable: false`, and no `nextAction`. Connector guides are not filtered and
|
|
108
|
+
may still name such a write. No route on that endpoint writes; the agent
|
|
109
|
+
reports it. Connecta
|
|
110
|
+
never pauses, replays, or approves a program.
|
|
102
111
|
|
|
103
112
|
Both search routes return the flat page specified under
|
|
104
113
|
[lexical discovery](#lexical-discovery), using the catalog's shared output schema.
|
|
@@ -129,14 +138,14 @@ Read-only lookup belongs in `connecta.search` inside the program; top-level
|
|
|
129
138
|
`search_tools` stays for explicit catalog inspection and approval-required
|
|
130
139
|
discovery. Both take the same arguments.
|
|
131
140
|
|
|
132
|
-
| Argument | What it does
|
|
133
|
-
| ------------------ |
|
|
134
|
-
| `query` | two to four action/object terms; empty or whitespace-only browses
|
|
135
|
-
| `connector` | scopes to one id, loading that catalog alone instead of fanning out across every configured connector. Set it when the integration is obvious, omit it when the right one is genuinely ambiguous
|
|
136
|
-
| `safety` | `"readOnly"` selects stored `read` verdicts; `"approvalRequired"` selects stored `write` verdicts; omitted or `"all"` selects both. Each row carries `classification: "read" \| "write"`. These legacy filter names do not describe
|
|
137
|
-
| `limit` / `offset` | page the ranked results; omit `limit` initially so the default eight-result page stays small
|
|
138
|
-
| `includeSchemas` | `"compact"` for the rendered routing view, `"json"` for the exact schema, `"typescript"` for a function signature ([below](#typescript-signatures))
|
|
139
|
-
| `fullDescriptions` | unabridged tool purposes, at the obvious cost
|
|
141
|
+
| Argument | What it does |
|
|
142
|
+
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
143
|
+
| `query` | two to four action/object terms; empty or whitespace-only browses |
|
|
144
|
+
| `connector` | scopes to one id, loading that catalog alone instead of fanning out across every configured connector. Set it when the integration is obvious, omit it when the right one is genuinely ambiguous |
|
|
145
|
+
| `safety` | `"readOnly"` selects stored `read` verdicts; `"approvalRequired"` selects stored `write` verdicts; omitted or `"all"` selects both. Each row carries `classification: "read" \| "write"`. These legacy filter names do not describe client approval policy; a read-only endpoint has no write rows. |
|
|
146
|
+
| `limit` / `offset` | page the ranked results; omit `limit` initially so the default eight-result page stays small |
|
|
147
|
+
| `includeSchemas` | `"compact"` for the rendered routing view, `"json"` for the exact schema, `"typescript"` for a function signature ([below](#typescript-signatures)) |
|
|
148
|
+
| `fullDescriptions` | unabridged tool purposes, at the obvious cost |
|
|
140
149
|
|
|
141
150
|
Neither `connector` nor `safety` grants authority or changes invocation
|
|
142
151
|
admission; they select what discovery shows and nothing else.
|
|
@@ -185,8 +194,7 @@ discovery made the same bet).
|
|
|
185
194
|
```
|
|
186
195
|
|
|
187
196
|
It is something to read, not something that runs: programs stay JavaScript,
|
|
188
|
-
and `execute_code` accepts no erasable TypeScript
|
|
189
|
-
([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
|
|
190
198
|
schema, else an `S9` observation that opens with the
|
|
191
199
|
`/* observed, not declared */` marker and keeps the `outputSchemaSource`
|
|
192
200
|
field, else `unknown` — runtime evidence never reads as a contract, even when
|
|
@@ -273,7 +281,7 @@ is its slug; other IDs use `connector-` followed by a stable SHA-256 prefix.
|
|
|
273
281
|
The suffix makes each
|
|
274
282
|
document a valid Agent Skills file; the roots `skill://connecta/usage` and
|
|
275
283
|
`skill://connecta/connectors/<connector-id>` also resolve. Provider guides are
|
|
276
|
-
built from
|
|
284
|
+
built from maintained provider guides with the existing
|
|
277
285
|
connection context and deployment instructions. Local manifests contain a
|
|
278
286
|
SHA-256 digest and UTF-8 byte size of the complete document. `usage` and
|
|
279
287
|
`investigate` remain compatibility names; `connector:<id>` remains a
|
|
@@ -381,7 +389,7 @@ caught catalog-load errors, unknown-tool failures, and recovery messages that
|
|
|
381
389
|
list visible connectors or local guides. Returns with no downstream calls still
|
|
382
390
|
require matching identity, origin and endpoint, current auth, and pool membership. A page must
|
|
383
391
|
match those bindings and pass current auth, connector/tool grants, pool membership,
|
|
384
|
-
and
|
|
392
|
+
and read-only checks. Old entries lacking bindings fail closed. A random UUID is a
|
|
385
393
|
handle, never an access grant.
|
|
386
394
|
|
|
387
395
|
New entries store UTF-8 bytes in a base64 envelope split across storage keys,
|
|
@@ -512,13 +520,10 @@ format: "text", text }`. The page size is clamped to the original call's inline
|
|
|
512
520
|
cap and a 32 KiB program bridge ceiling, with UTF-8 alignment and forward progress. Reassemble inside the sandbox;
|
|
513
521
|
returning pages unchanged can hit the program result cap. The admitted subject
|
|
514
522
|
and principal, endpoint/pool, request origin, connector, and tool bindings must
|
|
515
|
-
match. The host rechecks current access and
|
|
516
|
-
read-only endpoint cannot read a write stash.
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
usable bounded preview. It says paging is unavailable and the write already
|
|
520
|
-
ran; it carries no result handle or recovery action and stores no unreachable
|
|
521
|
-
stash. Write paging remains available on trusted endpoints.
|
|
523
|
+
match. The host rechecks current access and whether the endpoint is read-only
|
|
524
|
+
before returning each page; a read-only endpoint cannot read a write stash.
|
|
525
|
+
Caller arguments select no partition. A read-only endpoint never runs a write,
|
|
526
|
+
so every write result it could page came from a writable endpoint.
|
|
522
527
|
|
|
523
528
|
A refused stash write cannot undo a downstream success. Direct calls and program returns produce
|
|
524
529
|
a paging-unavailable notice, without a handle or recovery action. A write's
|
|
@@ -592,8 +597,8 @@ same when no visible connector ID or title names that service. This service-name
|
|
|
592
597
|
vocabulary is query interpretation, not an inventory of configured providers.
|
|
593
598
|
For other service names, use the explicit `connector` scope. An unavailable
|
|
594
599
|
catalog is a catalog failure, never an absence. Absence records and catalog
|
|
595
|
-
errors use only the endpoint
|
|
596
|
-
|
|
600
|
+
errors use only the endpoint's tools; a connector the endpoint does not serve
|
|
601
|
+
is indistinguishable from an unconfigured one.
|
|
597
602
|
|
|
598
603
|
If no tool covers every search term, wider any-term fallback remains available
|
|
599
604
|
for ordinary action/object searches and the page carries `matchMode: "partial"`.
|
|
@@ -820,10 +825,11 @@ attempted tool name; an unknown tool scopes the same query to the connector that
|
|
|
820
825
|
answered. The suggested route follows the route the caller took:
|
|
821
826
|
`tool: "search_tools"` for a top-level call, `function: "connecta.search"` with
|
|
822
827
|
the same arguments when the miss happened inside `execute_code`, which has no
|
|
823
|
-
way to call a tool. `call_tool` reaching an unannotated,
|
|
824
|
-
destructive tool returns `
|
|
825
|
-
|
|
826
|
-
|
|
828
|
+
way to call a tool. On a writable endpoint, `call_tool` reaching an unannotated,
|
|
829
|
+
write-capable, or destructive tool returns `destructive_tool_requires_approval`
|
|
830
|
+
with `nextAction` for `call_destructive_tool` and the canonical address. On a
|
|
831
|
+
read-only endpoint every write path returns `read_only_endpoint` with no
|
|
832
|
+
`nextAction`. Nothing is executed by these records.
|
|
827
833
|
|
|
828
834
|
`connecta.describe` keeps its failures inline instead, so one miss cannot
|
|
829
835
|
discard the other schemas; each failed entry carries a human `error`, typed
|
|
@@ -926,18 +932,22 @@ list connectors from another pool or identity's grants.
|
|
|
926
932
|
A write that times out after dispatch returns `write_outcome_unknown` with
|
|
927
933
|
`retryable: false` and an agent-only `uncertainCall: { address, args?, argsOmitted?, argsRedacted?, recovery? }`.
|
|
928
934
|
No write is automatically replayed. `recovery` carries facts the connector
|
|
929
|
-
recorded before dispatch
|
|
930
|
-
|
|
931
|
-
|
|
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
|
|
932
942
|
(Stripe may prune v1 keys after 24 hours). After that, look the object up before
|
|
933
943
|
retrying. When a connector recorded such facts, any other dispatched write whose
|
|
934
944
|
outcome is unknown (a lost response body, a 5xx) also carries `uncertainCall`
|
|
935
|
-
with them under its own code, and
|
|
945
|
+
with them under its own code, and program write accounting keeps it. `args` may be partial reconciliation context
|
|
936
946
|
with `argsRedacted: true`. A withheld echo or arguments over the 512-byte budget
|
|
937
947
|
carry `argsOmitted: true`; sensitive or unresolved schemas also carry
|
|
938
948
|
`argsRedacted: true`. When `args` is absent or redacted, use the original
|
|
939
|
-
arguments if reconciliation requires another call. A timeout before dispatch remains `timeout`.
|
|
940
|
-
|
|
949
|
+
arguments if reconciliation requires another call. A timeout before dispatch remains `timeout`.
|
|
950
|
+
Program write accounting keeps this detail even if the guest catches the
|
|
941
951
|
failure or returns early. Multiple uncertain writes use `uncertainCalls`,
|
|
942
952
|
bounded to ten calls with `uncertainCallsTruncated` when more exist.
|
|
943
953
|
|
|
@@ -947,7 +957,9 @@ SDK timeout classes, and runtime network codes. Untyped prose is non-retryable:
|
|
|
947
957
|
name, or URL never changes the verdict. JSON-RPC `ProtocolError.data` is dropped
|
|
948
958
|
at the downstream boundary, even when the agent may see the error's message.
|
|
949
959
|
|
|
950
|
-
##
|
|
960
|
+
## Contributor reference
|
|
961
|
+
|
|
962
|
+
### Source and tests
|
|
951
963
|
|
|
952
964
|
Handlers and schemas live in [meta-tools.ts](https://github.com/zackbart/connecta/blob/main/src/meta-tools.ts).
|
|
953
965
|
[Catalog service](https://github.com/zackbart/connecta/blob/main/src/catalog-service.ts)
|