@zackbart/connecta 0.7.8 → 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.
Files changed (187) hide show
  1. package/CHANGELOG.md +94 -0
  2. package/README.md +67 -144
  3. package/dist/activity.d.ts +1 -1
  4. package/dist/activity.d.ts.map +1 -1
  5. package/dist/activity.js.map +1 -1
  6. package/dist/auth/bearer.d.ts +1 -1
  7. package/dist/auth/bearer.js +4 -4
  8. package/dist/auth/bearer.js.map +1 -1
  9. package/dist/auth/clerk.d.ts +1 -1
  10. package/dist/auth/clerk.js +1 -1
  11. package/dist/call-admission.d.ts +81 -0
  12. package/dist/call-admission.d.ts.map +1 -0
  13. package/dist/call-admission.js +345 -0
  14. package/dist/call-admission.js.map +1 -0
  15. package/dist/catalog-fingerprint.d.ts +20 -0
  16. package/dist/catalog-fingerprint.d.ts.map +1 -0
  17. package/dist/catalog-fingerprint.js +34 -0
  18. package/dist/catalog-fingerprint.js.map +1 -0
  19. package/dist/catalog-limits.d.ts +10 -0
  20. package/dist/catalog-limits.d.ts.map +1 -0
  21. package/dist/catalog-limits.js +10 -0
  22. package/dist/catalog-limits.js.map +1 -0
  23. package/dist/catalog-service.d.ts +138 -0
  24. package/dist/catalog-service.d.ts.map +1 -0
  25. package/dist/catalog-service.js +407 -0
  26. package/dist/catalog-service.js.map +1 -0
  27. package/dist/catalog.js +2 -2
  28. package/dist/catalog.js.map +1 -1
  29. package/dist/concurrency.d.ts +4 -0
  30. package/dist/concurrency.d.ts.map +1 -0
  31. package/dist/concurrency.js +31 -0
  32. package/dist/concurrency.js.map +1 -0
  33. package/dist/connectors/api.d.ts +3 -1
  34. package/dist/connectors/api.d.ts.map +1 -1
  35. package/dist/connectors/api.js +22 -11
  36. package/dist/connectors/api.js.map +1 -1
  37. package/dist/connectors/remote-mcp.d.ts +3 -1
  38. package/dist/connectors/remote-mcp.d.ts.map +1 -1
  39. package/dist/connectors/remote-mcp.js +44 -18
  40. package/dist/connectors/remote-mcp.js.map +1 -1
  41. package/dist/credential-health.d.ts +0 -22
  42. package/dist/credential-health.d.ts.map +1 -1
  43. package/dist/credential-health.js +14 -10
  44. package/dist/credential-health.js.map +1 -1
  45. package/dist/credentials.d.ts +3 -2
  46. package/dist/credentials.d.ts.map +1 -1
  47. package/dist/errors.d.ts +1 -1
  48. package/dist/errors.d.ts.map +1 -1
  49. package/dist/errors.js.map +1 -1
  50. package/dist/execute.d.ts +9 -8
  51. package/dist/execute.d.ts.map +1 -1
  52. package/dist/execute.js +144 -291
  53. package/dist/execute.js.map +1 -1
  54. package/dist/executor-result.d.ts +0 -3
  55. package/dist/executor-result.d.ts.map +1 -1
  56. package/dist/executor-result.js +2 -2
  57. package/dist/executor-result.js.map +1 -1
  58. package/dist/executors/quickjs-child.js +3 -3
  59. package/dist/executors/quickjs-child.js.map +1 -1
  60. package/dist/executors/quickjs-protocol.d.ts +4 -1
  61. package/dist/executors/quickjs-protocol.d.ts.map +1 -1
  62. package/dist/executors/quickjs-runtime.d.ts.map +1 -1
  63. package/dist/executors/quickjs-runtime.js +7 -2
  64. package/dist/executors/quickjs-runtime.js.map +1 -1
  65. package/dist/executors/quickjs.d.ts.map +1 -1
  66. package/dist/executors/quickjs.js +4 -1
  67. package/dist/executors/quickjs.js.map +1 -1
  68. package/dist/favicon.js +2 -2
  69. package/dist/favicon.js.map +1 -1
  70. package/dist/index.d.ts +6 -1
  71. package/dist/index.d.ts.map +1 -1
  72. package/dist/index.js +45 -17
  73. package/dist/index.js.map +1 -1
  74. package/dist/invocation.d.ts +96 -0
  75. package/dist/invocation.d.ts.map +1 -0
  76. package/dist/invocation.js +369 -0
  77. package/dist/invocation.js.map +1 -0
  78. package/dist/meta-tools.d.ts +11 -86
  79. package/dist/meta-tools.d.ts.map +1 -1
  80. package/dist/meta-tools.js +145 -485
  81. package/dist/meta-tools.js.map +1 -1
  82. package/dist/operator-ui/generated.d.ts +3 -0
  83. package/dist/operator-ui/generated.d.ts.map +1 -0
  84. package/dist/operator-ui/generated.js +5 -0
  85. package/dist/operator-ui/generated.js.map +1 -0
  86. package/dist/operator-ui/model.d.ts +94 -0
  87. package/dist/operator-ui/model.d.ts.map +1 -0
  88. package/dist/operator-ui/model.js +28 -0
  89. package/dist/operator-ui/model.js.map +1 -0
  90. package/dist/registry.d.ts +47 -6
  91. package/dist/registry.d.ts.map +1 -1
  92. package/dist/registry.js +356 -35
  93. package/dist/registry.js.map +1 -1
  94. package/dist/routes/activity.d.ts +3 -0
  95. package/dist/routes/activity.d.ts.map +1 -0
  96. package/dist/routes/activity.js +173 -0
  97. package/dist/routes/activity.js.map +1 -0
  98. package/dist/routes/credentials.d.ts +3 -0
  99. package/dist/routes/credentials.d.ts.map +1 -0
  100. package/dist/routes/credentials.js +181 -0
  101. package/dist/routes/credentials.js.map +1 -0
  102. package/dist/routes/mcp.d.ts +8 -0
  103. package/dist/routes/mcp.d.ts.map +1 -0
  104. package/dist/routes/mcp.js +383 -0
  105. package/dist/routes/mcp.js.map +1 -0
  106. package/dist/routes/oauth.d.ts +4 -0
  107. package/dist/routes/oauth.d.ts.map +1 -0
  108. package/dist/routes/oauth.js +268 -0
  109. package/dist/routes/oauth.js.map +1 -0
  110. package/dist/routes/shared.d.ts +97 -0
  111. package/dist/routes/shared.d.ts.map +1 -0
  112. package/dist/routes/shared.js +199 -0
  113. package/dist/routes/shared.js.map +1 -0
  114. package/dist/routes/ui.d.ts +3 -0
  115. package/dist/routes/ui.d.ts.map +1 -0
  116. package/dist/routes/ui.js +122 -0
  117. package/dist/routes/ui.js.map +1 -0
  118. package/dist/server.d.ts +9 -40
  119. package/dist/server.d.ts.map +1 -1
  120. package/dist/server.js +67 -1292
  121. package/dist/server.js.map +1 -1
  122. package/dist/skills.d.ts +0 -15
  123. package/dist/skills.d.ts.map +1 -1
  124. package/dist/skills.js +6 -5
  125. package/dist/skills.js.map +1 -1
  126. package/dist/storage/file.d.ts.map +1 -1
  127. package/dist/storage/file.js +3 -1
  128. package/dist/storage/file.js.map +1 -1
  129. package/dist/storage/memory.d.ts.map +1 -1
  130. package/dist/storage/memory.js +3 -1
  131. package/dist/storage/memory.js.map +1 -1
  132. package/dist/toolkits.d.ts +0 -22
  133. package/dist/toolkits.d.ts.map +1 -1
  134. package/dist/toolkits.js +2 -2
  135. package/dist/toolkits.js.map +1 -1
  136. package/dist/types.d.ts +64 -2
  137. package/dist/types.d.ts.map +1 -1
  138. package/dist/ui.d.ts +3 -93
  139. package/dist/ui.d.ts.map +1 -1
  140. package/dist/ui.js +26 -1389
  141. package/dist/ui.js.map +1 -1
  142. package/dist/version.d.ts +1 -1
  143. package/dist/version.js +1 -1
  144. package/package.json +15 -8
  145. package/src/activity.ts +5 -1
  146. package/src/auth/bearer.ts +4 -4
  147. package/src/auth/clerk.ts +1 -1
  148. package/src/call-admission.ts +522 -0
  149. package/src/catalog-fingerprint.ts +52 -0
  150. package/src/catalog-limits.ts +11 -0
  151. package/src/catalog-service.ts +601 -0
  152. package/src/catalog.ts +2 -2
  153. package/src/concurrency.ts +39 -0
  154. package/src/connectors/api.ts +25 -11
  155. package/src/connectors/remote-mcp.ts +55 -21
  156. package/src/credential-health.ts +13 -10
  157. package/src/credentials.ts +2 -2
  158. package/src/errors.ts +1 -1
  159. package/src/execute.ts +194 -377
  160. package/src/executor-result.ts +2 -2
  161. package/src/executors/quickjs-child.ts +8 -4
  162. package/src/executors/quickjs-protocol.ts +1 -1
  163. package/src/executors/quickjs-runtime.ts +5 -1
  164. package/src/executors/quickjs.ts +11 -8
  165. package/src/favicon.ts +2 -2
  166. package/src/index.ts +54 -17
  167. package/src/invocation.ts +527 -0
  168. package/src/meta-tools.ts +369 -797
  169. package/src/operator-ui/browser.css +413 -0
  170. package/src/operator-ui/browser.ts +1121 -0
  171. package/src/operator-ui/generated.ts +4 -0
  172. package/src/operator-ui/model.ts +127 -0
  173. package/src/registry.ts +489 -44
  174. package/src/routes/activity.ts +220 -0
  175. package/src/routes/credentials.ts +266 -0
  176. package/src/routes/mcp.ts +485 -0
  177. package/src/routes/oauth.ts +328 -0
  178. package/src/routes/shared.ts +330 -0
  179. package/src/routes/ui.ts +153 -0
  180. package/src/server.ts +70 -1702
  181. package/src/skills.ts +6 -5
  182. package/src/storage/file.ts +3 -1
  183. package/src/storage/memory.ts +3 -1
  184. package/src/toolkits.ts +2 -2
  185. package/src/types.ts +70 -2
  186. package/src/ui.ts +52 -1489
  187. package/src/version.ts +1 -1
