@zackbart/connecta 0.18.2 → 0.19.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 +100 -4
- package/README.md +4 -0
- package/dist/catalog-service.d.ts +20 -13
- package/dist/catalog-service.js +123 -116
- package/dist/catalog.js +29 -46
- package/dist/connector-scope.js +2 -7
- package/dist/connectors/api.d.ts +4 -16
- package/dist/connectors/api.js +19 -46
- package/dist/connectors/guarded-fetch.d.ts +9 -23
- package/dist/connectors/guarded-fetch.js +38 -76
- package/dist/connectors/remote-mcp.js +36 -79
- package/dist/errors.d.ts +6 -27
- package/dist/errors.js +8 -5
- package/dist/execute.d.ts +24 -22
- package/dist/execute.js +98 -145
- package/dist/executor-result.d.ts +1 -0
- package/dist/executor-result.js +4 -11
- package/dist/executors/quickjs-child.js +1 -3
- package/dist/executors/quickjs-runtime.js +1 -3
- package/dist/executors/quickjs.js +1 -3
- package/dist/index.js +27 -57
- package/dist/invocation.js +114 -178
- package/dist/meta-tools.d.ts +15 -28
- package/dist/meta-tools.js +33 -89
- package/dist/providers/cloudflare.d.ts +2 -18
- package/dist/providers/cloudflare.js +1460 -2451
- package/dist/providers/linear.d.ts +4 -41
- package/dist/providers/linear.js +8 -39
- package/dist/providers/mixpanel.d.ts +3 -25
- package/dist/providers/mixpanel.js +7 -22
- package/dist/providers/notion.d.ts +1 -15
- package/dist/providers/notion.js +44 -173
- package/dist/providers/revenuecat.d.ts +4 -57
- package/dist/providers/revenuecat.js +10 -93
- package/dist/providers/stripe.d.ts +1 -12
- package/dist/providers/stripe.js +7 -45
- package/dist/registry.d.ts +16 -34
- package/dist/registry.js +18 -103
- package/dist/result-shapes.d.ts +13 -0
- package/dist/result-shapes.js +331 -0
- package/dist/routes/mcp.js +1 -1
- package/dist/routes/oauth.js +3 -3
- package/dist/routes/shared.d.ts +15 -15
- package/dist/routes/shared.js +1 -3
- package/dist/skills.js +3 -3
- package/dist/timeout.d.ts +8 -7
- package/dist/timeout.js +47 -38
- package/dist/types.d.ts +3 -3
- package/dist/ui.d.ts +1 -25
- package/dist/ui.js +18 -45
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/documentation/architecture.md +5 -2
- package/documentation/call-admission.md +1 -1
- package/documentation/cloudflare.md +1 -1
- package/documentation/code-mode.md +13 -13
- package/documentation/connectors.md +34 -1
- package/documentation/linear.md +1 -1
- package/documentation/meta-tools.md +17 -3
- package/documentation/mixpanel.md +1 -1
- package/documentation/notion.md +1 -1
- package/documentation/operations.md +20 -15
- package/documentation/provider-conventions.md +1 -1
- package/documentation/revenuecat.md +1 -1
- package/documentation/stripe.md +1 -1
- package/documentation/upgrading.md +24 -4
- package/ethos.md +74 -120
- package/package.json +3 -4
- package/templates/node/package.json +1 -1
- package/documentation/code-first-exploration.md +0 -292
- package/documentation/mcp-2026-07-28.md +0 -46
- package/documentation/mcp-ui-design.md +0 -382
- package/documentation/program-ui-read-calls.md +0 -213
- package/documentation/provider-audit.md +0 -198
- package/documentation/rich-output-design.md +0 -211
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Client, isInputRequiredResult, specTypeSchemas, StreamableHTTPClientTransport, UnauthorizedError, } from "@modelcontextprotocol/client";
|
|
2
2
|
import { KvOAuthProvider } from "../auth/downstream-oauth.js";
|
|
3
3
|
import { MAX_CATALOG_TOOLS } from "../catalog-limits.js";
|
|
4
|
-
import { ConnectorCallError } from "../errors.js";
|
|
4
|
+
import { ConnectorCallError, msg } from "../errors.js";
|
|
5
5
|
import { CONNECTA_VERSION } from "../version.js";
|
|
6
6
|
/**
|
|
7
7
|
* Apply a maintained provider's slot copy and header framing to credential
|
|
@@ -33,28 +33,6 @@ export function withCredentialDefaults(auth, defaults) {
|
|
|
33
33
|
* response, while callers continue to wait at most 100 ms.
|
|
34
34
|
*/
|
|
35
35
|
const TERMINATE_SESSION_BUDGET_MS = 1_000;
|
|
36
|
-
/**
|
|
37
|
-
* Ceiling on the tools one catalog refresh will accumulate while walking
|
|
38
|
-
* `tools/list`.
|
|
39
|
-
*
|
|
40
|
-
* This is the bound that matters, and pages are the wrong dimension to put it
|
|
41
|
-
* in: the *server* picks the page size, so a page ceiling is a tool ceiling
|
|
42
|
-
* multiplied by a number connecta can neither observe in advance nor control.
|
|
43
|
-
* At ten tools a page, 100 pages is 1,000 tools; at a hundred, 10,000 — and
|
|
44
|
-
* connecta's own large-catalog envelope is benchmarked to 100,000 (issue #82).
|
|
45
|
-
* A page ceiling low enough to be a real defense therefore sits *inside* the
|
|
46
|
-
* catalog sizes this product exists to serve. Worse, the common conformant
|
|
47
|
-
* idiom is to advertise a `nextCursor` whenever a page came back full and then
|
|
48
|
-
* serve one empty page to terminate, so a perfectly well-behaved 10,000-tool
|
|
49
|
-
* server paging at 100 spends 101 requests: bound the pages and its entire
|
|
50
|
-
* catalog fails, for doing nothing wrong.
|
|
51
|
-
*
|
|
52
|
-
* So the ceiling goes on accumulated tools — the thing actually held in memory
|
|
53
|
-
* — and it sits at the top of the benchmarked envelope rather than below it.
|
|
54
|
-
* Deliberately the same philosophy as issue #82's discovery-response bounds:
|
|
55
|
-
* cap the bytes a caller can be made to hold, not the number of round trips it
|
|
56
|
-
* took to get them.
|
|
57
|
-
*/
|
|
58
36
|
/**
|
|
59
37
|
* Absolute backstop on `tools/list` pages in one refresh — a runaway guard, not
|
|
60
38
|
* the primary defense.
|
|
@@ -111,9 +89,6 @@ function isCursorShapeError(err) {
|
|
|
111
89
|
// failing path in the message rather than exposing the validator's issues.
|
|
112
90
|
return msg(err).startsWith("Invalid result for tools/list: nextCursor:");
|
|
113
91
|
}
|
|
114
|
-
function msg(err) {
|
|
115
|
-
return err instanceof Error ? err.message : String(err);
|
|
116
|
-
}
|
|
117
92
|
/**
|
|
118
93
|
* End the downstream's session before the connection is torn down.
|
|
119
94
|
*
|
|
@@ -130,6 +105,8 @@ function msg(err) {
|
|
|
130
105
|
* close with the session left to age out as it did before.
|
|
131
106
|
*/
|
|
132
107
|
async function terminateSession(transport, logger, connectorId) {
|
|
108
|
+
// See documentation/connectors.md#mcp-version-skew for the legacy DELETE
|
|
109
|
+
// that Client.close() does not send.
|
|
133
110
|
const terminate = transport.terminateSession;
|
|
134
111
|
if (typeof terminate !== "function")
|
|
135
112
|
return;
|
|
@@ -517,11 +494,14 @@ export function remoteMcp(id, opts) {
|
|
|
517
494
|
}
|
|
518
495
|
return state;
|
|
519
496
|
};
|
|
520
|
-
const
|
|
521
|
-
state
|
|
522
|
-
|
|
497
|
+
const newProvider = (ctx, state) => {
|
|
498
|
+
if (state?.provider)
|
|
499
|
+
return state.provider;
|
|
500
|
+
const provider = new KvOAuthProvider(id, ctx.storage, `${ctx.baseUrl}/oauth/callback/${id}`);
|
|
501
|
+
if (state)
|
|
502
|
+
state.provider = provider;
|
|
503
|
+
return provider;
|
|
523
504
|
};
|
|
524
|
-
const newProvider = (ctx) => new KvOAuthProvider(id, ctx.storage, `${ctx.baseUrl}/oauth/callback/${id}`);
|
|
525
505
|
const buildTransport = (ctx, provider,
|
|
526
506
|
/**
|
|
527
507
|
* This attempt's assembled header value, for credential auth only — framed
|
|
@@ -560,6 +540,20 @@ export function remoteMcp(id, opts) {
|
|
|
560
540
|
state.credentialDigest = null;
|
|
561
541
|
// `closed` is deliberately not cleared — see ConnectionState.
|
|
562
542
|
};
|
|
543
|
+
const closeHalf = async (state) => {
|
|
544
|
+
const client = state.client;
|
|
545
|
+
const transport = state.transport;
|
|
546
|
+
reset(state);
|
|
547
|
+
try {
|
|
548
|
+
if (client)
|
|
549
|
+
await client.close();
|
|
550
|
+
else
|
|
551
|
+
await transport?.close();
|
|
552
|
+
}
|
|
553
|
+
catch {
|
|
554
|
+
// The discarded state remains authoritative if local close fails.
|
|
555
|
+
}
|
|
556
|
+
};
|
|
563
557
|
const ensureConnected = async (ctx, state) => {
|
|
564
558
|
// A 401 after connect is a verdict for the whole request scope, not merely
|
|
565
559
|
// for the one call that observed it. Do not let the still-cached client make
|
|
@@ -573,23 +567,12 @@ export function remoteMcp(id, opts) {
|
|
|
573
567
|
// turn it back into a pending consent flow.
|
|
574
568
|
let oauthGeneration;
|
|
575
569
|
if (isOauth && (state.client || state.connecting)) {
|
|
576
|
-
const provider =
|
|
570
|
+
const provider = newProvider(ctx, state);
|
|
577
571
|
oauthGeneration = await provider.generation();
|
|
578
572
|
if (provider.isOperatorDisconnectedGeneration(oauthGeneration)) {
|
|
579
573
|
const connecting = state.connecting;
|
|
580
|
-
const client = state.client;
|
|
581
|
-
const transport = state.transport;
|
|
582
|
-
reset(state);
|
|
583
574
|
void connecting?.catch(() => { });
|
|
584
|
-
|
|
585
|
-
if (client)
|
|
586
|
-
await client.close();
|
|
587
|
-
else
|
|
588
|
-
await transport?.close();
|
|
589
|
-
}
|
|
590
|
-
catch {
|
|
591
|
-
// The disconnected epoch is authoritative even if local close fails.
|
|
592
|
-
}
|
|
575
|
+
await closeHalf(state);
|
|
593
576
|
throw operatorDisconnectedError();
|
|
594
577
|
}
|
|
595
578
|
}
|
|
@@ -625,19 +608,8 @@ export function remoteMcp(id, opts) {
|
|
|
625
608
|
if (state.closed)
|
|
626
609
|
throw scopeEndedError();
|
|
627
610
|
const connecting = state.connecting;
|
|
628
|
-
const client = state.client;
|
|
629
|
-
const transport = state.transport;
|
|
630
|
-
reset(state);
|
|
631
611
|
void connecting?.catch(() => { });
|
|
632
|
-
|
|
633
|
-
if (client)
|
|
634
|
-
await client.close();
|
|
635
|
-
else
|
|
636
|
-
await transport?.close();
|
|
637
|
-
}
|
|
638
|
-
catch {
|
|
639
|
-
// The rotated-away client is discarded either way.
|
|
640
|
-
}
|
|
612
|
+
await closeHalf(state);
|
|
641
613
|
}
|
|
642
614
|
}
|
|
643
615
|
if (state.closed)
|
|
@@ -754,7 +726,7 @@ export function remoteMcp(id, opts) {
|
|
|
754
726
|
return state.connecting;
|
|
755
727
|
};
|
|
756
728
|
const disconnectAuthorization = async (ctx, state, operatorDisconnected = false) => {
|
|
757
|
-
const provider =
|
|
729
|
+
const provider = newProvider(ctx, state);
|
|
758
730
|
// Publish the replacement epoch before waiting on or closing any
|
|
759
731
|
// request-local transport. A hung connect therefore cannot delay the
|
|
760
732
|
// fence, and every late OAuth write stays in the older namespace.
|
|
@@ -767,18 +739,7 @@ export function remoteMcp(id, opts) {
|
|
|
767
739
|
// client/transport exists. Reset is unconditional because KV may already
|
|
768
740
|
// be fenced behind a newer epoch after a cleanup error.
|
|
769
741
|
void connecting?.catch(() => { });
|
|
770
|
-
|
|
771
|
-
if (state.client) {
|
|
772
|
-
await state.client.close();
|
|
773
|
-
}
|
|
774
|
-
else {
|
|
775
|
-
await state.transport?.close();
|
|
776
|
-
}
|
|
777
|
-
}
|
|
778
|
-
catch {
|
|
779
|
-
// best-effort; the state is discarded either way
|
|
780
|
-
}
|
|
781
|
-
reset(state);
|
|
742
|
+
await closeHalf(state);
|
|
782
743
|
}
|
|
783
744
|
};
|
|
784
745
|
const connector = {
|
|
@@ -854,6 +815,8 @@ export function remoteMcp(id, opts) {
|
|
|
854
815
|
// the accumulator is returned rather than stored: a cursor is opaque and
|
|
855
816
|
// session-bound, so nothing here may outlive this call.
|
|
856
817
|
async listTools(ctx) {
|
|
818
|
+
// The complete-catalog rule is documented at
|
|
819
|
+
// documentation/connectors.md#catalog-contract.
|
|
857
820
|
const state = stateFor(ctx);
|
|
858
821
|
await ensureConnected(ctx, state);
|
|
859
822
|
// Bind the client once so the whole walk provably rides one session — a
|
|
@@ -1019,13 +982,7 @@ export function remoteMcp(id, opts) {
|
|
|
1019
982
|
state.closed = true;
|
|
1020
983
|
const client = state.client;
|
|
1021
984
|
const transport = state.transport;
|
|
1022
|
-
state
|
|
1023
|
-
state.transport = null;
|
|
1024
|
-
state.toolDefinitions.clear();
|
|
1025
|
-
state.connecting = null;
|
|
1026
|
-
state.authRequired = false;
|
|
1027
|
-
state.connectedGeneration = null;
|
|
1028
|
-
state.credentialDigest = null;
|
|
985
|
+
reset(state);
|
|
1029
986
|
// Ask the downstream to drop its session first — closing only aborts our
|
|
1030
987
|
// side, and the DELETE that frees the server's rides on the very
|
|
1031
988
|
// AbortSignal the close is about to trip.
|
|
@@ -1059,7 +1016,7 @@ export function remoteMcp(id, opts) {
|
|
|
1059
1016
|
// credential connector's downstream 401 is repaired on /credentials,
|
|
1060
1017
|
// so do not reach into OAuth storage to look for one.
|
|
1061
1018
|
const url = isOauth
|
|
1062
|
-
? await
|
|
1019
|
+
? await newProvider(ctx, state).pendingAuthorizationUrl()
|
|
1063
1020
|
: undefined;
|
|
1064
1021
|
return {
|
|
1065
1022
|
state: "auth_required",
|
|
@@ -1077,7 +1034,7 @@ export function remoteMcp(id, opts) {
|
|
|
1077
1034
|
},
|
|
1078
1035
|
async finishAuth(code, ctx, callbackParams) {
|
|
1079
1036
|
const state = stateFor(ctx);
|
|
1080
|
-
const provider =
|
|
1037
|
+
const provider = newProvider(ctx, state);
|
|
1081
1038
|
// verifyState ran on this request-scoped provider first and captured the
|
|
1082
1039
|
// pending flow's generation. If force reset races the exchange, any late
|
|
1083
1040
|
// token write remains tagged with that older generation and is unreadable.
|
|
@@ -1097,14 +1054,14 @@ export function remoteMcp(id, opts) {
|
|
|
1097
1054
|
if (opts.auth?.type === "oauth") {
|
|
1098
1055
|
connector.verifyState = async (oauthState, ctx) => {
|
|
1099
1056
|
const state = stateFor(ctx);
|
|
1100
|
-
return
|
|
1057
|
+
return newProvider(ctx, state).verifyState(oauthState);
|
|
1101
1058
|
};
|
|
1102
1059
|
connector.disconnectAuth = async (ctx) => {
|
|
1103
1060
|
await disconnectAuthorization(ctx, stateFor(ctx), true);
|
|
1104
1061
|
};
|
|
1105
1062
|
connector.startAuth = async (ctx, startOpts) => {
|
|
1106
1063
|
const state = stateFor(ctx);
|
|
1107
|
-
const p =
|
|
1064
|
+
const p = newProvider(ctx, state);
|
|
1108
1065
|
if (startOpts?.force || (await p.operatorDisconnected())) {
|
|
1109
1066
|
await disconnectAuthorization(ctx, state);
|
|
1110
1067
|
}
|
package/dist/errors.d.ts
CHANGED
|
@@ -5,26 +5,8 @@
|
|
|
5
5
|
* naming a cause — the rule provider conventions call H11.
|
|
6
6
|
*/
|
|
7
7
|
export type ConnectorCallErrorCode = "timeout" | "auth_required" | "rate_limited" | "unavailable" | "invalid_args"
|
|
8
|
-
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* Its own code because the next move is none of the others': not a retry,
|
|
12
|
-
* not `authorize_connector`, not a reshaped argument object, but
|
|
13
|
-
* re-addressing — look the identifier up again, or accept the absence and
|
|
14
|
-
* carry on. Inside `execute_code` a program reads that difference from a
|
|
15
|
-
* caught error's `code` or a `connecta.batch` entry's `errorDetails.code` —
|
|
16
|
-
* continue past this one, abort on `connector_call_failed`. Message prose
|
|
17
|
-
* cannot be classified.
|
|
18
|
-
*
|
|
19
|
-
* Use it only where the provider distinguishes absence from a permission
|
|
20
|
-
* gap. A status that means both "it is not there" and "you cannot see it" —
|
|
21
|
-
* Notion's `object_not_found` is the worked example — stays
|
|
22
|
-
* `connector_call_failed` with a message that states the ambiguity, because
|
|
23
|
-
* inventing certainty here is how an agent concludes a page was deleted when
|
|
24
|
-
* it was simply never shared. Addresses connecta itself cannot resolve are
|
|
25
|
-
* already framed as `unknown_address` or `unknown_tool` and never reach a
|
|
26
|
-
* connector, so this code is always about a resource the downstream owns.
|
|
27
|
-
*/
|
|
8
|
+
/** Provider-owned absence; see provider-conventions.md H11 for the rule and
|
|
9
|
+
* the permission-ambiguity exception. */
|
|
28
10
|
| "not_found" | "input_required_unsupported" | "connector_call_failed";
|
|
29
11
|
/** One bounded, payload-free explanation of an input-schema mismatch. */
|
|
30
12
|
export interface ArgumentValidationIssue {
|
|
@@ -48,7 +30,7 @@ export declare const MAX_ARGUMENT_VALIDATION_ISSUES = 3;
|
|
|
48
30
|
*/
|
|
49
31
|
export declare function boundedEchoText(value: string, maxBytes?: number): string;
|
|
50
32
|
/**
|
|
51
|
-
* `{ args }` when the caller's arguments fit
|
|
33
|
+
* `{ args }` when the caller's arguments fit the shared echo budget,
|
|
52
34
|
* `{}` when they do not. All or nothing: a clipped echo would be a *different*
|
|
53
35
|
* call than the one that was refused, and the routes this feeds end at a human
|
|
54
36
|
* approving one. Unserializable arguments are treated the same way as oversized
|
|
@@ -97,11 +79,7 @@ export interface CallErrorDetails {
|
|
|
97
79
|
code: string;
|
|
98
80
|
message: string;
|
|
99
81
|
retryable: boolean;
|
|
100
|
-
/**
|
|
101
|
-
* Connector-reported wait window in ms, when known. Reported verbatim — the
|
|
102
|
-
* engine bounds how long it will itself wait, but the caller sees the real
|
|
103
|
-
* window so it can schedule a re-issue.
|
|
104
|
-
*/
|
|
82
|
+
/** Connector-known wait window; see {@link ConnectorCallError.retryAfterMs}. */
|
|
105
83
|
retryAfterMs?: number;
|
|
106
84
|
/** Bounded input-schema findings; paths and expectations, never values. */
|
|
107
85
|
validation?: ArgumentValidationDetails;
|
|
@@ -132,7 +110,7 @@ export interface CallErrorDetails {
|
|
|
132
110
|
address: string;
|
|
133
111
|
/**
|
|
134
112
|
* The caller's own arguments, echoed only when they fit
|
|
135
|
-
*
|
|
113
|
+
* the shared echo budget — and then whole, never clipped. Absent
|
|
136
114
|
* means "re-send exactly what you sent": a half-copied argument object
|
|
137
115
|
* routed into a human approval prompt would describe a call nobody made.
|
|
138
116
|
*/
|
|
@@ -172,3 +150,4 @@ export declare function framingError(code: string, message: string): CallErrorDe
|
|
|
172
150
|
* heuristic.
|
|
173
151
|
*/
|
|
174
152
|
export declare function classifyCallError(err: unknown, fallbackCode?: string): CallErrorDetails;
|
|
153
|
+
export declare function msg(err: unknown): string;
|
package/dist/errors.js
CHANGED
|
@@ -20,7 +20,8 @@ function boundedIssueText(value, maxChars) {
|
|
|
20
20
|
* the payload lands in both the text content and `structuredContent`. The agent
|
|
21
21
|
* already holds what it sent; the echo is a convenience, never the record.
|
|
22
22
|
*/
|
|
23
|
-
|
|
23
|
+
// Shared by argument and text echoes; see meta-tools.md lines 360-372.
|
|
24
|
+
const MAX_ECHOED_BYTES = 512;
|
|
24
25
|
/**
|
|
25
26
|
* The same budget spent on caller-authored *text* — the address it mistyped,
|
|
26
27
|
* the discovery query derived from it — rather than on its arguments.
|
|
@@ -37,7 +38,6 @@ const MAX_ECHOED_ARGS_BYTES = 512;
|
|
|
37
38
|
* `structuredContent`), so an unbounded address turned a 50 KB typo into a
|
|
38
39
|
* 200 KB refusal against a deployment that capped results at 1 KB.
|
|
39
40
|
*/
|
|
40
|
-
const MAX_ECHOED_TEXT_BYTES = 512;
|
|
41
41
|
const echoEncoder = new TextEncoder();
|
|
42
42
|
const echoDecoder = new TextDecoder();
|
|
43
43
|
/**
|
|
@@ -45,7 +45,7 @@ const echoDecoder = new TextDecoder();
|
|
|
45
45
|
* Short strings — the common case, and the one that has to stay exact — are
|
|
46
46
|
* returned unchanged and untagged.
|
|
47
47
|
*/
|
|
48
|
-
export function boundedEchoText(value, maxBytes =
|
|
48
|
+
export function boundedEchoText(value, maxBytes = MAX_ECHOED_BYTES) {
|
|
49
49
|
const bytes = echoEncoder.encode(value);
|
|
50
50
|
if (bytes.length <= maxBytes)
|
|
51
51
|
return value;
|
|
@@ -57,7 +57,7 @@ export function boundedEchoText(value, maxBytes = MAX_ECHOED_TEXT_BYTES) {
|
|
|
57
57
|
return `${echoDecoder.decode(bytes.slice(0, end))}…`;
|
|
58
58
|
}
|
|
59
59
|
/**
|
|
60
|
-
* `{ args }` when the caller's arguments fit
|
|
60
|
+
* `{ args }` when the caller's arguments fit the shared echo budget,
|
|
61
61
|
* `{}` when they do not. All or nothing: a clipped echo would be a *different*
|
|
62
62
|
* call than the one that was refused, and the routes this feeds end at a human
|
|
63
63
|
* approving one. Unserializable arguments are treated the same way as oversized
|
|
@@ -75,7 +75,7 @@ export function echoedCallArgs(args) {
|
|
|
75
75
|
}
|
|
76
76
|
if (text === undefined)
|
|
77
77
|
return {};
|
|
78
|
-
return echoEncoder.encode(text).length <=
|
|
78
|
+
return echoEncoder.encode(text).length <= MAX_ECHOED_BYTES
|
|
79
79
|
? { args }
|
|
80
80
|
: {};
|
|
81
81
|
}
|
|
@@ -221,3 +221,6 @@ export function classifyCallError(err, fallbackCode = "connector_call_failed") {
|
|
|
221
221
|
retryable: RETRYABLE_MESSAGE_RE.test(message),
|
|
222
222
|
};
|
|
223
223
|
}
|
|
224
|
+
export function msg(err) {
|
|
225
|
+
return err instanceof Error ? err.message : String(err);
|
|
226
|
+
}
|
package/dist/execute.d.ts
CHANGED
|
@@ -136,7 +136,9 @@ export declare class EmitCollector {
|
|
|
136
136
|
* complaint about its type would send the author to fix the wrong thing.
|
|
137
137
|
*/
|
|
138
138
|
acceptUi(...values: unknown[]): void;
|
|
139
|
-
|
|
139
|
+
acceptValidatedUi(payload: UiPayload): void;
|
|
140
|
+
private assertUiVacant;
|
|
141
|
+
private acceptUiPayload;
|
|
140
142
|
}
|
|
141
143
|
/** Convert a connector/tool name into a valid JS identifier. */
|
|
142
144
|
export declare function sanitizeIdentifier(name: string): string;
|
|
@@ -146,30 +148,30 @@ export declare function sanitizeIdentifier(name: string): string;
|
|
|
146
148
|
* calls that namespace or explicitly asks search/describe.
|
|
147
149
|
*/
|
|
148
150
|
export declare function buildSandboxProviders(registry: RegistryView, baseUrl: string, logger: Logger, activity?: ActivityRequestContext, limits?: {
|
|
149
|
-
signal?: AbortSignal;
|
|
150
|
-
maxHostCalls?: number;
|
|
151
|
-
hostCallTimeoutMs?: number;
|
|
152
|
-
discoveryConcurrency?: number;
|
|
151
|
+
signal?: AbortSignal | undefined;
|
|
152
|
+
maxHostCalls?: number | undefined;
|
|
153
|
+
hostCallTimeoutMs?: number | undefined;
|
|
154
|
+
discoveryConcurrency?: number | undefined;
|
|
153
155
|
/** Per-connector deadline for in-program catalog probes. Default 30_000. */
|
|
154
|
-
probeTimeoutMs?: number;
|
|
155
|
-
onInvocationFailure?: (failure: InvocationFailure) => void;
|
|
156
|
-
diagnostics?: ExecuteDiagnostics;
|
|
156
|
+
probeTimeoutMs?: number | undefined;
|
|
157
|
+
onInvocationFailure?: ((failure: InvocationFailure) => void) | undefined;
|
|
158
|
+
diagnostics?: ExecuteDiagnostics | undefined;
|
|
157
159
|
/**
|
|
158
160
|
* Where `connecta.emit` collects. The handler that will deliver the
|
|
159
161
|
* blocks owns it; without one, emit fails loudly rather than accept
|
|
160
162
|
* blocks nobody will ever return.
|
|
161
163
|
*/
|
|
162
|
-
emitCollector?: EmitCollector;
|
|
164
|
+
emitCollector?: EmitCollector | undefined;
|
|
163
165
|
/** Runtime-owned tail for stale catalog refreshes. */
|
|
164
|
-
defer?: DeferredWork;
|
|
166
|
+
defer?: DeferredWork | undefined;
|
|
165
167
|
}): Promise<ExecutorProvider[]>;
|
|
166
168
|
/** The execute_code handler. Exported for direct testing. */
|
|
167
169
|
export declare function createExecuteTool(registry: RegistryView, baseUrl: string, executor: Executor, logger: Logger, activity?: ActivityRequestContext, config?: {
|
|
168
|
-
discoveryConcurrency?: number;
|
|
169
|
-
probeTimeoutMs?: number;
|
|
170
|
-
maxEmittedBytes?: number;
|
|
171
|
-
maxEmittedBlocks?: number;
|
|
172
|
-
defer?: DeferredWork;
|
|
170
|
+
discoveryConcurrency?: number | undefined;
|
|
171
|
+
probeTimeoutMs?: number | undefined;
|
|
172
|
+
maxEmittedBytes?: number | undefined;
|
|
173
|
+
maxEmittedBlocks?: number | undefined;
|
|
174
|
+
defer?: DeferredWork | undefined;
|
|
173
175
|
}): ({ code, diagnostics: diagnosticsRequested }: {
|
|
174
176
|
code: string;
|
|
175
177
|
diagnostics?: boolean;
|
|
@@ -181,20 +183,20 @@ export declare function registerExecuteTool(server: McpServer, registry: Registr
|
|
|
181
183
|
baseUrl: string;
|
|
182
184
|
executor: Executor;
|
|
183
185
|
logger: Logger;
|
|
184
|
-
activity?: ActivityRequestContext;
|
|
185
|
-
requestSignal?: AbortSignal;
|
|
186
|
-
discoveryConcurrency?: number;
|
|
186
|
+
activity?: ActivityRequestContext | undefined;
|
|
187
|
+
requestSignal?: AbortSignal | undefined;
|
|
188
|
+
discoveryConcurrency?: number | undefined;
|
|
187
189
|
/**
|
|
188
190
|
* The deployment's configured per-connector probe deadline. Programs probe
|
|
189
191
|
* the same downstream catalogs the top-level tools do, so an operator who
|
|
190
192
|
* tightened `discovery.probeTimeoutMs` gets it honored inside the sandbox
|
|
191
193
|
* too rather than silently falling back to the 30s default.
|
|
192
194
|
*/
|
|
193
|
-
probeTimeoutMs?: number;
|
|
195
|
+
probeTimeoutMs?: number | undefined;
|
|
194
196
|
/** Aggregate serialized-byte budget for connecta.emit. Default 4_000_000. */
|
|
195
|
-
maxEmittedBytes?: number;
|
|
197
|
+
maxEmittedBytes?: number | undefined;
|
|
196
198
|
/** Block-count budget for connecta.emit. Default 32. */
|
|
197
|
-
maxEmittedBlocks?: number;
|
|
198
|
-
defer?: DeferredWork;
|
|
199
|
+
maxEmittedBlocks?: number | undefined;
|
|
200
|
+
defer?: DeferredWork | undefined;
|
|
199
201
|
}): void;
|
|
200
202
|
export {};
|