@mastra/connect 0.7.0-alpha.1 → 1.0.0-alpha.4

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 (83) hide show
  1. package/README.md +47 -42
  2. package/dist/channels.d.ts +40 -22
  3. package/dist/channels.d.ts.map +1 -1
  4. package/dist/client.d.ts +21 -0
  5. package/dist/client.d.ts.map +1 -1
  6. package/dist/errors.d.ts +23 -0
  7. package/dist/errors.d.ts.map +1 -1
  8. package/dist/index.cjs +821 -465
  9. package/dist/index.cjs.map +1 -1
  10. package/dist/index.d.ts +4 -10
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +822 -458
  13. package/dist/index.js.map +1 -1
  14. package/dist/instrumentation.d.ts +48 -0
  15. package/dist/instrumentation.d.ts.map +1 -0
  16. package/dist/multi-connection.d.ts +1 -1
  17. package/dist/multi-connection.d.ts.map +1 -1
  18. package/dist/providers/channels.d.ts +5 -1
  19. package/dist/providers/channels.d.ts.map +1 -1
  20. package/dist/providers/clerk/tools/create-organization-domain.d.ts +9 -9
  21. package/dist/providers/clerk/tools/create-organization-domain.d.ts.map +1 -1
  22. package/dist/providers/clerk/tools/create-organization-invitation.d.ts +3 -3
  23. package/dist/providers/clerk/tools/create-user.d.ts.map +1 -1
  24. package/dist/providers/clerk/tools/delete-email-address.d.ts.map +1 -1
  25. package/dist/providers/clerk/tools/delete-organization-domain.d.ts.map +1 -1
  26. package/dist/providers/clerk/tools/delete-organization-membership.d.ts.map +1 -1
  27. package/dist/providers/clerk/tools/delete-organization-role.d.ts.map +1 -1
  28. package/dist/providers/clerk/tools/delete-phone-number.d.ts.map +1 -1
  29. package/dist/providers/clerk/tools/get-email-address.d.ts.map +1 -1
  30. package/dist/providers/clerk/tools/get-organization-invitation.d.ts +3 -3
  31. package/dist/providers/clerk/tools/get-organization-role.d.ts.map +1 -1
  32. package/dist/providers/clerk/tools/get-phone-number.d.ts.map +1 -1
  33. package/dist/providers/clerk/tools/get-session.d.ts +3 -3
  34. package/dist/providers/clerk/tools/get-session.d.ts.map +1 -1
  35. package/dist/providers/clerk/tools/list-organization-domains.d.ts +9 -9
  36. package/dist/providers/clerk/tools/list-organization-domains.d.ts.map +1 -1
  37. package/dist/providers/clerk/tools/list-organization-invitations.d.ts +3 -3
  38. package/dist/providers/clerk/tools/list-organization-invitations.d.ts.map +1 -1
  39. package/dist/providers/clerk/tools/list-organization-memberships.d.ts.map +1 -1
  40. package/dist/providers/clerk/tools/list-organization-roles.d.ts.map +1 -1
  41. package/dist/providers/clerk/tools/list-organizations.d.ts.map +1 -1
  42. package/dist/providers/clerk/tools/list-sessions.d.ts +3 -5
  43. package/dist/providers/clerk/tools/list-sessions.d.ts.map +1 -1
  44. package/dist/providers/clerk/tools/list-users.d.ts +12 -0
  45. package/dist/providers/clerk/tools/list-users.d.ts.map +1 -1
  46. package/dist/providers/clerk/tools/revoke-organization-invitation.d.ts +3 -3
  47. package/dist/providers/clerk/tools/revoke-session.d.ts +3 -3
  48. package/dist/providers/clerk/tools/revoke-session.d.ts.map +1 -1
  49. package/dist/providers/clerk/tools/update-organization-domain.d.ts +9 -9
  50. package/dist/providers/clerk/tools/update-organization-domain.d.ts.map +1 -1
  51. package/dist/providers/clerk/tools/update-organization-role.d.ts.map +1 -1
  52. package/dist/providers/clerk/tools/update-organization.d.ts +2 -0
  53. package/dist/providers/clerk/tools/update-organization.d.ts.map +1 -1
  54. package/dist/providers/clerk/tools/update-user.d.ts +10 -10
  55. package/dist/providers/clerk/tools/verify-organization-domain.d.ts +12 -7
  56. package/dist/providers/clerk/tools/verify-organization-domain.d.ts.map +1 -1
  57. package/dist/providers/discord/tools/list-channels.d.ts +2 -2
  58. package/dist/providers/discord/tools/list-channels.d.ts.map +1 -1
  59. package/dist/providers/jira/tools/get-create-issue-metadata.d.ts +42 -0
  60. package/dist/providers/jira/tools/get-create-issue-metadata.d.ts.map +1 -1
  61. package/dist/providers/jira/tools/list-issue-types.d.ts +6 -2
  62. package/dist/providers/jira/tools/list-issue-types.d.ts.map +1 -1
  63. package/dist/providers/resend/tools/cancel-email.d.ts +2 -2
  64. package/dist/providers/resend/tools/get-email.d.ts +2 -2
  65. package/dist/providers/resend/tools/get-received-email.d.ts +2 -2
  66. package/dist/providers/resend/tools/get-template.d.ts +2 -2
  67. package/dist/providers/resend/tools/list-emails.d.ts +2 -2
  68. package/dist/providers/resend/tools/list-received-emails.d.ts +2 -2
  69. package/dist/providers/resend/tools/update-contact-topics.d.ts.map +1 -1
  70. package/dist/registry.d.ts +1 -8
  71. package/dist/registry.d.ts.map +1 -1
  72. package/dist/resolution.d.ts +3 -11
  73. package/dist/resolution.d.ts.map +1 -1
  74. package/dist/runtime/platform-proxy.d.ts.map +1 -1
  75. package/dist/tools.d.ts +94 -33
  76. package/dist/tools.d.ts.map +1 -1
  77. package/dist/toolset.d.ts +39 -13
  78. package/dist/toolset.d.ts.map +1 -1
  79. package/package.json +12 -8
  80. package/dist/connect.d.ts +0 -22
  81. package/dist/connect.d.ts.map +0 -1
  82. package/dist/environment.d.ts +0 -48
  83. package/dist/environment.d.ts.map +0 -1
package/dist/index.cjs CHANGED
@@ -1,6 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  let _mastra_mcp = require("@mastra/mcp");
3
3
  let zod = require("zod");
4
+ let _mastra_core_observability = require("@mastra/core/observability");
4
5
  let _mastra_core_tools = require("@mastra/core/tools");
5
6
  //#region src/errors.ts
6
7
  const MAX_DETAIL_LENGTH = 2e3;
@@ -8,18 +9,56 @@ var MastraConnectError = class extends Error {
8
9
  code;
9
10
  status;
10
11
  detail;
12
+ /**
13
+ * Axios-compatible alias for {@link status}. Generated provider tools come
14
+ * from upstream Nango templates whose error handlers check
15
+ * `error.response.status` (the axios/Nango SDK shape). Exposing the HTTP
16
+ * status under `response.status` as well lets that generated code work
17
+ * unchanged against the errors this package throws. Only set when the error
18
+ * carries an HTTP status.
19
+ */
20
+ response;
11
21
  constructor(code, message, options) {
12
22
  super(message);
13
23
  this.name = "MastraConnectError";
14
24
  this.code = code;
15
25
  this.status = options?.status;
16
26
  this.detail = options?.detail ? truncate(options.detail) : void 0;
27
+ if (typeof options?.status === "number") this.response = { status: options.status };
28
+ }
29
+ };
30
+ /**
31
+ * A caller configuration mistake (for example an unknown tool name in
32
+ * `requireApproval`) that must fail resolution instead of being downgraded
33
+ * to the resolver's warn-and-skip path, which exists for provider-side
34
+ * failures. Internal to the package: callers observe it as a regular
35
+ * `MastraConnectError` with code `invalid_options`.
36
+ *
37
+ * @internal
38
+ */
39
+ var MastraConnectConfigError = class extends MastraConnectError {
40
+ constructor(message) {
41
+ super("invalid_options", message);
17
42
  }
18
43
  };
19
44
  function truncate(text) {
20
45
  return text.length > MAX_DETAIL_LENGTH ? `${text.slice(0, MAX_DETAIL_LENGTH)}…` : text;
21
46
  }
22
47
  /**
48
+ * Pulls the first human-readable message from an array of error entries. Many
49
+ * providers (Clerk, Linear's GraphQL envelope, Nango v2) return
50
+ * `{ errors: [{ message, long_message, code }] }`; surfacing the first message
51
+ * is the most useful detail without echoing the whole payload.
52
+ */
53
+ function extractFirstArrayMessage(errors) {
54
+ for (const entry of errors) {
55
+ if (!entry || typeof entry !== "object") continue;
56
+ const record = entry;
57
+ const message = typeof record.long_message === "string" ? record.long_message : record.message;
58
+ if (typeof message === "string" && message) return message;
59
+ }
60
+ }
61
+ /**
23
62
  * Extracts a human-readable detail string from an RFC-7807 problem JSON body
24
63
  * (or a plain `{ error }` body) without echoing anything else from the response.
25
64
  * Returns undefined when the body is not parseable JSON.
@@ -50,6 +89,14 @@ async function extractProblemDetail(response) {
50
89
  };
51
90
  }
52
91
  }
92
+ if (Array.isArray(data.errors)) {
93
+ const message = extractFirstArrayMessage(data.errors);
94
+ if (message) return {
95
+ detail: truncate(message),
96
+ code,
97
+ isProblemJson
98
+ };
99
+ }
53
100
  return {
54
101
  code,
55
102
  isProblemJson
@@ -59,6 +106,98 @@ async function extractProblemDetail(response) {
59
106
  return { isProblemJson };
60
107
  }
61
108
  //#endregion
109
+ //#region src/instrumentation.ts
110
+ const ID_SEGMENT_ROUTES = [{
111
+ prefix: "/v2/connections/",
112
+ placeholder: "{connectionId}",
113
+ key: "connectionId"
114
+ }, {
115
+ prefix: "/v2/projects/",
116
+ placeholder: "{projectId}",
117
+ key: "projectId"
118
+ }];
119
+ const PROXY_SEGMENT = "/proxy/";
120
+ /** Describes a platform request for span naming without leaking query params, ids, or vendor path segments. */
121
+ function describePlatformCall(method, rawPath) {
122
+ const path = rawPath.split("?")[0];
123
+ let route = path;
124
+ const descriptor = {
125
+ method,
126
+ route,
127
+ isProxy: false
128
+ };
129
+ for (const idRoute of ID_SEGMENT_ROUTES) {
130
+ if (!path.startsWith(idRoute.prefix)) continue;
131
+ const rest = path.slice(idRoute.prefix.length);
132
+ const slash = rest.indexOf("/");
133
+ const id = slash === -1 ? rest : rest.slice(0, slash);
134
+ const tail = slash === -1 ? "" : rest.slice(slash);
135
+ descriptor[idRoute.key] = safeDecode(id);
136
+ route = `${idRoute.prefix}${idRoute.placeholder}${tail}`;
137
+ break;
138
+ }
139
+ const proxyIndex = route.indexOf(PROXY_SEGMENT);
140
+ if (proxyIndex !== -1) {
141
+ descriptor.isProxy = true;
142
+ route = `${route.slice(0, proxyIndex + 7)}*`;
143
+ }
144
+ descriptor.route = route;
145
+ return descriptor;
146
+ }
147
+ function safeDecode(segment) {
148
+ try {
149
+ return decodeURIComponent(segment);
150
+ } catch {
151
+ return segment;
152
+ }
153
+ }
154
+ /**
155
+ * Starts a GENERIC child span for an outbound connect HTTP call, or returns
156
+ * `undefined` when no ambient span is active. Span creation failures are
157
+ * swallowed: instrumentation must never break a request.
158
+ */
159
+ function startPlatformCallSpan(descriptor) {
160
+ let parent;
161
+ try {
162
+ parent = (0, _mastra_core_observability.resolveCurrentSpan)();
163
+ if (!parent) return void 0;
164
+ return parent.createChildSpan({
165
+ type: _mastra_core_observability.SpanType.GENERIC,
166
+ name: `connect.${descriptor.isProxy ? "proxy" : "platform"} ${descriptor.method} ${descriptor.route}`,
167
+ metadata: {
168
+ method: descriptor.method,
169
+ route: descriptor.route,
170
+ ...descriptor.connectionId ? { connectionId: descriptor.connectionId } : {},
171
+ ...descriptor.projectId ? { projectId: descriptor.projectId } : {}
172
+ }
173
+ });
174
+ } catch {
175
+ return;
176
+ }
177
+ }
178
+ /** Ends a platform-call span with the response status. Never throws. */
179
+ function endPlatformCallSpan(span, status) {
180
+ if (!span) return;
181
+ try {
182
+ span.end({ metadata: { status } });
183
+ } catch {}
184
+ }
185
+ /**
186
+ * Records a transport-level failure on a platform-call span. Nothing from the
187
+ * original error is recorded — fetch failures can embed the request URL in
188
+ * both `message` and `name`, which may carry secret query params — so the
189
+ * span gets a fixed, constant error. Never throws.
190
+ */
191
+ function errorPlatformCallSpan(span, _error) {
192
+ if (!span) return;
193
+ try {
194
+ span.error({
195
+ error: /* @__PURE__ */ new Error("connect request failed"),
196
+ endSpan: true
197
+ });
198
+ } catch {}
199
+ }
200
+ //#endregion
62
201
  //#region src/client.ts
63
202
  const DEFAULT_INTEGRATIONS_URL = "https://integrations.mastra.ai";