@@ -9,10 +9,12 @@ 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 {
15
16
  Connector,
17
+ ConnectorCallAdmissionPolicy,
16
18
  ConnectorContext,
17
19
  ConnectorStatus,
18
20
  Logger,
@@ -38,6 +40,8 @@ export interface RemoteMcpOptions {
38
40
  * and is ignored.
39
41
  */
40
42
  maxResultBytes?: number;
43
+ /** Optional per-runtime downstream call-admission policy. */
44
+ callAdmission?: ConnectorCallAdmissionPolicy;
41
45
  /**
42
46
  * Optional agent-facing usage guide (markdown) served by the `skills`
43
47
  * meta-tool as `connector:<id>`. See `Connector.usageGuide`.
@@ -106,18 +110,16 @@ const TERMINATE_SESSION_BUDGET_MS = 1_000;
106
110
  * cap the bytes a caller can be made to hold, not the number of round trips it
107
111
  * took to get them.
108
112
  */
109
- const MAX_TOOLS = 100_000;
110
-
111
113
  /**
112
114
  * Absolute backstop on `tools/list` pages in one refresh — a runaway guard, not
113
115
  * the primary defense.
114
116
  *
115
117
  * The walk terminates on its own well before this: a cursor handed back twice
116
118
  * is a definite loop, two consecutive pages that add no new tools are a server
117
- * going nowhere, and MAX_TOOLS caps what any of it can accumulate. This exists
118
- * only so the loop is finite even if a downstream somehow satisfies all three
119
- * forever on a path with no discovery deadline. Set high enough that no honest
120
- * 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.
121
123
  */
122
124
  const MAX_TOOL_PAGES = 10_000;
123
125
 
@@ -295,7 +297,9 @@ function redirectedInit(init: RequestInit, status: number): RequestInit {
295
297
  if (!becomesGet) return init;
296
298
  const headers = new Headers(init.headers);
297
299
  for (const name of BODY_HEADERS) headers.delete(name);
298
- return { ...init, method: "GET", body: undefined, headers };
300
+ const redirected = { ...init, method: "GET", headers };
301
+ delete redirected.body;
302
+ return redirected;
299
303
  }
300
304
 
301
305
  /**
@@ -543,10 +547,14 @@ export function remoteMcp(id: string, opts: RemoteMcpOptions): Connector {
543
547
  const url = new URL(opts.url);
544
548
  const guardedFetch = redirectSafeFetch(id, opts.redirects);
545
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.
546
554
  return new StreamableHTTPClientTransport(url, {
547
555
  authProvider: provider ?? newProvider(ctx),
548
556
  fetch: guardedFetch,
549
- });
557
+ }) as unknown as Transport;
550
558
  }
551
559
  const headers =
552
560
  opts.auth?.type === "headers" ? opts.auth.headers : undefined;
@@ -556,7 +564,7 @@ export function remoteMcp(id: string, opts: RemoteMcpOptions): Connector {
556
564
  ...(headers ? { requestInit: { headers } } : {}),
557
565
  fetch: guardedFetch,
558
566
  },
559
- );
567
+ ) as unknown as Transport;
560
568
  };
561
569
 
562
570
  const reset = (state: ConnectionState) => {
@@ -739,11 +747,18 @@ export function remoteMcp(id: string, opts: RemoteMcpOptions): Connector {
739
747
 
740
748
  const connector: Connector = {
741
749
  id,
742
- title: opts.title,
750
+ ...(opts.title !== undefined ? { title: opts.title } : {}),
743
751
  kind: "mcp",
744
- description: opts.description,
745
- maxResultBytes: opts.maxResultBytes,
746
- usageGuide: opts.usageGuide,
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 } : {}),
747
762
 
748
763
  // `tools/list` is cursor-paginated: the server chooses the page size and
749
764
  // signals "there is more" with a `nextCursor`, which the SDK's
@@ -826,9 +841,9 @@ export function remoteMcp(id: string, opts: RemoteMcpOptions): Connector {
826
841
  }
827
842
  // Checked here rather than on arrival: this bounds what a *walk* may
828
843
  // accumulate; a one-page server was always free to send its page.
829
- if (listed.length > MAX_TOOLS) {
844
+ if (listed.length > MAX_CATALOG_TOOLS) {
830
845
  throw new Error(
831
- `Connector "${id}" advertised further tools/list pages past ${listed.length} tools, over the ${MAX_TOOLS}-tool ceiling one catalog refresh will collect.`,
846
+ `Connector "${id}" advertised further tools/list pages past ${listed.length} tools, over the ${MAX_CATALOG_TOOLS}-tool ceiling one catalog refresh will collect.`,
832
847
  );
833
848
  }
834
849
  // Opaque by contract: handed straight back, never parsed, rewritten,
@@ -859,10 +874,28 @@ export function remoteMcp(id: string, opts: RemoteMcpOptions): Connector {
859
874
  primeToolMetadata(client, listed);
860
875
  return listed.map((t) => ({
861
876
  name: t.name,
862
- description: t.description,
863
- inputSchema: t.inputSchema as ToolDef["inputSchema"],
864
- outputSchema: t.outputSchema as ToolDef["outputSchema"],
865
- annotations: t.annotations as ToolDef["annotations"],
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
+ : {}),
866
899
  }));
867
900
  },
868
901
 
@@ -938,7 +971,7 @@ export function remoteMcp(id: string, opts: RemoteMcpOptions): Connector {
938
971
  const url = await getProvider(ctx, state).pendingAuthorizationUrl();
939
972
  return {
940
973
  state: "auth_required",
941
- authorizationUrl: url,
974
+ ...(url !== undefined ? { authorizationUrl: url } : {}),
942
975
  message: "Authorization required — open the URL to connect.",
943
976
  };
944
977
  }
@@ -1009,9 +1042,10 @@ export function remoteMcp(id: string, opts: RemoteMcpOptions): Connector {
1009
1042
  };
1010
1043
  } catch (err) {
1011
1044
  if (state.authRequired) {
1045
+ const authorizationUrl = await p.pendingAuthorizationUrl();
1012
1046
  return {
1013
1047
  state: "auth_required",
1014
- authorizationUrl: await p.pendingAuthorizationUrl(),
1048
+ ...(authorizationUrl !== undefined ? { authorizationUrl } : {}),
1015
1049
  message: "Authorization required — open the URL to connect.",
1016
1050
  };
1017
1051
  }
@@ -117,8 +117,8 @@ export interface CredentialHealthConfig {
117
117
  onRequest?: boolean;
118
118
  }
119
119
 
120
- export const DEFAULT_CREDENTIAL_CHECK_INTERVAL_SECONDS = 900;
121
- export const DEFAULT_CREDENTIAL_CHECK_CONCURRENCY = 4;
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
- export function isCheckableConnector(connector: Connector): boolean {
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
- if (mode === "single" && typeof storedValues.value === "string") {
412
- return (ctx) => connector.testCredential!(storedValues.value, ctx);
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 = new Array<R>(items.length);
424
- let next = 0;
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
- while (next < items.length) {
429
- const index = next++;
430
- out[index] = await fn(items[index]);
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
  );
@@ -24,7 +24,7 @@ interface CredentialPlaintext {
24
24
  updatedBy: string;
25
25
  }
26
26
 
27
- export interface CredentialFieldMetadata {
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
- export type CredentialTestMode = "single" | "multiple";
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?: number;
52
+ readonly retryAfterMs: number | undefined;
53
53
 
54
54
  constructor(
55
55
  code: ConnectorCallErrorCode,