@zackbart/connecta 0.22.2 → 0.23.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 +59 -0
- package/README.md +1 -1
- package/dist/auth/downstream-oauth.d.ts +3 -1
- package/dist/auth/downstream-oauth.js +11 -0
- package/dist/catalog-service.d.ts +1 -6
- package/dist/catalog-service.js +3 -53
- package/dist/errors.d.ts +1 -1
- package/dist/execute.d.ts +5 -52
- package/dist/execute.js +40 -347
- package/dist/executors/quickjs-protocol.d.ts +0 -7
- package/dist/executors/quickjs-protocol.js +2 -10
- package/dist/executors/quickjs.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/invocation.d.ts +0 -33
- package/dist/invocation.js +54 -121
- package/dist/meta-tools.d.ts +3 -6
- package/dist/meta-tools.js +6 -17
- package/dist/registry.js +4 -0
- package/dist/routes/mcp.js +0 -48
- package/dist/server.d.ts +1 -2
- package/dist/server.js +1 -19
- package/dist/skills.d.ts +1 -1
- package/dist/skills.js +55 -19
- package/dist/types.d.ts +1 -15
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/documentation/architecture.md +7 -11
- package/documentation/auth.md +4 -5
- package/documentation/call-admission.md +10 -11
- package/documentation/code-mode.md +65 -260
- package/documentation/connectors.md +7 -5
- package/documentation/meta-tools.md +31 -14
- package/documentation/operations.md +7 -9
- package/documentation/provider-conventions.md +2 -2
- package/documentation/upgrading.md +59 -9
- package/ethos.md +14 -13
- package/package.json +1 -1
- package/templates/node/package.json +1 -1
- package/dist/apps-shell.d.ts +0 -37
- package/dist/apps-shell.js +0 -174
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,65 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this package are documented here.
|
|
4
4
|
|
|
5
|
+
## 0.23.0 — 2026-09-07
|
|
6
|
+
|
|
7
|
+
This release removes server-owned program views, connector HTTP routes, and
|
|
8
|
+
three convenience APIs. It also exposes configured account titles during
|
|
9
|
+
discovery and clarifies schema inspection and dependent calls.
|
|
10
|
+
Programs use canonical tool addresses and JavaScript promises; callers own
|
|
11
|
+
retry timing. Stored programs using shortcut globals, `connecta.batch`, or
|
|
12
|
+
`connecta.ui` need migration. Direct calls must omit `maxRetries`. Deployments
|
|
13
|
+
using none of these need no configuration or storage changes. The seven tools,
|
|
14
|
+
operator pages, credentials, and emitted media remain. Cloudflare Global API
|
|
15
|
+
Key authentication and multi-field credentials remain supported.
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
|
|
19
|
+
- Optional `investigate` guidance for purchase verification, experiments, and
|
|
20
|
+
customer or deployment investigations. It explains account selection,
|
|
21
|
+
evidence requirements, and when to stop with an unresolved gap (#527).
|
|
22
|
+
- Bounded configured account titles in the initial connector inventory and
|
|
23
|
+
program search results, without provider calls or changes to ranking (#527).
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
|
|
27
|
+
- Remove connector `handleRequest` routes. Stale declarations fail at
|
|
28
|
+
construction; custom routes belong to the existing deployment fetch handler.
|
|
29
|
+
- Remove MCP Apps rendering, its HTML shell, resource handlers, extension
|
|
30
|
+
declaration, and tool UI metadata. Clients render returned data.
|
|
31
|
+
- Remove connector shortcut globals and their sanitization and collision rules.
|
|
32
|
+
Programs call the canonical address through `connecta.call`.
|
|
33
|
+
- Remove `connecta.batch`. Use `Promise.all` or `Promise.allSettled` under the
|
|
34
|
+
same host-call and connector admission limits.
|
|
35
|
+
- Remove automatic retries and backoff timing from direct calls. Failures keep
|
|
36
|
+
their classification and provider retry hint. Direct-call schemas reject
|
|
37
|
+
unknown arguments, including the removed `maxRetries` option.
|
|
38
|
+
- Clarify JSON schema inspection, provider result shapes, and promise failures.
|
|
39
|
+
Keep discovery and calls together when schemas suffice; allow a small sample
|
|
40
|
+
for unfamiliar results before continuing in another program (#527).
|
|
41
|
+
|
|
42
|
+
### Fixed
|
|
43
|
+
|
|
44
|
+
- Remove the stale CI invocation of the retired evaluation `audit` script.
|
|
45
|
+
The benchmark self-tests remain in CI; whole-agent comparisons run locally.
|
|
46
|
+
|
|
47
|
+
## 0.22.3 — 2026-09-03
|
|
48
|
+
|
|
49
|
+
This patch carries OAuth discovery across the browser redirect. It matters for
|
|
50
|
+
downstream MCP servers whose authentication challenge names a protected-resource
|
|
51
|
+
metadata URL outside the RFC 9728 default path, including Cloudflare Access
|
|
52
|
+
Managed OAuth. Existing grants and connectors using the default path require no
|
|
53
|
+
configuration or storage migration.
|
|
54
|
+
|
|
55
|
+
### Fixed
|
|
56
|
+
|
|
57
|
+
- **Non-default OAuth discovery survives callbacks.** The KV OAuth provider now
|
|
58
|
+
persists the SDK's discovery state in the authorization generation, restores
|
|
59
|
+
it in the callback's fresh request scope, and deletes it through discovery,
|
|
60
|
+
all-credential, and generation cleanup. A callback therefore exchanges its
|
|
61
|
+
code against the same validated authorization-server issuer that registered
|
|
62
|
+
the client instead of invalidating that client after rediscovery (#523).
|
|
63
|
+
|
|
5
64
|
## 0.22.2 — 2026-09-01
|
|
6
65
|
|
|
7
66
|
This patch makes the maintained-provider release check credential-free and
|
package/README.md
CHANGED
|
@@ -45,7 +45,7 @@ This is the kind of thing the agent writes, not you:
|
|
|
45
45
|
|
|
46
46
|
```js
|
|
47
47
|
async () => {
|
|
48
|
-
const { nodes } = await tracker.list_issues
|
|
48
|
+
const { nodes } = await connecta.call("tracker.list_issues", { state: "started" });
|
|
49
49
|
const byOwner = {};
|
|
50
50
|
for (const issue of nodes) {
|
|
51
51
|
(byOwner[issue.assignee?.name ?? "unassigned"] ??= []).push(issue.identifier);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { FetchLike, OAuthClientInformationContext, OAuthClientInformationMixed, OAuthClientMetadata, OAuthClientProvider, OAuthTokens } from "@modelcontextprotocol/client";
|
|
1
|
+
import type { FetchLike, OAuthClientInformationContext, OAuthClientInformationMixed, OAuthClientMetadata, OAuthClientProvider, OAuthDiscoveryState, OAuthTokens } from "@modelcontextprotocol/client";
|
|
2
2
|
import type { KVStorage } from "../types.js";
|
|
3
3
|
type OAuthRefreshFlightOutcome = {
|
|
4
4
|
status: "refreshed";
|
|
@@ -134,6 +134,8 @@ export declare class KvOAuthProvider implements OAuthClientProvider {
|
|
|
134
134
|
get clientMetadata(): OAuthClientMetadata;
|
|
135
135
|
clientInformation(ctx?: OAuthClientInformationContext): Promise<OAuthClientInformationMixed | undefined>;
|
|
136
136
|
saveClientInformation(info: OAuthClientInformationMixed, ctx?: OAuthClientInformationContext): Promise<void>;
|
|
137
|
+
discoveryState(): Promise<OAuthDiscoveryState | undefined>;
|
|
138
|
+
saveDiscoveryState(state: OAuthDiscoveryState): Promise<void>;
|
|
137
139
|
tokens(ctx?: OAuthClientInformationContext): Promise<OAuthTokens | undefined>;
|
|
138
140
|
saveTokens(tokens: OAuthTokens, ctx?: OAuthClientInformationContext): Promise<void>;
|
|
139
141
|
/**
|
|
@@ -24,6 +24,7 @@ const OAUTH_VALUE_KEYS = [
|
|
|
24
24
|
"oauth:pending",
|
|
25
25
|
"oauth:verifier",
|
|
26
26
|
"oauth:state",
|
|
27
|
+
"oauth:discovery",
|
|
27
28
|
];
|
|
28
29
|
const MAX_CLEANUP_BACKLOG = 1_000;
|
|
29
30
|
function isRefreshTokenRequest(init) {
|
|
@@ -621,6 +622,12 @@ export class KvOAuthProvider {
|
|
|
621
622
|
async saveClientInformation(info, ctx) {
|
|
622
623
|
await this.writeValue("oauth:client", info, (value) => JSON.stringify(value), ctx?.issuer);
|
|
623
624
|
}
|
|
625
|
+
async discoveryState() {
|
|
626
|
+
return (await this.readValue("oauth:discovery", (raw) => JSON.parse(raw)))?.value;
|
|
627
|
+
}
|
|
628
|
+
async saveDiscoveryState(state) {
|
|
629
|
+
await this.writeValue("oauth:discovery", state, (value) => JSON.stringify(value));
|
|
630
|
+
}
|
|
624
631
|
async tokens(ctx) {
|
|
625
632
|
const refreshGeneration = ctx ? await this.flowGeneration() : undefined;
|
|
626
633
|
const successIdentity = refreshGeneration !== undefined
|
|
@@ -800,6 +807,7 @@ export class KvOAuthProvider {
|
|
|
800
807
|
oauthValueStorageKey("oauth:client", generation),
|
|
801
808
|
oauthValueStorageKey("oauth:tokens", generation),
|
|
802
809
|
oauthValueStorageKey("oauth:verifier", generation),
|
|
810
|
+
oauthValueStorageKey("oauth:discovery", generation),
|
|
803
811
|
]);
|
|
804
812
|
}
|
|
805
813
|
else if (scope === "client") {
|
|
@@ -811,6 +819,9 @@ export class KvOAuthProvider {
|
|
|
811
819
|
else if (scope === "verifier") {
|
|
812
820
|
await this.storage.delete(oauthValueStorageKey("oauth:verifier", generation));
|
|
813
821
|
}
|
|
822
|
+
else if (scope === "discovery") {
|
|
823
|
+
await this.storage.delete(oauthValueStorageKey("oauth:discovery", generation));
|
|
824
|
+
}
|
|
814
825
|
if (endsRefresh) {
|
|
815
826
|
this.failRefreshFlight(new Error("OAuth refresh invalidated credentials before tokens were saved."));
|
|
816
827
|
}
|
|
@@ -181,12 +181,6 @@ export declare class CatalogService {
|
|
|
181
181
|
private catalogLoadFailure;
|
|
182
182
|
private unknownToolFailure;
|
|
183
183
|
resolveTool(address: string, callOptions?: ConnectorOperationOptions): Promise<CatalogResolution>;
|
|
184
|
-
/**
|
|
185
|
-
* Resolve the JavaScript-safe property used by a lazy code-mode namespace
|
|
186
|
-
* back to exactly one catalog tool. Ambiguous aliases fail with an explicit
|
|
187
|
-
* escape hatch instead of silently choosing the first tool.
|
|
188
|
-
*/
|
|
189
|
-
resolveToolAlias(connectorId: string, alias: string, aliasFor: (toolName: string) => string, callOptions?: ConnectorOperationOptions): Promise<CatalogResolution>;
|
|
190
184
|
search(args: CatalogSearchArgs): Promise<CatalogSearchPage>;
|
|
191
185
|
describe(args: CatalogDescribeArgs): Promise<CatalogDescription[]>;
|
|
192
186
|
}
|
|
@@ -247,6 +241,7 @@ export declare function flatSearchResult(page: CatalogSearchPage): {
|
|
|
247
241
|
tools: {
|
|
248
242
|
guideSummary?: string;
|
|
249
243
|
guide?: string;
|
|
244
|
+
connectorTitle?: string;
|
|
250
245
|
name: string;
|
|
251
246
|
address: string;
|
|
252
247
|
description?: string;
|
package/dist/catalog-service.js
CHANGED
|
@@ -336,59 +336,6 @@ export class CatalogService {
|
|
|
336
336
|
catalogMs: Date.now() - started,
|
|
337
337
|
};
|
|
338
338
|
}
|
|
339
|
-
/**
|
|
340
|
-
* Resolve the JavaScript-safe property used by a lazy code-mode namespace
|
|
341
|
-
* back to exactly one catalog tool. Ambiguous aliases fail with an explicit
|
|
342
|
-
* escape hatch instead of silently choosing the first tool.
|
|
343
|
-
*/
|
|
344
|
-
async resolveToolAlias(connectorId, alias, aliasFor, callOptions = {}) {
|
|
345
|
-
const connector = this.registry.getConnector(connectorId);
|
|
346
|
-
if (!connector) {
|
|
347
|
-
return this.unknownAddressFailure(`${connectorId}.${alias}`, alias);
|
|
348
|
-
}
|
|
349
|
-
const started = Date.now();
|
|
350
|
-
let tools;
|
|
351
|
-
try {
|
|
352
|
-
tools = await this.loadConnector(connector.id, callOptions);
|
|
353
|
-
}
|
|
354
|
-
catch (cause) {
|
|
355
|
-
return this.catalogLoadFailure(cause, started, connector, alias);
|
|
356
|
-
}
|
|
357
|
-
const [definition, ...collisions] = tools.filter((tool) => aliasFor(tool.name) === alias);
|
|
358
|
-
if (!definition) {
|
|
359
|
-
return this.unknownToolFailure(alias, connector, started);
|
|
360
|
-
}
|
|
361
|
-
if (collisions.length > 0) {
|
|
362
|
-
const names = [definition, ...collisions]
|
|
363
|
-
.map((tool) => `"${tool.name}"`)
|
|
364
|
-
.join(", ");
|
|
365
|
-
return {
|
|
366
|
-
ok: false,
|
|
367
|
-
error: {
|
|
368
|
-
code: "ambiguous_tool_alias",
|
|
369
|
-
message: `Tool alias "${boundedEchoText(alias)}" is ambiguous on connector "${connector.id}" because ${names} sanitize to the same name. Use connecta.call with an exact address.`,
|
|
370
|
-
retryable: false,
|
|
371
|
-
nextAction: {
|
|
372
|
-
function: "connecta.call",
|
|
373
|
-
addresses: [definition, ...collisions].map((tool) => `${connector.id}.${tool.name}`),
|
|
374
|
-
purpose: "Choose the intended canonical address and call it with the original arguments.",
|
|
375
|
-
},
|
|
376
|
-
},
|
|
377
|
-
catalogMs: Date.now() - started,
|
|
378
|
-
connector,
|
|
379
|
-
toolName: alias,
|
|
380
|
-
};
|
|
381
|
-
}
|
|
382
|
-
return {
|
|
383
|
-
ok: true,
|
|
384
|
-
resolved: {
|
|
385
|
-
connector,
|
|
386
|
-
toolName: definition.name,
|
|
387
|
-
definition,
|
|
388
|
-
},
|
|
389
|
-
catalogMs: Date.now() - started,
|
|
390
|
-
};
|
|
391
|
-
}
|
|
392
339
|
async search(args) {
|
|
393
340
|
const query = args.query ?? "";
|
|
394
341
|
const retrievalQuery = lexicalSearchQuery(query);
|
|
@@ -894,6 +841,9 @@ export function flatSearchResult(page) {
|
|
|
894
841
|
return {
|
|
895
842
|
tools: page.entries.map((entry) => ({
|
|
896
843
|
...entry.tool,
|
|
844
|
+
...(entry.connector.title
|
|
845
|
+
? { connectorTitle: boundedEchoText(entry.connector.title.replace(/\s+/g, " ").trim(), 117) }
|
|
846
|
+
: {}),
|
|
897
847
|
...(entry.guide ? { guide: entry.guide } : {}),
|
|
898
848
|
...(entry.guideSummary
|
|
899
849
|
? { guideSummary: entry.guideSummary }
|
package/dist/errors.d.ts
CHANGED
|
@@ -74,7 +74,7 @@ export declare class ConnectorCallError extends Error {
|
|
|
74
74
|
validation?: ArgumentValidationDetails;
|
|
75
75
|
});
|
|
76
76
|
}
|
|
77
|
-
/** The `error` object surfaced in value-mode call results and
|
|
77
|
+
/** The `error` object surfaced in value-mode call results and rejected promises. */
|
|
78
78
|
export interface CallErrorDetails {
|
|
79
79
|
code: string;
|
|
80
80
|
message: string;
|
package/dist/execute.d.ts
CHANGED
|
@@ -5,7 +5,6 @@ import { type ToolResult } from "./meta-tools.js";
|
|
|
5
5
|
import { InvocationFailure } from "./invocation.js";
|
|
6
6
|
import type { RegistryView } from "./registry.js";
|
|
7
7
|
import type { Executor, ExecutorProvider, Logger } from "./types.js";
|
|
8
|
-
export declare const EXECUTE_MAX_BATCH_CALLS = 10;
|
|
9
8
|
/** Complete entries plus an exact omission count, all inside this byte cap. */
|
|
10
9
|
export declare const CONNECTOR_INVENTORY_MAX_BYTES = 256;
|
|
11
10
|
/**
|
|
@@ -17,7 +16,7 @@ export declare const CONNECTOR_INVENTORY_MAX_BYTES = 256;
|
|
|
17
16
|
*/
|
|
18
17
|
export declare const EXECUTE_MAX_EMITTED_BYTES = 4000000;
|
|
19
18
|
export declare const EXECUTE_MAX_EMITTED_BLOCKS = 32;
|
|
20
|
-
type ExecuteDiagnosticOperation = "search" | "describe" | "call"
|
|
19
|
+
type ExecuteDiagnosticOperation = "search" | "describe" | "call";
|
|
21
20
|
interface ExecuteOperationDiagnostics {
|
|
22
21
|
operation: ExecuteDiagnosticOperation;
|
|
23
22
|
count: number;
|
|
@@ -26,7 +25,6 @@ interface ExecuteOperationDiagnostics {
|
|
|
26
25
|
resultBytes: number;
|
|
27
26
|
catalogMs: number;
|
|
28
27
|
connectorMs: number;
|
|
29
|
-
calls?: number;
|
|
30
28
|
}
|
|
31
29
|
declare class ExecuteDiagnostics {
|
|
32
30
|
private readonly started;
|
|
@@ -35,19 +33,12 @@ declare class ExecuteDiagnostics {
|
|
|
35
33
|
setupMs: number;
|
|
36
34
|
executorWallMs: number;
|
|
37
35
|
private emitted?;
|
|
38
|
-
private ui?;
|
|
39
36
|
/** Numbers only, per R8 — and only once something was emitted, so a
|
|
40
37
|
* non-emitting run's diagnostics stay byte-for-byte what they were. */
|
|
41
38
|
recordEmitted(count: number, bytes: number): void;
|
|
42
|
-
/**
|
|
43
|
-
* U9: the UI payload gets its own aggregate — one number, the payload's
|
|
44
|
-
* serialized size. Folding it into `emitted` would desync that aggregate's
|
|
45
|
-
* pair, which reports the bytes a specific block count cost.
|
|
46
|
-
*/
|
|
47
|
-
recordUi(bytes: number): void;
|
|
48
39
|
private stats;
|
|
49
40
|
recordCatalog(operation: "search" | "describe", durationMs: number, ok: boolean, result?: unknown): void;
|
|
50
|
-
recordCall(
|
|
41
|
+
recordCall(outcome: {
|
|
51
42
|
ok: boolean;
|
|
52
43
|
durationMs: number;
|
|
53
44
|
timing: {
|
|
@@ -56,7 +47,6 @@ declare class ExecuteDiagnostics {
|
|
|
56
47
|
};
|
|
57
48
|
value?: unknown;
|
|
58
49
|
}): void;
|
|
59
|
-
recordBatch(durationMs: number, ok: boolean, calls: number, result?: unknown): void;
|
|
60
50
|
finish(): {
|
|
61
51
|
timing: {
|
|
62
52
|
totalMs: number;
|
|
@@ -71,7 +61,6 @@ declare class ExecuteDiagnostics {
|
|
|
71
61
|
count: number;
|
|
72
62
|
bytes: number;
|
|
73
63
|
};
|
|
74
|
-
ui?: number;
|
|
75
64
|
};
|
|
76
65
|
}
|
|
77
66
|
/**
|
|
@@ -91,56 +80,20 @@ export type EmittedBlock = {
|
|
|
91
80
|
data: string;
|
|
92
81
|
mimeType: string;
|
|
93
82
|
};
|
|
94
|
-
interface UiPayload {
|
|
95
|
-
html: string;
|
|
96
|
-
}
|
|
97
|
-
/**
|
|
98
|
-
* Request-local collection for `connecta.emit` and `connecta.ui`. Budgets fail
|
|
99
|
-
* loudly at the crossing call — nothing is partially accepted and prior blocks
|
|
100
|
-
* are unaffected — so a program learns it is over budget while it can still
|
|
101
|
-
* choose differently (M5, U4). Accepted output never rides `ExecuteResult`; the
|
|
102
|
-
* handler that owns this collector delivers it on the final tool result.
|
|
103
|
-
*
|
|
104
|
-
* The two channels share the byte aggregate and nothing else: a UI payload is
|
|
105
|
-
* not a block, so it spends no block count, and at most one is ever accepted.
|
|
106
|
-
*/
|
|
107
83
|
export declare class EmitCollector {
|
|
108
84
|
private readonly maxBytes;
|
|
109
85
|
private readonly maxBlocks;
|
|
110
86
|
private readonly diagnostics?;
|
|
111
87
|
readonly blocks: EmittedBlock[];
|
|
112
|
-
/** The shared transport aggregate: emitted blocks plus the UI payload. */
|
|
113
88
|
bytes: number;
|
|
114
|
-
/** The one accepted UI payload (U2), delivered in result `_meta` on success. */
|
|
115
|
-
ui?: UiPayload;
|
|
116
|
-
/** What the blocks alone cost, so the `emitted` aggregate stays a true pair. */
|
|
117
|
-
private blockBytes;
|
|
118
89
|
constructor(maxBytes: number, maxBlocks: number, diagnostics?: ExecuteDiagnostics | undefined);
|
|
119
90
|
accept(raw: unknown): void;
|
|
120
|
-
/**
|
|
121
|
-
* U2 and U4: one payload per run, measured as the serialized bytes of
|
|
122
|
-
* `{ html }` against the same aggregate emit spends. A second call throws
|
|
123
|
-
* naming the constraint rather than replacing the first — one tool result
|
|
124
|
-
* renders one view, and last-wins would silently discard a payload the
|
|
125
|
-
* program deliberately supplied.
|
|
126
|
-
*
|
|
127
|
-
* Multiplicity is checked before shape, so the second call is told what it
|
|
128
|
-
* actually broke. A program whose second payload is also malformed has one
|
|
129
|
-
* problem worth naming — that there is a second payload at all — and a
|
|
130
|
-
* complaint about its type would send the author to fix the wrong thing.
|
|
131
|
-
*/
|
|
132
|
-
acceptUi(...values: unknown[]): void;
|
|
133
|
-
private assertUiVacant;
|
|
134
|
-
private acceptUiPayload;
|
|
135
91
|
}
|
|
136
|
-
/** Convert a connector/tool name into a valid JS identifier. */
|
|
137
|
-
export declare function sanitizeIdentifier(name: string): string;
|
|
138
92
|
/**
|
|
139
|
-
* Expose one
|
|
140
|
-
*
|
|
141
|
-
* calls that namespace or explicitly asks search/describe.
|
|
93
|
+
* Expose one host provider and typed guest errors. Catalogs load only when
|
|
94
|
+
* the program calls a tool or asks search/describe.
|
|
142
95
|
*/
|
|
143
|
-
export declare function buildSandboxProviders(registry: RegistryView, baseUrl: string,
|
|
96
|
+
export declare function buildSandboxProviders(registry: RegistryView, baseUrl: string, _logger: Logger, activity?: ActivityRequestContext, limits?: {
|
|
144
97
|
signal?: AbortSignal | undefined;
|
|
145
98
|
maxHostCalls?: number | undefined;
|
|
146
99
|
hostCallTimeoutMs?: number | undefined;
|