@zackbart/connecta 0.28.1 → 0.30.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 +855 -5
- package/README.md +125 -116
- package/bin/connecta.mjs +121 -139
- package/bin/meta-tool-names.d.mts +2 -0
- package/bin/meta-tool-names.mjs +9 -0
- package/bin/version.mjs +3 -0
- package/dist/access-tokens.js +53 -63
- package/dist/activity-request.js +8 -0
- package/dist/activity.d.ts +76 -42
- package/dist/activity.js +110 -42
- package/dist/argument-redaction.js +230 -0
- package/dist/auth/clerk-sdk/client.d.ts +65 -0
- package/dist/auth/clerk-sdk/client.js +5 -0
- package/dist/auth/clerk-sdk/generated.js +1845 -0
- package/dist/auth/clerk-transport.js +19 -0
- package/dist/auth/clerk.d.ts +17 -7
- package/dist/auth/clerk.js +189 -107
- package/dist/auth/cloudflare-access.js +25 -26
- package/dist/auth/downstream-client-metadata.d.ts +29 -0
- package/dist/auth/downstream-client-metadata.js +133 -0
- package/dist/auth/downstream-oauth.js +1584 -1580
- package/dist/auth/downstream-revocation.js +106 -0
- package/dist/auth/oauth-token-response.js +231 -0
- package/dist/auth/oauth-v2-migration.js +116 -0
- package/dist/auth/static-oauth.js +93 -71
- package/dist/auth-elicitation.js +288 -0
- package/dist/authorization-handoff.js +111 -0
- package/dist/branding.d.ts +8 -16
- package/dist/branding.js +26 -59
- package/dist/byte-read-response.js +39 -0
- package/dist/call-admission.js +12 -16
- package/dist/catalog-cache.js +739 -0
- package/dist/catalog-drift.d.ts +50 -15
- package/dist/catalog-drift.js +365 -128
- package/dist/catalog-fingerprint.js +2 -4
- package/dist/catalog-freshness.js +13 -0
- package/dist/catalog-limits.js +2 -2
- package/dist/catalog-service.js +409 -225
- package/dist/catalog.js +43 -84
- package/dist/concurrency.js +3 -4
- package/dist/config-defaults.d.ts +39 -0
- package/dist/config-defaults.js +46 -0
- package/dist/config-schema.d.ts +181 -0
- package/dist/config-schema.js +435 -0
- package/dist/config-value-sources.js +102 -0
- package/dist/config.d.ts +633 -0
- package/dist/config.js +508 -0
- package/dist/connector-access.d.ts +1 -0
- package/dist/connector-access.js +13 -15
- package/dist/connector-caller.d.ts +8 -0
- package/dist/connector-caller.js +15 -6
- package/dist/connector-scope.js +1 -1
- package/dist/connectors/api-connector.d.ts +59 -7
- package/dist/connectors/api-connector.js +106 -19
- package/dist/connectors/api.js +4 -1
- package/dist/connectors/guarded-fetch.d.ts +144 -0
- package/dist/connectors/guarded-fetch.js +87 -38
- package/dist/connectors/negotiation-cache.js +46 -0
- package/dist/connectors/option-shapes.js +27 -0
- package/dist/connectors/remote-mcp.d.ts +30 -4
- package/dist/connectors/remote-mcp.js +1774 -320
- package/dist/connectors/resource-uri.js +335 -0
- package/dist/credential-contract.d.ts +10 -0
- package/dist/credential-rules.js +1 -3
- package/dist/credential-url.js +108 -0
- package/dist/credentials.d.ts +6 -1
- package/dist/credentials.js +27 -18
- package/dist/d1.d.ts +130 -0
- package/dist/d1.js +290 -0
- package/dist/describe-config.d.ts +165 -0
- package/dist/describe-config.js +315 -0
- package/dist/described.js +106 -0
- package/dist/downstream-input-context.js +128 -0
- package/dist/downstream-input.js +325 -0
- package/dist/errors.d.ts +132 -31
- package/dist/errors.js +175 -87
- package/dist/execute.js +798 -318
- package/dist/executor-admission.d.ts +1 -0
- package/dist/executor-admission.js +11 -15
- package/dist/executor-contract.d.ts +20 -0
- package/dist/executor-contract.js +48 -0
- package/dist/executor-result.js +30 -13
- package/dist/executors/quickjs-child.js +15 -9
- package/dist/executors/quickjs-protocol.js +5 -6
- package/dist/executors/quickjs-runtime.js +152 -59
- package/dist/executors/quickjs.js +49 -39
- package/dist/favicon.js +1 -2
- package/dist/fix-prompt.js +1 -3
- package/dist/guest-runtime.js +238 -0
- package/dist/guest-types.d.ts +218 -0
- package/dist/guest-types.js +1 -0
- package/dist/html-security.js +24 -0
- package/dist/identity.js +1 -3
- package/dist/inbound-credential.js +52 -0
- package/dist/index.d.ts +24 -256
- package/dist/index.js +65 -478
- package/dist/invocation-auth.js +69 -0
- package/dist/invocation.js +262 -79
- package/dist/json-schema.d.ts +1 -1
- package/dist/mcp-client-context.js +35 -0
- package/dist/mcp-result.js +11 -7
- package/dist/meta-output.js +61 -0
- package/dist/meta-tool-names.d.ts +2 -0
- package/dist/meta-tool-names.js +3 -0
- package/dist/meta-tools.js +419 -272
- package/dist/module-contracts.d.ts +8 -23
- package/dist/node.d.ts +0 -2
- package/dist/node.js +2 -2
- package/dist/oauth-callback-outcome.js +1 -3
- package/dist/oauth-handoff.js +194 -0
- package/dist/oauth-sealing.js +20 -0
- package/dist/operator-record.d.ts +137 -0
- package/dist/operator-record.js +420 -0
- package/dist/operator-ui/assets.js +31 -0
- package/dist/operator-ui/contract.d.ts +72 -0
- package/dist/operator-ui/contract.js +1 -0
- package/dist/operator-ui/fix-prompts.d.ts +18 -0
- package/dist/operator-ui/generated.js +5 -4
- package/dist/operator-ui/model.d.ts +12 -87
- package/dist/operator-ui/model.js +2 -9
- package/dist/operator-ui/setup-commands.js +1 -3
- package/dist/operator-ui/view.d.ts +323 -0
- package/dist/operator-ui/view.js +62 -189
- package/dist/page-styles.js +2 -3
- package/dist/program-result.js +5 -0
- package/dist/program-source.js +14 -2
- package/dist/{exempt-writes.js → program-writes.js} +60 -19
- package/dist/provider.d.ts +142 -0
- package/dist/provider.js +187 -0
- package/dist/providers/_shared/google/result-size.js +57 -0
- package/dist/providers/_shared/google/service-account.d.ts +58 -0
- package/dist/providers/_shared/google/service-account.js +500 -0
- package/dist/providers/_shared/google/workspace.d.ts +276 -0
- package/dist/providers/_shared/google/workspace.js +518 -0
- package/dist/providers/_shared/request-token.js +83 -0
- package/dist/providers/{basecamp.d.ts → basecamp/index.d.ts} +6 -28
- package/dist/providers/basecamp/index.js +997 -0
- package/dist/providers/basecamp/skill.generated.js +9 -0
- package/dist/providers/{breeze.d.ts → breeze/index.d.ts} +2 -2
- package/dist/providers/{breeze.js → breeze/index.js} +184 -140
- package/dist/providers/breeze/skill.generated.js +9 -0
- package/dist/providers/{ccb.d.ts → ccb/index.d.ts} +2 -2
- package/dist/providers/{ccb.js → ccb/index.js} +271 -116
- package/dist/providers/ccb/skill.generated.js +9 -0
- package/dist/providers/{cloudflare.d.ts → cloudflare/index.d.ts} +8 -7
- package/dist/providers/{cloudflare.js → cloudflare/index.js} +171 -738
- package/dist/providers/cloudflare/skill.generated.js +10 -0
- package/dist/providers/docs/index.d.ts +54 -0
- package/dist/providers/docs/index.js +1237 -0
- package/dist/providers/docs/skill.generated.js +9 -0
- package/dist/providers/drive/index.d.ts +53 -0
- package/dist/providers/drive/index.js +1523 -0
- package/dist/providers/drive/skill.generated.js +9 -0
- package/dist/providers/forms/index.d.ts +54 -0
- package/dist/providers/forms/index.js +1217 -0
- package/dist/providers/forms/skill.generated.js +11 -0
- package/dist/providers/github/auth.d.ts +32 -0
- package/dist/providers/github/auth.js +361 -0
- package/dist/providers/github/hosted.js +218 -0
- package/dist/providers/github/index.d.ts +13 -0
- package/dist/providers/github/index.js +140 -0
- package/dist/providers/github/key.js +100 -0
- package/dist/providers/github/rest.js +321 -0
- package/dist/providers/github/scope.d.ts +29 -0
- package/dist/providers/github/scope.js +124 -0
- package/dist/providers/github/skill.generated.js +8 -0
- package/dist/providers/gmail/index.d.ts +51 -0
- package/dist/providers/gmail/index.js +1436 -0
- package/dist/providers/gmail/skill.generated.js +9 -0
- package/dist/providers/infisical/index.d.ts +7 -0
- package/dist/providers/infisical/index.js +713 -0
- package/dist/providers/infisical/skill.generated.js +8 -0
- package/dist/providers/{linear.d.ts → linear/index.d.ts} +11 -14
- package/dist/providers/linear/index.js +352 -0
- package/dist/providers/linear/skill.generated.js +8 -0
- package/dist/providers/{mixpanel.d.ts → mixpanel/index.d.ts} +5 -10
- package/dist/providers/mixpanel/index.js +416 -0
- package/dist/providers/mixpanel/skill.generated.js +9 -0
- package/dist/providers/{notion.d.ts → notion/index.d.ts} +8 -8
- package/dist/providers/{notion.js → notion/index.js} +226 -239
- package/dist/providers/notion/skill.generated.js +10 -0
- package/dist/providers/{overflow.d.ts → overflow/index.d.ts} +2 -2
- package/dist/providers/{overflow.js → overflow/index.js} +74 -111
- package/dist/providers/overflow/skill.generated.js +8 -0
- package/dist/providers/{planning-center.d.ts → planning-center/index.d.ts} +2 -2
- package/dist/providers/{planning-center.js → planning-center/index.js} +264 -104
- package/dist/providers/planning-center/skill.generated.js +10 -0
- package/dist/providers/{revenuecat.d.ts → revenuecat/index.d.ts} +5 -10
- package/dist/providers/revenuecat/index.js +557 -0
- package/dist/providers/revenuecat/skill.generated.js +11 -0
- package/dist/providers/sheets/index.d.ts +54 -0
- package/dist/providers/sheets/index.js +1237 -0
- package/dist/providers/sheets/skill.generated.js +10 -0
- package/dist/providers/slides/index.d.ts +53 -0
- package/dist/providers/slides/index.js +2645 -0
- package/dist/providers/slides/skill.generated.js +9 -0
- package/dist/providers/{stripe.d.ts → stripe/index.d.ts} +5 -12
- package/dist/providers/stripe/index.js +266 -0
- package/dist/providers/stripe/skill.generated.js +11 -0
- package/dist/providers/{tithely.d.ts → tithely/index.d.ts} +2 -2
- package/dist/providers/{tithely.js → tithely/index.js} +60 -91
- package/dist/providers/tithely/skill.generated.js +8 -0
- package/dist/providers/{vercel.d.ts → vercel/index.d.ts} +8 -8
- package/dist/providers/vercel/index.js +1038 -0
- package/dist/providers/vercel/mcp-ownership.js +212 -0
- package/dist/providers/vercel/skill.generated.js +11 -0
- package/dist/registry.d.ts +110 -171
- package/dist/registry.js +588 -927
- package/dist/request-state.js +21 -0
- package/dist/resource-read.js +103 -0
- package/dist/result-shapes.js +17 -49
- package/dist/retired-toolkits.js +1 -1
- package/dist/routes/access-tokens.js +3 -6
- package/dist/routes/activity-context.js +21 -0
- package/dist/routes/activity-disclosure.js +40 -0
- package/dist/routes/activity.js +59 -21
- package/dist/routes/actor-labels.js +3 -50
- package/dist/routes/connect.js +221 -0
- package/dist/routes/credentials.js +15 -27
- package/dist/routes/mcp.js +365 -130
- package/dist/routes/oauth-client-metadata.js +15 -0
- package/dist/routes/oauth-management.js +45 -107
- package/dist/routes/oauth.js +110 -57
- package/dist/routes/operator.js +3 -3
- package/dist/routes/shared.d.ts +25 -64
- package/dist/routes/shared.js +160 -80
- package/dist/routes/skills.js +30 -0
- package/dist/routes/ui-config.js +225 -0
- package/dist/routes/ui-data.js +40 -35
- package/dist/routes/ui.js +66 -56
- package/dist/runtime/admission.js +4 -2
- package/dist/runtime/call-admission.js +3 -1
- package/dist/runtime/connector-scope.js +1 -4
- package/dist/runtime/run.js +10 -39
- package/dist/runtime/services.js +12 -117
- package/dist/runtime/shared-read.js +1 -3
- package/dist/runtime/storage.js +8 -1
- package/dist/sent-secrets.d.ts +93 -0
- package/dist/sent-secrets.js +1013 -0
- package/dist/server.js +28 -71
- package/dist/skills.js +416 -174
- package/dist/sqlite.d.ts +48 -0
- package/dist/sqlite.js +181 -0
- package/dist/storage/keys.js +443 -0
- package/dist/storage/memory.js +16 -4
- package/dist/storage/sql.d.ts +66 -0
- package/dist/storage/sql.js +543 -0
- package/dist/timeout.js +4 -2
- package/dist/tool-name.js +17 -0
- package/dist/tool-safety.d.ts +9 -35
- package/dist/tool-safety.js +20 -40
- package/dist/types.d.ts +336 -56
- package/dist/types.js +0 -1
- package/dist/ui.d.ts +7 -19
- package/dist/ui.js +76 -90
- package/dist/url-safety.js +3 -6
- package/dist/usage-guide.js +146 -0
- package/dist/validate.d.ts +7 -0
- package/dist/validate.js +309 -47
- package/dist/version.d.ts +1 -7
- package/dist/version.js +3 -7
- package/dist/worker.d.ts +11 -0
- package/dist/worker.js +435 -0
- package/documentation/README.md +63 -0
- package/documentation/architecture.md +696 -231
- package/documentation/auth.md +1069 -546
- package/documentation/code-mode.md +662 -356
- package/documentation/deploying.md +146 -0
- package/documentation/integrating.md +159 -0
- package/documentation/meta-tools.md +570 -216
- package/documentation/operating.md +135 -0
- package/documentation/operator-tests.md +97 -0
- package/documentation/operator-ui.md +132 -0
- package/documentation/provider-migration-0.29.md +65 -0
- package/examples/worker/AGENTS.md +34 -12
- package/examples/worker/README.md +293 -255
- package/examples/worker/kv-to-d1.wrangler.jsonc +26 -0
- package/examples/worker/scripts/copy-kv-to-d1.mjs +162 -0
- package/examples/worker/src/connecta.config.ts +151 -0
- package/examples/worker/src/index.ts +14 -197
- package/examples/worker/wrangler.jsonc +15 -35
- package/package.json +126 -54
- package/templates/node/.dockerignore +1 -2
- package/templates/node/.env.example +20 -21
- package/templates/node/AGENTS.md +21 -17
- package/templates/node/Dockerfile +3 -5
- package/templates/node/README.md +140 -58
- package/templates/node/docker-compose.yml +11 -12
- package/templates/node/package.json +4 -2
- package/templates/node/src/connecta.config.ts +119 -0
- package/templates/node/src/index.ts +9 -154
- package/templates/node/src/provision-token.ts +17 -0
- package/AGENTS.md +0 -170
- package/dist/artifacts/connector.d.ts +0 -58
- package/dist/artifacts/connector.js +0 -730
- package/dist/artifacts/document.js +0 -86
- package/dist/artifacts/guide.js +0 -140
- package/dist/artifacts/html-scan.js +0 -329
- package/dist/artifacts/json.js +0 -78
- package/dist/artifacts/kv-store.d.ts +0 -20
- package/dist/artifacts/kv-store.js +0 -140
- package/dist/artifacts/markdown.js +0 -478
- package/dist/artifacts/module.d.ts +0 -37
- package/dist/artifacts/module.js +0 -66
- package/dist/artifacts/operations.d.ts +0 -197
- package/dist/artifacts/operations.js +0 -1002
- package/dist/artifacts/refresh.d.ts +0 -55
- package/dist/artifacts/refresh.js +0 -236
- package/dist/artifacts/routes.js +0 -206
- package/dist/artifacts/types.d.ts +0 -214
- package/dist/artifacts/types.js +0 -22
- package/dist/artifacts/validate.d.ts +0 -62
- package/dist/artifacts/validate.js +0 -651
- package/dist/artifacts.d.ts +0 -6
- package/dist/artifacts.js +0 -9
- package/dist/auth/bearer.d.ts +0 -11
- package/dist/auth/bearer.js +0 -50
- package/dist/providers/basecamp.js +0 -445
- package/dist/providers/linear.js +0 -217
- package/dist/providers/mixpanel.js +0 -247
- package/dist/providers/revenuecat.js +0 -317
- package/dist/providers/stripe.js +0 -253
- package/dist/providers/vercel.js +0 -1253
- package/dist/storage/file.d.ts +0 -15
- package/dist/storage/file.js +0 -455
- package/ethos.md +0 -93
- package/examples/worker/src/cloudflare-kv.ts +0 -43
- package/examples/worker/src/d1-activity-row.ts +0 -155
- package/examples/worker/src/d1-activity.ts +0 -147
- package/examples/worker/src/d1-storage.ts +0 -138
- package/examples/worker/src/r2-artifact-blobs.ts +0 -29
- package/templates/node/src/file-activity.ts +0 -182
|
@@ -1,44 +1,62 @@
|
|
|
1
1
|
# Meta-tools
|
|
2
2
|
|
|
3
3
|
Connecta keeps one small tool surface in model context and resolves downstream
|
|
4
|
-
tools behind it. `search_tools` finds addresses, the call tools enforce
|
|
5
|
-
|
|
4
|
+
tools behind it. `search_tools` finds addresses, the call tools enforce the
|
|
5
|
+
stored classification, `execute_code` runs programs under pool trust, 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
|
|
9
9
|
those tools imply belongs to [code mode](./code-mode.md); inbound identity and
|
|
10
10
|
credential administration belong to [auth](./auth.md).
|
|
11
11
|
|
|
12
|
-
##
|
|
12
|
+
## Task routes
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
Start with [Operating an endpoint](./operating.md) for a workflow, or
|
|
15
|
+
[the agent index](./README.md) for setup and repository tasks. This reference
|
|
16
|
+
owns the top-level MCP contract; it does not require reading the core internals.
|
|
17
|
+
|
|
18
|
+
| Task | Sections |
|
|
19
|
+
| -------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
20
|
+
| Choose a tool or construct its arguments | [Six-tool table](#the-six-tools), [call routing](#routing-between-the-call-surfaces), [downstream input](#downstream-input-on-direct-calls) |
|
|
21
|
+
| Find an operation and its schema | [Discovery context](#discovery-context), [TypeScript signatures](#typescript-signatures), [lexical discovery](#lexical-discovery) |
|
|
22
|
+
| Load provider instructions or native skills | [Connector guides](#connector-guides-and-skills), [native extension](#native-skills-extension) |
|
|
23
|
+
| Interpret a direct response or page a large result | [Representation](#result-representation), [truncation](#truncated-direct-call-results), [paging](#paging-with-connectaresult) |
|
|
24
|
+
| Recover a refused or invalid call | [Authorization](#authorization-recovery), [routing](#routing-recovery), [arguments](#argument-recovery), [echo budgets](#echo-budgets) |
|
|
25
|
+
| Change the contract | [Source and tests](#source-and-tests), [guest API](./code-mode.md#verification) |
|
|
26
|
+
|
|
27
|
+
## The six tools
|
|
28
|
+
|
|
29
|
+
Every deployment requires an executor, so `tools/list` is exactly six. No
|
|
30
|
+
configuration adds a seventh or removes one, so a client's cached tool list
|
|
16
31
|
never depends on the storage behind the deployment. There was an eighth,
|
|
17
32
|
`resume_execution`, while programs paused at writes; it left with pausing
|
|
18
33
|
([#672](https://github.com/zackbart/connecta/issues/672)). `execute_code`
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
|
29
|
-
|
|
|
30
|
-
| `
|
|
31
|
-
| `
|
|
32
|
-
| `
|
|
34
|
+
is annotated `readOnlyHint: true, destructiveHint: false` on a `read-only`
|
|
35
|
+
endpoint, and `readOnlyHint: false, destructiveHint: true` on a `trusted`
|
|
36
|
+
endpoint. Approval belongs to the host. Pool trust never changes connector
|
|
37
|
+
visibility or tool grants. The four tools with structured-only success results
|
|
38
|
+
advertise `outputSchema`. The two direct-call tools omit it because their default
|
|
39
|
+
mode returns native `content`. Default-mode successes declare
|
|
40
|
+
`_meta["dev.connecta/format"]: "json" | "text"`; value mode places the value in
|
|
41
|
+
`data` and declares `format` in its complete result envelope.
|
|
42
|
+
|
|
43
|
+
| Tool | Arguments | Returns |
|
|
44
|
+
| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
|
|
45
|
+
| `execute_code` | `code`, `diagnostics?` | `{ result?, error?, hostCalls }`, plus diagnostics when asked |
|
|
46
|
+
| `search_tools` | `query?`, `connector?`, `safety?`, `limit?`, `offset?`, `fullDescriptions?`, `includeSchemas?: "compact" \| "json" \| "typescript"` | `{ catalogErrors, tools, total, offset, limit, hasMore }`, plus `queryAnalysis` on a partial or failed search |
|
|
47
|
+
| `call_tool` | `address`, `args?`, `resultMode?: "mcp" \| "value"`, `timeoutMs?`, `diagnostics?` | the downstream result, bounded as [result representation](#result-representation) describes |
|
|
48
|
+
| `call_destructive_tool` | the same, plus `reason?` | the same |
|
|
49
|
+
| `authorize_connector` | `connector`, `force?` | the class-specific handoff in [authorization recovery](#authorization-recovery) |
|
|
50
|
+
| `skills` | `name?` | the listing when `name` is absent, that skill's markdown when it is present |
|
|
33
51
|
|
|
34
52
|
`limit` defaults to 8 and is capped at 100, as is one `connecta.describe` batch.
|
|
35
|
-
`
|
|
53
|
+
`connecta.result`'s `offset` is a whole number of bytes ≥ 0 defaulting to 0 and
|
|
36
54
|
`maxBytes` a whole number ≥ 1 that defaults to, and is clamped to, the inline
|
|
37
55
|
cap of the call that stashed the result — 24,000 bytes unless
|
|
38
56
|
`calls.maxResultBytes` or a per-connector override says otherwise
|
|
39
57
|
([why 24,000](#truncated-direct-call-results)). A value outside those domains is
|
|
40
58
|
an input error; a valid `maxBytes` above the cap is an upper bound, not an
|
|
41
|
-
error ([why](#paging-with-
|
|
59
|
+
error ([why](#paging-with-connectaresult)). `reason` is at most 500 characters of context for the host's human
|
|
42
60
|
approval view; Connecta neither treats it as authority nor sends it downstream,
|
|
43
61
|
and an empty or whitespace-only one reads as no reason rather than as grounds to
|
|
44
62
|
refuse a consequential call.
|
|
@@ -50,14 +68,11 @@ aggregates for a caller measuring a workflow: a `diagnostics` block from
|
|
|
50
68
|
and the measurements never contain program source, arguments, values, addresses,
|
|
51
69
|
credentials, logs, or raw error text.
|
|
52
70
|
|
|
53
|
-
Connecta's
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
its own policy. `call_destructive_tool` is where the prompt belongs: its
|
|
59
|
-
arguments are the exact write, so the human approves what will be sent rather
|
|
60
|
-
than a program that might send anything. Its `reason` is dropped before
|
|
71
|
+
Connecta's discovery tools carry read-only hints. `authorize_connector`
|
|
72
|
+
requests interactive authentication changes; `call_destructive_tool` sends
|
|
73
|
+
writes and is annotated destructive. `execute_code` reports the selected pool's
|
|
74
|
+
trust in its description and annotations. Its host may approve the whole
|
|
75
|
+
program on a trusted endpoint. `call_destructive_tool.reason` is dropped before
|
|
61
76
|
anything runs.
|
|
62
77
|
|
|
63
78
|
## Routing between the call surfaces
|
|
@@ -74,36 +89,25 @@ a small sample for inspection before continuing in another call, which avoids
|
|
|
74
89
|
repeated guesses at text formats and collection roots without restoring a
|
|
75
90
|
mandatory discovery-only round trip. A one-time write can return the only copy
|
|
76
91
|
of its result. Inspect and reduce the full value before a program returns, or
|
|
77
|
-
|
|
78
|
-
the write runs once.
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
trip and a replay
|
|
93
|
-
([#672](https://github.com/zackbart/connecta/issues/672)). Top-level discovery
|
|
94
|
-
stays for catalog inspection and for finding the address of a write, and the
|
|
95
|
-
MCP instructions say so.
|
|
96
|
-
|
|
97
|
-
The three discovery routes use deliberately different envelopes. These are their
|
|
98
|
-
smallest successful one-tool shapes:
|
|
92
|
+
page the completed direct-call result or oversized program return with
|
|
93
|
+
`connecta.result` after the write runs once. Sampling or slicing a write's output
|
|
94
|
+
inside the program can still discard the answer.
|
|
95
|
+
|
|
96
|
+
A `trusted` pool lets the same program discover and dispatch writes.
|
|
97
|
+
A `read-only` pool refuses writes before validation or dispatch with
|
|
98
|
+
`destructive_tool_requires_approval` and a `nextAction` naming
|
|
99
|
+
`call_destructive_tool` and the canonical address. Each write then uses its
|
|
100
|
+
own top-level call. Connecta never pauses, replays, or approves a program.
|
|
101
|
+
Top-level discovery remains available for catalog inspection and write routing.
|
|
102
|
+
|
|
103
|
+
Both search routes return the flat page specified under
|
|
104
|
+
[lexical discovery](#lexical-discovery), using the catalog's shared output schema.
|
|
105
|
+
Describe returns an ordered tool list without pagination. Optional row metadata
|
|
106
|
+
is omitted in this example:
|
|
99
107
|
|
|
100
108
|
```js
|
|
101
|
-
//
|
|
102
|
-
{
|
|
103
|
-
|
|
104
|
-
// Inside execute_code
|
|
105
|
-
{ tools: [{ name: "get_run", address: "ci.get_run" }], total: 1, offset: 0, limit: 8, hasMore: false } // connecta.search
|
|
106
|
-
{ tools: [{ name: "get_run", address: "ci.get_run", inputSchema: "{ runId: integer }" }] } // connecta.describe
|
|
109
|
+
// connecta.describe defaults to JSON
|
|
110
|
+
{ tools: [{ name: "get_run", address: "ci.get_run", schemaFormat: "json", inputSchema: { type: "object" } }] }
|
|
107
111
|
```
|
|
108
112
|
|
|
109
113
|
Live connector probing is not a fourth: the operator pages and `/health` own it.
|
|
@@ -119,21 +123,20 @@ account and environment hints cannot eat the inventory. It reads only the
|
|
|
119
123
|
configured registry: no catalog load, no credential probe, no capability, and no
|
|
120
124
|
replacement for canonical discovery or addressing. Program search results carry
|
|
121
125
|
the same bounded `connectorTitle` per tool, so choosing an account or
|
|
122
|
-
environment costs no provider read.
|
|
123
|
-
of live access.
|
|
126
|
+
environment costs no provider read. The inventory does not probe live access.
|
|
124
127
|
|
|
125
128
|
Read-only lookup belongs in `connecta.search` inside the program; top-level
|
|
126
129
|
`search_tools` stays for explicit catalog inspection and approval-required
|
|
127
130
|
discovery. Both take the same arguments.
|
|
128
131
|
|
|
129
|
-
| Argument
|
|
130
|
-
|
|
|
131
|
-
| `query`
|
|
132
|
-
| `connector`
|
|
133
|
-
| `safety`
|
|
134
|
-
| `limit` / `offset` | page the ranked results; omit `limit` initially so the default eight-result page stays small
|
|
135
|
-
| `includeSchemas`
|
|
136
|
-
| `fullDescriptions` | unabridged tool purposes, at the obvious cost
|
|
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 host approval policy or pool trust. |
|
|
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 |
|
|
137
140
|
|
|
138
141
|
Neither `connector` nor `safety` grants authority or changes invocation
|
|
139
142
|
admission; they select what discovery shows and nothing else.
|
|
@@ -170,7 +173,7 @@ describe, when the exact constraints matter.
|
|
|
170
173
|
### TypeScript signatures
|
|
171
174
|
|
|
172
175
|
`includeSchemas: "typescript"` replaces both schema fields with one
|
|
173
|
-
`signature`: the function `connecta.call(address, args)
|
|
176
|
+
`signature`: the downstream function whose result is `(await connecta.call(address, args)).data`, written
|
|
174
177
|
as a TypeScript type because agents write code against types more reliably
|
|
175
178
|
than against JSON Schema ([executor](https://github.com/UsefulSoftwareCo/executor)'s
|
|
176
179
|
discovery made the same bet).
|
|
@@ -182,8 +185,8 @@ discovery made the same bet).
|
|
|
182
185
|
```
|
|
183
186
|
|
|
184
187
|
It is something to read, not something that runs: programs stay JavaScript,
|
|
185
|
-
and
|
|
186
|
-
([
|
|
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
|
|
187
190
|
schema, else an `S9` observation that opens with the
|
|
188
191
|
`/* observed, not declared */` marker and keeps the `outputSchemaSource`
|
|
189
192
|
field, else `unknown` — runtime evidence never reads as a contract, even when
|
|
@@ -210,7 +213,8 @@ declared schema exactly as they do for compact.
|
|
|
210
213
|
A connector may attach a deployment-owned guide as markdown, keeping the
|
|
211
214
|
original `usageGuide: string` configuration, or as
|
|
212
215
|
`{ content, summary?, required? }` — which registers no connector and creates no
|
|
213
|
-
shared runtime template.
|
|
216
|
+
shared runtime template. The registry prepends Agent Skills frontmatter to
|
|
217
|
+
`content` and preserves the guide body, including its whitespace.
|
|
214
218
|
`summary` is normalized and refuses construction over 120 characters; absent,
|
|
215
219
|
Connecta derives the same bounded fallback the skills listing uses from the
|
|
216
220
|
guide's first meaningful body paragraph. `required: true` is reserved for
|
|
@@ -221,11 +225,11 @@ Search and describe results carry a `guide: "connector:<id>"` pointer and a
|
|
|
221
225
|
`guideSummary`. A matching tool also carries `guideRequired: true` and
|
|
222
226
|
`guideRequiredReasons` when Connecta can prove review is necessary:
|
|
223
227
|
|
|
224
|
-
| Reason
|
|
225
|
-
|
|
|
226
|
-
| `connector_required` | the explicit `required: true` above
|
|
227
|
-
| `approval_required`
|
|
228
|
-
| `schema_truncated`
|
|
228
|
+
| Reason | Raised by | Survives exact schema expansion |
|
|
229
|
+
| -------------------- | ------------------------------------ | -------------------------------------------------------- |
|
|
230
|
+
| `connector_required` | the explicit `required: true` above | yes |
|
|
231
|
+
| `approval_required` | an unannotated or write-capable tool | yes |
|
|
232
|
+
| `schema_truncated` | a requested compact shape was capped | no — the describe that returns the exact shape clears it |
|
|
229
233
|
|
|
230
234
|
Describe reports whatever reasons remain in the same two fields. The boolean is
|
|
231
235
|
an instruction, not a server-side gate: nothing refuses the call, so the agent
|
|
@@ -253,29 +257,101 @@ guides stay scoped to the deployment that listed them even when two deployments
|
|
|
253
257
|
use identical content, and a deployment with no connector guides receives none of
|
|
254
258
|
the short conditional guide pointers in its tool definitions.
|
|
255
259
|
|
|
260
|
+
### Native Skills extension
|
|
261
|
+
|
|
262
|
+
Connecta declares `resources: {}` and `io.modelcontextprotocol/skills`, then
|
|
263
|
+
serves `skills/list`, `skills/get`, `resources/list` and `resources/read` from
|
|
264
|
+
the same registry as `skills` and `connecta.skill`. These methods return
|
|
265
|
+
`resultType: "complete"`, `ttlMs: 0` and `cacheScope: "private"`. Listing pages
|
|
266
|
+
contain at most five complete skills: usage first, required connector guides
|
|
267
|
+
next, other connector guides, downstream skills, then the investigation guide.
|
|
268
|
+
Subsequent pages use `cursor`/`nextCursor`. Local lookup works without listing.
|
|
269
|
+
|
|
270
|
+
The local document URIs are `skill://connecta/usage/SKILL.md` and
|
|
271
|
+
`skill://connecta/connectors/<slug>/SKILL.md`. A valid Agent Skills connector ID
|
|
272
|
+
is its slug; other IDs use `connector-` followed by a stable SHA-256 prefix.
|
|
273
|
+
The suffix makes each
|
|
274
|
+
document a valid Agent Skills file; the roots `skill://connecta/usage` and
|
|
275
|
+
`skill://connecta/connectors/<connector-id>` also resolve. Provider guides are
|
|
276
|
+
built from the generated `src/providers/*/SKILL.md` content with the existing
|
|
277
|
+
connection context and deployment instructions. Local manifests contain a
|
|
278
|
+
SHA-256 digest and UTF-8 byte size of the complete document. `usage` and
|
|
279
|
+
`investigate` remain compatibility names; `connector:<id>` remains a
|
|
280
|
+
one-release alias for its canonical document.
|
|
281
|
+
|
|
282
|
+
Set `remoteMcp(id, { url, skills: true })` to opt into downstream skills.
|
|
283
|
+
Each downstream URI maps under `skill://downstream/<connector-id>/` with an
|
|
284
|
+
encoded origin and the original path tree, preserving relative references.
|
|
285
|
+
The originating authority is repeated as a path segment so an authority-rooted
|
|
286
|
+
skill retains its directory name. All frontmatter fields, manifests and digests
|
|
287
|
+
are preserved except for the namespace prefix on URIs. Listing never retrieves
|
|
288
|
+
file bodies. Reads accept only files advertised in a complete manifest, or the
|
|
289
|
+
main file of a dynamic skill. Non-file URI shapes, query/fragment URIs and
|
|
290
|
+
traversal segments fail closed. No URI is fetched directly over HTTP.
|
|
291
|
+
|
|
292
|
+
Local guides follow connector visibility. Downstream skills require a
|
|
293
|
+
whole-connector grant in the caller's admitted pool; a tool-only grant cannot
|
|
294
|
+
authorize arbitrary files. Each list/read uses that caller's context and
|
|
295
|
+
credential ownership. Downstream skills use uncached `skills/list` and explicit
|
|
296
|
+
`resources/read` requests on the same request-scoped connection as ordinary
|
|
297
|
+
resource reads. The SDK's auth-partitioned resource inventories remain separate
|
|
298
|
+
from skill manifests; neither skill catalogs nor file bodies enter its response
|
|
299
|
+
cache. A failed or malformed opted-in listing fails the entire skills catalog,
|
|
300
|
+
with no partial cache. Known local guides remain readable during an outage.
|
|
301
|
+
|
|
302
|
+
Downstream files are proxied byte-exact, including CRLF and binary supporting
|
|
303
|
+
files, within 512 files and 16 MiB per skill. Catalog metadata is bounded to
|
|
304
|
+
1,024 entries and 8 MiB. The existing request-scoped agent boundary redacts
|
|
305
|
+
sent credential echoes, including a credential in a binary file's wire
|
|
306
|
+
encoding. Binary echoes remain valid base64; mixed UTF-8/JSON escapes and an
|
|
307
|
+
encoding that itself echoes a credential cause the file to be withheld as an
|
|
308
|
+
encoded placeholder. Unmatched binary bytes remain exact. That is the sole
|
|
309
|
+
exception to byte-exactness: digests remain the downstream's originals, so a host's integrity check rejects altered
|
|
310
|
+
content. Refreshing a manifest cannot make credential-bearing content safe to
|
|
311
|
+
load. URI and digest fields containing a sent credential are refused rather
|
|
312
|
+
than repaired, including credentials sent by later catalog or read operations.
|
|
313
|
+
Skill content never reaches operator logs, activity or status. Upward
|
|
314
|
+
`resources/read` is skill-only; downstream general resource reads are the
|
|
315
|
+
separate Phase 3 item 7 program API.
|
|
316
|
+
|
|
317
|
+
The wire contract follows the [Skills extension](https://modelcontextprotocol.io/extensions/skills/overview)
|
|
318
|
+
and [2026-07-28 Resources](https://modelcontextprotocol.io/specification/2026-07-28/server/resources).
|
|
319
|
+
|
|
256
320
|
## Result representation
|
|
257
321
|
|
|
258
|
-
For
|
|
322
|
+
For structured envelopes, `structuredContent` is the canonical full-fidelity value and
|
|
259
323
|
`content` carries the same complete value as compact JSON for clients that only
|
|
260
324
|
consume text. Keeping both follows MCP's backwards-compatibility guidance;
|
|
261
325
|
dropping the text copy waits on host-forwarding measurements showing supported
|
|
262
|
-
clients do not need it.
|
|
263
|
-
|
|
264
|
-
|
|
326
|
+
clients do not need it. Direct-call failures set `isError: true` and carry the
|
|
327
|
+
same `{ ok: false, error, durationMs, attempts }` envelope in both forms, whether
|
|
328
|
+
`resultMode` is omitted, `"mcp"`, or `"value"`. Plain-text guidance stays
|
|
329
|
+
text-only. Successful direct calls with `resultMode` omitted or `"mcp"` return
|
|
330
|
+
their data only in `content`, with the downstream format in
|
|
331
|
+
`_meta["dev.connecta/format"]`. They omit `structuredContent`, including on
|
|
332
|
+
truncated results, so clients that prefer it cannot replace data or a preview
|
|
333
|
+
with metadata. API results keep their serialized value; downstream MCP native
|
|
334
|
+
content blocks pass through. Value-mode successes retain
|
|
335
|
+
`{ ok: true, data, format, durationMs, attempts }` in both forms, including when
|
|
336
|
+
`data` is a truncation notice. Direct-call tools advertise no `outputSchema`:
|
|
337
|
+
MCP requires a tool declaring one to supply conforming structured results, which
|
|
338
|
+
default native content does not promise.
|
|
339
|
+
When downstream MCP content has no text block and downstream `structuredContent`
|
|
340
|
+
is present, Connecta appends a
|
|
265
341
|
text block carrying its compact JSON and then applies the same content size
|
|
266
342
|
guard, which preserves structured-only results including `null`, arrays, and
|
|
267
343
|
scalars. An existing text mirror stays unchanged; Connecta adds no second copy.
|
|
268
344
|
Newly stashed JSON and downstream content envelopes use compact serialization,
|
|
269
|
-
and a lone text block stashes as its own text, so `
|
|
345
|
+
and a lone text block stashes as its own text, so `connecta.result` offsets and
|
|
270
346
|
totals describe exactly that text.
|
|
271
347
|
|
|
272
|
-
| Bound
|
|
273
|
-
|
|
|
274
|
-
| Stashed result TTL
|
|
275
|
-
| `results.maxStashBytes`
|
|
276
|
-
| `results.maxStashEntries`
|
|
277
|
-
| Top-level discovery result ceiling | 256,000 UTF-8 bytes
|
|
278
|
-
| Downstream MCP `isError` text
|
|
348
|
+
| Bound | Value |
|
|
349
|
+
| ---------------------------------- | ---------------------------------- |
|
|
350
|
+
| Stashed result TTL | 15 minutes |
|
|
351
|
+
| `results.maxStashBytes` | 8 MiB per shared storage ledger |
|
|
352
|
+
| `results.maxStashEntries` | 64 per shared storage ledger |
|
|
353
|
+
| Top-level discovery result ceiling | 256,000 UTF-8 bytes |
|
|
354
|
+
| Downstream MCP `isError` text | 512 UTF-8 bytes plus an `…` marker |
|
|
279
355
|
|
|
280
356
|
The discovery ceiling counts text, `structuredContent`, and JSON escaping
|
|
281
357
|
together, because measuring one copy would advertise half the bytes the adapter
|
|
@@ -286,28 +362,46 @@ subjects and pools; they count the stored ASCII paging envelope, base64 overhead
|
|
|
286
362
|
included, not only the result text. Capacity is reserved before each storage
|
|
287
363
|
write so concurrent requests cannot oversubscribe it, and a full stash refuses
|
|
288
364
|
new entries. A later attempt deletes expired entries before reusing their
|
|
289
|
-
capacity; a failed deletion keeps the charge. These bounds cover
|
|
290
|
-
|
|
291
|
-
|
|
365
|
+
capacity; a failed deletion keeps the charge. These bounds cover all processes and Worker isolates sharing the store.
|
|
366
|
+
Compare-and-set reserves each charge in one storage ledger before any chunk
|
|
367
|
+
is written; chunk TTLs cannot exceed the charge deadline.
|
|
292
368
|
|
|
293
369
|
Results belong to the authenticated subject whenever auth supplies a subject or
|
|
294
370
|
user id, independently of activity configuration, under the provider's namespace
|
|
295
371
|
when it has one and `connecta:auth:<provider kind>` otherwise. Keep subject ids
|
|
296
372
|
distinct within that namespace. An explicit principal is the fallback subject
|
|
297
373
|
when neither id is supplied, and open deployments and auth providers that supply
|
|
298
|
-
no identity share one partition.
|
|
374
|
+
no identity share one partition. Each new stash also binds the principal,
|
|
375
|
+
endpoint/pool, request origin, connector, tool, and classification. Program-return
|
|
376
|
+
stashes bind every contributing call, resource or skill read, and catalog lookup,
|
|
377
|
+
including dependencies inherited from pages read during the run. Downstream skill and
|
|
378
|
+
resource content requires a whole-connector grant on every page. Local guides and catalog
|
|
379
|
+
metadata require the contributing connector or tool to remain visible, including
|
|
380
|
+
caught catalog-load errors, unknown-tool failures, and recovery messages that
|
|
381
|
+
list visible connectors or local guides. Returns with no downstream calls still
|
|
382
|
+
require matching identity, origin and endpoint, current auth, and pool membership. A page must
|
|
383
|
+
match those bindings and pass current auth, connector/tool grants, pool membership,
|
|
384
|
+
and trust checks. Old entries lacking bindings fail closed. A random UUID is a
|
|
385
|
+
handle, never an access grant.
|
|
299
386
|
|
|
300
387
|
New entries store UTF-8 bytes in a base64 envelope split across storage keys,
|
|
301
388
|
48 KiB of result text per chunk — widening past roughly 1.5 MB so no result
|
|
302
|
-
occupies more than 33 keys, because every chunk is also a write. `
|
|
389
|
+
occupies more than 33 keys, because every chunk is also a write. `connecta.result`
|
|
303
390
|
reads and decodes only the chunks a page covers plus a few boundary bytes, so
|
|
304
391
|
paging a 1.2 MB result costs the same per page as paging a 300 KB one; it
|
|
305
|
-
neither encodes nor reads the whole result per page.
|
|
306
|
-
single-key
|
|
307
|
-
also pays one full encoding. Offsets and `totalBytes` always describe the
|
|
392
|
+
neither encodes nor reads the whole result per page. Entries without the required identity and invocation bindings fail closed,
|
|
393
|
+
including pre-upgrade single-key envelopes and raw-text entries. Offsets and `totalBytes` always describe the
|
|
308
394
|
original UTF-8 text, not the envelope. A supplied offset inside a character
|
|
309
395
|
moves back to its start; page ends also align to character boundaries, and a
|
|
310
396
|
page smaller than one character widens just enough to make progress.
|
|
397
|
+
Decoding preserves every payload code point, including U+FEFF at the start of
|
|
398
|
+
the result or any page, so joining pages reproduces the original UTF-8 text.
|
|
399
|
+
Oversized raw text containing unpaired UTF-16 surrogates cannot use this UTF-8
|
|
400
|
+
page/offset contract. It returns a successful truncation notice explaining that
|
|
401
|
+
the text cannot be paged and suggesting a JSON value request for recovery,
|
|
402
|
+
without a stash id, paging action, or altered preview.
|
|
403
|
+
Completed writes remain successful and must not be repeated. JSON values still
|
|
404
|
+
round-trip such strings through their escaped JSON representation.
|
|
311
405
|
|
|
312
406
|
A per-call `timeoutMs` covers catalog resolution, admission, and connector
|
|
313
407
|
execution under one deadline. The admission queue's own timeout may expire
|
|
@@ -320,10 +414,11 @@ retryable timeout while Connecta prepares its response.
|
|
|
320
414
|
A `call_tool` or `call_destructive_tool` result over its cap — the connector's
|
|
321
415
|
`maxResultBytes`, else `calls.maxResultBytes`, else 24,000 bytes — comes back
|
|
322
416
|
as one text block. Its first line is the truncation notice, one line of compact
|
|
323
|
-
JSON; everything after the first newline is the preview
|
|
417
|
+
JSON; everything after the first newline is the preview. `structuredContent`
|
|
418
|
+
is absent, so the notice cannot hide the preview in clients that prefer it:
|
|
324
419
|
|
|
325
420
|
```text
|
|
326
|
-
{"truncated":true,"resultId":"…","totalBytes":161420,"hint":"This write already ran: do not call it again to see its result. Bytes 0-24000 of 161420 follow; page the rest with
|
|
421
|
+
{"truncated":true,"resultId":"…","totalBytes":161420,"hint":"This write already ran: do not call it again to see its result. Bytes 0-24000 of 161420 follow; page the rest with connecta.result using nextAction.","nextOffset":24000,"nextAction":{"tool":"execute_code","arguments":{"code":"async () => await connecta.result(\"…\", { offset: 24000 })"}}}
|
|
327
422
|
{"ts":"2026-09-16T21:31:11.759Z","actor":"sam.ortiz@example.com",…
|
|
328
423
|
```
|
|
329
424
|
|
|
@@ -344,8 +439,8 @@ three models re-ran a billable export three times trying to read its result.
|
|
|
344
439
|
The default cap sits under both lines with room to spare. Preview plus notice
|
|
345
440
|
stays under 25,000 bytes, which is under 50,000 characters for any text, because
|
|
346
441
|
a character is at least one UTF-8 byte, and under 25,000 tokens for any text,
|
|
347
|
-
because a token covers at least one byte. A `
|
|
348
|
-
cap, and 24,000 matches the program result boundary in
|
|
442
|
+
because a token covers at least one byte. A `connecta.result` page is bounded by the same
|
|
443
|
+
inline byte cap, and 24,000 matches the program result boundary in
|
|
349
444
|
[code mode](./code-mode.md). A deployment whose
|
|
350
445
|
clients take more can raise the cap, and one whose clients take less can lower
|
|
351
446
|
it, per connector if need be; a result between 24,000 and 50,000 bytes that
|
|
@@ -354,7 +449,7 @@ the notice whatever its threshold, since the notice is the first few hundred
|
|
|
354
449
|
characters. One that rejects outright — Claude Code with
|
|
355
450
|
`MAX_MCP_OUTPUT_TOKENS` set below 12,500 — needs a cap under twice its limit.
|
|
356
451
|
|
|
357
|
-
The preview is the head of what `
|
|
452
|
+
The preview is the head of what `connecta.result` pages, cut on a character
|
|
358
453
|
boundary, so `nextAction.arguments.offset` continues exactly where it stops. A
|
|
359
454
|
lone text block — including the one synthesized from `structuredContent` — is
|
|
360
455
|
measured, stashed, previewed, and paged as its text: wrapping it in a content
|
|
@@ -373,130 +468,297 @@ The approved write happened; repeating it to look again is how one export
|
|
|
373
468
|
becomes three. For an explicitly read-only call, repeating is the better route,
|
|
374
469
|
so the hint offers it first: to find something specific, repeat the read inside
|
|
375
470
|
`execute_code` with `connecta.call` and filter or search the result there; to
|
|
376
|
-
read it in full, page with `
|
|
471
|
+
read it in full, page with `connecta.result`. Inside a program the inline cap does
|
|
377
472
|
not apply to a host call's result, only to what the program returns (`L6` in
|
|
378
473
|
[code mode](./code-mode.md) bounds a host call far higher), so the reduction
|
|
379
474
|
sees the whole result at once. When the hint named paging alone, the eval's
|
|
380
475
|
weakest model read a 185 KB CI log in 24,000-byte pages, skipped the range
|
|
381
476
|
holding the real failure, and named the flaky test near the top; before the
|
|
382
477
|
notice was visible, it had reduced the log in a program and found the failure.
|
|
383
|
-
`nextAction`
|
|
478
|
+
When paging is available, `nextAction` is the page handle for either kind of call, because paging is
|
|
384
479
|
the one next step connecta can spell out exactly, while a reduction is a
|
|
385
480
|
program the agent has to write. `resultId` stays beside the exact `nextAction`,
|
|
386
481
|
so the handle is actionable without copying an identifier out of prose.
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
482
|
+
Oversized program returns carry the same route, with a bounded preview after
|
|
483
|
+
its notice fields. They stash the compact JSON return and page from offset 0;
|
|
484
|
+
see [program returns](./code-mode.md#results-and-projection). A run that completed
|
|
485
|
+
any write gets the same no-repeat warning. Oversized discovery responses carry
|
|
486
|
+
no paging route.
|
|
487
|
+
|
|
488
|
+
### Paging with connecta.result
|
|
489
|
+
|
|
490
|
+
Paging is a guest operation, never another top-level tool. Program calls also
|
|
491
|
+
return handles for oversized values; see [program result limits](./code-mode.md#cancellation-and-limits).
|
|
492
|
+
`connecta.result(handle, { page: 0 })` accepts those handles alongside direct
|
|
493
|
+
result IDs. Numbered pages are zero-based and mutually exclusive with offset.
|
|
494
|
+
Keep maxBytes fixed while incrementing pages. A direct call's
|
|
495
|
+
notice carries a `resultId`, `nextOffset`, and an executable `execute_code`
|
|
496
|
+
recovery action. Read and reduce the result in one program:
|
|
390
497
|
|
|
391
|
-
|
|
498
|
+
```js
|
|
499
|
+
async () => {
|
|
500
|
+
let text = "", offset = 0, page;
|
|
501
|
+
do {
|
|
502
|
+
page = await connecta.result("result-id", { offset, maxBytes: 8_000 });
|
|
503
|
+
text += page.text;
|
|
504
|
+
offset = page.nextOffset;
|
|
505
|
+
} while (page.hasMore);
|
|
506
|
+
return JSON.parse(text).items.map(item => item.id);
|
|
507
|
+
}
|
|
508
|
+
```
|
|
392
509
|
|
|
393
|
-
A page is
|
|
394
|
-
|
|
510
|
+
A page is `{ resultId, offset, bytes, totalBytes, hasMore, nextOffset?,
|
|
511
|
+
format: "text", text }`. The page size is clamped to the original call's inline
|
|
512
|
+
cap and a 32 KiB program bridge ceiling, with UTF-8 alignment and forward progress. Reassemble inside the sandbox;
|
|
513
|
+
returning pages unchanged can hit the program result cap. The admitted subject
|
|
514
|
+
and principal, endpoint/pool, request origin, connector, and tool bindings must
|
|
515
|
+
match. The host rechecks current access and trust before returning each page; a
|
|
516
|
+
read-only endpoint cannot read a write stash. Caller arguments select no partition.
|
|
395
517
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
518
|
+
A write on a read-only endpoint returns an inline truncation notice and any
|
|
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.
|
|
400
522
|
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
`{ offset, nextOffset?, totalBytes, text }`, which escaped every quote and
|
|
406
|
-
newline in the page: a second layer over JSON payloads that made them hard to
|
|
407
|
-
read and swelled a 20,000-byte page of JSON lines to 25,000 characters or more.
|
|
408
|
-
|
|
409
|
-
`maxBytes` is an upper bound clamped to the inline cap of the call that stashed
|
|
410
|
-
the result — the connector's override when it had one, recorded in the stash
|
|
411
|
-
entry — and a clamped request is answered, not refused, with `bytes` saying how
|
|
412
|
-
much came back. Clients cut an oversized page exactly as they cut the original
|
|
413
|
-
result. In the eval, agents that could finally see the handle asked for pages of
|
|
414
|
-
50,000 bytes and more, and Claude Code rejected every one of those answers
|
|
415
|
-
outright, leaving an agent that had just been told not to repeat a write with
|
|
416
|
-
nothing to read. So no response to a truncated call or to a page request
|
|
417
|
-
exceeds the cap plus a header of a few hundred bytes. Value mode's unpageable
|
|
418
|
-
preview is cut short enough that its JSON escaping still fits. Entries stashed
|
|
419
|
-
before the cap was recorded page at the deployment cap.
|
|
420
|
-
|
|
421
|
-
A refused or failed stash write cannot undo a downstream success. Both call tools
|
|
422
|
-
then return the same layout with a paging-unavailable notice and no `resultId`
|
|
423
|
-
or paging action — the notice first, then the preview where one is usable, and
|
|
424
|
-
for a write the same warning not to repeat it. Activity records success, and
|
|
425
|
-
the operator logger receives a fixed warning naming the connector and tool
|
|
426
|
-
without storage error prose. For read-only work, reduce the result inside
|
|
427
|
-
`execute_code` — repeating an approved write is not a way to recover its output. Other result-processing failures use a fixed
|
|
428
|
-
`result_processing_failed` message and are never retryable.
|
|
523
|
+
A refused stash write cannot undo a downstream success. Direct calls and program returns produce
|
|
524
|
+
a paging-unavailable notice, without a handle or recovery action. A write's
|
|
525
|
+
notice still says it already ran. Activity records success; operator logs receive
|
|
526
|
+
a fixed warning without storage error prose. Never repeat a write to recover output.
|
|
429
527
|
|
|
430
528
|
## Lexical discovery
|
|
431
529
|
|
|
432
|
-
`search_tools`
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
530
|
+
`search_tools` and in-program `connecta.search` return the same flat discovery
|
|
531
|
+
page. Select tool rows from `page.tools`.
|
|
532
|
+
With the same schema format, schema-key option, and scoped registry, both paths
|
|
533
|
+
return identical data. Top-level search omits schemas unless requested; programs
|
|
534
|
+
default to JSON schemas and schema-key metadata.
|
|
535
|
+
|
|
536
|
+
```json
|
|
537
|
+
{
|
|
538
|
+
"catalogErrors": [],
|
|
539
|
+
"tools": [
|
|
540
|
+
{
|
|
541
|
+
"name": "get_issue",
|
|
542
|
+
"address": "linear.get_issue",
|
|
543
|
+
"connectorTitle": "Linear Production",
|
|
544
|
+
"classification": "read",
|
|
545
|
+
"schemaFormat": "json",
|
|
546
|
+
"inputSchema": { "type": "object", "properties": { "id": { "type": "string" } }, "required": ["id"] }
|
|
547
|
+
}
|
|
548
|
+
],
|
|
549
|
+
"total": 1,
|
|
550
|
+
"offset": 0,
|
|
551
|
+
"limit": 8,
|
|
552
|
+
"hasMore": false
|
|
553
|
+
}
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
`catalogErrors` is always present and serialized before tools. It contains
|
|
557
|
+
bounded typed failures from visible catalogs, including on an unscoped search
|
|
558
|
+
with healthy matches. Credential and permission failures appear first. OAuth
|
|
559
|
+
and operator credential failures carry the codes and `recovery`, `nextAction`,
|
|
560
|
+
and retry instructions described below. `provider_permission_denied` asks the
|
|
561
|
+
resource owner to grant access and carries no reconnect action. Discovery never
|
|
562
|
+
starts recovery. Failure messages use fixed text derived from the error code
|
|
563
|
+
and connector id, never connector-supplied error text. Other failures retain
|
|
564
|
+
`code`, `message`, `retryable`, and any
|
|
565
|
+
`retryAfterMs`. A scoped search also keeps its bounded failure subset under
|
|
566
|
+
`queryAnalysis.catalogError` for clients that already use it.
|
|
567
|
+
|
|
568
|
+
Tool rows carry the address, configured display title when present, guide and
|
|
569
|
+
guide summary when available, and stored classification. Requested schemas have
|
|
570
|
+
`schemaFormat: "json"` for JSON Schema values or `schemaFormat: "text"` for
|
|
571
|
+
compact schema strings and TypeScript signatures. Compact schemas are text;
|
|
572
|
+
`inputSchema.properties` is meaningful only in JSON mode. Pagination counts
|
|
573
|
+
tools across connectors: `nextOffset` is present only when another page remains.
|
|
574
|
+
|
|
575
|
+
Search tokenizes tool names and descriptions at punctuation and camel-case
|
|
576
|
+
boundaries. Whole-token matches and a small set of inflectional variants preserve
|
|
577
|
+
recall without admitting arbitrary mid-word substrings. Document frequency weights
|
|
578
|
+
rare domain terms above ubiquitous action terms. Exact tool names and canonical
|
|
579
|
+
addresses rank first, so `get_issue` beats `get_issue_status` even when a
|
|
580
|
+
connector is named `issue`. Exact configured connector IDs, full display titles,
|
|
581
|
+
and recognized service names rank next. Complete lexical matches then precede
|
|
582
|
+
partial matches, with score and catalog order breaking ties.
|
|
583
|
+
An exact connector ID or title query browses that connector's tools, even when
|
|
584
|
+
individual tool names or descriptions mention that identity. Connector identity
|
|
585
|
+
terms that never occur in its tools need not be repeated in every tool description.
|
|
586
|
+
|
|
587
|
+
An explicit unknown `connector` scope returns no tools and an `absence` record:
|
|
588
|
+
`{ service, message, configuredConnectors }`. The message says
|
|
589
|
+
`No connector for "X" is configured for this endpoint.` Unscoped queries naming
|
|
590
|
+
recognized services such as GitHub, Linear, Mixpanel, Supabase, or PostHog do the
|
|
591
|
+
same when no visible connector ID or title names that service. This service-name
|
|
592
|
+
vocabulary is query interpretation, not an inventory of configured providers.
|
|
593
|
+
For other service names, use the explicit `connector` scope. An unavailable
|
|
594
|
+
catalog is a catalog failure, never an absence. Absence records and catalog
|
|
595
|
+
errors use only the endpoint/pool and grant intersection; a connector hidden by
|
|
596
|
+
that intersection is indistinguishable from an unconfigured one.
|
|
597
|
+
|
|
598
|
+
If no tool covers every search term, wider any-term fallback remains available
|
|
599
|
+
for ordinary action/object searches and the page carries `matchMode: "partial"`.
|
|
600
|
+
A service absence suppresses that fallback, so `GitHub get issue` cannot return
|
|
601
|
+
Linear issues or Mixpanel/Supabase projects. Tool rows expose no scores or
|
|
602
|
+
per-result query coverage. `queryAnalysis` partitions at most eight terms of at
|
|
603
|
+
most 64 characters into `representedTerms`, `otherResultTerms`, and
|
|
604
|
+
`unmatchedTerms`, marking longer input `truncated`. Its guidance distinguishes
|
|
605
|
+
partial matches, unavailable catalogs, unknown scopes, and genuine no-match
|
|
606
|
+
results. A non-empty query with no ASCII lexical terms returns no tools with
|
|
607
|
+
bounded no-match analysis. An empty or whitespace-only query browses.
|
|
608
|
+
|
|
609
|
+
## Downstream input on direct calls
|
|
610
|
+
|
|
611
|
+
On MCP 2026-07-28, `call_tool` and `call_destructive_tool` relay a downstream
|
|
612
|
+
`input_required` through connecta's own `requestState`. This requires an
|
|
613
|
+
authenticated principal and a vault with `requestStateKey`, `seal`, and `open`.
|
|
614
|
+
The original request must be retried with identical arguments. Connecta
|
|
615
|
+
continues only the same connector and resolved address, after the normal
|
|
616
|
+
identity, pool, classification, schema, and admission checks.
|
|
617
|
+
|
|
618
|
+
The signed `createRequestStateCodec` envelope contains a version-2
|
|
619
|
+
`downstream` discriminator, connector id, and vault ciphertext. The encrypted
|
|
620
|
+
payload binds the principal, endpoint including its pool path, meta-tool,
|
|
621
|
+
submitted address and resolved target, arguments digest, round, original expiry,
|
|
622
|
+
and one-use nonce. It carries the opaque downstream state byte-exact, bounded
|
|
623
|
+
private state history from earlier rounds, and a map
|
|
624
|
+
from connecta's numbered `downstream/<connector>/<index>` keys to the original
|
|
625
|
+
downstream keys and elicitation modes. Neither the opaque state nor the original
|
|
626
|
+
keys appear in agent output. Each round consumes a TTL-bound storage CAS before
|
|
627
|
+
dispatch; tampering, expiry, changed arguments, cross-principal/pool reuse, and
|
|
628
|
+
concurrent or repeated consumption are refused.
|
|
629
|
+
|
|
630
|
+
Only well-formed form and URL elicitation declared by the client on that request
|
|
631
|
+
is forwarded. An empty `elicitation: {}` declaration means form support, as in
|
|
632
|
+
the spec. Capabilities are checked again on retry. Unknown response keys are
|
|
633
|
+
ignored; recognized bare responses are validated and renamed back before being
|
|
634
|
+
sent downstream. Accept, decline, and cancel all continue the pending downstream
|
|
635
|
+
call, so the downstream can finish or terminate it. URL acknowledgements and
|
|
636
|
+
decline/cancel carry only their action. Sampling and roots remain unsupported
|
|
637
|
+
under [#703](https://github.com/zackbart/connecta/issues/703).
|
|
638
|
+
|
|
639
|
+
URL elicitation retains the downstream-provided URL unchanged. It must be HTTPS,
|
|
640
|
+
have no URL userinfo or control/space characters, contain no credential known to
|
|
641
|
+
the sent-secret boundary, and remain byte-identical through agent redaction.
|
|
642
|
+
Connecta refuses unsafe URLs instead of rewriting them. Messages begin
|
|
643
|
+
with `Downstream <connector>:` so the host can display who supplied the prompt;
|
|
644
|
+
the host owns consent and browser navigation. Connecta never adds credentials
|
|
645
|
+
or follows the URL. Messages pass the ordinary agent-output redaction boundary.
|
|
646
|
+
A form is refused if that boundary would change its schema, including property
|
|
647
|
+
names, enum values, or annotations; the host never receives a rewritten answer
|
|
648
|
+
contract. Prompts, raw continuation results, discovery, and continuation-time
|
|
649
|
+
catalogs that echo any round's opaque state are refused before redaction, paging,
|
|
650
|
+
stashing, error shaping, schema observation, or cache publication and reuse.
|
|
651
|
+
This includes bounded percent-decoded and JSON-escaped views, encoded echoes,
|
|
652
|
+
short state, and serialized
|
|
653
|
+
numbers, booleans, and null. No prompt, state,
|
|
654
|
+
response, arguments, or raw error reaches activity, logs, or status.
|
|
655
|
+
|
|
656
|
+
Connecta's confidentiality guarantee covers its own handling and persistence of
|
|
657
|
+
`requestState`. Checks for state echoed in downstream content are defense in
|
|
658
|
+
depth; a downstream's deliberate disclosure of its own state is outside that
|
|
659
|
+
guarantee. Binary blobs are not decoded to look for echoes.
|
|
660
|
+
|
|
661
|
+
A write returning `input_required` has not completed its operation: the
|
|
662
|
+
[MRTR spec](https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/mrtr)
|
|
663
|
+
defines that result as awaiting input before completion. Sending the original
|
|
664
|
+
opaque state and input responses is a continuation, not an automatic replay.
|
|
665
|
+
The sealed arguments digest prevents using that continuation for fresh write
|
|
666
|
+
arguments. A timeout or other failure during a continuation leaves its nonce
|
|
667
|
+
spent, so it cannot authorize a second attempt. Write continuations stop at an
|
|
668
|
+
HTTP 401 or redirect before the SDK can refresh authorization or resend the call.
|
|
669
|
+
HTTP 403 scope escalation also remains disabled. Read continuations retain normal
|
|
670
|
+
OAuth refresh behavior.
|
|
671
|
+
|
|
672
|
+
Auth recovery and downstream input are distinct state variants, with only one
|
|
673
|
+
active in a round. An auth retry can reach downstream input within the same
|
|
674
|
+
three-prompt, ten-minute window. A downstream continuation that fails auth ends
|
|
675
|
+
with the ordinary failure; it does not replace its pending state with an auth
|
|
676
|
+
replay. Downstream payloads and input responses are capped at 64 KiB, with at
|
|
677
|
+
most 16 inputs and 256 characters per downstream key. The combined private
|
|
678
|
+
state history is also capped at 64 KiB. Sealed wire state is
|
|
679
|
+
capped at 128 KiB. `input_required_invalid`, `input_required_limit`,
|
|
680
|
+
`input_required_unsupported`, and `input_required_round_limit` are non-retryable
|
|
681
|
+
typed failures.
|
|
682
|
+
|
|
683
|
+
Programs and in-process meta-tools return `input_required_unsupported`, with a
|
|
684
|
+
`nextAction` naming the equivalent direct call and bounded original arguments.
|
|
685
|
+
Programs never receive downstream state or prompts, and never restart to
|
|
686
|
+
fulfill downstream input.
|
|
487
687
|
|
|
488
688
|
## Authorization recovery
|
|
489
689
|
|
|
490
|
-
|
|
690
|
+
On MCP 2026-07-28, a host declaring `elicitation.url` receives
|
|
691
|
+
`resultType: "input_required"` when an eligible call or program needs recoverable
|
|
692
|
+
connector authentication and the admitted identity may manage that connector.
|
|
693
|
+
Read-classified calls may re-run after a mid-handler auth failure only when
|
|
694
|
+
their classification came from a catalog accepted within its TTL. Stale
|
|
695
|
+
fallback catalogs cannot authorize post-entry recovery. A write may
|
|
696
|
+
elicit only when Connecta's own pre-invocation credential resolution
|
|
697
|
+
reports a missing grant, a missing credential slot, or required consent before
|
|
698
|
+
refresh. Its handler and transport have not been entered. Programs also require
|
|
699
|
+
that every entered call has a fresh read classification during this run.
|
|
700
|
+
The `connecta_auth` input request uses `elicitation/create`,
|
|
701
|
+
`mode: "url"`, fixed copy, and an identity-checked `/connect/<id>` link built
|
|
702
|
+
from configured `publicUrl`. OAuth consent stays in the browser; a credential
|
|
703
|
+
slot uses the authenticated operator UI. `authorize_connector` uses the same
|
|
704
|
+
flow for explicit connect and restart. There is no legacy shim.
|
|
705
|
+
|
|
706
|
+
The host echoes `requestState` and its bare `inputResponses.connecta_auth`
|
|
707
|
+
response on the original `tools/call`. Accept re-runs the original call; it
|
|
708
|
+
does not prove browser consent completed. Decline or cancel ends without
|
|
709
|
+
dispatch, with `auth_declined` or `auth_cancelled`. Three prompts are allowed
|
|
710
|
+
within one ten-minute retry window, then `auth_round_limit` ends the flow.
|
|
711
|
+
Each state can be consumed once; concurrent or repeated retries are refused
|
|
712
|
+
before dispatch. A Continue link from a pending restart requires that restart
|
|
713
|
+
to start successfully before the browser can consume it.
|
|
714
|
+
Host-owned invocation facts record the auth failure's origin and entry into
|
|
715
|
+
all calls, including each classification, catalog freshness and classification
|
|
716
|
+
digest. Raw fetches and custom connector transports cannot establish recovery
|
|
717
|
+
eligibility. Each accept retry rechecks all previously entered reads before
|
|
718
|
+
restarting a program or direct call. A write classification, changed digest, or
|
|
719
|
+
stale catalog returns `auth_replay_refused` and reconciliation guidance.
|
|
720
|
+
Each round also checks its own invocation facts. Normal stale-fallback calls
|
|
721
|
+
retain their existing behavior.
|
|
722
|
+
An auth failure after a write handler or transport was entered keeps its
|
|
723
|
+
ordinary error code,
|
|
724
|
+
`retryable: false`, `reconciliationRequired: true`, and manual `/connect` guidance
|
|
725
|
+
where available. The write may have partially run; reconcile its target before
|
|
726
|
+
retrying after connection. Handler-authored error fields cannot clear this guard.
|
|
727
|
+
|
|
728
|
+
State integrity, expiry, principal, endpoint, and tool failures produce the
|
|
729
|
+
SDK's JSON-RPC `-32602` with `data.reason: "invalid_request_state"` before the
|
|
730
|
+
handler runs. Changed arguments or code produce a typed `invalid_request_state`
|
|
731
|
+
tool failure before dispatch. Retry state grants no access; each request still
|
|
732
|
+
passes current identity, pool, connector visibility, and management checks.
|
|
733
|
+
Hosts without URL support keep the recovery envelope below, with a `/connect`
|
|
734
|
+
URL when this deployment can issue one. Without an interactive provider,
|
|
735
|
+
signing vault, or configured public URL, automatic elicitation is unavailable.
|
|
736
|
+
|
|
737
|
+
`downstream_oauth_required` means the connector needs an OAuth grant.
|
|
738
|
+
`auth_required` means its operator-managed credentials or configuration need
|
|
739
|
+
repair. Both carry the recovery envelope below. `provider_permission_denied`
|
|
740
|
+
means the provider refused a permission or scope; ask its resource owner or
|
|
741
|
+
administrator to grant access before retrying. It does not invite a reconnect.
|
|
742
|
+
|
|
743
|
+
A host rejected before MCP dispatch gets HTTP 401 or 403 with
|
|
744
|
+
`error.code: "host_auth_required"`, `recovery: "host_connection"`, and the auth
|
|
745
|
+
adapter's original `WWW-Authenticate` challenge. Custom streaming or non-JSON
|
|
746
|
+
responses keep their body and expose `Connecta-Error-Code` and
|
|
747
|
+
`Connecta-Recovery` headers instead. Repair the host's connecta
|
|
748
|
+
connection or endpoint grants. This cannot be fixed by `authorize_connector`.
|
|
749
|
+
|
|
750
|
+
An OAuth call failure uses this envelope:
|
|
491
751
|
|
|
492
752
|
```json
|
|
493
753
|
{
|
|
494
|
-
"code": "
|
|
754
|
+
"code": "downstream_oauth_required",
|
|
495
755
|
"message": "...",
|
|
496
756
|
"retryable": false,
|
|
497
757
|
"connector": "service",
|
|
498
758
|
"operation": "service.read",
|
|
499
759
|
"recovery": "oauth",
|
|
760
|
+
"authorizationUrl": "https://connecta.example/connect/service?h=...",
|
|
761
|
+
"instructions": "Copy authorizationUrl exactly as returned and sign in as the initiating user.",
|
|
500
762
|
"nextAction": {
|
|
501
763
|
"tool": "authorize_connector",
|
|
502
764
|
"arguments": { "connector": "service" },
|
|
@@ -506,11 +768,16 @@ Every typed `auth_required` call failure uses the same envelope:
|
|
|
506
768
|
}
|
|
507
769
|
```
|
|
508
770
|
|
|
509
|
-
`recovery` is `oauth`, `operator_config`, or `unavailable`.
|
|
510
|
-
|
|
511
|
-
|
|
771
|
+
`recovery` is `oauth`, `operator_config`, or `unavailable`. On hosts without URL
|
|
772
|
+
elicitation, auth errors carry the same handoff fields that `authorize_connector`
|
|
773
|
+
returns for the admitted user, connector, and pool. Direct calls include them in
|
|
774
|
+
`error`; program `connecta.call` failures include them in `error.data` and
|
|
775
|
+
`error.details`. Search `catalogErrors` and scoped `queryAnalysis.catalogError`,
|
|
776
|
+
and describe `errorDetails`, carry them too. When an auth error includes a
|
|
777
|
+
handoff, give it to the user or operator. The class-specific handoff is:
|
|
512
778
|
|
|
513
|
-
- `oauth`: an `authorizationUrl`
|
|
779
|
+
- `oauth`: an `authorizationUrl` to connecta's `/connect/<connector>?h=...` route
|
|
780
|
+
and instructions to sign in as the initiating user;
|
|
514
781
|
- `operator_config`: an `operatorUrl` to the mounted connection UI, plus the
|
|
515
782
|
declared credential label and field names/guidance; or
|
|
516
783
|
- `unavailable`: an honest deployment/configuration message.
|
|
@@ -520,12 +787,28 @@ The class follows what the connector declares, not how it was authored: a
|
|
|
520
787
|
and no OAuth flow, so it uses `operator_config` when both vault and UI are
|
|
521
788
|
configured. Without either it returns `unavailable`, never a dead UI link.
|
|
522
789
|
|
|
523
|
-
|
|
524
|
-
|
|
790
|
+
Errors mint at most one handoff per connector per direct call or program run,
|
|
791
|
+
including concurrent and repeated call or catalog errors. The request reuses the
|
|
792
|
+
same signed URL; a later request can issue a fresh one. Issuing a link is
|
|
793
|
+
stateless and starts no consent. Errors never request `force`; use an explicit
|
|
794
|
+
`authorize_connector` call for a restart or a fresh expired link. URL-elicitation
|
|
795
|
+
hosts keep the existing prompt and retry flow.
|
|
796
|
+
|
|
797
|
+
The tool accepts no secret and starts no downstream consent. `force` applies
|
|
798
|
+
only to OAuth and requests a restart when the verified browser opens the signed
|
|
799
|
+
link. That visit may discard the stored grant before restarting consent. Static credential values are written
|
|
525
800
|
only through the same-origin interactive-user credential route, and only for a
|
|
526
801
|
connector visible to that user with the relevant shared or personal management
|
|
527
|
-
permission; OAuth
|
|
528
|
-
|
|
802
|
+
permission; Issuing an OAuth link, `force` included, requires that permission too. The
|
|
803
|
+
`/connect` visit and callback both verify the same initiating user under Clerk or
|
|
804
|
+
Cloudflare Access, including for shared connectors.
|
|
805
|
+
|
|
806
|
+
Copy `authorizationUrl` exactly as returned. Do not decode or re-encode its opaque,
|
|
807
|
+
unpadded base64url handoff token. If the link is invalid or expired, request a fresh link with
|
|
808
|
+
`authorize_connector`. The URL expires after fifteen minutes and carries no browser authentication.
|
|
809
|
+
A signing credential vault is required; deployments without either interactive provider return `unavailable`
|
|
810
|
+
with a clear configuration message. Status reads stay passive and never expose
|
|
811
|
+
a downstream authorization-server URL. These routes work without the UI. After OAuth
|
|
529
812
|
consent or a human update, retry the original operation; a static update is read
|
|
530
813
|
from the vault on the next call and needs no redeploy.
|
|
531
814
|
|
|
@@ -540,7 +823,7 @@ the same arguments when the miss happened inside `execute_code`, which has no
|
|
|
540
823
|
way to call a tool. `call_tool` reaching an unannotated, write-capable, or
|
|
541
824
|
destructive tool returns `nextAction` for `call_destructive_tool` with the
|
|
542
825
|
canonical address, and so does the same call inside a program, unless config
|
|
543
|
-
|
|
826
|
+
marks that pool trusted. Nothing is executed by these records.
|
|
544
827
|
|
|
545
828
|
`connecta.describe` keeps its failures inline instead, so one miss cannot
|
|
546
829
|
discard the other schemas; each failed entry carries a human `error`, typed
|
|
@@ -560,20 +843,43 @@ invented address once produced a 200 KB refusal against a 1 KB result cap. Every
|
|
|
560
843
|
caller-authored string a refusal repeats therefore gets 512 UTF-8 bytes, and
|
|
561
844
|
what happens over budget differs by field.
|
|
562
845
|
|
|
563
|
-
| Field
|
|
564
|
-
|
|
|
565
|
-
| `args` on `call_tool` and `connecta.call`
|
|
566
|
-
| the attempted address
|
|
567
|
-
| unknown `
|
|
568
|
-
| `search_tools.connector`
|
|
569
|
-
|
|
570
|
-
Arguments
|
|
571
|
-
|
|
846
|
+
| Field | Over 512 UTF-8 bytes |
|
|
847
|
+
| ----------------------------------------------------------------------------- | ----------------------------------------------------------- |
|
|
848
|
+
| `args` on `call_tool` and `connecta.call` | dropped whole; `purpose` says to re-send what was just sent |
|
|
849
|
+
| the attempted address | clamped with a trailing `…` |
|
|
850
|
+
| unknown `connecta.result(id)`, `authorize_connector.connector`, `skills.name` | clamped the same way |
|
|
851
|
+
| `search_tools.connector` | rejected with `invalid_args` before catalog lookup |
|
|
852
|
+
|
|
853
|
+
Arguments are schema-filtered before budgeting. `writeOnly: true` values are
|
|
854
|
+
omitted at any depth, including array items and prefixes, local `$ref`/`$defs`,
|
|
855
|
+
and `allOf`. `oneOf`/`anyOf` alternatives must agree on sensitivity. Unresolved
|
|
856
|
+
or remote references, sensitive `patternProperties`/`additionalProperties`
|
|
857
|
+
schemas, unsupported sensitivity rules, and traversal limits omit the entire
|
|
858
|
+
echo. A private array element omits its containing array to keep indices intact.
|
|
859
|
+
`argsRedacted: true` marks partial or withheld echoes. Use them only to identify
|
|
860
|
+
the target for reconciliation; any new call requires the original arguments.
|
|
861
|
+
The filtered snapshot is never clipped: over-budget arguments are dropped whole.
|
|
862
|
+
The address gets the opposite rule
|
|
572
863
|
because it is the thing being corrected: a clipped one still identifies the
|
|
573
864
|
mistake, and a short one — every real one — comes back exact and untagged. A
|
|
574
865
|
scope is rejected outright because a clipped one could select a different
|
|
575
866
|
connector. A failed result-storage read returns typed `unavailable` without
|
|
576
867
|
exposing backend error text.
|
|
868
|
+
Submitted `writeOnly` values also enter the call's sent-secret output redaction
|
|
869
|
+
set, including property names inside private object subtrees. Downstream
|
|
870
|
+
result and error text quoting them, in raw or credential-supported encoded
|
|
871
|
+
forms, is redacted before direct-call output, program returns, logs, and emits,
|
|
872
|
+
or result stash persistence; paging in a later request reads already-redacted
|
|
873
|
+
bytes. A program's `connecta.read` resources, connector usage guides, and
|
|
874
|
+
downstream `connecta.skill` files take the same rules before the program sees
|
|
875
|
+
them. JSON stays valid: a matching number or boolean becomes `"[redacted]"`.
|
|
876
|
+
Empty private strings are exempt. A private value shorter than eight characters
|
|
877
|
+
redacts only structured fields that equal it, so identifiers and approval state
|
|
878
|
+
remain, and withholds prose that contains it, including error messages, while
|
|
879
|
+
typed classification, retry facts, and write outcome remain.
|
|
880
|
+
Work limits withhold the affected text without failing the call. See
|
|
881
|
+
[output redaction](./auth.md#what-a-servers-errors-may-say)
|
|
882
|
+
for the shared encoding, budget, and argument-filter contract.
|
|
577
883
|
|
|
578
884
|
Activity records each of these refusals with the coarse `friction` class derived
|
|
579
885
|
from its typed error code — `tool_not_found`, `schema_retry`,
|
|
@@ -601,3 +907,51 @@ the compact schema is needed, routed like any other miss: a program to
|
|
|
601
907
|
the listed arguments and reissue the original operation. Which keyword a finding
|
|
602
908
|
names, and what the local validator declines to evaluate, is
|
|
603
909
|
[code mode](./code-mode.md#errors)'s `E8`.
|
|
910
|
+
|
|
911
|
+
`repair` adds agent-only detail from that tool's published schema: accepted
|
|
912
|
+
keys, received JSON types, enum values, numeric/length/item bounds, and known
|
|
913
|
+
conditional requirements such as `dependentRequired` and `if`/`then`/`else`.
|
|
914
|
+
Its `example` is synthesized without submitted values and checked against the
|
|
915
|
+
same validator. Complex or unsatisfiable schemas get `exampleUnavailable`
|
|
916
|
+
rather than an invalid example. Synthesis detects recursive references and
|
|
917
|
+
shares a 128-node work budget. Alternative branches do not emit dependency
|
|
918
|
+
advice unless the branch condition is known. Repair detail has a 4 KiB budget; oversized
|
|
919
|
+
detail is withheld whole with `truncated: true`. Operator records still contain
|
|
920
|
+
only checked failure facts, never findings or examples.
|
|
921
|
+
|
|
922
|
+
Unknown-address errors list `configuredConnectors` from the current endpoint's
|
|
923
|
+
scoped registry, including an empty list when none are accessible. They never
|
|
924
|
+
list connectors from another pool or identity's grants.
|
|
925
|
+
|
|
926
|
+
A write that times out after dispatch returns `write_outcome_unknown` with
|
|
927
|
+
`retryable: false` and an agent-only `uncertainCall: { address, args?, argsOmitted?, argsRedacted? }`.
|
|
928
|
+
No write is automatically replayed. `args` may be partial reconciliation context
|
|
929
|
+
with `argsRedacted: true`. A withheld echo or arguments over the 512-byte budget
|
|
930
|
+
carry `argsOmitted: true`; sensitive or unresolved schemas also carry
|
|
931
|
+
`argsRedacted: true`. When `args` is absent or redacted, use the original
|
|
932
|
+
arguments if reconciliation requires another call. A timeout before dispatch remains `timeout`. Trusted
|
|
933
|
+
program write accounting keeps this detail even if the guest catches the
|
|
934
|
+
failure or returns early. Multiple uncertain writes use `uncertainCalls`,
|
|
935
|
+
bounded to ten calls with `uncertainCallsTruncated` when more exist.
|
|
936
|
+
|
|
937
|
+
Retryability comes from typed errors, HTTP status, registered OAuth error codes,
|
|
938
|
+
SDK timeout classes, and runtime network codes. Untyped prose is non-retryable:
|
|
939
|
+
"timeout", "temporarily unavailable", "rate limit", or "503" in a body, tool
|
|
940
|
+
name, or URL never changes the verdict. JSON-RPC `ProtocolError.data` is dropped
|
|
941
|
+
at the downstream boundary, even when the agent may see the error's message.
|
|
942
|
+
|
|
943
|
+
## Source and tests
|
|
944
|
+
|
|
945
|
+
Handlers and schemas live in [meta-tools.ts](https://github.com/zackbart/connecta/blob/main/src/meta-tools.ts).
|
|
946
|
+
[Catalog service](https://github.com/zackbart/connecta/blob/main/src/catalog-service.ts)
|
|
947
|
+
and [invocation](https://github.com/zackbart/connecta/blob/main/src/invocation.ts)
|
|
948
|
+
serve both direct tools and programs. [Skills](https://github.com/zackbart/connecta/blob/main/src/skills.ts)
|
|
949
|
+
owns the supplied usage instructions and connector guides.
|
|
950
|
+
|
|
951
|
+
[Schema tests](https://github.com/zackbart/connecta/blob/main/test/meta-tool-schemas.test.ts),
|
|
952
|
+
[search tests](https://github.com/zackbart/connecta/blob/main/test/meta-tools-search.test.ts),
|
|
953
|
+
[call tests](https://github.com/zackbart/connecta/blob/main/test/meta-tools-call.test.ts),
|
|
954
|
+
[skills tests](https://github.com/zackbart/connecta/blob/main/test/skills-extension.test.ts),
|
|
955
|
+
and [surface tests](https://github.com/zackbart/connecta/blob/main/test/code-first-surface.test.ts)
|
|
956
|
+
check the published contract. Guest parity and clause evidence are in
|
|
957
|
+
[code-mode verification](./code-mode.md#verification).
|