64
203
  const REGIONAL_INTEGRATIONS_URLS = {
@@ -101,20 +240,25 @@ function redact(message, accessToken) {
101
240
  return message.split(accessToken).join("[REDACTED]");
102
241
  }
103
242
  async function platformFetch(client, path, init) {
243
+ const span = startPlatformCallSpan(describePlatformCall(init?.method ?? "GET", path));
104
244
  try {
105
- return await client.fetch(`${client.baseUrl}${path}`, {
245
+ const response = await client.fetch(`${client.baseUrl}${path}`, {
106
246
  ...init,
107
247
  headers: {
108
248
  ...client.headers,
109
249
  ...init?.headers
110
250
  }
111
251
  });
252
+ endPlatformCallSpan(span, response.status);
253
+ return response;
112
254
  } catch (error) {
113
255
  if (error instanceof Error && error.message.includes(client.accessToken)) {
114
256
  const redacted = new Error(redact(error.message, client.accessToken));
115
257
  redacted.name = error.name;
258
+ errorPlatformCallSpan(span, redacted);
116
259
  throw redacted;
117
260
  }
261
+ errorPlatformCallSpan(span, error);
118
262
  throw error;
119
263
  }
120
264
  }
@@ -189,14 +333,35 @@ const integrationCatalogEntrySchema = zod.z.object({
189
333
  capabilities: zod.z.object({ mcp: zod.z.boolean().optional() })
190
334
  });
191
335
  const integrationCatalogResponseSchema = zod.z.object({ integrations: zod.z.array(integrationCatalogEntrySchema) });
192
- const credentialSchema = zod.z.discriminatedUnion("type", [zod.z.object({
193
- type: zod.z.literal("oauth2"),
336
+ /**
337
+ * Secondary access token minted by the vendor alongside the primary oauth2
338
+ * credential (e.g. `devPortalAccessToken` on Microsoft Teams connections).
339
+ * Keyed by the vendor's connection-config field name. Treat this like any
340
+ * other bearer credential — it authenticates second-audience API calls
341
+ * (Teams Dev Portal, etc.) and must not be logged or forwarded to code that
342
+ * shouldn't hold connection secrets.
343
+ */
344
+ const secondaryAccessTokenSchema = zod.z.object({
194
345
  accessToken: zod.z.string(),
195
346
  expiresAt: zod.z.string().nullable()
196
- }), zod.z.object({
197
- type: zod.z.literal("api_key"),
198
- apiKey: zod.z.string()
199
- })]);
347
+ });
348
+ const credentialSchema = zod.z.discriminatedUnion("type", [
349
+ zod.z.object({
350
+ type: zod.z.literal("oauth2"),
351
+ accessToken: zod.z.string(),
352
+ expiresAt: zod.z.string().nullable(),
353
+ secondaryAccessTokens: zod.z.record(zod.z.string(), secondaryAccessTokenSchema).optional()
354
+ }),
355
+ zod.z.object({
356
+ type: zod.z.literal("api_key"),
357
+ apiKey: zod.z.string()
358
+ }),
359
+ zod.z.object({
360
+ type: zod.z.literal("two_step"),
361
+ token: zod.z.string(),
362
+ expiresAt: zod.z.string().nullable()
363
+ })
364
+ ]);
200
365
  const connectionContextSchema = zod.z.object({
201
366
  connection_config: zod.z.record(zod.z.string(), zod.z.unknown()).nullable(),
202
367
  metadata: zod.z.record(zod.z.string(), zod.z.unknown()).nullable()
@@ -272,9 +437,6 @@ function assertValidBaseUrlOverride(baseUrlOverride) {
272
437
  if (parsed.protocol !== "https:") throw new MastraConnectError("invalid_options", `Invalid baseUrlOverride '${baseUrlOverride}': only https:// URLs are allowed.`);
273
438
  if (parsed.username || parsed.password) throw new MastraConnectError("invalid_options", `Invalid baseUrlOverride '${baseUrlOverride}': embedded credentials are not allowed.`);
274
439
  }
275
- async function proxyRequest(client, connectionId, options) {
276
- return (await proxyRequestWithResponse(client, connectionId, options)).data;
277
- }
278
440
  /** Preserves HTTP metadata for tools with status-dependent provider contracts. */
279
441
  async function proxyRequestWithResponse(client, connectionId, options) {
280
442
  const cleanPath = options.path.replace(/^\/+/, "");
@@ -287,7 +449,12 @@ async function proxyRequestWithResponse(client, connectionId, options) {
287
449
  }
288
450
  const queryString = search.size > 0 ? `?${search.toString()}` : "";
289
451
  const url = `/v2/connections/${encodeURIComponent(connectionId)}/proxy/${cleanPath}${queryString}`;
290
- const headers = { ...options.headers };
452
+ const headers = {};
453
+ for (const [name, value] of Object.entries(options.headers ?? {})) {
454
+ const lower = name.toLowerCase();
455
+ if (lower === "authorization" || lower === "proxy-authorization") continue;
456
+ headers[name] = value;
457
+ }
291
458
  if (options.baseUrlOverride !== void 0) {
292
459
  assertValidBaseUrlOverride(options.baseUrlOverride);
293
460
  headers["base-url-override"] = options.baseUrlOverride;
@@ -356,37 +523,64 @@ async function proxyRequestWithResponse(client, connectionId, options) {
356
523
  }
357
524
  //#endregion
358
525
  //#region src/toolset.ts
359
- /** Resolves a connection id lazily at execute time: option → env var → typed error naming the env var. */
360
- function resolveConnectionId(envVar, connectionId) {
361
- const resolved = connectionId?.trim() || process.env[envVar]?.trim();
362
- if (!resolved) throw new MastraConnectError("missing_connection_id", `Missing connection id: set ${envVar} or pass connectionId.`);
363
- return resolved;
526
+ /**
527
+ * Compiles a tool-filter entry containing `*` wildcards into an anchored
528
+ * regex; every other character matches literally.
529
+ */
530
+ function compileToolPattern(pattern) {
531
+ const escaped = pattern.split("*").map((part) => part.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join(".*");
532
+ return new RegExp(`^${escaped}$`);
364
533
  }
365
534
  /**
366
- * Wraps `createTool` so the tool executes through the platform connection
367
- * proxy. Connection id and client config resolve lazily inside execute, so
368
- * building tools without env vars set never throws.
535
+ * Returns a predicate testing tool keys against filter `entries`, where an
536
+ * entry containing `*` is a glob and anything else matches literally. Used
537
+ * where keys are only known later (MCP approval predicates); list-shaped
538
+ * call sites expand eagerly with {@link expandToolPatterns} instead.
369
539
  */
370
- function defineProxyTool(context, config) {
371
- return (0, _mastra_core_tools.createTool)({
372
- id: config.id,
373
- description: config.description,
374
- inputSchema: config.inputSchema,
375
- outputSchema: config.outputSchema,
376
- execute: async (input) => {
377
- const connectionId = resolveConnectionId(context.envVar, context.options?.connectionId);
378
- const raw = await proxyRequest(resolveClient(context.options?.client), connectionId, config.request(input));
379
- return config.transform(raw, input);
540
+ function compileToolMatcher(entries) {
541
+ const literals = /* @__PURE__ */ new Set();
542
+ const patterns = [];
543
+ for (const entry of entries) if (entry.includes("*")) patterns.push(compileToolPattern(entry));
544
+ else literals.add(entry);
545
+ return (toolKey) => literals.has(toolKey) || patterns.some((pattern) => pattern.test(toolKey));
546
+ }
547
+ /**
548
+ * Expands `*` glob entries against the known tool keys, preserving order and
549
+ * de-duplicating. Literal entries pass through untouched (callers validate
550
+ * those against their own key sets). A glob that matches nothing throws:
551
+ * like an unknown literal name, a dead pattern in access-limiting config is
552
+ * a typo that must surface instead of silently filtering nothing.
553
+ */
554
+ function expandToolPatterns(entries, knownKeys, label) {
555
+ const expanded = [];
556
+ const seen = /* @__PURE__ */ new Set();
557
+ const push = (key) => {
558
+ if (seen.has(key)) return;
559
+ seen.add(key);
560
+ expanded.push(key);
561
+ };
562
+ for (const entry of entries) {
563
+ if (!entry.includes("*")) {
564
+ push(entry);
565
+ continue;
380
566
  }
381
- });
567
+ const pattern = compileToolPattern(entry);
568
+ const matches = knownKeys.filter((key) => pattern.test(key));
569
+ if (matches.length === 0) throw new MastraConnectConfigError(`Pattern '${entry}' in ${label} matched no tools. Known tools: ${knownKeys.join(", ")}.`);
570
+ for (const match of matches) push(match);
571
+ }
572
+ return expanded;
382
573
  }
383
574
  /**
384
- * Filters a toolset by tool key. Throws at build time on unknown names so
385
- * typos in access-limiting config surface immediately.
575
+ * Filters a toolset by tool key. Entries containing `*` are globs expanded
576
+ * against the toolset's keys. Throws at build time on unknown names and on
577
+ * globs that match nothing, so typos in access-limiting config surface
578
+ * immediately.
386
579
  */
387
- function applyAllowTools(tools, allowTools) {
388
- if (!allowTools) return tools;
580
+ function applyAllowTools(tools, allowToolsInput) {
581
+ if (!allowToolsInput) return tools;
389
582
  const known = Object.keys(tools);
583
+ const allowTools = expandToolPatterns(allowToolsInput, known, "allowTools");
390
584
  const unknown = allowTools.filter((name) => !known.includes(name));
391
585
  if (unknown.length > 0) throw new Error(`Unknown tool name(s) in allowTools: ${unknown.join(", ")}. Known tools: ${known.join(", ")}.`);
392
586
  const filtered = {};
@@ -394,13 +588,15 @@ function applyAllowTools(tools, allowTools) {
394
588
  return filtered;
395
589
  }
396
590
  /**
397
- * Removes tool keys from a toolset. Throws at build time on unknown names so
398
- * typos in access-limiting config surface immediately instead of silently
399
- * removing nothing.
591
+ * Removes tool keys from a toolset. Entries containing `*` are globs
592
+ * expanded against the toolset's keys. Throws at build time on unknown names
593
+ * and on globs that match nothing, so typos in access-limiting config
594
+ * surface immediately instead of silently removing nothing.
400
595
  */
401
- function applyDisallowTools(tools, disallowTools) {
402
- if (!disallowTools || disallowTools.length === 0) return tools;
596
+ function applyDisallowTools(tools, disallowToolsInput) {
597
+ if (!disallowToolsInput || disallowToolsInput.length === 0) return tools;
403
598
  const known = Object.keys(tools);
599
+ const disallowTools = expandToolPatterns(disallowToolsInput, known, "disallowTools");
404
600
  const unknown = disallowTools.filter((name) => !known.includes(name));
405
601
  if (unknown.length > 0) throw new Error(`Unknown tool name(s) in disallowTools: ${unknown.join(", ")}. Known tools: ${known.join(", ")}.`);
406
602
  const remove = new Set(disallowTools);
@@ -637,8 +833,8 @@ function buildProxyMultiConnectionTools(input) {
637
833
  * client cache so stale clients can be reaped elsewhere.
638
834
  */
639
835
  async function buildMcpMultiConnectionTools(input) {
640
- const { registration, connections, allowTools, disallowTools, autoApproveTools, client, mcpClients, resolverId } = input;
641
- const autoApproved = new Set(autoApproveTools ?? []);
836
+ const { registration, connections, allowTools, disallowTools, requireApproval, client, mcpClients, resolverId } = input;
837
+ const requireApprovalFor = Array.isArray(requireApproval) ? compileToolMatcher(requireApproval) : void 0;
642
838
  const listToolKey = listConnectionsToolKey(registration.integrationId);
643
839
  const innerAllowTools = allowTools?.filter((name) => name !== listToolKey);
644
840
  const innerDisallowTools = disallowTools?.filter((name) => name !== listToolKey);
@@ -662,7 +858,7 @@ async function buildMcpMultiConnectionTools(input) {
662
858
  id: `mastra-connect-${resolverId}-${registration.integrationId}-${connection.id}`,
663
859
  servers: { [registration.integrationId]: {
664
860
  ...transport,
665
- requireToolApproval: ({ toolName }) => !autoApproved.has(`${registration.integrationId}_${String(toolName)}`)
861
+ ...requireApproval === true ? { requireToolApproval: true } : requireApprovalFor ? { requireToolApproval: ({ toolName }) => requireApprovalFor(`${registration.integrationId}_${String(toolName)}`) } : {}
666
862
  } }
667
863
  })
668
864
  };
@@ -679,8 +875,10 @@ async function buildMcpMultiConnectionTools(input) {
679
875
  }
680
876
  const catalogUnion = /* @__PURE__ */ new Set();
681
877
  for (const catalog of rawInnerCatalogs.values()) for (const key of Object.keys(catalog)) catalogUnion.add(key);
682
- const unknownAutoApprove = [...autoApproved].filter((name) => !catalogUnion.has(name));
683
- if (unknownAutoApprove.length > 0) throw new MastraConnectError("invalid_options", `Unknown tool name(s) in autoApproveTools for '${registration.integrationId}': ${unknownAutoApprove.join(", ")}. Known tools: ${[...catalogUnion].join(", ")}.`);
878
+ if (Array.isArray(requireApproval)) {
879
+ const unknown = expandToolPatterns(requireApproval, [...catalogUnion], `requireApproval for '${registration.integrationId}'`).filter((name) => !catalogUnion.has(name));
880
+ if (unknown.length > 0) throw new MastraConnectConfigError(`Unknown tool name(s) in requireApproval for '${registration.integrationId}': ${unknown.join(", ")}. Known tools: ${[...catalogUnion].join(", ")}.`);
881
+ }
684
882
  innerToolsByConnectionId = /* @__PURE__ */ new Map();
685
883
  for (const [connectionId, catalog] of rawInnerCatalogs) {
686
884
  const filtered = applyToolFilter(catalog, {
@@ -708,11 +906,15 @@ async function buildMcpMultiConnectionTools(input) {
708
906
  }
709
907
  //#endregion
710
908
  //#region src/providers/channels.ts
711
- function credentialToken$1(credential) {
712
- return credential.type === "oauth2" ? credential.accessToken : credential.apiKey;
909
+ function credentialToken(credential) {
910
+ switch (credential.type) {
911
+ case "oauth2": return credential.accessToken;
912
+ case "two_step": return credential.token;
913
+ default: return credential.apiKey;
914
+ }
713
915
  }
714
916
  const RESERVED_OPTION_KEYS = {
715
- slack: [
917
+ "slack-channels": [
716
918
  "baseUrl",
717
919
  "refreshToken",
718
920
  "token",
@@ -726,7 +928,14 @@ const RESERVED_OPTION_KEYS = {
726
928
  "tokenResolver",
727
929
  "encryptionKey"
728
930
  ],
729
- discord: ["baseUrl", "encryptionKey"]
931
+ discord: ["baseUrl", "encryptionKey"],
932
+ "microsoft-teams": [
933
+ "baseUrl",
934
+ "appId",
935
+ "appPassword",
936
+ "tokenResolver",
937
+ "encryptionKey"
938
+ ]
730
939
  };
731
940
  function stripReservedOptions(integrationId, options) {
732
941
  if (!options) return options;
@@ -746,12 +955,12 @@ function stripReservedOptions(integrationId, options) {
746
955
  }
747
956
  const CHANNELS$1 = [
748
957
  {
749
- integrationId: "slack",
958
+ integrationId: "slack-channels",
750
959
  async create(options, runtime) {
751
960
  const mod = await import("@mastra/slack");
752
- const safeOptions = stripReservedOptions("slack", options);
961
+ const safeOptions = stripReservedOptions("slack-channels", options);
753
962
  const tokenResolver = async () => {
754
- return credentialToken$1(await runtime.getCredential());
963
+ return credentialToken(await runtime.getCredential());
755
964
  };
756
965
  return { provider: new mod.SlackProvider({
757
966
  tokenResolver,
@@ -765,7 +974,7 @@ const CHANNELS$1 = [
765
974
  const mod = await import("@mastra/telegram");
766
975
  const safeOptions = stripReservedOptions("telegram", options);
767
976
  const tokenResolver = async () => {
768
- return credentialToken$1(await runtime.getCredential());
977
+ return credentialToken(await runtime.getCredential());
769
978
  };
770
979
  return { provider: new mod.TelegramProvider({
771
980
  tokenResolver,
@@ -797,17 +1006,42 @@ const CHANNELS$1 = [
797
1006
  }
798
1007
  };
799
1008
  }
1009
+ },
1010
+ {
1011
+ integrationId: "microsoft-teams",
1012
+ async create(options, runtime) {
1013
+ const mod = await import("@mastra/teams");
1014
+ if (!process.env.MASTRA_ENCRYPTION_KEY) throw new MastraConnectError("invalid_options", "Microsoft Teams channel: MASTRA_ENCRYPTION_KEY is not set. The Teams install store persists per-agent bot secrets and requires an at-rest encryption key (a 32-byte value, base64-encoded).");
1015
+ const safeOptions = stripReservedOptions("microsoft-teams", options);
1016
+ const tokenResolver = async (scope) => {
1017
+ const fresh = await runtime.getCredential();
1018
+ if (!(Array.isArray(scope) ? scope : [scope]).includes(mod.TEAMS_DEV_PORTAL_SCOPE)) return credentialToken(fresh);
1019
+ const token = fresh.type === "oauth2" ? fresh.secondaryAccessTokens?.devPortalAccessToken?.accessToken : void 0;
1020
+ if (!token) throw new MastraConnectError("no_active_connection", `Teams connection ${runtime.getConnectionId()} has no Dev Portal token on its credential. Reconnect with an integration that requests the ${mod.TEAMS_DEV_PORTAL_SCOPE} scope.`);
1021
+ return token;
1022
+ };
1023
+ return { provider: new mod.TeamsProvider({
1024
+ tokenResolver,
1025
+ ...safeOptions ?? {}
1026
+ }) };
1027
+ }
800
1028
  }
801
1029
  ];
802
1030
  //#endregion
803
1031
  //#region src/runtime/platform-proxy.ts
804
1032
  /** Maps the platform credential to the field names templates are written against. */
805
1033
  function toTemplateCredentials(credential) {
806
- return credential.type === "oauth2" ? {
1034
+ if (credential.type === "oauth2") return {
807
1035
  type: "OAUTH2",
808
1036
  access_token: credential.accessToken,
809
1037
  expires_at: credential.expiresAt
810
- } : {
1038
+ };
1039
+ if (credential.type === "two_step") return {
1040
+ type: "TWO_STEP",
1041
+ token: credential.token,
1042
+ expires_at: credential.expiresAt
1043
+ };
1044
+ return {
811
1045
  type: "API_KEY",
812
1046
  apiKey: credential.apiKey
813
1047
  };
@@ -1735,8 +1969,8 @@ const anthropicProvider = {
1735
1969
  //#endregion
1736
1970
  //#region src/providers/clerk/tools/assign-organization-role-permission.ts
1737
1971
  const assignOrganizationRolePermissionInputSchema = zod.z.object({
1738
- organization_role_id: zod.z.string(),
1739
- permission_id: zod.z.string()
1972
+ organization_role_id: zod.z.string().min(1),
1973
+ permission_id: zod.z.string().min(1)
1740
1974
  });
1741
1975
  const ResourceSchema$49 = zod.z.object({
1742
1976
  id: zod.z.string(),
@@ -1772,8 +2006,8 @@ function assignOrganizationRolePermissionTool(proxy) {
1772
2006
  //#endregion
1773
2007
  //#region src/providers/clerk/tools/create-email-address.ts
1774
2008
  const createEmailAddressInputSchema = zod.z.object({
1775
- user_id: zod.z.string(),
1776
- email_address: zod.z.string(),
2009
+ user_id: zod.z.string().min(1),
2010
+ email_address: zod.z.string().email(),
1777
2011
  verified: zod.z.boolean().optional(),
1778
2012
  primary: zod.z.boolean().optional(),
1779
2013
  notify_primary_email_address_changed: zod.z.boolean().optional()
@@ -1818,16 +2052,22 @@ function createEmailAddressTool(proxy) {
1818
2052
  }
1819
2053
  //#endregion
1820
2054
  //#region src/providers/clerk/tools/create-organization-domain.ts
1821
- const EnrollmentModeSchema$2 = zod.z.enum([
2055
+ const EnrollmentModeSchema$3 = zod.z.enum([
1822
2056
  "manual_invitation",
1823
2057
  "automatic_invitation",
1824
2058
  "automatic_suggestion",
1825
2059
  "enterprise_sso"
1826
2060
  ]);
2061
+ const EnrollmentModeSchemaWidened$2 = zod.z.enum([
2062
+ "manual_invitation",
2063
+ "automatic_invitation",
2064
+ "automatic_suggestion",
2065
+ "enterprise_sso"
2066
+ ]).or(zod.z.string());
1827
2067
  const createOrganizationDomainInputSchema$1 = zod.z.object({
1828
- organization_id: zod.z.string(),
2068
+ organization_id: zod.z.string().min(1),
1829
2069
  name: zod.z.string(),
1830
- enrollment_mode: EnrollmentModeSchema$2,
2070
+ enrollment_mode: EnrollmentModeSchema$3,
1831
2071
  verified: zod.z.boolean().optional()
1832
2072
  });
1833
2073
  const ResourceSchema$47 = zod.z.object({
@@ -1835,15 +2075,15 @@ const ResourceSchema$47 = zod.z.object({
1835
2075
  object: zod.z.string().optional(),
1836
2076
  organization_id: zod.z.string().optional(),
1837
2077
  name: zod.z.string(),
1838
- enrollment_mode: EnrollmentModeSchema$2.optional(),
2078
+ enrollment_mode: EnrollmentModeSchemaWidened$2.optional(),
1839
2079
  affiliation_verification: zod.z.object({
1840
2080
  attempts: zod.z.number().optional(),
1841
2081
  status: zod.z.string().optional()
1842
- }).passthrough().optional(),
2082
+ }).passthrough().nullable().optional(),
1843
2083
  verification: zod.z.object({
1844
2084
  attempts: zod.z.number().optional(),
1845
2085
  status: zod.z.string().optional()
1846
- }).passthrough().optional(),
2086
+ }).passthrough().nullable().optional(),
1847
2087
  verified: zod.z.boolean().optional(),
1848
2088
  created_at: zod.z.number().optional(),
1849
2089
  updated_at: zod.z.number().optional()
@@ -1872,7 +2112,7 @@ function createOrganizationDomainTool$1(proxy) {
1872
2112
  //#endregion
1873
2113
  //#region src/providers/clerk/tools/create-organization-invitation.ts
1874
2114
  const createOrganizationInvitationInputSchema = zod.z.object({
1875
- organization_id: zod.z.string(),
2115
+ organization_id: zod.z.string().min(1),
1876
2116
  email_address: zod.z.string().email(),
1877
2117
  role: zod.z.string(),
1878
2118
  inviter_user_id: zod.z.string().optional(),
@@ -1893,7 +2133,7 @@ const ResourceSchema$46 = zod.z.object({
1893
2133
  "accepted",
1894
2134
  "revoked",
1895
2135
  "expired"
1896
- ]).optional(),
2136
+ ]).or(zod.z.string()).optional(),
1897
2137
  created_at: zod.z.number().optional(),
1898
2138
  updated_at: zod.z.number().optional()
1899
2139
  }).passthrough();
@@ -1926,8 +2166,8 @@ function createOrganizationInvitationTool(proxy) {
1926
2166
  //#endregion
1927
2167
  //#region src/providers/clerk/tools/create-organization-membership.ts
1928
2168
  const createOrganizationMembershipInputSchema$1 = zod.z.object({
1929
- organization_id: zod.z.string(),
1930
- user_id: zod.z.string(),
2169
+ organization_id: zod.z.string().min(1),
2170
+ user_id: zod.z.string().min(1),
1931
2171
  role: zod.z.string(),
1932
2172
  public_metadata: zod.z.record(zod.z.string(), zod.z.unknown()).optional(),
1933
2173
  private_metadata: zod.z.record(zod.z.string(), zod.z.unknown()).optional()
@@ -2063,7 +2303,7 @@ function createOrganizationTool$1(proxy) {
2063
2303
  //#endregion
2064
2304
  //#region src/providers/clerk/tools/create-phone-number.ts
2065
2305
  const createPhoneNumberInputSchema = zod.z.object({
2066
- user_id: zod.z.string(),
2306
+ user_id: zod.z.string().min(1),
2067
2307
  phone_number: zod.z.string(),
2068
2308
  verified: zod.z.boolean().optional(),
2069
2309
  primary: zod.z.boolean().optional(),
@@ -2126,7 +2366,7 @@ const createUserInputSchema$2 = zod.z.object({
2126
2366
  public_metadata: zod.z.record(zod.z.string(), zod.z.unknown()).optional(),
2127
2367
  private_metadata: zod.z.record(zod.z.string(), zod.z.unknown()).optional(),
2128
2368
  unsafe_metadata: zod.z.record(zod.z.string(), zod.z.unknown()).optional()
2129
- });
2369
+ }).refine((value) => (value.email_address?.length ?? 0) > 0 || (value.phone_number?.length ?? 0) > 0 || value.username !== void 0 || value.password !== void 0, { message: "Provide at least one of email_address, phone_number, username, or password." });
2130
2370
  const UserSchema$27 = zod.z.object({
2131
2371
  id: zod.z.string(),
2132
2372
  object: zod.z.string().optional(),
@@ -2178,7 +2418,7 @@ function createUserTool$2(proxy) {
2178
2418
  }
2179
2419
  //#endregion
2180
2420
  //#region src/providers/clerk/tools/delete-email-address.ts
2181
- const deleteEmailAddressInputSchema = zod.z.object({ email_address_id: zod.z.string() });
2421
+ const deleteEmailAddressInputSchema = zod.z.object({ email_address_id: zod.z.string().min(1) });
2182
2422
  const deleteEmailAddressOutputSchema = zod.z.object({
2183
2423
  id: zod.z.string(),
2184
2424
  success: zod.z.boolean()
@@ -2204,8 +2444,8 @@ function deleteEmailAddressTool(proxy) {
2204
2444
  //#endregion
2205
2445
  //#region src/providers/clerk/tools/delete-organization-domain.ts
2206
2446
  const deleteOrganizationDomainInputSchema$1 = zod.z.object({
2207
- organization_id: zod.z.string(),
2208
- domain_id: zod.z.string()
2447
+ organization_id: zod.z.string().min(1),
2448
+ domain_id: zod.z.string().min(1)
2209
2449
  });
2210
2450
  const deleteOrganizationDomainOutputSchema$1 = zod.z.object({
2211
2451
  id: zod.z.string(),
@@ -2232,8 +2472,8 @@ function deleteOrganizationDomainTool$1(proxy) {
2232
2472
  //#endregion
2233
2473
  //#region src/providers/clerk/tools/delete-organization-membership.ts
2234
2474
  const deleteOrganizationMembershipInputSchema$1 = zod.z.object({
2235
- organization_id: zod.z.string(),
2236
- user_id: zod.z.string()
2475
+ organization_id: zod.z.string().min(1),
2476
+ user_id: zod.z.string().min(1)
2237
2477
  });
2238
2478
  const deleteOrganizationMembershipOutputSchema$1 = zod.z.object({
2239
2479
  id: zod.z.string(),
@@ -2259,7 +2499,7 @@ function deleteOrganizationMembershipTool$1(proxy) {
2259
2499
  }
2260
2500
  //#endregion
2261
2501
  //#region src/providers/clerk/tools/delete-organization-role.ts
2262
- const deleteOrganizationRoleInputSchema = zod.z.object({ organization_role_id: zod.z.string() });
2502
+ const deleteOrganizationRoleInputSchema = zod.z.object({ organization_role_id: zod.z.string().min(1) });
2263
2503
  const deleteOrganizationRoleOutputSchema = zod.z.object({
2264
2504
  id: zod.z.string(),
2265
2505
  success: zod.z.boolean()
@@ -2309,7 +2549,7 @@ function deleteOrganizationTool$1(proxy) {
2309
2549
  }
2310
2550
  //#endregion
2311
2551
  //#region src/providers/clerk/tools/delete-phone-number.ts
2312
- const deletePhoneNumberInputSchema = zod.z.object({ phone_number_id: zod.z.string() });
2552
+ const deletePhoneNumberInputSchema = zod.z.object({ phone_number_id: zod.z.string().min(1) });
2313
2553
  const deletePhoneNumberOutputSchema = zod.z.object({
2314
2554
  id: zod.z.string(),
2315
2555
  success: zod.z.boolean()
@@ -2359,7 +2599,7 @@ function deleteUserTool$2(proxy) {
2359
2599
  }
2360
2600
  //#endregion
2361
2601
  //#region src/providers/clerk/tools/get-email-address.ts
2362
- const getEmailAddressInputSchema = zod.z.object({ email_address_id: zod.z.string() });
2602
+ const getEmailAddressInputSchema = zod.z.object({ email_address_id: zod.z.string().min(1) });
2363
2603
  const ResourceSchema$42 = zod.z.object({
2364
2604
  id: zod.z.string(),
2365
2605
  object: zod.z.string().optional(),
@@ -2394,8 +2634,8 @@ function getEmailAddressTool(proxy) {
2394
2634
  //#endregion
2395
2635
  //#region src/providers/clerk/tools/get-organization-invitation.ts
2396
2636
  const getOrganizationInvitationInputSchema = zod.z.object({
2397
- organization_id: zod.z.string(),
2398
- invitation_id: zod.z.string()
2637
+ organization_id: zod.z.string().min(1),
2638
+ invitation_id: zod.z.string().min(1)
2399
2639
  });
2400
2640
  const ResourceSchema$41 = zod.z.object({
2401
2641
  id: zod.z.string(),
@@ -2408,7 +2648,7 @@ const ResourceSchema$41 = zod.z.object({
2408
2648
  "accepted",
2409
2649
  "revoked",
2410
2650
  "expired"
2411
- ]).optional(),
2651
+ ]).or(zod.z.string()).optional(),
2412
2652
  created_at: zod.z.number().optional(),
2413
2653
  updated_at: zod.z.number().optional()
2414
2654
  }).passthrough();
@@ -2430,7 +2670,7 @@ function getOrganizationInvitationTool(proxy) {
2430
2670
  }
2431
2671
  //#endregion
2432
2672
  //#region src/providers/clerk/tools/get-organization-role.ts
2433
- const getOrganizationRoleInputSchema = zod.z.object({ organization_role_id: zod.z.string() });
2673
+ const getOrganizationRoleInputSchema = zod.z.object({ organization_role_id: zod.z.string().min(1) });
2434
2674
  const ResourceSchema$40 = zod.z.object({
2435
2675
  id: zod.z.string(),
2436
2676
  object: zod.z.string().optional(),
@@ -2502,7 +2742,7 @@ function getOrganizationTool$1(proxy) {
2502
2742
  }
2503
2743
  //#endregion
2504
2744
  //#region src/providers/clerk/tools/get-phone-number.ts
2505
- const getPhoneNumberInputSchema = zod.z.object({ phone_number_id: zod.z.string() });
2745
+ const getPhoneNumberInputSchema = zod.z.object({ phone_number_id: zod.z.string().min(1) });
2506
2746
  const ResourceSchema$39 = zod.z.object({
2507
2747
  id: zod.z.string(),
2508
2748
  object: zod.z.string().optional(),
@@ -2537,7 +2777,7 @@ function getPhoneNumberTool(proxy) {
2537
2777
  }
2538
2778
  //#endregion
2539
2779
  //#region src/providers/clerk/tools/get-session.ts
2540
- const getSessionInputSchema = zod.z.object({ session_id: zod.z.string() });
2780
+ const getSessionInputSchema = zod.z.object({ session_id: zod.z.string().min(1) });
2541
2781
  const ResourceSchema$38 = zod.z.object({
2542
2782
  id: zod.z.string(),
2543
2783
  object: zod.z.string().optional(),
@@ -2551,7 +2791,7 @@ const ResourceSchema$38 = zod.z.object({
2551
2791
  "removed",
2552
2792
  "replaced",
2553
2793
  "revoked"
2554
- ]).optional(),
2794
+ ]).or(zod.z.string()).optional(),
2555
2795
  last_active_at: zod.z.number().optional(),
2556
2796
  expire_at: zod.z.number().optional(),
2557
2797
  abandon_at: zod.z.number().optional(),
@@ -2611,33 +2851,39 @@ function getUserTool$7(proxy) {
2611
2851
  }
2612
2852
  //#endregion
2613
2853
  //#region src/providers/clerk/tools/list-organization-domains.ts
2614
- const EnrollmentModeSchema$1 = zod.z.enum([
2854
+ const EnrollmentModeSchema$2 = zod.z.enum([
2615
2855
  "manual_invitation",
2616
2856
  "automatic_invitation",
2617
2857
  "automatic_suggestion",
2618
2858
  "enterprise_sso"
2619
2859
  ]);
2860
+ const EnrollmentModeSchemaWidened$1 = zod.z.enum([
2861
+ "manual_invitation",
2862
+ "automatic_invitation",
2863
+ "automatic_suggestion",
2864
+ "enterprise_sso"
2865
+ ]).or(zod.z.string());
2620
2866
  const listOrganizationDomainsInputSchema = zod.z.object({
2621
- cursor: zod.z.string().optional().describe("Pagination cursor returned by a previous request. Omit for the first page."),
2867
+ cursor: zod.z.string().regex(/^\d+$/, "Cursor must be a non-negative integer.").refine((value) => Number.isSafeInteger(Number(value)), "Cursor must be a non-negative integer.").optional().describe("Pagination cursor returned by a previous request. Omit for the first page."),
2622
2868
  limit: zod.z.number().int().min(1).max(500).optional(),
2623
- organization_id: zod.z.string(),
2869
+ organization_id: zod.z.string().min(1),
2624
2870
  verified: zod.z.boolean().optional(),
2625
- enrollment_mode: EnrollmentModeSchema$1.optional()
2871
+ enrollment_mode: EnrollmentModeSchema$2.optional()
2626
2872
  });
2627
2873
  const ResourceSchema$37 = zod.z.object({
2628
2874
  id: zod.z.string(),
2629
2875
  object: zod.z.string().optional(),
2630
2876
  organization_id: zod.z.string().optional(),
2631
2877
  name: zod.z.string(),
2632
- enrollment_mode: EnrollmentModeSchema$1.optional(),
2878
+ enrollment_mode: EnrollmentModeSchemaWidened$1.optional(),
2633
2879
  affiliation_verification: zod.z.object({
2634
2880
  attempts: zod.z.number().optional(),
2635
2881
  status: zod.z.string().optional()
2636
- }).passthrough().optional(),
2882
+ }).passthrough().nullable().optional(),
2637
2883
  verification: zod.z.object({
2638
2884
  attempts: zod.z.number().optional(),
2639
2885
  status: zod.z.string().optional()
2640
- }).passthrough().optional(),
2886
+ }).passthrough().nullable().optional(),
2641
2887
  verified: zod.z.boolean().optional(),
2642
2888
  created_at: zod.z.number().optional(),
2643
2889
  updated_at: zod.z.number().optional()
@@ -2648,7 +2894,7 @@ const ProviderResponseSchema$244 = zod.z.object({
2648
2894
  });
2649
2895
  const listOrganizationDomainsOutputSchema = zod.z.object({
2650
2896
  items: zod.z.array(ResourceSchema$37),
2651
- next_cursor: zod.z.string().optional(),
2897
+ next_cursor: zod.z.string().regex(/^\d+$/, "Cursor must be a non-negative integer.").refine((value) => Number.isSafeInteger(Number(value)), "Cursor must be a non-negative integer.").optional().describe("Pagination cursor returned by a previous request. Omit for the first page."),
2652
2898
  total: zod.z.number()
2653
2899
  });
2654
2900
  function listOrganizationDomainsTool(proxy) {
@@ -2659,11 +2905,7 @@ function listOrganizationDomainsTool(proxy) {
2659
2905
  outputSchema: listOrganizationDomainsOutputSchema,
2660
2906
  execute: async (input, { requestContext }) => {
2661
2907
  const platformProxy = proxy.withRequestContext(requestContext);
2662
- const offset = input.cursor === void 0 ? 0 : Number.parseInt(input.cursor, 10);
2663
- if (!Number.isInteger(offset) || offset < 0) throw new platformProxy.ActionError({
2664
- type: "invalid_cursor",
2665
- message: "Cursor must be a non-negative integer."
2666
- });
2908
+ const offset = input.cursor === void 0 ? 0 : Number(input.cursor);
2667
2909
  const response = await platformProxy.get({
2668
2910
  endpoint: `/v1/organizations/${encodeURIComponent(input.organization_id)}/domains`,
2669
2911
  params: {
@@ -2687,9 +2929,9 @@ function listOrganizationDomainsTool(proxy) {
2687
2929
  //#endregion
2688
2930
  //#region src/providers/clerk/tools/list-organization-invitations.ts
2689
2931
  const listOrganizationInvitationsInputSchema = zod.z.object({
2690
- cursor: zod.z.string().optional().describe("Pagination cursor returned by a previous request. Omit for the first page."),
2932
+ cursor: zod.z.string().regex(/^\d+$/, "Cursor must be a non-negative integer.").refine((value) => Number.isSafeInteger(Number(value)), "Cursor must be a non-negative integer.").optional().describe("Pagination cursor returned by a previous request. Omit for the first page."),
2691
2933
  limit: zod.z.number().int().min(1).max(500).optional(),
2692
- organization_id: zod.z.string(),
2934
+ organization_id: zod.z.string().min(1),
2693
2935
  status: zod.z.enum([
2694
2936
  "pending",
2695
2937
  "accepted",
@@ -2710,7 +2952,7 @@ const ResourceSchema$36 = zod.z.object({
2710
2952
  "accepted",
2711
2953
  "revoked",
2712
2954
  "expired"
2713
- ]).optional(),
2955
+ ]).or(zod.z.string()).optional(),
2714
2956
  created_at: zod.z.number().optional(),
2715
2957
  updated_at: zod.z.number().optional()
2716
2958
  }).passthrough();
@@ -2720,7 +2962,7 @@ const ProviderResponseSchema$243 = zod.z.object({
2720
2962
  });
2721
2963
  const listOrganizationInvitationsOutputSchema = zod.z.object({
2722
2964
  items: zod.z.array(ResourceSchema$36),
2723
- next_cursor: zod.z.string().optional(),
2965
+ next_cursor: zod.z.string().regex(/^\d+$/, "Cursor must be a non-negative integer.").refine((value) => Number.isSafeInteger(Number(value)), "Cursor must be a non-negative integer.").optional().describe("Pagination cursor returned by a previous request. Omit for the first page."),
2724
2966
  total: zod.z.number()
2725
2967
  });
2726
2968
  function listOrganizationInvitationsTool(proxy) {
@@ -2731,11 +2973,7 @@ function listOrganizationInvitationsTool(proxy) {
2731
2973
  outputSchema: listOrganizationInvitationsOutputSchema,
2732
2974
  execute: async (input, { requestContext }) => {
2733
2975
  const platformProxy = proxy.withRequestContext(requestContext);
2734
- const offset = input.cursor === void 0 ? 0 : Number.parseInt(input.cursor, 10);
2735
- if (!Number.isInteger(offset) || offset < 0) throw new platformProxy.ActionError({
2736
- type: "invalid_cursor",
2737
- message: "Cursor must be a non-negative integer."
2738
- });
2976
+ const offset = input.cursor === void 0 ? 0 : Number(input.cursor);
2739
2977
  const response = await platformProxy.get({
2740
2978
  endpoint: `/v1/organizations/${encodeURIComponent(input.organization_id)}/invitations`,
2741
2979
  params: {
@@ -2760,9 +2998,9 @@ function listOrganizationInvitationsTool(proxy) {
2760
2998
  //#endregion
2761
2999
  //#region src/providers/clerk/tools/list-organization-memberships.ts
2762
3000
  const listOrganizationMembershipsInputSchema$1 = zod.z.object({
2763
- cursor: zod.z.string().optional().describe("Pagination cursor returned by a previous request. Omit for the first page."),
3001
+ cursor: zod.z.string().regex(/^\d+$/, "Cursor must be a non-negative integer.").refine((value) => Number.isSafeInteger(Number(value)), "Cursor must be a non-negative integer.").optional().describe("Pagination cursor returned by a previous request. Omit for the first page."),
2764
3002
  limit: zod.z.number().int().min(1).max(500).optional(),
2765
- organization_id: zod.z.string(),
3003
+ organization_id: zod.z.string().min(1),
2766
3004
  user_id: zod.z.array(zod.z.string()).optional(),
2767
3005
  email_address: zod.z.array(zod.z.string()).optional(),
2768
3006
  phone_number: zod.z.array(zod.z.string()).optional(),
@@ -2796,7 +3034,7 @@ const ProviderResponseSchema$242 = zod.z.object({
2796
3034
  });
2797
3035
  const listOrganizationMembershipsOutputSchema$1 = zod.z.object({
2798
3036
  items: zod.z.array(ResourceSchema$35),
2799
- next_cursor: zod.z.string().optional(),
3037
+ next_cursor: zod.z.string().regex(/^\d+$/, "Cursor must be a non-negative integer.").refine((value) => Number.isSafeInteger(Number(value)), "Cursor must be a non-negative integer.").optional().describe("Pagination cursor returned by a previous request. Omit for the first page."),
2800
3038
  total: zod.z.number()
2801
3039
  });
2802
3040
  function listOrganizationMembershipsTool$1(proxy) {
@@ -2807,11 +3045,7 @@ function listOrganizationMembershipsTool$1(proxy) {
2807
3045
  outputSchema: listOrganizationMembershipsOutputSchema$1,
2808
3046
  execute: async (input, { requestContext }) => {
2809
3047
  const platformProxy = proxy.withRequestContext(requestContext);
2810
- const offset = input.cursor === void 0 ? 0 : Number.parseInt(input.cursor, 10);
2811
- if (!Number.isInteger(offset) || offset < 0) throw new platformProxy.ActionError({
2812
- type: "invalid_cursor",
2813
- message: "Cursor must be a non-negative integer."
2814
- });
3048
+ const offset = input.cursor === void 0 ? 0 : Number(input.cursor);
2815
3049
  const response = await platformProxy.get({
2816
3050
  endpoint: `/v1/organizations/${encodeURIComponent(input.organization_id)}/memberships`,
2817
3051
  params: {
@@ -2849,7 +3083,7 @@ function listOrganizationMembershipsTool$1(proxy) {
2849
3083
  //#endregion
2850
3084
  //#region src/providers/clerk/tools/list-organization-roles.ts
2851
3085
  const listOrganizationRolesInputSchema = zod.z.object({
2852
- cursor: zod.z.string().optional().describe("Pagination cursor returned by a previous request. Omit for the first page."),
3086
+ cursor: zod.z.string().regex(/^\d+$/, "Cursor must be a non-negative integer.").refine((value) => Number.isSafeInteger(Number(value)), "Cursor must be a non-negative integer.").optional().describe("Pagination cursor returned by a previous request. Omit for the first page."),
2853
3087
  limit: zod.z.number().int().min(1).max(500).optional(),
2854
3088
  query: zod.z.string().optional(),
2855
3089
  order_by: zod.z.string().optional()
@@ -2874,7 +3108,7 @@ const ProviderResponseSchema$241 = zod.z.object({
2874
3108
  });
2875
3109
  const listOrganizationRolesOutputSchema = zod.z.object({
2876
3110
  items: zod.z.array(ResourceSchema$34),
2877
- next_cursor: zod.z.string().optional(),
3111
+ next_cursor: zod.z.string().regex(/^\d+$/, "Cursor must be a non-negative integer.").refine((value) => Number.isSafeInteger(Number(value)), "Cursor must be a non-negative integer.").optional().describe("Pagination cursor returned by a previous request. Omit for the first page."),
2878
3112
  total: zod.z.number()
2879
3113
  });
2880
3114
  function listOrganizationRolesTool(proxy) {
@@ -2885,11 +3119,7 @@ function listOrganizationRolesTool(proxy) {
2885
3119
  outputSchema: listOrganizationRolesOutputSchema,
2886
3120
  execute: async (input, { requestContext }) => {
2887
3121
  const platformProxy = proxy.withRequestContext(requestContext);
2888
- const offset = input.cursor === void 0 ? 0 : Number.parseInt(input.cursor, 10);
2889
- if (!Number.isInteger(offset) || offset < 0) throw new platformProxy.ActionError({
2890
- type: "invalid_cursor",
2891
- message: "Cursor must be a non-negative integer."
2892
- });
3122
+ const offset = input.cursor === void 0 ? 0 : Number(input.cursor);
2893
3123
  const response = await platformProxy.get({
2894
3124
  endpoint: "/v1/organization_roles",
2895
3125
  params: {
@@ -2913,7 +3143,7 @@ function listOrganizationRolesTool(proxy) {
2913
3143
  //#endregion
2914
3144
  //#region src/providers/clerk/tools/list-organizations.ts
2915
3145
  const listOrganizationsInputSchema$1 = zod.z.object({
2916
- cursor: zod.z.string().optional(),
3146
+ cursor: zod.z.string().regex(/^\d+$/, "Cursor must be a non-negative integer.").refine((value) => Number.isSafeInteger(Number(value)), "Cursor must be a non-negative integer.").optional().describe("Pagination cursor returned by a previous request. Omit for the first page."),
2917
3147
  limit: zod.z.number().int().min(1).max(500).optional(),
2918
3148
  query: zod.z.string().optional(),
2919
3149
  order_by: zod.z.string().optional().describe("Sort by name, created_at, or members_count, prefixed with + or -."),
@@ -2953,11 +3183,7 @@ function listOrganizationsTool$1(proxy) {
2953
3183
  outputSchema: listOrganizationsOutputSchema$1,
2954
3184
  execute: async (input, { requestContext }) => {
2955
3185
  const platformProxy = proxy.withRequestContext(requestContext);
2956
- const offset = input.cursor === void 0 ? 0 : Number.parseInt(input.cursor, 10);
2957
- if (!Number.isInteger(offset) || offset < 0) throw new platformProxy.ActionError({
2958
- type: "invalid_cursor",
2959
- message: "Cursor must be a non-negative integer."
2960
- });
3186
+ const offset = input.cursor === void 0 ? 0 : Number(input.cursor);
2961
3187
  const response = await platformProxy.get({
2962
3188
  endpoint: "/v1/organizations",
2963
3189
  params: {
@@ -2983,10 +3209,10 @@ function listOrganizationsTool$1(proxy) {
2983
3209
  //#endregion
2984
3210
  //#region src/providers/clerk/tools/list-sessions.ts
2985
3211
  const listSessionsInputSchema = zod.z.object({
2986
- cursor: zod.z.string().optional().describe("Pagination cursor returned by a previous request. Omit for the first page."),
3212
+ cursor: zod.z.string().regex(/^\d+$/, "Cursor must be a non-negative integer.").refine((value) => Number.isSafeInteger(Number(value)), "Cursor must be a non-negative integer.").optional().describe("Pagination cursor returned by a previous request. Omit for the first page."),
2987
3213
  limit: zod.z.number().int().min(1).max(500).optional(),
2988
- client_id: zod.z.string().optional(),
2989
- user_id: zod.z.string().optional(),
3214
+ client_id: zod.z.string().min(1).optional(),
3215
+ user_id: zod.z.string().min(1).optional(),
2990
3216
  status: zod.z.enum([
2991
3217
  "abandoned",
2992
3218
  "active",
@@ -2996,7 +3222,7 @@ const listSessionsInputSchema = zod.z.object({
2996
3222
  "replaced",
2997
3223
  "revoked"
2998
3224
  ]).optional()
2999
- });
3225
+ }).refine((value) => value.client_id !== void 0 || value.user_id !== void 0, { message: "Provide at least one of client_id or user_id." });
3000
3226
  const ResourceSchema$33 = zod.z.object({
3001
3227
  id: zod.z.string(),
3002
3228
  object: zod.z.string().optional(),
@@ -3010,21 +3236,17 @@ const ResourceSchema$33 = zod.z.object({
3010
3236
  "removed",
3011
3237
  "replaced",
3012
3238
  "revoked"
3013
- ]).optional(),
3239
+ ]).or(zod.z.string()).optional(),
3014
3240
  last_active_at: zod.z.number().optional(),
3015
3241
  expire_at: zod.z.number().optional(),
3016
3242
  abandon_at: zod.z.number().optional(),
3017
3243
  created_at: zod.z.number().optional(),
3018
3244
  updated_at: zod.z.number().optional()
3019
3245
  }).passthrough();
3020
- const ProviderResponseSchema$239 = zod.z.object({
3021
- data: zod.z.array(ResourceSchema$33),
3022
- total_count: zod.z.number()
3023
- });
3246
+ const ProviderResponseSchema$239 = zod.z.array(ResourceSchema$33);
3024
3247
  const listSessionsOutputSchema = zod.z.object({
3025
3248
  items: zod.z.array(ResourceSchema$33),
3026
- next_cursor: zod.z.string().optional(),
3027
- total: zod.z.number()
3249
+ next_cursor: zod.z.string().regex(/^\d+$/, "Cursor must be a non-negative integer.").refine((value) => Number.isSafeInteger(Number(value)), "Cursor must be a non-negative integer.").optional().describe("Pagination cursor returned by a previous request. Omit for the first page.")
3028
3250
  });
3029
3251
  function listSessionsTool(proxy) {
3030
3252
  return (0, _mastra_core_tools.createTool)({
@@ -3034,28 +3256,23 @@ function listSessionsTool(proxy) {
3034
3256
  outputSchema: listSessionsOutputSchema,
3035
3257
  execute: async (input, { requestContext }) => {
3036
3258
  const platformProxy = proxy.withRequestContext(requestContext);
3037
- const offset = input.cursor === void 0 ? 0 : Number.parseInt(input.cursor, 10);
3038
- if (!Number.isInteger(offset) || offset < 0) throw new platformProxy.ActionError({
3039
- type: "invalid_cursor",
3040
- message: "Cursor must be a non-negative integer."
3041
- });
3259
+ const offset = input.cursor === void 0 ? 0 : Number(input.cursor);
3260
+ const limit = input.limit ?? 10;
3042
3261
  const response = await platformProxy.get({
3043
3262
  endpoint: "/v1/sessions",
3044
3263
  params: {
3045
3264
  offset: String(offset),
3046
- ...input.limit !== void 0 && { limit: String(input.limit) },
3265
+ limit: String(limit),
3047
3266
  ...input.client_id !== void 0 && { client_id: input.client_id },
3048
3267
  ...input.user_id !== void 0 && { user_id: input.user_id },
3049
3268
  ...input.status !== void 0 && { status: input.status }
3050
3269
  },
3051
3270
  retries: 3
3052
3271
  });
3053
- const provider = ProviderResponseSchema$239.parse(response.data);
3054
- const nextOffset = offset + provider.data.length;
3272
+ const sessions = ProviderResponseSchema$239.parse(response.data);
3055
3273
  return {
3056
- items: provider.data,
3057
- ...nextOffset < provider.total_count && { next_cursor: String(nextOffset) },
3058
- total: provider.total_count
3274
+ items: sessions,
3275
+ ...sessions.length === limit && { next_cursor: String(offset + sessions.length) }
3059
3276
  };
3060
3277
  }
3061
3278
  });
@@ -3063,13 +3280,19 @@ function listSessionsTool(proxy) {
3063
3280
  //#endregion
3064
3281
  //#region src/providers/clerk/tools/list-users.ts
3065
3282
  const listUsersInputSchema$9 = zod.z.object({
3066
- cursor: zod.z.string().optional().describe("Pagination cursor returned by a previous request. Omit for the first page."),
3283
+ cursor: zod.z.string().regex(/^\d+$/, "Cursor must be a non-negative integer.").refine((value) => Number.isSafeInteger(Number(value)), "Cursor must be a non-negative integer.").optional().describe("Pagination cursor returned by a previous request. Omit for the first page."),
3067
3284
  limit: zod.z.number().int().min(1).max(500).optional().describe("Maximum number of users to return. Maximum 500."),
3068
3285
  query: zod.z.string().optional().describe("Search across names, identifiers, email addresses, phone numbers, and usernames."),
3069
3286
  email_address: zod.z.array(zod.z.string()).max(100).optional().describe("Filter by email addresses."),
3287
+ phone_number: zod.z.array(zod.z.string()).max(100).optional().describe("Filter by phone numbers."),
3288
+ username: zod.z.array(zod.z.string()).max(100).optional().describe("Filter by usernames."),
3070
3289
  user_id: zod.z.array(zod.z.string()).max(100).optional().describe("Filter by Clerk user IDs."),
3071
3290
  external_id: zod.z.array(zod.z.string()).max(100).optional().describe("Filter by external user IDs."),
3072
3291
  organization_id: zod.z.array(zod.z.string()).max(100).optional().describe("Filter by organization IDs."),
3292
+ last_active_at_before: zod.z.number().int().optional().describe("Filter users last active before this Unix timestamp in milliseconds."),
3293
+ last_active_at_after: zod.z.number().int().optional().describe("Filter users last active after this Unix timestamp in milliseconds."),
3294
+ created_at_before: zod.z.number().int().optional().describe("Filter users created before this Unix timestamp in milliseconds."),
3295
+ created_at_after: zod.z.number().int().optional().describe("Filter users created after this Unix timestamp in milliseconds."),
3073
3296
  order_by: zod.z.string().optional().describe("Sort field prefixed with + for ascending or - for descending. Example: \"-created_at\"")
3074
3297
  });
3075
3298
  const UserSchema$25 = zod.z.object({
@@ -3088,13 +3311,11 @@ const UserSchema$25 = zod.z.object({
3088
3311
  updated_at: zod.z.number().optional(),
3089
3312
  locale: zod.z.string().nullable().optional()
3090
3313
  }).passthrough();
3091
- const ProviderResponseSchema$238 = zod.z.object({
3092
- data: zod.z.array(UserSchema$25),
3093
- total_count: zod.z.number()
3094
- });
3314
+ const ProviderResponseSchema$238 = zod.z.array(UserSchema$25);
3315
+ const ProviderCountSchema = zod.z.object({ total_count: zod.z.number() }).passthrough();
3095
3316
  const listUsersOutputSchema$9 = zod.z.object({
3096
3317
  items: zod.z.array(UserSchema$25),
3097
- next_cursor: zod.z.string().optional(),
3318
+ next_cursor: zod.z.string().regex(/^\d+$/, "Cursor must be a non-negative integer.").refine((value) => Number.isSafeInteger(Number(value)), "Cursor must be a non-negative integer.").optional().describe("Pagination cursor returned by a previous request. Omit for the first page."),
3098
3319
  total: zod.z.number()
3099
3320
  });
3100
3321
  function listUsersTool$9(proxy) {
@@ -3105,31 +3326,42 @@ function listUsersTool$9(proxy) {
3105
3326
  outputSchema: listUsersOutputSchema$9,
3106
3327
  execute: async (input, { requestContext }) => {
3107
3328
  const platformProxy = proxy.withRequestContext(requestContext);
3108
- const offset = input.cursor === void 0 ? 0 : Number.parseInt(input.cursor, 10);
3109
- if (!Number.isInteger(offset) || offset < 0) throw new platformProxy.ActionError({
3110
- type: "invalid_cursor",
3111
- message: "Cursor must be a non-negative integer."
3112
- });
3329
+ const offset = input.cursor === void 0 ? 0 : Number(input.cursor);
3330
+ const filterParams = {
3331
+ ...input.query !== void 0 && { query: input.query },
3332
+ ...input.email_address !== void 0 && { email_address: input.email_address },
3333
+ ...input.phone_number !== void 0 && { phone_number: input.phone_number },
3334
+ ...input.username !== void 0 && { username: input.username },
3335
+ ...input.user_id !== void 0 && { user_id: input.user_id },
3336
+ ...input.external_id !== void 0 && { external_id: input.external_id },
3337
+ ...input.organization_id !== void 0 && { organization_id: input.organization_id },
3338
+ ...input.last_active_at_before !== void 0 && { last_active_at_before: String(input.last_active_at_before) },
3339
+ ...input.last_active_at_after !== void 0 && { last_active_at_after: String(input.last_active_at_after) },
3340
+ ...input.created_at_before !== void 0 && { created_at_before: String(input.created_at_before) },
3341
+ ...input.created_at_after !== void 0 && { created_at_after: String(input.created_at_after) }
3342
+ };
3113
3343
  const response = await platformProxy.get({
3114
3344
  endpoint: "/v1/users",
3115
3345
  params: {
3116
3346
  offset: String(offset),
3117
3347
  ...input.limit !== void 0 && { limit: String(input.limit) },
3118
- ...input.query !== void 0 && { query: input.query },
3119
- ...input.email_address !== void 0 && { email_address: input.email_address },
3120
- ...input.user_id !== void 0 && { user_id: input.user_id },
3121
- ...input.external_id !== void 0 && { external_id: input.external_id },
3122
- ...input.organization_id !== void 0 && { organization_id: input.organization_id },
3123
- ...input.order_by !== void 0 && { order_by: input.order_by }
3348
+ ...input.order_by !== void 0 && { order_by: input.order_by },
3349
+ ...filterParams
3124
3350
  },
3125
3351
  retries: 3
3126
3352
  });
3127
- const provider = ProviderResponseSchema$238.parse(response.data);
3128
- const nextOffset = offset + provider.data.length;
3353
+ const users = ProviderResponseSchema$238.parse(response.data);
3354
+ const countResponse = await platformProxy.get({
3355
+ endpoint: "/v1/users/count",
3356
+ params: filterParams,
3357
+ retries: 3
3358
+ });
3359
+ const total = ProviderCountSchema.parse(countResponse.data).total_count;
3360
+ const nextOffset = offset + users.length;
3129
3361
  return {
3130
- items: provider.data,
3131
- ...nextOffset < provider.total_count && { next_cursor: String(nextOffset) },
3132
- total: provider.total_count
3362
+ items: users,
3363
+ ...users.length > 0 && nextOffset < total && { next_cursor: String(nextOffset) },
3364
+ total
3133
3365
  };
3134
3366
  }
3135
3367
  });
@@ -3137,8 +3369,8 @@ function listUsersTool$9(proxy) {
3137
3369
  //#endregion
3138
3370
  //#region src/providers/clerk/tools/remove-organization-role-permission.ts
3139
3371
  const removeOrganizationRolePermissionInputSchema = zod.z.object({
3140
- organization_role_id: zod.z.string(),
3141
- permission_id: zod.z.string()
3372
+ organization_role_id: zod.z.string().min(1),
3373
+ permission_id: zod.z.string().min(1)
3142
3374
  });
3143
3375
  const removeOrganizationRolePermissionOutputSchema = zod.z.object({
3144
3376
  id: zod.z.string(),
@@ -3165,8 +3397,8 @@ function removeOrganizationRolePermissionTool(proxy) {
3165
3397
  //#endregion
3166
3398
  //#region src/providers/clerk/tools/revoke-organization-invitation.ts
3167
3399
  const revokeOrganizationInvitationInputSchema = zod.z.object({
3168
- organization_id: zod.z.string(),
3169
- invitation_id: zod.z.string(),
3400
+ organization_id: zod.z.string().min(1),
3401
+ invitation_id: zod.z.string().min(1),
3170
3402
  requesting_user_id: zod.z.string().optional()
3171
3403
  });
3172
3404
  const ResourceSchema$32 = zod.z.object({
@@ -3180,7 +3412,7 @@ const ResourceSchema$32 = zod.z.object({
3180
3412
  "accepted",
3181
3413
  "revoked",
3182
3414
  "expired"
3183
- ]).optional(),
3415
+ ]).or(zod.z.string()).optional(),
3184
3416
  created_at: zod.z.number().optional(),
3185
3417
  updated_at: zod.z.number().optional()
3186
3418
  }).passthrough();
@@ -3203,7 +3435,7 @@ function revokeOrganizationInvitationTool(proxy) {
3203
3435
  }
3204
3436
  //#endregion
3205
3437
  //#region src/providers/clerk/tools/revoke-session.ts
3206
- const revokeSessionInputSchema = zod.z.object({ session_id: zod.z.string() });
3438
+ const revokeSessionInputSchema = zod.z.object({ session_id: zod.z.string().min(1) });
3207
3439
  const ResourceSchema$31 = zod.z.object({
3208
3440
  id: zod.z.string(),
3209
3441
  object: zod.z.string().optional(),
@@ -3217,7 +3449,7 @@ const ResourceSchema$31 = zod.z.object({
3217
3449
  "removed",
3218
3450
  "replaced",
3219
3451
  "revoked"
3220
- ]).optional(),
3452
+ ]).or(zod.z.string()).optional(),
3221
3453
  last_active_at: zod.z.number().optional(),
3222
3454
  expire_at: zod.z.number().optional(),
3223
3455
  abandon_at: zod.z.number().optional(),
@@ -3244,7 +3476,7 @@ function revokeSessionTool(proxy) {
3244
3476
  //#endregion
3245
3477
  //#region src/providers/clerk/tools/update-email-address.ts
3246
3478
  const updateEmailAddressInputSchema = zod.z.object({
3247
- email_address_id: zod.z.string(),
3479
+ email_address_id: zod.z.string().min(1),
3248
3480
  verified: zod.z.boolean().optional(),
3249
3481
  primary: zod.z.boolean().optional(),
3250
3482
  notify_primary_email_address_changed: zod.z.boolean().optional()
@@ -3287,16 +3519,22 @@ function updateEmailAddressTool(proxy) {
3287
3519
  }
3288
3520
  //#endregion
3289
3521
  //#region src/providers/clerk/tools/update-organization-domain.ts
3290
- const EnrollmentModeSchema = zod.z.enum([
3522
+ const EnrollmentModeSchema$1 = zod.z.enum([
3291
3523
  "manual_invitation",
3292
3524
  "automatic_invitation",
3293
3525
  "automatic_suggestion",
3294
3526
  "enterprise_sso"
3295
3527
  ]);
3528
+ const EnrollmentModeSchemaWidened = zod.z.enum([
3529
+ "manual_invitation",
3530
+ "automatic_invitation",
3531
+ "automatic_suggestion",
3532
+ "enterprise_sso"
3533
+ ]).or(zod.z.string());
3296
3534
  const updateOrganizationDomainInputSchema = zod.z.object({
3297
- organization_id: zod.z.string(),
3298
- domain_id: zod.z.string(),
3299
- enrollment_mode: EnrollmentModeSchema.optional(),
3535
+ organization_id: zod.z.string().min(1),
3536
+ domain_id: zod.z.string().min(1),
3537
+ enrollment_mode: EnrollmentModeSchema$1.optional(),
3300
3538
  verified: zod.z.boolean().optional()
3301
3539
  });
3302
3540
  const ResourceSchema$29 = zod.z.object({
@@ -3304,15 +3542,15 @@ const ResourceSchema$29 = zod.z.object({
3304
3542
  object: zod.z.string().optional(),
3305
3543
  organization_id: zod.z.string().optional(),
3306
3544
  name: zod.z.string(),
3307
- enrollment_mode: EnrollmentModeSchema.optional(),
3545
+ enrollment_mode: EnrollmentModeSchemaWidened.optional(),
3308
3546
  affiliation_verification: zod.z.object({
3309
3547
  attempts: zod.z.number().optional(),
3310
3548
  status: zod.z.string().optional()
3311
- }).passthrough().optional(),
3549
+ }).passthrough().nullable().optional(),
3312
3550
  verification: zod.z.object({
3313
3551
  attempts: zod.z.number().optional(),
3314
3552
  status: zod.z.string().optional()
3315
- }).passthrough().optional(),
3553
+ }).passthrough().nullable().optional(),
3316
3554
  verified: zod.z.boolean().optional(),
3317
3555
  created_at: zod.z.number().optional(),
3318
3556
  updated_at: zod.z.number().optional()
@@ -3340,8 +3578,8 @@ function updateOrganizationDomainTool(proxy) {
3340
3578
  //#endregion
3341
3579
  //#region src/providers/clerk/tools/update-organization-membership-metadata.ts
3342
3580
  const updateOrganizationMembershipMetadataInputSchema = zod.z.object({
3343
- organization_id: zod.z.string(),
3344
- user_id: zod.z.string(),
3581
+ organization_id: zod.z.string().min(1),
3582
+ user_id: zod.z.string().min(1),
3345
3583
  public_metadata: zod.z.record(zod.z.string(), zod.z.unknown()).optional(),
3346
3584
  private_metadata: zod.z.record(zod.z.string(), zod.z.unknown()).optional()
3347
3585
  });
@@ -3378,8 +3616,8 @@ function updateOrganizationMembershipMetadataTool(proxy) {
3378
3616
  //#endregion
3379
3617
  //#region src/providers/clerk/tools/update-organization-membership.ts
3380
3618
  const updateOrganizationMembershipInputSchema$1 = zod.z.object({
3381
- organization_id: zod.z.string(),
3382
- user_id: zod.z.string(),
3619
+ organization_id: zod.z.string().min(1),
3620
+ user_id: zod.z.string().min(1),
3383
3621
  role: zod.z.string()
3384
3622
  });
3385
3623
  const ResourceSchema$27 = zod.z.object({
@@ -3412,12 +3650,12 @@ function updateOrganizationMembershipTool$1(proxy) {
3412
3650
  //#endregion
3413
3651
  //#region src/providers/clerk/tools/update-organization-role.ts
3414
3652
  const updateOrganizationRoleInputSchema = zod.z.object({
3415
- organization_role_id: zod.z.string(),
3653
+ organization_role_id: zod.z.string().min(1),
3416
3654
  name: zod.z.string().optional(),
3417
3655
  key: zod.z.string().optional(),
3418
3656
  description: zod.z.string().optional(),
3419
3657
  permissions: zod.z.array(zod.z.string()).optional()
3420
- });
3658
+ }).refine((value) => value.name !== void 0 || value.key !== void 0 || value.description !== void 0 || value.permissions !== void 0, { message: "Provide at least one of name, key, description, or permissions." });
3421
3659
  const ResourceSchema$26 = zod.z.object({
3422
3660
  id: zod.z.string(),
3423
3661
  object: zod.z.string().optional(),
@@ -3461,7 +3699,8 @@ const updateOrganizationInputSchema$1 = zod.z.object({
3461
3699
  name: zod.z.string().min(1).optional(),
3462
3700
  slug: zod.z.string().optional(),
3463
3701
  admin_delete_enabled: zod.z.boolean().optional(),
3464
- max_allowed_memberships: zod.z.number().int().min(0).optional()
3702
+ max_allowed_memberships: zod.z.number().int().min(0).optional(),
3703
+ public_metadata: zod.z.record(zod.z.string(), zod.z.unknown()).optional()
3465
3704
  });
3466
3705
  const OrganizationSchema$1 = zod.z.object({
3467
3706
  id: zod.z.string(),
@@ -3493,7 +3732,8 @@ function updateOrganizationTool$1(proxy) {
3493
3732
  ...input.name !== void 0 && { name: input.name },
3494
3733
  ...input.slug !== void 0 && { slug: input.slug },
3495
3734
  ...input.admin_delete_enabled !== void 0 && { admin_delete_enabled: input.admin_delete_enabled },
3496
- ...input.max_allowed_memberships !== void 0 && { max_allowed_memberships: input.max_allowed_memberships }
3735
+ ...input.max_allowed_memberships !== void 0 && { max_allowed_memberships: input.max_allowed_memberships },
3736
+ ...input.public_metadata !== void 0 && { public_metadata: input.public_metadata }
3497
3737
  },
3498
3738
  retries: 3
3499
3739
  });
@@ -3504,7 +3744,7 @@ function updateOrganizationTool$1(proxy) {
3504
3744
  //#endregion
3505
3745
  //#region src/providers/clerk/tools/update-phone-number.ts
3506
3746
  const updatePhoneNumberInputSchema = zod.z.object({
3507
- phone_number_id: zod.z.string(),
3747
+ phone_number_id: zod.z.string().min(1),
3508
3748
  verified: zod.z.boolean().optional(),
3509
3749
  primary: zod.z.boolean().optional(),
3510
3750
  reserved_for_second_factor: zod.z.boolean().optional()
@@ -3550,14 +3790,14 @@ function updatePhoneNumberTool(proxy) {
3550
3790
  //#region src/providers/clerk/tools/update-user.ts
3551
3791
  const updateUserInputSchema$1 = zod.z.object({
3552
3792
  user_id: zod.z.string().min(1),
3553
- first_name: zod.z.string().optional(),
3554
- last_name: zod.z.string().optional(),
3555
- username: zod.z.string().optional(),
3793
+ first_name: zod.z.string().nullable().optional().describe("Pass null to clear the first name."),
3794
+ last_name: zod.z.string().nullable().optional().describe("Pass null to clear the last name."),
3795
+ username: zod.z.string().nullable().optional().describe("Pass null to clear the username."),
3556
3796
  password: zod.z.string().min(8).optional(),
3557
3797
  skip_password_checks: zod.z.boolean().optional(),
3558
3798
  sign_out_of_other_sessions: zod.z.boolean().optional(),
3559
- external_id: zod.z.string().optional(),
3560
- locale: zod.z.string().optional()
3799
+ external_id: zod.z.string().nullable().optional().describe("Pass null to clear the external ID."),
3800
+ locale: zod.z.string().nullable().optional().describe("Pass null to clear the locale.")
3561
3801
  });
3562
3802
  const UserSchema$24 = zod.z.object({
3563
3803
  id: zod.z.string(),
@@ -3603,24 +3843,30 @@ function updateUserTool$1(proxy) {
3603
3843
  }
3604
3844
  //#endregion
3605
3845
  //#region src/providers/clerk/tools/verify-organization-domain.ts
3846
+ const EnrollmentModeSchema = zod.z.enum([
3847
+ "manual_invitation",
3848
+ "automatic_invitation",
3849
+ "automatic_suggestion",
3850
+ "enterprise_sso"
3851
+ ]).or(zod.z.string());
3606
3852
  const verifyOrganizationDomainInputSchema$1 = zod.z.object({
3607
- organization_id: zod.z.string(),
3608
- domain_id: zod.z.string()
3853
+ organization_id: zod.z.string().min(1),
3854
+ domain_id: zod.z.string().min(1)
3609
3855
  });
3610
3856
  const ResourceSchema$24 = zod.z.object({
3611
3857
  id: zod.z.string(),
3612
3858
  object: zod.z.string().optional(),
3613
3859
  organization_id: zod.z.string().optional(),
3614
3860
  name: zod.z.string(),
3615
- enrollment_mode: zod.z.string().optional(),
3861
+ enrollment_mode: EnrollmentModeSchema.optional(),
3616
3862
  affiliation_verification: zod.z.object({
3617
3863
  attempts: zod.z.number().optional(),
3618
3864
  status: zod.z.string().optional()
3619
- }).passthrough().optional(),
3865
+ }).passthrough().nullable().optional(),
3620
3866
  verification: zod.z.object({
3621
3867
  attempts: zod.z.number().optional(),
3622
3868
  status: zod.z.string().optional()
3623
- }).passthrough().optional(),
3869
+ }).passthrough().nullable().optional(),
3624
3870
  verified: zod.z.boolean().optional(),
3625
3871
  created_at: zod.z.number().optional(),
3626
3872
  updated_at: zod.z.number().optional()
@@ -5178,7 +5424,7 @@ const ChannelSchema$2 = zod.z.object({
5178
5424
  recipients: zod.z.array(zod.z.unknown()).optional(),
5179
5425
  icon: zod.z.string().nullable().optional(),
5180
5426
  owner_id: zod.z.string().optional(),
5181
- application_id: zod.z.string().optional(),
5427
+ application_id: zod.z.string().nullable().optional(),
5182
5428
  managed: zod.z.boolean().optional(),
5183
5429
  parent_id: zod.z.string().nullable().optional(),
5184
5430
  last_pin_timestamp: zod.z.string().nullable().optional(),
@@ -34496,12 +34742,35 @@ const getCreateIssueMetadataInputSchema = zod.z.object({
34496
34742
  issuetypeIds: zod.z.array(zod.z.string()).optional().describe("List of issue type IDs to filter by. Example: [\"10000\", \"10001\"]"),
34497
34743
  expand: zod.z.string().optional().describe("Use expand to include additional information about issue metadata in the response. Supported values: projects, projects.issuetypes, projects.issuetypes.fields")
34498
34744
  });
34745
+ const CreateIssueFieldSchema = zod.z.object({
34746
+ required: zod.z.boolean().optional(),
34747
+ schema: zod.z.record(zod.z.string(), zod.z.unknown()).optional(),
34748
+ name: zod.z.string().optional(),
34749
+ key: zod.z.string().optional(),
34750
+ hasDefaultValue: zod.z.boolean().optional(),
34751
+ operations: zod.z.array(zod.z.string()).optional(),
34752
+ allowedValues: zod.z.array(zod.z.unknown()).optional(),
34753
+ defaultValue: zod.z.unknown().optional(),
34754
+ autoCompleteUrl: zod.z.string().optional()
34755
+ });
34756
+ const IssueTypeSchema$1 = zod.z.object({
34757
+ id: zod.z.string(),
34758
+ name: zod.z.string(),
34759
+ self: zod.z.string().optional(),
34760
+ description: zod.z.string().optional(),
34761
+ iconUrl: zod.z.string().optional(),
34762
+ avatarId: zod.z.number().optional(),
34763
+ subtask: zod.z.boolean().optional(),
34764
+ hierarchyLevel: zod.z.number().optional(),
34765
+ fields: zod.z.record(zod.z.string(), CreateIssueFieldSchema).optional()
34766
+ });
34499
34767
  const ProjectSchema$3 = zod.z.object({
34500
34768
  id: zod.z.string(),
34501
34769
  key: zod.z.string(),
34502
34770
  name: zod.z.string(),
34503
34771
  self: zod.z.string().optional(),
34504
- avatarUrls: zod.z.record(zod.z.string(), zod.z.string()).optional()
34772
+ avatarUrls: zod.z.record(zod.z.string(), zod.z.string()).optional(),
34773
+ issuetypes: zod.z.array(IssueTypeSchema$1).optional()
34505
34774
  });
34506
34775
  const ProviderResponseSchema$149 = zod.z.object({ projects: zod.z.array(ProjectSchema$3).optional() });
34507
34776
  const getCreateIssueMetadataOutputSchema = zod.z.object({ projects: zod.z.array(ProjectSchema$3).optional() });
@@ -35621,7 +35890,7 @@ zod.z.object({
35621
35890
  cloudId: zod.z.string().optional(),
35622
35891
  baseUrl: zod.z.string().optional()
35623
35892
  });
35624
- const listIssueTypesInputSchema = zod.z.object({});
35893
+ const listIssueTypesInputSchema = zod.z.object({ projectId: zod.z.string().optional().describe("Project ID used to list only issue types available in that project.") });
35625
35894
  const IssueTypeSchema = zod.z.object({
35626
35895
  id: zod.z.string(),
35627
35896
  name: zod.z.string(),
@@ -35650,7 +35919,7 @@ const AccessibleResourceSchema$1 = zod.z.object({
35650
35919
  function listIssueTypesTool(proxy) {
35651
35920
  return (0, _mastra_core_tools.createTool)({
35652
35921
  id: "jira_list_issue_types",
35653
- description: "List Jira issue types available to the user",
35922
+ description: "List Jira issue types available to the user. Pass projectId to list only the issue types available in that project (recommended before creating an issue).",
35654
35923
  inputSchema: listIssueTypesInputSchema,
35655
35924
  outputSchema: listIssueTypesOutputSchema,
35656
35925
  execute: async (input, { requestContext }) => {
@@ -35685,7 +35954,12 @@ function listIssueTypesTool(proxy) {
35685
35954
  baseUrl
35686
35955
  });
35687
35956
  }
35688
- const config = {
35957
+ const config = input.projectId ? {
35958
+ endpoint: `/ex/jira/${cloudId}/rest/api/3/issuetype/project`,
35959
+ params: { projectId: input.projectId },
35960
+ headers: { "X-Atlassian-Token": "no-check" },
35961
+ retries: 3
35962
+ } : {
35689
35963
  endpoint: `/ex/jira/${cloudId}/rest/api/3/issuetype`,
35690
35964
  headers: { "X-Atlassian-Token": "no-check" },
35691
35965
  retries: 3
@@ -55243,7 +55517,7 @@ const cancelEmailInputSchema = zod.z.object({ email_id: zod.z.string() });
55243
55517
  const ProviderResponseSchema$107 = zod.z.object({
55244
55518
  object: zod.z.string().optional(),
55245
55519
  id: zod.z.string().optional(),
55246
- message_id: zod.z.string().optional(),
55520
+ message_id: zod.z.string().nullable().optional(),
55247
55521
  to: zod.z.array(zod.z.string()).optional(),
55248
55522
  from: zod.z.string().optional(),
55249
55523
  created_at: zod.z.string().optional(),
@@ -56493,7 +56767,7 @@ const getEmailInputSchema = zod.z.object({ email_id: zod.z.string() });
56493
56767
  const ProviderResponseSchema$76 = zod.z.object({
56494
56768
  object: zod.z.string().optional(),
56495
56769
  id: zod.z.string().optional(),
56496
- message_id: zod.z.string().optional(),
56770
+ message_id: zod.z.string().nullable().optional(),
56497
56771
  to: zod.z.array(zod.z.string()).optional(),
56498
56772
  from: zod.z.string().optional(),
56499
56773
  created_at: zod.z.string().optional(),
@@ -56580,7 +56854,7 @@ const ProviderResponseSchema$74 = zod.z.object({
56580
56854
  to: zod.z.array(zod.z.string()).optional(),
56581
56855
  from: zod.z.string().optional(),
56582
56856
  subject: zod.z.string().optional(),
56583
- message_id: zod.z.string().optional(),
56857
+ message_id: zod.z.string().nullable().optional(),
56584
56858
  bcc: zod.z.array(zod.z.string()).nullable().optional(),
56585
56859
  cc: zod.z.array(zod.z.string()).nullable().optional(),
56586
56860
  reply_to: zod.z.array(zod.z.string()).nullable().optional(),
@@ -56654,7 +56928,7 @@ const ProviderResponseSchema$72 = zod.z.object({
56654
56928
  current_version_id: zod.z.string().optional(),
56655
56929
  name: zod.z.string().optional(),
56656
56930
  alias: zod.z.string().optional(),
56657
- from: zod.z.string().optional(),
56931
+ from: zod.z.string().nullable().optional(),
56658
56932
  subject: zod.z.string().optional(),
56659
56933
  reply_to: zod.z.array(zod.z.string()).nullable().optional(),
56660
56934
  html: zod.z.string().optional(),
@@ -57377,7 +57651,7 @@ const ProviderResponseSchema$57 = zod.z.object({
57377
57651
  data: zod.z.array(zod.z.object({
57378
57652
  object: zod.z.string().optional(),
57379
57653
  id: zod.z.string().optional(),
57380
- message_id: zod.z.string().optional(),
57654
+ message_id: zod.z.string().nullable().optional(),
57381
57655
  to: zod.z.array(zod.z.string()).optional(),
57382
57656
  from: zod.z.string().optional(),
57383
57657
  created_at: zod.z.string().optional(),
@@ -57496,7 +57770,7 @@ const ProviderResponseSchema$55 = zod.z.object({
57496
57770
  to: zod.z.array(zod.z.string()).optional(),
57497
57771
  from: zod.z.string().optional(),
57498
57772
  subject: zod.z.string().nullable().optional(),
57499
- message_id: zod.z.string().optional(),
57773
+ message_id: zod.z.string().nullable().optional(),
57500
57774
  bcc: zod.z.array(zod.z.string()).nullable().optional(),
57501
57775
  cc: zod.z.array(zod.z.string()).nullable().optional(),
57502
57776
  reply_to: zod.z.array(zod.z.string()).nullable().optional(),
@@ -58184,7 +58458,7 @@ function updateContactTopicsTool(proxy) {
58184
58458
  const config = {
58185
58459
  endpoint: `/contacts/${encodeURIComponent(input["contact_id"])}/topics`,
58186
58460
  retries: 3,
58187
- data: input.body
58461
+ data: input.body.topics
58188
58462
  };
58189
58463
  const response = await platformProxy.patch(config);
58190
58464
  return ProviderResponseSchema$39.parse(response.data);
@@ -73974,7 +74248,7 @@ function createWorkosTools(options) {
73974
74248
  * Providers with checked-in HTTP toolsets. MCP-backed providers are discovered
73975
74249
  * from the Platform integration catalog at runtime.
73976
74250
  */
73977
- const TOOLS = [
74251
+ const PROVIDERS = [
73978
74252
  anthropicProvider,
73979
74253
  clerkProvider,
73980
74254
  discordProvider,
@@ -74007,27 +74281,16 @@ const TOOLS = [
74007
74281
  }
74008
74282
  ];
74009
74283
  /**
74010
- * @deprecated Use `TOOLS`. This alias is retained for one release cycle so
74011
- * downstream consumers keep working; it will be removed in the next minor.
74012
- */
74013
- const PROVIDERS = TOOLS;
74014
- function findRegistration(integrationId) {
74015
- return TOOLS.find((p) => p.integrationId === integrationId);
74016
- }
74017
- /**
74018
74284
  * Channel-capable providers with a hand-maintained `channels()` registration.
74019
74285
  * The launch ships three (Slack, Telegram, Discord); the provider generator
74020
74286
  * grows to cover new entries when a fourth lands.
74021
74287
  */
74022
74288
  const CHANNELS = CHANNELS$1;
74023
- function findChannelRegistration(integrationId) {
74024
- return CHANNELS.find((c) => c.integrationId === integrationId);
74025
- }
74026
74289
  //#endregion
74027
74290
  //#region src/resolution.ts
74028
74291
  const INTEGRATION_ID_PATTERN = /^[a-zA-Z0-9_-]{1,128}$/;
74029
- function validateIntegrationOverrides(integrations) {
74030
- for (const integrationId of Object.keys(integrations ?? {})) if (!INTEGRATION_ID_PATTERN.test(integrationId)) throw new MastraConnectError("invalid_options", `Invalid provider '${integrationId}' in integrations option: expected 1-128 letters, numbers, underscores, or hyphens.`);
74292
+ function validateProviderIds(providers) {
74293
+ for (const integrationId of Object.keys(providers ?? {})) if (!INTEGRATION_ID_PATTERN.test(integrationId)) throw new MastraConnectError("invalid_options", `Invalid provider '${integrationId}' in providers option: expected 1-128 letters, numbers, underscores, or hyphens.`);
74031
74294
  }
74032
74295
  function connectionIdEnvVar(integrationId) {
74033
74296
  return `MASTRA_${integrationId.toUpperCase().replace(/[^A-Z0-9]/g, "_")}_CONNECTION_ID`;
@@ -74042,42 +74305,8 @@ function groupByIntegrationId(connections) {
74042
74305
  return byIntegrationId;
74043
74306
  }
74044
74307
  /**
74045
- * Resolves the connection to use for one provider, per the contract:
74046
- * option/env var wins; else a single active connection; anything else
74047
- * (ambiguity, needs_reauth, no usable candidate) warns and skips so one bad
74048
- * integration never takes down the whole resolution. A needs_reauth
74049
- * connection is never silently mapped.
74050
- */
74051
- function resolveConnection(request, candidates) {
74052
- const integrationId = request.integrationId;
74053
- const directed = request.connectionId?.trim() || process.env[request.envVar]?.trim() || void 0;
74054
- if (directed) {
74055
- const match = candidates.find((connection) => connection.id === directed);
74056
- if (!match) {
74057
- console.warn(`[@mastra/connect] Skipping ${integrationId}: pinned connection ${directed} is not attached to this project.`);
74058
- return;
74059
- }
74060
- if (match.status === "needs_reauth") {
74061
- console.warn(`[@mastra/connect] Skipping ${integrationId}: connection ${directed} needs re-auth.`);
74062
- return;
74063
- }
74064
- if (match.status !== "active") {
74065
- console.warn(`[@mastra/connect] Skipping ${integrationId}: connection ${directed} is not active (status '${match.status}').`);
74066
- return;
74067
- }
74068
- return directed;
74069
- }
74070
- const active = candidates.filter((connection) => connection.status === "active");
74071
- if (active.length === 1) return active[0].id;
74072
- if (active.length === 0) {
74073
- console.warn(`[@mastra/connect] Skipping ${integrationId}: no active connections (found ${candidates.length} in other states).`);
74074
- return;
74075
- }
74076
- console.warn(`[@mastra/connect] Skipping ${integrationId}: ${active.length} active connections; pin one with connectionId or ${request.envVar}.`);
74077
- }
74078
- /**
74079
74308
  * Resolves how to configure one provider given its candidate connections:
74080
- * - An explicit pin (option or env var) forces `single` at that id.
74309
+ * - An explicit pin (`connectionId`) forces `single` at that id.
74081
74310
  * - Exactly one active connection → `single`.
74082
74311
  * - Two or more active connections → `multi`; the caller wraps tools with
74083
74312
  * `connection_name` so the agent chooses per call at execute time.
@@ -74128,16 +74357,18 @@ const FAILURE_COOLDOWN_MS$1 = 3e4;
74128
74357
  let nextResolverId = 0;
74129
74358
  /**
74130
74359
  * Returns a live toolset resolver over the project's Platform connections.
74131
- * HTTP providers are loaded from the shipped `TOOLS` registry. MCP providers
74360
+ * HTTP providers are loaded from the shipped `PROVIDERS` registry. MCP providers
74132
74361
  * are discovered from the Platform integration catalog. Tools from every supported
74133
74362
  * provider with a matching project connection are merged into one flat record
74134
74363
  * (matched by `integrationId`). The resolver serves a cached snapshot,
74135
- * revalidating from the platform every `ttlMs`, so integrations attached
74136
- * to (or detached from) the project are picked up (or dropped) without a
74364
+ * revalidating from the platform every `ttlMs`, so providers connected
74365
+ * to (or disconnected from) the project are picked up (or dropped) without a
74137
74366
  * restart.
74138
74367
  *
74139
- * Configuration errors (missing project id, bad ttlMs, malformed integration id)
74140
- * throw here — at call time — so they surface at startup.
74368
+ * Configuration errors (missing project id, bad ttlMs, malformed integration id,
74369
+ * the removed `autoApproveTools` key) throw here — at call time — so they
74370
+ * surface at startup. Configuration errors that need discovery to detect
74371
+ * (an unknown tool name in `requireApproval`) fail the resolution instead.
74141
74372
  * Expected provider absence is silently skipped. Actionable per-integration
74142
74373
  * problems during resolution (needs re-auth or ambiguity) are downgraded to
74143
74374
  * warn-and-skip so one bad integration never takes down the whole toolset.
@@ -74150,9 +74381,14 @@ function tools(options = {}) {
74150
74381
  const client = resolveClient(options.client);
74151
74382
  const resolverId = ++nextResolverId;
74152
74383
  const mcpClients = /* @__PURE__ */ new Map();
74153
- const integrationOverrides = normalizeIntegrationOverrides(options.integrations);
74154
- validateIntegrationOverrides(integrationOverrides);
74155
- validateIntegrationXor(integrationOverrides);
74384
+ const normalizedProviders = normalizeProviderOverrides(options.providers);
74385
+ const providerOverrides = normalizedProviders.overrides;
74386
+ validateProviderIds(providerOverrides);
74387
+ validateProviderXor(providerOverrides);
74388
+ validateRequireApproval(providerOverrides);
74389
+ rejectRemovedAutoApproveTools(providerOverrides);
74390
+ if (options.allowTools !== void 0 && options.disallowTools !== void 0) throw new MastraConnectError("invalid_options", "Top-level allowTools and disallowTools are mutually exclusive; set at most one.");
74391
+ if (options.requireApproval !== void 0 && typeof options.requireApproval !== "boolean" && !(Array.isArray(options.requireApproval) && options.requireApproval.every((name) => typeof name === "string"))) throw new MastraConnectError("invalid_options", "Top-level requireApproval must be a boolean or an array of tool keys.");
74156
74392
  let cache;
74157
74393
  let inflight;
74158
74394
  let closing;
@@ -74168,15 +74404,17 @@ function tools(options = {}) {
74168
74404
  const connections = connectionsResult.value;
74169
74405
  if (catalogResult.status === "fulfilled") return {
74170
74406
  connections,
74171
- catalog: catalogResult.value
74407
+ catalog: catalogResult.value,
74408
+ catalogAvailable: true
74172
74409
  };
74173
- const checkedIn = new Set(TOOLS.map((registration) => registration.integrationId));
74174
- if (connections.some((connection) => connection.status === "active" && !checkedIn.has(connection.integrationId) && !integrationOverrides[connection.integrationId]?.disabled)) throw catalogResult.reason;
74410
+ const checkedIn = new Set(PROVIDERS.map((registration) => registration.integrationId));
74411
+ if (connections.some((connection) => connection.status === "active" && !checkedIn.has(connection.integrationId) && !providerOverrides[connection.integrationId]?.disabled && (normalizedProviders.only === void 0 || normalizedProviders.only.has(connection.integrationId)))) throw catalogResult.reason;
74175
74412
  const reason = catalogResult.reason;
74176
74413
  console.warn(`[@mastra/connect] Platform catalog unavailable (${reason instanceof Error ? reason.message : String(reason)}); resolving checked-in providers only.`);
74177
74414
  return {
74178
74415
  connections,
74179
- catalog: []
74416
+ catalog: [],
74417
+ catalogAvailable: false
74180
74418
  };
74181
74419
  };
74182
74420
  /**
@@ -74187,8 +74425,8 @@ function tools(options = {}) {
74187
74425
  if (closing) return closing.then(refresh);
74188
74426
  if (!inflight) inflight = (async () => {
74189
74427
  try {
74190
- const { connections, catalog } = await loadSnapshotInputs();
74191
- const snapshot = await mapTools(connections, buildRequests(integrationOverrides, catalog), options, client, mcpClients, resolverId);
74428
+ const { connections, catalog, catalogAvailable } = await loadSnapshotInputs();
74429
+ const snapshot = await mapTools(connections, buildRequests(normalizedProviders, catalog, catalogAvailable), options, client, mcpClients, resolverId);
74192
74430
  cache = {
74193
74431
  snapshot,
74194
74432
  fetchedAt: Date.now()
@@ -74218,10 +74456,7 @@ function tools(options = {}) {
74218
74456
  }
74219
74457
  return refresh();
74220
74458
  };
74221
- return Object.assign(resolve, {
74222
- invalidate: () => {
74223
- cache = void 0;
74224
- },
74459
+ const resolver = Object.assign(resolve, {
74225
74460
  refresh,
74226
74461
  disconnect: () => {
74227
74462
  closing ??= (async () => {
@@ -74236,28 +74471,75 @@ function tools(options = {}) {
74236
74471
  }
74237
74472
  })();
74238
74473
  return closing;
74239
- }
74474
+ },
74475
+ with: (extra) => withExtraTools(resolver, extra)
74240
74476
  });
74477
+ return resolver;
74241
74478
  }
74242
74479
  /**
74243
- * Turns the two accepted `integrations` shapes into the internal Record form.
74244
- * The string-array shorthand (`["linear", "github"]`) becomes
74245
- * `{ linear: {}, github: {} }`; the object form passes through unchanged.
74246
- * Also rejects malformed inputs early (non-string array entries, duplicates)
74247
- * so a bad option throws at tools() time rather than at first refresh.
74480
+ * Builds the resolver `.with()` returns: resolutions merge the base
74481
+ * resolver's tools with `extra` (extra wins on key collision), cache handles
74482
+ * delegate to the base, and further `.with()` calls chain.
74248
74483
  */
74249
- function normalizeIntegrationOverrides(integrations) {
74250
- if (integrations === void 0) return {};
74251
- if (Array.isArray(integrations)) {
74252
- const record = {};
74253
- for (const entry of integrations) {
74254
- if (typeof entry !== "string") throw new MastraConnectError("invalid_options", `Invalid integrations entry: expected a string integration id, got ${typeof entry}.`);
74255
- if (record[entry] !== void 0) throw new MastraConnectError("invalid_options", `Duplicate integration '${entry}' in integrations array.`);
74256
- record[entry] = {};
74257
- }
74258
- return record;
74484
+ function withExtraTools(base, extra) {
74485
+ const resolveExtra = typeof extra === "function" ? extra : () => extra;
74486
+ const resolve = async (ctx) => {
74487
+ const [baseTools, extraTools] = await Promise.all([base(ctx), resolveExtra(ctx)]);
74488
+ return {
74489
+ ...baseTools,
74490
+ ...extraTools
74491
+ };
74492
+ };
74493
+ const resolver = Object.assign(resolve, {
74494
+ refresh: async () => {
74495
+ const [baseTools, extraTools] = await Promise.all([base.refresh(), resolveExtra()]);
74496
+ return {
74497
+ ...baseTools,
74498
+ ...extraTools
74499
+ };
74500
+ },
74501
+ disconnect: () => base.disconnect(),
74502
+ with: (more) => withExtraTools(resolver, more)
74503
+ });
74504
+ return resolver;
74505
+ }
74506
+ /**
74507
+ * Turns the two accepted `providers` shapes into the internal form. The
74508
+ * array form (`["linear", "github"]`) becomes an allowlist with default
74509
+ * options; the record form expands boolean shorthands (`true` → `{}`,
74510
+ * `false` → an internal exclusion marker). Malformed inputs (non-string
74511
+ * array entries, duplicates, non-boolean/non-object record values) throw at
74512
+ * tools() time rather than at first refresh.
74513
+ */
74514
+ function normalizeProviderOverrides(providers) {
74515
+ if (providers === void 0) return {
74516
+ overrides: {},
74517
+ only: void 0
74518
+ };
74519
+ if (Array.isArray(providers)) {
74520
+ const overrides = {};
74521
+ for (const entry of providers) {
74522
+ if (typeof entry !== "string") throw new MastraConnectError("invalid_options", `Invalid providers entry: expected a string provider id, got ${typeof entry}.`);
74523
+ if (overrides[entry] !== void 0) throw new MastraConnectError("invalid_options", `Duplicate provider '${entry}' in providers array.`);
74524
+ overrides[entry] = {};
74525
+ }
74526
+ return {
74527
+ overrides,
74528
+ only: new Set(Object.keys(overrides))
74529
+ };
74259
74530
  }
74260
- return integrations;
74531
+ const overrides = {};
74532
+ for (const [providerId, value] of Object.entries(providers)) {
74533
+ if (value === void 0) continue;
74534
+ if (value === true) overrides[providerId] = {};
74535
+ else if (value === false) overrides[providerId] = { disabled: true };
74536
+ else if (typeof value === "object" && value !== null && !Array.isArray(value)) overrides[providerId] = value;
74537
+ else throw new MastraConnectError("invalid_options", `Invalid providers entry for '${providerId}': expected true, false, or an options object, got ${value === null ? "null" : Array.isArray(value) ? "an array" : typeof value}.`);
74538
+ }
74539
+ return {
74540
+ overrides,
74541
+ only: void 0
74542
+ };
74261
74543
  }
74262
74544
  /**
74263
74545
  * Rejects any provider that sets both `allowTools` and `disallowTools`.
@@ -74265,15 +74547,39 @@ function normalizeIntegrationOverrides(integrations) {
74265
74547
  * runtime guard catches loosely typed inputs (e.g. built from JSON or a
74266
74548
  * `Record<string, unknown>` upstream).
74267
74549
  */
74268
- function validateIntegrationXor(integrations) {
74269
- for (const [integrationId, providerOptions] of Object.entries(integrations)) {
74550
+ function validateProviderXor(providers) {
74551
+ for (const [integrationId, providerOptions] of Object.entries(providers)) {
74270
74552
  const filters = providerOptions;
74271
74553
  if (filters.allowTools !== void 0 && filters.disallowTools !== void 0) throw new MastraConnectError("invalid_options", `Invalid options for '${integrationId}': allowTools and disallowTools are mutually exclusive; set at most one.`);
74272
74554
  }
74273
74555
  }
74274
- function buildRequests(integrations, catalog) {
74275
- const overrides = integrations;
74276
- const registrations = new Map(TOOLS.map((registration) => [registration.integrationId, registration]));
74556
+ /**
74557
+ * Rejects a `requireApproval` value that is not a boolean or an array of
74558
+ * string tool keys. The approval branches check for literal `true` or an
74559
+ * array, so a loosely typed value like `'true'` would otherwise disable
74560
+ * approval on MCP providers silently (and crash the HTTP path into
74561
+ * warn-and-skip) instead of gating tools as the author intended.
74562
+ */
74563
+ function validateRequireApproval(providers) {
74564
+ for (const [integrationId, providerOptions] of Object.entries(providers)) {
74565
+ const requireApproval = providerOptions.requireApproval;
74566
+ if (requireApproval === void 0 || typeof requireApproval === "boolean") continue;
74567
+ if (Array.isArray(requireApproval) && requireApproval.every((name) => typeof name === "string")) continue;
74568
+ throw new MastraConnectError("invalid_options", `Invalid options for '${integrationId}': requireApproval must be a boolean or an array of tool keys.`);
74569
+ }
74570
+ }
74571
+ /**
74572
+ * Rejects the removed `autoApproveTools` option by name. Discovered MCP tools
74573
+ * no longer require approval by default, so a loosely typed config still
74574
+ * carrying this key would otherwise be ignored silently and its tools would
74575
+ * run without the prompts the author expected.
74576
+ */
74577
+ function rejectRemovedAutoApproveTools(providers) {
74578
+ for (const [integrationId, providerOptions] of Object.entries(providers)) if ("autoApproveTools" in providerOptions) throw new MastraConnectError("invalid_options", `Invalid options for '${integrationId}': autoApproveTools was removed. Tools no longer require approval by default; opt in with requireApproval: true or a list of tool keys to gate.`);
74579
+ }
74580
+ function buildRequests(providers, catalog, catalogAvailable) {
74581
+ const { overrides, only } = providers;
74582
+ const registrations = new Map(PROVIDERS.map((registration) => [registration.integrationId, registration]));
74277
74583
  const catalogIds = new Set(catalog.map((integration) => integration.id));
74278
74584
  for (const integration of catalog) {
74279
74585
  if (!integration.capabilities.mcp) continue;
@@ -74283,9 +74589,14 @@ function buildRequests(integrations, catalog) {
74283
74589
  transport: "mcp"
74284
74590
  });
74285
74591
  }
74286
- for (const integrationId of Object.keys(overrides)) if (!registrations.has(integrationId) && !catalogIds.has(integrationId)) console.warn(`[@mastra/connect] Ignoring unknown integration override '${integrationId}'.`);
74592
+ const unknown = Object.keys(overrides).filter((integrationId) => !registrations.has(integrationId) && !catalogIds.has(integrationId) && !overrides[integrationId]?.disabled);
74593
+ if (unknown.length > 0) {
74594
+ if (catalogAvailable) throw new MastraConnectConfigError(`Unknown provider${unknown.length > 1 ? "s" : ""} in the providers option: ${unknown.map((id) => `'${id}'`).join(", ")}. Expected a checked-in provider id or a platform catalog integration id.`);
74595
+ for (const integrationId of unknown) console.warn(`[@mastra/connect] Platform catalog unavailable; cannot verify provider '${integrationId}'. Skipping it this resolution.`);
74596
+ }
74287
74597
  const requests = [];
74288
74598
  for (const registration of registrations.values()) {
74599
+ if (only !== void 0 && !only.has(registration.integrationId)) continue;
74289
74600
  const providerOptions = overrides[registration.integrationId] ?? {};
74290
74601
  if (providerOptions.disabled) continue;
74291
74602
  requests.push({
@@ -74301,6 +74612,7 @@ async function mapTools(connections, requests, options, client, mcpClients, reso
74301
74612
  const activeMcpKeys = /* @__PURE__ */ new Set();
74302
74613
  const result = {};
74303
74614
  const toolOwners = /* @__PURE__ */ new Map();
74615
+ const matchedDefaultEntries = /* @__PURE__ */ new Set();
74304
74616
  for (const request of requests) {
74305
74617
  const integrationId = request.registration.integrationId;
74306
74618
  let providerTools;
@@ -74320,16 +74632,19 @@ async function mapTools(connections, requests, options, client, mcpClients, reso
74320
74632
  connectionId: resolution.connectionId,
74321
74633
  allowTools: request.options.allowTools,
74322
74634
  disallowTools: request.options.disallowTools,
74323
- autoApproveTools: request.options.autoApproveTools,
74635
+ requireApproval: request.options.requireApproval,
74324
74636
  client,
74325
74637
  mcpClients,
74326
74638
  resolverId
74327
74639
  });
74328
- } else providerTools = request.registration.createTools({
74329
- connectionId: resolution.connectionId,
74330
- client: options.client,
74331
- ...providerFilterOptions(request.options)
74332
- });
74640
+ } else {
74641
+ providerTools = request.registration.createTools({
74642
+ connectionId: resolution.connectionId,
74643
+ client: options.client,
74644
+ ...providerFilterOptions(request.options)
74645
+ });
74646
+ applyProxyRequireApproval(providerTools, integrationId, request.options.requireApproval);
74647
+ }
74333
74648
  else if (request.registration.transport === "mcp") {
74334
74649
  for (const connection of resolution.connections) activeMcpKeys.add(`${integrationId}::${connection.id}`);
74335
74650
  providerTools = await buildMcpMultiConnectionTools({
@@ -74337,22 +74652,31 @@ async function mapTools(connections, requests, options, client, mcpClients, reso
74337
74652
  connections: resolution.connections,
74338
74653
  allowTools: request.options.allowTools,
74339
74654
  disallowTools: request.options.disallowTools,
74340
- autoApproveTools: request.options.autoApproveTools,
74655
+ requireApproval: request.options.requireApproval,
74341
74656
  client,
74342
74657
  mcpClients,
74343
74658
  resolverId
74344
74659
  });
74345
- } else providerTools = buildProxyMultiConnectionTools({
74346
- registration: request.registration,
74347
- connections: resolution.connections,
74348
- allowTools: request.options.allowTools,
74349
- disallowTools: request.options.disallowTools,
74350
- client: options.client
74351
- });
74660
+ } else {
74661
+ providerTools = buildProxyMultiConnectionTools({
74662
+ registration: request.registration,
74663
+ connections: resolution.connections,
74664
+ allowTools: request.options.allowTools,
74665
+ disallowTools: request.options.disallowTools,
74666
+ client: options.client
74667
+ });
74668
+ applyProxyRequireApproval(providerTools, integrationId, request.options.requireApproval, [listConnectionsToolKey(integrationId)]);
74669
+ }
74352
74670
  } catch (error) {
74671
+ if (error instanceof MastraConnectConfigError) throw error;
74353
74672
  console.warn(`[@mastra/connect] Skipping ${integrationId}: ${error instanceof Error ? error.message : String(error)}`);
74354
74673
  continue;
74355
74674
  }
74675
+ if (!(request.options.allowTools !== void 0 || request.options.disallowTools !== void 0) && (options.allowTools !== void 0 || options.disallowTools !== void 0)) providerTools = applyDefaultFilter(providerTools, options, integrationId, matchedDefaultEntries);
74676
+ if (request.options.requireApproval === void 0 && options.requireApproval !== void 0) {
74677
+ const policy = options.requireApproval;
74678
+ if (policy !== false) applyDefaultRequireApproval(providerTools, policy, integrationId, matchedDefaultEntries);
74679
+ }
74356
74680
  for (const toolKey of Object.keys(providerTools)) {
74357
74681
  const existingOwner = toolOwners.get(toolKey);
74358
74682
  if (existingOwner) throw new MastraConnectError("invalid_options", `Duplicate tool key '${toolKey}' from providers '${existingOwner}' and '${integrationId}'.`);
@@ -74360,22 +74684,114 @@ async function mapTools(connections, requests, options, client, mcpClients, reso
74360
74684
  }
74361
74685
  Object.assign(result, providerTools);
74362
74686
  }
74687
+ if (Object.keys(result).length > 0) {
74688
+ const defaultEntries = [
74689
+ ...options.allowTools ?? [],
74690
+ ...options.disallowTools ?? [],
74691
+ ...Array.isArray(options.requireApproval) ? options.requireApproval : []
74692
+ ];
74693
+ for (const entry of defaultEntries) if (!matchedDefaultEntries.has(entry)) console.warn(`[@mastra/connect] Top-level entry '${entry}' matched no tools on any resolved provider.`);
74694
+ }
74363
74695
  const staleClients = Array.from(mcpClients.entries()).filter(([key]) => !activeMcpKeys.has(key));
74364
74696
  for (const [key] of staleClients) mcpClients.delete(key);
74365
74697
  await Promise.allSettled(staleClients.map(([, entry]) => entry.client.disconnect()));
74366
74698
  return result;
74367
74699
  }
74368
74700
  /**
74369
- * Extracts whichever provider tool filter is set. Since `ToolsIntegrationOptions`
74701
+ * Applies the top-level default filter to a provider that set no filter of
74702
+ * its own. Lenient by design: the provider set is live, so a default entry
74703
+ * that matches nothing on this provider simply does not apply here. Entries
74704
+ * that match are recorded in `matchedEntries` so mapTools can warn about
74705
+ * defaults that matched nothing anywhere. The synthetic
74706
+ * `<provider>__list_connections` wrapper is never filtered by defaults,
74707
+ * matching the per-provider multi-connection behavior.
74708
+ */
74709
+ function applyDefaultFilter(providerTools, defaults, integrationId, matchedEntries) {
74710
+ const listToolKey = listConnectionsToolKey(integrationId);
74711
+ const matchers = (defaults.allowTools ?? defaults.disallowTools ?? []).map((entry) => ({
74712
+ entry,
74713
+ matches: compileToolMatcher([entry])
74714
+ }));
74715
+ const filtered = {};
74716
+ for (const [key, tool] of Object.entries(providerTools)) {
74717
+ if (key === listToolKey) {
74718
+ filtered[key] = tool;
74719
+ continue;
74720
+ }
74721
+ let matchedAny = false;
74722
+ for (const { entry, matches } of matchers) if (matches(key)) {
74723
+ matchedEntries.add(entry);
74724
+ matchedAny = true;
74725
+ }
74726
+ if (defaults.allowTools !== void 0 ? matchedAny : !matchedAny) filtered[key] = tool;
74727
+ }
74728
+ return filtered;
74729
+ }
74730
+ /**
74731
+ * Applies the top-level default `requireApproval` policy to a provider that
74732
+ * set no policy of its own. `true` gates every tool except the synthetic
74733
+ * `<provider>__list_connections` wrapper; an array gates matching keys with
74734
+ * the same lenient semantics as {@link applyDefaultFilter}.
74735
+ */
74736
+ function applyDefaultRequireApproval(providerTools, policy, integrationId, matchedEntries) {
74737
+ const listToolKey = listConnectionsToolKey(integrationId);
74738
+ if (policy === true) {
74739
+ for (const [key, tool] of Object.entries(providerTools)) {
74740
+ if (key === listToolKey) continue;
74741
+ tool.requireApproval = true;
74742
+ }
74743
+ return;
74744
+ }
74745
+ const matchers = policy.map((entry) => ({
74746
+ entry,
74747
+ matches: compileToolMatcher([entry])
74748
+ }));
74749
+ for (const [key, tool] of Object.entries(providerTools)) {
74750
+ if (key === listToolKey) continue;
74751
+ for (const { entry, matches } of matchers) if (matches(key)) {
74752
+ matchedEntries.add(entry);
74753
+ tool.requireApproval = true;
74754
+ }
74755
+ }
74756
+ }
74757
+ /**
74758
+ * Extracts whichever provider tool filter is set. Since `ToolsProviderOptions`
74370
74759
  * is an XOR union and tools() validates co-occurrence up front, at most one
74371
74760
  * of the two will ever be defined here.
74372
74761
  */
74373
74762
  function providerFilterOptions(options) {
74374
74763
  return options.allowTools !== void 0 ? { allowTools: options.allowTools } : options.disallowTools !== void 0 ? { disallowTools: options.disallowTools } : {};
74375
74764
  }
74765
+ /**
74766
+ * Applies a per-provider `requireApproval` policy to a checked-in HTTP
74767
+ * toolset by marking the selected tools. `true` gates every provider tool
74768
+ * (but never the synthetic `<provider>__list_connections` wrapper tool,
74769
+ * matching the MCP paths, where only server-discovered tools are gated);
74770
+ * an array gates the listed keys — entries containing `*` are globs,
74771
+ * expanded against the provider tools minus the synthetic wrapper so a
74772
+ * broad glob behaves like `true` — and rejects unknown names and dead
74773
+ * globs with the same `invalid_options` error MCP discovery raises, so a
74774
+ * typo never silently widens access.
74775
+ */
74776
+ function applyProxyRequireApproval(providerTools, integrationId, requireApproval, excludeKeys = []) {
74777
+ if (!requireApproval) return;
74778
+ const excluded = new Set(excludeKeys);
74779
+ if (requireApproval === true) {
74780
+ for (const [toolKey, tool] of Object.entries(providerTools)) {
74781
+ if (excluded.has(toolKey)) continue;
74782
+ tool.requireApproval = true;
74783
+ }
74784
+ return;
74785
+ }
74786
+ const known = Object.keys(providerTools);
74787
+ const expanded = expandToolPatterns(requireApproval, known.filter((key) => !excluded.has(key)), `requireApproval for '${integrationId}'`);
74788
+ const unknown = expanded.filter((name) => !known.includes(name));
74789
+ if (unknown.length > 0) throw new MastraConnectConfigError(`Unknown tool name(s) in requireApproval for '${integrationId}': ${unknown.join(", ")}. Known tools: ${known.join(", ")}.`);
74790
+ for (const name of expanded) providerTools[name].requireApproval = true;
74791
+ }
74376
74792
  async function discoverMcpTools(input) {
74377
- const { registration, connectionId, allowTools, disallowTools, autoApproveTools, client, mcpClients, resolverId } = input;
74378
- const autoApproved = new Set(autoApproveTools ?? []);
74793
+ const { registration, connectionId, allowTools, disallowTools, requireApproval, client, mcpClients, resolverId } = input;
74794
+ const requireApprovalFor = Array.isArray(requireApproval) ? compileToolMatcher(requireApproval) : void 0;
74379
74795
  const cacheKey = `${registration.integrationId}::${connectionId}`;
74380
74796
  let entry = mcpClients.get(cacheKey);
74381
74797
  if (!entry) {
@@ -74387,7 +74803,7 @@ async function discoverMcpTools(input) {
74387
74803
  id: `mastra-connect-${resolverId}-${registration.integrationId}-${connectionId}`,
74388
74804
  servers: { [registration.integrationId]: {
74389
74805
  ...transport,
74390
- requireToolApproval: ({ toolName }) => !autoApproved.has(`${registration.integrationId}_${String(toolName)}`)
74806
+ ...requireApproval === true ? { requireToolApproval: true } : requireApprovalFor ? { requireToolApproval: ({ toolName }) => requireApprovalFor(`${registration.integrationId}_${String(toolName)}`) } : {}
74391
74807
  } }
74392
74808
  })
74393
74809
  };
@@ -74396,31 +74812,16 @@ async function discoverMcpTools(input) {
74396
74812
  const discovery = await entry.client.listToolsWithErrors();
74397
74813
  const error = discovery.errors[registration.integrationId];
74398
74814
  if (error) throw new Error(`MCP tool discovery failed: ${error}`);
74399
- const unknown = [...autoApproved].filter((name) => !(name in discovery.tools));
74400
- if (unknown.length > 0) throw new MastraConnectError("invalid_options", `Unknown tool name(s) in autoApproveTools for '${registration.integrationId}': ${unknown.join(", ")}. Known tools: ${Object.keys(discovery.tools).join(", ")}.`);
74815
+ if (Array.isArray(requireApproval)) {
74816
+ const unknown = expandToolPatterns(requireApproval, Object.keys(discovery.tools), `requireApproval for '${registration.integrationId}'`).filter((name) => !(name in discovery.tools));
74817
+ if (unknown.length > 0) throw new MastraConnectConfigError(`Unknown tool name(s) in requireApproval for '${registration.integrationId}': ${unknown.join(", ")}. Known tools: ${Object.keys(discovery.tools).join(", ")}.`);
74818
+ }
74401
74819
  return applyToolFilter(discovery.tools, {
74402
74820
  allowTools,
74403
74821
  disallowTools
74404
74822
  });
74405
74823
  }
74406
74824
  //#endregion
74407
- //#region src/connect.ts
74408
- /**
74409
- * @deprecated Use `tools` from `@mastra/connect` instead. This module is a
74410
- * thin re-export retained for one release cycle so downstream consumers keep
74411
- * working; it will be removed in the next minor.
74412
- */
74413
- /**
74414
- * @deprecated Renamed to {@link tools}.
74415
- *
74416
- * `connect(options)` is a drop-in alias for `tools(options)`. Prefer `tools`
74417
- * from `@mastra/connect` in new code; this export will be removed in the next
74418
- * minor version.
74419
- */
74420
- function connect(options = {}) {
74421
- return tools(options);
74422
- }
74423
- //#endregion
74424
74825
  //#region src/channels.ts
74425
74826
  const DEFAULT_TTL_MS = 3e4;
74426
74827
  /** Minimum wait after a failed platform fetch before another background revalidation. */
@@ -74433,7 +74834,7 @@ const FAILURE_COOLDOWN_MS = 3e4;
74433
74834
  * Discord) are constructed once, up front and credential-less, so their
74434
74835
  * webhook/OAuth routes can mount at Mastra construction. Each resolution
74435
74836
  * fetches the project's connections and late-binds credentials into the live
74436
- * instances: integrations with an active connection appear in the resolved
74837
+ * instances: providers with an active connection appear in the resolved
74437
74838
  * map, others don't — so connecting a new channel on the platform takes
74438
74839
  * effect without redeploying the app.
74439
74840
  *
@@ -74458,12 +74859,17 @@ async function channels(options = {}) {
74458
74859
  const projectId = options.projectId?.trim() || process.env.MASTRA_PROJECT_ID?.trim();
74459
74860
  if (!projectId) throw new MastraConnectError("missing_project_id", "Missing project id: set MASTRA_PROJECT_ID or pass projectId.");
74460
74861
  if (options.ttlMs !== void 0 && (!Number.isFinite(options.ttlMs) || options.ttlMs < 0)) throw new MastraConnectError("invalid_options", `Invalid ttlMs (${options.ttlMs}): expected a finite number of milliseconds >= 0.`);
74461
- validateIntegrationOverrides(options.integrations);
74862
+ const { overrides: providerOverrides, only } = normalizeChannelProviders(options.providers);
74863
+ validateProviderIds(providerOverrides);
74864
+ const knownChannelIds = new Set(CHANNELS.map((registration) => registration.integrationId));
74865
+ const unknownChannelIds = Object.keys(providerOverrides).filter((integrationId) => !knownChannelIds.has(integrationId) && !providerOverrides[integrationId]?.disabled);
74866
+ if (unknownChannelIds.length > 0) throw new MastraConnectError("invalid_options", `Unknown channel${unknownChannelIds.length > 1 ? "s" : ""} in the providers option: ${unknownChannelIds.map((id) => `'${id}'`).join(", ")}. Known channels: ${[...knownChannelIds].join(", ")}.`);
74462
74867
  const ttlMs = options.ttlMs ?? DEFAULT_TTL_MS;
74463
74868
  const client = resolveClient(options.client);
74464
74869
  const states = [];
74465
74870
  for (const registration of CHANNELS) {
74466
- const overrides = options.integrations?.[registration.integrationId] ?? {};
74871
+ if (only !== void 0 && !only.has(registration.integrationId)) continue;
74872
+ const overrides = providerOverrides[registration.integrationId] ?? {};
74467
74873
  if (overrides.disabled) continue;
74468
74874
  const state = {
74469
74875
  registration,
@@ -74499,6 +74905,7 @@ async function channels(options = {}) {
74499
74905
  let cache;
74500
74906
  let inflight;
74501
74907
  let lastFailureAt;
74908
+ let warnedStaleSlackConnection = false;
74502
74909
  const buildSnapshot = async () => {
74503
74910
  let connections;
74504
74911
  try {
@@ -74509,9 +74916,13 @@ async function channels(options = {}) {
74509
74916
  }
74510
74917
  const byIntegrationId = groupByIntegrationId(connections);
74511
74918
  const providers = {};
74919
+ if (!warnedStaleSlackConnection && states.some((state) => state.registration.integrationId === "slack-channels") && (byIntegrationId.get("slack")?.length ?? 0) > 0 && (byIntegrationId.get("slack-channels")?.length ?? 0) === 0) {
74920
+ warnedStaleSlackConnection = true;
74921
+ console.warn(`[@mastra/connect] Project ${projectId} has an active 'slack' connection but no 'slack-channels' connection: the Slack channel is now keyed off 'slack-channels'. Connect Slack again as 'slack-channels' to restore it; the existing 'slack' connection still powers the generated Slack tools.`);
74922
+ }
74512
74923
  for (const state of states) {
74513
74924
  const integrationId = state.registration.integrationId;
74514
- const overrides = options.integrations?.[integrationId] ?? {};
74925
+ const overrides = providerOverrides[integrationId] ?? {};
74515
74926
  const candidates = byIntegrationId.get(integrationId) ?? [];
74516
74927
  const connectionId = candidates.length === 0 ? void 0 : selectChannelConnection(integrationId, overrides.connectionId, candidates);
74517
74928
  state.connectionId = connectionId;
@@ -74558,9 +74969,6 @@ async function channels(options = {}) {
74558
74969
  };
74559
74970
  const invocable = ((_context) => resolve());
74560
74971
  invocable.getRoutes = () => states.flatMap((state) => state.instance.provider.getRoutes());
74561
- invocable.invalidate = () => {
74562
- cache = void 0;
74563
- };
74564
74972
  invocable.refresh = refresh;
74565
74973
  invocable.disconnect = async () => {
74566
74974
  cache = void 0;
@@ -74568,15 +74976,73 @@ async function channels(options = {}) {
74568
74976
  return invocable;
74569
74977
  }
74570
74978
  /**
74979
+ * Friendly channel-key aliases. The Slack channel is keyed `slack-channels`
74980
+ * on the platform (plain `slack` names the Slack tools provider), but inside
74981
+ * a channels() config `slack` is unambiguous — accept it and canonicalize to
74982
+ * the platform key for registration and connection lookup.
74983
+ */
74984
+ const CHANNEL_KEY_ALIASES = { slack: "slack-channels" };
74985
+ const canonicalChannelId = (id) => CHANNEL_KEY_ALIASES[id] ?? id;
74986
+ /** Throws when two option keys (e.g. `slack` and `slack-channels`) name the same channel. */
74987
+ function rejectAliasCollision(sourceKeys, canonical, key) {
74988
+ const existing = sourceKeys[canonical];
74989
+ if (existing === void 0) return;
74990
+ throw new MastraConnectError("invalid_options", existing === key ? `Duplicate provider '${key}' in providers array.` : `Both '${existing}' and '${key}' name the '${canonical}' channel in the providers option; use one key.`);
74991
+ }
74992
+ /**
74993
+ * Turns the two accepted `providers` shapes into the internal form, mirroring
74994
+ * `tools()`. The array form becomes an allowlist with default options; the
74995
+ * record form expands boolean shorthands (`true` → `{}`, `false` → an
74996
+ * internal exclusion marker). Alias keys canonicalize first, so `slack` and
74997
+ * `slack-channels` configure the same channel (and collide loudly). Malformed
74998
+ * inputs throw at channels() time.
74999
+ */
75000
+ function normalizeChannelProviders(providers) {
75001
+ if (providers === void 0) return {
75002
+ overrides: {},
75003
+ only: void 0
75004
+ };
75005
+ const sourceKeys = {};
75006
+ if (Array.isArray(providers)) {
75007
+ const overrides = {};
75008
+ for (const entry of providers) {
75009
+ if (typeof entry !== "string") throw new MastraConnectError("invalid_options", `Invalid providers entry: expected a string channel id, got ${typeof entry}.`);
75010
+ const canonical = canonicalChannelId(entry);
75011
+ rejectAliasCollision(sourceKeys, canonical, entry);
75012
+ sourceKeys[canonical] = entry;
75013
+ overrides[canonical] = {};
75014
+ }
75015
+ return {
75016
+ overrides,
75017
+ only: new Set(Object.keys(overrides))
75018
+ };
75019
+ }
75020
+ const overrides = {};
75021
+ for (const [providerId, value] of Object.entries(providers)) {
75022
+ if (value === void 0) continue;
75023
+ const canonical = canonicalChannelId(providerId);
75024
+ rejectAliasCollision(sourceKeys, canonical, providerId);
75025
+ sourceKeys[canonical] = providerId;
75026
+ if (value === true) overrides[canonical] = {};
75027
+ else if (value === false) overrides[canonical] = { disabled: true };
75028
+ else if (typeof value === "object" && value !== null && !Array.isArray(value)) overrides[canonical] = value;
75029
+ else throw new MastraConnectError("invalid_options", `Invalid providers entry for '${providerId}': expected true, false, or an options object, got ${value === null ? "null" : Array.isArray(value) ? "an array" : typeof value}.`);
75030
+ }
75031
+ return {
75032
+ overrides,
75033
+ only: void 0
75034
+ };
75035
+ }
75036
+ /**
74571
75037
  * Selects the connection `channels()` should use for one provider.
74572
75038
  *
74573
- * - Pinned `connectionId` (from `integrations.<id>.connectionId`) wins, but is
75039
+ * - Pinned `connectionId` (from `providers.<id>.connectionId`) wins, but is
74574
75040
  * skipped if the pinned id isn't attached to the project or the connection
74575
75041
  * isn't `active`.
74576
75042
  * - Otherwise, the single active connection is used.
74577
75043
  * - When more than one active connection exists, this warns naming the chosen
74578
75044
  * id and picks the first active connection. There is no env-var fallback;
74579
- * pin explicitly with `integrations.<id>.connectionId` when the deterministic
75045
+ * pin explicitly with `providers.<id>.connectionId` when the deterministic
74580
75046
  * choice matters.
74581
75047
  */
74582
75048
  function selectChannelConnection(integrationId, pinnedId, candidates) {
@@ -74605,7 +75071,7 @@ function selectChannelConnection(integrationId, pinnedId, candidates) {
74605
75071
  if (active.length === 1) return active[0].id;
74606
75072
  const chosen = active[0].id;
74607
75073
  const others = active.slice(1).map((connection) => connection.id).join(", ");
74608
- console.warn(`[@mastra/connect] ${integrationId} channel: found ${active.length} active connections; using ${chosen}. Ignoring ${others}. Pin one with integrations.${integrationId}.connectionId to silence this warning.`);
75074
+ console.warn(`[@mastra/connect] ${integrationId} channel: found ${active.length} active connections; using ${chosen}. Ignoring ${others}. Pin one with providers.${integrationId}.connectionId to silence this warning.`);
74609
75075
  return chosen;
74610
75076
  }
74611
75077
  //#endregion
@@ -74618,121 +75084,11 @@ async function credential(connectionId, options) {
74618
75084
  return getCredential(resolveClient(options?.client), connectionId);
74619
75085
  }
74620
75086
  //#endregion
74621
- //#region src/environment.ts
74622
- function credentialToken(credential) {
74623
- return credential.type === "oauth2" ? credential.accessToken : credential.apiKey;
74624
- }
74625
- /**
74626
- * Wires git's credential helper to read the token from the environment at use
74627
- * time, so the secret lives in the process env rather than in git config or
74628
- * remote URLs. `gh` needs no setup: it honors GH_TOKEN directly.
74629
- */
74630
- const GITHUB_GIT_CREDENTIAL_HELPER = "!f() { echo username=x-access-token; echo \"password=$GH_TOKEN\"; }; f";
74631
- /** Providers that know how to materialize sandbox credentials. */
74632
- const ENVIRONMENT_CONTRIBUTORS = [{
74633
- integrationId: "github",
74634
- envVar: "MASTRA_GITHUB_CONNECTION_ID",
74635
- build(credential) {
74636
- const token = credentialToken(credential);
74637
- return {
74638
- env: {
74639
- GH_TOKEN: token,
74640
- GITHUB_TOKEN: token
74641
- },
74642
- onStart: async ({ sandbox }) => {
74643
- if (!sandbox.executeCommand) {
74644
- console.warn("[@mastra/connect] github environment: sandbox does not support executeCommand; skipping git credential setup (gh still works via GH_TOKEN).");
74645
- return;
74646
- }
74647
- await sandbox.executeCommand("git", [
74648
- "config",
74649
- "--global",
74650
- "credential.https://github.com.helper",
74651
- GITHUB_GIT_CREDENTIAL_HELPER
74652
- ]);
74653
- }
74654
- };
74655
- }
74656
- }];
74657
- /**
74658
- * Resolves the project's Platform connections into sandbox credentials:
74659
- * environment variables plus a start hook that finishes in-sandbox setup.
74660
- * Currently GitHub-aware (`GH_TOKEN`/`GITHUB_TOKEN` + git credential helper);
74661
- * more providers plug in over time.
74662
- *
74663
- * Connection resolution matches `connect()`: a per-integration `connectionId`
74664
- * or the provider's `MASTRA_*_CONNECTION_ID` env var wins, else a single
74665
- * active connection; ambiguity, needs_reauth, and credential-fetch failures
74666
- * warn and skip that provider. Configuration errors (missing project id,
74667
- * malformed integration id) throw here so they surface at startup.
74668
- *
74669
- * The returned `env` is a snapshot: call `environment()` again for a fresh
74670
- * token when starting new sandboxes.
74671
- *
74672
- * @example
74673
- * const { env, onStart } = await environment({ projectId });
74674
- * const sandbox = new E2BSandbox({ env, onStart });
74675
- * // in the sandbox: `gh pr list`, `git clone https://github.com/org/repo` just work
74676
- */
74677
- async function environment(options = {}) {
74678
- const projectId = options.projectId?.trim() || process.env.MASTRA_PROJECT_ID?.trim();
74679
- if (!projectId) throw new MastraConnectError("missing_project_id", "Missing project id: set MASTRA_PROJECT_ID or pass projectId.");
74680
- validateIntegrationOverrides(options.integrations);
74681
- const client = resolveClient(options.client);
74682
- const byIntegrationId = groupByIntegrationId(await listProjectConnections(client, projectId));
74683
- const env = {};
74684
- const hooks = [];
74685
- for (const contributor of ENVIRONMENT_CONTRIBUTORS) {
74686
- const integrationId = contributor.integrationId;
74687
- const overrides = options.integrations?.[integrationId] ?? {};
74688
- if (overrides.disabled) continue;
74689
- const candidates = byIntegrationId.get(integrationId) ?? [];
74690
- if (candidates.length === 0) continue;
74691
- const connectionId = resolveConnection({
74692
- integrationId,
74693
- envVar: contributor.envVar,
74694
- connectionId: overrides.connectionId
74695
- }, candidates);
74696
- if (!connectionId) continue;
74697
- let credential;
74698
- try {
74699
- credential = await getCredential(client, connectionId);
74700
- } catch (error) {
74701
- console.warn(`[@mastra/connect] Skipping ${integrationId} environment: ${error instanceof Error ? error.message : String(error)}`);
74702
- continue;
74703
- }
74704
- const contribution = contributor.build(credential);
74705
- for (const [key, value] of Object.entries(contribution.env)) {
74706
- if (key in env) console.warn(`[@mastra/connect] ${integrationId} environment overwrites env var '${key}' set by an earlier provider.`);
74707
- env[key] = value;
74708
- }
74709
- if (contribution.onStart) hooks.push({
74710
- integrationId,
74711
- hook: contribution.onStart
74712
- });
74713
- }
74714
- const onStart = async (args) => {
74715
- for (const { hook } of hooks) await hook(args);
74716
- };
74717
- return {
74718
- env,
74719
- onStart
74720
- };
74721
- }
74722
- //#endregion
74723
75087
  exports.CHANNELS = CHANNELS;
74724
75088
  exports.MastraConnectError = MastraConnectError;
74725
75089
  exports.PROVIDERS = PROVIDERS;
74726
- exports.TOOLS = TOOLS;
74727
- exports.applyAllowTools = applyAllowTools;
74728
75090
  exports.channels = channels;
74729
- exports.connect = connect;
74730
75091
  exports.credential = credential;
74731
- exports.defineProxyTool = defineProxyTool;
74732
- exports.environment = environment;
74733
- exports.findChannelRegistration = findChannelRegistration;
74734
- exports.findRegistration = findRegistration;
74735
- exports.resolveConnectionId = resolveConnectionId;
74736
75092
  exports.tools = tools;
74737
75093
 
74738
75094
  //# sourceMappingURL=index.cjs.map