@dereekb/firebase-server 13.11.17 → 13.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/index.cjs.js +218 -31
  2. package/index.esm.js +217 -34
  3. package/mailgun/package.json +9 -9
  4. package/mcp/index.cjs.default.js +1 -0
  5. package/mcp/index.cjs.js +3646 -0
  6. package/mcp/index.cjs.mjs +2 -0
  7. package/mcp/index.d.ts +1 -0
  8. package/mcp/index.esm.js +3609 -0
  9. package/mcp/package.json +33 -0
  10. package/mcp/src/index.d.ts +1 -0
  11. package/mcp/src/lib/controller/index.d.ts +2 -0
  12. package/mcp/src/lib/controller/mcp.controller.d.ts +19 -0
  13. package/mcp/src/lib/controller/mcp.wellknown.controller.d.ts +25 -0
  14. package/mcp/src/lib/index.d.ts +5 -0
  15. package/mcp/src/lib/mcp.config.d.ts +100 -0
  16. package/mcp/src/lib/mcp.module.d.ts +49 -0
  17. package/mcp/src/lib/service/index.d.ts +8 -0
  18. package/mcp/src/lib/service/mcp.manifest.d.ts +150 -0
  19. package/mcp/src/lib/service/mcp.response-formatter.d.ts +36 -0
  20. package/mcp/src/lib/service/mcp.server.factory.d.ts +124 -0
  21. package/mcp/src/lib/service/mcp.tool-generator.d.ts +235 -0
  22. package/mcp/src/lib/service/mcp.visibility.d.ts +99 -0
  23. package/mcp/src/lib/service/tools/mcp.tool.model-decode.d.ts +87 -0
  24. package/mcp/src/lib/service/tools/mcp.tool.model-get.d.ts +81 -0
  25. package/mcp/src/lib/service/tools/mcp.tool.model-info.d.ts +84 -0
  26. package/mcp/src/lib/service/tools/mcp.tool.whoami.d.ts +72 -0
  27. package/mcp/src/lib/transport/index.d.ts +1 -0
  28. package/mcp/src/lib/transport/streamable-http.transport.d.ts +21 -0
  29. package/model/index.cjs.js +639 -266
  30. package/model/index.esm.js +640 -270
  31. package/model/package.json +9 -9
  32. package/model/src/lib/storagefile/extension/compress.pdf.d.ts +29 -1
  33. package/model/src/lib/storagefile/index.d.ts +1 -0
  34. package/model/src/lib/storagefile/storagefile.action.server.d.ts +29 -2
  35. package/model/src/lib/storagefile/storagefile.mcp.d.ts +32 -0
  36. package/model/src/lib/storagefile/storagefile.module.d.ts +20 -3
  37. package/oidc/index.cjs.js +322 -147
  38. package/oidc/index.esm.js +321 -148
  39. package/oidc/package.json +10 -10
  40. package/oidc/src/lib/controller/oidc.wellknown.controller.d.ts +6 -15
  41. package/oidc/src/lib/middleware/oauth-auth.middleware.d.ts +22 -2
  42. package/oidc/src/lib/middleware/oauth-auth.module.d.ts +57 -0
  43. package/oidc/src/lib/oidc.config.d.ts +73 -0
  44. package/oidc/src/lib/oidc.module.d.ts +44 -2
  45. package/package.json +16 -10
  46. package/src/lib/auth/auth.service.d.ts +16 -1
  47. package/src/lib/auth/auth.service.error.util.d.ts +24 -5
  48. package/src/lib/env/env.config.d.ts +16 -0
  49. package/src/lib/env/env.service.d.ts +9 -0
  50. package/src/lib/nest/controller/model/model.api.get.service.d.ts +35 -1
  51. package/src/lib/nest/env/env.service.d.ts +1 -0
  52. package/src/lib/nest/model/api.details.d.ts +116 -5
  53. package/src/lib/nest/model/crud.assert.function.d.ts +1 -1
  54. package/src/lib/nest/model/index.d.ts +1 -0
  55. package/src/lib/nest/model/invoke.model.function.d.ts +89 -0
  56. package/test/package.json +11 -11
  57. package/twilio/LICENSE +21 -0
  58. package/twilio/index.cjs.default.js +1 -0
  59. package/twilio/index.cjs.js +404 -0
  60. package/twilio/index.cjs.mjs +2 -0
  61. package/twilio/index.d.ts +1 -0
  62. package/twilio/index.esm.js +398 -0
  63. package/twilio/package.json +25 -0
  64. package/twilio/src/index.d.ts +1 -0
  65. package/twilio/src/lib/index.d.ts +1 -0
  66. package/twilio/src/lib/notification.send.service.twilio.d.ts +148 -0
  67. package/zoho/package.json +9 -9
