@zackbart/connecta 0.7.9 → 0.8.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 +48 -0
- package/README.md +67 -144
- package/dist/auth/bearer.d.ts +1 -1
- package/dist/auth/bearer.js +4 -4
- package/dist/auth/bearer.js.map +1 -1
- package/dist/auth/clerk.d.ts +1 -1
- package/dist/auth/clerk.js +1 -1
- package/dist/call-admission.d.ts.map +1 -1
- package/dist/call-admission.js +9 -3
- package/dist/call-admission.js.map +1 -1
- package/dist/catalog-fingerprint.d.ts +20 -0
- package/dist/catalog-fingerprint.d.ts.map +1 -0
- package/dist/catalog-fingerprint.js +34 -0
- package/dist/catalog-fingerprint.js.map +1 -0
- package/dist/catalog-limits.d.ts +10 -0
- package/dist/catalog-limits.d.ts.map +1 -0
- package/dist/catalog-limits.js +10 -0
- package/dist/catalog-limits.js.map +1 -0
- package/dist/catalog-service.d.ts +138 -0
- package/dist/catalog-service.d.ts.map +1 -0
- package/dist/catalog-service.js +407 -0
- package/dist/catalog-service.js.map +1 -0
- package/dist/catalog.js +2 -2
- package/dist/catalog.js.map +1 -1
- package/dist/concurrency.d.ts +4 -0
- package/dist/concurrency.d.ts.map +1 -0
- package/dist/concurrency.js +31 -0
- package/dist/concurrency.js.map +1 -0
- package/dist/connectors/api.d.ts.map +1 -1
- package/dist/connectors/api.js +22 -12
- package/dist/connectors/api.js.map +1 -1
- package/dist/connectors/remote-mcp.d.ts.map +1 -1
- package/dist/connectors/remote-mcp.js +44 -19
- package/dist/connectors/remote-mcp.js.map +1 -1
- package/dist/credential-health.d.ts +0 -22
- package/dist/credential-health.d.ts.map +1 -1
- package/dist/credential-health.js +14 -10
- package/dist/credential-health.js.map +1 -1
- package/dist/credentials.d.ts +3 -2
- package/dist/credentials.d.ts.map +1 -1
- package/dist/errors.d.ts +1 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js.map +1 -1
- package/dist/execute.d.ts +9 -8
- package/dist/execute.d.ts.map +1 -1
- package/dist/execute.js +144 -321
- package/dist/execute.js.map +1 -1
- package/dist/executor-result.d.ts +0 -3
- package/dist/executor-result.d.ts.map +1 -1
- package/dist/executor-result.js +2 -2
- package/dist/executor-result.js.map +1 -1
- package/dist/executors/quickjs-child.js +3 -3
- package/dist/executors/quickjs-child.js.map +1 -1
- package/dist/executors/quickjs-protocol.d.ts +4 -1
- package/dist/executors/quickjs-protocol.d.ts.map +1 -1
- package/dist/executors/quickjs-runtime.d.ts.map +1 -1
- package/dist/executors/quickjs-runtime.js +7 -2
- package/dist/executors/quickjs-runtime.js.map +1 -1
- package/dist/executors/quickjs.d.ts.map +1 -1
- package/dist/executors/quickjs.js +4 -1
- package/dist/executors/quickjs.js.map +1 -1
- package/dist/favicon.js +2 -2
- package/dist/favicon.js.map +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +44 -17
- package/dist/index.js.map +1 -1
- package/dist/invocation.d.ts +96 -0
- package/dist/invocation.d.ts.map +1 -0
- package/dist/invocation.js +369 -0
- package/dist/invocation.js.map +1 -0
- package/dist/meta-tools.d.ts +8 -86
- package/dist/meta-tools.d.ts.map +1 -1
- package/dist/meta-tools.js +145 -583
- package/dist/meta-tools.js.map +1 -1
- package/dist/operator-ui/generated.d.ts +3 -0
- package/dist/operator-ui/generated.d.ts.map +1 -0
- package/dist/operator-ui/generated.js +5 -0
- package/dist/operator-ui/generated.js.map +1 -0
- package/dist/operator-ui/model.d.ts +94 -0
- package/dist/operator-ui/model.d.ts.map +1 -0
- package/dist/operator-ui/model.js +28 -0
- package/dist/operator-ui/model.js.map +1 -0
- package/dist/registry.d.ts +22 -6
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +328 -35
- package/dist/registry.js.map +1 -1
- package/dist/routes/activity.d.ts +3 -0
- package/dist/routes/activity.d.ts.map +1 -0
- package/dist/routes/activity.js +173 -0
- package/dist/routes/activity.js.map +1 -0
- package/dist/routes/credentials.d.ts +3 -0
- package/dist/routes/credentials.d.ts.map +1 -0
- package/dist/routes/credentials.js +181 -0
- package/dist/routes/credentials.js.map +1 -0
- package/dist/routes/mcp.d.ts +8 -0
- package/dist/routes/mcp.d.ts.map +1 -0
- package/dist/routes/mcp.js +383 -0
- package/dist/routes/mcp.js.map +1 -0
- package/dist/routes/oauth.d.ts +4 -0
- package/dist/routes/oauth.d.ts.map +1 -0
- package/dist/routes/oauth.js +268 -0
- package/dist/routes/oauth.js.map +1 -0
- package/dist/routes/shared.d.ts +97 -0
- package/dist/routes/shared.d.ts.map +1 -0
- package/dist/routes/shared.js +199 -0
- package/dist/routes/shared.js.map +1 -0
- package/dist/routes/ui.d.ts +3 -0
- package/dist/routes/ui.d.ts.map +1 -0
- package/dist/routes/ui.js +122 -0
- package/dist/routes/ui.js.map +1 -0
- package/dist/server.d.ts +9 -40
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +63 -1293
- package/dist/server.js.map +1 -1
- package/dist/skills.d.ts +0 -15
- package/dist/skills.d.ts.map +1 -1
- package/dist/skills.js +6 -5
- package/dist/skills.js.map +1 -1
- package/dist/storage/file.d.ts.map +1 -1
- package/dist/storage/file.js +3 -1
- package/dist/storage/file.js.map +1 -1
- package/dist/storage/memory.d.ts.map +1 -1
- package/dist/storage/memory.js +3 -1
- package/dist/storage/memory.js.map +1 -1
- package/dist/toolkits.d.ts +0 -22
- package/dist/toolkits.d.ts.map +1 -1
- package/dist/toolkits.js +2 -2
- package/dist/toolkits.js.map +1 -1
- package/dist/types.d.ts +9 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/ui.d.ts +3 -93
- package/dist/ui.d.ts.map +1 -1
- package/dist/ui.js +26 -1393
- package/dist/ui.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +15 -8
- package/src/auth/bearer.ts +4 -4
- package/src/auth/clerk.ts +1 -1
- package/src/call-admission.ts +8 -5
- package/src/catalog-fingerprint.ts +52 -0
- package/src/catalog-limits.ts +11 -0
- package/src/catalog-service.ts +601 -0
- package/src/catalog.ts +2 -2
- package/src/concurrency.ts +39 -0
- package/src/connectors/api.ts +22 -12
- package/src/connectors/remote-mcp.ts +52 -22
- package/src/credential-health.ts +13 -10
- package/src/credentials.ts +2 -2
- package/src/errors.ts +1 -1
- package/src/execute.ts +194 -409
- package/src/executor-result.ts +2 -2
- package/src/executors/quickjs-child.ts +8 -4
- package/src/executors/quickjs-protocol.ts +1 -1
- package/src/executors/quickjs-runtime.ts +5 -1
- package/src/executors/quickjs.ts +11 -8
- package/src/favicon.ts +2 -2
- package/src/index.ts +49 -17
- package/src/invocation.ts +527 -0
- package/src/meta-tools.ts +366 -906
- package/src/operator-ui/browser.css +413 -0
- package/src/operator-ui/browser.ts +1121 -0
- package/src/operator-ui/generated.ts +4 -0
- package/src/operator-ui/model.ts +127 -0
- package/src/registry.ts +434 -44
- package/src/routes/activity.ts +220 -0
- package/src/routes/credentials.ts +266 -0
- package/src/routes/mcp.ts +485 -0
- package/src/routes/oauth.ts +328 -0
- package/src/routes/shared.ts +330 -0
- package/src/routes/ui.ts +153 -0
- package/src/server.ts +66 -1703
- package/src/skills.ts +6 -5
- package/src/storage/file.ts +3 -1
- package/src/storage/memory.ts +3 -1
- package/src/toolkits.ts +2 -2
- package/src/types.ts +9 -2
- package/src/ui.ts +52 -1493
- package/src/version.ts +1 -1
|
@@ -9,6 +9,7 @@ import { ListToolsResultSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
|
9
9
|
import { CfWorkerJsonSchemaValidator } from "@modelcontextprotocol/sdk/validation/cfworker";
|
|
10
10
|
import { z } from "zod";
|
|
11
11
|
import { KvOAuthProvider } from "../auth/downstream-oauth.js";
|
|
12
|
+
import { MAX_CATALOG_TOOLS } from "../catalog-limits.js";
|
|
12
13
|
import { ConnectorCallError } from "../errors.js";
|
|
13
14
|
import { CONNECTA_VERSION } from "../version.js";
|
|
14
15
|
import type {
|
|
@@ -109,18 +110,16 @@ const TERMINATE_SESSION_BUDGET_MS = 1_000;
|
|
|
109
110
|
* cap the bytes a caller can be made to hold, not the number of round trips it
|
|
110
111
|
* took to get them.
|
|
111
112
|
*/
|
|
112
|
-
const MAX_TOOLS = 100_000;
|
|
113
|
-
|
|
114
113
|
/**
|
|
115
114
|
* Absolute backstop on `tools/list` pages in one refresh — a runaway guard, not
|
|
116
115
|
* the primary defense.
|
|
117
116
|
*
|
|
118
117
|
* The walk terminates on its own well before this: a cursor handed back twice
|
|
119
118
|
* is a definite loop, two consecutive pages that add no new tools are a server
|
|
120
|
-
* going nowhere, and
|
|
121
|
-
* only so the loop is finite even if a downstream somehow
|
|
122
|
-
* forever on a path with no discovery deadline. Set high
|
|
123
|
-
* server reaches it.
|
|
119
|
+
* going nowhere, and MAX_CATALOG_TOOLS caps what any of it can accumulate.
|
|
120
|
+
* This exists only so the loop is finite even if a downstream somehow
|
|
121
|
+
* satisfies all three forever on a path with no discovery deadline. Set high
|
|
122
|
+
* enough that no honest server reaches it.
|
|
124
123
|
*/
|
|
125
124
|
const MAX_TOOL_PAGES = 10_000;
|
|
126
125
|
|
|
@@ -298,7 +297,9 @@ function redirectedInit(init: RequestInit, status: number): RequestInit {
|
|
|
298
297
|
if (!becomesGet) return init;
|
|
299
298
|
const headers = new Headers(init.headers);
|
|
300
299
|
for (const name of BODY_HEADERS) headers.delete(name);
|
|
301
|
-
|
|
300
|
+
const redirected = { ...init, method: "GET", headers };
|
|
301
|
+
delete redirected.body;
|
|
302
|
+
return redirected;
|
|
302
303
|
}
|
|
303
304
|
|
|
304
305
|
/**
|
|
@@ -546,10 +547,14 @@ export function remoteMcp(id: string, opts: RemoteMcpOptions): Connector {
|
|
|
546
547
|
const url = new URL(opts.url);
|
|
547
548
|
const guardedFetch = redirectSafeFetch(id, opts.redirects);
|
|
548
549
|
if (opts.auth?.type === "oauth") {
|
|
550
|
+
// The SDK class declares `sessionId` as an own `string | undefined`
|
|
551
|
+
// property while its Transport interface declares it optional. They are
|
|
552
|
+
// runtime-compatible; exact optional types only exposes that declaration
|
|
553
|
+
// mismatch at this boundary.
|
|
549
554
|
return new StreamableHTTPClientTransport(url, {
|
|
550
555
|
authProvider: provider ?? newProvider(ctx),
|
|
551
556
|
fetch: guardedFetch,
|
|
552
|
-
});
|
|
557
|
+
}) as unknown as Transport;
|
|
553
558
|
}
|
|
554
559
|
const headers =
|
|
555
560
|
opts.auth?.type === "headers" ? opts.auth.headers : undefined;
|
|
@@ -559,7 +564,7 @@ export function remoteMcp(id: string, opts: RemoteMcpOptions): Connector {
|
|
|
559
564
|
...(headers ? { requestInit: { headers } } : {}),
|
|
560
565
|
fetch: guardedFetch,
|
|
561
566
|
},
|
|
562
|
-
);
|
|
567
|
+
) as unknown as Transport;
|
|
563
568
|
};
|
|
564
569
|
|
|
565
570
|
const reset = (state: ConnectionState) => {
|
|
@@ -742,12 +747,18 @@ export function remoteMcp(id: string, opts: RemoteMcpOptions): Connector {
|
|
|
742
747
|
|
|
743
748
|
const connector: Connector = {
|
|
744
749
|
id,
|
|
745
|
-
title: opts.title,
|
|
750
|
+
...(opts.title !== undefined ? { title: opts.title } : {}),
|
|
746
751
|
kind: "mcp",
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
752
|
+
...(opts.description !== undefined
|
|
753
|
+
? { description: opts.description }
|
|
754
|
+
: {}),
|
|
755
|
+
...(opts.maxResultBytes !== undefined
|
|
756
|
+
? { maxResultBytes: opts.maxResultBytes }
|
|
757
|
+
: {}),
|
|
758
|
+
...(opts.callAdmission !== undefined
|
|
759
|
+
? { callAdmission: opts.callAdmission }
|
|
760
|
+
: {}),
|
|
761
|
+
...(opts.usageGuide !== undefined ? { usageGuide: opts.usageGuide } : {}),
|
|
751
762
|
|
|
752
763
|
// `tools/list` is cursor-paginated: the server chooses the page size and
|
|
753
764
|
// signals "there is more" with a `nextCursor`, which the SDK's
|
|
@@ -830,9 +841,9 @@ export function remoteMcp(id: string, opts: RemoteMcpOptions): Connector {
|
|
|
830
841
|
}
|
|
831
842
|
// Checked here rather than on arrival: this bounds what a *walk* may
|
|
832
843
|
// accumulate; a one-page server was always free to send its page.
|
|
833
|
-
if (listed.length >
|
|
844
|
+
if (listed.length > MAX_CATALOG_TOOLS) {
|
|
834
845
|
throw new Error(
|
|
835
|
-
`Connector "${id}" advertised further tools/list pages past ${listed.length} tools, over the ${
|
|
846
|
+
`Connector "${id}" advertised further tools/list pages past ${listed.length} tools, over the ${MAX_CATALOG_TOOLS}-tool ceiling one catalog refresh will collect.`,
|
|
836
847
|
);
|
|
837
848
|
}
|
|
838
849
|
// Opaque by contract: handed straight back, never parsed, rewritten,
|
|
@@ -863,10 +874,28 @@ export function remoteMcp(id: string, opts: RemoteMcpOptions): Connector {
|
|
|
863
874
|
primeToolMetadata(client, listed);
|
|
864
875
|
return listed.map((t) => ({
|
|
865
876
|
name: t.name,
|
|
866
|
-
description: t.description,
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
877
|
+
...(t.description !== undefined ? { description: t.description } : {}),
|
|
878
|
+
...(t.inputSchema !== undefined
|
|
879
|
+
? {
|
|
880
|
+
inputSchema: t.inputSchema as NonNullable<
|
|
881
|
+
ToolDef["inputSchema"]
|
|
882
|
+
>,
|
|
883
|
+
}
|
|
884
|
+
: {}),
|
|
885
|
+
...(t.outputSchema !== undefined
|
|
886
|
+
? {
|
|
887
|
+
outputSchema: t.outputSchema as NonNullable<
|
|
888
|
+
ToolDef["outputSchema"]
|
|
889
|
+
>,
|
|
890
|
+
}
|
|
891
|
+
: {}),
|
|
892
|
+
...(t.annotations !== undefined
|
|
893
|
+
? {
|
|
894
|
+
annotations: t.annotations as NonNullable<
|
|
895
|
+
ToolDef["annotations"]
|
|
896
|
+
>,
|
|
897
|
+
}
|
|
898
|
+
: {}),
|
|
870
899
|
}));
|
|
871
900
|
},
|
|
872
901
|
|
|
@@ -942,7 +971,7 @@ export function remoteMcp(id: string, opts: RemoteMcpOptions): Connector {
|
|
|
942
971
|
const url = await getProvider(ctx, state).pendingAuthorizationUrl();
|
|
943
972
|
return {
|
|
944
973
|
state: "auth_required",
|
|
945
|
-
authorizationUrl: url,
|
|
974
|
+
...(url !== undefined ? { authorizationUrl: url } : {}),
|
|
946
975
|
message: "Authorization required — open the URL to connect.",
|
|
947
976
|
};
|
|
948
977
|
}
|
|
@@ -1013,9 +1042,10 @@ export function remoteMcp(id: string, opts: RemoteMcpOptions): Connector {
|
|
|
1013
1042
|
};
|
|
1014
1043
|
} catch (err) {
|
|
1015
1044
|
if (state.authRequired) {
|
|
1045
|
+
const authorizationUrl = await p.pendingAuthorizationUrl();
|
|
1016
1046
|
return {
|
|
1017
1047
|
state: "auth_required",
|
|
1018
|
-
authorizationUrl:
|
|
1048
|
+
...(authorizationUrl !== undefined ? { authorizationUrl } : {}),
|
|
1019
1049
|
message: "Authorization required — open the URL to connect.",
|
|
1020
1050
|
};
|
|
1021
1051
|
}
|
package/src/credential-health.ts
CHANGED
|
@@ -117,8 +117,8 @@ export interface CredentialHealthConfig {
|
|
|
117
117
|
onRequest?: boolean;
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
-
|
|
121
|
-
|
|
120
|
+
const DEFAULT_CREDENTIAL_CHECK_INTERVAL_SECONDS = 900;
|
|
121
|
+
const DEFAULT_CREDENTIAL_CHECK_CONCURRENCY = 4;
|
|
122
122
|
|
|
123
123
|
/**
|
|
124
124
|
* How long a read of one connector's record is served from memory before going
|
|
@@ -362,7 +362,7 @@ export interface CredentialCheckOptions {
|
|
|
362
362
|
* their back. A connector whose only hook cannot test its declared shape is
|
|
363
363
|
* checkable only if it also implements `status()`.
|
|
364
364
|
*/
|
|
365
|
-
|
|
365
|
+
function isCheckableConnector(connector: Connector): boolean {
|
|
366
366
|
const hasCredentialStore = Boolean(
|
|
367
367
|
connector.credential || connector.hasStoredCredential,
|
|
368
368
|
);
|
|
@@ -408,8 +408,9 @@ function testHookFor(
|
|
|
408
408
|
}
|
|
409
409
|
// A single-value shape with nothing under the reserved field is still nothing
|
|
410
410
|
// to test, so the stored value gets the last word even when the rule fits.
|
|
411
|
-
|
|
412
|
-
|
|
411
|
+
const storedValue = storedValues.value;
|
|
412
|
+
if (mode === "single" && typeof storedValue === "string") {
|
|
413
|
+
return (ctx) => connector.testCredential!(storedValue, ctx);
|
|
413
414
|
}
|
|
414
415
|
return undefined;
|
|
415
416
|
}
|
|
@@ -420,14 +421,16 @@ async function mapWithConcurrency<T, R>(
|
|
|
420
421
|
limit: number,
|
|
421
422
|
fn: (item: T) => Promise<R>,
|
|
422
423
|
): Promise<R[]> {
|
|
423
|
-
const out =
|
|
424
|
-
|
|
424
|
+
const out = Array<R>(items.length);
|
|
425
|
+
const remaining = items.entries();
|
|
425
426
|
const workers = Array.from(
|
|
426
427
|
{ length: Math.min(limit, items.length) },
|
|
427
428
|
async () => {
|
|
428
|
-
|
|
429
|
-
const
|
|
430
|
-
|
|
429
|
+
for (;;) {
|
|
430
|
+
const next = remaining.next();
|
|
431
|
+
if (next.done) return;
|
|
432
|
+
const [index, item] = next.value;
|
|
433
|
+
out[index] = await fn(item);
|
|
431
434
|
}
|
|
432
435
|
},
|
|
433
436
|
);
|
package/src/credentials.ts
CHANGED
|
@@ -24,7 +24,7 @@ interface CredentialPlaintext {
|
|
|
24
24
|
updatedBy: string;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
interface CredentialFieldMetadata {
|
|
28
28
|
configured: true;
|
|
29
29
|
/** Only emitted when the value is long enough that four chars don't leak much. */
|
|
30
30
|
lastFour?: string;
|
|
@@ -41,7 +41,7 @@ export interface CredentialMetadata {
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
/** Which hook a testable credential is checked with. */
|
|
44
|
-
|
|
44
|
+
type CredentialTestMode = "single" | "multiple";
|
|
45
45
|
|
|
46
46
|
/** Operator-safe explanation shared by every surface that detects shape drift. */
|
|
47
47
|
export const STORED_CREDENTIAL_SHAPE_MISMATCH_ERROR =
|
package/src/errors.ts
CHANGED
|
@@ -49,7 +49,7 @@ export class ConnectorCallError extends Error {
|
|
|
49
49
|
* the assignment would not keep it off the instance. Keeping the window out
|
|
50
50
|
* of the wire format is `classifyCallError`'s job, not this constructor's.
|
|
51
51
|
*/
|
|
52
|
-
readonly retryAfterMs
|
|
52
|
+
readonly retryAfterMs: number | undefined;
|
|
53
53
|
|
|
54
54
|
constructor(
|
|
55
55
|
code: ConnectorCallErrorCode,
|