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