@dereekb/firebase-server 13.12.1 → 13.12.3

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
@@ -12,12 +12,12 @@ var model = require('@dereekb/model');
12
12
  var firebase = require('@dereekb/firebase');
13
13
  var streamableHttp_js = require('@modelcontextprotocol/sdk/server/streamableHttp.js');
14
14
 
15
- function _class_call_check$3(instance, Constructor) {
15
+ function _class_call_check$5(instance, Constructor) {
16
16
  if (!(instance instanceof Constructor)) {
17
17
  throw new TypeError("Cannot call a class as a function");
18
18
  }
19
19
  }
20
- function _define_property$6(obj, key, value) {
20
+ function _define_property$7(obj, key, value) {
21
21
  if (key in obj) {
22
22
  Object.defineProperty(obj, key, {
23
23
  value: value,
@@ -43,6 +43,10 @@ function _define_property$6(obj, key, value) {
43
43
  * Apps may override this via {@link McpModuleConfig.serverName} to identify their
44
44
  * deployment (e.g., `demo-api-mcp`, `hellosubs-api-mcp`).
45
45
  */ var DEFAULT_MCP_SERVER_NAME = 'dbx-firebase-server-mcp';
46
+ /**
47
+ * Default `instructions` string advertised by the MCP server on the JSON-RPC `initialize`
48
+ * handshake. Apps may override this via {@link McpModuleConfig.serverInstructions}.
49
+ */ var DEFAULT_MCP_SERVER_INSTRUCTIONS = 'A set of call-model tools generated automatically.';
46
50
  /**
47
51
  * Configuration for the firebase-server/mcp module.
48
52
  *
@@ -59,7 +63,7 @@ function _define_property$6(obj, key, value) {
59
63
  * The OAuth bearer middleware that authenticates `/mcp` is configured on
60
64
  * {@link OidcModuleConfig.protectedPaths} — that's outside this config's scope.
61
65
  */ var McpModuleConfig = function McpModuleConfig() {
62
- _class_call_check$3(this, McpModuleConfig);
66
+ _class_call_check$5(this, McpModuleConfig);
63
67
  /**
64
68
  * The canonical issuer URL of the OIDC provider that gates this MCP endpoint.
65
69
  *
@@ -67,7 +71,7 @@ function _define_property$6(obj, key, value) {
67
71
  * discovery document. Claude custom-connector reads this to discover the OIDC issuer.
68
72
  *
69
73
  * @example 'https://api.example.com/oidc'
70
- */ _define_property$6(this, "oidcIssuer", void 0);
74
+ */ _define_property$7(this, "oidcIssuer", void 0);
71
75
  /**
72
76
  * The canonical resource URL of the MCP endpoint.
73
77
  *
@@ -75,14 +79,19 @@ function _define_property$6(obj, key, value) {
75
79
  * and used as the audience the access token's `aud` claim should match.
76
80
  *
77
81
  * @example 'https://api.example.com/mcp'
78
- */ _define_property$6(this, "mcpUrl", void 0);
82
+ */ _define_property$7(this, "mcpUrl", void 0);
79
83
  /**
80
84
  * Optional name advertised on the MCP `initialize` handshake. Defaults to
81
85
  * {@link DEFAULT_MCP_SERVER_NAME}.
82
- */ _define_property$6(this, "serverName", void 0);
86
+ */ _define_property$7(this, "serverName", void 0);
83
87
  /**
84
88
  * Optional version advertised on the MCP `initialize` handshake.
85
- */ _define_property$6(this, "serverVersion", void 0);
89
+ */ _define_property$7(this, "serverVersion", void 0);
90
+ /**
91
+ * Optional override for the `instructions` string passed to `new McpServer(...)` and
92
+ * advertised on the JSON-RPC `initialize` handshake. Defaults to
93
+ * {@link DEFAULT_MCP_SERVER_INSTRUCTIONS}.
94
+ */ _define_property$7(this, "serverInstructions", void 0);
86
95
  /**
87
96
  * Absolute path to a pre-rendered MCP manifest JSON file produced by
88
97
  * `dbx-cli-generate-mcp-manifest`. When set, the runtime reads it once at
@@ -92,7 +101,7 @@ function _define_property$6(obj, key, value) {
92
101
  * Optional. When unset or the file is missing, the runtime falls back to
93
102
  * today's behavior (auto-generated descriptions, ArkType-derived input
94
103
  * schemas, no output schemas) and emits a single boot warning.
95
- */ _define_property$6(this, "mcpManifestPath", void 0);
104
+ */ _define_property$7(this, "mcpManifestPath", void 0);
96
105
  /**
97
106
  * When `true`, the MCP server only advertises tools whose effective read-only classification is `true`.
98
107
  *
@@ -102,19 +111,19 @@ function _define_property$6(obj, key, value) {
102
111
  *
103
112
  * The advertised `serverName` on the JSON-RPC `initialize` handshake is suffixed with
104
113
  * ` (read-only)` so the client surface reflects the mode.
105
- */ _define_property$6(this, "readOnly", void 0);
114
+ */ _define_property$7(this, "readOnly", void 0);
106
115
  };
107
116
  /**
108
117
  * NestJS injection token for the optional {@link McpAuthRoleReader} provider.
109
118
  */ var MCP_AUTH_ROLE_READER = 'MCP_AUTH_ROLE_READER';
110
119
 
111
- function _type_of$1(obj) {
120
+ function _type_of$2(obj) {
112
121
  "@swc/helpers - typeof";
113
122
  return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj;
114
123
  }
115
124
  function __decorate(decorators, target, key, desc) {
116
125
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
117
- if ((typeof Reflect === "undefined" ? "undefined" : _type_of$1(Reflect)) === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
126
+ if ((typeof Reflect === "undefined" ? "undefined" : _type_of$2(Reflect)) === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
118
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;
119
128
  return c > 3 && r && Object.defineProperty(target, key, r), r;
120
129
  }
@@ -128,6 +137,39 @@ typeof SuppressedError === "function" ? SuppressedError : function(error, suppre
128
137
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
129
138
  };
130
139
 
140
+ function _class_call_check$4(instance, Constructor) {
141
+ if (!(instance instanceof Constructor)) {
142
+ throw new TypeError("Cannot call a class as a function");
143
+ }
144
+ }
145
+ /**
146
+ * Abstract analytics service that apps implement to process MCP analytics events.
147
+ *
148
+ * Analogous to {@link OnCallModelAnalyticsService} but scoped to the MCP transport.
149
+ * Apps extend this class and provide it via {@link MCP_ANALYTICS_SERVICE}.
150
+ */ var McpAnalyticsService = function McpAnalyticsService() {
151
+ _class_call_check$4(this, McpAnalyticsService);
152
+ };
153
+ /**
154
+ * Injection token for the MCP analytics service.
155
+ * Apps provide this in their MCP module to enable analytics in the MCP dispatch chain.
156
+ */ var MCP_ANALYTICS_SERVICE = 'MCP_ANALYTICS_SERVICE';
157
+ /**
158
+ * Creates a no-op {@link McpAnalyticsService} that silently discards all events.
159
+ *
160
+ * Used as the default fallback by {@link McpServerFactoryService} when no analytics
161
+ * service is registered.
162
+ *
163
+ * @returns An {@link McpAnalyticsService} that discards all analytics events.
164
+ * @__NO_SIDE_EFFECTS__
165
+ */ function noopMcpAnalyticsService() {
166
+ return {
167
+ handleMcpAnalyticsEvent: function handleMcpAnalyticsEvent() {
168
+ return undefined;
169
+ }
170
+ };
171
+ }
172
+
131
173
  /**
132
174
  * Version stamp embedded in the build-time MCP manifest JSON. Runtime loaders
133
175
  * refuse manifests whose `version` does not match this constant.
@@ -315,7 +357,7 @@ function stringifyResult(result) {
315
357
  return firebase.callModelOidcScopeForCallType(callType);
316
358
  }
317
359
 
318
- function _array_like_to_array$4(arr, len) {
360
+ function _array_like_to_array$6(arr, len) {
319
361
  if (len == null || len > arr.length) len = arr.length;
320
362
  for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
321
363
  return arr2;
@@ -351,19 +393,19 @@ function _non_iterable_rest$2() {
351
393
  throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
352
394
  }
353
395
  function _sliced_to_array$2(arr, i) {
354
- return _array_with_holes$2(arr) || _iterable_to_array_limit$2(arr, i) || _unsupported_iterable_to_array$4(arr, i) || _non_iterable_rest$2();
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();
355
397
  }
356
- function _type_of(obj) {
398
+ function _type_of$1(obj) {
357
399
  "@swc/helpers - typeof";
358
400
  return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj;
359
401
  }
360
- function _unsupported_iterable_to_array$4(o, minLen) {
402
+ function _unsupported_iterable_to_array$6(o, minLen) {
361
403
  if (!o) return;
362
- if (typeof o === "string") return _array_like_to_array$4(o, minLen);
404
+ if (typeof o === "string") return _array_like_to_array$6(o, minLen);
363
405
  var n = Object.prototype.toString.call(o).slice(8, -1);
364
406
  if (n === "Object" && o.constructor) n = o.constructor.name;
365
407
  if (n === "Map" || n === "Set") return Array.from(n);
366
- if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$4(o, minLen);
408
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$6(o, minLen);
367
409
  }
368
410
  /**
369
411
  * Default `toJsonSchema()` options.
@@ -630,7 +672,7 @@ function resolveInputSchema(context) {
630
672
  var result;
631
673
  try {
632
674
  var exported = model.arktypeToJsonSchemaForExport(handlerDetails.inputType);
633
- if (exported && (typeof exported === "undefined" ? "undefined" : _type_of(exported)) === 'object') {
675
+ if (exported && (typeof exported === "undefined" ? "undefined" : _type_of$1(exported)) === 'object') {
634
676
  result = exported;
635
677
  } else {
636
678
  // arktypeToJsonSchemaForExport returned a non-object (shouldn't happen for object schemas).
@@ -649,13 +691,13 @@ function resolveInputSchema(context) {
649
691
  return result;
650
692
  }
651
693
 
652
- function _array_like_to_array$3(arr, len) {
694
+ function _array_like_to_array$5(arr, len) {
653
695
  if (len == null || len > arr.length) len = arr.length;
654
696
  for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
655
697
  return arr2;
656
698
  }
657
- function _array_without_holes$3(arr) {
658
- if (Array.isArray(arr)) return _array_like_to_array$3(arr);
699
+ function _array_without_holes$5(arr) {
700
+ if (Array.isArray(arr)) return _array_like_to_array$5(arr);
659
701
  }
660
702
  function asyncGeneratorStep$3(gen, resolve, reject, _next, _throw, key, arg) {
661
703
  try {
@@ -686,22 +728,22 @@ function _async_to_generator$3(fn) {
686
728
  });
687
729
  };
688
730
  }
689
- function _iterable_to_array$3(iter) {
731
+ function _iterable_to_array$5(iter) {
690
732
  if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
691
733
  }
692
- function _non_iterable_spread$3() {
734
+ function _non_iterable_spread$5() {
693
735
  throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
694
736
  }
695
- function _to_consumable_array$3(arr) {
696
- return _array_without_holes$3(arr) || _iterable_to_array$3(arr) || _unsupported_iterable_to_array$3(arr) || _non_iterable_spread$3();
737
+ 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();
697
739
  }
698
- function _unsupported_iterable_to_array$3(o, minLen) {
740
+ function _unsupported_iterable_to_array$5(o, minLen) {
699
741
  if (!o) return;
700
- if (typeof o === "string") return _array_like_to_array$3(o, minLen);
742
+ if (typeof o === "string") return _array_like_to_array$5(o, minLen);
701
743
  var n = Object.prototype.toString.call(o).slice(8, -1);
702
744
  if (n === "Object" && o.constructor) n = o.constructor.name;
703
745
  if (n === "Map" || n === "Set") return Array.from(n);
704
- if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$3(o, minLen);
746
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$5(o, minLen);
705
747
  }
706
748
  function _ts_generator$3(thisArg, body) {
707
749
  var f, y, t, _ = {
@@ -1006,8 +1048,8 @@ function readInChunks(input) {
1006
1048
  ];
1007
1049
  case 2:
1008
1050
  partial = _state.sent();
1009
- (_merged_results = merged.results).push.apply(_merged_results, _to_consumable_array$3(partial.results));
1010
- (_merged_errors = merged.errors).push.apply(_merged_errors, _to_consumable_array$3(partial.errors));
1051
+ (_merged_results = merged.results).push.apply(_merged_results, _to_consumable_array$5(partial.results));
1052
+ (_merged_errors = merged.errors).push.apply(_merged_errors, _to_consumable_array$5(partial.errors));
1011
1053
  _state.label = 3;
1012
1054
  case 3:
1013
1055
  offset += MCP_MODEL_GET_BATCH_SIZE;
@@ -1098,7 +1140,15 @@ var MODEL_GET_OUTPUT_SCHEMA = {
1098
1140
  }
1099
1141
  };
1100
1142
 
1101
- function _define_property$5(obj, key, value) {
1143
+ function _array_like_to_array$4(arr, len) {
1144
+ if (len == null || len > arr.length) len = arr.length;
1145
+ for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
1146
+ return arr2;
1147
+ }
1148
+ function _array_without_holes$4(arr) {
1149
+ if (Array.isArray(arr)) return _array_like_to_array$4(arr);
1150
+ }
1151
+ function _define_property$6(obj, key, value) {
1102
1152
  if (key in obj) {
1103
1153
  Object.defineProperty(obj, key, {
1104
1154
  value: value,
@@ -1111,6 +1161,12 @@ function _define_property$5(obj, key, value) {
1111
1161
  }
1112
1162
  return obj;
1113
1163
  }
1164
+ function _iterable_to_array$4(iter) {
1165
+ if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
1166
+ }
1167
+ function _non_iterable_spread$4() {
1168
+ throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
1169
+ }
1114
1170
  function _object_spread$2(target) {
1115
1171
  for(var i = 1; i < arguments.length; i++){
1116
1172
  var source = arguments[i] != null ? arguments[i] : {};
@@ -1121,11 +1177,41 @@ function _object_spread$2(target) {
1121
1177
  }));
1122
1178
  }
1123
1179
  ownKeys.forEach(function(key) {
1124
- _define_property$5(target, key, source[key]);
1180
+ _define_property$6(target, key, source[key]);
1181
+ });
1182
+ }
1183
+ return target;
1184
+ }
1185
+ function ownKeys(object, enumerableOnly) {
1186
+ var keys = Object.keys(object);
1187
+ if (Object.getOwnPropertySymbols) {
1188
+ var symbols = Object.getOwnPropertySymbols(object);
1189
+ keys.push.apply(keys, symbols);
1190
+ }
1191
+ return keys;
1192
+ }
1193
+ function _object_spread_props(target, source) {
1194
+ source = source != null ? source : {};
1195
+ if (Object.getOwnPropertyDescriptors) {
1196
+ Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
1197
+ } else {
1198
+ ownKeys(Object(source)).forEach(function(key) {
1199
+ Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
1125
1200
  });
1126
1201
  }
1127
1202
  return target;
1128
1203
  }
1204
+ 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();
1206
+ }
1207
+ function _unsupported_iterable_to_array$4(o, minLen) {
1208
+ if (!o) return;
1209
+ if (typeof o === "string") return _array_like_to_array$4(o, minLen);
1210
+ var n = Object.prototype.toString.call(o).slice(8, -1);
1211
+ if (n === "Object" && o.constructor) n = o.constructor.name;
1212
+ 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);
1214
+ }
1129
1215
  // MARK: Constants
1130
1216
  /**
1131
1217
  * Reserved tool name for the built-in `model-info` static tool.
@@ -1138,13 +1224,27 @@ function _object_spread$2(target) {
1138
1224
  * Synthetic model type used in the tool's dispatch identity. Mirrors {@link MODEL_GET_DISPATCH_MODEL_TYPE};
1139
1225
  * apps avoiding collisions should not register a real model literally named "model".
1140
1226
  */ var MODEL_INFO_DISPATCH_MODEL_TYPE = 'model';
1227
+ /**
1228
+ * Group label applied to manifest entries that declare no `modelGroup`. Keeps the `groups` mode
1229
+ * total reconcilable with the catalog size (sum of group counts always equals `totalModels`).
1230
+ */ var MODEL_INFO_UNGROUPED_LABEL = '(ungrouped)';
1231
+ /**
1232
+ * Hint string surfaced alongside the default `groups` response so callers know how to drill in.
1233
+ */ var MODEL_INFO_GROUPS_HINT = 'Pass `model` for one/many models, `modelGroup` for a group, or `all:true` for the full catalog.';
1141
1234
  // MARK: Factory
1142
1235
  /**
1143
1236
  * Builds the built-in `model-info` MCP tool definition.
1144
1237
  *
1145
- * Mirrors dbx-cli's `model-info [model]` command:
1146
- * - Without a `model` arg: returns a summary list (modelType, modelName, prefix, group, identity, field count).
1147
- * - With a `model` arg: matches by `modelType`, `identityConst`, or `collectionPrefix` and returns the full entry.
1238
+ * Modes (selected by input):
1239
+ * - No args: returns model groups + counts (`mode: 'groups'`) — the cheap default for browsing.
1240
+ * - `model` (string): returns the full entry for one model (`mode: 'single'`).
1241
+ * - `model` (string array): returns full detail per match (`mode: 'multiple'`); misses land in `notFound`.
1242
+ * - `modelGroup`: returns the summary list of that group's models (`mode: 'list'`).
1243
+ * - `all: true`: returns the full catalog summary (`mode: 'list'`).
1244
+ * - `fields`: forces (`true`) or suppresses (`false`) full persisted-field detail in list/multiple modes.
1245
+ *
1246
+ * Each `model` query matches by `modelType`, `identityConst`, or `collectionPrefix`. When several
1247
+ * params are supplied, precedence is `model` > `modelGroup` > `all` > the default `groups` view.
1148
1248
  *
1149
1249
  * Output is delivered as both stringified JSON in `content[0].text` and `structuredContent`
1150
1250
  * so MCP clients can consume either form.
@@ -1157,7 +1257,8 @@ function _object_spread$2(target) {
1157
1257
  return Promise.resolve(modelInfoToolHandler(args, ctx, deps));
1158
1258
  };
1159
1259
  var name = MODEL_INFO_TOOL_NAME;
1160
- var description = "Browse the Firestore model catalog (".concat(deps.manifest.length, " model").concat(deps.manifest.length === 1 ? '' : 's', "). Without `model`, returns a summary list of every model. With `model` (matched by modelType, identityConst, or collectionPrefix), returns the full entry with persisted fields.");
1260
+ var count = deps.manifest.length;
1261
+ var description = "Browse the Firestore model catalog (".concat(count, " model").concat(count === 1 ? '' : 's', "). No args returns model groups + counts (start here). ") + '`model` (a modelType/identityConst/collectionPrefix string, or an array of them) returns full detail per match — misses are reported in `notFound`. ' + '`modelGroup` returns the summary list for that group. `all:true` returns the full catalog summary. ' + '`fields` (boolean) forces or suppresses persisted-field detail in list/multiple modes.';
1161
1262
  return {
1162
1263
  name: name,
1163
1264
  description: description,
@@ -1188,7 +1289,7 @@ function modelInfoToolHandler(args, _ctx, deps) {
1188
1289
  var result;
1189
1290
  try {
1190
1291
  var input = parseModelInfoInput(args);
1191
- var output = input.model == null ? buildListOutput(deps.manifest) : buildSingleOutput(input.model, deps.manifest);
1292
+ var output = resolveModelInfoOutput(input, deps.manifest);
1192
1293
  result = {
1193
1294
  content: [
1194
1295
  {
@@ -1203,60 +1304,285 @@ function modelInfoToolHandler(args, _ctx, deps) {
1203
1304
  }
1204
1305
  return result;
1205
1306
  }
1307
+ function resolveModelInfoOutput(input, manifest) {
1308
+ var output;
1309
+ if (input.modelQueries != null) {
1310
+ output = buildModelLookupOutput({
1311
+ queries: input.modelQueries,
1312
+ isArray: input.modelIsArray,
1313
+ manifest: manifest,
1314
+ fields: input.fields
1315
+ });
1316
+ } else if (input.modelGroup != null) {
1317
+ output = buildGroupFilterOutput({
1318
+ group: input.modelGroup,
1319
+ manifest: manifest,
1320
+ fields: input.fields
1321
+ });
1322
+ } else if (input.all) {
1323
+ output = buildAllOutput(manifest, input.fields);
1324
+ } else {
1325
+ output = buildGroupsOutput(manifest);
1326
+ }
1327
+ return output;
1328
+ }
1329
+ // MARK: Input parsing
1206
1330
  function parseModelInfoInput(args) {
1207
- var raw = args['model'];
1208
- var model;
1331
+ var modelQueries = parseModelArg(args['model']);
1332
+ var modelGroup = parseModelGroupArg(args['modelGroup']);
1333
+ var all = parseBooleanArg(args['all'], 'all');
1334
+ var fields = parseBooleanArg(args['fields'], 'fields');
1335
+ return _object_spread$2(_object_spread_props(_object_spread$2(_object_spread_props(_object_spread$2({}, modelQueries == null ? {} : {
1336
+ modelQueries: modelQueries
1337
+ }), {
1338
+ modelIsArray: Array.isArray(args['model'])
1339
+ }), modelGroup == null ? {} : {
1340
+ modelGroup: modelGroup
1341
+ }), {
1342
+ all: all !== null && all !== void 0 ? all : false
1343
+ }), fields == null ? {} : {
1344
+ fields: fields
1345
+ });
1346
+ }
1347
+ function parseModelArg(raw) {
1348
+ var result;
1209
1349
  if (raw == null) {
1210
- model = undefined;
1350
+ result = undefined;
1211
1351
  } else if (typeof raw === 'string') {
1212
- var trimmed = raw.trim();
1213
- if (trimmed.length === 0) {
1214
- throw new Error('model-info: "model" must be a non-empty string when provided.');
1352
+ result = [
1353
+ requireNonEmptyString(raw, 'model')
1354
+ ];
1355
+ } else if (Array.isArray(raw)) {
1356
+ if (raw.length === 0) {
1357
+ throw new Error('model-info: "model" array must contain at least one entry.');
1215
1358
  }
1216
- model = trimmed;
1359
+ result = raw.map(function(value, index) {
1360
+ return requireNonEmptyString(value, "model[".concat(index, "]"));
1361
+ });
1362
+ } else {
1363
+ throw new TypeError('model-info: "model" must be a string or an array of strings when provided.');
1364
+ }
1365
+ return result;
1366
+ }
1367
+ function parseModelGroupArg(raw) {
1368
+ var result;
1369
+ if (raw == null) {
1370
+ result = undefined;
1371
+ } else if (typeof raw === 'string') {
1372
+ result = requireNonEmptyString(raw, 'modelGroup');
1217
1373
  } else {
1218
- throw new TypeError('model-info: "model" must be a string when provided.');
1374
+ throw new TypeError('model-info: "modelGroup" must be a string when provided.');
1375
+ }
1376
+ return result;
1377
+ }
1378
+ function parseBooleanArg(raw, label) {
1379
+ var result;
1380
+ if (raw == null) {
1381
+ result = undefined;
1382
+ } else if (typeof raw === 'boolean') {
1383
+ result = raw;
1384
+ } else {
1385
+ throw new TypeError('model-info: "'.concat(label, '" must be a boolean when provided.'));
1386
+ }
1387
+ return result;
1388
+ }
1389
+ function requireNonEmptyString(value, label) {
1390
+ if (typeof value !== 'string') {
1391
+ throw new TypeError('model-info: "'.concat(label, '" must be a string.'));
1219
1392
  }
1393
+ var trimmed = value.trim();
1394
+ if (trimmed.length === 0) {
1395
+ throw new Error('model-info: "'.concat(label, '" must be a non-empty string.'));
1396
+ }
1397
+ return trimmed;
1398
+ }
1399
+ // MARK: Output builders
1400
+ function buildGroupsOutput(manifest) {
1220
1401
  return {
1221
- model: model
1402
+ mode: 'groups',
1403
+ groups: computeGroupCounts(manifest),
1404
+ totalModels: manifest.length,
1405
+ hint: MODEL_INFO_GROUPS_HINT
1222
1406
  };
1223
1407
  }
1224
- function buildListOutput(manifest) {
1225
- var models = manifest.map(function(entry) {
1226
- var row = _object_spread$2({
1227
- modelType: entry.modelType,
1228
- modelName: entry.modelName,
1229
- identityConst: entry.identityConst,
1230
- collectionPrefix: entry.collectionPrefix,
1231
- sourcePackage: entry.sourcePackage,
1232
- fieldCount: entry.fields.length
1233
- }, entry.modelGroup == null ? {} : {
1234
- modelGroup: entry.modelGroup
1235
- }, entry.parentIdentityConst == null ? {} : {
1236
- parentIdentityConst: entry.parentIdentityConst
1237
- }, entry.description == null ? {} : {
1238
- description: entry.description
1239
- }, entry.read == null ? {} : {
1240
- read: entry.read
1241
- }, entry.serviceFactory == null ? {} : {
1242
- serviceFactoryExport: entry.serviceFactory.exportName
1243
- });
1244
- return row;
1408
+ function buildGroupFilterOutput(config) {
1409
+ var group = config.group, manifest = config.manifest, fields = config.fields;
1410
+ var detailed = fields !== null && fields !== void 0 ? fields : false;
1411
+ var lower = group.toLowerCase();
1412
+ var matches = manifest.filter(function(entry) {
1413
+ var _entry_modelGroup;
1414
+ return ((_entry_modelGroup = entry.modelGroup) === null || _entry_modelGroup === void 0 ? void 0 : _entry_modelGroup.toLowerCase()) === lower;
1245
1415
  });
1416
+ var result;
1417
+ if (matches.length === 0) {
1418
+ throw new Error(buildUnknownGroupMessage(group, manifest));
1419
+ } else {
1420
+ var canonical = matches[0].modelGroup;
1421
+ result = {
1422
+ mode: 'list',
1423
+ modelGroup: canonical,
1424
+ models: matches.map(function(entry) {
1425
+ return toModelRow(entry, detailed);
1426
+ })
1427
+ };
1428
+ }
1429
+ return result;
1430
+ }
1431
+ function buildAllOutput(manifest, fields) {
1432
+ var detailed = fields !== null && fields !== void 0 ? fields : false;
1246
1433
  return {
1247
1434
  mode: 'list',
1248
- models: models
1435
+ models: manifest.map(function(entry) {
1436
+ return toModelRow(entry, detailed);
1437
+ })
1249
1438
  };
1250
1439
  }
1251
- function buildSingleOutput(query, manifest) {
1252
- var entry = findModelEntry(query, manifest);
1253
- if (entry == null) {
1254
- throw new Error('model-info: no model matches "'.concat(query, '". Call `model-info` without arguments to list available models.'));
1440
+ function buildModelLookupOutput(config) {
1441
+ var queries = config.queries, isArray = config.isArray, manifest = config.manifest, fields = config.fields;
1442
+ var detailed = fields !== null && fields !== void 0 ? fields : true;
1443
+ var matched = [];
1444
+ var notFound = [];
1445
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
1446
+ try {
1447
+ for(var _iterator = queries[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
1448
+ var query = _step.value;
1449
+ var entry = findModelEntry(query, manifest);
1450
+ if (entry == null) {
1451
+ notFound.push({
1452
+ query: query,
1453
+ message: buildModelNotFoundMessage(query, manifest)
1454
+ });
1455
+ } else {
1456
+ matched.push(toModelRow(entry, detailed));
1457
+ }
1458
+ }
1459
+ } catch (err) {
1460
+ _didIteratorError = true;
1461
+ _iteratorError = err;
1462
+ } finally{
1463
+ try {
1464
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
1465
+ _iterator.return();
1466
+ }
1467
+ } finally{
1468
+ if (_didIteratorError) {
1469
+ throw _iteratorError;
1470
+ }
1471
+ }
1255
1472
  }
1256
- return {
1257
- mode: 'single',
1258
- model: entry
1259
- };
1473
+ var result;
1474
+ if (isArray) {
1475
+ result = notFound.length > 0 ? {
1476
+ mode: 'multiple',
1477
+ models: matched,
1478
+ notFound: notFound
1479
+ } : {
1480
+ mode: 'multiple',
1481
+ models: matched
1482
+ };
1483
+ } else if (matched.length > 0) {
1484
+ result = {
1485
+ mode: 'single',
1486
+ model: matched[0]
1487
+ };
1488
+ } else {
1489
+ throw new Error(notFound[0].message);
1490
+ }
1491
+ return result;
1492
+ }
1493
+ // MARK: Row + group helpers
1494
+ function toModelRow(entry, detailed) {
1495
+ return detailed ? entry : toSummaryRow(entry);
1496
+ }
1497
+ function toSummaryRow(entry) {
1498
+ return _object_spread$2({
1499
+ modelType: entry.modelType,
1500
+ modelName: entry.modelName,
1501
+ identityConst: entry.identityConst,
1502
+ collectionPrefix: entry.collectionPrefix,
1503
+ sourcePackage: entry.sourcePackage,
1504
+ fieldCount: entry.fields.length
1505
+ }, entry.modelGroup == null ? {} : {
1506
+ modelGroup: entry.modelGroup
1507
+ }, entry.parentIdentityConst == null ? {} : {
1508
+ parentIdentityConst: entry.parentIdentityConst
1509
+ }, entry.description == null ? {} : {
1510
+ description: entry.description
1511
+ }, entry.read == null ? {} : {
1512
+ read: entry.read
1513
+ }, entry.serviceFactory == null ? {} : {
1514
+ serviceFactoryExport: entry.serviceFactory.exportName
1515
+ });
1516
+ }
1517
+ /**
1518
+ * Counts models per `modelGroup`, bucketing entries without a group under
1519
+ * {@link MODEL_INFO_UNGROUPED_LABEL}. Sorted by count descending, then group name ascending.
1520
+ *
1521
+ * @param manifest - Model manifest to summarize.
1522
+ * @returns One {@link ModelInfoGroupCount} per group, ordered most-populous-first.
1523
+ *
1524
+ * @__NO_SIDE_EFFECTS__
1525
+ */ function computeGroupCounts(manifest) {
1526
+ var grouped = util.makeValuesGroupMap(_to_consumable_array$4(manifest), function(entry) {
1527
+ var _entry_modelGroup;
1528
+ return (_entry_modelGroup = entry.modelGroup) !== null && _entry_modelGroup !== void 0 ? _entry_modelGroup : MODEL_INFO_UNGROUPED_LABEL;
1529
+ });
1530
+ var counts = [];
1531
+ grouped.forEach(function(entries, group) {
1532
+ counts.push({
1533
+ modelGroup: group,
1534
+ modelCount: entries.length
1535
+ });
1536
+ });
1537
+ counts.sort(function(a, b) {
1538
+ return b.modelCount - a.modelCount || a.modelGroup.localeCompare(b.modelGroup);
1539
+ });
1540
+ return counts;
1541
+ }
1542
+ function findGroupCount(query, manifest) {
1543
+ var lower = query.toLowerCase();
1544
+ var result;
1545
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
1546
+ try {
1547
+ for(var _iterator = computeGroupCounts(manifest)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
1548
+ var count = _step.value;
1549
+ if (count.modelGroup.toLowerCase() === lower) {
1550
+ result = count;
1551
+ break;
1552
+ }
1553
+ }
1554
+ } catch (err) {
1555
+ _didIteratorError = true;
1556
+ _iteratorError = err;
1557
+ } finally{
1558
+ try {
1559
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
1560
+ _iterator.return();
1561
+ }
1562
+ } finally{
1563
+ if (_didIteratorError) {
1564
+ throw _iteratorError;
1565
+ }
1566
+ }
1567
+ }
1568
+ return result;
1569
+ }
1570
+ function buildModelNotFoundMessage(query, manifest) {
1571
+ var groupMatch = findGroupCount(query, manifest);
1572
+ var message;
1573
+ if (groupMatch != null) {
1574
+ var plural = groupMatch.modelCount === 1 ? '' : 's';
1575
+ message = 'model-info: no exact match for "'.concat(query, '" — did you mean group:"').concat(groupMatch.modelGroup, '" (').concat(groupMatch.modelCount, " model").concat(plural, ')? Use modelGroup:"').concat(groupMatch.modelGroup, '", or all:true for everything.');
1576
+ } else {
1577
+ message = 'model-info: no exact match for "'.concat(query, '". Call `model-info` with no arguments to list groups, or pass all:true for the full catalog.');
1578
+ }
1579
+ return message;
1580
+ }
1581
+ function buildUnknownGroupMessage(group, manifest) {
1582
+ var available = computeGroupCounts(manifest).map(function(count) {
1583
+ return "".concat(count.modelGroup, " (").concat(count.modelCount, ")");
1584
+ }).join(', ');
1585
+ return 'model-info: no model group matches "'.concat(group, '". Available groups: ').concat(available || '(none)', ". Call `model-info` with no arguments to list groups.");
1260
1586
  }
1261
1587
  /**
1262
1588
  * Resolves a manifest entry by `modelType`, `identityConst`, or `collectionPrefix`.
@@ -1298,160 +1624,205 @@ var MODEL_INFO_INPUT_SCHEMA = {
1298
1624
  type: 'object',
1299
1625
  properties: {
1300
1626
  model: {
1627
+ description: 'One model (string) or many (string array), each matched by modelType, identityConst, or collectionPrefix. A string → `mode:"single"`; an array → `mode:"multiple"`. Misses are reported in `notFound`.',
1628
+ oneOf: [
1629
+ {
1630
+ type: 'string',
1631
+ minLength: 1
1632
+ },
1633
+ {
1634
+ type: 'array',
1635
+ minItems: 1,
1636
+ items: {
1637
+ type: 'string',
1638
+ minLength: 1
1639
+ }
1640
+ }
1641
+ ]
1642
+ },
1643
+ modelGroup: {
1301
1644
  type: 'string',
1302
1645
  minLength: 1,
1303
- description: 'Model to inspect (modelType, identityConst, or collectionPrefix). Omit to list every model.'
1646
+ description: 'Return the summary list of models in this group (`mode:"list"`). Matched case-insensitively.'
1647
+ },
1648
+ all: {
1649
+ type: 'boolean',
1650
+ description: 'Opt in to the full catalog summary (every model). Never the default — omit to get groups instead.'
1651
+ },
1652
+ fields: {
1653
+ type: 'boolean',
1654
+ description: 'Force (true) or suppress (false) full persisted-field detail. Defaults to summary rows for list mode and full entries for single/multiple modes.'
1304
1655
  }
1305
1656
  },
1306
1657
  additionalProperties: false
1307
1658
  };
1659
+ // Shared item schema for model-bearing rows. Required props cover the summary form; full entries
1660
+ // add `fields`, `sourceFile`, and `serviceFactory` (allowed as additional properties).
1661
+ var MODEL_ROW_SCHEMA = {
1662
+ type: 'object',
1663
+ required: [
1664
+ 'modelType',
1665
+ 'modelName',
1666
+ 'identityConst',
1667
+ 'collectionPrefix',
1668
+ 'sourcePackage'
1669
+ ],
1670
+ properties: {
1671
+ modelType: {
1672
+ type: 'string'
1673
+ },
1674
+ modelName: {
1675
+ type: 'string'
1676
+ },
1677
+ modelGroup: {
1678
+ type: 'string'
1679
+ },
1680
+ identityConst: {
1681
+ type: 'string'
1682
+ },
1683
+ collectionPrefix: {
1684
+ type: 'string'
1685
+ },
1686
+ parentIdentityConst: {
1687
+ type: 'string'
1688
+ },
1689
+ sourcePackage: {
1690
+ type: 'string'
1691
+ },
1692
+ sourceFile: {
1693
+ type: 'string'
1694
+ },
1695
+ fieldCount: {
1696
+ type: 'integer'
1697
+ },
1698
+ description: {
1699
+ type: 'string'
1700
+ },
1701
+ read: {
1702
+ type: 'string',
1703
+ enum: [
1704
+ 'system',
1705
+ 'owner',
1706
+ 'admin-only',
1707
+ 'permissions'
1708
+ ]
1709
+ },
1710
+ serviceFactoryExport: {
1711
+ type: 'string'
1712
+ },
1713
+ fields: {
1714
+ type: 'array',
1715
+ items: {
1716
+ type: 'object'
1717
+ }
1718
+ },
1719
+ serviceFactory: {
1720
+ type: 'object',
1721
+ required: [
1722
+ 'exportName',
1723
+ 'sourceFile'
1724
+ ],
1725
+ properties: {
1726
+ exportName: {
1727
+ type: 'string'
1728
+ },
1729
+ sourceFile: {
1730
+ type: 'string'
1731
+ }
1732
+ }
1733
+ }
1734
+ }
1735
+ };
1308
1736
  // MCP's `tools/list` validator requires `outputSchema.type === 'object'` at the root
1309
- // (see @modelcontextprotocol/sdk Zod schema), so the list/single union is expressed via a
1310
- // top-level object whose nested `oneOf` discriminates by the `mode` literal.
1737
+ // (see @modelcontextprotocol/sdk Zod schema), so the variants are expressed via a top-level
1738
+ // object whose nested `oneOf` discriminates by the `mode` literal.
1311
1739
  var MODEL_INFO_OUTPUT_SCHEMA = {
1312
1740
  type: 'object',
1313
1741
  required: [
1314
1742
  'mode'
1315
1743
  ],
1316
- description: 'Either lists every model in the manifest (when `model` is omitted) or returns a full entry for the requested model (when `model` is provided). The `mode` field discriminates the variant.',
1744
+ description: 'Discriminated by `mode`: `groups` (default model groups + counts), `list` (summary/full list for `modelGroup` or `all`), `single` (one `model`), or `multiple` (a `model` array, with misses in `notFound`).',
1317
1745
  properties: {
1318
1746
  mode: {
1319
1747
  type: 'string',
1320
1748
  enum: [
1749
+ 'groups',
1321
1750
  'list',
1322
- 'single'
1751
+ 'single',
1752
+ 'multiple'
1323
1753
  ]
1324
1754
  },
1325
- models: {
1755
+ groups: {
1326
1756
  type: 'array',
1327
- description: 'Present when `mode` is `"list"`. One summary entry per registered model.',
1757
+ description: 'Present when `mode` is `"groups"`. One entry per model group.',
1328
1758
  items: {
1329
1759
  type: 'object',
1330
1760
  required: [
1331
- 'modelType',
1332
- 'modelName',
1333
- 'identityConst',
1334
- 'collectionPrefix',
1335
- 'sourcePackage',
1336
- 'fieldCount'
1761
+ 'modelGroup',
1762
+ 'modelCount'
1337
1763
  ],
1338
1764
  properties: {
1339
- modelType: {
1340
- type: 'string'
1341
- },
1342
- modelName: {
1343
- type: 'string'
1344
- },
1345
1765
  modelGroup: {
1346
1766
  type: 'string'
1347
1767
  },
1348
- identityConst: {
1349
- type: 'string'
1350
- },
1351
- collectionPrefix: {
1352
- type: 'string'
1353
- },
1354
- parentIdentityConst: {
1355
- type: 'string'
1356
- },
1357
- sourcePackage: {
1358
- type: 'string'
1359
- },
1360
- fieldCount: {
1768
+ modelCount: {
1361
1769
  type: 'integer'
1362
- },
1363
- description: {
1364
- type: 'string'
1365
- },
1366
- read: {
1367
- type: 'string',
1368
- enum: [
1369
- 'system',
1370
- 'owner',
1371
- 'admin-only',
1372
- 'permissions'
1373
- ]
1374
- },
1375
- serviceFactoryExport: {
1376
- type: 'string'
1377
1770
  }
1378
1771
  }
1379
1772
  }
1380
1773
  },
1381
- model: {
1382
- type: 'object',
1383
- description: 'Present when `mode` is `"single"`. The full manifest entry for the requested model.',
1384
- required: [
1385
- 'modelType',
1386
- 'modelName',
1387
- 'identityConst',
1388
- 'collectionPrefix',
1389
- 'sourcePackage',
1390
- 'sourceFile',
1391
- 'fields'
1392
- ],
1393
- properties: {
1394
- modelType: {
1395
- type: 'string'
1396
- },
1397
- modelName: {
1398
- type: 'string'
1399
- },
1400
- modelGroup: {
1401
- type: 'string'
1402
- },
1403
- identityConst: {
1404
- type: 'string'
1405
- },
1406
- collectionPrefix: {
1407
- type: 'string'
1408
- },
1409
- parentIdentityConst: {
1410
- type: 'string'
1411
- },
1412
- description: {
1413
- type: 'string'
1414
- },
1415
- sourcePackage: {
1416
- type: 'string'
1417
- },
1418
- sourceFile: {
1419
- type: 'string'
1420
- },
1421
- fields: {
1422
- type: 'array',
1423
- items: {
1424
- type: 'object'
1425
- }
1426
- },
1427
- read: {
1428
- type: 'string',
1429
- enum: [
1430
- 'system',
1431
- 'owner',
1432
- 'admin-only',
1433
- 'permissions'
1434
- ]
1435
- },
1436
- serviceFactory: {
1437
- type: 'object',
1438
- required: [
1439
- 'exportName',
1440
- 'sourceFile'
1441
- ],
1442
- properties: {
1443
- exportName: {
1444
- type: 'string'
1445
- },
1446
- sourceFile: {
1447
- type: 'string'
1448
- }
1774
+ totalModels: {
1775
+ type: 'integer',
1776
+ description: 'Present when `mode` is `"groups"`. Total models across all groups.'
1777
+ },
1778
+ hint: {
1779
+ type: 'string',
1780
+ description: 'Present when `mode` is `"groups"`. Guidance on how to drill into the catalog.'
1781
+ },
1782
+ models: {
1783
+ type: 'array',
1784
+ description: 'Present when `mode` is `"list"` or `"multiple"`. Summary rows by default; full entries when `fields` requests detail.',
1785
+ items: MODEL_ROW_SCHEMA
1786
+ },
1787
+ modelGroup: {
1788
+ type: 'string',
1789
+ description: 'Present when `mode` is `"list"` from a `modelGroup` filter. The canonical group name.'
1790
+ },
1791
+ model: _object_spread_props(_object_spread$2({}, MODEL_ROW_SCHEMA), {
1792
+ description: 'Present when `mode` is `"single"`. The matched model entry (full detail unless `fields:false`).'
1793
+ }),
1794
+ notFound: {
1795
+ type: 'array',
1796
+ description: 'Present when `mode` is `"multiple"` and one or more queries matched nothing.',
1797
+ items: {
1798
+ type: 'object',
1799
+ required: [
1800
+ 'query',
1801
+ 'message'
1802
+ ],
1803
+ properties: {
1804
+ query: {
1805
+ type: 'string'
1806
+ },
1807
+ message: {
1808
+ type: 'string'
1449
1809
  }
1450
1810
  }
1451
1811
  }
1452
1812
  }
1453
1813
  },
1454
1814
  oneOf: [
1815
+ {
1816
+ required: [
1817
+ 'groups',
1818
+ 'totalModels'
1819
+ ],
1820
+ properties: {
1821
+ mode: {
1822
+ const: 'groups'
1823
+ }
1824
+ }
1825
+ },
1455
1826
  {
1456
1827
  required: [
1457
1828
  'models'
@@ -1471,11 +1842,21 @@ var MODEL_INFO_OUTPUT_SCHEMA = {
1471
1842
  const: 'single'
1472
1843
  }
1473
1844
  }
1845
+ },
1846
+ {
1847
+ required: [
1848
+ 'models'
1849
+ ],
1850
+ properties: {
1851
+ mode: {
1852
+ const: 'multiple'
1853
+ }
1854
+ }
1474
1855
  }
1475
1856
  ]
1476
1857
  };
1477
1858
 
1478
- function _define_property$4(obj, key, value) {
1859
+ function _define_property$5(obj, key, value) {
1479
1860
  if (key in obj) {
1480
1861
  Object.defineProperty(obj, key, {
1481
1862
  value: value,
@@ -1498,7 +1879,7 @@ function _object_spread$1(target) {
1498
1879
  }));
1499
1880
  }
1500
1881
  ownKeys.forEach(function(key) {
1501
- _define_property$4(target, key, source[key]);
1882
+ _define_property$5(target, key, source[key]);
1502
1883
  });
1503
1884
  }
1504
1885
  return target;
@@ -1734,7 +2115,7 @@ var MODEL_DECODE_OUTPUT_SCHEMA = {
1734
2115
  }
1735
2116
  };
1736
2117
 
1737
- function _array_like_to_array$2(arr, len) {
2118
+ function _array_like_to_array$3(arr, len) {
1738
2119
  if (len == null || len > arr.length) len = arr.length;
1739
2120
  for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
1740
2121
  return arr2;
@@ -1742,10 +2123,10 @@ function _array_like_to_array$2(arr, len) {
1742
2123
  function _array_with_holes$1(arr) {
1743
2124
  if (Array.isArray(arr)) return arr;
1744
2125
  }
1745
- function _array_without_holes$2(arr) {
1746
- if (Array.isArray(arr)) return _array_like_to_array$2(arr);
2126
+ function _array_without_holes$3(arr) {
2127
+ if (Array.isArray(arr)) return _array_like_to_array$3(arr);
1747
2128
  }
1748
- function _define_property$3(obj, key, value) {
2129
+ function _define_property$4(obj, key, value) {
1749
2130
  if (key in obj) {
1750
2131
  Object.defineProperty(obj, key, {
1751
2132
  value: value,
@@ -1758,7 +2139,7 @@ function _define_property$3(obj, key, value) {
1758
2139
  }
1759
2140
  return obj;
1760
2141
  }
1761
- function _iterable_to_array$2(iter) {
2142
+ function _iterable_to_array$3(iter) {
1762
2143
  if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
1763
2144
  }
1764
2145
  function _iterable_to_array_limit$1(arr, i) {
@@ -1788,7 +2169,7 @@ function _iterable_to_array_limit$1(arr, i) {
1788
2169
  function _non_iterable_rest$1() {
1789
2170
  throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
1790
2171
  }
1791
- function _non_iterable_spread$2() {
2172
+ function _non_iterable_spread$3() {
1792
2173
  throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
1793
2174
  }
1794
2175
  function _object_spread(target) {
@@ -1801,24 +2182,24 @@ function _object_spread(target) {
1801
2182
  }));
1802
2183
  }
1803
2184
  ownKeys.forEach(function(key) {
1804
- _define_property$3(target, key, source[key]);
2185
+ _define_property$4(target, key, source[key]);
1805
2186
  });
1806
2187
  }
1807
2188
  return target;
1808
2189
  }
1809
2190
  function _sliced_to_array$1(arr, i) {
1810
- return _array_with_holes$1(arr) || _iterable_to_array_limit$1(arr, i) || _unsupported_iterable_to_array$2(arr, i) || _non_iterable_rest$1();
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();
1811
2192
  }
1812
- function _to_consumable_array$2(arr) {
1813
- return _array_without_holes$2(arr) || _iterable_to_array$2(arr) || _unsupported_iterable_to_array$2(arr) || _non_iterable_spread$2();
2193
+ 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();
1814
2195
  }
1815
- function _unsupported_iterable_to_array$2(o, minLen) {
2196
+ function _unsupported_iterable_to_array$3(o, minLen) {
1816
2197
  if (!o) return;
1817
- if (typeof o === "string") return _array_like_to_array$2(o, minLen);
2198
+ if (typeof o === "string") return _array_like_to_array$3(o, minLen);
1818
2199
  var n = Object.prototype.toString.call(o).slice(8, -1);
1819
2200
  if (n === "Object" && o.constructor) n = o.constructor.name;
1820
2201
  if (n === "Map" || n === "Set") return Array.from(n);
1821
- if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$2(o, minLen);
2202
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$3(o, minLen);
1822
2203
  }
1823
2204
  // MARK: Constants
1824
2205
  /**
@@ -1899,7 +2280,7 @@ function whoamiToolHandler(ctx, deps) {
1899
2280
  return key;
1900
2281
  });
1901
2282
  var roleSet = deps.roleReader == null ? new Set() : deps.roleReader(token);
1902
- var roles = _to_consumable_array$2(roleSet).sort(function(a, b) {
2283
+ var roles = _to_consumable_array$3(roleSet).sort(function(a, b) {
1903
2284
  return a.localeCompare(b);
1904
2285
  });
1905
2286
  var claimsByKey = new Map();
@@ -2168,7 +2549,7 @@ var WHOAMI_OUTPUT_SCHEMA = {
2168
2549
  }
2169
2550
  };
2170
2551
 
2171
- function _array_like_to_array$1(arr, len) {
2552
+ function _array_like_to_array$2(arr, len) {
2172
2553
  if (len == null || len > arr.length) len = arr.length;
2173
2554
  for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
2174
2555
  return arr2;
@@ -2176,8 +2557,8 @@ function _array_like_to_array$1(arr, len) {
2176
2557
  function _array_with_holes(arr) {
2177
2558
  if (Array.isArray(arr)) return arr;
2178
2559
  }
2179
- function _array_without_holes$1(arr) {
2180
- if (Array.isArray(arr)) return _array_like_to_array$1(arr);
2560
+ function _array_without_holes$2(arr) {
2561
+ if (Array.isArray(arr)) return _array_like_to_array$2(arr);
2181
2562
  }
2182
2563
  function asyncGeneratorStep$2(gen, resolve, reject, _next, _throw, key, arg) {
2183
2564
  try {
@@ -2208,12 +2589,12 @@ function _async_to_generator$2(fn) {
2208
2589
  });
2209
2590
  };
2210
2591
  }
2211
- function _class_call_check$2(instance, Constructor) {
2592
+ function _class_call_check$3(instance, Constructor) {
2212
2593
  if (!(instance instanceof Constructor)) {
2213
2594
  throw new TypeError("Cannot call a class as a function");
2214
2595
  }
2215
2596
  }
2216
- function _defineProperties$2(target, props) {
2597
+ function _defineProperties$3(target, props) {
2217
2598
  for(var i = 0; i < props.length; i++){
2218
2599
  var descriptor = props[i];
2219
2600
  descriptor.enumerable = descriptor.enumerable || false;
@@ -2222,11 +2603,11 @@ function _defineProperties$2(target, props) {
2222
2603
  Object.defineProperty(target, descriptor.key, descriptor);
2223
2604
  }
2224
2605
  }
2225
- function _create_class$2(Constructor, protoProps, staticProps) {
2226
- if (protoProps) _defineProperties$2(Constructor.prototype, protoProps);
2606
+ function _create_class$3(Constructor, protoProps, staticProps) {
2607
+ if (protoProps) _defineProperties$3(Constructor.prototype, protoProps);
2227
2608
  return Constructor;
2228
2609
  }
2229
- function _define_property$2(obj, key, value) {
2610
+ function _define_property$3(obj, key, value) {
2230
2611
  if (key in obj) {
2231
2612
  Object.defineProperty(obj, key, {
2232
2613
  value: value,
@@ -2239,7 +2620,7 @@ function _define_property$2(obj, key, value) {
2239
2620
  }
2240
2621
  return obj;
2241
2622
  }
2242
- function _iterable_to_array$1(iter) {
2623
+ function _iterable_to_array$2(iter) {
2243
2624
  if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
2244
2625
  }
2245
2626
  function _iterable_to_array_limit(arr, i) {
@@ -2269,22 +2650,22 @@ function _iterable_to_array_limit(arr, i) {
2269
2650
  function _non_iterable_rest() {
2270
2651
  throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
2271
2652
  }
2272
- function _non_iterable_spread$1() {
2653
+ function _non_iterable_spread$2() {
2273
2654
  throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
2274
2655
  }
2275
2656
  function _sliced_to_array(arr, i) {
2276
- return _array_with_holes(arr) || _iterable_to_array_limit(arr, i) || _unsupported_iterable_to_array$1(arr, i) || _non_iterable_rest();
2657
+ return _array_with_holes(arr) || _iterable_to_array_limit(arr, i) || _unsupported_iterable_to_array$2(arr, i) || _non_iterable_rest();
2277
2658
  }
2278
- function _to_consumable_array$1(arr) {
2279
- return _array_without_holes$1(arr) || _iterable_to_array$1(arr) || _unsupported_iterable_to_array$1(arr) || _non_iterable_spread$1();
2659
+ function _to_consumable_array$2(arr) {
2660
+ return _array_without_holes$2(arr) || _iterable_to_array$2(arr) || _unsupported_iterable_to_array$2(arr) || _non_iterable_spread$2();
2280
2661
  }
2281
- function _unsupported_iterable_to_array$1(o, minLen) {
2662
+ function _unsupported_iterable_to_array$2(o, minLen) {
2282
2663
  if (!o) return;
2283
- if (typeof o === "string") return _array_like_to_array$1(o, minLen);
2664
+ if (typeof o === "string") return _array_like_to_array$2(o, minLen);
2284
2665
  var n = Object.prototype.toString.call(o).slice(8, -1);
2285
2666
  if (n === "Object" && o.constructor) n = o.constructor.name;
2286
2667
  if (n === "Map" || n === "Set") return Array.from(n);
2287
- if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$1(o, minLen);
2668
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$2(o, minLen);
2288
2669
  }
2289
2670
  function _ts_generator$2(thisArg, body) {
2290
2671
  var f, y, t, _ = {
@@ -2394,27 +2775,29 @@ var McpServerFactoryService_1;
2394
2775
  * recommends a fresh `McpServer` + transport pair per stateless JSON-RPC request,
2395
2776
  * which sidesteps session bookkeeping for the common Claude-connector case.
2396
2777
  */ exports.McpServerFactoryService = McpServerFactoryService_1 = /*#__PURE__*/ function() {
2397
- function McpServerFactoryService(mcpConfig, dispatchService, modelApiGetService, roleReader) {
2398
- _class_call_check$2(this, McpServerFactoryService);
2399
- _define_property$2(this, "mcpConfig", void 0);
2400
- _define_property$2(this, "dispatchService", void 0);
2401
- _define_property$2(this, "modelApiGetService", void 0);
2402
- _define_property$2(this, "roleReader", void 0);
2403
- _define_property$2(this, "_logger", new common.Logger(McpServerFactoryService_1.name));
2404
- _define_property$2(this, "_cachedTools", void 0);
2405
- _define_property$2(this, "_cachedStaticTools", void 0);
2406
- _define_property$2(this, "_cachedManifest", void 0);
2407
- _define_property$2(this, "_cachedManifestModels", void 0);
2408
- _define_property$2(this, "_cachedManifestAuth", void 0);
2409
- _define_property$2(this, "_manifestLoaded", false);
2410
- _define_property$2(this, "_loggedSkips", false);
2411
- _define_property$2(this, "_warnedMissingRoleReader", false);
2778
+ function McpServerFactoryService(mcpConfig, dispatchService, modelApiGetService, roleReader, analyticsService) {
2779
+ _class_call_check$3(this, McpServerFactoryService);
2780
+ _define_property$3(this, "mcpConfig", void 0);
2781
+ _define_property$3(this, "dispatchService", void 0);
2782
+ _define_property$3(this, "modelApiGetService", void 0);
2783
+ _define_property$3(this, "roleReader", void 0);
2784
+ _define_property$3(this, "_logger", new common.Logger(McpServerFactoryService_1.name));
2785
+ _define_property$3(this, "_cachedTools", void 0);
2786
+ _define_property$3(this, "_cachedStaticTools", void 0);
2787
+ _define_property$3(this, "_cachedManifest", void 0);
2788
+ _define_property$3(this, "_cachedManifestModels", void 0);
2789
+ _define_property$3(this, "_cachedManifestAuth", void 0);
2790
+ _define_property$3(this, "_manifestLoaded", false);
2791
+ _define_property$3(this, "_loggedSkips", false);
2792
+ _define_property$3(this, "_warnedMissingRoleReader", false);
2793
+ _define_property$3(this, "_analyticsService", void 0);
2412
2794
  this.mcpConfig = mcpConfig;
2413
2795
  this.dispatchService = dispatchService;
2414
2796
  this.modelApiGetService = modelApiGetService;
2415
2797
  this.roleReader = roleReader;
2798
+ this._analyticsService = analyticsService !== null && analyticsService !== void 0 ? analyticsService : noopMcpAnalyticsService();
2416
2799
  }
2417
- _create_class$2(McpServerFactoryService, [
2800
+ _create_class$3(McpServerFactoryService, [
2418
2801
  {
2419
2802
  /**
2420
2803
  * Builds a configured MCP server with tool listing + dispatch handlers wired up.
@@ -2424,14 +2807,14 @@ var McpServerFactoryService_1;
2424
2807
  */ key: "createServer",
2425
2808
  value: function createServer(ctx) {
2426
2809
  var _this = this;
2427
- var _this_mcpConfig_serverName, _this_mcpConfig_serverVersion;
2810
+ var _this_mcpConfig_serverName, _this_mcpConfig_serverVersion, _this_mcpConfig_serverInstructions;
2428
2811
  var baseServerName = (_this_mcpConfig_serverName = this.mcpConfig.serverName) !== null && _this_mcpConfig_serverName !== void 0 ? _this_mcpConfig_serverName : DEFAULT_MCP_SERVER_NAME;
2429
2812
  var serverName = this.mcpConfig.readOnly === true ? "".concat(baseServerName, " (read-only)") : baseServerName;
2430
2813
  var server = new mcp_js.McpServer({
2431
2814
  name: serverName,
2432
2815
  version: (_this_mcpConfig_serverVersion = this.mcpConfig.serverVersion) !== null && _this_mcpConfig_serverVersion !== void 0 ? _this_mcpConfig_serverVersion : '0.0.0'
2433
2816
  }, {
2434
- instructions: 'Model-bound RPC tools generated from the callModel _apiDetails tree.'
2817
+ instructions: (_this_mcpConfig_serverInstructions = this.mcpConfig.serverInstructions) !== null && _this_mcpConfig_serverInstructions !== void 0 ? _this_mcpConfig_serverInstructions : DEFAULT_MCP_SERVER_INSTRUCTIONS
2435
2818
  });
2436
2819
  server.server.registerCapabilities({
2437
2820
  tools: {}
@@ -2440,7 +2823,7 @@ var McpServerFactoryService_1;
2440
2823
  var staticTools = this._resolveStaticTools();
2441
2824
  var scopes = this._resolveScopes(ctx);
2442
2825
  var authRoles = this._resolveAuthRoles(ctx);
2443
- var combinedTools = _to_consumable_array$1(toolGeneration.tools).concat(_to_consumable_array$1(staticTools));
2826
+ var combinedTools = _to_consumable_array$2(toolGeneration.tools).concat(_to_consumable_array$2(staticTools));
2444
2827
  var visibleTools = this._filterToolsForRequest(combinedTools, {
2445
2828
  ctx: ctx,
2446
2829
  scopes: scopes,
@@ -2891,19 +3274,36 @@ var McpServerFactoryService_1;
2891
3274
  },
2892
3275
  {
2893
3276
  key: "_handleToolCall",
2894
- value: function _handleToolCall(request, definitionsByName, ctx) {
3277
+ value: /**
3278
+ * Central dispatch point for every MCP tool call. Runs the underlying handler — callModel,
3279
+ * static, or unknown-tool — then emits a single analytics event on completion so every call
3280
+ * is tracked uniformly.
3281
+ *
3282
+ * Success vs error is decided by the resolved outcome: an outcome that carries a thrown
3283
+ * error, or a response flagged `isError`, counts as a failure. The original thrown error
3284
+ * (when present) is forwarded on the event.
3285
+ *
3286
+ * @param request - The `tools/call` request carrying the tool name and arguments.
3287
+ * @param definitionsByName - The visible tool definitions keyed by name for this request.
3288
+ * @param ctx - The per-request context (auth, raw request) forwarded to the handler.
3289
+ * @returns The MCP tool response.
3290
+ */ function _handleToolCall(request, definitionsByName, ctx) {
2895
3291
  return _async_to_generator$2(function() {
2896
- var _request_params_arguments, definition, args, response;
3292
+ var _request_params_arguments, _ctx_auth, toolName, definition, args, startedAt, outcome, isSuccessful, toolKind;
2897
3293
  return _ts_generator$2(this, function(_state) {
2898
3294
  switch(_state.label){
2899
3295
  case 0:
2900
- definition = definitionsByName.get(request.params.name);
3296
+ toolName = request.params.name;
3297
+ definition = definitionsByName.get(toolName);
2901
3298
  args = (_request_params_arguments = request.params.arguments) !== null && _request_params_arguments !== void 0 ? _request_params_arguments : {};
3299
+ startedAt = Date.now();
2902
3300
  if (!(definition == null)) return [
2903
3301
  3,
2904
3302
  1
2905
3303
  ];
2906
- response = formatMcpToolErrorResponse(new Error("Unknown tool: ".concat(request.params.name)));
3304
+ outcome = {
3305
+ response: formatMcpToolErrorResponse(new Error("Unknown tool: ".concat(toolName)))
3306
+ };
2907
3307
  return [
2908
3308
  3,
2909
3309
  5
@@ -2918,7 +3318,7 @@ var McpServerFactoryService_1;
2918
3318
  this._handleCallModelToolCall(definition, args, ctx)
2919
3319
  ];
2920
3320
  case 2:
2921
- response = _state.sent();
3321
+ outcome = _state.sent();
2922
3322
  return [
2923
3323
  3,
2924
3324
  5
@@ -2929,23 +3329,57 @@ var McpServerFactoryService_1;
2929
3329
  this._handleStaticToolCall(definition.staticHandler, args, ctx)
2930
3330
  ];
2931
3331
  case 4:
2932
- response = _state.sent();
3332
+ outcome = _state.sent();
2933
3333
  _state.label = 5;
2934
3334
  case 5:
3335
+ isSuccessful = outcome.error == null && outcome.response.isError !== true;
3336
+ // Unknown tools never reached a handler; classify as 'static' since no callModel dispatch occurred.
3337
+ toolKind = definition != null && definition.staticHandler == null ? 'callModel' : 'static';
3338
+ this._emitMcpAnalytics({
3339
+ event: toolName,
3340
+ toolName: toolName,
3341
+ toolKind: toolKind,
3342
+ call: definition === null || definition === void 0 ? void 0 : definition.dispatch.call,
3343
+ modelType: definition === null || definition === void 0 ? void 0 : definition.dispatch.modelType,
3344
+ specifier: definition === null || definition === void 0 ? void 0 : definition.dispatch.specifier,
3345
+ uid: (_ctx_auth = ctx.auth) === null || _ctx_auth === void 0 ? void 0 : _ctx_auth.uid,
3346
+ auth: ctx.auth,
3347
+ readOnly: this.mcpConfig.readOnly === true,
3348
+ args: args,
3349
+ isSuccessful: isSuccessful,
3350
+ error: outcome.error,
3351
+ durationMs: Date.now() - startedAt
3352
+ });
2935
3353
  return [
2936
3354
  2,
2937
- response
3355
+ outcome.response
2938
3356
  ];
2939
3357
  }
2940
3358
  });
2941
3359
  }).call(this);
2942
3360
  }
2943
3361
  },
3362
+ {
3363
+ /**
3364
+ * Forwards an event to the registered {@link McpAnalyticsService}, swallowing any failure so
3365
+ * a faulty analytics implementation can never break tool dispatch (fail-soft, matching the
3366
+ * visibility-predicate guards above).
3367
+ *
3368
+ * @param event - The MCP analytics event to forward.
3369
+ */ key: "_emitMcpAnalytics",
3370
+ value: function _emitMcpAnalytics(event) {
3371
+ try {
3372
+ this._analyticsService.handleMcpAnalyticsEvent(event);
3373
+ } catch (error) {
3374
+ this._logger.warn("MCP analytics handler threw for tool ".concat(event.toolName, "; ignoring: ").concat(error.message));
3375
+ }
3376
+ }
3377
+ },
2944
3378
  {
2945
3379
  key: "_handleStaticToolCall",
2946
3380
  value: function _handleStaticToolCall(staticHandler, args, ctx) {
2947
3381
  return _async_to_generator$2(function() {
2948
- var response, error;
3382
+ var outcome, _tmp, error;
2949
3383
  return _ts_generator$2(this, function(_state) {
2950
3384
  switch(_state.label){
2951
3385
  case 0:
@@ -2955,19 +3389,23 @@ var McpServerFactoryService_1;
2955
3389
  ,
2956
3390
  3
2957
3391
  ]);
3392
+ _tmp = {};
2958
3393
  return [
2959
3394
  4,
2960
3395
  staticHandler(args, ctx)
2961
3396
  ];
2962
3397
  case 1:
2963
- response = _state.sent();
3398
+ outcome = (_tmp.response = _state.sent(), _tmp);
2964
3399
  return [
2965
3400
  3,
2966
3401
  3
2967
3402
  ];
2968
3403
  case 2:
2969
3404
  error = _state.sent();
2970
- response = formatMcpToolErrorResponse(error);
3405
+ outcome = {
3406
+ response: formatMcpToolErrorResponse(error),
3407
+ error: error
3408
+ };
2971
3409
  return [
2972
3410
  3,
2973
3411
  3
@@ -2975,7 +3413,7 @@ var McpServerFactoryService_1;
2975
3413
  case 3:
2976
3414
  return [
2977
3415
  2,
2978
- response
3416
+ outcome
2979
3417
  ];
2980
3418
  }
2981
3419
  });
@@ -2986,7 +3424,7 @@ var McpServerFactoryService_1;
2986
3424
  key: "_handleCallModelToolCall",
2987
3425
  value: function _handleCallModelToolCall(definition, args, ctx) {
2988
3426
  return _async_to_generator$2(function() {
2989
- var params, response, result, error;
3427
+ var params, outcome, result, error;
2990
3428
  return _ts_generator$2(this, function(_state) {
2991
3429
  switch(_state.label){
2992
3430
  case 0:
@@ -3010,14 +3448,19 @@ var McpServerFactoryService_1;
3010
3448
  ];
3011
3449
  case 2:
3012
3450
  result = _state.sent();
3013
- response = formatMcpToolResponse(result, params, definition.details);
3451
+ outcome = {
3452
+ response: formatMcpToolResponse(result, params, definition.details)
3453
+ };
3014
3454
  return [
3015
3455
  3,
3016
3456
  4
3017
3457
  ];
3018
3458
  case 3:
3019
3459
  error = _state.sent();
3020
- response = formatMcpToolErrorResponse(error);
3460
+ outcome = {
3461
+ response: formatMcpToolErrorResponse(error),
3462
+ error: error
3463
+ };
3021
3464
  return [
3022
3465
  3,
3023
3466
  4
@@ -3025,7 +3468,7 @@ var McpServerFactoryService_1;
3025
3468
  case 4:
3026
3469
  return [
3027
3470
  2,
3028
- response
3471
+ outcome
3029
3472
  ];
3030
3473
  }
3031
3474
  });
@@ -3042,7 +3485,9 @@ exports.McpServerFactoryService = McpServerFactoryService_1 = __decorate([
3042
3485
  __param(2, common.Optional()),
3043
3486
  __param(2, common.Inject(firebaseServer.ModelApiGetService)),
3044
3487
  __param(3, common.Optional()),
3045
- __param(3, common.Inject(MCP_AUTH_ROLE_READER))
3488
+ __param(3, common.Inject(MCP_AUTH_ROLE_READER)),
3489
+ __param(4, common.Optional()),
3490
+ __param(4, common.Inject(MCP_ANALYTICS_SERVICE))
3046
3491
  ], exports.McpServerFactoryService);
3047
3492
 
3048
3493
  function asyncGeneratorStep$1(gen, resolve, reject, _next, _throw, key, arg) {
@@ -3250,12 +3695,12 @@ function _async_to_generator(fn) {
3250
3695
  });
3251
3696
  };
3252
3697
  }
3253
- function _class_call_check$1(instance, Constructor) {
3698
+ function _class_call_check$2(instance, Constructor) {
3254
3699
  if (!(instance instanceof Constructor)) {
3255
3700
  throw new TypeError("Cannot call a class as a function");
3256
3701
  }
3257
3702
  }
3258
- function _defineProperties$1(target, props) {
3703
+ function _defineProperties$2(target, props) {
3259
3704
  for(var i = 0; i < props.length; i++){
3260
3705
  var descriptor = props[i];
3261
3706
  descriptor.enumerable = descriptor.enumerable || false;
@@ -3264,11 +3709,11 @@ function _defineProperties$1(target, props) {
3264
3709
  Object.defineProperty(target, descriptor.key, descriptor);
3265
3710
  }
3266
3711
  }
3267
- function _create_class$1(Constructor, protoProps, staticProps) {
3268
- if (protoProps) _defineProperties$1(Constructor.prototype, protoProps);
3712
+ function _create_class$2(Constructor, protoProps, staticProps) {
3713
+ if (protoProps) _defineProperties$2(Constructor.prototype, protoProps);
3269
3714
  return Constructor;
3270
3715
  }
3271
- function _define_property$1(obj, key, value) {
3716
+ function _define_property$2(obj, key, value) {
3272
3717
  if (key in obj) {
3273
3718
  Object.defineProperty(obj, key, {
3274
3719
  value: value,
@@ -3393,12 +3838,12 @@ var McpController_1;
3393
3838
  * be layered on later if streaming tool output becomes a requirement.
3394
3839
  */ exports.McpController = McpController_1 = /*#__PURE__*/ function() {
3395
3840
  function McpController(factory) {
3396
- _class_call_check$1(this, McpController);
3397
- _define_property$1(this, "factory", void 0);
3398
- _define_property$1(this, "_logger", new common.Logger(McpController_1.name));
3841
+ _class_call_check$2(this, McpController);
3842
+ _define_property$2(this, "factory", void 0);
3843
+ _define_property$2(this, "_logger", new common.Logger(McpController_1.name));
3399
3844
  this.factory = factory;
3400
3845
  }
3401
- _create_class$1(McpController, [
3846
+ _create_class$2(McpController, [
3402
3847
  {
3403
3848
  key: "handleMcpRequest",
3404
3849
  value: function handleMcpRequest(req, res) {
@@ -3465,12 +3910,12 @@ exports.McpController = McpController_1 = __decorate([
3465
3910
  __param(0, common.Inject(exports.McpServerFactoryService))
3466
3911
  ], exports.McpController);
3467
3912
 
3468
- function _class_call_check(instance, Constructor) {
3913
+ function _class_call_check$1(instance, Constructor) {
3469
3914
  if (!(instance instanceof Constructor)) {
3470
3915
  throw new TypeError("Cannot call a class as a function");
3471
3916
  }
3472
3917
  }
3473
- function _defineProperties(target, props) {
3918
+ function _defineProperties$1(target, props) {
3474
3919
  for(var i = 0; i < props.length; i++){
3475
3920
  var descriptor = props[i];
3476
3921
  descriptor.enumerable = descriptor.enumerable || false;
@@ -3479,11 +3924,11 @@ function _defineProperties(target, props) {
3479
3924
  Object.defineProperty(target, descriptor.key, descriptor);
3480
3925
  }
3481
3926
  }
3482
- function _create_class(Constructor, protoProps, staticProps) {
3483
- if (protoProps) _defineProperties(Constructor.prototype, protoProps);
3927
+ function _create_class$1(Constructor, protoProps, staticProps) {
3928
+ if (protoProps) _defineProperties$1(Constructor.prototype, protoProps);
3484
3929
  return Constructor;
3485
3930
  }
3486
- function _define_property(obj, key, value) {
3931
+ function _define_property$1(obj, key, value) {
3487
3932
  if (key in obj) {
3488
3933
  Object.defineProperty(obj, key, {
3489
3934
  value: value,
@@ -3507,11 +3952,11 @@ function _define_property(obj, key, value) {
3507
3952
  * in `firebase-server/oidc` for the corresponding OIDC excludes).
3508
3953
  */ exports.McpWellKnownController = /*#__PURE__*/ function() {
3509
3954
  function McpWellKnownController(mcpConfig) {
3510
- _class_call_check(this, McpWellKnownController);
3511
- _define_property(this, "mcpConfig", void 0);
3955
+ _class_call_check$1(this, McpWellKnownController);
3956
+ _define_property$1(this, "mcpConfig", void 0);
3512
3957
  this.mcpConfig = mcpConfig;
3513
3958
  }
3514
- _create_class(McpWellKnownController, [
3959
+ _create_class$1(McpWellKnownController, [
3515
3960
  {
3516
3961
  key: "getProtectedResourceMetadata",
3517
3962
  value: function getProtectedResourceMetadata() {
@@ -3534,30 +3979,30 @@ exports.McpWellKnownController = __decorate([
3534
3979
  __param(0, common.Inject(McpModuleConfig))
3535
3980
  ], exports.McpWellKnownController);
3536
3981
 
3537
- function _array_like_to_array(arr, len) {
3982
+ function _array_like_to_array$1(arr, len) {
3538
3983
  if (len == null || len > arr.length) len = arr.length;
3539
3984
  for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
3540
3985
  return arr2;
3541
3986
  }
3542
- function _array_without_holes(arr) {
3543
- if (Array.isArray(arr)) return _array_like_to_array(arr);
3987
+ function _array_without_holes$1(arr) {
3988
+ if (Array.isArray(arr)) return _array_like_to_array$1(arr);
3544
3989
  }
3545
- function _iterable_to_array(iter) {
3990
+ function _iterable_to_array$1(iter) {
3546
3991
  if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
3547
3992
  }
3548
- function _non_iterable_spread() {
3993
+ function _non_iterable_spread$1() {
3549
3994
  throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
3550
3995
  }
3551
- function _to_consumable_array(arr) {
3552
- return _array_without_holes(arr) || _iterable_to_array(arr) || _unsupported_iterable_to_array(arr) || _non_iterable_spread();
3996
+ function _to_consumable_array$1(arr) {
3997
+ return _array_without_holes$1(arr) || _iterable_to_array$1(arr) || _unsupported_iterable_to_array$1(arr) || _non_iterable_spread$1();
3553
3998
  }
3554
- function _unsupported_iterable_to_array(o, minLen) {
3999
+ function _unsupported_iterable_to_array$1(o, minLen) {
3555
4000
  if (!o) return;
3556
- if (typeof o === "string") return _array_like_to_array(o, minLen);
4001
+ if (typeof o === "string") return _array_like_to_array$1(o, minLen);
3557
4002
  var n = Object.prototype.toString.call(o).slice(8, -1);
3558
4003
  if (n === "Object" && o.constructor) n = o.constructor.name;
3559
4004
  if (n === "Map" || n === "Set") return Array.from(n);
3560
- if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
4005
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$1(o, minLen);
3561
4006
  }
3562
4007
  /**
3563
4008
  * Routes the firebase-server/mcp module owns. Apps should exclude these from
@@ -3594,26 +4039,254 @@ function _unsupported_iterable_to_array(o, minLen) {
3594
4039
  return {
3595
4040
  imports: [
3596
4041
  dependencyModule
3597
- ].concat(_to_consumable_array(imports !== null && imports !== void 0 ? imports : [])),
4042
+ ].concat(_to_consumable_array$1(imports !== null && imports !== void 0 ? imports : [])),
3598
4043
  controllers: [
3599
4044
  exports.McpController,
3600
4045
  exports.McpWellKnownController
3601
4046
  ],
3602
4047
  exports: [
3603
4048
  exports.McpServerFactoryService
3604
- ].concat(_to_consumable_array(exports$1 !== null && exports$1 !== void 0 ? exports$1 : [])),
4049
+ ].concat(_to_consumable_array$1(exports$1 !== null && exports$1 !== void 0 ? exports$1 : [])),
3605
4050
  providers: [
3606
4051
  exports.McpServerFactoryService
3607
- ].concat(_to_consumable_array(providers !== null && providers !== void 0 ? providers : []))
4052
+ ].concat(_to_consumable_array$1(providers !== null && providers !== void 0 ? providers : []))
4053
+ };
4054
+ }
4055
+
4056
+ /**
4057
+ * Default analytics event name used by {@link FirebaseServerMcpAnalyticsService} when
4058
+ * forwarding a completed MCP tool call to the downstream analytics pipeline.
4059
+ */ var DEFAULT_MCP_ANALYTICS_EVENT_NAME = 'mcp-tool';
4060
+ /**
4061
+ * NestJS injection token for the optional {@link FirebaseServerMcpAnalyticsConfig} provider.
4062
+ *
4063
+ * @example
4064
+ * ```typescript
4065
+ * @Module(appMcpAnalyticsModuleMetadata({ mcpAnalyticsConfig: { eventName: 'mcp-tool', logEvents: true } }))
4066
+ * export class AppMcpAnalyticsModule {}
4067
+ * ```
4068
+ */ var FIREBASE_SERVER_MCP_ANALYTICS_CONFIG = 'FIREBASE_SERVER_MCP_ANALYTICS_CONFIG';
4069
+
4070
+ function _assert_this_initialized(self) {
4071
+ if (self === void 0) {
4072
+ throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
4073
+ }
4074
+ return self;
4075
+ }
4076
+ function _call_super(_this, derived, args) {
4077
+ derived = _get_prototype_of(derived);
4078
+ return _possible_constructor_return(_this, _is_native_reflect_construct() ? Reflect.construct(derived, [], _get_prototype_of(_this).constructor) : derived.apply(_this, args));
4079
+ }
4080
+ function _class_call_check(instance, Constructor) {
4081
+ if (!(instance instanceof Constructor)) {
4082
+ throw new TypeError("Cannot call a class as a function");
4083
+ }
4084
+ }
4085
+ function _defineProperties(target, props) {
4086
+ for(var i = 0; i < props.length; i++){
4087
+ var descriptor = props[i];
4088
+ descriptor.enumerable = descriptor.enumerable || false;
4089
+ descriptor.configurable = true;
4090
+ if ("value" in descriptor) descriptor.writable = true;
4091
+ Object.defineProperty(target, descriptor.key, descriptor);
4092
+ }
4093
+ }
4094
+ function _create_class(Constructor, protoProps, staticProps) {
4095
+ if (protoProps) _defineProperties(Constructor.prototype, protoProps);
4096
+ return Constructor;
4097
+ }
4098
+ function _define_property(obj, key, value) {
4099
+ if (key in obj) {
4100
+ Object.defineProperty(obj, key, {
4101
+ value: value,
4102
+ enumerable: true,
4103
+ configurable: true,
4104
+ writable: true
4105
+ });
4106
+ } else {
4107
+ obj[key] = value;
4108
+ }
4109
+ return obj;
4110
+ }
4111
+ function _get_prototype_of(o) {
4112
+ _get_prototype_of = Object.setPrototypeOf ? Object.getPrototypeOf : function getPrototypeOf(o) {
4113
+ return o.__proto__ || Object.getPrototypeOf(o);
4114
+ };
4115
+ return _get_prototype_of(o);
4116
+ }
4117
+ function _inherits(subClass, superClass) {
4118
+ if (typeof superClass !== "function" && superClass !== null) {
4119
+ throw new TypeError("Super expression must either be null or a function");
4120
+ }
4121
+ subClass.prototype = Object.create(superClass && superClass.prototype, {
4122
+ constructor: {
4123
+ value: subClass,
4124
+ writable: true,
4125
+ configurable: true
4126
+ }
4127
+ });
4128
+ if (superClass) _set_prototype_of(subClass, superClass);
4129
+ }
4130
+ function _possible_constructor_return(self, call) {
4131
+ if (call && (_type_of(call) === "object" || typeof call === "function")) {
4132
+ return call;
4133
+ }
4134
+ return _assert_this_initialized(self);
4135
+ }
4136
+ function _set_prototype_of(o, p) {
4137
+ _set_prototype_of = Object.setPrototypeOf || function setPrototypeOf(o, p) {
4138
+ o.__proto__ = p;
4139
+ return o;
4140
+ };
4141
+ return _set_prototype_of(o, p);
4142
+ }
4143
+ function _type_of(obj) {
4144
+ "@swc/helpers - typeof";
4145
+ return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj;
4146
+ }
4147
+ function _is_native_reflect_construct() {
4148
+ try {
4149
+ var result = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function() {}));
4150
+ } catch (_) {}
4151
+ return (_is_native_reflect_construct = function() {
4152
+ return !!result;
4153
+ })();
4154
+ }
4155
+ var FirebaseServerMcpAnalyticsService_1;
4156
+ /**
4157
+ * Reusable {@link McpAnalyticsService} that forwards each completed MCP tool call to the app's
4158
+ * {@link FirebaseServerAnalyticsService}, so MCP-transport analytics feed the same downstream
4159
+ * pipeline (e.g. Segment) as model analytics.
4160
+ *
4161
+ * Registered globally via {@link appMcpAnalyticsModuleMetadata}; tuned via
4162
+ * {@link FirebaseServerMcpAnalyticsConfig}. When no analytics service is available the call is a
4163
+ * no-op aside from the optional log line.
4164
+ */ exports.FirebaseServerMcpAnalyticsService = FirebaseServerMcpAnalyticsService_1 = /*#__PURE__*/ function(McpAnalyticsService) {
4165
+ _inherits(FirebaseServerMcpAnalyticsService, McpAnalyticsService);
4166
+ function FirebaseServerMcpAnalyticsService(analyticsService, config) {
4167
+ _class_call_check(this, FirebaseServerMcpAnalyticsService);
4168
+ var _this;
4169
+ var _ref, _ref1;
4170
+ _this = _call_super(this, FirebaseServerMcpAnalyticsService), _define_property(_this, "analyticsService", void 0), _define_property(_this, "_logger", new common.Logger(FirebaseServerMcpAnalyticsService_1.name)), _define_property(_this, "_eventName", void 0), _define_property(_this, "_logEvents", void 0);
4171
+ _this.analyticsService = analyticsService;
4172
+ _this._eventName = (_ref = config === null || config === void 0 ? void 0 : config.eventName) !== null && _ref !== void 0 ? _ref : DEFAULT_MCP_ANALYTICS_EVENT_NAME;
4173
+ _this._logEvents = (_ref1 = config === null || config === void 0 ? void 0 : config.logEvents) !== null && _ref1 !== void 0 ? _ref1 : true;
4174
+ return _this;
4175
+ }
4176
+ _create_class(FirebaseServerMcpAnalyticsService, [
4177
+ {
4178
+ key: "handleMcpAnalyticsEvent",
4179
+ value: function handleMcpAnalyticsEvent(event) {
4180
+ if (this._logEvents) {
4181
+ var uidSuffix = event.uid ? " uid=".concat(event.uid) : '';
4182
+ var durationSuffix = event.durationMs != null ? " (".concat(event.durationMs, "ms)") : '';
4183
+ var outcome = event.isSuccessful ? 'Succeeded' : 'Failed';
4184
+ this._logger.log("MCP ".concat(event.toolName, " [").concat(event.toolKind, "] ").concat(outcome).concat(uidSuffix).concat(durationSuffix));
4185
+ }
4186
+ if (this.analyticsService != null) {
4187
+ var _event_call, _event_modelType, _event_specifier;
4188
+ this.analyticsService.sendEventData(event.uid, this._eventName, {
4189
+ tool: event.toolName,
4190
+ toolKind: event.toolKind,
4191
+ call: (_event_call = event.call) !== null && _event_call !== void 0 ? _event_call : '',
4192
+ modelType: (_event_modelType = event.modelType) !== null && _event_modelType !== void 0 ? _event_modelType : '',
4193
+ specifier: (_event_specifier = event.specifier) !== null && _event_specifier !== void 0 ? _event_specifier : '',
4194
+ success: event.isSuccessful
4195
+ });
4196
+ }
4197
+ }
4198
+ }
4199
+ ]);
4200
+ return FirebaseServerMcpAnalyticsService;
4201
+ }(McpAnalyticsService);
4202
+ exports.FirebaseServerMcpAnalyticsService = FirebaseServerMcpAnalyticsService_1 = __decorate([
4203
+ common.Injectable(),
4204
+ __param(0, common.Optional()),
4205
+ __param(0, common.Inject(firebaseServer.FirebaseServerAnalyticsService)),
4206
+ __param(1, common.Optional()),
4207
+ __param(1, common.Inject(FIREBASE_SERVER_MCP_ANALYTICS_CONFIG))
4208
+ ], exports.FirebaseServerMcpAnalyticsService);
4209
+
4210
+ function _array_like_to_array(arr, len) {
4211
+ if (len == null || len > arr.length) len = arr.length;
4212
+ for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
4213
+ return arr2;
4214
+ }
4215
+ function _array_without_holes(arr) {
4216
+ if (Array.isArray(arr)) return _array_like_to_array(arr);
4217
+ }
4218
+ function _iterable_to_array(iter) {
4219
+ if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
4220
+ }
4221
+ function _non_iterable_spread() {
4222
+ throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
4223
+ }
4224
+ function _to_consumable_array(arr) {
4225
+ return _array_without_holes(arr) || _iterable_to_array(arr) || _unsupported_iterable_to_array(arr) || _non_iterable_spread();
4226
+ }
4227
+ function _unsupported_iterable_to_array(o, minLen) {
4228
+ if (!o) return;
4229
+ if (typeof o === "string") return _array_like_to_array(o, minLen);
4230
+ var n = Object.prototype.toString.call(o).slice(8, -1);
4231
+ if (n === "Object" && o.constructor) n = o.constructor.name;
4232
+ if (n === "Map" || n === "Set") return Array.from(n);
4233
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
4234
+ }
4235
+ /**
4236
+ * Generates NestJS module metadata that registers {@link FirebaseServerMcpAnalyticsService} as the
4237
+ * MCP analytics consumer, aliased to {@link MCP_ANALYTICS_SERVICE}.
4238
+ *
4239
+ * Mirrors the convention used by `appAnalyticsModuleMetadata`. Unlike `mcpModuleMetadata`, this
4240
+ * requires no dependency module — `FirebaseServerAnalyticsService` is resolved optionally and is
4241
+ * expected to be supplied globally by the app's analytics module.
4242
+ *
4243
+ * Decorate a `@Global()` module with the result so the `MCP_ANALYTICS_SERVICE` token is visible to
4244
+ * the `McpServerFactoryService` provided by the app's MCP module.
4245
+ *
4246
+ * @param config - Optional metadata + analytics config to merge in.
4247
+ * @returns NestJS module metadata providing + exporting the MCP analytics service and token.
4248
+ *
4249
+ * @example
4250
+ * ```typescript
4251
+ * @Global()
4252
+ * @Module(appMcpAnalyticsModuleMetadata())
4253
+ * export class AppMcpAnalyticsModule {}
4254
+ * ```
4255
+ */ function appMcpAnalyticsModuleMetadata() {
4256
+ var config = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
4257
+ var mcpAnalyticsConfig = config.mcpAnalyticsConfig, imports = config.imports, exports$1 = config.exports, providers = config.providers;
4258
+ var configProviders = mcpAnalyticsConfig ? [
4259
+ {
4260
+ provide: FIREBASE_SERVER_MCP_ANALYTICS_CONFIG,
4261
+ useValue: mcpAnalyticsConfig
4262
+ }
4263
+ ] : [];
4264
+ return {
4265
+ imports: _to_consumable_array(imports !== null && imports !== void 0 ? imports : []),
4266
+ exports: [
4267
+ MCP_ANALYTICS_SERVICE,
4268
+ exports.FirebaseServerMcpAnalyticsService
4269
+ ].concat(_to_consumable_array(exports$1 !== null && exports$1 !== void 0 ? exports$1 : [])),
4270
+ providers: [
4271
+ exports.FirebaseServerMcpAnalyticsService,
4272
+ {
4273
+ provide: MCP_ANALYTICS_SERVICE,
4274
+ useExisting: exports.FirebaseServerMcpAnalyticsService
4275
+ }
4276
+ ].concat(_to_consumable_array(configProviders), _to_consumable_array(providers !== null && providers !== void 0 ? providers : []))
3608
4277
  };
3609
4278
  }
3610
4279
 
3611
4280
  exports.DEFAULT_JSON_SCHEMA_GENERATION_OPTIONS = DEFAULT_JSON_SCHEMA_GENERATION_OPTIONS;
4281
+ exports.DEFAULT_MCP_ANALYTICS_EVENT_NAME = DEFAULT_MCP_ANALYTICS_EVENT_NAME;
3612
4282
  exports.DEFAULT_MCP_PATH = DEFAULT_MCP_PATH;
4283
+ exports.DEFAULT_MCP_SERVER_INSTRUCTIONS = DEFAULT_MCP_SERVER_INSTRUCTIONS;
3613
4284
  exports.DEFAULT_MCP_SERVER_NAME = DEFAULT_MCP_SERVER_NAME;
3614
4285
  exports.DEFAULT_SPECIFIER_KEY = DEFAULT_SPECIFIER_KEY;
3615
4286
  exports.DEFAULT_VOID_MCP_SUCCESS_VALUE = DEFAULT_VOID_MCP_SUCCESS_VALUE;
4287
+ exports.FIREBASE_SERVER_MCP_ANALYTICS_CONFIG = FIREBASE_SERVER_MCP_ANALYTICS_CONFIG;
3616
4288
  exports.FIREBASE_SERVER_MCP_ROUTES_FOR_GLOBAL_ROUTE_EXCLUDE = FIREBASE_SERVER_MCP_ROUTES_FOR_GLOBAL_ROUTE_EXCLUDE;
4289
+ exports.MCP_ANALYTICS_SERVICE = MCP_ANALYTICS_SERVICE;
3617
4290
  exports.MCP_AUTH_ROLE_READER = MCP_AUTH_ROLE_READER;
3618
4291
  exports.MCP_MANIFEST_VERSION = MCP_MANIFEST_VERSION;
3619
4292
  exports.MCP_MODEL_GET_BATCH_SIZE = MCP_MODEL_GET_BATCH_SIZE;
@@ -3625,8 +4298,12 @@ exports.MODEL_GET_DISPATCH_MODEL_TYPE = MODEL_GET_DISPATCH_MODEL_TYPE;
3625
4298
  exports.MODEL_GET_TOOL_NAME = MODEL_GET_TOOL_NAME;
3626
4299
  exports.MODEL_INFO_DISPATCH_CALL = MODEL_INFO_DISPATCH_CALL;
3627
4300
  exports.MODEL_INFO_DISPATCH_MODEL_TYPE = MODEL_INFO_DISPATCH_MODEL_TYPE;
4301
+ exports.MODEL_INFO_GROUPS_HINT = MODEL_INFO_GROUPS_HINT;
3628
4302
  exports.MODEL_INFO_TOOL_NAME = MODEL_INFO_TOOL_NAME;
4303
+ exports.MODEL_INFO_UNGROUPED_LABEL = MODEL_INFO_UNGROUPED_LABEL;
4304
+ exports.McpAnalyticsService = McpAnalyticsService;
3629
4305
  exports.McpModuleConfig = McpModuleConfig;
4306
+ exports.appMcpAnalyticsModuleMetadata = appMcpAnalyticsModuleMetadata;
3630
4307
  exports.buildDefaultMcpToolDescription = buildDefaultMcpToolDescription;
3631
4308
  exports.buildMcpToolName = buildMcpToolName;
3632
4309
  exports.buildStaticWireEntry = buildStaticWireEntry;
@@ -3642,5 +4319,6 @@ exports.generateMcpToolDefinitions = generateMcpToolDefinitions;
3642
4319
  exports.handleStreamableHttpMcpRequest = handleStreamableHttpMcpRequest;
3643
4320
  exports.mcpManifestKey = mcpManifestKey;
3644
4321
  exports.mcpModuleMetadata = mcpModuleMetadata;
4322
+ exports.noopMcpAnalyticsService = noopMcpAnalyticsService;
3645
4323
  exports.resolveEffectiveReadOnly = resolveEffectiveReadOnly;
3646
4324
  exports.resolveRequiredScope = resolveRequiredScope;