@dereekb/firebase-server 13.13.0 → 13.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/mcp/index.cjs.js CHANGED
@@ -117,13 +117,13 @@ function _define_property$7(obj, key, value) {
117
117
  * NestJS injection token for the optional {@link McpAuthRoleReader} provider.
118
118
  */ var MCP_AUTH_ROLE_READER = 'MCP_AUTH_ROLE_READER';
119
119
 
120
- function _type_of$2(obj) {
120
+ function _type_of$3(obj) {
121
121
  "@swc/helpers - typeof";
122
122
  return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj;
123
123
  }
124
124
  function __decorate(decorators, target, key, desc) {
125
125
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
126
- if ((typeof Reflect === "undefined" ? "undefined" : _type_of$2(Reflect)) === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
126
+ if ((typeof Reflect === "undefined" ? "undefined" : _type_of$3(Reflect)) === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
127
127
  else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
128
128
  return c > 3 && r && Object.defineProperty(target, key, r), r;
129
129
  }
@@ -192,7 +192,36 @@ function _class_call_check$4(instance, Constructor) {
192
192
  return isDefault ? "".concat(modelType, ".").concat(call, "._") : "".concat(modelType, ".").concat(call, ".").concat(specifier);
193
193
  }
194
194
 
195
- function _instanceof(left, right) {
195
+ function asyncGeneratorStep$5(gen, resolve, reject, _next, _throw, key, arg) {
196
+ try {
197
+ var info = gen[key](arg);
198
+ var value = info.value;
199
+ } catch (error) {
200
+ reject(error);
201
+ return;
202
+ }
203
+ if (info.done) {
204
+ resolve(value);
205
+ } else {
206
+ Promise.resolve(value).then(_next, _throw);
207
+ }
208
+ }
209
+ function _async_to_generator$5(fn) {
210
+ return function() {
211
+ var self = this, args = arguments;
212
+ return new Promise(function(resolve, reject) {
213
+ var gen = fn.apply(self, args);
214
+ function _next(value) {
215
+ asyncGeneratorStep$5(gen, resolve, reject, _next, _throw, "next", value);
216
+ }
217
+ function _throw(err) {
218
+ asyncGeneratorStep$5(gen, resolve, reject, _next, _throw, "throw", err);
219
+ }
220
+ _next(undefined);
221
+ });
222
+ };
223
+ }
224
+ function _instanceof$1(left, right) {
196
225
  "@swc/helpers - instanceof";
197
226
  if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) {
198
227
  return !!right[Symbol.hasInstance](left);
@@ -200,6 +229,105 @@ function _instanceof(left, right) {
200
229
  return left instanceof right;
201
230
  }
202
231
  }
232
+ function _ts_generator$5(thisArg, body) {
233
+ var f, y, t, _ = {
234
+ label: 0,
235
+ sent: function() {
236
+ if (t[0] & 1) throw t[1];
237
+ return t[1];
238
+ },
239
+ trys: [],
240
+ ops: []
241
+ }, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype), d = Object.defineProperty;
242
+ return d(g, "next", {
243
+ value: verb(0)
244
+ }), d(g, "throw", {
245
+ value: verb(1)
246
+ }), d(g, "return", {
247
+ value: verb(2)
248
+ }), typeof Symbol === "function" && d(g, Symbol.iterator, {
249
+ value: function() {
250
+ return this;
251
+ }
252
+ }), g;
253
+ function verb(n) {
254
+ return function(v) {
255
+ return step([
256
+ n,
257
+ v
258
+ ]);
259
+ };
260
+ }
261
+ function step(op) {
262
+ if (f) throw new TypeError("Generator is already executing.");
263
+ while(g && (g = 0, op[0] && (_ = 0)), _)try {
264
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
265
+ if (y = 0, t) op = [
266
+ op[0] & 2,
267
+ t.value
268
+ ];
269
+ switch(op[0]){
270
+ case 0:
271
+ case 1:
272
+ t = op;
273
+ break;
274
+ case 4:
275
+ _.label++;
276
+ return {
277
+ value: op[1],
278
+ done: false
279
+ };
280
+ case 5:
281
+ _.label++;
282
+ y = op[1];
283
+ op = [
284
+ 0
285
+ ];
286
+ continue;
287
+ case 7:
288
+ op = _.ops.pop();
289
+ _.trys.pop();
290
+ continue;
291
+ default:
292
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
293
+ _ = 0;
294
+ continue;
295
+ }
296
+ if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
297
+ _.label = op[1];
298
+ break;
299
+ }
300
+ if (op[0] === 6 && _.label < t[1]) {
301
+ _.label = t[1];
302
+ t = op;
303
+ break;
304
+ }
305
+ if (t && _.label < t[2]) {
306
+ _.label = t[2];
307
+ _.ops.push(op);
308
+ break;
309
+ }
310
+ if (t[2]) _.ops.pop();
311
+ _.trys.pop();
312
+ continue;
313
+ }
314
+ op = body.call(thisArg, _);
315
+ } catch (e) {
316
+ op = [
317
+ 6,
318
+ e
319
+ ];
320
+ y = 0;
321
+ } finally{
322
+ f = t = 0;
323
+ }
324
+ if (op[0] & 5) throw op[1];
325
+ return {
326
+ value: op[0] ? op[1] : void 0,
327
+ done: true
328
+ };
329
+ }
330
+ }
203
331
  /**
204
332
  * Default structured value emitted by MCP when a handler returns `undefined`.
205
333
  *
@@ -212,46 +340,84 @@ function _instanceof(left, right) {
212
340
  /**
213
341
  * Resolves a dispatch result + handler API details into the MCP `CallToolResult` shape.
214
342
  *
343
+ * When `mcp.mapSuccessfulResult` is set, the raw result is first mapped (async-capable) to the value
344
+ * exposed via MCP; the tiers and the default path then operate on the mapped value. The tier
345
+ * callbacks receive `(value, context)` where `context` carries both the raw + mapped values + params.
346
+ *
215
347
  * Three-tier resolution as documented on {@link OnCallModelFunctionApiDetails.mcp}:
216
348
  *
217
349
  * - **Tier 3** — when `mcp.formatResponse` is set, its return value is used verbatim.
218
350
  * - **Tier 2** — when `mcp.summarizeResponse` is set, the summary string is wrapped into a
219
- * single text content block with the raw `result` exposed as `structuredContent`.
220
- * - **Tier 1** — default: JSON-stringify `result` as a single text content block, also
221
- * exposing the raw value as `structuredContent`.
351
+ * single text content block with the (mapped) value exposed as `structuredContent`.
352
+ * - **Tier 1** — default: JSON-stringify the (mapped) value as a single text content block, also
353
+ * exposing it as `structuredContent`.
222
354
  *
223
- * @param result - The handler's return value.
355
+ * @param result - The handler's raw return value.
224
356
  * @param params - The {@link OnCallTypedModelParams} that were dispatched.
225
- * @param details - The handler-level API details (carries Tier 2/3 formatters).
357
+ * @param details - The handler-level API details (carries the mapper + Tier 2/3 formatters).
226
358
  * @returns The MCP tool response content.
227
359
  */ function formatMcpToolResponse(result, params, details) {
228
- var mcp = details === null || details === void 0 ? void 0 : details.mcp;
229
- var response;
230
- if (mcp === null || mcp === void 0 ? void 0 : mcp.formatResponse) {
231
- response = mcp.formatResponse(result, params);
232
- } else if (mcp === null || mcp === void 0 ? void 0 : mcp.summarizeResponse) {
233
- var summary = mcp.summarizeResponse(result, params);
234
- response = {
235
- content: [
236
- {
237
- type: 'text',
238
- text: summary
239
- }
240
- ],
241
- structuredContent: result
242
- };
243
- } else {
244
- response = {
245
- content: [
246
- {
247
- type: 'text',
248
- text: stringifyResult(result)
249
- }
250
- ],
251
- structuredContent: result === undefined ? DEFAULT_VOID_MCP_SUCCESS_VALUE : result
252
- };
253
- }
254
- return response;
360
+ return _async_to_generator$5(function() {
361
+ var mcp, value, _tmp, context, response, summary;
362
+ return _ts_generator$5(this, function(_state) {
363
+ switch(_state.label){
364
+ case 0:
365
+ mcp = details === null || details === void 0 ? void 0 : details.mcp;
366
+ if (!(mcp === null || mcp === void 0 ? void 0 : mcp.mapSuccessfulResult)) return [
367
+ 3,
368
+ 2
369
+ ];
370
+ return [
371
+ 4,
372
+ mcp.mapSuccessfulResult(result, params)
373
+ ];
374
+ case 1:
375
+ _tmp = _state.sent();
376
+ return [
377
+ 3,
378
+ 3
379
+ ];
380
+ case 2:
381
+ _tmp = result;
382
+ _state.label = 3;
383
+ case 3:
384
+ value = _tmp;
385
+ context = {
386
+ raw: result,
387
+ value: value,
388
+ params: params
389
+ };
390
+ if (mcp === null || mcp === void 0 ? void 0 : mcp.formatResponse) {
391
+ response = mcp.formatResponse(value, context);
392
+ } else if (mcp === null || mcp === void 0 ? void 0 : mcp.summarizeResponse) {
393
+ summary = mcp.summarizeResponse(value, context);
394
+ response = {
395
+ content: [
396
+ {
397
+ type: 'text',
398
+ text: summary
399
+ }
400
+ ],
401
+ structuredContent: value
402
+ };
403
+ } else {
404
+ response = {
405
+ content: [
406
+ {
407
+ type: 'text',
408
+ text: stringifyResult(value)
409
+ }
410
+ ],
411
+ structuredContent: value === undefined ? DEFAULT_VOID_MCP_SUCCESS_VALUE : value
412
+ };
413
+ }
414
+ return [
415
+ 2,
416
+ response
417
+ ];
418
+ }
419
+ });
420
+ })();
255
421
  }
256
422
  /**
257
423
  * Converts an error thrown from the dispatch chain into the MCP error response shape.
@@ -259,7 +425,7 @@ function _instanceof(left, right) {
259
425
  * @param error - The thrown error.
260
426
  * @returns An MCP tool response with `isError: true` and the error message as a text block.
261
427
  */ function formatMcpToolErrorResponse(error) {
262
- var message = _instanceof(error, Error) ? error.message : String(error);
428
+ var message = _instanceof$1(error, Error) ? error.message : String(error);
263
429
  return {
264
430
  isError: true,
265
431
  content: [
@@ -357,15 +523,15 @@ function stringifyResult(result) {
357
523
  return firebase.callModelOidcScopeForCallType(callType);
358
524
  }
359
525
 
360
- function _array_like_to_array$6(arr, len) {
526
+ function _array_like_to_array$7(arr, len) {
361
527
  if (len == null || len > arr.length) len = arr.length;
362
528
  for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
363
529
  return arr2;
364
530
  }
365
- function _array_with_holes$2(arr) {
531
+ function _array_with_holes$3(arr) {
366
532
  if (Array.isArray(arr)) return arr;
367
533
  }
368
- function _iterable_to_array_limit$2(arr, i) {
534
+ function _iterable_to_array_limit$3(arr, i) {
369
535
  var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
370
536
  if (_i == null) return;
371
537
  var _arr = [];
@@ -389,23 +555,23 @@ function _iterable_to_array_limit$2(arr, i) {
389
555
  }
390
556
  return _arr;
391
557
  }
392
- function _non_iterable_rest$2() {
558
+ function _non_iterable_rest$3() {
393
559
  throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
394
560
  }
395
- function _sliced_to_array$2(arr, i) {
396
- return _array_with_holes$2(arr) || _iterable_to_array_limit$2(arr, i) || _unsupported_iterable_to_array$6(arr, i) || _non_iterable_rest$2();
561
+ function _sliced_to_array$3(arr, i) {
562
+ return _array_with_holes$3(arr) || _iterable_to_array_limit$3(arr, i) || _unsupported_iterable_to_array$7(arr, i) || _non_iterable_rest$3();
397
563
  }
398
- function _type_of$1(obj) {
564
+ function _type_of$2(obj) {
399
565
  "@swc/helpers - typeof";
400
566
  return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj;
401
567
  }
402
- function _unsupported_iterable_to_array$6(o, minLen) {
568
+ function _unsupported_iterable_to_array$7(o, minLen) {
403
569
  if (!o) return;
404
- if (typeof o === "string") return _array_like_to_array$6(o, minLen);
570
+ if (typeof o === "string") return _array_like_to_array$7(o, minLen);
405
571
  var n = Object.prototype.toString.call(o).slice(8, -1);
406
572
  if (n === "Object" && o.constructor) n = o.constructor.name;
407
573
  if (n === "Map" || n === "Set") return Array.from(n);
408
- if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$6(o, minLen);
574
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$7(o, minLen);
409
575
  }
410
576
  /**
411
577
  * Default `toJsonSchema()` options.
@@ -458,18 +624,124 @@ function _unsupported_iterable_to_array$6(o, minLen) {
458
624
  * The default specifier key used when a handler is not behind a specifier router.
459
625
  */ var DEFAULT_SPECIFIER_KEY = '_';
460
626
  /**
461
- * Builds the MCP tool name for a (modelType, callType, specifier) triple.
627
+ * Soft limit for an MCP tool name. Names longer than this still register, but the generator
628
+ * surfaces a `name_length_warning` so the drift toward the hard cap is visible at boot / build.
629
+ */ var MCP_TOOL_NAME_WARN_LENGTH = 55;
630
+ /**
631
+ * Hard limit for an MCP tool name. Remote MCP clients reject a `tools/list` payload that contains
632
+ * any tool whose `name` exceeds this (`FrontendRemoteMcpToolDefinition.name: String should have at
633
+ * most 64 characters`), which fails the whole connection. Names over this are not registered.
634
+ */ var MCP_TOOL_NAME_MAX_LENGTH = 64;
635
+ /**
636
+ * Classifies a tool name's length against the soft/hard MCP name-length limits.
637
+ *
638
+ * Shared by the runtime generator and the build-time manifest renderer so both apply the
639
+ * same thresholds and never drift.
640
+ *
641
+ * @param name - The fully-resolved tool name (including any per-handler override).
642
+ * @returns The length classification — `error` over {@link MCP_TOOL_NAME_MAX_LENGTH}, `warn` over
643
+ * {@link MCP_TOOL_NAME_WARN_LENGTH}, otherwise `ok`.
644
+ *
645
+ * @example
646
+ * ```ts
647
+ * validateMcpToolName('worker-create'); // { name: 'worker-create', length: 13, level: 'ok' }
648
+ * ```
649
+ */ function validateMcpToolName(name) {
650
+ var length = name.length;
651
+ var level = 'ok';
652
+ if (length > MCP_TOOL_NAME_MAX_LENGTH) {
653
+ level = 'error';
654
+ } else if (length > MCP_TOOL_NAME_WARN_LENGTH) {
655
+ level = 'warn';
656
+ }
657
+ return {
658
+ name: name,
659
+ length: length,
660
+ level: level
661
+ };
662
+ }
663
+ /**
664
+ * Builds the MCP tool name for a (modelSegment, callType, specifier) triple.
462
665
  *
463
- * Apps can override the auto-generated name by setting
464
- * {@link OnCallModelFunctionApiDetails.mcp.name} on the handler.
666
+ * The call-type segment is only emitted for the default (`_`) specifier, where it carries the
667
+ * meaning (`worker-create`, `worker-update`). Named specifiers drop it — the specifier already
668
+ * disambiguates (`worker-syncCheckHqEmployee`), which keeps names short and within the MCP
669
+ * 64-character cap. Apps can override the whole name per handler via
670
+ * {@link OnCallModelFunctionApiDetails.mcp.name}.
465
671
  *
466
- * @param modelType - The Firestore model type (e.g., `storageFile`).
672
+ * This is the preferred (short) form. When two visible tools collide on it — two call types share a
673
+ * specifier once the call-type segment is dropped — the generator re-derives both names with
674
+ * {@link buildDisambiguatedMcpToolName} instead.
675
+ *
676
+ * @param modelSegment - The model segment of the name. Defaults to the model type, but may be a
677
+ * shorter per-model override (e.g. the collection prefix) resolved by the caller.
467
678
  * @param callType - The call type (e.g., `invoke`).
468
679
  * @param specifier - The specifier key, or `_` / undefined for the default entry.
469
680
  * @returns The hyphen-joined tool name advertised on `tools/list`.
470
- */ function buildMcpToolName(modelType, callType, specifier) {
681
+ *
682
+ * @example
683
+ * ```ts
684
+ * buildMcpToolName('worker', 'create'); // 'worker-create'
685
+ * buildMcpToolName('worker', 'update', 'syncCheckHqEmployee'); // 'worker-syncCheckHqEmployee'
686
+ * ```
687
+ */ function buildMcpToolName(modelSegment, callType, specifier) {
688
+ var isDefault = specifier == null || specifier === DEFAULT_SPECIFIER_KEY;
689
+ return isDefault ? "".concat(modelSegment, "-").concat(callType) : "".concat(modelSegment, "-").concat(specifier);
690
+ }
691
+ /**
692
+ * Single-character abbreviations for the standard CRUDQ + invoke call types, used to disambiguate
693
+ * colliding tool names without re-introducing the full call-type segment everywhere.
694
+ *
695
+ * @example
696
+ * ```ts
697
+ * MCP_CALL_TYPE_ABBREVIATIONS.update; // 'u'
698
+ * ```
699
+ */ var MCP_CALL_TYPE_ABBREVIATIONS = {
700
+ create: 'c',
701
+ read: 'r',
702
+ update: 'u',
703
+ delete: 'd',
704
+ query: 'q',
705
+ invoke: 'i'
706
+ };
707
+ /**
708
+ * Abbreviates a call type for use in a disambiguated tool name. Known CRUDQ + invoke types collapse
709
+ * to a single character; a custom call type is returned unchanged so the name stays unambiguous.
710
+ *
711
+ * @param callType - The call type / verb.
712
+ * @returns The single-character abbreviation, or the original string for a custom call type.
713
+ *
714
+ * @example
715
+ * ```ts
716
+ * abbreviateMcpCallType('update'); // 'u'
717
+ * abbreviateMcpCallType('recompute'); // 'recompute'
718
+ * ```
719
+ */ function abbreviateMcpCallType(callType) {
720
+ var _MCP_CALL_TYPE_ABBREVIATIONS_callType;
721
+ return (_MCP_CALL_TYPE_ABBREVIATIONS_callType = MCP_CALL_TYPE_ABBREVIATIONS[callType]) !== null && _MCP_CALL_TYPE_ABBREVIATIONS_callType !== void 0 ? _MCP_CALL_TYPE_ABBREVIATIONS_callType : callType;
722
+ }
723
+ /**
724
+ * Builds the disambiguated MCP tool name for a (modelSegment, callType, specifier) triple — the form
725
+ * used only when the preferred {@link buildMcpToolName} output collides with another visible tool.
726
+ *
727
+ * Named specifiers re-insert the call type, abbreviated, between the segment and specifier
728
+ * (`worker-u-syncCheckHqEmployee`); since the two colliding tools differ only by call type, their
729
+ * abbreviations differ and the names no longer clash. Default (`_`) specifiers already carry the
730
+ * full call type, so they are returned in their {@link buildMcpToolName} form unchanged.
731
+ *
732
+ * @param modelSegment - The model segment of the name (model type, or a per-model override).
733
+ * @param callType - The call type / verb.
734
+ * @param specifier - The specifier key, or `_` / undefined for the default entry.
735
+ * @returns The hyphen-joined disambiguated tool name.
736
+ *
737
+ * @example
738
+ * ```ts
739
+ * buildDisambiguatedMcpToolName('worker', 'update', 'syncCheckHqEmployee'); // 'worker-u-syncCheckHqEmployee'
740
+ * buildDisambiguatedMcpToolName('worker', 'create'); // 'worker-create'
741
+ * ```
742
+ */ function buildDisambiguatedMcpToolName(modelSegment, callType, specifier) {
471
743
  var isDefault = specifier == null || specifier === DEFAULT_SPECIFIER_KEY;
472
- return isDefault ? "".concat(modelType, "-").concat(callType) : "".concat(modelType, "-").concat(callType, "-").concat(specifier);
744
+ return isDefault ? "".concat(modelSegment, "-").concat(callType) : "".concat(modelSegment, "-").concat(abbreviateMcpCallType(callType), "-").concat(specifier);
473
745
  }
474
746
  /**
475
747
  * Builds the default description used when no build-time MCP manifest
@@ -483,7 +755,6 @@ function _unsupported_iterable_to_array$6(o, minLen) {
483
755
  var isDefault = specifier == null || specifier === DEFAULT_SPECIFIER_KEY;
484
756
  return isDefault ? 'Performs the "'.concat(callType, '" call on the "').concat(modelType, '" model.') : 'Performs the "'.concat(callType, '" call on the "').concat(modelType, '" model with the "').concat(specifier, '" specifier.');
485
757
  }
486
- // MARK: Generation
487
758
  /**
488
759
  * Generates MCP tool definitions from a model-first API details tree.
489
760
  *
@@ -491,38 +762,136 @@ function _unsupported_iterable_to_array$6(o, minLen) {
491
762
  * `inputType.toJsonSchema(options)` for the schema, and applies any handler-level
492
763
  * MCP `name` override. Descriptions and input/output schemas are pulled from the
493
764
  * build-time manifest when supplied. Tools without an `inputType` are skipped and
494
- * reported so callers can log the gap at startup.
765
+ * reported so callers can log the gap at startup. Tools whose resolved name exceeds
766
+ * {@link MCP_TOOL_NAME_MAX_LENGTH} are skipped so the advertised `tools/list` stays valid.
767
+ *
768
+ * Generation runs in two passes so a name clash is known before any name is finalized: the first
769
+ * pass plans every candidate and counts how many visible auto-named tools share each preferred name;
770
+ * the second builds each tool, re-deriving the colliding ones with the abbreviated call type
771
+ * ({@link buildDisambiguatedMcpToolName}) so both survive instead of one shadowing the other. A
772
+ * residual collision that disambiguation cannot resolve (e.g. an `mcp.name` override matching an auto
773
+ * name) drops the later tool so the dispatch map stays unambiguous.
495
774
  *
496
775
  * @param apiDetails - The model-first API details tree returned by `getModelApiDetails(callModelFn)`.
497
776
  * @param options - Optional schema generation options forwarded to `toJsonSchema()`. Defaults to {@link DEFAULT_JSON_SCHEMA_GENERATION_OPTIONS}.
498
- * @param manifest - Optional build-time manifest map; supplies overrides for descriptions and input/output schemas keyed by {@link mcpManifestKey}.
777
+ * @param context - Optional build-time context (manifest overrides + per-model name segments).
499
778
  * @returns The list of generated tool definitions plus any skip reports.
500
779
  */ function generateMcpToolDefinitions(apiDetails) {
501
- var options = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : DEFAULT_JSON_SCHEMA_GENERATION_OPTIONS, manifest = arguments.length > 2 ? arguments[2] : void 0;
780
+ var options = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : DEFAULT_JSON_SCHEMA_GENERATION_OPTIONS, context = arguments.length > 2 ? arguments[2] : void 0;
502
781
  var tools = [];
503
782
  var neverVisibleTools = [];
504
783
  var skipped = [];
784
+ var warnings = [];
785
+ var seenNames = new Set();
786
+ var manifest = context === null || context === void 0 ? void 0 : context.manifest;
787
+ var naming = context === null || context === void 0 ? void 0 : context.naming;
788
+ var candidates = planMcpToolCandidates(apiDetails, naming);
789
+ var clashCounts = countVisibleAutoNameClashes(candidates);
790
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
791
+ try {
792
+ for(var _iterator = candidates[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
793
+ var candidate = _step.value;
794
+ buildToolFromCandidate({
795
+ candidate: candidate,
796
+ clashCounts: clashCounts,
797
+ options: options,
798
+ manifest: manifest,
799
+ seenNames: seenNames,
800
+ outTools: tools,
801
+ outNeverVisibleTools: neverVisibleTools,
802
+ outSkipped: skipped,
803
+ outWarnings: warnings
804
+ });
805
+ }
806
+ } catch (err) {
807
+ _didIteratorError = true;
808
+ _iteratorError = err;
809
+ } finally{
810
+ try {
811
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
812
+ _iterator.return();
813
+ }
814
+ } finally{
815
+ if (_didIteratorError) {
816
+ throw _iteratorError;
817
+ }
818
+ }
819
+ }
820
+ return {
821
+ tools: tools,
822
+ neverVisibleTools: neverVisibleTools,
823
+ skipped: skipped,
824
+ warnings: warnings
825
+ };
826
+ }
827
+ /**
828
+ * First pass: walk the API tree and plan one {@link McpToolCandidate} per handler. No schema
829
+ * generation happens here — only the cheap naming + visibility classification needed to detect
830
+ * clashes before any name is finalized.
831
+ *
832
+ * @param apiDetails - The model-first API details tree.
833
+ * @param naming - Optional per-model name-segment overrides.
834
+ * @returns One candidate per non-null handler, in tree order.
835
+ */ function planMcpToolCandidates(apiDetails, naming) {
836
+ var candidates = [];
505
837
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
506
838
  try {
507
839
  for(var _iterator = Object.entries(apiDetails.models)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
508
- var _step_value = _sliced_to_array$2(_step.value, 2), modelType = _step_value[0], modelEntry = _step_value[1];
840
+ var _step_value = _sliced_to_array$3(_step.value, 2), modelType = _step_value[0], modelEntry = _step_value[1];
509
841
  var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
510
842
  try {
511
843
  for(var _iterator1 = Object.entries(modelEntry.calls)[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
512
- var _step_value1 = _sliced_to_array$2(_step1.value, 2), callType = _step_value1[0], callDetails = _step_value1[1];
844
+ var _step_value1 = _sliced_to_array$3(_step1.value, 2), callType = _step_value1[0], callDetails = _step_value1[1];
513
845
  if (callDetails == null) {
514
846
  continue;
515
847
  }
516
- generateToolsForModelCall({
517
- modelType: modelType,
518
- callType: callType,
519
- callDetails: callDetails,
520
- options: options,
521
- manifest: manifest,
522
- outTools: tools,
523
- outNeverVisibleTools: neverVisibleTools,
524
- outSkipped: skipped
525
- });
848
+ var _iteratorNormalCompletion2 = true, _didIteratorError2 = false, _iteratorError2 = undefined;
849
+ try {
850
+ for(var _iterator2 = Object.entries(callDetails.specifiers)[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true){
851
+ var _step_value2 = _sliced_to_array$3(_step2.value, 2), specifierKey = _step_value2[0], handlerDetails = _step_value2[1];
852
+ var _ref;
853
+ var _naming_modelSegments, _handlerDetails_mcp, _handlerDetails_mcp1;
854
+ if (handlerDetails == null) {
855
+ continue;
856
+ }
857
+ var specifier = callDetails.isSpecifier ? specifierKey : undefined;
858
+ var dispatch = {
859
+ call: callType,
860
+ modelType: modelType,
861
+ specifier: specifier
862
+ };
863
+ var modelSegment = (_ref = naming === null || naming === void 0 ? void 0 : (_naming_modelSegments = naming.modelSegments) === null || _naming_modelSegments === void 0 ? void 0 : _naming_modelSegments.get(modelType)) !== null && _ref !== void 0 ? _ref : modelType;
864
+ var overrideName = (_handlerDetails_mcp = handlerDetails.mcp) === null || _handlerDetails_mcp === void 0 ? void 0 : _handlerDetails_mcp.name;
865
+ var baseName = overrideName !== null && overrideName !== void 0 ? overrideName : buildMcpToolName(modelSegment, callType, specifier);
866
+ var classified = classifyVisibility((_handlerDetails_mcp1 = handlerDetails.mcp) === null || _handlerDetails_mcp1 === void 0 ? void 0 : _handlerDetails_mcp1.visibility);
867
+ var isVisible = classified.visibilityKind !== 'never';
868
+ candidates.push({
869
+ modelType: modelType,
870
+ callType: callType,
871
+ handlerDetails: handlerDetails,
872
+ specifier: specifier,
873
+ dispatch: dispatch,
874
+ modelSegment: modelSegment,
875
+ overrideName: overrideName,
876
+ baseName: baseName,
877
+ classified: classified,
878
+ isVisible: isVisible
879
+ });
880
+ }
881
+ } catch (err) {
882
+ _didIteratorError2 = true;
883
+ _iteratorError2 = err;
884
+ } finally{
885
+ try {
886
+ if (!_iteratorNormalCompletion2 && _iterator2.return != null) {
887
+ _iterator2.return();
888
+ }
889
+ } finally{
890
+ if (_didIteratorError2) {
891
+ throw _iteratorError2;
892
+ }
893
+ }
894
+ }
526
895
  }
527
896
  } catch (err) {
528
897
  _didIteratorError1 = true;
@@ -553,19 +922,24 @@ function _unsupported_iterable_to_array$6(o, minLen) {
553
922
  }
554
923
  }
555
924
  }
556
- return {
557
- tools: tools,
558
- neverVisibleTools: neverVisibleTools,
559
- skipped: skipped
560
- };
925
+ return candidates;
561
926
  }
562
- function generateToolsForModelCall(context) {
927
+ /**
928
+ * Counts how many visible, auto-named (no `mcp.name` override) candidates share each preferred name.
929
+ * Only these participate in clash detection — hidden tools never reach the wire, and overrides are
930
+ * explicit. A base name with a count over 1 is a clash that the build pass disambiguates.
931
+ *
932
+ * @param candidates - The planned candidates from {@link planMcpToolCandidates}.
933
+ * @returns A map of preferred name to the number of visible auto-named candidates producing it.
934
+ */ function countVisibleAutoNameClashes(candidates) {
935
+ var counts = new Map();
563
936
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
564
937
  try {
565
- for(var _iterator = Object.entries(context.callDetails.specifiers)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
566
- var _step_value = _sliced_to_array$2(_step.value, 2), specifierKey = _step_value[0], handlerDetails = _step_value[1];
567
- if (handlerDetails != null) {
568
- generateToolForSpecifier(context, specifierKey, handlerDetails);
938
+ for(var _iterator = candidates[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
939
+ var candidate = _step.value;
940
+ if (candidate.isVisible && candidate.overrideName == null) {
941
+ var _counts_get;
942
+ counts.set(candidate.baseName, ((_counts_get = counts.get(candidate.baseName)) !== null && _counts_get !== void 0 ? _counts_get : 0) + 1);
569
943
  }
570
944
  }
571
945
  } catch (err) {
@@ -582,20 +956,36 @@ function generateToolsForModelCall(context) {
582
956
  }
583
957
  }
584
958
  }
959
+ return counts;
585
960
  }
586
- function generateToolForSpecifier(context, specifierKey, handlerDetails) {
587
- var _ref, _ref1, _resolveRequiredScope;
588
- var _handlerDetails_mcp, _handlerDetails_mcp1, _handlerDetails_mcp2, _handlerDetails_mcp3;
589
- var modelType = context.modelType, callType = context.callType, callDetails = context.callDetails, options = context.options, manifest = context.manifest, outTools = context.outTools, outNeverVisibleTools = context.outNeverVisibleTools, outSkipped = context.outSkipped;
590
- var specifier = callDetails.isSpecifier ? specifierKey : undefined;
591
- var dispatch = {
592
- call: callType,
593
- modelType: modelType,
594
- specifier: specifier
595
- };
596
- var name = (_ref = (_handlerDetails_mcp = handlerDetails.mcp) === null || _handlerDetails_mcp === void 0 ? void 0 : _handlerDetails_mcp.name) !== null && _ref !== void 0 ? _ref : buildMcpToolName(modelType, callType, specifier);
961
+ /**
962
+ * Second pass: turn one planned {@link McpToolCandidate} into a tool definition, resolving its final
963
+ * name (disambiguating a clash with the abbreviated call type), generating its schema, and routing it
964
+ * to the visible or never-visible bucket.
965
+ *
966
+ * @param context - The candidate plus the shared generation accumulators.
967
+ */ function buildToolFromCandidate(context) {
968
+ var _clashCounts_get, _ref, _resolveRequiredScope;
969
+ var _handlerDetails_mcp, _handlerDetails_mcp1;
970
+ var candidate = context.candidate, clashCounts = context.clashCounts, options = context.options, manifest = context.manifest, seenNames = context.seenNames, outTools = context.outTools, outNeverVisibleTools = context.outNeverVisibleTools, outSkipped = context.outSkipped, outWarnings = context.outWarnings;
971
+ var modelType = candidate.modelType, callType = candidate.callType, handlerDetails = candidate.handlerDetails, specifier = candidate.specifier, dispatch = candidate.dispatch, modelSegment = candidate.modelSegment, overrideName = candidate.overrideName, baseName = candidate.baseName, classified = candidate.classified, isVisible = candidate.isVisible;
972
+ // A visible auto-named tool whose preferred name is produced by more than one visible tool is
973
+ // re-derived with the abbreviated call type so both survive on the wire. Overrides and hidden tools
974
+ // keep their preferred name (overrides are explicit; hidden tools never reach the wire).
975
+ var needsDisambiguation = isVisible && overrideName == null && ((_clashCounts_get = clashCounts.get(baseName)) !== null && _clashCounts_get !== void 0 ? _clashCounts_get : 0) > 1;
976
+ var name = needsDisambiguation ? buildDisambiguatedMcpToolName(modelSegment, callType, specifier) : baseName;
977
+ var nameValidation = validateMcpToolName(name);
978
+ // A name over the hard cap would make remote clients reject the whole tools/list payload — never advertise it.
979
+ if (nameValidation.level === 'error') {
980
+ outSkipped.push({
981
+ toolName: name,
982
+ reason: 'name_too_long',
983
+ dispatch: dispatch
984
+ });
985
+ return;
986
+ }
597
987
  var manifestEntry = manifest === null || manifest === void 0 ? void 0 : manifest.get(mcpManifestKey(modelType, callType, specifier));
598
- var description = (_ref1 = manifestEntry === null || manifestEntry === void 0 ? void 0 : manifestEntry.description) !== null && _ref1 !== void 0 ? _ref1 : buildDefaultMcpToolDescription(modelType, callType, specifier);
988
+ var description = (_ref = manifestEntry === null || manifestEntry === void 0 ? void 0 : manifestEntry.description) !== null && _ref !== void 0 ? _ref : buildDefaultMcpToolDescription(modelType, callType, specifier);
599
989
  var inputSchema = resolveInputSchema({
600
990
  handlerDetails: handlerDetails,
601
991
  manifestEntry: manifestEntry,
@@ -607,9 +997,28 @@ function generateToolForSpecifier(context, specifierKey, handlerDetails) {
607
997
  if (inputSchema == null) {
608
998
  return;
609
999
  }
610
- var classified = classifyVisibility((_handlerDetails_mcp1 = handlerDetails.mcp) === null || _handlerDetails_mcp1 === void 0 ? void 0 : _handlerDetails_mcp1.visibility);
1000
+ // Cross-check the handler's mapSuccessfulResult against the manifest's mapped-result signal. Only
1001
+ // meaningful when a manifest is supplied (it carries the `.api.ts` annotation outcome).
1002
+ if (manifest != null) {
1003
+ var _handlerDetails_mcp2;
1004
+ var hasMapper = ((_handlerDetails_mcp2 = handlerDetails.mcp) === null || _handlerDetails_mcp2 === void 0 ? void 0 : _handlerDetails_mcp2.mapSuccessfulResult) != null;
1005
+ var manifestMapped = (manifestEntry === null || manifestEntry === void 0 ? void 0 : manifestEntry.mcpResultTypeName) != null;
1006
+ if (hasMapper && !manifestMapped) {
1007
+ outWarnings.push({
1008
+ toolName: name,
1009
+ reason: 'mapper_without_mapped_manifest',
1010
+ dispatch: dispatch
1011
+ });
1012
+ } else if (!hasMapper && manifestMapped) {
1013
+ outWarnings.push({
1014
+ toolName: name,
1015
+ reason: 'mapped_manifest_without_mapper',
1016
+ dispatch: dispatch
1017
+ });
1018
+ }
1019
+ }
611
1020
  var requiredScope = (_resolveRequiredScope = resolveRequiredScope(callType)) !== null && _resolveRequiredScope !== void 0 ? _resolveRequiredScope : undefined;
612
- var effectiveReadOnly = resolveEffectiveReadOnly((_handlerDetails_mcp2 = handlerDetails.mcp) === null || _handlerDetails_mcp2 === void 0 ? void 0 : _handlerDetails_mcp2.readOnly, callType);
1021
+ var effectiveReadOnly = resolveEffectiveReadOnly((_handlerDetails_mcp = handlerDetails.mcp) === null || _handlerDetails_mcp === void 0 ? void 0 : _handlerDetails_mcp.readOnly, callType);
613
1022
  var filterMetadata;
614
1023
  if (classified.visibilityKind === 'declarative') {
615
1024
  filterMetadata = {
@@ -632,6 +1041,21 @@ function generateToolForSpecifier(context, specifierKey, handlerDetails) {
632
1041
  effectiveReadOnly: effectiveReadOnly
633
1042
  };
634
1043
  }
1044
+ // Disambiguation has already separated the common dropped-call-type clash; this is the backstop for
1045
+ // a residual collision it cannot resolve (an `mcp.name` override matching an auto name, or two model
1046
+ // segments coinciding on the same call type) which would otherwise let one tool silently shadow the
1047
+ // other in the per-request name→definition map. Hidden tools never reach the map, so skip the check.
1048
+ if (isVisible) {
1049
+ if (seenNames.has(name)) {
1050
+ outSkipped.push({
1051
+ toolName: name,
1052
+ reason: 'duplicate_name',
1053
+ dispatch: dispatch
1054
+ });
1055
+ return;
1056
+ }
1057
+ seenNames.add(name);
1058
+ }
635
1059
  var outputSchema = manifestEntry === null || manifestEntry === void 0 ? void 0 : manifestEntry.outputSchema;
636
1060
  var staticWireEntry = buildStaticWireEntry({
637
1061
  name: name,
@@ -648,12 +1072,12 @@ function generateToolForSpecifier(context, specifierKey, handlerDetails) {
648
1072
  dispatch: dispatch,
649
1073
  filterMetadata: filterMetadata,
650
1074
  staticWireEntry: staticWireEntry,
651
- toolDetailsBuilder: (_handlerDetails_mcp3 = handlerDetails.mcp) === null || _handlerDetails_mcp3 === void 0 ? void 0 : _handlerDetails_mcp3.toolDetails
1075
+ toolDetailsBuilder: (_handlerDetails_mcp1 = handlerDetails.mcp) === null || _handlerDetails_mcp1 === void 0 ? void 0 : _handlerDetails_mcp1.toolDetails
652
1076
  };
653
- if (filterMetadata.visibilityKind === 'never') {
654
- outNeverVisibleTools.push(definition);
655
- } else {
1077
+ if (isVisible) {
656
1078
  outTools.push(definition);
1079
+ } else {
1080
+ outNeverVisibleTools.push(definition);
657
1081
  }
658
1082
  }
659
1083
  function resolveInputSchema(context) {
@@ -672,7 +1096,7 @@ function resolveInputSchema(context) {
672
1096
  var result;
673
1097
  try {
674
1098
  var exported = model.arktypeToJsonSchemaForExport(handlerDetails.inputType);
675
- if (exported && (typeof exported === "undefined" ? "undefined" : _type_of$1(exported)) === 'object') {
1099
+ if (exported && (typeof exported === "undefined" ? "undefined" : _type_of$2(exported)) === 'object') {
676
1100
  result = exported;
677
1101
  } else {
678
1102
  // arktypeToJsonSchemaForExport returned a non-object (shouldn't happen for object schemas).
@@ -691,15 +1115,15 @@ function resolveInputSchema(context) {
691
1115
  return result;
692
1116
  }
693
1117
 
694
- function _array_like_to_array$5(arr, len) {
1118
+ function _array_like_to_array$6(arr, len) {
695
1119
  if (len == null || len > arr.length) len = arr.length;
696
1120
  for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
697
1121
  return arr2;
698
1122
  }
699
1123
  function _array_without_holes$5(arr) {
700
- if (Array.isArray(arr)) return _array_like_to_array$5(arr);
1124
+ if (Array.isArray(arr)) return _array_like_to_array$6(arr);
701
1125
  }
702
- function asyncGeneratorStep$3(gen, resolve, reject, _next, _throw, key, arg) {
1126
+ function asyncGeneratorStep$4(gen, resolve, reject, _next, _throw, key, arg) {
703
1127
  try {
704
1128
  var info = gen[key](arg);
705
1129
  var value = info.value;
@@ -713,16 +1137,16 @@ function asyncGeneratorStep$3(gen, resolve, reject, _next, _throw, key, arg) {
713
1137
  Promise.resolve(value).then(_next, _throw);
714
1138
  }
715
1139
  }
716
- function _async_to_generator$3(fn) {
1140
+ function _async_to_generator$4(fn) {
717
1141
  return function() {
718
1142
  var self = this, args = arguments;
719
1143
  return new Promise(function(resolve, reject) {
720
1144
  var gen = fn.apply(self, args);
721
1145
  function _next(value) {
722
- asyncGeneratorStep$3(gen, resolve, reject, _next, _throw, "next", value);
1146
+ asyncGeneratorStep$4(gen, resolve, reject, _next, _throw, "next", value);
723
1147
  }
724
1148
  function _throw(err) {
725
- asyncGeneratorStep$3(gen, resolve, reject, _next, _throw, "throw", err);
1149
+ asyncGeneratorStep$4(gen, resolve, reject, _next, _throw, "throw", err);
726
1150
  }
727
1151
  _next(undefined);
728
1152
  });
@@ -735,17 +1159,17 @@ function _non_iterable_spread$5() {
735
1159
  throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
736
1160
  }
737
1161
  function _to_consumable_array$5(arr) {
738
- return _array_without_holes$5(arr) || _iterable_to_array$5(arr) || _unsupported_iterable_to_array$5(arr) || _non_iterable_spread$5();
1162
+ return _array_without_holes$5(arr) || _iterable_to_array$5(arr) || _unsupported_iterable_to_array$6(arr) || _non_iterable_spread$5();
739
1163
  }
740
- function _unsupported_iterable_to_array$5(o, minLen) {
1164
+ function _unsupported_iterable_to_array$6(o, minLen) {
741
1165
  if (!o) return;
742
- if (typeof o === "string") return _array_like_to_array$5(o, minLen);
1166
+ if (typeof o === "string") return _array_like_to_array$6(o, minLen);
743
1167
  var n = Object.prototype.toString.call(o).slice(8, -1);
744
1168
  if (n === "Object" && o.constructor) n = o.constructor.name;
745
1169
  if (n === "Map" || n === "Set") return Array.from(n);
746
- if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$5(o, minLen);
1170
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$6(o, minLen);
747
1171
  }
748
- function _ts_generator$3(thisArg, body) {
1172
+ function _ts_generator$4(thisArg, body) {
749
1173
  var f, y, t, _ = {
750
1174
  label: 0,
751
1175
  sent: function() {
@@ -915,9 +1339,9 @@ function _ts_generator$3(thisArg, body) {
915
1339
  }
916
1340
  // MARK: Handler
917
1341
  function modelGetToolHandler(args, ctx, deps) {
918
- return _async_to_generator$3(function() {
1342
+ return _async_to_generator$4(function() {
919
1343
  var result, input, identity, resolvedKeys, merged, error;
920
- return _ts_generator$3(this, function(_state) {
1344
+ return _ts_generator$4(this, function(_state) {
921
1345
  switch(_state.label){
922
1346
  case 0:
923
1347
  _state.trys.push([
@@ -1024,9 +1448,9 @@ function resolveKeys(keys, identity) {
1024
1448
  return resolved;
1025
1449
  }
1026
1450
  function readInChunks(input) {
1027
- return _async_to_generator$3(function() {
1451
+ return _async_to_generator$4(function() {
1028
1452
  var modelType, keys, auth, readDocuments, merged, offset, _merged_results, _merged_errors, batch, partial;
1029
- return _ts_generator$3(this, function(_state) {
1453
+ return _ts_generator$4(this, function(_state) {
1030
1454
  switch(_state.label){
1031
1455
  case 0:
1032
1456
  modelType = input.modelType, keys = input.keys, auth = input.auth, readDocuments = input.readDocuments;
@@ -1140,13 +1564,13 @@ var MODEL_GET_OUTPUT_SCHEMA = {
1140
1564
  }
1141
1565
  };
1142
1566
 
1143
- function _array_like_to_array$4(arr, len) {
1567
+ function _array_like_to_array$5(arr, len) {
1144
1568
  if (len == null || len > arr.length) len = arr.length;
1145
1569
  for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
1146
1570
  return arr2;
1147
1571
  }
1148
1572
  function _array_without_holes$4(arr) {
1149
- if (Array.isArray(arr)) return _array_like_to_array$4(arr);
1573
+ if (Array.isArray(arr)) return _array_like_to_array$5(arr);
1150
1574
  }
1151
1575
  function _define_property$6(obj, key, value) {
1152
1576
  if (key in obj) {
@@ -1202,15 +1626,15 @@ function _object_spread_props(target, source) {
1202
1626
  return target;
1203
1627
  }
1204
1628
  function _to_consumable_array$4(arr) {
1205
- return _array_without_holes$4(arr) || _iterable_to_array$4(arr) || _unsupported_iterable_to_array$4(arr) || _non_iterable_spread$4();
1629
+ return _array_without_holes$4(arr) || _iterable_to_array$4(arr) || _unsupported_iterable_to_array$5(arr) || _non_iterable_spread$4();
1206
1630
  }
1207
- function _unsupported_iterable_to_array$4(o, minLen) {
1631
+ function _unsupported_iterable_to_array$5(o, minLen) {
1208
1632
  if (!o) return;
1209
- if (typeof o === "string") return _array_like_to_array$4(o, minLen);
1633
+ if (typeof o === "string") return _array_like_to_array$5(o, minLen);
1210
1634
  var n = Object.prototype.toString.call(o).slice(8, -1);
1211
1635
  if (n === "Object" && o.constructor) n = o.constructor.name;
1212
1636
  if (n === "Map" || n === "Set") return Array.from(n);
1213
- if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$4(o, minLen);
1637
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$5(o, minLen);
1214
1638
  }
1215
1639
  // MARK: Constants
1216
1640
  /**
@@ -2115,16 +2539,16 @@ var MODEL_DECODE_OUTPUT_SCHEMA = {
2115
2539
  }
2116
2540
  };
2117
2541
 
2118
- function _array_like_to_array$3(arr, len) {
2542
+ function _array_like_to_array$4(arr, len) {
2119
2543
  if (len == null || len > arr.length) len = arr.length;
2120
2544
  for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
2121
2545
  return arr2;
2122
2546
  }
2123
- function _array_with_holes$1(arr) {
2547
+ function _array_with_holes$2(arr) {
2124
2548
  if (Array.isArray(arr)) return arr;
2125
2549
  }
2126
2550
  function _array_without_holes$3(arr) {
2127
- if (Array.isArray(arr)) return _array_like_to_array$3(arr);
2551
+ if (Array.isArray(arr)) return _array_like_to_array$4(arr);
2128
2552
  }
2129
2553
  function _define_property$4(obj, key, value) {
2130
2554
  if (key in obj) {
@@ -2142,7 +2566,7 @@ function _define_property$4(obj, key, value) {
2142
2566
  function _iterable_to_array$3(iter) {
2143
2567
  if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
2144
2568
  }
2145
- function _iterable_to_array_limit$1(arr, i) {
2569
+ function _iterable_to_array_limit$2(arr, i) {
2146
2570
  var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
2147
2571
  if (_i == null) return;
2148
2572
  var _arr = [];
@@ -2166,7 +2590,7 @@ function _iterable_to_array_limit$1(arr, i) {
2166
2590
  }
2167
2591
  return _arr;
2168
2592
  }
2169
- function _non_iterable_rest$1() {
2593
+ function _non_iterable_rest$2() {
2170
2594
  throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
2171
2595
  }
2172
2596
  function _non_iterable_spread$3() {
@@ -2187,19 +2611,19 @@ function _object_spread(target) {
2187
2611
  }
2188
2612
  return target;
2189
2613
  }
2190
- function _sliced_to_array$1(arr, i) {
2191
- return _array_with_holes$1(arr) || _iterable_to_array_limit$1(arr, i) || _unsupported_iterable_to_array$3(arr, i) || _non_iterable_rest$1();
2614
+ function _sliced_to_array$2(arr, i) {
2615
+ return _array_with_holes$2(arr) || _iterable_to_array_limit$2(arr, i) || _unsupported_iterable_to_array$4(arr, i) || _non_iterable_rest$2();
2192
2616
  }
2193
2617
  function _to_consumable_array$3(arr) {
2194
- return _array_without_holes$3(arr) || _iterable_to_array$3(arr) || _unsupported_iterable_to_array$3(arr) || _non_iterable_spread$3();
2618
+ return _array_without_holes$3(arr) || _iterable_to_array$3(arr) || _unsupported_iterable_to_array$4(arr) || _non_iterable_spread$3();
2195
2619
  }
2196
- function _unsupported_iterable_to_array$3(o, minLen) {
2620
+ function _unsupported_iterable_to_array$4(o, minLen) {
2197
2621
  if (!o) return;
2198
- if (typeof o === "string") return _array_like_to_array$3(o, minLen);
2622
+ if (typeof o === "string") return _array_like_to_array$4(o, minLen);
2199
2623
  var n = Object.prototype.toString.call(o).slice(8, -1);
2200
2624
  if (n === "Object" && o.constructor) n = o.constructor.name;
2201
2625
  if (n === "Map" || n === "Set") return Array.from(n);
2202
- if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$3(o, minLen);
2626
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$4(o, minLen);
2203
2627
  }
2204
2628
  // MARK: Constants
2205
2629
  /**
@@ -2273,10 +2697,10 @@ function whoamiToolHandler(ctx, deps) {
2273
2697
  }
2274
2698
  var token = (_auth_token = auth.token) !== null && _auth_token !== void 0 ? _auth_token : {};
2275
2699
  var presentKeys = Object.entries(token).filter(function(param) {
2276
- var _param = _sliced_to_array$1(param, 2), value = _param[1];
2700
+ var _param = _sliced_to_array$2(param, 2), value = _param[1];
2277
2701
  return value !== undefined;
2278
2702
  }).map(function(param) {
2279
- var _param = _sliced_to_array$1(param, 1), key = _param[0];
2703
+ var _param = _sliced_to_array$2(param, 1), key = _param[0];
2280
2704
  return key;
2281
2705
  });
2282
2706
  var roleSet = deps.roleReader == null ? new Set() : deps.roleReader(token);
@@ -2452,99 +2876,956 @@ function appendUnknownClaimLines(lines, unknownClaimKeys) {
2452
2876
  if (!_iteratorNormalCompletion && _iterator.return != null) {
2453
2877
  _iterator.return();
2454
2878
  }
2455
- } finally{
2456
- if (_didIteratorError) {
2457
- throw _iteratorError;
2879
+ } finally{
2880
+ if (_didIteratorError) {
2881
+ throw _iteratorError;
2882
+ }
2883
+ }
2884
+ }
2885
+ }
2886
+ // MARK: Schemas
2887
+ var WHOAMI_INPUT_SCHEMA = {
2888
+ type: 'object',
2889
+ properties: {},
2890
+ additionalProperties: false
2891
+ };
2892
+ var WHOAMI_OUTPUT_SCHEMA = {
2893
+ type: 'object',
2894
+ required: [
2895
+ 'authenticated',
2896
+ 'claims',
2897
+ 'roles',
2898
+ 'claimDetails',
2899
+ 'unknownClaimKeys'
2900
+ ],
2901
+ description: 'Caller identity, raw token claims, decoded role set, and per-claim descriptions for every key present on the live token.',
2902
+ properties: {
2903
+ authenticated: {
2904
+ type: 'boolean'
2905
+ },
2906
+ uid: {
2907
+ type: 'string'
2908
+ },
2909
+ email: {
2910
+ type: 'string'
2911
+ },
2912
+ emailVerified: {
2913
+ type: 'boolean'
2914
+ },
2915
+ app: {
2916
+ type: 'string'
2917
+ },
2918
+ claims: {
2919
+ type: 'object',
2920
+ additionalProperties: true
2921
+ },
2922
+ roles: {
2923
+ type: 'array',
2924
+ items: {
2925
+ type: 'string'
2926
+ }
2927
+ },
2928
+ claimDetails: {
2929
+ type: 'array',
2930
+ items: {
2931
+ type: 'object',
2932
+ required: [
2933
+ 'key',
2934
+ 'description',
2935
+ 'grantedRoles',
2936
+ 'inverse',
2937
+ 'tags'
2938
+ ],
2939
+ properties: {
2940
+ key: {
2941
+ type: 'string'
2942
+ },
2943
+ interfaceName: {
2944
+ type: 'string'
2945
+ },
2946
+ description: {
2947
+ type: 'string'
2948
+ },
2949
+ grantedRoles: {
2950
+ type: 'array',
2951
+ items: {
2952
+ type: 'string'
2953
+ }
2954
+ },
2955
+ inverse: {
2956
+ type: 'boolean'
2957
+ },
2958
+ tags: {
2959
+ type: 'array',
2960
+ items: {
2961
+ type: 'string'
2962
+ }
2963
+ }
2964
+ }
2965
+ }
2966
+ },
2967
+ unknownClaimKeys: {
2968
+ type: 'array',
2969
+ items: {
2970
+ type: 'string'
2971
+ }
2972
+ }
2973
+ }
2974
+ };
2975
+
2976
+ function _array_like_to_array$3(arr, len) {
2977
+ if (len == null || len > arr.length) len = arr.length;
2978
+ for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
2979
+ return arr2;
2980
+ }
2981
+ function _array_with_holes$1(arr) {
2982
+ if (Array.isArray(arr)) return arr;
2983
+ }
2984
+ function asyncGeneratorStep$3(gen, resolve, reject, _next, _throw, key, arg) {
2985
+ try {
2986
+ var info = gen[key](arg);
2987
+ var value = info.value;
2988
+ } catch (error) {
2989
+ reject(error);
2990
+ return;
2991
+ }
2992
+ if (info.done) {
2993
+ resolve(value);
2994
+ } else {
2995
+ Promise.resolve(value).then(_next, _throw);
2996
+ }
2997
+ }
2998
+ function _async_to_generator$3(fn) {
2999
+ return function() {
3000
+ var self = this, args = arguments;
3001
+ return new Promise(function(resolve, reject) {
3002
+ var gen = fn.apply(self, args);
3003
+ function _next(value) {
3004
+ asyncGeneratorStep$3(gen, resolve, reject, _next, _throw, "next", value);
3005
+ }
3006
+ function _throw(err) {
3007
+ asyncGeneratorStep$3(gen, resolve, reject, _next, _throw, "throw", err);
3008
+ }
3009
+ _next(undefined);
3010
+ });
3011
+ };
3012
+ }
3013
+ function _instanceof(left, right) {
3014
+ "@swc/helpers - instanceof";
3015
+ if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) {
3016
+ return !!right[Symbol.hasInstance](left);
3017
+ } else {
3018
+ return left instanceof right;
3019
+ }
3020
+ }
3021
+ function _iterable_to_array_limit$1(arr, i) {
3022
+ var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
3023
+ if (_i == null) return;
3024
+ var _arr = [];
3025
+ var _n = true;
3026
+ var _d = false;
3027
+ var _s, _e;
3028
+ try {
3029
+ for(_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true){
3030
+ _arr.push(_s.value);
3031
+ if (i && _arr.length === i) break;
3032
+ }
3033
+ } catch (err) {
3034
+ _d = true;
3035
+ _e = err;
3036
+ } finally{
3037
+ try {
3038
+ if (!_n && _i["return"] != null) _i["return"]();
3039
+ } finally{
3040
+ if (_d) throw _e;
3041
+ }
3042
+ }
3043
+ return _arr;
3044
+ }
3045
+ function _non_iterable_rest$1() {
3046
+ throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
3047
+ }
3048
+ function _sliced_to_array$1(arr, i) {
3049
+ return _array_with_holes$1(arr) || _iterable_to_array_limit$1(arr, i) || _unsupported_iterable_to_array$3(arr, i) || _non_iterable_rest$1();
3050
+ }
3051
+ function _type_of$1(obj) {
3052
+ "@swc/helpers - typeof";
3053
+ return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj;
3054
+ }
3055
+ function _unsupported_iterable_to_array$3(o, minLen) {
3056
+ if (!o) return;
3057
+ if (typeof o === "string") return _array_like_to_array$3(o, minLen);
3058
+ var n = Object.prototype.toString.call(o).slice(8, -1);
3059
+ if (n === "Object" && o.constructor) n = o.constructor.name;
3060
+ if (n === "Map" || n === "Set") return Array.from(n);
3061
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$3(o, minLen);
3062
+ }
3063
+ function _ts_generator$3(thisArg, body) {
3064
+ var f, y, t, _ = {
3065
+ label: 0,
3066
+ sent: function() {
3067
+ if (t[0] & 1) throw t[1];
3068
+ return t[1];
3069
+ },
3070
+ trys: [],
3071
+ ops: []
3072
+ }, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype), d = Object.defineProperty;
3073
+ return d(g, "next", {
3074
+ value: verb(0)
3075
+ }), d(g, "throw", {
3076
+ value: verb(1)
3077
+ }), d(g, "return", {
3078
+ value: verb(2)
3079
+ }), typeof Symbol === "function" && d(g, Symbol.iterator, {
3080
+ value: function() {
3081
+ return this;
3082
+ }
3083
+ }), g;
3084
+ function verb(n) {
3085
+ return function(v) {
3086
+ return step([
3087
+ n,
3088
+ v
3089
+ ]);
3090
+ };
3091
+ }
3092
+ function step(op) {
3093
+ if (f) throw new TypeError("Generator is already executing.");
3094
+ while(g && (g = 0, op[0] && (_ = 0)), _)try {
3095
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
3096
+ if (y = 0, t) op = [
3097
+ op[0] & 2,
3098
+ t.value
3099
+ ];
3100
+ switch(op[0]){
3101
+ case 0:
3102
+ case 1:
3103
+ t = op;
3104
+ break;
3105
+ case 4:
3106
+ _.label++;
3107
+ return {
3108
+ value: op[1],
3109
+ done: false
3110
+ };
3111
+ case 5:
3112
+ _.label++;
3113
+ y = op[1];
3114
+ op = [
3115
+ 0
3116
+ ];
3117
+ continue;
3118
+ case 7:
3119
+ op = _.ops.pop();
3120
+ _.trys.pop();
3121
+ continue;
3122
+ default:
3123
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
3124
+ _ = 0;
3125
+ continue;
3126
+ }
3127
+ if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
3128
+ _.label = op[1];
3129
+ break;
3130
+ }
3131
+ if (op[0] === 6 && _.label < t[1]) {
3132
+ _.label = t[1];
3133
+ t = op;
3134
+ break;
3135
+ }
3136
+ if (t && _.label < t[2]) {
3137
+ _.label = t[2];
3138
+ _.ops.push(op);
3139
+ break;
3140
+ }
3141
+ if (t[2]) _.ops.pop();
3142
+ _.trys.pop();
3143
+ continue;
3144
+ }
3145
+ op = body.call(thisArg, _);
3146
+ } catch (e) {
3147
+ op = [
3148
+ 6,
3149
+ e
3150
+ ];
3151
+ y = 0;
3152
+ } finally{
3153
+ f = t = 0;
3154
+ }
3155
+ if (op[0] & 5) throw op[1];
3156
+ return {
3157
+ value: op[0] ? op[1] : void 0,
3158
+ done: true
3159
+ };
3160
+ }
3161
+ }
3162
+ // MARK: Constants
3163
+ /**
3164
+ * Reserved tool name for the built-in `batch-execute` static tool.
3165
+ */ var BATCH_EXECUTE_TOOL_NAME = 'batch-execute';
3166
+ /**
3167
+ * Synthetic call type used in the tool's dispatch identity (analytics only — the tool re-dispatches
3168
+ * to other callModel tools rather than resolving a `batch` call type of its own).
3169
+ */ var BATCH_EXECUTE_DISPATCH_CALL = 'batch';
3170
+ /**
3171
+ * Synthetic model type used in the tool's dispatch identity. The tool isn't bound to a model type
3172
+ * (each operation carries its own), so we use the literal "batch" as the identity. Apps avoiding
3173
+ * collision should not register a real model literally named "batch".
3174
+ */ var BATCH_EXECUTE_DISPATCH_MODEL_TYPE = 'batch';
3175
+ /**
3176
+ * Default per-operation concurrency when the caller does not specify `maxParallel`.
3177
+ */ var DEFAULT_BATCH_EXECUTE_MAX_PARALLEL = 5;
3178
+ /**
3179
+ * Hard upper bound on operations accepted in a single batch file, guarding against an
3180
+ * accidentally enormous upload exhausting the function's memory/time budget.
3181
+ */ var MAX_BATCH_EXECUTE_OPERATIONS = 1000;
3182
+ /**
3183
+ * Maximum bytes read from the operations file. NDJSON of typical CRUD payloads stays well under
3184
+ * this; an oversized file is rejected rather than streamed.
3185
+ */ var MAX_BATCH_EXECUTE_FILE_BYTES = 5 * 1024 * 1024;
3186
+ // MARK: Coordinate key
3187
+ /**
3188
+ * Builds the lookup key identifying a callModel dispatch coordinate. The factory indexes the
3189
+ * caller's visible callModel tools by this key; the batch handler looks each operation up by the
3190
+ * same key, so authorization reuses the exact tool set advertised on `tools/list`.
3191
+ *
3192
+ * @param dispatch - The `(call, modelType, specifier?)` coordinate to key.
3193
+ * @returns A stable string key. Uses a NUL separator so segment values can't collide.
3194
+ */ function batchOperationCoordKey(dispatch) {
3195
+ var _dispatch_specifier;
3196
+ return "".concat(dispatch.call, "\0").concat(dispatch.modelType, "\0").concat((_dispatch_specifier = dispatch.specifier) !== null && _dispatch_specifier !== void 0 ? _dispatch_specifier : '');
3197
+ }
3198
+ // MARK: Factory
3199
+ /**
3200
+ * Builds the built-in `batch-execute` MCP tool definition.
3201
+ *
3202
+ * The tool ingests an uploaded JSON / NDJSON file of `(call, modelType, specifier?, data)`
3203
+ * operations and runs them server-side, returning a single success/failure summary. It exists so an
3204
+ * agent can perform a bulk mutation (e.g. "update 200 workers") by *generating* the operations file
3205
+ * with a script and uploading it — rather than emitting each payload as tool-call output and paying
3206
+ * one model turn per record.
3207
+ *
3208
+ * Safety model:
3209
+ * - Every operation is validated and authorized against the caller's visible tool set *before any
3210
+ * dispatch*. A malformed or forbidden operation aborts the whole batch with a pre-flight error and
3211
+ * nothing runs — `dispatch` would otherwise bypass the `tools/list` visibility filter.
3212
+ * - Runtime failures are best-effort by default (collected into the summary); `stopOnError` halts at
3213
+ * the first failure (forcing sequential execution).
3214
+ *
3215
+ * @param deps - Storage reader, dispatch fn, and per-operation authorizer (typically wired in the
3216
+ * server factory to the request's visible tool set).
3217
+ * @returns A statically-registered {@link McpToolDefinition} ready to be appended to the MCP server
3218
+ * factory's tool registry.
3219
+ */ function createBatchExecuteTool(deps) {
3220
+ var handler = function handler(args, ctx) {
3221
+ return batchExecuteToolHandler(args, ctx, deps);
3222
+ };
3223
+ var name = BATCH_EXECUTE_TOOL_NAME;
3224
+ var description = 'Execute a batch of MCP operations server-side from an uploaded JSON/NDJSON file, returning a success/failure summary. Each line/element is an operation `{ call, modelType, specifier?, data }` matching any other write tool you could call individually. Generate the file with a script and upload it instead of invoking a per-record tool many times. Every operation is authorized against your visible tools before any run; a forbidden or malformed operation aborts the whole batch with nothing executed.';
3225
+ return {
3226
+ name: name,
3227
+ description: description,
3228
+ inputSchema: BATCH_EXECUTE_INPUT_SCHEMA,
3229
+ outputSchema: BATCH_EXECUTE_OUTPUT_SCHEMA,
3230
+ dispatch: {
3231
+ call: BATCH_EXECUTE_DISPATCH_CALL,
3232
+ modelType: BATCH_EXECUTE_DISPATCH_MODEL_TYPE
3233
+ },
3234
+ staticHandler: handler,
3235
+ filterMetadata: {
3236
+ visibilityKind: 'declarative',
3237
+ rule: {
3238
+ requireAuthenticated: true
3239
+ },
3240
+ effectiveReadOnly: false
3241
+ },
3242
+ staticWireEntry: buildStaticWireEntry({
3243
+ name: name,
3244
+ description: description,
3245
+ inputSchema: BATCH_EXECUTE_INPUT_SCHEMA,
3246
+ outputSchema: BATCH_EXECUTE_OUTPUT_SCHEMA
3247
+ })
3248
+ };
3249
+ }
3250
+ // MARK: Handler
3251
+ function batchExecuteToolHandler(args, ctx, deps) {
3252
+ return _async_to_generator$3(function() {
3253
+ var result, _deps_maxOperations, input, maxOperations, fileText, operations, preflightErrors, execution, failureCount, successCount, skippedCount, uploadDeleted, summary, error;
3254
+ return _ts_generator$3(this, function(_state) {
3255
+ switch(_state.label){
3256
+ case 0:
3257
+ _state.trys.push([
3258
+ 0,
3259
+ 4,
3260
+ ,
3261
+ 5
3262
+ ]);
3263
+ input = parseBatchExecuteInput(args);
3264
+ maxOperations = (_deps_maxOperations = deps.maxOperations) !== null && _deps_maxOperations !== void 0 ? _deps_maxOperations : MAX_BATCH_EXECUTE_OPERATIONS;
3265
+ return [
3266
+ 4,
3267
+ readOperationsFile({
3268
+ storageService: deps.storageService,
3269
+ uploadPath: input.uploadPath,
3270
+ bucketId: input.bucketId
3271
+ })
3272
+ ];
3273
+ case 1:
3274
+ fileText = _state.sent();
3275
+ operations = parseOperations(fileText, input.format, maxOperations);
3276
+ // Pre-flight: validate + authorize every operation before any dispatch. dispatch() bypasses the
3277
+ // tools/list visibility filter, so an unauthorized operation must never reach it.
3278
+ preflightErrors = collectPreflightErrors(operations, deps.authorizeOperation);
3279
+ if (preflightErrors.length > 0) {
3280
+ throw new Error("batch-execute: ".concat(preflightErrors.length, " of ").concat(operations.length, " operation(s) failed pre-flight; nothing was executed. ").concat(describePreflightErrors(preflightErrors)));
3281
+ }
3282
+ return [
3283
+ 4,
3284
+ executeOperations({
3285
+ operations: operations,
3286
+ input: input,
3287
+ ctx: ctx,
3288
+ dispatch: deps.dispatch
3289
+ })
3290
+ ];
3291
+ case 2:
3292
+ execution = _state.sent();
3293
+ failureCount = execution.errors.length;
3294
+ successCount = execution.succeededCount;
3295
+ skippedCount = operations.length - successCount - failureCount;
3296
+ return [
3297
+ 4,
3298
+ maybeDeleteUpload({
3299
+ storageService: deps.storageService,
3300
+ input: input,
3301
+ failureCount: failureCount
3302
+ })
3303
+ ];
3304
+ case 3:
3305
+ uploadDeleted = _state.sent();
3306
+ summary = {
3307
+ total: operations.length,
3308
+ successCount: successCount,
3309
+ failureCount: failureCount,
3310
+ skippedCount: skippedCount,
3311
+ errors: execution.errors,
3312
+ uploadDeleted: uploadDeleted
3313
+ };
3314
+ result = {
3315
+ content: [
3316
+ {
3317
+ type: 'text',
3318
+ text: JSON.stringify(summary)
3319
+ }
3320
+ ],
3321
+ structuredContent: summary
3322
+ };
3323
+ return [
3324
+ 3,
3325
+ 5
3326
+ ];
3327
+ case 4:
3328
+ error = _state.sent();
3329
+ result = formatMcpToolErrorResponse(error);
3330
+ return [
3331
+ 3,
3332
+ 5
3333
+ ];
3334
+ case 5:
3335
+ return [
3336
+ 2,
3337
+ result
3338
+ ];
3339
+ }
3340
+ });
3341
+ })();
3342
+ }
3343
+ // MARK: Input parsing
3344
+ function parseBatchExecuteInput(args) {
3345
+ var _args_format, _args_maxParallel;
3346
+ var uploadPath = args.uploadPath;
3347
+ if (typeof uploadPath !== 'string' || uploadPath.length === 0) {
3348
+ throw new Error('batch-execute: "uploadPath" is required and must be a non-empty string.');
3349
+ }
3350
+ var bucketId = args.bucketId;
3351
+ if (bucketId != null && (typeof bucketId !== 'string' || bucketId.length === 0)) {
3352
+ throw new Error('batch-execute: "bucketId" must be a non-empty string when provided.');
3353
+ }
3354
+ var format = (_args_format = args.format) !== null && _args_format !== void 0 ? _args_format : 'ndjson';
3355
+ if (format !== 'json' && format !== 'ndjson') {
3356
+ throw new Error('batch-execute: "format" must be "json" or "ndjson".');
3357
+ }
3358
+ var maxParallel = (_args_maxParallel = args.maxParallel) !== null && _args_maxParallel !== void 0 ? _args_maxParallel : DEFAULT_BATCH_EXECUTE_MAX_PARALLEL;
3359
+ if (typeof maxParallel !== 'number' || !Number.isInteger(maxParallel) || maxParallel < 1) {
3360
+ throw new Error('batch-execute: "maxParallel" must be a positive integer.');
3361
+ }
3362
+ return {
3363
+ uploadPath: uploadPath,
3364
+ bucketId: bucketId !== null && bucketId !== void 0 ? bucketId : undefined,
3365
+ format: format,
3366
+ maxParallel: maxParallel,
3367
+ stopOnError: args.stopOnError === true,
3368
+ deleteUploadOnSuccess: args.deleteUploadOnSuccess !== false
3369
+ };
3370
+ }
3371
+ function readOperationsFile(input) {
3372
+ return _async_to_generator$3(function() {
3373
+ var file, exists, bytes;
3374
+ return _ts_generator$3(this, function(_state) {
3375
+ switch(_state.label){
3376
+ case 0:
3377
+ file = input.storageService.file(toStoragePathInput(input.uploadPath, input.bucketId));
3378
+ return [
3379
+ 4,
3380
+ file.exists()
3381
+ ];
3382
+ case 1:
3383
+ exists = _state.sent();
3384
+ if (!exists) {
3385
+ throw new Error('batch-execute: operations file not found at "'.concat(input.uploadPath, '".'));
3386
+ }
3387
+ return [
3388
+ 4,
3389
+ file.getBytes(MAX_BATCH_EXECUTE_FILE_BYTES)
3390
+ ];
3391
+ case 2:
3392
+ bytes = _state.sent();
3393
+ return [
3394
+ 2,
3395
+ Buffer.from(bytes).toString('utf8')
3396
+ ];
3397
+ }
3398
+ });
3399
+ })();
3400
+ }
3401
+ // MARK: Operation parsing
3402
+ function parseOperations(fileText, format, maxOperations) {
3403
+ var rawOperations = format === 'ndjson' ? parseNdjsonOperations(fileText) : parseJsonArrayOperations(fileText);
3404
+ if (rawOperations.length === 0) {
3405
+ throw new Error('batch-execute: the operations file contained no operations.');
3406
+ }
3407
+ if (rawOperations.length > maxOperations) {
3408
+ throw new Error("batch-execute: ".concat(rawOperations.length, " operations exceed the limit of ").concat(maxOperations, "."));
3409
+ }
3410
+ return rawOperations.map(function(value, index) {
3411
+ return validateOperation(value, index);
3412
+ });
3413
+ }
3414
+ function parseNdjsonOperations(fileText) {
3415
+ var operations = [];
3416
+ fileText.split('\n').forEach(function(line, lineIndex) {
3417
+ var trimmed = line.trim();
3418
+ if (trimmed.length > 0) {
3419
+ try {
3420
+ operations.push(JSON.parse(trimmed));
3421
+ } catch (error) {
3422
+ throw new Error("batch-execute: invalid JSON on line ".concat(lineIndex + 1, ": ").concat(error.message), {
3423
+ cause: error
3424
+ });
3425
+ }
3426
+ }
3427
+ });
3428
+ return operations;
3429
+ }
3430
+ function parseJsonArrayOperations(fileText) {
3431
+ var parsed;
3432
+ try {
3433
+ parsed = JSON.parse(fileText);
3434
+ } catch (error) {
3435
+ throw new Error("batch-execute: file is not valid JSON: ".concat(error.message), {
3436
+ cause: error
3437
+ });
3438
+ }
3439
+ if (!Array.isArray(parsed)) {
3440
+ throw new Error('batch-execute: with format "json" the file must contain a top-level array of operations.');
3441
+ }
3442
+ return parsed;
3443
+ }
3444
+ function validateOperation(value, index) {
3445
+ if (value == null || (typeof value === "undefined" ? "undefined" : _type_of$1(value)) !== 'object') {
3446
+ throw new Error("batch-execute: operation[".concat(index, "] must be an object."));
3447
+ }
3448
+ var candidate = value;
3449
+ var modelType = candidate.modelType;
3450
+ var call = candidate.call;
3451
+ var specifier = candidate.specifier;
3452
+ if (typeof modelType !== 'string' || modelType.length === 0) {
3453
+ throw new Error("batch-execute: operation[".concat(index, '] is missing a non-empty "modelType".'));
3454
+ }
3455
+ if (typeof call !== 'string' || call.length === 0) {
3456
+ throw new Error("batch-execute: operation[".concat(index, '] is missing a non-empty "call".'));
3457
+ }
3458
+ if (specifier != null && typeof specifier !== 'string') {
3459
+ throw new Error("batch-execute: operation[".concat(index, '] "specifier" must be a string when provided.'));
3460
+ }
3461
+ return {
3462
+ call: call,
3463
+ modelType: modelType,
3464
+ specifier: specifier !== null && specifier !== void 0 ? specifier : undefined,
3465
+ data: candidate.data
3466
+ };
3467
+ }
3468
+ function collectPreflightErrors(operations, authorizeOperation) {
3469
+ var errors = [];
3470
+ operations.forEach(function(operation, index) {
3471
+ var authorization = authorizeOperation(operation);
3472
+ if (!authorization.allowed) {
3473
+ var _operation_call;
3474
+ errors.push({
3475
+ index: index,
3476
+ modelType: operation.modelType,
3477
+ call: (_operation_call = operation.call) !== null && _operation_call !== void 0 ? _operation_call : undefined,
3478
+ specifier: operation.specifier,
3479
+ reason: authorization.reason
3480
+ });
3481
+ }
3482
+ });
3483
+ return errors;
3484
+ }
3485
+ function describePreflightErrors(errors) {
3486
+ var sample = errors.slice(0, 5).map(function(error) {
3487
+ var _error_call;
3488
+ var specifierSuffix = error.specifier ? "/".concat(error.specifier) : '';
3489
+ return "[".concat(error.index, "] ").concat((_error_call = error.call) !== null && _error_call !== void 0 ? _error_call : '?', "/").concat(error.modelType).concat(specifierSuffix, ": ").concat(error.reason);
3490
+ }).join('; ');
3491
+ var suffix = errors.length > 5 ? " (+".concat(errors.length - 5, " more)") : '';
3492
+ return "".concat(sample).concat(suffix);
3493
+ }
3494
+ function executeOperations(input) {
3495
+ return _async_to_generator$3(function() {
3496
+ return _ts_generator$3(this, function(_state) {
3497
+ return [
3498
+ 2,
3499
+ input.input.stopOnError ? executeSequentialStopOnError(input) : executeBestEffort(input)
3500
+ ];
3501
+ });
3502
+ })();
3503
+ }
3504
+ function executeBestEffort(input) {
3505
+ return _async_to_generator$3(function() {
3506
+ var operations, ctx, dispatch, indices, taskResult, errors;
3507
+ return _ts_generator$3(this, function(_state) {
3508
+ switch(_state.label){
3509
+ case 0:
3510
+ operations = input.operations, ctx = input.ctx, dispatch = input.dispatch;
3511
+ indices = operations.map(function(_, index) {
3512
+ return index;
3513
+ });
3514
+ return [
3515
+ 4,
3516
+ util.performAsyncTasks(indices, function(index) {
3517
+ return _async_to_generator$3(function() {
3518
+ var entry, error;
3519
+ return _ts_generator$3(this, function(_state) {
3520
+ switch(_state.label){
3521
+ case 0:
3522
+ _state.trys.push([
3523
+ 0,
3524
+ 2,
3525
+ ,
3526
+ 3
3527
+ ]);
3528
+ return [
3529
+ 4,
3530
+ dispatch(operations[index], ctx.auth, ctx.rawRequest)
3531
+ ];
3532
+ case 1:
3533
+ _state.sent();
3534
+ return [
3535
+ 3,
3536
+ 3
3537
+ ];
3538
+ case 2:
3539
+ error = _state.sent();
3540
+ entry = toErrorEntry(operations[index], index, error);
3541
+ return [
3542
+ 3,
3543
+ 3
3544
+ ];
3545
+ case 3:
3546
+ return [
3547
+ 2,
3548
+ entry
3549
+ ];
3550
+ }
3551
+ });
3552
+ })();
3553
+ }, {
3554
+ throwError: false,
3555
+ maxParallelTasks: input.input.maxParallel
3556
+ })
3557
+ ];
3558
+ case 1:
3559
+ taskResult = _state.sent();
3560
+ errors = taskResult.results.map(function(param) {
3561
+ var _param = _sliced_to_array$1(param, 2), entry = _param[1];
3562
+ return entry;
3563
+ }).filter(function(entry) {
3564
+ return entry != null;
3565
+ }).sort(function(a, b) {
3566
+ return a.index - b.index;
3567
+ });
3568
+ return [
3569
+ 2,
3570
+ {
3571
+ succeededCount: operations.length - errors.length,
3572
+ errors: errors
3573
+ }
3574
+ ];
3575
+ }
3576
+ });
3577
+ })();
3578
+ }
3579
+ function executeSequentialStopOnError(input) {
3580
+ return _async_to_generator$3(function() {
3581
+ var operations, ctx, dispatch, errors, succeededCount, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, _step_value, index, operation, error, err;
3582
+ return _ts_generator$3(this, function(_state) {
3583
+ switch(_state.label){
3584
+ case 0:
3585
+ operations = input.operations, ctx = input.ctx, dispatch = input.dispatch;
3586
+ errors = [];
3587
+ succeededCount = 0;
3588
+ _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
3589
+ _state.label = 1;
3590
+ case 1:
3591
+ _state.trys.push([
3592
+ 1,
3593
+ 8,
3594
+ 9,
3595
+ 10
3596
+ ]);
3597
+ _iterator = operations.entries()[Symbol.iterator]();
3598
+ _state.label = 2;
3599
+ case 2:
3600
+ if (!!(_iteratorNormalCompletion = (_step = _iterator.next()).done)) return [
3601
+ 3,
3602
+ 7
3603
+ ];
3604
+ _step_value = _sliced_to_array$1(_step.value, 2), index = _step_value[0], operation = _step_value[1];
3605
+ _state.label = 3;
3606
+ case 3:
3607
+ _state.trys.push([
3608
+ 3,
3609
+ 5,
3610
+ ,
3611
+ 6
3612
+ ]);
3613
+ return [
3614
+ 4,
3615
+ dispatch(operation, ctx.auth, ctx.rawRequest)
3616
+ ];
3617
+ case 4:
3618
+ _state.sent();
3619
+ succeededCount += 1;
3620
+ return [
3621
+ 3,
3622
+ 6
3623
+ ];
3624
+ case 5:
3625
+ error = _state.sent();
3626
+ errors.push(toErrorEntry(operation, index, error));
3627
+ return [
3628
+ 3,
3629
+ 7
3630
+ ];
3631
+ case 6:
3632
+ _iteratorNormalCompletion = true;
3633
+ return [
3634
+ 3,
3635
+ 2
3636
+ ];
3637
+ case 7:
3638
+ return [
3639
+ 3,
3640
+ 10
3641
+ ];
3642
+ case 8:
3643
+ err = _state.sent();
3644
+ _didIteratorError = true;
3645
+ _iteratorError = err;
3646
+ return [
3647
+ 3,
3648
+ 10
3649
+ ];
3650
+ case 9:
3651
+ try {
3652
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
3653
+ _iterator.return();
3654
+ }
3655
+ } finally{
3656
+ if (_didIteratorError) {
3657
+ throw _iteratorError;
3658
+ }
3659
+ }
3660
+ return [
3661
+ 7
3662
+ ];
3663
+ case 10:
3664
+ return [
3665
+ 2,
3666
+ {
3667
+ succeededCount: succeededCount,
3668
+ errors: errors
3669
+ }
3670
+ ];
3671
+ }
3672
+ });
3673
+ })();
3674
+ }
3675
+ function toErrorEntry(operation, index, error) {
3676
+ var _operation_call;
3677
+ return {
3678
+ index: index,
3679
+ modelType: operation.modelType,
3680
+ call: (_operation_call = operation.call) !== null && _operation_call !== void 0 ? _operation_call : undefined,
3681
+ specifier: operation.specifier,
3682
+ message: _instanceof(error, Error) ? error.message : String(error)
3683
+ };
3684
+ }
3685
+ function maybeDeleteUpload(input) {
3686
+ return _async_to_generator$3(function() {
3687
+ var deleted, file;
3688
+ return _ts_generator$3(this, function(_state) {
3689
+ switch(_state.label){
3690
+ case 0:
3691
+ deleted = false;
3692
+ if (!(input.input.deleteUploadOnSuccess && input.failureCount === 0)) return [
3693
+ 3,
3694
+ 2
3695
+ ];
3696
+ file = input.storageService.file(toStoragePathInput(input.input.uploadPath, input.input.bucketId));
3697
+ return [
3698
+ 4,
3699
+ file.delete()
3700
+ ];
3701
+ case 1:
3702
+ _state.sent();
3703
+ deleted = true;
3704
+ _state.label = 2;
3705
+ case 2:
3706
+ return [
3707
+ 2,
3708
+ deleted
3709
+ ];
2458
3710
  }
2459
- }
2460
- }
3711
+ });
3712
+ })();
3713
+ }
3714
+ /**
3715
+ * Builds a {@link StoragePathInput} from a path + optional bucket. Omits `bucketId` entirely when
3716
+ * absent (rather than passing `undefined`) so the accessor falls back to the app default bucket.
3717
+ *
3718
+ * @param pathString - The slash path of the file within the bucket.
3719
+ * @param bucketId - The bucket id, or `undefined` for the default bucket.
3720
+ * @returns The resolved storage path input.
3721
+ */ function toStoragePathInput(pathString, bucketId) {
3722
+ return bucketId != null ? {
3723
+ bucketId: bucketId,
3724
+ pathString: pathString
3725
+ } : {
3726
+ pathString: pathString
3727
+ };
2461
3728
  }
2462
3729
  // MARK: Schemas
2463
- var WHOAMI_INPUT_SCHEMA = {
2464
- type: 'object',
2465
- properties: {},
2466
- additionalProperties: false
2467
- };
2468
- var WHOAMI_OUTPUT_SCHEMA = {
3730
+ var BATCH_EXECUTE_INPUT_SCHEMA = {
2469
3731
  type: 'object',
2470
3732
  required: [
2471
- 'authenticated',
2472
- 'claims',
2473
- 'roles',
2474
- 'claimDetails',
2475
- 'unknownClaimKeys'
3733
+ 'uploadPath'
2476
3734
  ],
2477
- description: 'Caller identity, raw token claims, decoded role set, and per-claim descriptions for every key present on the live token.',
2478
3735
  properties: {
2479
- authenticated: {
2480
- type: 'boolean'
3736
+ uploadPath: {
3737
+ type: 'string',
3738
+ minLength: 1,
3739
+ description: 'Storage path of the uploaded operations file (JSON array or NDJSON).'
2481
3740
  },
2482
- uid: {
2483
- type: 'string'
3741
+ bucketId: {
3742
+ type: 'string',
3743
+ minLength: 1,
3744
+ description: 'Storage bucket id. Defaults to the app default bucket when omitted.'
2484
3745
  },
2485
- email: {
2486
- type: 'string'
3746
+ format: {
3747
+ type: 'string',
3748
+ enum: [
3749
+ 'json',
3750
+ 'ndjson'
3751
+ ],
3752
+ description: 'File format. "ndjson" (default) = one operation per line; "json" = a top-level array.'
2487
3753
  },
2488
- emailVerified: {
2489
- type: 'boolean'
3754
+ maxParallel: {
3755
+ type: 'integer',
3756
+ minimum: 1,
3757
+ description: "Operations dispatched concurrently. Defaults to ".concat(DEFAULT_BATCH_EXECUTE_MAX_PARALLEL, ". Ignored (forced to sequential) when stopOnError is true.")
2490
3758
  },
2491
- app: {
2492
- type: 'string'
3759
+ stopOnError: {
3760
+ type: 'boolean',
3761
+ description: 'Halt at the first runtime failure (runs sequentially). Defaults to false (best-effort; all operations attempted).'
2493
3762
  },
2494
- claims: {
2495
- type: 'object',
2496
- additionalProperties: true
3763
+ deleteUploadOnSuccess: {
3764
+ type: 'boolean',
3765
+ description: 'Delete the uploaded file when every operation succeeds. Defaults to true. The file is always kept when any operation fails.'
3766
+ }
3767
+ },
3768
+ additionalProperties: false
3769
+ };
3770
+ var BATCH_EXECUTE_OUTPUT_SCHEMA = {
3771
+ type: 'object',
3772
+ required: [
3773
+ 'total',
3774
+ 'successCount',
3775
+ 'failureCount',
3776
+ 'skippedCount',
3777
+ 'errors',
3778
+ 'uploadDeleted'
3779
+ ],
3780
+ properties: {
3781
+ total: {
3782
+ type: 'integer',
3783
+ description: 'Total operations in the file.'
2497
3784
  },
2498
- roles: {
2499
- type: 'array',
2500
- items: {
2501
- type: 'string'
2502
- }
3785
+ successCount: {
3786
+ type: 'integer',
3787
+ description: 'Operations that succeeded.'
2503
3788
  },
2504
- claimDetails: {
3789
+ failureCount: {
3790
+ type: 'integer',
3791
+ description: 'Operations that failed at runtime.'
3792
+ },
3793
+ skippedCount: {
3794
+ type: 'integer',
3795
+ description: 'Operations not attempted (only non-zero when stopOnError halted the run early).'
3796
+ },
3797
+ errors: {
2505
3798
  type: 'array',
3799
+ description: 'Per-operation runtime failures, keyed by original file index.',
2506
3800
  items: {
2507
3801
  type: 'object',
2508
3802
  required: [
2509
- 'key',
2510
- 'description',
2511
- 'grantedRoles',
2512
- 'inverse',
2513
- 'tags'
3803
+ 'index',
3804
+ 'modelType',
3805
+ 'message'
2514
3806
  ],
2515
3807
  properties: {
2516
- key: {
2517
- type: 'string'
3808
+ index: {
3809
+ type: 'integer'
2518
3810
  },
2519
- interfaceName: {
3811
+ modelType: {
2520
3812
  type: 'string'
2521
3813
  },
2522
- description: {
3814
+ call: {
2523
3815
  type: 'string'
2524
3816
  },
2525
- grantedRoles: {
2526
- type: 'array',
2527
- items: {
2528
- type: 'string'
2529
- }
2530
- },
2531
- inverse: {
2532
- type: 'boolean'
3817
+ specifier: {
3818
+ type: 'string'
2533
3819
  },
2534
- tags: {
2535
- type: 'array',
2536
- items: {
2537
- type: 'string'
2538
- }
3820
+ message: {
3821
+ type: 'string'
2539
3822
  }
2540
3823
  }
2541
3824
  }
2542
3825
  },
2543
- unknownClaimKeys: {
2544
- type: 'array',
2545
- items: {
2546
- type: 'string'
2547
- }
3826
+ uploadDeleted: {
3827
+ type: 'boolean',
3828
+ description: 'Whether the uploaded operations file was deleted after the run.'
2548
3829
  }
2549
3830
  }
2550
3831
  };
@@ -2775,12 +4056,13 @@ var McpServerFactoryService_1;
2775
4056
  * recommends a fresh `McpServer` + transport pair per stateless JSON-RPC request,
2776
4057
  * which sidesteps session bookkeeping for the common Claude-connector case.
2777
4058
  */ exports.McpServerFactoryService = McpServerFactoryService_1 = /*#__PURE__*/ function() {
2778
- function McpServerFactoryService(mcpConfig, dispatchService, modelApiGetService, roleReader, analyticsService) {
4059
+ function McpServerFactoryService(mcpConfig, dispatchService, modelApiGetService, roleReader, analyticsService, storageService) {
2779
4060
  _class_call_check$3(this, McpServerFactoryService);
2780
4061
  _define_property$3(this, "mcpConfig", void 0);
2781
4062
  _define_property$3(this, "dispatchService", void 0);
2782
4063
  _define_property$3(this, "modelApiGetService", void 0);
2783
4064
  _define_property$3(this, "roleReader", void 0);
4065
+ _define_property$3(this, "storageService", void 0);
2784
4066
  _define_property$3(this, "_logger", new common.Logger(McpServerFactoryService_1.name));
2785
4067
  _define_property$3(this, "_cachedTools", void 0);
2786
4068
  _define_property$3(this, "_cachedStaticTools", void 0);
@@ -2795,6 +4077,7 @@ var McpServerFactoryService_1;
2795
4077
  this.dispatchService = dispatchService;
2796
4078
  this.modelApiGetService = modelApiGetService;
2797
4079
  this.roleReader = roleReader;
4080
+ this.storageService = storageService;
2798
4081
  this._analyticsService = analyticsService !== null && analyticsService !== void 0 ? analyticsService : noopMcpAnalyticsService();
2799
4082
  }
2800
4083
  _create_class$3(McpServerFactoryService, [
@@ -2835,6 +4118,16 @@ var McpServerFactoryService_1;
2835
4118
  tool
2836
4119
  ];
2837
4120
  }));
4121
+ // The batch tool is request-scoped: it authorizes each batched operation against this caller's
4122
+ // resolved visible tool set, so it can't be cached like the other static tools.
4123
+ var batchTool = this._resolveBatchTool(ctx, definitionsByName);
4124
+ var listedTools = visibleTools;
4125
+ if (batchTool != null) {
4126
+ definitionsByName.set(batchTool.name, batchTool);
4127
+ listedTools = _to_consumable_array$2(visibleTools).concat([
4128
+ batchTool
4129
+ ]);
4130
+ }
2838
4131
  server.server.setRequestHandler(types_js.ListToolsRequestSchema, function() {
2839
4132
  return _async_to_generator$2(function() {
2840
4133
  var _this;
@@ -2843,7 +4136,7 @@ var McpServerFactoryService_1;
2843
4136
  return [
2844
4137
  2,
2845
4138
  {
2846
- tools: visibleTools.map(function(tool) {
4139
+ tools: listedTools.map(function(tool) {
2847
4140
  return _this._buildToolListEntry(tool, ctx, scopes);
2848
4141
  })
2849
4142
  }
@@ -2882,21 +4175,84 @@ var McpServerFactoryService_1;
2882
4175
  result = {
2883
4176
  tools: [],
2884
4177
  neverVisibleTools: [],
2885
- skipped: []
4178
+ skipped: [],
4179
+ warnings: []
2886
4180
  };
2887
4181
  } else {
2888
- result = generateMcpToolDefinitions(apiDetails, undefined, manifest);
4182
+ result = generateMcpToolDefinitions(apiDetails, undefined, {
4183
+ manifest: manifest,
4184
+ naming: this._resolveToolNamingOptions()
4185
+ });
2889
4186
  }
2890
4187
  this._cachedTools = result;
2891
4188
  }
2892
- if (!this._loggedSkips && result.skipped.length > 0) {
4189
+ if (!this._loggedSkips && (result.skipped.length > 0 || result.warnings.length > 0)) {
2893
4190
  this._loggedSkips = true;
2894
4191
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
2895
4192
  try {
2896
4193
  for(var _iterator = result.skipped[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
2897
4194
  var skip = _step.value;
2898
- var errorSuffix = skip.error ? ": ".concat(skip.error.message) : '';
2899
- this._logger.warn("Skipped MCP tool ".concat(skip.toolName, " (").concat(skip.reason, ")").concat(errorSuffix));
4195
+ this._logSkip(skip);
4196
+ }
4197
+ } catch (err) {
4198
+ _didIteratorError = true;
4199
+ _iteratorError = err;
4200
+ } finally{
4201
+ try {
4202
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
4203
+ _iterator.return();
4204
+ }
4205
+ } finally{
4206
+ if (_didIteratorError) {
4207
+ throw _iteratorError;
4208
+ }
4209
+ }
4210
+ }
4211
+ var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
4212
+ try {
4213
+ for(var _iterator1 = result.warnings[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
4214
+ var warning = _step1.value;
4215
+ this._logger.warn(this._describeToolGenerationWarning(warning));
4216
+ }
4217
+ } catch (err) {
4218
+ _didIteratorError1 = true;
4219
+ _iteratorError1 = err;
4220
+ } finally{
4221
+ try {
4222
+ if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
4223
+ _iterator1.return();
4224
+ }
4225
+ } finally{
4226
+ if (_didIteratorError1) {
4227
+ throw _iteratorError1;
4228
+ }
4229
+ }
4230
+ }
4231
+ }
4232
+ return result;
4233
+ }
4234
+ },
4235
+ {
4236
+ /**
4237
+ * Builds the per-model tool-name segment overrides from the loaded manifest's `models` catalog.
4238
+ *
4239
+ * Sourcing the segments from the manifest (rather than runtime config) keeps the runtime in
4240
+ * agreement with the build-time manifest validation, which reads the same `mcpToolNameSegment`.
4241
+ *
4242
+ * @returns Naming options carrying the segment map, or `undefined` when no model declares one.
4243
+ */ key: "_resolveToolNamingOptions",
4244
+ value: function _resolveToolNamingOptions() {
4245
+ var models = this._cachedManifestModels;
4246
+ var result;
4247
+ if (models != null && models.length > 0) {
4248
+ var modelSegments = new Map();
4249
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
4250
+ try {
4251
+ for(var _iterator = models[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
4252
+ var model = _step.value;
4253
+ if (model.mcpToolNameSegment != null && model.mcpToolNameSegment.length > 0) {
4254
+ modelSegments.set(model.modelType, model.mcpToolNameSegment);
4255
+ }
2900
4256
  }
2901
4257
  } catch (err) {
2902
4258
  _didIteratorError = true;
@@ -2912,6 +4268,47 @@ var McpServerFactoryService_1;
2912
4268
  }
2913
4269
  }
2914
4270
  }
4271
+ if (modelSegments.size > 0) {
4272
+ result = {
4273
+ modelSegments: modelSegments
4274
+ };
4275
+ }
4276
+ }
4277
+ return result;
4278
+ }
4279
+ },
4280
+ {
4281
+ /**
4282
+ * Logs one skipped tool at the appropriate level: name-cap and collision skips are errors (they
4283
+ * would otherwise break or shadow tools on the wire), the rest are warnings.
4284
+ *
4285
+ * @param skip - The skipped-tool report to log.
4286
+ */ key: "_logSkip",
4287
+ value: function _logSkip(skip) {
4288
+ var errorSuffix = skip.error ? ": ".concat(skip.error.message) : '';
4289
+ if (skip.reason === 'name_too_long') {
4290
+ this._logger.error("Dropped MCP tool ".concat(skip.toolName, " — its name is ").concat(skip.toolName.length, " chars, over the ").concat(MCP_TOOL_NAME_MAX_LENGTH, "-char limit. Shorten the model/specifier, hide it (mcp.visibility: false), or set an mcp.name override."));
4291
+ } else if (skip.reason === 'duplicate_name') {
4292
+ this._logger.error("Dropped MCP tool ".concat(skip.toolName, " — another visible tool already resolved to this name. Give one an mcp.name override to disambiguate."));
4293
+ } else {
4294
+ this._logger.warn("Skipped MCP tool ".concat(skip.toolName, " (").concat(skip.reason, ")").concat(errorSuffix));
4295
+ }
4296
+ }
4297
+ },
4298
+ {
4299
+ /**
4300
+ * Renders a human-readable boot-time warning for an MCP-result mapping inconsistency between a
4301
+ * handler's `mapSuccessfulResult` and the build-time manifest.
4302
+ *
4303
+ * @param warning - The tool-generation warning to describe.
4304
+ * @returns The log line to emit at startup.
4305
+ */ key: "_describeToolGenerationWarning",
4306
+ value: function _describeToolGenerationWarning(warning) {
4307
+ var result;
4308
+ if (warning.reason === 'mapper_without_mapped_manifest') {
4309
+ result = "MCP tool ".concat(warning.toolName, " declares mcp.mapSuccessfulResult but its manifest entry has no mapped result type — annotate the matching '.api.ts' leaf with '@dbxModelApiMcpResult <TypeName>' and regenerate the manifest so the advertised output schema matches the mapped result.");
4310
+ } else {
4311
+ result = "MCP tool ".concat(warning.toolName, " has a '@dbxModelApiMcpResult' manifest annotation but its handler no longer declares mcp.mapSuccessfulResult — remove the stale annotation and regenerate the manifest, or restore the mapper.");
2915
4312
  }
2916
4313
  return result;
2917
4314
  }
@@ -3000,6 +4397,92 @@ var McpServerFactoryService_1;
3000
4397
  },
3001
4398
  {
3002
4399
  /**
4400
+ * Builds the per-request `batch-execute` tool, or `undefined` when it should not be offered.
4401
+ *
4402
+ * Unlike the cached static tools this is rebuilt per request, because it closes over the caller's
4403
+ * resolved visible tool set: each batched operation is authorized against exactly the callModel
4404
+ * tools this caller may invoke directly. Offered only when a storage service is wired (it reads
4405
+ * the uploaded operations file), the caller is authenticated, and the server is not in read-only
4406
+ * mode (the tool performs writes).
4407
+ *
4408
+ * @param ctx - The per-request context (auth, raw request) forwarded to dispatched operations.
4409
+ * @param definitionsByName - The caller's visible tool definitions, keyed by name.
4410
+ * @returns The batch tool definition, or `undefined` when unavailable for this request.
4411
+ */ key: "_resolveBatchTool",
4412
+ value: function _resolveBatchTool(ctx, definitionsByName) {
4413
+ var _this = this;
4414
+ var result;
4415
+ var storageService = this.storageService;
4416
+ if (storageService != null && ctx.auth != null && this.mcpConfig.readOnly !== true) {
4417
+ var authorizedCoords = new Set();
4418
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
4419
+ try {
4420
+ for(var _iterator = definitionsByName.values()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
4421
+ var definition = _step.value;
4422
+ // Only callModel tools are re-dispatchable; static tools (model-get, whoami) have synthetic
4423
+ // dispatch identities the callModel chain can't resolve.
4424
+ if (definition.staticHandler == null) {
4425
+ authorizedCoords.add(batchOperationCoordKey(definition.dispatch));
4426
+ }
4427
+ }
4428
+ } catch (err) {
4429
+ _didIteratorError = true;
4430
+ _iteratorError = err;
4431
+ } finally{
4432
+ try {
4433
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
4434
+ _iterator.return();
4435
+ }
4436
+ } finally{
4437
+ if (_didIteratorError) {
4438
+ throw _iteratorError;
4439
+ }
4440
+ }
4441
+ }
4442
+ result = createBatchExecuteTool({
4443
+ storageService: storageService,
4444
+ dispatch: function dispatch(operation, auth, rawRequest) {
4445
+ return _this.dispatchService.dispatch(operation, auth, rawRequest);
4446
+ },
4447
+ authorizeOperation: function authorizeOperation(operation) {
4448
+ return _this._authorizeBatchOperation(operation, authorizedCoords);
4449
+ }
4450
+ });
4451
+ }
4452
+ return result;
4453
+ }
4454
+ },
4455
+ {
4456
+ /**
4457
+ * Authorizes a single batched operation against the caller's visible callModel tool coordinates.
4458
+ *
4459
+ * Re-applies the same gate the `tools/list` filter already enforced: an operation is allowed only
4460
+ * when its `(call, modelType, specifier)` coordinate matches a tool this caller can see. This is
4461
+ * the critical guard — `dispatchService.dispatch` bypasses the MCP visibility filter, so without
4462
+ * this check a batch could reach scope-, role-, or read-only-gated handlers.
4463
+ *
4464
+ * @param operation - The operation to authorize.
4465
+ * @param authorizedCoords - The set of dispatchable coordinate keys visible to this caller.
4466
+ * @returns Whether the operation may be dispatched, with a reason when it may not.
4467
+ */ key: "_authorizeBatchOperation",
4468
+ value: function _authorizeBatchOperation(operation, authorizedCoords) {
4469
+ var _operation_call, _operation_specifier, _operation_call1;
4470
+ var coordKey = batchOperationCoordKey({
4471
+ call: (_operation_call = operation.call) !== null && _operation_call !== void 0 ? _operation_call : '',
4472
+ modelType: operation.modelType,
4473
+ specifier: (_operation_specifier = operation.specifier) !== null && _operation_specifier !== void 0 ? _operation_specifier : undefined
4474
+ });
4475
+ var specifierSuffix = operation.specifier ? ' specifier="'.concat(operation.specifier, '"') : '';
4476
+ return authorizedCoords.has(coordKey) ? {
4477
+ allowed: true
4478
+ } : {
4479
+ allowed: false,
4480
+ reason: 'no visible tool matches call="'.concat((_operation_call1 = operation.call) !== null && _operation_call1 !== void 0 ? _operation_call1 : '', '" modelType="').concat(operation.modelType, '"').concat(specifierSuffix, " (unknown, or hidden by scope/role/read-only).")
4481
+ };
4482
+ }
4483
+ },
4484
+ {
4485
+ /**
3003
4486
  * Reads the pre-rendered MCP manifest JSON once, validates its version, and caches the
3004
4487
  * resulting `key → entry` map plus the optional `models` catalog for the process lifetime.
3005
4488
  *
@@ -3424,7 +4907,7 @@ var McpServerFactoryService_1;
3424
4907
  key: "_handleCallModelToolCall",
3425
4908
  value: function _handleCallModelToolCall(definition, args, ctx) {
3426
4909
  return _async_to_generator$2(function() {
3427
- var params, outcome, result, error;
4910
+ var params, outcome, result, _tmp, error;
3428
4911
  return _ts_generator$2(this, function(_state) {
3429
4912
  switch(_state.label){
3430
4913
  case 0:
@@ -3438,9 +4921,9 @@ var McpServerFactoryService_1;
3438
4921
  case 1:
3439
4922
  _state.trys.push([
3440
4923
  1,
3441
- 3,
4924
+ 4,
3442
4925
  ,
3443
- 4
4926
+ 5
3444
4927
  ]);
3445
4928
  return [
3446
4929
  4,
@@ -3448,14 +4931,18 @@ var McpServerFactoryService_1;
3448
4931
  ];
3449
4932
  case 2:
3450
4933
  result = _state.sent();
3451
- outcome = {
3452
- response: formatMcpToolResponse(result, params, definition.details)
3453
- };
4934
+ _tmp = {};
3454
4935
  return [
3455
- 3,
3456
- 4
4936
+ 4,
4937
+ formatMcpToolResponse(result, params, definition.details)
3457
4938
  ];
3458
4939
  case 3:
4940
+ outcome = (_tmp.response = _state.sent(), _tmp);
4941
+ return [
4942
+ 3,
4943
+ 5
4944
+ ];
4945
+ case 4:
3459
4946
  error = _state.sent();
3460
4947
  outcome = {
3461
4948
  response: formatMcpToolErrorResponse(error),
@@ -3463,9 +4950,9 @@ var McpServerFactoryService_1;
3463
4950
  };
3464
4951
  return [
3465
4952
  3,
3466
- 4
4953
+ 5
3467
4954
  ];
3468
- case 4:
4955
+ case 5:
3469
4956
  return [
3470
4957
  2,
3471
4958
  outcome
@@ -3487,7 +4974,9 @@ exports.McpServerFactoryService = McpServerFactoryService_1 = __decorate([
3487
4974
  __param(3, common.Optional()),
3488
4975
  __param(3, common.Inject(MCP_AUTH_ROLE_READER)),
3489
4976
  __param(4, common.Optional()),
3490
- __param(4, common.Inject(MCP_ANALYTICS_SERVICE))
4977
+ __param(4, common.Inject(MCP_ANALYTICS_SERVICE)),
4978
+ __param(5, common.Optional()),
4979
+ __param(5, common.Inject(firebaseServer.FirebaseServerStorageService))
3491
4980
  ], exports.McpServerFactoryService);
3492
4981
 
3493
4982
  function asyncGeneratorStep$1(gen, resolve, reject, _next, _throw, key, arg) {
@@ -4279,6 +5768,10 @@ function _unsupported_iterable_to_array(o, minLen) {
4279
5768
  };
4280
5769
  }
4281
5770
 
5771
+ exports.BATCH_EXECUTE_DISPATCH_CALL = BATCH_EXECUTE_DISPATCH_CALL;
5772
+ exports.BATCH_EXECUTE_DISPATCH_MODEL_TYPE = BATCH_EXECUTE_DISPATCH_MODEL_TYPE;
5773
+ exports.BATCH_EXECUTE_TOOL_NAME = BATCH_EXECUTE_TOOL_NAME;
5774
+ exports.DEFAULT_BATCH_EXECUTE_MAX_PARALLEL = DEFAULT_BATCH_EXECUTE_MAX_PARALLEL;
4282
5775
  exports.DEFAULT_JSON_SCHEMA_GENERATION_OPTIONS = DEFAULT_JSON_SCHEMA_GENERATION_OPTIONS;
4283
5776
  exports.DEFAULT_MCP_ANALYTICS_EVENT_NAME = DEFAULT_MCP_ANALYTICS_EVENT_NAME;
4284
5777
  exports.DEFAULT_MCP_PATH = DEFAULT_MCP_PATH;
@@ -4288,10 +5781,15 @@ exports.DEFAULT_SPECIFIER_KEY = DEFAULT_SPECIFIER_KEY;
4288
5781
  exports.DEFAULT_VOID_MCP_SUCCESS_VALUE = DEFAULT_VOID_MCP_SUCCESS_VALUE;
4289
5782
  exports.FIREBASE_SERVER_MCP_ANALYTICS_CONFIG = FIREBASE_SERVER_MCP_ANALYTICS_CONFIG;
4290
5783
  exports.FIREBASE_SERVER_MCP_ROUTES_FOR_GLOBAL_ROUTE_EXCLUDE = FIREBASE_SERVER_MCP_ROUTES_FOR_GLOBAL_ROUTE_EXCLUDE;
5784
+ exports.MAX_BATCH_EXECUTE_FILE_BYTES = MAX_BATCH_EXECUTE_FILE_BYTES;
5785
+ exports.MAX_BATCH_EXECUTE_OPERATIONS = MAX_BATCH_EXECUTE_OPERATIONS;
4291
5786
  exports.MCP_ANALYTICS_SERVICE = MCP_ANALYTICS_SERVICE;
4292
5787
  exports.MCP_AUTH_ROLE_READER = MCP_AUTH_ROLE_READER;
5788
+ exports.MCP_CALL_TYPE_ABBREVIATIONS = MCP_CALL_TYPE_ABBREVIATIONS;
4293
5789
  exports.MCP_MANIFEST_VERSION = MCP_MANIFEST_VERSION;
4294
5790
  exports.MCP_MODEL_GET_BATCH_SIZE = MCP_MODEL_GET_BATCH_SIZE;
5791
+ exports.MCP_TOOL_NAME_MAX_LENGTH = MCP_TOOL_NAME_MAX_LENGTH;
5792
+ exports.MCP_TOOL_NAME_WARN_LENGTH = MCP_TOOL_NAME_WARN_LENGTH;
4295
5793
  exports.MODEL_DECODE_DISPATCH_CALL = MODEL_DECODE_DISPATCH_CALL;
4296
5794
  exports.MODEL_DECODE_DISPATCH_MODEL_TYPE = MODEL_DECODE_DISPATCH_MODEL_TYPE;
4297
5795
  exports.MODEL_DECODE_TOOL_NAME = MODEL_DECODE_TOOL_NAME;
@@ -4305,11 +5803,15 @@ exports.MODEL_INFO_TOOL_NAME = MODEL_INFO_TOOL_NAME;
4305
5803
  exports.MODEL_INFO_UNGROUPED_LABEL = MODEL_INFO_UNGROUPED_LABEL;
4306
5804
  exports.McpAnalyticsService = McpAnalyticsService;
4307
5805
  exports.McpModuleConfig = McpModuleConfig;
5806
+ exports.abbreviateMcpCallType = abbreviateMcpCallType;
4308
5807
  exports.appMcpAnalyticsModuleMetadata = appMcpAnalyticsModuleMetadata;
5808
+ exports.batchOperationCoordKey = batchOperationCoordKey;
4309
5809
  exports.buildDefaultMcpToolDescription = buildDefaultMcpToolDescription;
5810
+ exports.buildDisambiguatedMcpToolName = buildDisambiguatedMcpToolName;
4310
5811
  exports.buildMcpToolName = buildMcpToolName;
4311
5812
  exports.buildStaticWireEntry = buildStaticWireEntry;
4312
5813
  exports.classifyVisibility = classifyVisibility;
5814
+ exports.createBatchExecuteTool = createBatchExecuteTool;
4313
5815
  exports.createModelDecodeTool = createModelDecodeTool;
4314
5816
  exports.createModelGetTool = createModelGetTool;
4315
5817
  exports.createModelInfoTool = createModelInfoTool;
@@ -4324,3 +5826,4 @@ exports.mcpModuleMetadata = mcpModuleMetadata;
4324
5826
  exports.noopMcpAnalyticsService = noopMcpAnalyticsService;
4325
5827
  exports.resolveEffectiveReadOnly = resolveEffectiveReadOnly;
4326
5828
  exports.resolveRequiredScope = resolveRequiredScope;
5829
+ exports.validateMcpToolName = validateMcpToolName;