@@ -0,0 +1,3646 @@
1
+ 'use strict';
2
+
3
+ var common = require('@nestjs/common');
4
+ var node_fs = require('node:fs');
5
+ var mcp_js = require('@modelcontextprotocol/sdk/server/mcp.js');
6
+ var types_js = require('@modelcontextprotocol/sdk/types.js');
7
+ var oidc = require('@dereekb/firebase-server/oidc');
8
+ var util = require('@dereekb/util');
9
+ var firebaseServer = require('@dereekb/firebase-server');
10
+ var node_util = require('node:util');
11
+ var model = require('@dereekb/model');
12
+ var firebase = require('@dereekb/firebase');
13
+ var streamableHttp_js = require('@modelcontextprotocol/sdk/server/streamableHttp.js');
14
+
15
+ function _class_call_check$3(instance, Constructor) {
16
+ if (!(instance instanceof Constructor)) {
17
+ throw new TypeError("Cannot call a class as a function");
18
+ }
19
+ }
20
+ function _define_property$6(obj, key, value) {
21
+ if (key in obj) {
22
+ Object.defineProperty(obj, key, {
23
+ value: value,
24
+ enumerable: true,
25
+ configurable: true,
26
+ writable: true
27
+ });
28
+ } else {
29
+ obj[key] = value;
30
+ }
31
+ return obj;
32
+ }
33
+ /**
34
+ * Default path the MCP Streamable HTTP transport is mounted at.
35
+ *
36
+ * Combined with the app origin to form the canonical MCP resource URL
37
+ * (e.g., `https://api.example.com/mcp`) advertised in the protected-resource
38
+ * discovery document at `/.well-known/oauth-protected-resource`.
39
+ */ var DEFAULT_MCP_PATH = '/mcp';
40
+ /**
41
+ * Default name advertised by the MCP server on the JSON-RPC `initialize` handshake.
42
+ *
43
+ * Apps may override this via {@link McpModuleConfig.serverName} to identify their
44
+ * deployment (e.g., `demo-api-mcp`, `hellosubs-api-mcp`).
45
+ */ var DEFAULT_MCP_SERVER_NAME = 'dbx-firebase-server-mcp';
46
+ /**
47
+ * Configuration for the firebase-server/mcp module.
48
+ *
49
+ * Apps construct this in their `*McpModule` provider and pass it through
50
+ * {@link mcpModuleMetadata}. It carries:
51
+ *
52
+ * - The canonical issuer URL for the OIDC provider that gates this MCP endpoint
53
+ * (used in the protected-resource discovery document).
54
+ * - The canonical resource URL where the MCP transport is mounted (also part of
55
+ * the discovery document; doubles as the `resource` claim consumers should
56
+ * verify their access tokens against).
57
+ * - Optional server identity (name, version) advertised on the MCP `initialize` handshake.
58
+ *
59
+ * The OAuth bearer middleware that authenticates `/mcp` is configured on
60
+ * {@link OidcModuleConfig.protectedPaths} — that's outside this config's scope.
61
+ */ var McpModuleConfig = function McpModuleConfig() {
62
+ _class_call_check$3(this, McpModuleConfig);
63
+ /**
64
+ * The canonical issuer URL of the OIDC provider that gates this MCP endpoint.
65
+ *
66
+ * Surfaced in the `authorization_servers` field of the protected-resource
67
+ * discovery document. Claude custom-connector reads this to discover the OIDC issuer.
68
+ *
69
+ * @example 'https://api.example.com/oidc'
70
+ */ _define_property$6(this, "oidcIssuer", void 0);
71
+ /**
72
+ * The canonical resource URL of the MCP endpoint.
73
+ *
74
+ * Surfaced as the `resource` field of the protected-resource discovery document,
75
+ * and used as the audience the access token's `aud` claim should match.
76
+ *
77
+ * @example 'https://api.example.com/mcp'
78
+ */ _define_property$6(this, "mcpUrl", void 0);
79
+ /**
80
+ * Optional name advertised on the MCP `initialize` handshake. Defaults to
81
+ * {@link DEFAULT_MCP_SERVER_NAME}.
82
+ */ _define_property$6(this, "serverName", void 0);
83
+ /**
84
+ * Optional version advertised on the MCP `initialize` handshake.
85
+ */ _define_property$6(this, "serverVersion", void 0);
86
+ /**
87
+ * Absolute path to a pre-rendered MCP manifest JSON file produced by
88
+ * `dbx-cli-generate-mcp-manifest`. When set, the runtime reads it once at
89
+ * boot and uses each tool's `description`, `inputSchema`, and `outputSchema`
90
+ * during tool generation — no per-request file I/O.
91
+ *
92
+ * Optional. When unset or the file is missing, the runtime falls back to
93
+ * today's behavior (auto-generated descriptions, ArkType-derived input
94
+ * schemas, no output schemas) and emits a single boot warning.
95
+ */ _define_property$6(this, "mcpManifestPath", void 0);
96
+ /**
97
+ * When `true`, the MCP server only advertises tools whose effective read-only classification is `true`.
98
+ *
99
+ * Write tools (`create`/`update`/`delete`) and tools with unknown classification (e.g., `invoke`
100
+ * with no explicit `mcp.readOnly` override) are dropped from `tools/list` — fail-safe under the
101
+ * principle that anything not provably read-only is treated as a write.
102
+ *
103
+ * The advertised `serverName` on the JSON-RPC `initialize` handshake is suffixed with
104
+ * ` (read-only)` so the client surface reflects the mode.
105
+ */ _define_property$6(this, "readOnly", void 0);
106
+ };
107
+ /**
108
+ * NestJS injection token for the optional {@link McpAuthRoleReader} provider.
109
+ */ var MCP_AUTH_ROLE_READER = 'MCP_AUTH_ROLE_READER';
110
+
111
+ function _type_of$1(obj) {
112
+ "@swc/helpers - typeof";
113
+ return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj;
114
+ }
115
+ function __decorate(decorators, target, key, desc) {
116
+ 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);
118
+ 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
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
120
+ }
121
+ function __param(paramIndex, decorator) {
122
+ return function(target, key) {
123
+ decorator(target, key, paramIndex);
124
+ };
125
+ }
126
+ typeof SuppressedError === "function" ? SuppressedError : function(error, suppressed, message) {
127
+ var e = new Error(message);
128
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
129
+ };
130
+
131
+ /**
132
+ * Version stamp embedded in the build-time MCP manifest JSON. Runtime loaders
133
+ * refuse manifests whose `version` does not match this constant.
134
+ *
135
+ * Mirrors {@link MCP_MANIFEST_VERSION} in `@dereekb/dbx-cli` — both packages
136
+ * version-bump together when the manifest shape changes.
137
+ */ var MCP_MANIFEST_VERSION = 1;
138
+ /**
139
+ * Builds the canonical MCP manifest key for a (modelType, callType, specifier) triple.
140
+ *
141
+ * Default-specifier entries collapse to `_`. Must stay in sync with the build-time
142
+ * helper of the same name in `@dereekb/dbx-cli`.
143
+ *
144
+ * @param modelType - The Firestore model type segment of the key.
145
+ * @param call - The call type segment of the key.
146
+ * @param specifier - The specifier segment, or `_` / undefined for the default entry.
147
+ * @returns The canonical `modelType.call.specifier` manifest key.
148
+ */ function mcpManifestKey(modelType, call, specifier) {
149
+ var isDefault = specifier == null || specifier === '_';
150
+ return isDefault ? "".concat(modelType, ".").concat(call, "._") : "".concat(modelType, ".").concat(call, ".").concat(specifier);
151
+ }
152
+
153
+ function _instanceof(left, right) {
154
+ "@swc/helpers - instanceof";
155
+ if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) {
156
+ return !!right[Symbol.hasInstance](left);
157
+ } else {
158
+ return left instanceof right;
159
+ }
160
+ }
161
+ /**
162
+ * Default structured value emitted by MCP when a handler returns `undefined`.
163
+ *
164
+ * Keeps the response usable by clients that key off either the text content or the
165
+ * structured/object body. Tests and any future overrides should compare against this
166
+ * constant rather than re-literalling `{ ok: true }`.
167
+ */ var DEFAULT_VOID_MCP_SUCCESS_VALUE = Object.freeze({
168
+ ok: true
169
+ });
170
+ /**
171
+ * Resolves a dispatch result + handler API details into the MCP `CallToolResult` shape.
172
+ *
173
+ * Three-tier resolution as documented on {@link OnCallModelFunctionApiDetails.mcp}:
174
+ *
175
+ * - **Tier 3** — when `mcp.formatResponse` is set, its return value is used verbatim.
176
+ * - **Tier 2** — when `mcp.summarizeResponse` is set, the summary string is wrapped into a
177
+ * single text content block with the raw `result` exposed as `structuredContent`.
178
+ * - **Tier 1** — default: JSON-stringify `result` as a single text content block, also
179
+ * exposing the raw value as `structuredContent`.
180
+ *
181
+ * @param result - The handler's return value.
182
+ * @param params - The {@link OnCallTypedModelParams} that were dispatched.
183
+ * @param details - The handler-level API details (carries Tier 2/3 formatters).
184
+ * @returns The MCP tool response content.
185
+ */ function formatMcpToolResponse(result, params, details) {
186
+ var mcp = details === null || details === void 0 ? void 0 : details.mcp;
187
+ var response;
188
+ if (mcp === null || mcp === void 0 ? void 0 : mcp.formatResponse) {
189
+ response = mcp.formatResponse(result, params);
190
+ } else if (mcp === null || mcp === void 0 ? void 0 : mcp.summarizeResponse) {
191
+ var summary = mcp.summarizeResponse(result, params);
192
+ response = {
193
+ content: [
194
+ {
195
+ type: 'text',
196
+ text: summary
197
+ }
198
+ ],
199
+ structuredContent: result
200
+ };
201
+ } else {
202
+ response = {
203
+ content: [
204
+ {
205
+ type: 'text',
206
+ text: stringifyResult(result)
207
+ }
208
+ ],
209
+ structuredContent: result === undefined ? DEFAULT_VOID_MCP_SUCCESS_VALUE : result
210
+ };
211
+ }
212
+ return response;
213
+ }
214
+ /**
215
+ * Converts an error thrown from the dispatch chain into the MCP error response shape.
216
+ *
217
+ * @param error - The thrown error.
218
+ * @returns An MCP tool response with `isError: true` and the error message as a text block.
219
+ */ function formatMcpToolErrorResponse(error) {
220
+ var message = _instanceof(error, Error) ? error.message : String(error);
221
+ return {
222
+ isError: true,
223
+ content: [
224
+ {
225
+ type: 'text',
226
+ text: message
227
+ }
228
+ ]
229
+ };
230
+ }
231
+ function stringifyResult(result) {
232
+ var text;
233
+ if (result === undefined) {
234
+ text = JSON.stringify(DEFAULT_VOID_MCP_SUCCESS_VALUE);
235
+ } else if (typeof result === 'string') {
236
+ text = result;
237
+ } else {
238
+ try {
239
+ text = JSON.stringify(result, null, 2);
240
+ } catch (unused) {
241
+ text = node_util.inspect(result, {
242
+ depth: 4
243
+ });
244
+ }
245
+ }
246
+ return text;
247
+ }
248
+
249
+ /**
250
+ * Classifies a {@link McpToolVisibility} value into its normalized boot-time form.
251
+ *
252
+ * Defaults `undefined` to `'always'` so handlers without a visibility field stay visible.
253
+ *
254
+ * @param visibility - The raw visibility value from the handler's `mcp.visibility` field.
255
+ * @returns The discriminated classification used by the per-request filter loop.
256
+ */ function classifyVisibility(visibility) {
257
+ var result;
258
+ if (visibility == null || visibility === true) {
259
+ result = {
260
+ visibilityKind: 'always'
261
+ };
262
+ } else if (visibility === false) {
263
+ result = {
264
+ visibilityKind: 'never'
265
+ };
266
+ } else if (typeof visibility === 'function') {
267
+ result = {
268
+ visibilityKind: 'dynamic',
269
+ visibilityFn: visibility
270
+ };
271
+ } else {
272
+ result = {
273
+ visibilityKind: 'declarative',
274
+ rule: visibility
275
+ };
276
+ }
277
+ return result;
278
+ }
279
+ /**
280
+ * Inference table from CRUD call type to "is this a read operation?".
281
+ *
282
+ * `read` and `query` → true. `create`/`update`/`delete` → false. Anything else → undefined.
283
+ * Unknown call types (custom verbs, `invoke`) intentionally leave `effectiveReadOnly`
284
+ * undefined so the module-level `readOnly` filter treats them as writes (fail-safe).
285
+ */ var READ_ONLY_BY_CALL_TYPE = {
286
+ read: true,
287
+ query: true,
288
+ create: false,
289
+ update: false,
290
+ delete: false
291
+ };
292
+ /**
293
+ * Resolves the effective read-only classification for a handler.
294
+ *
295
+ * Explicit handler override wins. Otherwise infers from the call type. Returns
296
+ * `undefined` when neither source provides a definite classification.
297
+ *
298
+ * @param explicitReadOnly - The handler's explicit `mcp.readOnly` value, if any.
299
+ * @param callType - The dispatch call type used to infer read-only when no override is present.
300
+ * @returns The effective read-only flag, or `undefined` when neither source resolves a value.
301
+ */ function resolveEffectiveReadOnly(explicitReadOnly, callType) {
302
+ if (explicitReadOnly != null) {
303
+ return explicitReadOnly;
304
+ }
305
+ return READ_ONLY_BY_CALL_TYPE[callType];
306
+ }
307
+ /**
308
+ * Resolves the OIDC scope required to invoke a given call type, or `undefined` for
309
+ * non-CRUD calls. Thin re-export so the tool generator doesn't need to reach into
310
+ * `@dereekb/firebase` directly.
311
+ *
312
+ * @param callType - The dispatch call type to map to a CRUD OIDC scope.
313
+ * @returns The required scope for this call type, or `undefined` when no scope is enforced.
314
+ */ function resolveRequiredScope(callType) {
315
+ return firebase.callModelOidcScopeForCallType(callType);
316
+ }
317
+
318
+ function _array_like_to_array$4(arr, len) {
319
+ if (len == null || len > arr.length) len = arr.length;
320
+ for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
321
+ return arr2;
322
+ }
323
+ function _array_with_holes$2(arr) {
324
+ if (Array.isArray(arr)) return arr;
325
+ }
326
+ function _iterable_to_array_limit$2(arr, i) {
327
+ var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
328
+ if (_i == null) return;
329
+ var _arr = [];
330
+ var _n = true;
331
+ var _d = false;
332
+ var _s, _e;
333
+ try {
334
+ for(_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true){
335
+ _arr.push(_s.value);
336
+ if (i && _arr.length === i) break;
337
+ }
338
+ } catch (err) {
339
+ _d = true;
340
+ _e = err;
341
+ } finally{
342
+ try {
343
+ if (!_n && _i["return"] != null) _i["return"]();
344
+ } finally{
345
+ if (_d) throw _e;
346
+ }
347
+ }
348
+ return _arr;
349
+ }
350
+ function _non_iterable_rest$2() {
351
+ 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
+ }
353
+ 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();
355
+ }
356
+ function _type_of(obj) {
357
+ "@swc/helpers - typeof";
358
+ return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj;
359
+ }
360
+ function _unsupported_iterable_to_array$4(o, minLen) {
361
+ if (!o) return;
362
+ if (typeof o === "string") return _array_like_to_array$4(o, minLen);
363
+ var n = Object.prototype.toString.call(o).slice(8, -1);
364
+ if (n === "Object" && o.constructor) n = o.constructor.name;
365
+ 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);
367
+ }
368
+ /**
369
+ * Default `toJsonSchema()` options.
370
+ *
371
+ * ArkType throws on predicate definitions and on `undefined` fields by default;
372
+ * these fallback handlers downgrade those errors so a partial schema is emitted
373
+ * for tools that mostly fit JSON Schema. The `unit` fallback covers `clearable(t)`
374
+ * from `@dereekb/model` (which expands to `t | undefined` and surfaces as an ArkType
375
+ * `unit: undefined` schema node).
376
+ */ var DEFAULT_JSON_SCHEMA_GENERATION_OPTIONS = {
377
+ fallback: {
378
+ predicate: function predicate() {
379
+ return {};
380
+ },
381
+ unit: function unit() {
382
+ return {};
383
+ },
384
+ undefinedAsClearable: function undefinedAsClearable() {
385
+ return {};
386
+ }
387
+ }
388
+ };
389
+ /**
390
+ * Builds the frozen wire-shape entry used by the per-request `tools/list` hot path.
391
+ *
392
+ * Tools without an `inputSchema` default to `{ type: 'object' }` to match the runtime
393
+ * behaviour the factory used before the precompute optimisation existed.
394
+ *
395
+ * @param input - The tool name, description, and optional input/output schemas used to assemble the wire entry.
396
+ * @returns A frozen wire entry safe to share across requests.
397
+ */ function buildStaticWireEntry(input) {
398
+ var _input_inputSchema;
399
+ var inputSchema = (_input_inputSchema = input.inputSchema) !== null && _input_inputSchema !== void 0 ? _input_inputSchema : {
400
+ type: 'object'
401
+ };
402
+ var entry = input.outputSchema == null ? {
403
+ name: input.name,
404
+ description: input.description,
405
+ inputSchema: inputSchema
406
+ } : {
407
+ name: input.name,
408
+ description: input.description,
409
+ inputSchema: inputSchema,
410
+ outputSchema: input.outputSchema
411
+ };
412
+ return Object.freeze(entry);
413
+ }
414
+ // MARK: Naming
415
+ /**
416
+ * The default specifier key used when a handler is not behind a specifier router.
417
+ */ var DEFAULT_SPECIFIER_KEY = '_';
418
+ /**
419
+ * Builds the MCP tool name for a (modelType, callType, specifier) triple.
420
+ *
421
+ * Apps can override the auto-generated name by setting
422
+ * {@link OnCallModelFunctionApiDetails.mcp.name} on the handler.
423
+ *
424
+ * @param modelType - The Firestore model type (e.g., `storageFile`).
425
+ * @param callType - The call type (e.g., `invoke`).
426
+ * @param specifier - The specifier key, or `_` / undefined for the default entry.
427
+ * @returns The hyphen-joined tool name advertised on `tools/list`.
428
+ */ function buildMcpToolName(modelType, callType, specifier) {
429
+ var isDefault = specifier == null || specifier === DEFAULT_SPECIFIER_KEY;
430
+ return isDefault ? "".concat(modelType, "-").concat(callType) : "".concat(modelType, "-").concat(callType, "-").concat(specifier);
431
+ }
432
+ /**
433
+ * Builds the default description used when no build-time MCP manifest
434
+ * entry is available for the (modelType, callType, specifier) tuple.
435
+ *
436
+ * @param modelType - The Firestore model type segment used in the generated description.
437
+ * @param callType - The call type segment used in the generated description.
438
+ * @param specifier - The specifier segment, or `_` / undefined for the default entry.
439
+ * @returns A human-readable fallback description for the tool.
440
+ */ function buildDefaultMcpToolDescription(modelType, callType, specifier) {
441
+ var isDefault = specifier == null || specifier === DEFAULT_SPECIFIER_KEY;
442
+ return isDefault ? 'Performs the "'.concat(callType, '" call on the "').concat(modelType, '" model.') : 'Performs the "'.concat(callType, '" call on the "').concat(modelType, '" model with the "').concat(specifier, '" specifier.');
443
+ }
444
+ // MARK: Generation
445
+ /**
446
+ * Generates MCP tool definitions from a model-first API details tree.
447
+ *
448
+ * Walks each (modelType, callType, specifier) triple in the tree, calls
449
+ * `inputType.toJsonSchema(options)` for the schema, and applies any handler-level
450
+ * MCP `name` override. Descriptions and input/output schemas are pulled from the
451
+ * build-time manifest when supplied. Tools without an `inputType` are skipped and
452
+ * reported so callers can log the gap at startup.
453
+ *
454
+ * @param apiDetails - The model-first API details tree returned by `getModelApiDetails(callModelFn)`.
455
+ * @param options - Optional schema generation options forwarded to `toJsonSchema()`. Defaults to {@link DEFAULT_JSON_SCHEMA_GENERATION_OPTIONS}.
456
+ * @param manifest - Optional build-time manifest map; supplies overrides for descriptions and input/output schemas keyed by {@link mcpManifestKey}.
457
+ * @returns The list of generated tool definitions plus any skip reports.
458
+ */ function generateMcpToolDefinitions(apiDetails) {
459
+ var options = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : DEFAULT_JSON_SCHEMA_GENERATION_OPTIONS, manifest = arguments.length > 2 ? arguments[2] : void 0;
460
+ var tools = [];
461
+ var neverVisibleTools = [];
462
+ var skipped = [];
463
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
464
+ try {
465
+ for(var _iterator = Object.entries(apiDetails.models)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
466
+ var _step_value = _sliced_to_array$2(_step.value, 2), modelType = _step_value[0], modelEntry = _step_value[1];
467
+ var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
468
+ try {
469
+ for(var _iterator1 = Object.entries(modelEntry.calls)[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
470
+ var _step_value1 = _sliced_to_array$2(_step1.value, 2), callType = _step_value1[0], callDetails = _step_value1[1];
471
+ if (callDetails == null) {
472
+ continue;
473
+ }
474
+ generateToolsForModelCall({
475
+ modelType: modelType,
476
+ callType: callType,
477
+ callDetails: callDetails,
478
+ options: options,
479
+ manifest: manifest,
480
+ outTools: tools,
481
+ outNeverVisibleTools: neverVisibleTools,
482
+ outSkipped: skipped
483
+ });
484
+ }
485
+ } catch (err) {
486
+ _didIteratorError1 = true;
487
+ _iteratorError1 = err;
488
+ } finally{
489
+ try {
490
+ if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
491
+ _iterator1.return();
492
+ }
493
+ } finally{
494
+ if (_didIteratorError1) {
495
+ throw _iteratorError1;
496
+ }
497
+ }
498
+ }
499
+ }
500
+ } catch (err) {
501
+ _didIteratorError = true;
502
+ _iteratorError = err;
503
+ } finally{
504
+ try {
505
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
506
+ _iterator.return();
507
+ }
508
+ } finally{
509
+ if (_didIteratorError) {
510
+ throw _iteratorError;
511
+ }
512
+ }
513
+ }
514
+ return {
515
+ tools: tools,
516
+ neverVisibleTools: neverVisibleTools,
517
+ skipped: skipped
518
+ };
519
+ }
520
+ function generateToolsForModelCall(context) {
521
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
522
+ try {
523
+ for(var _iterator = Object.entries(context.callDetails.specifiers)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
524
+ var _step_value = _sliced_to_array$2(_step.value, 2), specifierKey = _step_value[0], handlerDetails = _step_value[1];
525
+ if (handlerDetails != null) {
526
+ generateToolForSpecifier(context, specifierKey, handlerDetails);
527
+ }
528
+ }
529
+ } catch (err) {
530
+ _didIteratorError = true;
531
+ _iteratorError = err;
532
+ } finally{
533
+ try {
534
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
535
+ _iterator.return();
536
+ }
537
+ } finally{
538
+ if (_didIteratorError) {
539
+ throw _iteratorError;
540
+ }
541
+ }
542
+ }
543
+ }
544
+ function generateToolForSpecifier(context, specifierKey, handlerDetails) {
545
+ var _ref, _ref1, _resolveRequiredScope;
546
+ var _handlerDetails_mcp, _handlerDetails_mcp1, _handlerDetails_mcp2, _handlerDetails_mcp3;
547
+ var modelType = context.modelType, callType = context.callType, callDetails = context.callDetails, options = context.options, manifest = context.manifest, outTools = context.outTools, outNeverVisibleTools = context.outNeverVisibleTools, outSkipped = context.outSkipped;
548
+ var specifier = callDetails.isSpecifier ? specifierKey : undefined;
549
+ var dispatch = {
550
+ call: callType,
551
+ modelType: modelType,
552
+ specifier: specifier
553
+ };
554
+ var name = (_ref = (_handlerDetails_mcp = handlerDetails.mcp) === null || _handlerDetails_mcp === void 0 ? void 0 : _handlerDetails_mcp.name) !== null && _ref !== void 0 ? _ref : buildMcpToolName(modelType, callType, specifier);
555
+ var manifestEntry = manifest === null || manifest === void 0 ? void 0 : manifest.get(mcpManifestKey(modelType, callType, specifier));
556
+ var description = (_ref1 = manifestEntry === null || manifestEntry === void 0 ? void 0 : manifestEntry.description) !== null && _ref1 !== void 0 ? _ref1 : buildDefaultMcpToolDescription(modelType, callType, specifier);
557
+ var inputSchema = resolveInputSchema({
558
+ handlerDetails: handlerDetails,
559
+ manifestEntry: manifestEntry,
560
+ options: options,
561
+ dispatch: dispatch,
562
+ toolName: name,
563
+ outSkipped: outSkipped
564
+ });
565
+ if (inputSchema == null) {
566
+ return;
567
+ }
568
+ var classified = classifyVisibility((_handlerDetails_mcp1 = handlerDetails.mcp) === null || _handlerDetails_mcp1 === void 0 ? void 0 : _handlerDetails_mcp1.visibility);
569
+ var requiredScope = (_resolveRequiredScope = resolveRequiredScope(callType)) !== null && _resolveRequiredScope !== void 0 ? _resolveRequiredScope : undefined;
570
+ var effectiveReadOnly = resolveEffectiveReadOnly((_handlerDetails_mcp2 = handlerDetails.mcp) === null || _handlerDetails_mcp2 === void 0 ? void 0 : _handlerDetails_mcp2.readOnly, callType);
571
+ var filterMetadata;
572
+ if (classified.visibilityKind === 'declarative') {
573
+ filterMetadata = {
574
+ visibilityKind: 'declarative',
575
+ rule: classified.rule,
576
+ requiredScope: requiredScope,
577
+ effectiveReadOnly: effectiveReadOnly
578
+ };
579
+ } else if (classified.visibilityKind === 'dynamic') {
580
+ filterMetadata = {
581
+ visibilityKind: 'dynamic',
582
+ visibilityFn: classified.visibilityFn,
583
+ requiredScope: requiredScope,
584
+ effectiveReadOnly: effectiveReadOnly
585
+ };
586
+ } else {
587
+ filterMetadata = {
588
+ visibilityKind: classified.visibilityKind,
589
+ requiredScope: requiredScope,
590
+ effectiveReadOnly: effectiveReadOnly
591
+ };
592
+ }
593
+ var outputSchema = manifestEntry === null || manifestEntry === void 0 ? void 0 : manifestEntry.outputSchema;
594
+ var staticWireEntry = buildStaticWireEntry({
595
+ name: name,
596
+ description: description,
597
+ inputSchema: inputSchema,
598
+ outputSchema: outputSchema
599
+ });
600
+ var definition = {
601
+ name: name,
602
+ description: description,
603
+ inputSchema: inputSchema,
604
+ outputSchema: outputSchema,
605
+ details: handlerDetails,
606
+ dispatch: dispatch,
607
+ filterMetadata: filterMetadata,
608
+ staticWireEntry: staticWireEntry,
609
+ toolDetailsBuilder: (_handlerDetails_mcp3 = handlerDetails.mcp) === null || _handlerDetails_mcp3 === void 0 ? void 0 : _handlerDetails_mcp3.toolDetails
610
+ };
611
+ if (filterMetadata.visibilityKind === 'never') {
612
+ outNeverVisibleTools.push(definition);
613
+ } else {
614
+ outTools.push(definition);
615
+ }
616
+ }
617
+ function resolveInputSchema(context) {
618
+ var handlerDetails = context.handlerDetails, manifestEntry = context.manifestEntry, options = context.options, dispatch = context.dispatch, toolName = context.toolName, outSkipped = context.outSkipped;
619
+ if ((manifestEntry === null || manifestEntry === void 0 ? void 0 : manifestEntry.inputSchema) != null) {
620
+ return manifestEntry.inputSchema;
621
+ }
622
+ if (handlerDetails.inputType == null) {
623
+ outSkipped.push({
624
+ toolName: toolName,
625
+ reason: 'missing_input_type',
626
+ dispatch: dispatch
627
+ });
628
+ return undefined;
629
+ }
630
+ var result;
631
+ try {
632
+ var exported = model.arktypeToJsonSchemaForExport(handlerDetails.inputType);
633
+ if (exported && (typeof exported === "undefined" ? "undefined" : _type_of(exported)) === 'object') {
634
+ result = exported;
635
+ } else {
636
+ // arktypeToJsonSchemaForExport returned a non-object (shouldn't happen for object schemas).
637
+ // Fall back to the raw arktype output preserving the legacy options for safety.
638
+ result = handlerDetails.inputType.toJsonSchema(options);
639
+ }
640
+ } catch (error) {
641
+ outSkipped.push({
642
+ toolName: toolName,
643
+ reason: 'schema_generation_failed',
644
+ dispatch: dispatch,
645
+ error: error
646
+ });
647
+ result = undefined;
648
+ }
649
+ return result;
650
+ }
651
+
652
+ function _array_like_to_array$3(arr, len) {
653
+ if (len == null || len > arr.length) len = arr.length;
654
+ for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
655
+ return arr2;
656
+ }
657
+ function _array_without_holes$3(arr) {
658
+ if (Array.isArray(arr)) return _array_like_to_array$3(arr);
659
+ }
660
+ function asyncGeneratorStep$3(gen, resolve, reject, _next, _throw, key, arg) {
661
+ try {
662
+ var info = gen[key](arg);
663
+ var value = info.value;
664
+ } catch (error) {
665
+ reject(error);
666
+ return;
667
+ }
668
+ if (info.done) {
669
+ resolve(value);
670
+ } else {
671
+ Promise.resolve(value).then(_next, _throw);
672
+ }
673
+ }
674
+ function _async_to_generator$3(fn) {
675
+ return function() {
676
+ var self = this, args = arguments;
677
+ return new Promise(function(resolve, reject) {
678
+ var gen = fn.apply(self, args);
679
+ function _next(value) {
680
+ asyncGeneratorStep$3(gen, resolve, reject, _next, _throw, "next", value);
681
+ }
682
+ function _throw(err) {
683
+ asyncGeneratorStep$3(gen, resolve, reject, _next, _throw, "throw", err);
684
+ }
685
+ _next(undefined);
686
+ });
687
+ };
688
+ }
689
+ function _iterable_to_array$3(iter) {
690
+ if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
691
+ }
692
+ function _non_iterable_spread$3() {
693
+ 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
+ }
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();
697
+ }
698
+ function _unsupported_iterable_to_array$3(o, minLen) {
699
+ if (!o) return;
700
+ if (typeof o === "string") return _array_like_to_array$3(o, minLen);
701
+ var n = Object.prototype.toString.call(o).slice(8, -1);
702
+ if (n === "Object" && o.constructor) n = o.constructor.name;
703
+ 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);
705
+ }
706
+ function _ts_generator$3(thisArg, body) {
707
+ var f, y, t, _ = {
708
+ label: 0,
709
+ sent: function() {
710
+ if (t[0] & 1) throw t[1];
711
+ return t[1];
712
+ },
713
+ trys: [],
714
+ ops: []
715
+ }, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype), d = Object.defineProperty;
716
+ return d(g, "next", {
717
+ value: verb(0)
718
+ }), d(g, "throw", {
719
+ value: verb(1)
720
+ }), d(g, "return", {
721
+ value: verb(2)
722
+ }), typeof Symbol === "function" && d(g, Symbol.iterator, {
723
+ value: function() {
724
+ return this;
725
+ }
726
+ }), g;
727
+ function verb(n) {
728
+ return function(v) {
729
+ return step([
730
+ n,
731
+ v
732
+ ]);
733
+ };
734
+ }
735
+ function step(op) {
736
+ if (f) throw new TypeError("Generator is already executing.");
737
+ while(g && (g = 0, op[0] && (_ = 0)), _)try {
738
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
739
+ if (y = 0, t) op = [
740
+ op[0] & 2,
741
+ t.value
742
+ ];
743
+ switch(op[0]){
744
+ case 0:
745
+ case 1:
746
+ t = op;
747
+ break;
748
+ case 4:
749
+ _.label++;
750
+ return {
751
+ value: op[1],
752
+ done: false
753
+ };
754
+ case 5:
755
+ _.label++;
756
+ y = op[1];
757
+ op = [
758
+ 0
759
+ ];
760
+ continue;
761
+ case 7:
762
+ op = _.ops.pop();
763
+ _.trys.pop();
764
+ continue;
765
+ default:
766
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
767
+ _ = 0;
768
+ continue;
769
+ }
770
+ if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
771
+ _.label = op[1];
772
+ break;
773
+ }
774
+ if (op[0] === 6 && _.label < t[1]) {
775
+ _.label = t[1];
776
+ t = op;
777
+ break;
778
+ }
779
+ if (t && _.label < t[2]) {
780
+ _.label = t[2];
781
+ _.ops.push(op);
782
+ break;
783
+ }
784
+ if (t[2]) _.ops.pop();
785
+ _.trys.pop();
786
+ continue;
787
+ }
788
+ op = body.call(thisArg, _);
789
+ } catch (e) {
790
+ op = [
791
+ 6,
792
+ e
793
+ ];
794
+ y = 0;
795
+ } finally{
796
+ f = t = 0;
797
+ }
798
+ if (op[0] & 5) throw op[1];
799
+ return {
800
+ value: op[0] ? op[1] : void 0,
801
+ done: true
802
+ };
803
+ }
804
+ }
805
+ // MARK: Constants
806
+ /**
807
+ * Reserved tool name for the built-in `model-get` static tool.
808
+ */ var MODEL_GET_TOOL_NAME = 'model-get';
809
+ /**
810
+ * Synthetic call type used in the tool's dispatch identity. Aligns with the dbx-cli `get`
811
+ * command and the `/api/model/:modelType/get` HTTP endpoint that backs it.
812
+ */ var MODEL_GET_DISPATCH_CALL = 'get';
813
+ /**
814
+ * Synthetic model type used in the tool's dispatch identity. The tool itself isn't bound to a
815
+ * specific model type (the `modelType` is part of its input), so we use the literal "model" as
816
+ * the identity. Apps avoiding collision should not register a real model literally named
817
+ * "model".
818
+ */ var MODEL_GET_DISPATCH_MODEL_TYPE = 'model';
819
+ /**
820
+ * Maximum number of keys per backend multi-read request. Matches
821
+ * `MAX_MODEL_ACCESS_MULTI_READ_KEYS` exported from `@dereekb/firebase-server`; mirrored as a
822
+ * local constant so the bundler doesn't have to follow the import chain just for one number.
823
+ */ var MCP_MODEL_GET_BATCH_SIZE = 50;
824
+ // MARK: Factory
825
+ /**
826
+ * Builds the built-in `model-get` MCP tool definition.
827
+ *
828
+ * Mirrors dbx-cli's `get` / `get-many` behavior:
829
+ * - Accepts an array of keys; values containing `/` are treated as full keys and passed verbatim
830
+ * while bare ids are promoted to `${collectionName}/${id}` for root models.
831
+ * - Nested (subcollection) models reject bare ids since a parent path is required.
832
+ * - Auto-chunks at {@link MCP_MODEL_GET_BATCH_SIZE} keys per backend call, mirroring
833
+ * `getMultipleModelsOverHttpChunked` on the CLI side.
834
+ *
835
+ * The handler returns the same `{ results, errors }` shape produced by
836
+ * `ModelApiGetService.readDocuments`, exposed via both the text content block and
837
+ * `structuredContent` so MCP clients can consume either form.
838
+ *
839
+ * @param deps - Read-documents and identity-resolver callbacks (typically wired to
840
+ * `ModelApiGetService`).
841
+ * @returns A statically-registered {@link McpToolDefinition} ready to be appended to the MCP
842
+ * server factory's tool registry.
843
+ */ function createModelGetTool(deps) {
844
+ var handler = function handler(args, ctx) {
845
+ return modelGetToolHandler(args, ctx, deps);
846
+ };
847
+ var name = MODEL_GET_TOOL_NAME;
848
+ var description = 'Fetch one or more Firestore model documents by key or bare id. Values containing `/` are treated as full keys; bare ids are auto-promoted to `<collectionName>/<id>` for root models. Subcollection models require full keys.';
849
+ return {
850
+ name: name,
851
+ description: description,
852
+ inputSchema: MODEL_GET_INPUT_SCHEMA,
853
+ outputSchema: MODEL_GET_OUTPUT_SCHEMA,
854
+ dispatch: {
855
+ call: MODEL_GET_DISPATCH_CALL,
856
+ modelType: MODEL_GET_DISPATCH_MODEL_TYPE
857
+ },
858
+ staticHandler: handler,
859
+ filterMetadata: {
860
+ visibilityKind: 'declarative',
861
+ rule: {
862
+ requireAuthenticated: true
863
+ },
864
+ effectiveReadOnly: true
865
+ },
866
+ staticWireEntry: buildStaticWireEntry({
867
+ name: name,
868
+ description: description,
869
+ inputSchema: MODEL_GET_INPUT_SCHEMA,
870
+ outputSchema: MODEL_GET_OUTPUT_SCHEMA
871
+ })
872
+ };
873
+ }
874
+ // MARK: Handler
875
+ function modelGetToolHandler(args, ctx, deps) {
876
+ return _async_to_generator$3(function() {
877
+ var result, input, identity, resolvedKeys, merged, error;
878
+ return _ts_generator$3(this, function(_state) {
879
+ switch(_state.label){
880
+ case 0:
881
+ _state.trys.push([
882
+ 0,
883
+ 2,
884
+ ,
885
+ 3
886
+ ]);
887
+ input = parseModelGetInput(args);
888
+ identity = deps.resolveIdentity(input.modelType, ctx.auth);
889
+ if (identity == null) {
890
+ throw new Error("Unknown modelType: ".concat(input.modelType));
891
+ }
892
+ resolvedKeys = resolveKeys(input.keys, identity);
893
+ return [
894
+ 4,
895
+ readInChunks({
896
+ modelType: input.modelType,
897
+ keys: resolvedKeys,
898
+ auth: ctx.auth,
899
+ readDocuments: deps.readDocuments
900
+ })
901
+ ];
902
+ case 1:
903
+ merged = _state.sent();
904
+ result = {
905
+ content: [
906
+ {
907
+ type: 'text',
908
+ text: JSON.stringify(merged)
909
+ }
910
+ ],
911
+ structuredContent: merged
912
+ };
913
+ return [
914
+ 3,
915
+ 3
916
+ ];
917
+ case 2:
918
+ error = _state.sent();
919
+ result = formatMcpToolErrorResponse(error);
920
+ return [
921
+ 3,
922
+ 3
923
+ ];
924
+ case 3:
925
+ return [
926
+ 2,
927
+ result
928
+ ];
929
+ }
930
+ });
931
+ })();
932
+ }
933
+ function parseModelGetInput(args) {
934
+ var modelType = args.modelType;
935
+ var keys = args.keys;
936
+ if (typeof modelType !== 'string' || modelType.length === 0) {
937
+ throw new Error('model-get: "modelType" is required and must be a non-empty string.');
938
+ }
939
+ if (!Array.isArray(keys) || keys.length === 0) {
940
+ throw new Error('model-get: "keys" is required and must be a non-empty array.');
941
+ }
942
+ var normalizedKeys = keys.map(function(value, index) {
943
+ if (typeof value !== 'string' || value.length === 0) {
944
+ throw new Error("model-get: keys[".concat(index, "] must be a non-empty string."));
945
+ }
946
+ return value;
947
+ });
948
+ return {
949
+ modelType: modelType,
950
+ keys: normalizedKeys
951
+ };
952
+ }
953
+ function resolveKeys(keys, identity) {
954
+ var isRoot = identity.type === 'root';
955
+ var resolved = [];
956
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
957
+ try {
958
+ for(var _iterator = keys[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
959
+ var value = _step.value;
960
+ if (value.includes('/')) {
961
+ resolved.push(value);
962
+ } else if (isRoot) {
963
+ resolved.push("".concat(identity.collectionName, "/").concat(value));
964
+ } else {
965
+ throw new Error('model-get: modelType "'.concat(identity.modelType, '" is a subcollection; bare ids are not allowed. Provide full keys (e.g. "parentPrefix/parentId/').concat(identity.collectionName, "/").concat(value, '").'));
966
+ }
967
+ }
968
+ } catch (err) {
969
+ _didIteratorError = true;
970
+ _iteratorError = err;
971
+ } finally{
972
+ try {
973
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
974
+ _iterator.return();
975
+ }
976
+ } finally{
977
+ if (_didIteratorError) {
978
+ throw _iteratorError;
979
+ }
980
+ }
981
+ }
982
+ return resolved;
983
+ }
984
+ function readInChunks(input) {
985
+ return _async_to_generator$3(function() {
986
+ var modelType, keys, auth, readDocuments, merged, offset, _merged_results, _merged_errors, batch, partial;
987
+ return _ts_generator$3(this, function(_state) {
988
+ switch(_state.label){
989
+ case 0:
990
+ modelType = input.modelType, keys = input.keys, auth = input.auth, readDocuments = input.readDocuments;
991
+ merged = {
992
+ results: [],
993
+ errors: []
994
+ };
995
+ offset = 0;
996
+ _state.label = 1;
997
+ case 1:
998
+ if (!(offset < keys.length)) return [
999
+ 3,
1000
+ 4
1001
+ ];
1002
+ batch = keys.slice(offset, offset + MCP_MODEL_GET_BATCH_SIZE);
1003
+ return [
1004
+ 4,
1005
+ readDocuments(modelType, batch, auth)
1006
+ ];
1007
+ case 2:
1008
+ 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));
1011
+ _state.label = 3;
1012
+ case 3:
1013
+ offset += MCP_MODEL_GET_BATCH_SIZE;
1014
+ return [
1015
+ 3,
1016
+ 1
1017
+ ];
1018
+ case 4:
1019
+ return [
1020
+ 2,
1021
+ merged
1022
+ ];
1023
+ }
1024
+ });
1025
+ })();
1026
+ }
1027
+ // MARK: Schemas
1028
+ var MODEL_GET_INPUT_SCHEMA = {
1029
+ type: 'object',
1030
+ required: [
1031
+ 'modelType',
1032
+ 'keys'
1033
+ ],
1034
+ properties: {
1035
+ modelType: {
1036
+ type: 'string',
1037
+ minLength: 1,
1038
+ description: 'Firestore model type to fetch (e.g. "guestbook", "profile").'
1039
+ },
1040
+ keys: {
1041
+ type: 'array',
1042
+ minItems: 1,
1043
+ description: 'Full keys ("prefix/id") or bare ids (root models only).',
1044
+ items: {
1045
+ type: 'string',
1046
+ minLength: 1
1047
+ }
1048
+ }
1049
+ },
1050
+ additionalProperties: false
1051
+ };
1052
+ var MODEL_GET_OUTPUT_SCHEMA = {
1053
+ type: 'object',
1054
+ required: [
1055
+ 'results',
1056
+ 'errors'
1057
+ ],
1058
+ properties: {
1059
+ results: {
1060
+ type: 'array',
1061
+ description: 'Per-key successful reads.',
1062
+ items: {
1063
+ type: 'object',
1064
+ required: [
1065
+ 'key',
1066
+ 'data'
1067
+ ],
1068
+ properties: {
1069
+ key: {
1070
+ type: 'string'
1071
+ },
1072
+ data: {}
1073
+ }
1074
+ }
1075
+ },
1076
+ errors: {
1077
+ type: 'array',
1078
+ description: 'Per-key failures (not-found, forbidden, etc.).',
1079
+ items: {
1080
+ type: 'object',
1081
+ required: [
1082
+ 'key',
1083
+ 'message'
1084
+ ],
1085
+ properties: {
1086
+ key: {
1087
+ type: 'string'
1088
+ },
1089
+ message: {
1090
+ type: 'string'
1091
+ },
1092
+ code: {
1093
+ type: 'string'
1094
+ }
1095
+ }
1096
+ }
1097
+ }
1098
+ }
1099
+ };
1100
+
1101
+ function _define_property$5(obj, key, value) {
1102
+ if (key in obj) {
1103
+ Object.defineProperty(obj, key, {
1104
+ value: value,
1105
+ enumerable: true,
1106
+ configurable: true,
1107
+ writable: true
1108
+ });
1109
+ } else {
1110
+ obj[key] = value;
1111
+ }
1112
+ return obj;
1113
+ }
1114
+ function _object_spread$2(target) {
1115
+ for(var i = 1; i < arguments.length; i++){
1116
+ var source = arguments[i] != null ? arguments[i] : {};
1117
+ var ownKeys = Object.keys(source);
1118
+ if (typeof Object.getOwnPropertySymbols === "function") {
1119
+ ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
1120
+ return Object.getOwnPropertyDescriptor(source, sym).enumerable;
1121
+ }));
1122
+ }
1123
+ ownKeys.forEach(function(key) {
1124
+ _define_property$5(target, key, source[key]);
1125
+ });
1126
+ }
1127
+ return target;
1128
+ }
1129
+ // MARK: Constants
1130
+ /**
1131
+ * Reserved tool name for the built-in `model-info` static tool.
1132
+ */ var MODEL_INFO_TOOL_NAME = 'model-info';
1133
+ /**
1134
+ * Synthetic call type used in the tool's dispatch identity. Aligns with the dbx-cli `model-info`
1135
+ * command.
1136
+ */ var MODEL_INFO_DISPATCH_CALL = 'info';
1137
+ /**
1138
+ * Synthetic model type used in the tool's dispatch identity. Mirrors {@link MODEL_GET_DISPATCH_MODEL_TYPE};
1139
+ * apps avoiding collisions should not register a real model literally named "model".
1140
+ */ var MODEL_INFO_DISPATCH_MODEL_TYPE = 'model';
1141
+ // MARK: Factory
1142
+ /**
1143
+ * Builds the built-in `model-info` MCP tool definition.
1144
+ *
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.
1148
+ *
1149
+ * Output is delivered as both stringified JSON in `content[0].text` and `structuredContent`
1150
+ * so MCP clients can consume either form.
1151
+ *
1152
+ * @param deps - The frozen model manifest loaded at boot from the MCP manifest JSON.
1153
+ * @returns A statically-registered {@link McpToolDefinition} ready to be appended to the MCP
1154
+ * server factory's tool registry.
1155
+ */ function createModelInfoTool(deps) {
1156
+ var handler = function handler(args, ctx) {
1157
+ return Promise.resolve(modelInfoToolHandler(args, ctx, deps));
1158
+ };
1159
+ 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.");
1161
+ return {
1162
+ name: name,
1163
+ description: description,
1164
+ inputSchema: MODEL_INFO_INPUT_SCHEMA,
1165
+ outputSchema: MODEL_INFO_OUTPUT_SCHEMA,
1166
+ dispatch: {
1167
+ call: MODEL_INFO_DISPATCH_CALL,
1168
+ modelType: MODEL_INFO_DISPATCH_MODEL_TYPE
1169
+ },
1170
+ staticHandler: handler,
1171
+ filterMetadata: {
1172
+ visibilityKind: 'declarative',
1173
+ rule: {
1174
+ requireAuthenticated: true
1175
+ },
1176
+ effectiveReadOnly: true
1177
+ },
1178
+ staticWireEntry: buildStaticWireEntry({
1179
+ name: name,
1180
+ description: description,
1181
+ inputSchema: MODEL_INFO_INPUT_SCHEMA,
1182
+ outputSchema: MODEL_INFO_OUTPUT_SCHEMA
1183
+ })
1184
+ };
1185
+ }
1186
+ // MARK: Handler
1187
+ function modelInfoToolHandler(args, _ctx, deps) {
1188
+ var result;
1189
+ try {
1190
+ var input = parseModelInfoInput(args);
1191
+ var output = input.model == null ? buildListOutput(deps.manifest) : buildSingleOutput(input.model, deps.manifest);
1192
+ result = {
1193
+ content: [
1194
+ {
1195
+ type: 'text',
1196
+ text: JSON.stringify(output)
1197
+ }
1198
+ ],
1199
+ structuredContent: output
1200
+ };
1201
+ } catch (error) {
1202
+ result = formatMcpToolErrorResponse(error);
1203
+ }
1204
+ return result;
1205
+ }
1206
+ function parseModelInfoInput(args) {
1207
+ var raw = args['model'];
1208
+ var model;
1209
+ if (raw == null) {
1210
+ model = undefined;
1211
+ } 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.');
1215
+ }
1216
+ model = trimmed;
1217
+ } else {
1218
+ throw new TypeError('model-info: "model" must be a string when provided.');
1219
+ }
1220
+ return {
1221
+ model: model
1222
+ };
1223
+ }
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;
1245
+ });
1246
+ return {
1247
+ mode: 'list',
1248
+ models: models
1249
+ };
1250
+ }
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.'));
1255
+ }
1256
+ return {
1257
+ mode: 'single',
1258
+ model: entry
1259
+ };
1260
+ }
1261
+ /**
1262
+ * Resolves a manifest entry by `modelType`, `identityConst`, or `collectionPrefix`.
1263
+ *
1264
+ * @param query - Identifier to look up.
1265
+ * @param manifest - Model manifest to search.
1266
+ * @returns The matching entry or `undefined`.
1267
+ *
1268
+ * @__NO_SIDE_EFFECTS__
1269
+ */ function findModelEntry(query, manifest) {
1270
+ var result;
1271
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
1272
+ try {
1273
+ for(var _iterator = manifest[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
1274
+ var entry = _step.value;
1275
+ if (entry.modelType === query || entry.identityConst === query || entry.collectionPrefix === query) {
1276
+ result = entry;
1277
+ break;
1278
+ }
1279
+ }
1280
+ } catch (err) {
1281
+ _didIteratorError = true;
1282
+ _iteratorError = err;
1283
+ } finally{
1284
+ try {
1285
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
1286
+ _iterator.return();
1287
+ }
1288
+ } finally{
1289
+ if (_didIteratorError) {
1290
+ throw _iteratorError;
1291
+ }
1292
+ }
1293
+ }
1294
+ return result;
1295
+ }
1296
+ // MARK: Schemas
1297
+ var MODEL_INFO_INPUT_SCHEMA = {
1298
+ type: 'object',
1299
+ properties: {
1300
+ model: {
1301
+ type: 'string',
1302
+ minLength: 1,
1303
+ description: 'Model to inspect (modelType, identityConst, or collectionPrefix). Omit to list every model.'
1304
+ }
1305
+ },
1306
+ additionalProperties: false
1307
+ };
1308
+ // 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.
1311
+ var MODEL_INFO_OUTPUT_SCHEMA = {
1312
+ type: 'object',
1313
+ required: [
1314
+ 'mode'
1315
+ ],
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.',
1317
+ properties: {
1318
+ mode: {
1319
+ type: 'string',
1320
+ enum: [
1321
+ 'list',
1322
+ 'single'
1323
+ ]
1324
+ },
1325
+ models: {
1326
+ type: 'array',
1327
+ description: 'Present when `mode` is `"list"`. One summary entry per registered model.',
1328
+ items: {
1329
+ type: 'object',
1330
+ required: [
1331
+ 'modelType',
1332
+ 'modelName',
1333
+ 'identityConst',
1334
+ 'collectionPrefix',
1335
+ 'sourcePackage',
1336
+ 'fieldCount'
1337
+ ],
1338
+ properties: {
1339
+ modelType: {
1340
+ type: 'string'
1341
+ },
1342
+ modelName: {
1343
+ type: 'string'
1344
+ },
1345
+ modelGroup: {
1346
+ type: 'string'
1347
+ },
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: {
1361
+ 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
+ }
1378
+ }
1379
+ }
1380
+ },
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
+ }
1449
+ }
1450
+ }
1451
+ }
1452
+ }
1453
+ },
1454
+ oneOf: [
1455
+ {
1456
+ required: [
1457
+ 'models'
1458
+ ],
1459
+ properties: {
1460
+ mode: {
1461
+ const: 'list'
1462
+ }
1463
+ }
1464
+ },
1465
+ {
1466
+ required: [
1467
+ 'model'
1468
+ ],
1469
+ properties: {
1470
+ mode: {
1471
+ const: 'single'
1472
+ }
1473
+ }
1474
+ }
1475
+ ]
1476
+ };
1477
+
1478
+ function _define_property$4(obj, key, value) {
1479
+ if (key in obj) {
1480
+ Object.defineProperty(obj, key, {
1481
+ value: value,
1482
+ enumerable: true,
1483
+ configurable: true,
1484
+ writable: true
1485
+ });
1486
+ } else {
1487
+ obj[key] = value;
1488
+ }
1489
+ return obj;
1490
+ }
1491
+ function _object_spread$1(target) {
1492
+ for(var i = 1; i < arguments.length; i++){
1493
+ var source = arguments[i] != null ? arguments[i] : {};
1494
+ var ownKeys = Object.keys(source);
1495
+ if (typeof Object.getOwnPropertySymbols === "function") {
1496
+ ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
1497
+ return Object.getOwnPropertyDescriptor(source, sym).enumerable;
1498
+ }));
1499
+ }
1500
+ ownKeys.forEach(function(key) {
1501
+ _define_property$4(target, key, source[key]);
1502
+ });
1503
+ }
1504
+ return target;
1505
+ }
1506
+ // MARK: Constants
1507
+ /**
1508
+ * Reserved tool name for the built-in `model-decode` static tool.
1509
+ */ var MODEL_DECODE_TOOL_NAME = 'model-decode';
1510
+ /**
1511
+ * Synthetic call type used in the tool's dispatch identity. Aligns with the dbx-cli `model-decode`
1512
+ * command.
1513
+ */ var MODEL_DECODE_DISPATCH_CALL = 'decode';
1514
+ /**
1515
+ * Synthetic model type used in the tool's dispatch identity. Mirrors the other built-in static
1516
+ * tools (`model-get`, `model-info`); apps avoiding collisions should not register a real model
1517
+ * literally named "model".
1518
+ */ var MODEL_DECODE_DISPATCH_MODEL_TYPE = 'model';
1519
+ // MARK: Factory
1520
+ /**
1521
+ * Builds the built-in `model-decode` MCP tool definition.
1522
+ *
1523
+ * Mirrors dbx-cli's `model-decode <key>` command:
1524
+ * - Splits the supplied Firestore key on `/`, walks `[prefix, id]` pairs, and resolves each prefix
1525
+ * against the manifest.
1526
+ * - Supports subcollection paths (`parentPrefix/parentId/childPrefix/childId`).
1527
+ *
1528
+ * Output is delivered as both stringified JSON in `content[0].text` and `structuredContent` so
1529
+ * MCP clients can consume either form.
1530
+ *
1531
+ * @param deps - The frozen model manifest loaded at boot from the MCP manifest JSON.
1532
+ * @returns A statically-registered {@link McpToolDefinition} ready to be appended to the MCP
1533
+ * server factory's tool registry.
1534
+ */ function createModelDecodeTool(deps) {
1535
+ var handler = function handler(args, ctx) {
1536
+ return Promise.resolve(modelDecodeToolHandler(args, ctx, deps));
1537
+ };
1538
+ var name = MODEL_DECODE_TOOL_NAME;
1539
+ var description = 'Decode a Firestore model key ("prefix/id", or subcollection path "parentPrefix/parentId/childPrefix/childId") into { leaf, ancestors, unresolvedPrefixes } using the registered manifest ('.concat(deps.manifest.length, " model").concat(deps.manifest.length === 1 ? '' : 's', ").");
1540
+ return {
1541
+ name: name,
1542
+ description: description,
1543
+ inputSchema: MODEL_DECODE_INPUT_SCHEMA,
1544
+ outputSchema: MODEL_DECODE_OUTPUT_SCHEMA,
1545
+ dispatch: {
1546
+ call: MODEL_DECODE_DISPATCH_CALL,
1547
+ modelType: MODEL_DECODE_DISPATCH_MODEL_TYPE
1548
+ },
1549
+ staticHandler: handler,
1550
+ filterMetadata: {
1551
+ visibilityKind: 'declarative',
1552
+ rule: {
1553
+ requireAuthenticated: true
1554
+ },
1555
+ effectiveReadOnly: true
1556
+ },
1557
+ staticWireEntry: buildStaticWireEntry({
1558
+ name: name,
1559
+ description: description,
1560
+ inputSchema: MODEL_DECODE_INPUT_SCHEMA,
1561
+ outputSchema: MODEL_DECODE_OUTPUT_SCHEMA
1562
+ })
1563
+ };
1564
+ }
1565
+ // MARK: Handler
1566
+ function modelDecodeToolHandler(args, _ctx, deps) {
1567
+ var result;
1568
+ try {
1569
+ var input = parseModelDecodeInput(args);
1570
+ var output = decodeFirestoreModelKey(input.key, deps.manifest);
1571
+ result = {
1572
+ content: [
1573
+ {
1574
+ type: 'text',
1575
+ text: JSON.stringify(output)
1576
+ }
1577
+ ],
1578
+ structuredContent: output
1579
+ };
1580
+ } catch (error) {
1581
+ result = formatMcpToolErrorResponse(error);
1582
+ }
1583
+ return result;
1584
+ }
1585
+ function parseModelDecodeInput(args) {
1586
+ var raw = args['key'];
1587
+ if (typeof raw !== 'string' || raw.length === 0) {
1588
+ throw new Error('model-decode: "key" is required and must be a non-empty string.');
1589
+ }
1590
+ return {
1591
+ key: raw
1592
+ };
1593
+ }
1594
+ /**
1595
+ * Splits `rawKey` on `/`, resolves each `[prefix, id]` pair against the manifest, and
1596
+ * returns the leaf segment + ancestor chain.
1597
+ *
1598
+ * Mirrors the dbx-cli `decodeFirestoreModelKey` helper structurally; both implementations
1599
+ * must stay in lockstep on segment count and resolution order.
1600
+ *
1601
+ * @param rawKey - The Firestore key string.
1602
+ * @param manifest - The model manifest.
1603
+ * @returns The decoded key with leaf, ancestors, and any unresolved prefixes.
1604
+ * @throws {Error} When `rawKey` is empty or does not parse into an even number of `prefix/id` segments.
1605
+ *
1606
+ * @__NO_SIDE_EFFECTS__
1607
+ */ function decodeFirestoreModelKey(rawKey, manifest) {
1608
+ var trimmed = rawKey.trim();
1609
+ if (trimmed.length === 0) {
1610
+ throw new Error('model-decode: key is empty. Provide a Firestore key like `sf/abc123`.');
1611
+ }
1612
+ var segments = trimmed.split('/').filter(function(s) {
1613
+ return s.length > 0;
1614
+ });
1615
+ if (segments.length < 2 || segments.length % 2 !== 0) {
1616
+ throw new Error('model-decode: invalid Firestore key "'.concat(trimmed, '". Expected an even number of segments (`prefix/id` pairs). Got ').concat(segments.length, " segment(s). Use the format `prefix/id` (or `parentPrefix/parentId/childPrefix/childId` for subcollections)."));
1617
+ }
1618
+ var decoded = [];
1619
+ var unresolved = [];
1620
+ for(var i = 0; i < segments.length; i += 2){
1621
+ var prefix = segments[i];
1622
+ var id = segments[i + 1];
1623
+ var entry = findModelEntry(prefix, manifest);
1624
+ if (entry == null) {
1625
+ unresolved.push(prefix);
1626
+ }
1627
+ decoded.push(toSegment(prefix, id, entry));
1628
+ }
1629
+ var leaf = decoded.at(-1);
1630
+ var ancestors = decoded.slice(0, -1);
1631
+ return {
1632
+ key: trimmed,
1633
+ leaf: leaf,
1634
+ ancestors: ancestors,
1635
+ unresolvedPrefixes: unresolved
1636
+ };
1637
+ }
1638
+ function toSegment(prefix, id, entry) {
1639
+ var segment = entry ? _object_spread$1({
1640
+ prefix: prefix,
1641
+ id: id,
1642
+ modelType: entry.modelType,
1643
+ modelName: entry.modelName,
1644
+ identityConst: entry.identityConst,
1645
+ sourcePackage: entry.sourcePackage,
1646
+ sourceFile: entry.sourceFile
1647
+ }, entry.modelGroup == null ? {} : {
1648
+ modelGroup: entry.modelGroup
1649
+ }, entry.parentIdentityConst == null ? {} : {
1650
+ parentIdentityConst: entry.parentIdentityConst
1651
+ }) : {
1652
+ prefix: prefix,
1653
+ id: id
1654
+ };
1655
+ return segment;
1656
+ }
1657
+ // MARK: Schemas
1658
+ var MODEL_DECODE_INPUT_SCHEMA = {
1659
+ type: 'object',
1660
+ required: [
1661
+ 'key'
1662
+ ],
1663
+ properties: {
1664
+ key: {
1665
+ type: 'string',
1666
+ minLength: 1,
1667
+ description: 'Firestore model key — prefix/id, or `parentPrefix/parentId/childPrefix/childId` for subcollections.'
1668
+ }
1669
+ },
1670
+ additionalProperties: false
1671
+ };
1672
+ var SEGMENT_SCHEMA = {
1673
+ type: 'object',
1674
+ required: [
1675
+ 'prefix',
1676
+ 'id'
1677
+ ],
1678
+ properties: {
1679
+ prefix: {
1680
+ type: 'string'
1681
+ },
1682
+ id: {
1683
+ type: 'string'
1684
+ },
1685
+ modelType: {
1686
+ type: 'string'
1687
+ },
1688
+ modelName: {
1689
+ type: 'string'
1690
+ },
1691
+ modelGroup: {
1692
+ type: 'string'
1693
+ },
1694
+ identityConst: {
1695
+ type: 'string'
1696
+ },
1697
+ parentIdentityConst: {
1698
+ type: 'string'
1699
+ },
1700
+ sourcePackage: {
1701
+ type: 'string'
1702
+ },
1703
+ sourceFile: {
1704
+ type: 'string'
1705
+ }
1706
+ }
1707
+ };
1708
+ var MODEL_DECODE_OUTPUT_SCHEMA = {
1709
+ type: 'object',
1710
+ required: [
1711
+ 'key',
1712
+ 'leaf',
1713
+ 'ancestors',
1714
+ 'unresolvedPrefixes'
1715
+ ],
1716
+ properties: {
1717
+ key: {
1718
+ type: 'string',
1719
+ description: 'The trimmed input key.'
1720
+ },
1721
+ leaf: SEGMENT_SCHEMA,
1722
+ ancestors: {
1723
+ type: 'array',
1724
+ description: 'Parent segments, root-first.',
1725
+ items: SEGMENT_SCHEMA
1726
+ },
1727
+ unresolvedPrefixes: {
1728
+ type: 'array',
1729
+ description: 'Prefixes that did not match any model in the manifest.',
1730
+ items: {
1731
+ type: 'string'
1732
+ }
1733
+ }
1734
+ }
1735
+ };
1736
+
1737
+ function _array_like_to_array$2(arr, len) {
1738
+ if (len == null || len > arr.length) len = arr.length;
1739
+ for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
1740
+ return arr2;
1741
+ }
1742
+ function _array_with_holes$1(arr) {
1743
+ if (Array.isArray(arr)) return arr;
1744
+ }
1745
+ function _array_without_holes$2(arr) {
1746
+ if (Array.isArray(arr)) return _array_like_to_array$2(arr);
1747
+ }
1748
+ function _define_property$3(obj, key, value) {
1749
+ if (key in obj) {
1750
+ Object.defineProperty(obj, key, {
1751
+ value: value,
1752
+ enumerable: true,
1753
+ configurable: true,
1754
+ writable: true
1755
+ });
1756
+ } else {
1757
+ obj[key] = value;
1758
+ }
1759
+ return obj;
1760
+ }
1761
+ function _iterable_to_array$2(iter) {
1762
+ if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
1763
+ }
1764
+ function _iterable_to_array_limit$1(arr, i) {
1765
+ var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
1766
+ if (_i == null) return;
1767
+ var _arr = [];
1768
+ var _n = true;
1769
+ var _d = false;
1770
+ var _s, _e;
1771
+ try {
1772
+ for(_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true){
1773
+ _arr.push(_s.value);
1774
+ if (i && _arr.length === i) break;
1775
+ }
1776
+ } catch (err) {
1777
+ _d = true;
1778
+ _e = err;
1779
+ } finally{
1780
+ try {
1781
+ if (!_n && _i["return"] != null) _i["return"]();
1782
+ } finally{
1783
+ if (_d) throw _e;
1784
+ }
1785
+ }
1786
+ return _arr;
1787
+ }
1788
+ function _non_iterable_rest$1() {
1789
+ 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
+ }
1791
+ function _non_iterable_spread$2() {
1792
+ 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
+ }
1794
+ function _object_spread(target) {
1795
+ for(var i = 1; i < arguments.length; i++){
1796
+ var source = arguments[i] != null ? arguments[i] : {};
1797
+ var ownKeys = Object.keys(source);
1798
+ if (typeof Object.getOwnPropertySymbols === "function") {
1799
+ ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
1800
+ return Object.getOwnPropertyDescriptor(source, sym).enumerable;
1801
+ }));
1802
+ }
1803
+ ownKeys.forEach(function(key) {
1804
+ _define_property$3(target, key, source[key]);
1805
+ });
1806
+ }
1807
+ return target;
1808
+ }
1809
+ 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();
1811
+ }
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();
1814
+ }
1815
+ function _unsupported_iterable_to_array$2(o, minLen) {
1816
+ if (!o) return;
1817
+ if (typeof o === "string") return _array_like_to_array$2(o, minLen);
1818
+ var n = Object.prototype.toString.call(o).slice(8, -1);
1819
+ if (n === "Object" && o.constructor) n = o.constructor.name;
1820
+ 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);
1822
+ }
1823
+ // MARK: Constants
1824
+ /**
1825
+ * Reserved tool name for the built-in `whoami` static tool.
1826
+ */ var WHOAMI_TOOL_NAME = 'whoami';
1827
+ /**
1828
+ * Synthetic call type used in the tool's dispatch identity. Matches the
1829
+ * pattern set by `model-info` — `read` (not `info`) so the visibility
1830
+ * classifier treats the tool as a read.
1831
+ */ var WHOAMI_DISPATCH_CALL = 'read';
1832
+ /**
1833
+ * Synthetic model type used in the tool's dispatch identity.
1834
+ */ var WHOAMI_DISPATCH_MODEL_TYPE = 'auth';
1835
+ // MARK: Factory
1836
+ /**
1837
+ * Builds the built-in `whoami` MCP tool definition. Returns the calling
1838
+ * caller's `uid`, claims object, decoded role set, and rendered descriptions
1839
+ * for every claim key actually present on the live token.
1840
+ *
1841
+ * Unauthenticated callers receive a structured `authenticated: false` result
1842
+ * (no exception) so the tool can be used as a "do you see me?" probe.
1843
+ *
1844
+ * @param deps - The manifest's auth section + optional role reader.
1845
+ * @returns A statically-registered {@link McpToolDefinition} to append to the MCP server factory's tool registry.
1846
+ */ function createWhoamiTool(deps) {
1847
+ var _ref;
1848
+ var _deps_auth_app;
1849
+ var handler = function handler(_args, ctx) {
1850
+ return Promise.resolve(whoamiToolHandler(ctx, deps));
1851
+ };
1852
+ var name = WHOAMI_TOOL_NAME;
1853
+ var appLabel = (_ref = (_deps_auth_app = deps.auth.app) === null || _deps_auth_app === void 0 ? void 0 : _deps_auth_app.app) !== null && _ref !== void 0 ? _ref : 'this server';
1854
+ var description = "Reports the authenticated caller's uid, raw custom claims, and decoded role set for `".concat(appLabel, "`. Returns `authenticated: false` for anonymous callers. Claim descriptions are drawn from the build-time auth manifest; only keys actually present on the live token are detailed.");
1855
+ return {
1856
+ name: name,
1857
+ description: description,
1858
+ inputSchema: WHOAMI_INPUT_SCHEMA,
1859
+ outputSchema: WHOAMI_OUTPUT_SCHEMA,
1860
+ dispatch: {
1861
+ call: WHOAMI_DISPATCH_CALL,
1862
+ modelType: WHOAMI_DISPATCH_MODEL_TYPE
1863
+ },
1864
+ staticHandler: handler,
1865
+ filterMetadata: {
1866
+ visibilityKind: 'declarative',
1867
+ rule: {},
1868
+ effectiveReadOnly: true
1869
+ },
1870
+ staticWireEntry: buildStaticWireEntry({
1871
+ name: name,
1872
+ description: description,
1873
+ inputSchema: WHOAMI_INPUT_SCHEMA,
1874
+ outputSchema: WHOAMI_OUTPUT_SCHEMA
1875
+ })
1876
+ };
1877
+ }
1878
+ // MARK: Handler
1879
+ function whoamiToolHandler(ctx, deps) {
1880
+ var _auth_token;
1881
+ var _deps_auth_app;
1882
+ var auth = ctx.auth;
1883
+ if ((auth === null || auth === void 0 ? void 0 : auth.uid) == null) {
1884
+ var output = {
1885
+ authenticated: false,
1886
+ claims: {},
1887
+ roles: [],
1888
+ claimDetails: [],
1889
+ unknownClaimKeys: []
1890
+ };
1891
+ return buildResult(output, '# whoami\n\nUnauthenticated.');
1892
+ }
1893
+ var token = (_auth_token = auth.token) !== null && _auth_token !== void 0 ? _auth_token : {};
1894
+ var presentKeys = Object.entries(token).filter(function(param) {
1895
+ var _param = _sliced_to_array$1(param, 2), value = _param[1];
1896
+ return value !== undefined;
1897
+ }).map(function(param) {
1898
+ var _param = _sliced_to_array$1(param, 1), key = _param[0];
1899
+ return key;
1900
+ });
1901
+ var roleSet = deps.roleReader == null ? new Set() : deps.roleReader(token);
1902
+ var roles = _to_consumable_array$2(roleSet).sort(function(a, b) {
1903
+ return a.localeCompare(b);
1904
+ });
1905
+ var claimsByKey = new Map();
1906
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
1907
+ try {
1908
+ for(var _iterator = deps.auth.claims[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
1909
+ var claim = _step.value;
1910
+ claimsByKey.set(claim.key, claim);
1911
+ }
1912
+ } catch (err) {
1913
+ _didIteratorError = true;
1914
+ _iteratorError = err;
1915
+ } finally{
1916
+ try {
1917
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
1918
+ _iterator.return();
1919
+ }
1920
+ } finally{
1921
+ if (_didIteratorError) {
1922
+ throw _iteratorError;
1923
+ }
1924
+ }
1925
+ }
1926
+ var claimDetails = [];
1927
+ var unknownClaimKeys = [];
1928
+ var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
1929
+ try {
1930
+ for(var _iterator1 = presentKeys[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
1931
+ var key = _step1.value;
1932
+ if (key === 'email' || key === 'email_verified') {
1933
+ continue;
1934
+ }
1935
+ var claim1 = claimsByKey.get(key);
1936
+ if (claim1 == null) {
1937
+ unknownClaimKeys.push(key);
1938
+ } else {
1939
+ claimDetails.push(_object_spread({
1940
+ key: claim1.key,
1941
+ description: claim1.description,
1942
+ grantedRoles: claim1.mapping.roles,
1943
+ inverse: claim1.mapping.inverse,
1944
+ tags: claim1.tags
1945
+ }, claim1.interfaceName == null ? {} : {
1946
+ interfaceName: claim1.interfaceName
1947
+ }));
1948
+ }
1949
+ }
1950
+ } catch (err) {
1951
+ _didIteratorError1 = true;
1952
+ _iteratorError1 = err;
1953
+ } finally{
1954
+ try {
1955
+ if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
1956
+ _iterator1.return();
1957
+ }
1958
+ } finally{
1959
+ if (_didIteratorError1) {
1960
+ throw _iteratorError1;
1961
+ }
1962
+ }
1963
+ }
1964
+ var output1 = _object_spread({
1965
+ authenticated: true,
1966
+ uid: auth.uid,
1967
+ claims: _object_spread({}, token),
1968
+ roles: roles,
1969
+ claimDetails: claimDetails,
1970
+ unknownClaimKeys: unknownClaimKeys
1971
+ }, ((_deps_auth_app = deps.auth.app) === null || _deps_auth_app === void 0 ? void 0 : _deps_auth_app.app) == null ? {} : {
1972
+ app: deps.auth.app.app
1973
+ }, token.email == null ? {} : {
1974
+ email: token.email
1975
+ }, token.email_verified == null ? {} : {
1976
+ emailVerified: token.email_verified
1977
+ });
1978
+ var text = renderText(output1);
1979
+ return buildResult(output1, text);
1980
+ }
1981
+ function buildResult(output, text) {
1982
+ return {
1983
+ content: [
1984
+ {
1985
+ type: 'text',
1986
+ text: text
1987
+ }
1988
+ ],
1989
+ structuredContent: output
1990
+ };
1991
+ }
1992
+ function renderText(output) {
1993
+ var lines = [
1994
+ '# whoami',
1995
+ ''
1996
+ ];
1997
+ appendHeaderLines(lines, output);
1998
+ appendClaimDetailLines(lines, output.claimDetails);
1999
+ appendUnknownClaimLines(lines, output.unknownClaimKeys);
2000
+ return lines.join('\n');
2001
+ }
2002
+ function appendHeaderLines(lines, output) {
2003
+ if (output.uid != null) {
2004
+ lines.push("- **uid:** `".concat(output.uid, "`"));
2005
+ }
2006
+ if (output.app != null) {
2007
+ lines.push("- **app:** `".concat(output.app, "`"));
2008
+ }
2009
+ if (output.email != null) {
2010
+ lines.push("- **email:** `".concat(output.email, "`"));
2011
+ }
2012
+ if (output.roles.length > 0) {
2013
+ var rolesText = output.roles.map(function(role) {
2014
+ return "`".concat(role, "`");
2015
+ }).join(', ');
2016
+ lines.push("- **roles:** ".concat(rolesText));
2017
+ } else {
2018
+ lines.push('- **roles:** _(none)_');
2019
+ }
2020
+ }
2021
+ function appendClaimDetailLines(lines, claimDetails) {
2022
+ if (claimDetails.length === 0) {
2023
+ return;
2024
+ }
2025
+ lines.push('', '## Claims on this token');
2026
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
2027
+ try {
2028
+ for(var _iterator = claimDetails[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
2029
+ var detail = _step.value;
2030
+ var headerInterfacePart = detail.interfaceName == null ? '' : " on `".concat(detail.interfaceName, "`");
2031
+ var grants = detail.grantedRoles.length > 0 ? detail.grantedRoles.map(function(role) {
2032
+ return "`".concat(role, "`");
2033
+ }).join(', ') : '_(no roles)_';
2034
+ var action = detail.inverse ? 'revokes' : 'grants';
2035
+ lines.push("- `".concat(detail.key, "`").concat(headerInterfacePart, " — ").concat(action, " ").concat(grants));
2036
+ if (detail.description.length > 0) {
2037
+ lines.push(" ".concat(detail.description));
2038
+ }
2039
+ }
2040
+ } catch (err) {
2041
+ _didIteratorError = true;
2042
+ _iteratorError = err;
2043
+ } finally{
2044
+ try {
2045
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
2046
+ _iterator.return();
2047
+ }
2048
+ } finally{
2049
+ if (_didIteratorError) {
2050
+ throw _iteratorError;
2051
+ }
2052
+ }
2053
+ }
2054
+ }
2055
+ function appendUnknownClaimLines(lines, unknownClaimKeys) {
2056
+ if (unknownClaimKeys.length === 0) {
2057
+ return;
2058
+ }
2059
+ lines.push('', '## Unknown claim keys');
2060
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
2061
+ try {
2062
+ for(var _iterator = unknownClaimKeys[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
2063
+ var key = _step.value;
2064
+ lines.push("- `".concat(key, "`"));
2065
+ }
2066
+ } catch (err) {
2067
+ _didIteratorError = true;
2068
+ _iteratorError = err;
2069
+ } finally{
2070
+ try {
2071
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
2072
+ _iterator.return();
2073
+ }
2074
+ } finally{
2075
+ if (_didIteratorError) {
2076
+ throw _iteratorError;
2077
+ }
2078
+ }
2079
+ }
2080
+ }
2081
+ // MARK: Schemas
2082
+ var WHOAMI_INPUT_SCHEMA = {
2083
+ type: 'object',
2084
+ properties: {},
2085
+ additionalProperties: false
2086
+ };
2087
+ var WHOAMI_OUTPUT_SCHEMA = {
2088
+ type: 'object',
2089
+ required: [
2090
+ 'authenticated',
2091
+ 'claims',
2092
+ 'roles',
2093
+ 'claimDetails',
2094
+ 'unknownClaimKeys'
2095
+ ],
2096
+ description: 'Caller identity, raw token claims, decoded role set, and per-claim descriptions for every key present on the live token.',
2097
+ properties: {
2098
+ authenticated: {
2099
+ type: 'boolean'
2100
+ },
2101
+ uid: {
2102
+ type: 'string'
2103
+ },
2104
+ email: {
2105
+ type: 'string'
2106
+ },
2107
+ emailVerified: {
2108
+ type: 'boolean'
2109
+ },
2110
+ app: {
2111
+ type: 'string'
2112
+ },
2113
+ claims: {
2114
+ type: 'object',
2115
+ additionalProperties: true
2116
+ },
2117
+ roles: {
2118
+ type: 'array',
2119
+ items: {
2120
+ type: 'string'
2121
+ }
2122
+ },
2123
+ claimDetails: {
2124
+ type: 'array',
2125
+ items: {
2126
+ type: 'object',
2127
+ required: [
2128
+ 'key',
2129
+ 'description',
2130
+ 'grantedRoles',
2131
+ 'inverse',
2132
+ 'tags'
2133
+ ],
2134
+ properties: {
2135
+ key: {
2136
+ type: 'string'
2137
+ },
2138
+ interfaceName: {
2139
+ type: 'string'
2140
+ },
2141
+ description: {
2142
+ type: 'string'
2143
+ },
2144
+ grantedRoles: {
2145
+ type: 'array',
2146
+ items: {
2147
+ type: 'string'
2148
+ }
2149
+ },
2150
+ inverse: {
2151
+ type: 'boolean'
2152
+ },
2153
+ tags: {
2154
+ type: 'array',
2155
+ items: {
2156
+ type: 'string'
2157
+ }
2158
+ }
2159
+ }
2160
+ }
2161
+ },
2162
+ unknownClaimKeys: {
2163
+ type: 'array',
2164
+ items: {
2165
+ type: 'string'
2166
+ }
2167
+ }
2168
+ }
2169
+ };
2170
+
2171
+ function _array_like_to_array$1(arr, len) {
2172
+ if (len == null || len > arr.length) len = arr.length;
2173
+ for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
2174
+ return arr2;
2175
+ }
2176
+ function _array_with_holes(arr) {
2177
+ if (Array.isArray(arr)) return arr;
2178
+ }
2179
+ function _array_without_holes$1(arr) {
2180
+ if (Array.isArray(arr)) return _array_like_to_array$1(arr);
2181
+ }
2182
+ function asyncGeneratorStep$2(gen, resolve, reject, _next, _throw, key, arg) {
2183
+ try {
2184
+ var info = gen[key](arg);
2185
+ var value = info.value;
2186
+ } catch (error) {
2187
+ reject(error);
2188
+ return;
2189
+ }
2190
+ if (info.done) {
2191
+ resolve(value);
2192
+ } else {
2193
+ Promise.resolve(value).then(_next, _throw);
2194
+ }
2195
+ }
2196
+ function _async_to_generator$2(fn) {
2197
+ return function() {
2198
+ var self = this, args = arguments;
2199
+ return new Promise(function(resolve, reject) {
2200
+ var gen = fn.apply(self, args);
2201
+ function _next(value) {
2202
+ asyncGeneratorStep$2(gen, resolve, reject, _next, _throw, "next", value);
2203
+ }
2204
+ function _throw(err) {
2205
+ asyncGeneratorStep$2(gen, resolve, reject, _next, _throw, "throw", err);
2206
+ }
2207
+ _next(undefined);
2208
+ });
2209
+ };
2210
+ }
2211
+ function _class_call_check$2(instance, Constructor) {
2212
+ if (!(instance instanceof Constructor)) {
2213
+ throw new TypeError("Cannot call a class as a function");
2214
+ }
2215
+ }
2216
+ function _defineProperties$2(target, props) {
2217
+ for(var i = 0; i < props.length; i++){
2218
+ var descriptor = props[i];
2219
+ descriptor.enumerable = descriptor.enumerable || false;
2220
+ descriptor.configurable = true;
2221
+ if ("value" in descriptor) descriptor.writable = true;
2222
+ Object.defineProperty(target, descriptor.key, descriptor);
2223
+ }
2224
+ }
2225
+ function _create_class$2(Constructor, protoProps, staticProps) {
2226
+ if (protoProps) _defineProperties$2(Constructor.prototype, protoProps);
2227
+ return Constructor;
2228
+ }
2229
+ function _define_property$2(obj, key, value) {
2230
+ if (key in obj) {
2231
+ Object.defineProperty(obj, key, {
2232
+ value: value,
2233
+ enumerable: true,
2234
+ configurable: true,
2235
+ writable: true
2236
+ });
2237
+ } else {
2238
+ obj[key] = value;
2239
+ }
2240
+ return obj;
2241
+ }
2242
+ function _iterable_to_array$1(iter) {
2243
+ if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
2244
+ }
2245
+ function _iterable_to_array_limit(arr, i) {
2246
+ var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
2247
+ if (_i == null) return;
2248
+ var _arr = [];
2249
+ var _n = true;
2250
+ var _d = false;
2251
+ var _s, _e;
2252
+ try {
2253
+ for(_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true){
2254
+ _arr.push(_s.value);
2255
+ if (i && _arr.length === i) break;
2256
+ }
2257
+ } catch (err) {
2258
+ _d = true;
2259
+ _e = err;
2260
+ } finally{
2261
+ try {
2262
+ if (!_n && _i["return"] != null) _i["return"]();
2263
+ } finally{
2264
+ if (_d) throw _e;
2265
+ }
2266
+ }
2267
+ return _arr;
2268
+ }
2269
+ function _non_iterable_rest() {
2270
+ 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
+ }
2272
+ function _non_iterable_spread$1() {
2273
+ 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
+ }
2275
+ 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();
2277
+ }
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();
2280
+ }
2281
+ function _unsupported_iterable_to_array$1(o, minLen) {
2282
+ if (!o) return;
2283
+ if (typeof o === "string") return _array_like_to_array$1(o, minLen);
2284
+ var n = Object.prototype.toString.call(o).slice(8, -1);
2285
+ if (n === "Object" && o.constructor) n = o.constructor.name;
2286
+ 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);
2288
+ }
2289
+ function _ts_generator$2(thisArg, body) {
2290
+ var f, y, t, _ = {
2291
+ label: 0,
2292
+ sent: function() {
2293
+ if (t[0] & 1) throw t[1];
2294
+ return t[1];
2295
+ },
2296
+ trys: [],
2297
+ ops: []
2298
+ }, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype), d = Object.defineProperty;
2299
+ return d(g, "next", {
2300
+ value: verb(0)
2301
+ }), d(g, "throw", {
2302
+ value: verb(1)
2303
+ }), d(g, "return", {
2304
+ value: verb(2)
2305
+ }), typeof Symbol === "function" && d(g, Symbol.iterator, {
2306
+ value: function() {
2307
+ return this;
2308
+ }
2309
+ }), g;
2310
+ function verb(n) {
2311
+ return function(v) {
2312
+ return step([
2313
+ n,
2314
+ v
2315
+ ]);
2316
+ };
2317
+ }
2318
+ function step(op) {
2319
+ if (f) throw new TypeError("Generator is already executing.");
2320
+ while(g && (g = 0, op[0] && (_ = 0)), _)try {
2321
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
2322
+ if (y = 0, t) op = [
2323
+ op[0] & 2,
2324
+ t.value
2325
+ ];
2326
+ switch(op[0]){
2327
+ case 0:
2328
+ case 1:
2329
+ t = op;
2330
+ break;
2331
+ case 4:
2332
+ _.label++;
2333
+ return {
2334
+ value: op[1],
2335
+ done: false
2336
+ };
2337
+ case 5:
2338
+ _.label++;
2339
+ y = op[1];
2340
+ op = [
2341
+ 0
2342
+ ];
2343
+ continue;
2344
+ case 7:
2345
+ op = _.ops.pop();
2346
+ _.trys.pop();
2347
+ continue;
2348
+ default:
2349
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
2350
+ _ = 0;
2351
+ continue;
2352
+ }
2353
+ if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
2354
+ _.label = op[1];
2355
+ break;
2356
+ }
2357
+ if (op[0] === 6 && _.label < t[1]) {
2358
+ _.label = t[1];
2359
+ t = op;
2360
+ break;
2361
+ }
2362
+ if (t && _.label < t[2]) {
2363
+ _.label = t[2];
2364
+ _.ops.push(op);
2365
+ break;
2366
+ }
2367
+ if (t[2]) _.ops.pop();
2368
+ _.trys.pop();
2369
+ continue;
2370
+ }
2371
+ op = body.call(thisArg, _);
2372
+ } catch (e) {
2373
+ op = [
2374
+ 6,
2375
+ e
2376
+ ];
2377
+ y = 0;
2378
+ } finally{
2379
+ f = t = 0;
2380
+ }
2381
+ if (op[0] & 5) throw op[1];
2382
+ return {
2383
+ value: op[0] ? op[1] : void 0,
2384
+ done: true
2385
+ };
2386
+ }
2387
+ }
2388
+ var McpServerFactoryService_1;
2389
+ /**
2390
+ * Injectable factory that builds {@link McpServer} instances pre-wired to the
2391
+ * call model dispatch chain.
2392
+ *
2393
+ * The factory is invoked per Streamable HTTP request — `@modelcontextprotocol/sdk`
2394
+ * recommends a fresh `McpServer` + transport pair per stateless JSON-RPC request,
2395
+ * which sidesteps session bookkeeping for the common Claude-connector case.
2396
+ */ 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);
2412
+ this.mcpConfig = mcpConfig;
2413
+ this.dispatchService = dispatchService;
2414
+ this.modelApiGetService = modelApiGetService;
2415
+ this.roleReader = roleReader;
2416
+ }
2417
+ _create_class$2(McpServerFactoryService, [
2418
+ {
2419
+ /**
2420
+ * Builds a configured MCP server with tool listing + dispatch handlers wired up.
2421
+ *
2422
+ * @param ctx - The per-request context (auth, raw request) used when forwarding tool calls.
2423
+ * @returns A configured MCP server ready to be `connect()`-ed to a transport.
2424
+ */ key: "createServer",
2425
+ value: function createServer(ctx) {
2426
+ var _this = this;
2427
+ var _this_mcpConfig_serverName, _this_mcpConfig_serverVersion;
2428
+ var baseServerName = (_this_mcpConfig_serverName = this.mcpConfig.serverName) !== null && _this_mcpConfig_serverName !== void 0 ? _this_mcpConfig_serverName : DEFAULT_MCP_SERVER_NAME;
2429
+ var serverName = this.mcpConfig.readOnly === true ? "".concat(baseServerName, " (read-only)") : baseServerName;
2430
+ var server = new mcp_js.McpServer({
2431
+ name: serverName,
2432
+ version: (_this_mcpConfig_serverVersion = this.mcpConfig.serverVersion) !== null && _this_mcpConfig_serverVersion !== void 0 ? _this_mcpConfig_serverVersion : '0.0.0'
2433
+ }, {
2434
+ instructions: 'Model-bound RPC tools generated from the callModel _apiDetails tree.'
2435
+ });
2436
+ server.server.registerCapabilities({
2437
+ tools: {}
2438
+ });
2439
+ var toolGeneration = this._resolveToolDefinitions();
2440
+ var staticTools = this._resolveStaticTools();
2441
+ var scopes = this._resolveScopes(ctx);
2442
+ var authRoles = this._resolveAuthRoles(ctx);
2443
+ var combinedTools = _to_consumable_array$1(toolGeneration.tools).concat(_to_consumable_array$1(staticTools));
2444
+ var visibleTools = this._filterToolsForRequest(combinedTools, {
2445
+ ctx: ctx,
2446
+ scopes: scopes,
2447
+ authRoles: authRoles
2448
+ });
2449
+ var definitionsByName = new Map(visibleTools.map(function(tool) {
2450
+ return [
2451
+ tool.name,
2452
+ tool
2453
+ ];
2454
+ }));
2455
+ server.server.setRequestHandler(types_js.ListToolsRequestSchema, function() {
2456
+ return _async_to_generator$2(function() {
2457
+ var _this;
2458
+ return _ts_generator$2(this, function(_state) {
2459
+ _this = this;
2460
+ return [
2461
+ 2,
2462
+ {
2463
+ tools: visibleTools.map(function(tool) {
2464
+ return _this._buildToolListEntry(tool, ctx, scopes);
2465
+ })
2466
+ }
2467
+ ];
2468
+ });
2469
+ }).call(_this);
2470
+ });
2471
+ server.server.setRequestHandler(types_js.CallToolRequestSchema, function(request) {
2472
+ return _async_to_generator$2(function() {
2473
+ return _ts_generator$2(this, function(_state) {
2474
+ return [
2475
+ 2,
2476
+ this._handleToolCall(request, definitionsByName, ctx)
2477
+ ];
2478
+ });
2479
+ }).call(_this);
2480
+ });
2481
+ return server;
2482
+ }
2483
+ },
2484
+ {
2485
+ /**
2486
+ * Reads cached tool definitions, regenerating + logging skips on first call.
2487
+ *
2488
+ * The underlying call model `_apiDetails` is built at boot and doesn't change at runtime,
2489
+ * so the generation result is safe to cache for the lifetime of the process.
2490
+ *
2491
+ * @returns The cached or freshly-generated tool generation result.
2492
+ */ key: "_resolveToolDefinitions",
2493
+ value: function _resolveToolDefinitions() {
2494
+ var result = this._cachedTools;
2495
+ if (result == null) {
2496
+ var apiDetails = this.dispatchService.getApiDetails();
2497
+ var manifest = this._resolveManifest();
2498
+ if (apiDetails == null) {
2499
+ result = {
2500
+ tools: [],
2501
+ neverVisibleTools: [],
2502
+ skipped: []
2503
+ };
2504
+ } else {
2505
+ result = generateMcpToolDefinitions(apiDetails, undefined, manifest);
2506
+ }
2507
+ this._cachedTools = result;
2508
+ }
2509
+ if (!this._loggedSkips && result.skipped.length > 0) {
2510
+ this._loggedSkips = true;
2511
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
2512
+ try {
2513
+ for(var _iterator = result.skipped[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
2514
+ var skip = _step.value;
2515
+ var errorSuffix = skip.error ? ": ".concat(skip.error.message) : '';
2516
+ this._logger.warn("Skipped MCP tool ".concat(skip.toolName, " (").concat(skip.reason, ")").concat(errorSuffix));
2517
+ }
2518
+ } catch (err) {
2519
+ _didIteratorError = true;
2520
+ _iteratorError = err;
2521
+ } finally{
2522
+ try {
2523
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
2524
+ _iterator.return();
2525
+ }
2526
+ } finally{
2527
+ if (_didIteratorError) {
2528
+ throw _iteratorError;
2529
+ }
2530
+ }
2531
+ }
2532
+ }
2533
+ return result;
2534
+ }
2535
+ },
2536
+ {
2537
+ /**
2538
+ * Builds the list of statically-registered (non-callModel) MCP tools.
2539
+ *
2540
+ * Includes `model-get` whenever {@link ModelApiGetService} is available, plus
2541
+ * `model-info` and `model-decode` whenever the boot-time MCP manifest provided
2542
+ * a non-empty `models` catalog. The list is cached for the lifetime of the
2543
+ * process since static tools share the same boot-time inputs as the
2544
+ * auto-generated ones.
2545
+ *
2546
+ * @returns The cached array of static tool definitions, filtered for collisions with generated tools.
2547
+ */ key: "_resolveStaticTools",
2548
+ value: function _resolveStaticTools() {
2549
+ var result = this._cachedStaticTools;
2550
+ if (result == null) {
2551
+ var _ref;
2552
+ var _this__cachedTools;
2553
+ // Ensure the manifest has been loaded so its `models` array is available for the catalog tools.
2554
+ this._resolveManifest();
2555
+ var staticTools = [];
2556
+ var getService = this.modelApiGetService;
2557
+ if (getService != null) {
2558
+ staticTools.push(createModelGetTool({
2559
+ readDocuments: function readDocuments(modelType, keys, auth) {
2560
+ return getService.readDocuments(modelType, keys, auth);
2561
+ },
2562
+ resolveIdentity: function resolveIdentity(modelType, auth) {
2563
+ return getService.getModelIdentity(modelType, auth);
2564
+ }
2565
+ }));
2566
+ }
2567
+ var modelManifest = this._cachedManifestModels;
2568
+ if (modelManifest != null && modelManifest.length > 0) {
2569
+ staticTools.push(createModelInfoTool({
2570
+ manifest: modelManifest
2571
+ }), createModelDecodeTool({
2572
+ manifest: modelManifest
2573
+ }));
2574
+ }
2575
+ var authManifest = this._cachedManifestAuth;
2576
+ if (authManifest != null) {
2577
+ staticTools.push(createWhoamiTool({
2578
+ auth: authManifest,
2579
+ roleReader: this.roleReader
2580
+ }));
2581
+ }
2582
+ // Guard against the auto-generated tools accidentally claiming a static tool name. The first
2583
+ // dispatch wins via Map.set order, so a collision would silently shadow one side.
2584
+ var generatedNames = new Set((_ref = (_this__cachedTools = this._cachedTools) === null || _this__cachedTools === void 0 ? void 0 : _this__cachedTools.tools.map(function(t) {
2585
+ return t.name;
2586
+ })) !== null && _ref !== void 0 ? _ref : []);
2587
+ var filtered = [];
2588
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
2589
+ try {
2590
+ for(var _iterator = staticTools[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
2591
+ var tool = _step.value;
2592
+ if (generatedNames.has(tool.name)) {
2593
+ this._logger.warn('Static MCP tool "'.concat(tool.name, '" collides with an auto-generated tool of the same name; the auto-generated tool will win.'));
2594
+ } else {
2595
+ filtered.push(tool);
2596
+ }
2597
+ }
2598
+ } catch (err) {
2599
+ _didIteratorError = true;
2600
+ _iteratorError = err;
2601
+ } finally{
2602
+ try {
2603
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
2604
+ _iterator.return();
2605
+ }
2606
+ } finally{
2607
+ if (_didIteratorError) {
2608
+ throw _iteratorError;
2609
+ }
2610
+ }
2611
+ }
2612
+ result = filtered;
2613
+ this._cachedStaticTools = result;
2614
+ }
2615
+ return result;
2616
+ }
2617
+ },
2618
+ {
2619
+ /**
2620
+ * Reads the pre-rendered MCP manifest JSON once, validates its version, and caches the
2621
+ * resulting `key → entry` map plus the optional `models` catalog for the process lifetime.
2622
+ *
2623
+ * Missing file or wrong version fall back to "no manifest" with a single boot warning;
2624
+ * the runtime still produces tools using the auto-generated descriptions and
2625
+ * ArkType-derived schemas.
2626
+ *
2627
+ * @returns The cached tool-entry map, or `undefined` when no manifest was loaded.
2628
+ */ key: "_resolveManifest",
2629
+ value: function _resolveManifest() {
2630
+ if (!this._manifestLoaded) {
2631
+ this._manifestLoaded = true;
2632
+ var path = this.mcpConfig.mcpManifestPath;
2633
+ if (path == null) {
2634
+ this._resetManifestCache();
2635
+ } else if (node_fs.existsSync(path)) {
2636
+ this._parseManifestFile(path);
2637
+ } else {
2638
+ this._logger.warn("MCP manifest path is set but the file is missing: ".concat(path, ". Falling back to runtime defaults."));
2639
+ this._resetManifestCache();
2640
+ }
2641
+ }
2642
+ return this._cachedManifest;
2643
+ }
2644
+ },
2645
+ {
2646
+ key: "_resetManifestCache",
2647
+ value: function _resetManifestCache() {
2648
+ this._cachedManifest = undefined;
2649
+ this._cachedManifestModels = undefined;
2650
+ this._cachedManifestAuth = undefined;
2651
+ }
2652
+ },
2653
+ {
2654
+ key: "_parseManifestFile",
2655
+ value: function _parseManifestFile(path) {
2656
+ try {
2657
+ var raw = node_fs.readFileSync(path, 'utf8');
2658
+ var parsed = JSON.parse(raw);
2659
+ if (parsed.version === MCP_MANIFEST_VERSION) {
2660
+ this._applyParsedManifest(parsed, path);
2661
+ } else {
2662
+ this._logger.warn("MCP manifest version mismatch at ".concat(path, ": got ").concat(String(parsed.version), ", expected ").concat(MCP_MANIFEST_VERSION, ". Falling back to runtime defaults."));
2663
+ this._resetManifestCache();
2664
+ }
2665
+ } catch (error) {
2666
+ this._logger.warn("Failed to read MCP manifest at ".concat(path, ": ").concat(error.message, ". Falling back to runtime defaults."));
2667
+ this._resetManifestCache();
2668
+ }
2669
+ }
2670
+ },
2671
+ {
2672
+ key: "_applyParsedManifest",
2673
+ value: function _applyParsedManifest(parsed, path) {
2674
+ var map = new Map();
2675
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
2676
+ try {
2677
+ for(var _iterator = Object.entries(parsed.tools)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
2678
+ var _step_value = _sliced_to_array(_step.value, 2), key = _step_value[0], entry = _step_value[1];
2679
+ if (entry != null) {
2680
+ map.set(key, entry);
2681
+ }
2682
+ }
2683
+ } catch (err) {
2684
+ _didIteratorError = true;
2685
+ _iteratorError = err;
2686
+ } finally{
2687
+ try {
2688
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
2689
+ _iterator.return();
2690
+ }
2691
+ } finally{
2692
+ if (_didIteratorError) {
2693
+ throw _iteratorError;
2694
+ }
2695
+ }
2696
+ }
2697
+ var models = Array.isArray(parsed.models) && parsed.models.length > 0 ? parsed.models : undefined;
2698
+ var modelSuffix = models == null ? '' : ", ".concat(models.length, " model entries");
2699
+ var auth = parsed.auth != null && Array.isArray(parsed.auth.claims) ? parsed.auth : undefined;
2700
+ var authSuffix = auth == null ? '' : ", ".concat(auth.claims.length, " auth claim entries");
2701
+ this._logger.log("Loaded MCP manifest from ".concat(path, ": ").concat(map.size, " tool entries").concat(modelSuffix).concat(authSuffix, "."));
2702
+ this._cachedManifest = map;
2703
+ this._cachedManifestModels = models;
2704
+ this._cachedManifestAuth = auth;
2705
+ }
2706
+ },
2707
+ {
2708
+ /**
2709
+ * Reads the caller's OIDC scopes from the raw Express request via the auth context.
2710
+ *
2711
+ * Synthesizes the same `{ auth: { token } }` shape that `getOidcScopesFromRequest`
2712
+ * expects post-dispatch, so the upstream helper stays the single source of scope parsing.
2713
+ * Returns `undefined` for non-OIDC callers (no `oidcValidatedToken.scope`) — the filter
2714
+ * loop treats that as "skip scope enforcement", matching `oidcCallModelScopePreAssert`.
2715
+ *
2716
+ * @param ctx - The per-request context carrying the validated auth payload.
2717
+ * @returns The set of granted OIDC scopes, or `undefined` when scope enforcement should be skipped.
2718
+ */ key: "_resolveScopes",
2719
+ value: function _resolveScopes(ctx) {
2720
+ var _ctx_auth;
2721
+ var oidcValidatedToken = (_ctx_auth = ctx.auth) === null || _ctx_auth === void 0 ? void 0 : _ctx_auth.oidcValidatedToken;
2722
+ return oidcValidatedToken == null ? undefined : oidc.getOidcScopesFromRequest({
2723
+ auth: {
2724
+ token: oidcValidatedToken
2725
+ }
2726
+ });
2727
+ }
2728
+ },
2729
+ {
2730
+ /**
2731
+ * Maps the caller's Firebase custom claims through the optional role reader.
2732
+ * Emits one boot-time warning when a declarative `requiredRoles` rule will be checked
2733
+ * but no reader is wired — that path will fail closed.
2734
+ *
2735
+ * @param ctx - The per-request context carrying the authenticated user's token.
2736
+ * @returns The resolved auth role set, or `undefined` when no auth or reader is available.
2737
+ */ key: "_resolveAuthRoles",
2738
+ value: function _resolveAuthRoles(ctx) {
2739
+ var _ctx_auth;
2740
+ var result;
2741
+ if (((_ctx_auth = ctx.auth) === null || _ctx_auth === void 0 ? void 0 : _ctx_auth.token) != null && this.roleReader != null) {
2742
+ result = this.roleReader(ctx.auth.token);
2743
+ }
2744
+ return result;
2745
+ }
2746
+ },
2747
+ {
2748
+ key: "_filterToolsForRequest",
2749
+ value: function _filterToolsForRequest(tools, context) {
2750
+ var ctx = context.ctx, scopes = context.scopes, authRoles = context.authRoles;
2751
+ var readOnlyMode = this.mcpConfig.readOnly === true;
2752
+ var visible = [];
2753
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
2754
+ try {
2755
+ for(var _iterator = tools[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
2756
+ var tool = _step.value;
2757
+ var filterMetadata = tool.filterMetadata;
2758
+ if (scopes != null && filterMetadata.requiredScope != null && !scopes.has(filterMetadata.requiredScope)) {
2759
+ continue;
2760
+ }
2761
+ if (readOnlyMode && filterMetadata.effectiveReadOnly !== true) {
2762
+ continue;
2763
+ }
2764
+ if (!this._passesVisibility({
2765
+ tool: tool,
2766
+ ctx: ctx,
2767
+ scopes: scopes,
2768
+ authRoles: authRoles
2769
+ })) {
2770
+ continue;
2771
+ }
2772
+ visible.push(tool);
2773
+ }
2774
+ } catch (err) {
2775
+ _didIteratorError = true;
2776
+ _iteratorError = err;
2777
+ } finally{
2778
+ try {
2779
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
2780
+ _iterator.return();
2781
+ }
2782
+ } finally{
2783
+ if (_didIteratorError) {
2784
+ throw _iteratorError;
2785
+ }
2786
+ }
2787
+ }
2788
+ return visible;
2789
+ }
2790
+ },
2791
+ {
2792
+ key: "_passesVisibility",
2793
+ value: function _passesVisibility(input) {
2794
+ var tool = input.tool, ctx = input.ctx, scopes = input.scopes, authRoles = input.authRoles;
2795
+ var filterMetadata = tool.filterMetadata;
2796
+ var result;
2797
+ if (filterMetadata.visibilityKind === 'declarative') {
2798
+ result = this._checkDeclarativeVisibility(filterMetadata.rule, ctx, authRoles);
2799
+ } else if (filterMetadata.visibilityKind === 'dynamic') {
2800
+ try {
2801
+ result = filterMetadata.visibilityFn({
2802
+ auth: ctx.auth,
2803
+ scopes: scopes !== null && scopes !== void 0 ? scopes : undefined,
2804
+ tool: tool.dispatch
2805
+ }) === true;
2806
+ } catch (error) {
2807
+ this._logger.warn("MCP tool ".concat(tool.name, " visibility predicate threw; treating as not visible: ").concat(error.message));
2808
+ result = false;
2809
+ }
2810
+ } else {
2811
+ result = true;
2812
+ }
2813
+ return result;
2814
+ }
2815
+ },
2816
+ {
2817
+ key: "_checkDeclarativeVisibility",
2818
+ value: function _checkDeclarativeVisibility(rule, ctx, authRoles) {
2819
+ var result = true;
2820
+ if (rule.requireAuthenticated === true && ctx.auth == null) {
2821
+ result = false;
2822
+ } else if (rule.requiredRoles != null && rule.requiredRoles.length > 0) {
2823
+ if (authRoles == null) {
2824
+ if (this.roleReader == null && !this._warnedMissingRoleReader) {
2825
+ this._warnedMissingRoleReader = true;
2826
+ this._logger.warn('MCP tool visibility rule declared requiredRoles but no McpAuthRoleReader is provided. Tools gated by role will be hidden.');
2827
+ }
2828
+ result = false;
2829
+ } else {
2830
+ result = util.authRolesSetHasRoles(authRoles, rule.requiredRoles);
2831
+ }
2832
+ }
2833
+ return result;
2834
+ }
2835
+ },
2836
+ {
2837
+ /**
2838
+ * Resolves the wire-shape `tools/list` entry for a single tool.
2839
+ *
2840
+ * Hot-path short-circuit: tools without a `toolDetailsBuilder` reuse the precomputed,
2841
+ * frozen {@link McpToolDefinition.staticWireEntry} verbatim — zero allocations per
2842
+ * request for the common case.
2843
+ *
2844
+ * Tools that opted in to {@link McpToolDetailsBuilder} get a fresh wire entry built
2845
+ * from the builder's overrides. If the builder throws, the framework falls back to
2846
+ * the static defaults and logs a warning (fail-soft, matching `_passesVisibility`).
2847
+ *
2848
+ * @param tool - The tool definition whose wire entry is being resolved.
2849
+ * @param ctx - The per-request context forwarded to any dynamic details builder.
2850
+ * @param scopes - The caller's granted OIDC scopes forwarded to any dynamic details builder.
2851
+ * @returns The wire-shape entry to emit for this tool on `tools/list`.
2852
+ */ key: "_buildToolListEntry",
2853
+ value: function _buildToolListEntry(tool, ctx, scopes) {
2854
+ var result;
2855
+ if (tool.toolDetailsBuilder == null) {
2856
+ result = tool.staticWireEntry;
2857
+ } else {
2858
+ var description = tool.description;
2859
+ var inputSchema = tool.inputSchema;
2860
+ try {
2861
+ var overrides = tool.toolDetailsBuilder({
2862
+ dispatch: tool.dispatch,
2863
+ defaultDescription: description,
2864
+ defaultInputSchema: inputSchema,
2865
+ auth: ctx.auth,
2866
+ scopes: scopes !== null && scopes !== void 0 ? scopes : undefined
2867
+ });
2868
+ if (overrides.description != null) {
2869
+ description = overrides.description;
2870
+ }
2871
+ if (overrides.inputSchema != null) {
2872
+ inputSchema = overrides.inputSchema;
2873
+ }
2874
+ } catch (error) {
2875
+ this._logger.warn("MCP tool ".concat(tool.name, " toolDetails builder threw; falling back to defaults: ").concat(error.message));
2876
+ }
2877
+ var wire = {
2878
+ name: tool.name,
2879
+ description: description,
2880
+ inputSchema: inputSchema !== null && inputSchema !== void 0 ? inputSchema : {
2881
+ type: 'object'
2882
+ }
2883
+ };
2884
+ if (tool.outputSchema != null) {
2885
+ wire.outputSchema = tool.outputSchema;
2886
+ }
2887
+ result = wire;
2888
+ }
2889
+ return result;
2890
+ }
2891
+ },
2892
+ {
2893
+ key: "_handleToolCall",
2894
+ value: function _handleToolCall(request, definitionsByName, ctx) {
2895
+ return _async_to_generator$2(function() {
2896
+ var _request_params_arguments, definition, args, response;
2897
+ return _ts_generator$2(this, function(_state) {
2898
+ switch(_state.label){
2899
+ case 0:
2900
+ definition = definitionsByName.get(request.params.name);
2901
+ args = (_request_params_arguments = request.params.arguments) !== null && _request_params_arguments !== void 0 ? _request_params_arguments : {};
2902
+ if (!(definition == null)) return [
2903
+ 3,
2904
+ 1
2905
+ ];
2906
+ response = formatMcpToolErrorResponse(new Error("Unknown tool: ".concat(request.params.name)));
2907
+ return [
2908
+ 3,
2909
+ 5
2910
+ ];
2911
+ case 1:
2912
+ if (!(definition.staticHandler == null)) return [
2913
+ 3,
2914
+ 3
2915
+ ];
2916
+ return [
2917
+ 4,
2918
+ this._handleCallModelToolCall(definition, args, ctx)
2919
+ ];
2920
+ case 2:
2921
+ response = _state.sent();
2922
+ return [
2923
+ 3,
2924
+ 5
2925
+ ];
2926
+ case 3:
2927
+ return [
2928
+ 4,
2929
+ this._handleStaticToolCall(definition.staticHandler, args, ctx)
2930
+ ];
2931
+ case 4:
2932
+ response = _state.sent();
2933
+ _state.label = 5;
2934
+ case 5:
2935
+ return [
2936
+ 2,
2937
+ response
2938
+ ];
2939
+ }
2940
+ });
2941
+ }).call(this);
2942
+ }
2943
+ },
2944
+ {
2945
+ key: "_handleStaticToolCall",
2946
+ value: function _handleStaticToolCall(staticHandler, args, ctx) {
2947
+ return _async_to_generator$2(function() {
2948
+ var response, error;
2949
+ return _ts_generator$2(this, function(_state) {
2950
+ switch(_state.label){
2951
+ case 0:
2952
+ _state.trys.push([
2953
+ 0,
2954
+ 2,
2955
+ ,
2956
+ 3
2957
+ ]);
2958
+ return [
2959
+ 4,
2960
+ staticHandler(args, ctx)
2961
+ ];
2962
+ case 1:
2963
+ response = _state.sent();
2964
+ return [
2965
+ 3,
2966
+ 3
2967
+ ];
2968
+ case 2:
2969
+ error = _state.sent();
2970
+ response = formatMcpToolErrorResponse(error);
2971
+ return [
2972
+ 3,
2973
+ 3
2974
+ ];
2975
+ case 3:
2976
+ return [
2977
+ 2,
2978
+ response
2979
+ ];
2980
+ }
2981
+ });
2982
+ })();
2983
+ }
2984
+ },
2985
+ {
2986
+ key: "_handleCallModelToolCall",
2987
+ value: function _handleCallModelToolCall(definition, args, ctx) {
2988
+ return _async_to_generator$2(function() {
2989
+ var params, response, result, error;
2990
+ return _ts_generator$2(this, function(_state) {
2991
+ switch(_state.label){
2992
+ case 0:
2993
+ params = {
2994
+ call: definition.dispatch.call,
2995
+ modelType: definition.dispatch.modelType,
2996
+ specifier: definition.dispatch.specifier,
2997
+ data: args
2998
+ };
2999
+ _state.label = 1;
3000
+ case 1:
3001
+ _state.trys.push([
3002
+ 1,
3003
+ 3,
3004
+ ,
3005
+ 4
3006
+ ]);
3007
+ return [
3008
+ 4,
3009
+ this.dispatchService.dispatch(params, ctx.auth, ctx.rawRequest)
3010
+ ];
3011
+ case 2:
3012
+ result = _state.sent();
3013
+ response = formatMcpToolResponse(result, params, definition.details);
3014
+ return [
3015
+ 3,
3016
+ 4
3017
+ ];
3018
+ case 3:
3019
+ error = _state.sent();
3020
+ response = formatMcpToolErrorResponse(error);
3021
+ return [
3022
+ 3,
3023
+ 4
3024
+ ];
3025
+ case 4:
3026
+ return [
3027
+ 2,
3028
+ response
3029
+ ];
3030
+ }
3031
+ });
3032
+ }).call(this);
3033
+ }
3034
+ }
3035
+ ]);
3036
+ return McpServerFactoryService;
3037
+ }();
3038
+ exports.McpServerFactoryService = McpServerFactoryService_1 = __decorate([
3039
+ common.Injectable(),
3040
+ __param(0, common.Inject(McpModuleConfig)),
3041
+ __param(1, common.Inject(firebaseServer.ModelApiCallModelDispatchService)),
3042
+ __param(2, common.Optional()),
3043
+ __param(2, common.Inject(firebaseServer.ModelApiGetService)),
3044
+ __param(3, common.Optional()),
3045
+ __param(3, common.Inject(MCP_AUTH_ROLE_READER))
3046
+ ], exports.McpServerFactoryService);
3047
+
3048
+ function asyncGeneratorStep$1(gen, resolve, reject, _next, _throw, key, arg) {
3049
+ try {
3050
+ var info = gen[key](arg);
3051
+ var value = info.value;
3052
+ } catch (error) {
3053
+ reject(error);
3054
+ return;
3055
+ }
3056
+ if (info.done) {
3057
+ resolve(value);
3058
+ } else {
3059
+ Promise.resolve(value).then(_next, _throw);
3060
+ }
3061
+ }
3062
+ function _async_to_generator$1(fn) {
3063
+ return function() {
3064
+ var self = this, args = arguments;
3065
+ return new Promise(function(resolve, reject) {
3066
+ var gen = fn.apply(self, args);
3067
+ function _next(value) {
3068
+ asyncGeneratorStep$1(gen, resolve, reject, _next, _throw, "next", value);
3069
+ }
3070
+ function _throw(err) {
3071
+ asyncGeneratorStep$1(gen, resolve, reject, _next, _throw, "throw", err);
3072
+ }
3073
+ _next(undefined);
3074
+ });
3075
+ };
3076
+ }
3077
+ function _ts_generator$1(thisArg, body) {
3078
+ var f, y, t, _ = {
3079
+ label: 0,
3080
+ sent: function() {
3081
+ if (t[0] & 1) throw t[1];
3082
+ return t[1];
3083
+ },
3084
+ trys: [],
3085
+ ops: []
3086
+ }, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype), d = Object.defineProperty;
3087
+ return d(g, "next", {
3088
+ value: verb(0)
3089
+ }), d(g, "throw", {
3090
+ value: verb(1)
3091
+ }), d(g, "return", {
3092
+ value: verb(2)
3093
+ }), typeof Symbol === "function" && d(g, Symbol.iterator, {
3094
+ value: function() {
3095
+ return this;
3096
+ }
3097
+ }), g;
3098
+ function verb(n) {
3099
+ return function(v) {
3100
+ return step([
3101
+ n,
3102
+ v
3103
+ ]);
3104
+ };
3105
+ }
3106
+ function step(op) {
3107
+ if (f) throw new TypeError("Generator is already executing.");
3108
+ while(g && (g = 0, op[0] && (_ = 0)), _)try {
3109
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
3110
+ if (y = 0, t) op = [
3111
+ op[0] & 2,
3112
+ t.value
3113
+ ];
3114
+ switch(op[0]){
3115
+ case 0:
3116
+ case 1:
3117
+ t = op;
3118
+ break;
3119
+ case 4:
3120
+ _.label++;
3121
+ return {
3122
+ value: op[1],
3123
+ done: false
3124
+ };
3125
+ case 5:
3126
+ _.label++;
3127
+ y = op[1];
3128
+ op = [
3129
+ 0
3130
+ ];
3131
+ continue;
3132
+ case 7:
3133
+ op = _.ops.pop();
3134
+ _.trys.pop();
3135
+ continue;
3136
+ default:
3137
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
3138
+ _ = 0;
3139
+ continue;
3140
+ }
3141
+ if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
3142
+ _.label = op[1];
3143
+ break;
3144
+ }
3145
+ if (op[0] === 6 && _.label < t[1]) {
3146
+ _.label = t[1];
3147
+ t = op;
3148
+ break;
3149
+ }
3150
+ if (t && _.label < t[2]) {
3151
+ _.label = t[2];
3152
+ _.ops.push(op);
3153
+ break;
3154
+ }
3155
+ if (t[2]) _.ops.pop();
3156
+ _.trys.pop();
3157
+ continue;
3158
+ }
3159
+ op = body.call(thisArg, _);
3160
+ } catch (e) {
3161
+ op = [
3162
+ 6,
3163
+ e
3164
+ ];
3165
+ y = 0;
3166
+ } finally{
3167
+ f = t = 0;
3168
+ }
3169
+ if (op[0] & 5) throw op[1];
3170
+ return {
3171
+ value: op[0] ? op[1] : void 0,
3172
+ done: true
3173
+ };
3174
+ }
3175
+ }
3176
+ /**
3177
+ * Handles a single Streamable HTTP JSON-RPC request against the supplied MCP server.
3178
+ *
3179
+ * Each call creates a fresh `StreamableHTTPServerTransport` in stateless mode — the
3180
+ * transport binds the server, processes one request, and is discarded. Stateless
3181
+ * mode is adequate for Claude custom-connector usage and avoids the bookkeeping
3182
+ * cost of session-tracked transports for the common case.
3183
+ *
3184
+ * The caller is expected to have already validated the bearer token (via the
3185
+ * OIDC bearer middleware) before this function runs.
3186
+ *
3187
+ * @param req - The Express request carrying the JSON-RPC body.
3188
+ * @param res - The Express response.
3189
+ * @param server - The MCP server instance to back the transport.
3190
+ * @param server.connect - The MCP server's connect method that binds the transport before request handling.
3191
+ */ function handleStreamableHttpMcpRequest(req, res, server) {
3192
+ return _async_to_generator$1(function() {
3193
+ var transport;
3194
+ return _ts_generator$1(this, function(_state) {
3195
+ switch(_state.label){
3196
+ case 0:
3197
+ // sessionIdGenerator: undefined → stateless mode.
3198
+ transport = new streamableHttp_js.StreamableHTTPServerTransport({
3199
+ sessionIdGenerator: undefined
3200
+ });
3201
+ res.on('close', function() {
3202
+ void transport.close();
3203
+ });
3204
+ return [
3205
+ 4,
3206
+ server.connect(transport)
3207
+ ];
3208
+ case 1:
3209
+ _state.sent();
3210
+ return [
3211
+ 4,
3212
+ transport.handleRequest(req, res, req.body)
3213
+ ];
3214
+ case 2:
3215
+ _state.sent();
3216
+ return [
3217
+ 2
3218
+ ];
3219
+ }
3220
+ });
3221
+ })();
3222
+ }
3223
+
3224
+ function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
3225
+ try {
3226
+ var info = gen[key](arg);
3227
+ var value = info.value;
3228
+ } catch (error) {
3229
+ reject(error);
3230
+ return;
3231
+ }
3232
+ if (info.done) {
3233
+ resolve(value);
3234
+ } else {
3235
+ Promise.resolve(value).then(_next, _throw);
3236
+ }
3237
+ }
3238
+ function _async_to_generator(fn) {
3239
+ return function() {
3240
+ var self = this, args = arguments;
3241
+ return new Promise(function(resolve, reject) {
3242
+ var gen = fn.apply(self, args);
3243
+ function _next(value) {
3244
+ asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
3245
+ }
3246
+ function _throw(err) {
3247
+ asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
3248
+ }
3249
+ _next(undefined);
3250
+ });
3251
+ };
3252
+ }
3253
+ function _class_call_check$1(instance, Constructor) {
3254
+ if (!(instance instanceof Constructor)) {
3255
+ throw new TypeError("Cannot call a class as a function");
3256
+ }
3257
+ }
3258
+ function _defineProperties$1(target, props) {
3259
+ for(var i = 0; i < props.length; i++){
3260
+ var descriptor = props[i];
3261
+ descriptor.enumerable = descriptor.enumerable || false;
3262
+ descriptor.configurable = true;
3263
+ if ("value" in descriptor) descriptor.writable = true;
3264
+ Object.defineProperty(target, descriptor.key, descriptor);
3265
+ }
3266
+ }
3267
+ function _create_class$1(Constructor, protoProps, staticProps) {
3268
+ if (protoProps) _defineProperties$1(Constructor.prototype, protoProps);
3269
+ return Constructor;
3270
+ }
3271
+ function _define_property$1(obj, key, value) {
3272
+ if (key in obj) {
3273
+ Object.defineProperty(obj, key, {
3274
+ value: value,
3275
+ enumerable: true,
3276
+ configurable: true,
3277
+ writable: true
3278
+ });
3279
+ } else {
3280
+ obj[key] = value;
3281
+ }
3282
+ return obj;
3283
+ }
3284
+ function _ts_generator(thisArg, body) {
3285
+ var f, y, t, _ = {
3286
+ label: 0,
3287
+ sent: function() {
3288
+ if (t[0] & 1) throw t[1];
3289
+ return t[1];
3290
+ },
3291
+ trys: [],
3292
+ ops: []
3293
+ }, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype), d = Object.defineProperty;
3294
+ return d(g, "next", {
3295
+ value: verb(0)
3296
+ }), d(g, "throw", {
3297
+ value: verb(1)
3298
+ }), d(g, "return", {
3299
+ value: verb(2)
3300
+ }), typeof Symbol === "function" && d(g, Symbol.iterator, {
3301
+ value: function() {
3302
+ return this;
3303
+ }
3304
+ }), g;
3305
+ function verb(n) {
3306
+ return function(v) {
3307
+ return step([
3308
+ n,
3309
+ v
3310
+ ]);
3311
+ };
3312
+ }
3313
+ function step(op) {
3314
+ if (f) throw new TypeError("Generator is already executing.");
3315
+ while(g && (g = 0, op[0] && (_ = 0)), _)try {
3316
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
3317
+ if (y = 0, t) op = [
3318
+ op[0] & 2,
3319
+ t.value
3320
+ ];
3321
+ switch(op[0]){
3322
+ case 0:
3323
+ case 1:
3324
+ t = op;
3325
+ break;
3326
+ case 4:
3327
+ _.label++;
3328
+ return {
3329
+ value: op[1],
3330
+ done: false
3331
+ };
3332
+ case 5:
3333
+ _.label++;
3334
+ y = op[1];
3335
+ op = [
3336
+ 0
3337
+ ];
3338
+ continue;
3339
+ case 7:
3340
+ op = _.ops.pop();
3341
+ _.trys.pop();
3342
+ continue;
3343
+ default:
3344
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
3345
+ _ = 0;
3346
+ continue;
3347
+ }
3348
+ if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
3349
+ _.label = op[1];
3350
+ break;
3351
+ }
3352
+ if (op[0] === 6 && _.label < t[1]) {
3353
+ _.label = t[1];
3354
+ t = op;
3355
+ break;
3356
+ }
3357
+ if (t && _.label < t[2]) {
3358
+ _.label = t[2];
3359
+ _.ops.push(op);
3360
+ break;
3361
+ }
3362
+ if (t[2]) _.ops.pop();
3363
+ _.trys.pop();
3364
+ continue;
3365
+ }
3366
+ op = body.call(thisArg, _);
3367
+ } catch (e) {
3368
+ op = [
3369
+ 6,
3370
+ e
3371
+ ];
3372
+ y = 0;
3373
+ } finally{
3374
+ f = t = 0;
3375
+ }
3376
+ if (op[0] & 5) throw op[1];
3377
+ return {
3378
+ value: op[0] ? op[1] : void 0,
3379
+ done: true
3380
+ };
3381
+ }
3382
+ }
3383
+ var McpController_1;
3384
+ /**
3385
+ * NestJS controller mounting the MCP Streamable HTTP transport at `POST /mcp`.
3386
+ *
3387
+ * Auth is enforced by the global OIDC bearer middleware (`OidcAuthBearerTokenMiddleware`)
3388
+ * which must include `'/mcp'` in its `protectedPaths`. By the time the request reaches
3389
+ * this controller, `req.auth` is populated with the authenticated user's data.
3390
+ *
3391
+ * Each request gets a fresh transport + MCP server pair (stateless mode), which is
3392
+ * adequate for Claude custom-connector style usage. A session-tracked variant can
3393
+ * be layered on later if streaming tool output becomes a requirement.
3394
+ */ exports.McpController = McpController_1 = /*#__PURE__*/ function() {
3395
+ 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));
3399
+ this.factory = factory;
3400
+ }
3401
+ _create_class$1(McpController, [
3402
+ {
3403
+ key: "handleMcpRequest",
3404
+ value: function handleMcpRequest(req, res) {
3405
+ return _async_to_generator(function() {
3406
+ var auth, server, error;
3407
+ return _ts_generator(this, function(_state) {
3408
+ switch(_state.label){
3409
+ case 0:
3410
+ auth = req.auth;
3411
+ server = this.factory.createServer({
3412
+ auth: auth,
3413
+ rawRequest: req
3414
+ });
3415
+ _state.label = 1;
3416
+ case 1:
3417
+ _state.trys.push([
3418
+ 1,
3419
+ 3,
3420
+ ,
3421
+ 4
3422
+ ]);
3423
+ return [
3424
+ 4,
3425
+ handleStreamableHttpMcpRequest(req, res, server)
3426
+ ];
3427
+ case 2:
3428
+ _state.sent();
3429
+ return [
3430
+ 3,
3431
+ 4
3432
+ ];
3433
+ case 3:
3434
+ error = _state.sent();
3435
+ this._logger.error('MCP request handling failed', error);
3436
+ if (!res.headersSent) {
3437
+ res.status(500).json({
3438
+ statusCode: 500,
3439
+ message: 'MCP request handling failed'
3440
+ });
3441
+ }
3442
+ return [
3443
+ 3,
3444
+ 4
3445
+ ];
3446
+ case 4:
3447
+ return [
3448
+ 2
3449
+ ];
3450
+ }
3451
+ });
3452
+ }).call(this);
3453
+ }
3454
+ }
3455
+ ]);
3456
+ return McpController;
3457
+ }();
3458
+ __decorate([
3459
+ common.Post(),
3460
+ __param(0, common.Req()),
3461
+ __param(1, common.Res())
3462
+ ], exports.McpController.prototype, "handleMcpRequest", null);
3463
+ exports.McpController = McpController_1 = __decorate([
3464
+ common.Controller('mcp'),
3465
+ __param(0, common.Inject(exports.McpServerFactoryService))
3466
+ ], exports.McpController);
3467
+
3468
+ function _class_call_check(instance, Constructor) {
3469
+ if (!(instance instanceof Constructor)) {
3470
+ throw new TypeError("Cannot call a class as a function");
3471
+ }
3472
+ }
3473
+ function _defineProperties(target, props) {
3474
+ for(var i = 0; i < props.length; i++){
3475
+ var descriptor = props[i];
3476
+ descriptor.enumerable = descriptor.enumerable || false;
3477
+ descriptor.configurable = true;
3478
+ if ("value" in descriptor) descriptor.writable = true;
3479
+ Object.defineProperty(target, descriptor.key, descriptor);
3480
+ }
3481
+ }
3482
+ function _create_class(Constructor, protoProps, staticProps) {
3483
+ if (protoProps) _defineProperties(Constructor.prototype, protoProps);
3484
+ return Constructor;
3485
+ }
3486
+ function _define_property(obj, key, value) {
3487
+ if (key in obj) {
3488
+ Object.defineProperty(obj, key, {
3489
+ value: value,
3490
+ enumerable: true,
3491
+ configurable: true,
3492
+ writable: true
3493
+ });
3494
+ } else {
3495
+ obj[key] = value;
3496
+ }
3497
+ return obj;
3498
+ }
3499
+ /**
3500
+ * Serves the `GET /.well-known/oauth-protected-resource` metadata document so
3501
+ * Claude (and other MCP clients) can discover which OIDC issuer guards this
3502
+ * MCP endpoint.
3503
+ *
3504
+ * The route is registered without a controller-level prefix because well-known
3505
+ * URIs must live at the host root. Apps need to exclude `.well-known/{*path}`
3506
+ * from any global API route prefix (see `FIREBASE_SERVER_OIDC_ROUTES_FOR_GLOBAL_ROUTE_EXCLUDE`
3507
+ * in `firebase-server/oidc` for the corresponding OIDC excludes).
3508
+ */ exports.McpWellKnownController = /*#__PURE__*/ function() {
3509
+ function McpWellKnownController(mcpConfig) {
3510
+ _class_call_check(this, McpWellKnownController);
3511
+ _define_property(this, "mcpConfig", void 0);
3512
+ this.mcpConfig = mcpConfig;
3513
+ }
3514
+ _create_class(McpWellKnownController, [
3515
+ {
3516
+ key: "getProtectedResourceMetadata",
3517
+ value: function getProtectedResourceMetadata() {
3518
+ return {
3519
+ resource: this.mcpConfig.mcpUrl,
3520
+ authorization_servers: [
3521
+ this.mcpConfig.oidcIssuer
3522
+ ]
3523
+ };
3524
+ }
3525
+ }
3526
+ ]);
3527
+ return McpWellKnownController;
3528
+ }();
3529
+ __decorate([
3530
+ common.Get('oauth-protected-resource')
3531
+ ], exports.McpWellKnownController.prototype, "getProtectedResourceMetadata", null);
3532
+ exports.McpWellKnownController = __decorate([
3533
+ common.Controller('.well-known'),
3534
+ __param(0, common.Inject(McpModuleConfig))
3535
+ ], exports.McpWellKnownController);
3536
+
3537
+ function _array_like_to_array(arr, len) {
3538
+ if (len == null || len > arr.length) len = arr.length;
3539
+ for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
3540
+ return arr2;
3541
+ }
3542
+ function _array_without_holes(arr) {
3543
+ if (Array.isArray(arr)) return _array_like_to_array(arr);
3544
+ }
3545
+ function _iterable_to_array(iter) {
3546
+ if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
3547
+ }
3548
+ function _non_iterable_spread() {
3549
+ 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
+ }
3551
+ function _to_consumable_array(arr) {
3552
+ return _array_without_holes(arr) || _iterable_to_array(arr) || _unsupported_iterable_to_array(arr) || _non_iterable_spread();
3553
+ }
3554
+ function _unsupported_iterable_to_array(o, minLen) {
3555
+ if (!o) return;
3556
+ if (typeof o === "string") return _array_like_to_array(o, minLen);
3557
+ var n = Object.prototype.toString.call(o).slice(8, -1);
3558
+ if (n === "Object" && o.constructor) n = o.constructor.name;
3559
+ 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);
3561
+ }
3562
+ /**
3563
+ * Routes the firebase-server/mcp module owns. Apps should exclude these from
3564
+ * any global API route prefix (`globalApiRoutePrefix.exclude`) so the canonical
3565
+ * URLs land at `/.well-known/...` and `/mcp` rather than `/api/.well-known/...`.
3566
+ */ var FIREBASE_SERVER_MCP_ROUTES_FOR_GLOBAL_ROUTE_EXCLUDE = [
3567
+ '.well-known/{*path}',
3568
+ 'mcp'
3569
+ ];
3570
+ /**
3571
+ * Generates NestJS module metadata for the firebase-server/mcp module.
3572
+ *
3573
+ * Mirrors the convention used by {@link modelApiModuleMetadata}: the consumer provides
3574
+ * a dependency module that exposes the required tokens, and this factory wires up the
3575
+ * controllers + factory service.
3576
+ *
3577
+ * @param metadataConfig - Configuration including the dependency module.
3578
+ * @returns NestJS module metadata exposing the MCP transport + well-known controller.
3579
+ *
3580
+ * @Module ({
3581
+ * imports: [DemoModelApiModule],
3582
+ * providers: [{ provide: McpModuleConfig, useValue: { oidcIssuer, mcpUrl } }],
3583
+ * exports: [McpModuleConfig, ModelApiCallModelDispatchService, MODEL_API_NEST_APPLICATION_CONTEXT]
3584
+ * })
3585
+ * export class DemoMcpDependencyModule {}
3586
+ * @Module (mcpModuleMetadata({ dependencyModule: DemoMcpDependencyModule }))
3587
+ * export class DemoMcpModule {}
3588
+ * ```
3589
+ *
3590
+ * @example
3591
+ * ```typescript
3592
+ */ function mcpModuleMetadata(metadataConfig) {
3593
+ var dependencyModule = metadataConfig.dependencyModule, imports = metadataConfig.imports, exports$1 = metadataConfig.exports, providers = metadataConfig.providers;
3594
+ return {
3595
+ imports: [
3596
+ dependencyModule
3597
+ ].concat(_to_consumable_array(imports !== null && imports !== void 0 ? imports : [])),
3598
+ controllers: [
3599
+ exports.McpController,
3600
+ exports.McpWellKnownController
3601
+ ],
3602
+ exports: [
3603
+ exports.McpServerFactoryService
3604
+ ].concat(_to_consumable_array(exports$1 !== null && exports$1 !== void 0 ? exports$1 : [])),
3605
+ providers: [
3606
+ exports.McpServerFactoryService
3607
+ ].concat(_to_consumable_array(providers !== null && providers !== void 0 ? providers : []))
3608
+ };
3609
+ }
3610
+
3611
+ exports.DEFAULT_JSON_SCHEMA_GENERATION_OPTIONS = DEFAULT_JSON_SCHEMA_GENERATION_OPTIONS;
3612
+ exports.DEFAULT_MCP_PATH = DEFAULT_MCP_PATH;
3613
+ exports.DEFAULT_MCP_SERVER_NAME = DEFAULT_MCP_SERVER_NAME;
3614
+ exports.DEFAULT_SPECIFIER_KEY = DEFAULT_SPECIFIER_KEY;
3615
+ exports.DEFAULT_VOID_MCP_SUCCESS_VALUE = DEFAULT_VOID_MCP_SUCCESS_VALUE;
3616
+ exports.FIREBASE_SERVER_MCP_ROUTES_FOR_GLOBAL_ROUTE_EXCLUDE = FIREBASE_SERVER_MCP_ROUTES_FOR_GLOBAL_ROUTE_EXCLUDE;
3617
+ exports.MCP_AUTH_ROLE_READER = MCP_AUTH_ROLE_READER;
3618
+ exports.MCP_MANIFEST_VERSION = MCP_MANIFEST_VERSION;
3619
+ exports.MCP_MODEL_GET_BATCH_SIZE = MCP_MODEL_GET_BATCH_SIZE;
3620
+ exports.MODEL_DECODE_DISPATCH_CALL = MODEL_DECODE_DISPATCH_CALL;
3621
+ exports.MODEL_DECODE_DISPATCH_MODEL_TYPE = MODEL_DECODE_DISPATCH_MODEL_TYPE;
3622
+ exports.MODEL_DECODE_TOOL_NAME = MODEL_DECODE_TOOL_NAME;
3623
+ exports.MODEL_GET_DISPATCH_CALL = MODEL_GET_DISPATCH_CALL;
3624
+ exports.MODEL_GET_DISPATCH_MODEL_TYPE = MODEL_GET_DISPATCH_MODEL_TYPE;
3625
+ exports.MODEL_GET_TOOL_NAME = MODEL_GET_TOOL_NAME;
3626
+ exports.MODEL_INFO_DISPATCH_CALL = MODEL_INFO_DISPATCH_CALL;
3627
+ exports.MODEL_INFO_DISPATCH_MODEL_TYPE = MODEL_INFO_DISPATCH_MODEL_TYPE;
3628
+ exports.MODEL_INFO_TOOL_NAME = MODEL_INFO_TOOL_NAME;
3629
+ exports.McpModuleConfig = McpModuleConfig;
3630
+ exports.buildDefaultMcpToolDescription = buildDefaultMcpToolDescription;
3631
+ exports.buildMcpToolName = buildMcpToolName;
3632
+ exports.buildStaticWireEntry = buildStaticWireEntry;
3633
+ exports.classifyVisibility = classifyVisibility;
3634
+ exports.createModelDecodeTool = createModelDecodeTool;
3635
+ exports.createModelGetTool = createModelGetTool;
3636
+ exports.createModelInfoTool = createModelInfoTool;
3637
+ exports.decodeFirestoreModelKey = decodeFirestoreModelKey;
3638
+ exports.findModelEntry = findModelEntry;
3639
+ exports.formatMcpToolErrorResponse = formatMcpToolErrorResponse;
3640
+ exports.formatMcpToolResponse = formatMcpToolResponse;
3641
+ exports.generateMcpToolDefinitions = generateMcpToolDefinitions;
3642
+ exports.handleStreamableHttpMcpRequest = handleStreamableHttpMcpRequest;
3643
+ exports.mcpManifestKey = mcpManifestKey;
3644
+ exports.mcpModuleMetadata = mcpModuleMetadata;
3645
+ exports.resolveEffectiveReadOnly = resolveEffectiveReadOnly;
3646
+ exports.resolveRequiredScope = resolveRequiredScope;