@dereekb/firebase-server 13.36.0 → 13.38.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/calcom/package.json +10 -10
- package/discord/package.json +10 -10
- package/index.cjs.js +1732 -510
- package/index.esm.js +1717 -513
- package/mailgun/package.json +9 -9
- package/mcp/index.cjs.js +913 -167
- package/mcp/index.esm.js +906 -166
- package/mcp/package.json +13 -12
- package/mcp/src/lib/controller/mcp.controller.d.ts +28 -3
- package/mcp/src/lib/controller/mcp.wellknown.controller.d.ts +21 -1
- package/mcp/src/lib/mcp.config.d.ts +31 -8
- package/mcp/src/lib/mcp.module.d.ts +2 -1
- package/mcp/src/lib/service/index.d.ts +1 -0
- package/mcp/src/lib/service/mcp.server.factory.d.ts +8 -6
- package/mcp/src/lib/service/mcp.tool-generator.d.ts +1 -1
- package/mcp/src/lib/service/mcp.visibility.d.ts +1 -1
- package/mcp/src/lib/service/tools/mcp.tool.model-roles.d.ts +95 -0
- package/mcp/src/lib/transport/streamable-http.transport.d.ts +16 -11
- package/model/index.cjs.js +1 -1
- package/model/index.esm.js +1 -1
- package/model/package.json +9 -9
- package/oidc/index.cjs.js +257 -67
- package/oidc/index.esm.js +256 -69
- package/oidc/package.json +10 -10
- package/oidc/src/lib/profile.d.ts +21 -0
- package/oidc/src/lib/service/index.d.ts +1 -0
- package/oidc/src/lib/service/oidc.config.service.d.ts +14 -0
- package/oidc/src/lib/service/oidc.interaction-policy.d.ts +35 -0
- package/oidc/src/lib/service/oidc.service.d.ts +29 -0
- package/package.json +14 -13
- package/src/lib/env/env.service.d.ts +27 -3
- package/src/lib/nest/controller/api.scope.d.ts +63 -0
- package/src/lib/nest/controller/index.d.ts +2 -0
- package/src/lib/nest/controller/model/model.api.get.service.d.ts +146 -1
- package/src/lib/nest/controller/model/model.api.scope.d.ts +3 -2
- package/src/lib/nest/controller/session/index.d.ts +4 -0
- package/src/lib/nest/controller/session/session.api.config.d.ts +104 -0
- package/src/lib/nest/controller/session/session.api.controller.d.ts +26 -0
- package/src/lib/nest/controller/session/session.api.module.d.ts +49 -0
- package/src/lib/nest/controller/session/session.api.service.d.ts +71 -0
- package/test/index.cjs.js +8 -8
- package/test/index.esm.js +8 -8
- package/test/package.json +11 -11
- package/twilio/package.json +8 -8
- package/zoho/package.json +10 -10
package/mcp/index.esm.js
CHANGED
|
@@ -1,21 +1,20 @@
|
|
|
1
|
-
import { Injectable, Inject, Optional, Logger, Post, Req, Res, Controller,
|
|
1
|
+
import { Injectable, Inject, Optional, Logger, Post, Req, Res, Get, Delete, Controller, HttpStatus } from '@nestjs/common';
|
|
2
2
|
import { existsSync, readFileSync } from 'node:fs';
|
|
3
|
-
import { McpServer } from '@modelcontextprotocol/
|
|
4
|
-
import { ListToolsRequestSchema, CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
3
|
+
import { McpServer, isLegacyRequest, isJsonContentType, createMcpHandler } from '@modelcontextprotocol/server';
|
|
5
4
|
import { callModelOidcScopeForCallType, resolveEffectiveOidcScopeTerms, inferKeyFromTwoWayFlatFirestoreModelKey, oidcScopeTermsSatisfied } from '@dereekb/firebase';
|
|
6
5
|
import { getOidcScopesFromRequest, OidcProviderConfigService } from '@dereekb/firebase-server/oidc';
|
|
7
6
|
import { makeValuesGroupMap, IMPERSONATION_URL_QUERY_PARAM, performAsyncTasks, authRolesSetHasRoles } from '@dereekb/util';
|
|
8
7
|
import { ModelApiCallModelDispatchService, ModelApiGetService, FirebaseServerStorageService, FirebaseServerEnvService, FirebaseServerAnalyticsService } from '@dereekb/firebase-server';
|
|
9
8
|
import { inspect } from 'node:util';
|
|
10
9
|
import { arktypeToJsonSchemaForExport } from '@dereekb/model';
|
|
11
|
-
import {
|
|
10
|
+
import { toWebRequest, toNodeHandler, NodeStreamableHTTPServerTransport } from '@modelcontextprotocol/node';
|
|
12
11
|
|
|
13
12
|
function _class_call_check$5(instance, Constructor) {
|
|
14
13
|
if (!(instance instanceof Constructor)) {
|
|
15
14
|
throw new TypeError("Cannot call a class as a function");
|
|
16
15
|
}
|
|
17
16
|
}
|
|
18
|
-
function _define_property$
|
|
17
|
+
function _define_property$a(obj, key, value) {
|
|
19
18
|
if (key in obj) {
|
|
20
19
|
Object.defineProperty(obj, key, {
|
|
21
20
|
value: value,
|
|
@@ -86,7 +85,7 @@ function _define_property$9(obj, key, value) {
|
|
|
86
85
|
* discovery document. Claude custom-connector reads this to discover the OIDC issuer.
|
|
87
86
|
*
|
|
88
87
|
* @example 'https://api.example.com/oidc'
|
|
89
|
-
*/ _define_property$
|
|
88
|
+
*/ _define_property$a(this, "oidcIssuer", void 0);
|
|
90
89
|
/**
|
|
91
90
|
* The canonical resource URL of the MCP endpoint.
|
|
92
91
|
*
|
|
@@ -94,17 +93,18 @@ function _define_property$9(obj, key, value) {
|
|
|
94
93
|
* and used as the audience the access token's `aud` claim should match.
|
|
95
94
|
*
|
|
96
95
|
* @example 'https://api.example.com/mcp'
|
|
97
|
-
*/ _define_property$
|
|
96
|
+
*/ _define_property$a(this, "mcpUrl", void 0);
|
|
98
97
|
/**
|
|
99
98
|
* Optional filter applied to the OIDC provider's scope list when building the
|
|
100
99
|
* protected-resource discovery document's `scopes_supported` (RFC 9728 §2).
|
|
101
100
|
*
|
|
102
101
|
* The base list is pulled automatically from the OIDC provider config via the
|
|
103
|
-
* injected {@link OidcProviderConfigService.
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
102
|
+
* injected {@link OidcProviderConfigService.clientRequestableScopesSupported}, so
|
|
103
|
+
* the MCP resource advertises the scopes the issuer grants an arbitrary client
|
|
104
|
+
* without the app restating them. Scopes only an admin-assigned provider profile
|
|
105
|
+
* unlocks are already excluded — requesting one is fatal at the consent unlock
|
|
106
|
+
* gate. Provide this only to narrow the set further; it returns the subset to
|
|
107
|
+
* advertise. When unset, the whole base list is advertised.
|
|
108
108
|
*
|
|
109
109
|
* Advertising these matters because dynamic-registration MCP clients (the Claude
|
|
110
110
|
* Code CLI) read `scopes_supported` to decide which scopes to request on the
|
|
@@ -112,19 +112,19 @@ function _define_property$9(obj, key, value) {
|
|
|
112
112
|
* the OIDC provider nothing to grant and ending the interaction in `access_denied`.
|
|
113
113
|
*
|
|
114
114
|
* @example (allScopes) => allScopes.filter((scope) => scope === 'openid' || scope.startsWith('model.'))
|
|
115
|
-
*/ _define_property$
|
|
115
|
+
*/ _define_property$a(this, "scopesSupported", void 0);
|
|
116
116
|
/**
|
|
117
117
|
* Optional name advertised on the MCP `initialize` handshake. Defaults to
|
|
118
118
|
* {@link DEFAULT_MCP_SERVER_NAME}.
|
|
119
|
-
*/ _define_property$
|
|
119
|
+
*/ _define_property$a(this, "serverName", void 0);
|
|
120
120
|
/**
|
|
121
121
|
* Optional version advertised on the MCP `initialize` handshake.
|
|
122
|
-
*/ _define_property$
|
|
122
|
+
*/ _define_property$a(this, "serverVersion", void 0);
|
|
123
123
|
/**
|
|
124
124
|
* Optional override for the `instructions` string passed to `new McpServer(...)` and
|
|
125
125
|
* advertised on the JSON-RPC `initialize` handshake. Defaults to
|
|
126
126
|
* {@link DEFAULT_MCP_SERVER_INSTRUCTIONS}.
|
|
127
|
-
*/ _define_property$
|
|
127
|
+
*/ _define_property$a(this, "serverInstructions", void 0);
|
|
128
128
|
/**
|
|
129
129
|
* Absolute path to a pre-rendered MCP manifest JSON file produced by
|
|
130
130
|
* `dbx-cli-generate-mcp-manifest`. When set, the runtime reads it once at
|
|
@@ -134,7 +134,7 @@ function _define_property$9(obj, key, value) {
|
|
|
134
134
|
* Optional. When unset or the file is missing, the runtime falls back to
|
|
135
135
|
* today's behavior (auto-generated descriptions, ArkType-derived input
|
|
136
136
|
* schemas, no output schemas) and emits a single boot warning.
|
|
137
|
-
*/ _define_property$
|
|
137
|
+
*/ _define_property$a(this, "mcpManifestPath", void 0);
|
|
138
138
|
/**
|
|
139
139
|
* Absolute path to a pre-rendered route manifest JSON file produced by
|
|
140
140
|
* `dbx-cli-generate-route-manifest`. When set, the runtime reads it once at
|
|
@@ -144,7 +144,7 @@ function _define_property$9(obj, key, value) {
|
|
|
144
144
|
* Optional. When unset or the file is missing, the runtime skips registering
|
|
145
145
|
* `url-models` and emits a single boot warning when the path was set but
|
|
146
146
|
* unreadable.
|
|
147
|
-
*/ _define_property$
|
|
147
|
+
*/ _define_property$a(this, "mcpRouteManifestPath", void 0);
|
|
148
148
|
/**
|
|
149
149
|
* When `true`, the MCP server only advertises tools whose effective read-only classification is `true`.
|
|
150
150
|
*
|
|
@@ -154,7 +154,7 @@ function _define_property$9(obj, key, value) {
|
|
|
154
154
|
*
|
|
155
155
|
* The advertised `serverName` on the JSON-RPC `initialize` handshake is suffixed with
|
|
156
156
|
* ` (read-only)` so the client surface reflects the mode.
|
|
157
|
-
*/ _define_property$
|
|
157
|
+
*/ _define_property$a(this, "readOnly", void 0);
|
|
158
158
|
/**
|
|
159
159
|
* Controls the auto-injected `reason` parameter added to every advertised tool's input schema.
|
|
160
160
|
*
|
|
@@ -164,7 +164,7 @@ function _define_property$9(obj, key, value) {
|
|
|
164
164
|
* When enabled, every advertised tool's `inputSchema` carries a required `reason` string the model
|
|
165
165
|
* fills with a short justification for the call. The value is forwarded to analytics and stripped
|
|
166
166
|
* from the dispatched handler body. See {@link McpReasonParameterConfig}.
|
|
167
|
-
*/ _define_property$
|
|
167
|
+
*/ _define_property$a(this, "reasonParameter", void 0);
|
|
168
168
|
/**
|
|
169
169
|
* Default OIDC scope group term required on EVERY `callModel` op, mirrored into MCP tool-list
|
|
170
170
|
* visibility, unless a finer term overrides it (a per-function `requiredScope`, then a
|
|
@@ -174,17 +174,20 @@ function _define_property$9(obj, key, value) {
|
|
|
174
174
|
*
|
|
175
175
|
* Set this to the SAME value passed to `ModelApiDispatchConfig.defaultRequiredScope` to
|
|
176
176
|
* keep tool visibility and enforcement in lockstep.
|
|
177
|
-
*/ _define_property$
|
|
177
|
+
*/ _define_property$a(this, "defaultRequiredScope", void 0);
|
|
178
178
|
/**
|
|
179
179
|
* Per-model OIDC scope group-term overrides, keyed by {@link FirestoreModelType}, mirrored into MCP
|
|
180
180
|
* tool-list visibility. Set this to the SAME value passed to
|
|
181
181
|
* `ModelApiDispatchConfig.modelRequiredScopes` so per-model / verb-keyed restrictions that
|
|
182
182
|
* confine a subset client apply identically to the advertised tool list.
|
|
183
|
-
*/ _define_property$
|
|
183
|
+
*/ _define_property$a(this, "modelRequiredScopes", void 0);
|
|
184
184
|
};
|
|
185
185
|
/**
|
|
186
186
|
* NestJS injection token for the optional {@link McpAuthRoleReader} provider.
|
|
187
187
|
*/ var MCP_AUTH_ROLE_READER = 'MCP_AUTH_ROLE_READER';
|
|
188
|
+
/**
|
|
189
|
+
* NestJS injection token for the optional {@link McpModelRolesTargetUidPredicate} provider.
|
|
190
|
+
*/ var MCP_MODEL_ROLES_TARGET_UID_PREDICATE = 'MCP_MODEL_ROLES_TARGET_UID_PREDICATE';
|
|
188
191
|
|
|
189
192
|
function _type_of$5(obj) {
|
|
190
193
|
"@swc/helpers - typeof";
|
|
@@ -214,7 +217,7 @@ function _array_like_to_array$b(arr, len) {
|
|
|
214
217
|
function _array_without_holes$8(arr) {
|
|
215
218
|
if (Array.isArray(arr)) return _array_like_to_array$b(arr);
|
|
216
219
|
}
|
|
217
|
-
function _define_property$
|
|
220
|
+
function _define_property$9(obj, key, value) {
|
|
218
221
|
if (key in obj) {
|
|
219
222
|
Object.defineProperty(obj, key, {
|
|
220
223
|
value: value,
|
|
@@ -233,7 +236,7 @@ function _iterable_to_array$8(iter) {
|
|
|
233
236
|
function _non_iterable_spread$8() {
|
|
234
237
|
throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
|
235
238
|
}
|
|
236
|
-
function _object_spread$
|
|
239
|
+
function _object_spread$7(target) {
|
|
237
240
|
for(var i = 1; i < arguments.length; i++){
|
|
238
241
|
var source = arguments[i] != null ? arguments[i] : {};
|
|
239
242
|
var ownKeys = Object.keys(source);
|
|
@@ -243,7 +246,7 @@ function _object_spread$6(target) {
|
|
|
243
246
|
}));
|
|
244
247
|
}
|
|
245
248
|
ownKeys.forEach(function(key) {
|
|
246
|
-
_define_property$
|
|
249
|
+
_define_property$9(target, key, source[key]);
|
|
247
250
|
});
|
|
248
251
|
}
|
|
249
252
|
return target;
|
|
@@ -353,9 +356,9 @@ function _unsupported_iterable_to_array$b(o, minLen) {
|
|
|
353
356
|
var _base_type;
|
|
354
357
|
var base = (typeof inputSchema === "undefined" ? "undefined" : _type_of$4(inputSchema)) === 'object' && inputSchema != null ? inputSchema : {};
|
|
355
358
|
var existingProperties = _type_of$4(base.properties) === 'object' && base.properties != null ? base.properties : {};
|
|
356
|
-
var next = _object_spread_props$3(_object_spread$
|
|
359
|
+
var next = _object_spread_props$3(_object_spread$7({}, base), {
|
|
357
360
|
type: (_base_type = base.type) !== null && _base_type !== void 0 ? _base_type : 'object',
|
|
358
|
-
properties: _object_spread_props$3(_object_spread$
|
|
361
|
+
properties: _object_spread_props$3(_object_spread$7({}, existingProperties), _define_property$9({}, resolved.parameterName, {
|
|
359
362
|
type: 'string',
|
|
360
363
|
maxLength: resolved.maxLength,
|
|
361
364
|
description: resolved.description
|
|
@@ -389,7 +392,7 @@ function _unsupported_iterable_to_array$b(o, minLen) {
|
|
|
389
392
|
var result;
|
|
390
393
|
if (resolved.enabled && !toolDeclaresOwnReason && Object.prototype.hasOwnProperty.call(args, resolved.parameterName)) {
|
|
391
394
|
var rawValue = args[resolved.parameterName];
|
|
392
|
-
var nextArgs = _object_spread$
|
|
395
|
+
var nextArgs = _object_spread$7({}, args);
|
|
393
396
|
delete nextArgs[resolved.parameterName];
|
|
394
397
|
var stringValue = rawValue == null ? '' : String(rawValue);
|
|
395
398
|
var clamped = stringValue.length > resolved.maxLength ? stringValue.slice(0, resolved.maxLength) : stringValue;
|
|
@@ -744,7 +747,7 @@ function scoreCandidates(states, pathname) {
|
|
|
744
747
|
});
|
|
745
748
|
}
|
|
746
749
|
|
|
747
|
-
function asyncGeneratorStep$
|
|
750
|
+
function asyncGeneratorStep$7(gen, resolve, reject, _next, _throw, key, arg) {
|
|
748
751
|
try {
|
|
749
752
|
var info = gen[key](arg);
|
|
750
753
|
var value = info.value;
|
|
@@ -758,16 +761,16 @@ function asyncGeneratorStep$6(gen, resolve, reject, _next, _throw, key, arg) {
|
|
|
758
761
|
Promise.resolve(value).then(_next, _throw);
|
|
759
762
|
}
|
|
760
763
|
}
|
|
761
|
-
function _async_to_generator$
|
|
764
|
+
function _async_to_generator$7(fn) {
|
|
762
765
|
return function() {
|
|
763
766
|
var self = this, args = arguments;
|
|
764
767
|
return new Promise(function(resolve, reject) {
|
|
765
768
|
var gen = fn.apply(self, args);
|
|
766
769
|
function _next(value) {
|
|
767
|
-
asyncGeneratorStep$
|
|
770
|
+
asyncGeneratorStep$7(gen, resolve, reject, _next, _throw, "next", value);
|
|
768
771
|
}
|
|
769
772
|
function _throw(err) {
|
|
770
|
-
asyncGeneratorStep$
|
|
773
|
+
asyncGeneratorStep$7(gen, resolve, reject, _next, _throw, "throw", err);
|
|
771
774
|
}
|
|
772
775
|
_next(undefined);
|
|
773
776
|
});
|
|
@@ -781,7 +784,7 @@ function _instanceof$1(left, right) {
|
|
|
781
784
|
return left instanceof right;
|
|
782
785
|
}
|
|
783
786
|
}
|
|
784
|
-
function _ts_generator$
|
|
787
|
+
function _ts_generator$7(thisArg, body) {
|
|
785
788
|
var f, y, t, _ = {
|
|
786
789
|
label: 0,
|
|
787
790
|
sent: function() {
|
|
@@ -909,9 +912,9 @@ function _ts_generator$6(thisArg, body) {
|
|
|
909
912
|
* @param details - The handler-level API details (carries the mapper + Tier 2/3 formatters).
|
|
910
913
|
* @returns The MCP tool response content.
|
|
911
914
|
*/ function formatMcpToolResponse(result, params, details) {
|
|
912
|
-
return _async_to_generator$
|
|
915
|
+
return _async_to_generator$7(function() {
|
|
913
916
|
var mcp, value, _tmp, context, response, summary;
|
|
914
|
-
return _ts_generator$
|
|
917
|
+
return _ts_generator$7(this, function(_state) {
|
|
915
918
|
switch(_state.label){
|
|
916
919
|
case 0:
|
|
917
920
|
mcp = details === null || details === void 0 ? void 0 : details.mcp;
|
|
@@ -1771,7 +1774,7 @@ function _array_like_to_array$8(arr, len) {
|
|
|
1771
1774
|
function _array_without_holes$7(arr) {
|
|
1772
1775
|
if (Array.isArray(arr)) return _array_like_to_array$8(arr);
|
|
1773
1776
|
}
|
|
1774
|
-
function asyncGeneratorStep$
|
|
1777
|
+
function asyncGeneratorStep$6(gen, resolve, reject, _next, _throw, key, arg) {
|
|
1775
1778
|
try {
|
|
1776
1779
|
var info = gen[key](arg);
|
|
1777
1780
|
var value = info.value;
|
|
@@ -1785,16 +1788,16 @@ function asyncGeneratorStep$5(gen, resolve, reject, _next, _throw, key, arg) {
|
|
|
1785
1788
|
Promise.resolve(value).then(_next, _throw);
|
|
1786
1789
|
}
|
|
1787
1790
|
}
|
|
1788
|
-
function _async_to_generator$
|
|
1791
|
+
function _async_to_generator$6(fn) {
|
|
1789
1792
|
return function() {
|
|
1790
1793
|
var self = this, args = arguments;
|
|
1791
1794
|
return new Promise(function(resolve, reject) {
|
|
1792
1795
|
var gen = fn.apply(self, args);
|
|
1793
1796
|
function _next(value) {
|
|
1794
|
-
asyncGeneratorStep$
|
|
1797
|
+
asyncGeneratorStep$6(gen, resolve, reject, _next, _throw, "next", value);
|
|
1795
1798
|
}
|
|
1796
1799
|
function _throw(err) {
|
|
1797
|
-
asyncGeneratorStep$
|
|
1800
|
+
asyncGeneratorStep$6(gen, resolve, reject, _next, _throw, "throw", err);
|
|
1798
1801
|
}
|
|
1799
1802
|
_next(undefined);
|
|
1800
1803
|
});
|
|
@@ -1817,7 +1820,7 @@ function _unsupported_iterable_to_array$8(o, minLen) {
|
|
|
1817
1820
|
if (n === "Map" || n === "Set") return Array.from(n);
|
|
1818
1821
|
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$8(o, minLen);
|
|
1819
1822
|
}
|
|
1820
|
-
function _ts_generator$
|
|
1823
|
+
function _ts_generator$6(thisArg, body) {
|
|
1821
1824
|
var f, y, t, _ = {
|
|
1822
1825
|
label: 0,
|
|
1823
1826
|
sent: function() {
|
|
@@ -1978,55 +1981,564 @@ function _ts_generator$5(thisArg, body) {
|
|
|
1978
1981
|
}
|
|
1979
1982
|
// MARK: Handler
|
|
1980
1983
|
function modelGetToolHandler(args, ctx, deps) {
|
|
1984
|
+
return _async_to_generator$6(function() {
|
|
1985
|
+
var result, input, identity, resolvedKeys, merged, error;
|
|
1986
|
+
return _ts_generator$6(this, function(_state) {
|
|
1987
|
+
switch(_state.label){
|
|
1988
|
+
case 0:
|
|
1989
|
+
_state.trys.push([
|
|
1990
|
+
0,
|
|
1991
|
+
2,
|
|
1992
|
+
,
|
|
1993
|
+
3
|
|
1994
|
+
]);
|
|
1995
|
+
input = parseModelGetInput(args);
|
|
1996
|
+
identity = deps.resolveIdentity(input.modelType, ctx.auth);
|
|
1997
|
+
if (identity == null) {
|
|
1998
|
+
throw new Error("Unknown modelType: ".concat(input.modelType));
|
|
1999
|
+
}
|
|
2000
|
+
resolvedKeys = resolveKeys$1(input.keys, identity);
|
|
2001
|
+
return [
|
|
2002
|
+
4,
|
|
2003
|
+
readInChunks$1({
|
|
2004
|
+
modelType: input.modelType,
|
|
2005
|
+
keys: resolvedKeys,
|
|
2006
|
+
auth: ctx.auth,
|
|
2007
|
+
readDocuments: deps.readDocuments
|
|
2008
|
+
})
|
|
2009
|
+
];
|
|
2010
|
+
case 1:
|
|
2011
|
+
merged = _state.sent();
|
|
2012
|
+
result = {
|
|
2013
|
+
content: [
|
|
2014
|
+
{
|
|
2015
|
+
type: 'text',
|
|
2016
|
+
text: JSON.stringify(merged)
|
|
2017
|
+
}
|
|
2018
|
+
],
|
|
2019
|
+
structuredContent: merged
|
|
2020
|
+
};
|
|
2021
|
+
return [
|
|
2022
|
+
3,
|
|
2023
|
+
3
|
|
2024
|
+
];
|
|
2025
|
+
case 2:
|
|
2026
|
+
error = _state.sent();
|
|
2027
|
+
result = formatMcpToolErrorResponse(error);
|
|
2028
|
+
return [
|
|
2029
|
+
3,
|
|
2030
|
+
3
|
|
2031
|
+
];
|
|
2032
|
+
case 3:
|
|
2033
|
+
return [
|
|
2034
|
+
2,
|
|
2035
|
+
result
|
|
2036
|
+
];
|
|
2037
|
+
}
|
|
2038
|
+
});
|
|
2039
|
+
})();
|
|
2040
|
+
}
|
|
2041
|
+
function parseModelGetInput(args) {
|
|
2042
|
+
var modelType = args['modelType'];
|
|
2043
|
+
var keys = args['keys'];
|
|
2044
|
+
if (typeof modelType !== 'string' || modelType.length === 0) {
|
|
2045
|
+
throw new Error('model-get: "modelType" is required and must be a non-empty string.');
|
|
2046
|
+
}
|
|
2047
|
+
if (!Array.isArray(keys) || keys.length === 0) {
|
|
2048
|
+
throw new Error('model-get: "keys" is required and must be a non-empty array.');
|
|
2049
|
+
}
|
|
2050
|
+
var normalizedKeys = keys.map(function(value, index) {
|
|
2051
|
+
if (typeof value !== 'string' || value.length === 0) {
|
|
2052
|
+
throw new Error("model-get: keys[".concat(index, "] must be a non-empty string."));
|
|
2053
|
+
}
|
|
2054
|
+
return value;
|
|
2055
|
+
});
|
|
2056
|
+
return {
|
|
2057
|
+
modelType: modelType,
|
|
2058
|
+
keys: normalizedKeys
|
|
2059
|
+
};
|
|
2060
|
+
}
|
|
2061
|
+
function resolveKeys$1(keys, identity) {
|
|
2062
|
+
var isRoot = identity.type === 'root';
|
|
2063
|
+
var resolved = [];
|
|
2064
|
+
var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
|
|
2065
|
+
try {
|
|
2066
|
+
for(var _iterator = keys[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
|
|
2067
|
+
var value = _step.value;
|
|
2068
|
+
if (value.includes('/')) {
|
|
2069
|
+
resolved.push(value);
|
|
2070
|
+
} else if (isRoot) {
|
|
2071
|
+
resolved.push("".concat(identity.collectionName, "/").concat(value));
|
|
2072
|
+
} else {
|
|
2073
|
+
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, '").'));
|
|
2074
|
+
}
|
|
2075
|
+
}
|
|
2076
|
+
} catch (err) {
|
|
2077
|
+
_didIteratorError = true;
|
|
2078
|
+
_iteratorError = err;
|
|
2079
|
+
} finally{
|
|
2080
|
+
try {
|
|
2081
|
+
if (!_iteratorNormalCompletion && _iterator.return != null) {
|
|
2082
|
+
_iterator.return();
|
|
2083
|
+
}
|
|
2084
|
+
} finally{
|
|
2085
|
+
if (_didIteratorError) {
|
|
2086
|
+
throw _iteratorError;
|
|
2087
|
+
}
|
|
2088
|
+
}
|
|
2089
|
+
}
|
|
2090
|
+
return resolved;
|
|
2091
|
+
}
|
|
2092
|
+
function readInChunks$1(input) {
|
|
2093
|
+
return _async_to_generator$6(function() {
|
|
2094
|
+
var modelType, keys, auth, readDocuments, merged, offset, _merged_results, _merged_errors, batch, partial;
|
|
2095
|
+
return _ts_generator$6(this, function(_state) {
|
|
2096
|
+
switch(_state.label){
|
|
2097
|
+
case 0:
|
|
2098
|
+
modelType = input.modelType, keys = input.keys, auth = input.auth, readDocuments = input.readDocuments;
|
|
2099
|
+
merged = {
|
|
2100
|
+
results: [],
|
|
2101
|
+
errors: []
|
|
2102
|
+
};
|
|
2103
|
+
offset = 0;
|
|
2104
|
+
_state.label = 1;
|
|
2105
|
+
case 1:
|
|
2106
|
+
if (!(offset < keys.length)) return [
|
|
2107
|
+
3,
|
|
2108
|
+
4
|
|
2109
|
+
];
|
|
2110
|
+
batch = keys.slice(offset, offset + MCP_MODEL_GET_BATCH_SIZE);
|
|
2111
|
+
return [
|
|
2112
|
+
4,
|
|
2113
|
+
readDocuments(modelType, batch, auth)
|
|
2114
|
+
];
|
|
2115
|
+
case 2:
|
|
2116
|
+
partial = _state.sent();
|
|
2117
|
+
(_merged_results = merged.results).push.apply(_merged_results, _to_consumable_array$7(partial.results));
|
|
2118
|
+
(_merged_errors = merged.errors).push.apply(_merged_errors, _to_consumable_array$7(partial.errors));
|
|
2119
|
+
_state.label = 3;
|
|
2120
|
+
case 3:
|
|
2121
|
+
offset += MCP_MODEL_GET_BATCH_SIZE;
|
|
2122
|
+
return [
|
|
2123
|
+
3,
|
|
2124
|
+
1
|
|
2125
|
+
];
|
|
2126
|
+
case 4:
|
|
2127
|
+
return [
|
|
2128
|
+
2,
|
|
2129
|
+
merged
|
|
2130
|
+
];
|
|
2131
|
+
}
|
|
2132
|
+
});
|
|
2133
|
+
})();
|
|
2134
|
+
}
|
|
2135
|
+
// MARK: Schemas
|
|
2136
|
+
var MODEL_GET_INPUT_SCHEMA = {
|
|
2137
|
+
type: 'object',
|
|
2138
|
+
required: [
|
|
2139
|
+
'modelType',
|
|
2140
|
+
'keys'
|
|
2141
|
+
],
|
|
2142
|
+
properties: {
|
|
2143
|
+
modelType: {
|
|
2144
|
+
type: 'string',
|
|
2145
|
+
minLength: 1,
|
|
2146
|
+
description: 'Firestore model type to fetch (e.g. "guestbook", "profile").'
|
|
2147
|
+
},
|
|
2148
|
+
keys: {
|
|
2149
|
+
type: 'array',
|
|
2150
|
+
minItems: 1,
|
|
2151
|
+
description: 'Full keys ("prefix/id") or bare ids (root models only).',
|
|
2152
|
+
items: {
|
|
2153
|
+
type: 'string',
|
|
2154
|
+
minLength: 1
|
|
2155
|
+
}
|
|
2156
|
+
}
|
|
2157
|
+
},
|
|
2158
|
+
additionalProperties: false
|
|
2159
|
+
};
|
|
2160
|
+
var MODEL_GET_OUTPUT_SCHEMA = {
|
|
2161
|
+
type: 'object',
|
|
2162
|
+
required: [
|
|
2163
|
+
'results',
|
|
2164
|
+
'errors'
|
|
2165
|
+
],
|
|
2166
|
+
properties: {
|
|
2167
|
+
results: {
|
|
2168
|
+
type: 'array',
|
|
2169
|
+
description: 'Per-key successful reads.',
|
|
2170
|
+
items: {
|
|
2171
|
+
type: 'object',
|
|
2172
|
+
required: [
|
|
2173
|
+
'key',
|
|
2174
|
+
'data'
|
|
2175
|
+
],
|
|
2176
|
+
properties: {
|
|
2177
|
+
key: {
|
|
2178
|
+
type: 'string'
|
|
2179
|
+
},
|
|
2180
|
+
data: {}
|
|
2181
|
+
}
|
|
2182
|
+
}
|
|
2183
|
+
},
|
|
2184
|
+
errors: {
|
|
2185
|
+
type: 'array',
|
|
2186
|
+
description: 'Per-key failures (not-found, forbidden, etc.).',
|
|
2187
|
+
items: {
|
|
2188
|
+
type: 'object',
|
|
2189
|
+
required: [
|
|
2190
|
+
'key',
|
|
2191
|
+
'message'
|
|
2192
|
+
],
|
|
2193
|
+
properties: {
|
|
2194
|
+
key: {
|
|
2195
|
+
type: 'string'
|
|
2196
|
+
},
|
|
2197
|
+
message: {
|
|
2198
|
+
type: 'string'
|
|
2199
|
+
},
|
|
2200
|
+
code: {
|
|
2201
|
+
type: 'string'
|
|
2202
|
+
}
|
|
2203
|
+
}
|
|
2204
|
+
}
|
|
2205
|
+
}
|
|
2206
|
+
}
|
|
2207
|
+
};
|
|
2208
|
+
|
|
2209
|
+
function asyncGeneratorStep$5(gen, resolve, reject, _next, _throw, key, arg) {
|
|
2210
|
+
try {
|
|
2211
|
+
var info = gen[key](arg);
|
|
2212
|
+
var value = info.value;
|
|
2213
|
+
} catch (error) {
|
|
2214
|
+
reject(error);
|
|
2215
|
+
return;
|
|
2216
|
+
}
|
|
2217
|
+
if (info.done) {
|
|
2218
|
+
resolve(value);
|
|
2219
|
+
} else {
|
|
2220
|
+
Promise.resolve(value).then(_next, _throw);
|
|
2221
|
+
}
|
|
2222
|
+
}
|
|
2223
|
+
function _async_to_generator$5(fn) {
|
|
2224
|
+
return function() {
|
|
2225
|
+
var self = this, args = arguments;
|
|
2226
|
+
return new Promise(function(resolve, reject) {
|
|
2227
|
+
var gen = fn.apply(self, args);
|
|
2228
|
+
function _next(value) {
|
|
2229
|
+
asyncGeneratorStep$5(gen, resolve, reject, _next, _throw, "next", value);
|
|
2230
|
+
}
|
|
2231
|
+
function _throw(err) {
|
|
2232
|
+
asyncGeneratorStep$5(gen, resolve, reject, _next, _throw, "throw", err);
|
|
2233
|
+
}
|
|
2234
|
+
_next(undefined);
|
|
2235
|
+
});
|
|
2236
|
+
};
|
|
2237
|
+
}
|
|
2238
|
+
function _define_property$8(obj, key, value) {
|
|
2239
|
+
if (key in obj) {
|
|
2240
|
+
Object.defineProperty(obj, key, {
|
|
2241
|
+
value: value,
|
|
2242
|
+
enumerable: true,
|
|
2243
|
+
configurable: true,
|
|
2244
|
+
writable: true
|
|
2245
|
+
});
|
|
2246
|
+
} else {
|
|
2247
|
+
obj[key] = value;
|
|
2248
|
+
}
|
|
2249
|
+
return obj;
|
|
2250
|
+
}
|
|
2251
|
+
function _object_spread$6(target) {
|
|
2252
|
+
for(var i = 1; i < arguments.length; i++){
|
|
2253
|
+
var source = arguments[i] != null ? arguments[i] : {};
|
|
2254
|
+
var ownKeys = Object.keys(source);
|
|
2255
|
+
if (typeof Object.getOwnPropertySymbols === "function") {
|
|
2256
|
+
ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
|
|
2257
|
+
return Object.getOwnPropertyDescriptor(source, sym).enumerable;
|
|
2258
|
+
}));
|
|
2259
|
+
}
|
|
2260
|
+
ownKeys.forEach(function(key) {
|
|
2261
|
+
_define_property$8(target, key, source[key]);
|
|
2262
|
+
});
|
|
2263
|
+
}
|
|
2264
|
+
return target;
|
|
2265
|
+
}
|
|
2266
|
+
function _ts_generator$5(thisArg, body) {
|
|
2267
|
+
var f, y, t, _ = {
|
|
2268
|
+
label: 0,
|
|
2269
|
+
sent: function() {
|
|
2270
|
+
if (t[0] & 1) throw t[1];
|
|
2271
|
+
return t[1];
|
|
2272
|
+
},
|
|
2273
|
+
trys: [],
|
|
2274
|
+
ops: []
|
|
2275
|
+
}, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype), d = Object.defineProperty;
|
|
2276
|
+
return d(g, "next", {
|
|
2277
|
+
value: verb(0)
|
|
2278
|
+
}), d(g, "throw", {
|
|
2279
|
+
value: verb(1)
|
|
2280
|
+
}), d(g, "return", {
|
|
2281
|
+
value: verb(2)
|
|
2282
|
+
}), typeof Symbol === "function" && d(g, Symbol.iterator, {
|
|
2283
|
+
value: function() {
|
|
2284
|
+
return this;
|
|
2285
|
+
}
|
|
2286
|
+
}), g;
|
|
2287
|
+
function verb(n) {
|
|
2288
|
+
return function(v) {
|
|
2289
|
+
return step([
|
|
2290
|
+
n,
|
|
2291
|
+
v
|
|
2292
|
+
]);
|
|
2293
|
+
};
|
|
2294
|
+
}
|
|
2295
|
+
function step(op) {
|
|
2296
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
2297
|
+
while(g && (g = 0, op[0] && (_ = 0)), _)try {
|
|
2298
|
+
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;
|
|
2299
|
+
if (y = 0, t) op = [
|
|
2300
|
+
op[0] & 2,
|
|
2301
|
+
t.value
|
|
2302
|
+
];
|
|
2303
|
+
switch(op[0]){
|
|
2304
|
+
case 0:
|
|
2305
|
+
case 1:
|
|
2306
|
+
t = op;
|
|
2307
|
+
break;
|
|
2308
|
+
case 4:
|
|
2309
|
+
_.label++;
|
|
2310
|
+
return {
|
|
2311
|
+
value: op[1],
|
|
2312
|
+
done: false
|
|
2313
|
+
};
|
|
2314
|
+
case 5:
|
|
2315
|
+
_.label++;
|
|
2316
|
+
y = op[1];
|
|
2317
|
+
op = [
|
|
2318
|
+
0
|
|
2319
|
+
];
|
|
2320
|
+
continue;
|
|
2321
|
+
case 7:
|
|
2322
|
+
op = _.ops.pop();
|
|
2323
|
+
_.trys.pop();
|
|
2324
|
+
continue;
|
|
2325
|
+
default:
|
|
2326
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
|
|
2327
|
+
_ = 0;
|
|
2328
|
+
continue;
|
|
2329
|
+
}
|
|
2330
|
+
if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
|
|
2331
|
+
_.label = op[1];
|
|
2332
|
+
break;
|
|
2333
|
+
}
|
|
2334
|
+
if (op[0] === 6 && _.label < t[1]) {
|
|
2335
|
+
_.label = t[1];
|
|
2336
|
+
t = op;
|
|
2337
|
+
break;
|
|
2338
|
+
}
|
|
2339
|
+
if (t && _.label < t[2]) {
|
|
2340
|
+
_.label = t[2];
|
|
2341
|
+
_.ops.push(op);
|
|
2342
|
+
break;
|
|
2343
|
+
}
|
|
2344
|
+
if (t[2]) _.ops.pop();
|
|
2345
|
+
_.trys.pop();
|
|
2346
|
+
continue;
|
|
2347
|
+
}
|
|
2348
|
+
op = body.call(thisArg, _);
|
|
2349
|
+
} catch (e) {
|
|
2350
|
+
op = [
|
|
2351
|
+
6,
|
|
2352
|
+
e
|
|
2353
|
+
];
|
|
2354
|
+
y = 0;
|
|
2355
|
+
} finally{
|
|
2356
|
+
f = t = 0;
|
|
2357
|
+
}
|
|
2358
|
+
if (op[0] & 5) throw op[1];
|
|
2359
|
+
return {
|
|
2360
|
+
value: op[0] ? op[1] : void 0,
|
|
2361
|
+
done: true
|
|
2362
|
+
};
|
|
2363
|
+
}
|
|
2364
|
+
}
|
|
2365
|
+
// MARK: Constants
|
|
2366
|
+
/**
|
|
2367
|
+
* Reserved tool name for the built-in `model-roles` static tool.
|
|
2368
|
+
*/ var MODEL_ROLES_TOOL_NAME = 'model-roles';
|
|
2369
|
+
/**
|
|
2370
|
+
* Synthetic call type used in the tool's dispatch identity. Distinct from `model-get`'s `get` so
|
|
2371
|
+
* visibility predicates can target the two independently.
|
|
2372
|
+
*/ var MODEL_ROLES_DISPATCH_CALL = 'roles';
|
|
2373
|
+
/**
|
|
2374
|
+
* Synthetic model type used in the tool's dispatch identity. Mirrors {@link MODEL_GET_DISPATCH_MODEL_TYPE}
|
|
2375
|
+
* — the tool isn't bound to one model type, so the literal "model" stands in.
|
|
2376
|
+
*/ var MODEL_ROLES_DISPATCH_MODEL_TYPE = 'model';
|
|
2377
|
+
/**
|
|
2378
|
+
* Maximum number of keys accepted per `model-roles` call. Role resolution runs the model's real
|
|
2379
|
+
* permission delegate per key (which may itself read parent documents), so this is deliberately
|
|
2380
|
+
* lower than the `model-get` batch size.
|
|
2381
|
+
*/ var MCP_MODEL_ROLES_MAX_KEYS = 25;
|
|
2382
|
+
// MARK: Factory
|
|
2383
|
+
/**
|
|
2384
|
+
* Builds the built-in `model-roles` MCP tool definition.
|
|
2385
|
+
*
|
|
2386
|
+
* Answers "what is this user actually allowed to do with this document?" by running the same
|
|
2387
|
+
* `roleMapForModel()` delegate the permission-checked read/write paths use, and returning the
|
|
2388
|
+
* resolved roles instead of consuming them. Because the model's real delegate runs, derived and
|
|
2389
|
+
* cascading roles appear exactly as the API grants them — there is no second implementation of the
|
|
2390
|
+
* rules to drift.
|
|
2391
|
+
*
|
|
2392
|
+
* Two things it disambiguates that a plain read cannot:
|
|
2393
|
+
* - **Missing vs. forbidden.** A key that resolves to a missing document returns
|
|
2394
|
+
* `exists: false, roles: []` rather than an error, so "the document is not there" reads
|
|
2395
|
+
* differently from "it is there and you have no access" (`exists: true, roles: []`).
|
|
2396
|
+
* - **Full access.** Admin short-circuits that grant the full-access marker come back as
|
|
2397
|
+
* `fullAccess: true` rather than as an opaque enumerated set.
|
|
2398
|
+
*
|
|
2399
|
+
* By default roles are resolved for the calling user. Passing `uid` resolves them for another user
|
|
2400
|
+
* and is gated behind {@link CreateModelRolesToolDeps.canTargetOtherUids}.
|
|
2401
|
+
*
|
|
2402
|
+
* @param deps - Role-map reader, identity resolver, and the target-uid authorization predicate.
|
|
2403
|
+
* @returns A statically-registered {@link McpToolDefinition} ready to be appended to the MCP
|
|
2404
|
+
* server factory's tool registry.
|
|
2405
|
+
*/ function createModelRolesTool(deps) {
|
|
2406
|
+
var handler = function handler(args, ctx) {
|
|
2407
|
+
return modelRolesToolHandler(args, ctx, deps);
|
|
2408
|
+
};
|
|
2409
|
+
var name = MODEL_ROLES_TOOL_NAME;
|
|
2410
|
+
var description = 'Resolve which roles the current user (or, with "uid", another user) is granted on one or more model keys — the same permission computation the API runs, returned instead of enforced. Use to answer "why was this forbidden?" and to tell a missing document (exists:false) apart from one you cannot access (exists:true, roles:[]). Admin full-access short-circuits report fullAccess:true. Targeting another uid requires elevated access.';
|
|
2411
|
+
return buildStaticToolDefinition({
|
|
2412
|
+
name: name,
|
|
2413
|
+
description: description,
|
|
2414
|
+
inputSchema: MODEL_ROLES_INPUT_SCHEMA,
|
|
2415
|
+
outputSchema: MODEL_ROLES_OUTPUT_SCHEMA,
|
|
2416
|
+
dispatch: {
|
|
2417
|
+
call: MODEL_ROLES_DISPATCH_CALL,
|
|
2418
|
+
modelType: MODEL_ROLES_DISPATCH_MODEL_TYPE
|
|
2419
|
+
},
|
|
2420
|
+
staticHandler: handler,
|
|
2421
|
+
effectiveReadOnly: true,
|
|
2422
|
+
rule: {
|
|
2423
|
+
requireAuthenticated: true
|
|
2424
|
+
}
|
|
2425
|
+
});
|
|
2426
|
+
}
|
|
2427
|
+
// MARK: Handler
|
|
2428
|
+
function modelRolesToolHandler(args, ctx, deps) {
|
|
1981
2429
|
return _async_to_generator$5(function() {
|
|
1982
|
-
var result, input, identity,
|
|
2430
|
+
var result, input, identity, targetUid, keys, resolved, error;
|
|
1983
2431
|
return _ts_generator$5(this, function(_state) {
|
|
1984
2432
|
switch(_state.label){
|
|
1985
2433
|
case 0:
|
|
1986
2434
|
_state.trys.push([
|
|
1987
2435
|
0,
|
|
1988
|
-
|
|
2436
|
+
3,
|
|
1989
2437
|
,
|
|
1990
|
-
|
|
2438
|
+
4
|
|
1991
2439
|
]);
|
|
1992
|
-
input =
|
|
2440
|
+
input = parseModelRolesInput(args);
|
|
1993
2441
|
identity = deps.resolveIdentity(input.modelType, ctx.auth);
|
|
1994
2442
|
if (identity == null) {
|
|
1995
2443
|
throw new Error("Unknown modelType: ".concat(input.modelType));
|
|
1996
2444
|
}
|
|
1997
|
-
resolvedKeys = resolveKeys(input.keys, identity);
|
|
1998
2445
|
return [
|
|
1999
2446
|
4,
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
keys: resolvedKeys,
|
|
2447
|
+
resolveTargetUid({
|
|
2448
|
+
requestedUid: input.uid,
|
|
2003
2449
|
auth: ctx.auth,
|
|
2004
|
-
|
|
2450
|
+
canTargetOtherUids: deps.canTargetOtherUids
|
|
2005
2451
|
})
|
|
2006
2452
|
];
|
|
2007
2453
|
case 1:
|
|
2008
|
-
|
|
2454
|
+
targetUid = _state.sent();
|
|
2455
|
+
keys = resolveKeys(input.keys, identity);
|
|
2456
|
+
return [
|
|
2457
|
+
4,
|
|
2458
|
+
deps.readRoleMaps(_object_spread$6({
|
|
2459
|
+
modelType: input.modelType,
|
|
2460
|
+
keys: keys,
|
|
2461
|
+
auth: ctx.auth
|
|
2462
|
+
}, targetUid == null ? {} : {
|
|
2463
|
+
targetUid: targetUid
|
|
2464
|
+
}))
|
|
2465
|
+
];
|
|
2466
|
+
case 2:
|
|
2467
|
+
resolved = _state.sent();
|
|
2009
2468
|
result = {
|
|
2010
2469
|
content: [
|
|
2011
2470
|
{
|
|
2012
2471
|
type: 'text',
|
|
2013
|
-
text: JSON.stringify(
|
|
2472
|
+
text: JSON.stringify(resolved)
|
|
2014
2473
|
}
|
|
2015
2474
|
],
|
|
2016
|
-
structuredContent:
|
|
2475
|
+
structuredContent: resolved
|
|
2017
2476
|
};
|
|
2018
2477
|
return [
|
|
2019
2478
|
3,
|
|
2020
|
-
|
|
2479
|
+
4
|
|
2021
2480
|
];
|
|
2022
|
-
case
|
|
2481
|
+
case 3:
|
|
2023
2482
|
error = _state.sent();
|
|
2024
2483
|
result = formatMcpToolErrorResponse(error);
|
|
2484
|
+
return [
|
|
2485
|
+
3,
|
|
2486
|
+
4
|
|
2487
|
+
];
|
|
2488
|
+
case 4:
|
|
2489
|
+
return [
|
|
2490
|
+
2,
|
|
2491
|
+
result
|
|
2492
|
+
];
|
|
2493
|
+
}
|
|
2494
|
+
});
|
|
2495
|
+
})();
|
|
2496
|
+
}
|
|
2497
|
+
/**
|
|
2498
|
+
* Resolves the effective target uid for a call, enforcing the elevated-access gate.
|
|
2499
|
+
*
|
|
2500
|
+
* Requesting your own uid is always allowed and is treated as no target at all, so a caller that
|
|
2501
|
+
* passes their own uid never trips the predicate.
|
|
2502
|
+
*
|
|
2503
|
+
* @param input - The requested uid, the caller's auth, and the authorization predicate.
|
|
2504
|
+
* @returns The uid to resolve as, or `undefined` to resolve as the caller.
|
|
2505
|
+
* @throws {Error} When another user's uid is requested and the predicate denies (or is absent).
|
|
2506
|
+
*/ function resolveTargetUid(input) {
|
|
2507
|
+
return _async_to_generator$5(function() {
|
|
2508
|
+
var requestedUid, auth, canTargetOtherUids, result, allowed, _tmp;
|
|
2509
|
+
return _ts_generator$5(this, function(_state) {
|
|
2510
|
+
switch(_state.label){
|
|
2511
|
+
case 0:
|
|
2512
|
+
requestedUid = input.requestedUid, auth = input.auth, canTargetOtherUids = input.canTargetOtherUids;
|
|
2513
|
+
if (!(requestedUid != null && requestedUid !== (auth === null || auth === void 0 ? void 0 : auth.uid))) return [
|
|
2514
|
+
3,
|
|
2515
|
+
4
|
|
2516
|
+
];
|
|
2517
|
+
if (!(canTargetOtherUids == null)) return [
|
|
2518
|
+
3,
|
|
2519
|
+
1
|
|
2520
|
+
];
|
|
2521
|
+
_tmp = false;
|
|
2025
2522
|
return [
|
|
2026
2523
|
3,
|
|
2027
2524
|
3
|
|
2028
2525
|
];
|
|
2526
|
+
case 1:
|
|
2527
|
+
return [
|
|
2528
|
+
4,
|
|
2529
|
+
canTargetOtherUids(auth)
|
|
2530
|
+
];
|
|
2531
|
+
case 2:
|
|
2532
|
+
_tmp = _state.sent();
|
|
2533
|
+
_state.label = 3;
|
|
2029
2534
|
case 3:
|
|
2535
|
+
allowed = _tmp;
|
|
2536
|
+
if (!allowed) {
|
|
2537
|
+
throw new Error("model-roles: resolving roles for another user's uid requires elevated access.");
|
|
2538
|
+
}
|
|
2539
|
+
result = requestedUid;
|
|
2540
|
+
_state.label = 4;
|
|
2541
|
+
case 4:
|
|
2030
2542
|
return [
|
|
2031
2543
|
2,
|
|
2032
2544
|
result
|
|
@@ -2035,25 +2547,34 @@ function modelGetToolHandler(args, ctx, deps) {
|
|
|
2035
2547
|
});
|
|
2036
2548
|
})();
|
|
2037
2549
|
}
|
|
2038
|
-
function
|
|
2039
|
-
var modelType = args
|
|
2040
|
-
var keys = args
|
|
2550
|
+
function parseModelRolesInput(args) {
|
|
2551
|
+
var modelType = args['modelType'];
|
|
2552
|
+
var keys = args['keys'];
|
|
2553
|
+
var uid = args['uid'];
|
|
2041
2554
|
if (typeof modelType !== 'string' || modelType.length === 0) {
|
|
2042
|
-
throw new Error('model-
|
|
2555
|
+
throw new Error('model-roles: "modelType" is required and must be a non-empty string.');
|
|
2043
2556
|
}
|
|
2044
2557
|
if (!Array.isArray(keys) || keys.length === 0) {
|
|
2045
|
-
throw new Error('model-
|
|
2558
|
+
throw new Error('model-roles: "keys" is required and must be a non-empty array.');
|
|
2559
|
+
}
|
|
2560
|
+
if (keys.length > MCP_MODEL_ROLES_MAX_KEYS) {
|
|
2561
|
+
throw new Error("model-roles: at most ".concat(MCP_MODEL_ROLES_MAX_KEYS, " keys may be resolved per call (received ").concat(keys.length, ")."));
|
|
2562
|
+
}
|
|
2563
|
+
if (uid !== undefined && (typeof uid !== 'string' || uid.length === 0)) {
|
|
2564
|
+
throw new Error('model-roles: "uid" must be a non-empty string when provided.');
|
|
2046
2565
|
}
|
|
2047
2566
|
var normalizedKeys = keys.map(function(value, index) {
|
|
2048
2567
|
if (typeof value !== 'string' || value.length === 0) {
|
|
2049
|
-
throw new Error("model-
|
|
2568
|
+
throw new Error("model-roles: keys[".concat(index, "] must be a non-empty string."));
|
|
2050
2569
|
}
|
|
2051
2570
|
return value;
|
|
2052
2571
|
});
|
|
2053
|
-
return {
|
|
2572
|
+
return _object_spread$6({
|
|
2054
2573
|
modelType: modelType,
|
|
2055
2574
|
keys: normalizedKeys
|
|
2056
|
-
}
|
|
2575
|
+
}, uid === undefined ? {} : {
|
|
2576
|
+
uid: uid
|
|
2577
|
+
});
|
|
2057
2578
|
}
|
|
2058
2579
|
function resolveKeys(keys, identity) {
|
|
2059
2580
|
var isRoot = identity.type === 'root';
|
|
@@ -2067,7 +2588,7 @@ function resolveKeys(keys, identity) {
|
|
|
2067
2588
|
} else if (isRoot) {
|
|
2068
2589
|
resolved.push("".concat(identity.collectionName, "/").concat(value));
|
|
2069
2590
|
} else {
|
|
2070
|
-
throw new Error('model-
|
|
2591
|
+
throw new Error('model-roles: modelType "'.concat(identity.modelType, '" is a subcollection; bare ids are not allowed. Provide full keys (e.g. "parentPrefix/parentId/').concat(identity.collectionName, "/").concat(value, '").'));
|
|
2071
2592
|
}
|
|
2072
2593
|
}
|
|
2073
2594
|
} catch (err) {
|
|
@@ -2086,51 +2607,8 @@ function resolveKeys(keys, identity) {
|
|
|
2086
2607
|
}
|
|
2087
2608
|
return resolved;
|
|
2088
2609
|
}
|
|
2089
|
-
function readInChunks$1(input) {
|
|
2090
|
-
return _async_to_generator$5(function() {
|
|
2091
|
-
var modelType, keys, auth, readDocuments, merged, offset, _merged_results, _merged_errors, batch, partial;
|
|
2092
|
-
return _ts_generator$5(this, function(_state) {
|
|
2093
|
-
switch(_state.label){
|
|
2094
|
-
case 0:
|
|
2095
|
-
modelType = input.modelType, keys = input.keys, auth = input.auth, readDocuments = input.readDocuments;
|
|
2096
|
-
merged = {
|
|
2097
|
-
results: [],
|
|
2098
|
-
errors: []
|
|
2099
|
-
};
|
|
2100
|
-
offset = 0;
|
|
2101
|
-
_state.label = 1;
|
|
2102
|
-
case 1:
|
|
2103
|
-
if (!(offset < keys.length)) return [
|
|
2104
|
-
3,
|
|
2105
|
-
4
|
|
2106
|
-
];
|
|
2107
|
-
batch = keys.slice(offset, offset + MCP_MODEL_GET_BATCH_SIZE);
|
|
2108
|
-
return [
|
|
2109
|
-
4,
|
|
2110
|
-
readDocuments(modelType, batch, auth)
|
|
2111
|
-
];
|
|
2112
|
-
case 2:
|
|
2113
|
-
partial = _state.sent();
|
|
2114
|
-
(_merged_results = merged.results).push.apply(_merged_results, _to_consumable_array$7(partial.results));
|
|
2115
|
-
(_merged_errors = merged.errors).push.apply(_merged_errors, _to_consumable_array$7(partial.errors));
|
|
2116
|
-
_state.label = 3;
|
|
2117
|
-
case 3:
|
|
2118
|
-
offset += MCP_MODEL_GET_BATCH_SIZE;
|
|
2119
|
-
return [
|
|
2120
|
-
3,
|
|
2121
|
-
1
|
|
2122
|
-
];
|
|
2123
|
-
case 4:
|
|
2124
|
-
return [
|
|
2125
|
-
2,
|
|
2126
|
-
merged
|
|
2127
|
-
];
|
|
2128
|
-
}
|
|
2129
|
-
});
|
|
2130
|
-
})();
|
|
2131
|
-
}
|
|
2132
2610
|
// MARK: Schemas
|
|
2133
|
-
var
|
|
2611
|
+
var MODEL_ROLES_INPUT_SCHEMA = {
|
|
2134
2612
|
type: 'object',
|
|
2135
2613
|
required: [
|
|
2136
2614
|
'modelType',
|
|
@@ -2140,47 +2618,78 @@ var MODEL_GET_INPUT_SCHEMA = {
|
|
|
2140
2618
|
modelType: {
|
|
2141
2619
|
type: 'string',
|
|
2142
2620
|
minLength: 1,
|
|
2143
|
-
description: 'Firestore model type to
|
|
2621
|
+
description: 'Firestore model type to resolve roles on (e.g. "guestbook", "profile").'
|
|
2144
2622
|
},
|
|
2145
2623
|
keys: {
|
|
2146
2624
|
type: 'array',
|
|
2147
2625
|
minItems: 1,
|
|
2626
|
+
maxItems: MCP_MODEL_ROLES_MAX_KEYS,
|
|
2148
2627
|
description: 'Full keys ("prefix/id") or bare ids (root models only).',
|
|
2149
2628
|
items: {
|
|
2150
2629
|
type: 'string',
|
|
2151
2630
|
minLength: 1
|
|
2152
2631
|
}
|
|
2632
|
+
},
|
|
2633
|
+
uid: {
|
|
2634
|
+
type: 'string',
|
|
2635
|
+
minLength: 1,
|
|
2636
|
+
description: 'Resolve roles as this user instead of the caller. Requires elevated access; passing your own uid is always allowed.'
|
|
2153
2637
|
}
|
|
2154
2638
|
},
|
|
2155
2639
|
additionalProperties: false
|
|
2156
2640
|
};
|
|
2157
|
-
var
|
|
2641
|
+
var MODEL_ROLES_OUTPUT_SCHEMA = {
|
|
2158
2642
|
type: 'object',
|
|
2159
2643
|
required: [
|
|
2644
|
+
'targeted',
|
|
2160
2645
|
'results',
|
|
2161
2646
|
'errors'
|
|
2162
2647
|
],
|
|
2163
2648
|
properties: {
|
|
2649
|
+
uid: {
|
|
2650
|
+
type: 'string',
|
|
2651
|
+
description: 'The uid the roles were resolved for.'
|
|
2652
|
+
},
|
|
2653
|
+
targeted: {
|
|
2654
|
+
type: 'boolean',
|
|
2655
|
+
description: 'True when the roles were resolved for a user other than the caller.'
|
|
2656
|
+
},
|
|
2164
2657
|
results: {
|
|
2165
2658
|
type: 'array',
|
|
2166
|
-
description: 'Per-key
|
|
2659
|
+
description: 'Per-key resolved permission state.',
|
|
2167
2660
|
items: {
|
|
2168
2661
|
type: 'object',
|
|
2169
2662
|
required: [
|
|
2170
2663
|
'key',
|
|
2171
|
-
'
|
|
2664
|
+
'exists',
|
|
2665
|
+
'fullAccess',
|
|
2666
|
+
'roles'
|
|
2172
2667
|
],
|
|
2173
2668
|
properties: {
|
|
2174
2669
|
key: {
|
|
2175
2670
|
type: 'string'
|
|
2176
2671
|
},
|
|
2177
|
-
|
|
2672
|
+
exists: {
|
|
2673
|
+
type: 'boolean',
|
|
2674
|
+
description: 'Whether the document exists. Roles are only computed for documents that exist.'
|
|
2675
|
+
},
|
|
2676
|
+
fullAccess: {
|
|
2677
|
+
type: 'boolean',
|
|
2678
|
+
description: 'True when the full-access marker was granted; every role is implicitly held and "roles" is empty.'
|
|
2679
|
+
},
|
|
2680
|
+
roles: {
|
|
2681
|
+
type: 'array',
|
|
2682
|
+
items: {
|
|
2683
|
+
type: 'string'
|
|
2684
|
+
},
|
|
2685
|
+
description: 'Granted role names, sorted.'
|
|
2686
|
+
}
|
|
2178
2687
|
}
|
|
2179
2688
|
}
|
|
2180
2689
|
},
|
|
2181
2690
|
errors: {
|
|
2182
2691
|
type: 'array',
|
|
2183
|
-
description: 'Per-key failures
|
|
2692
|
+
description: 'Per-key failures. A missing document is NOT an error — it appears in results with exists:false.',
|
|
2184
2693
|
items: {
|
|
2185
2694
|
type: 'object',
|
|
2186
2695
|
required: [
|
|
@@ -2938,7 +3447,7 @@ var MODEL_ROW_SCHEMA = {
|
|
|
2938
3447
|
}
|
|
2939
3448
|
};
|
|
2940
3449
|
// MCP's `tools/list` validator requires `outputSchema.type === 'object'` at the root
|
|
2941
|
-
// (see
|
|
3450
|
+
// (see the MCP SDK's `ToolSchema`), so the variants are expressed via a top-level
|
|
2942
3451
|
// object whose nested `oneOf` discriminates by the `mode` literal.
|
|
2943
3452
|
var MODEL_INFO_OUTPUT_SCHEMA = {
|
|
2944
3453
|
type: 'object',
|
|
@@ -3740,7 +4249,7 @@ function whoamiToolHandler(args, ctx, deps) {
|
|
|
3740
4249
|
}
|
|
3741
4250
|
// Coerces the `detail` input into a WhoamiDetailLevel, defaulting unknown or absent values to `summary`.
|
|
3742
4251
|
function parseDetailLevel(args) {
|
|
3743
|
-
var value = args
|
|
4252
|
+
var value = args['detail'];
|
|
3744
4253
|
return value === 'claims' || value === 'full' ? value : 'summary';
|
|
3745
4254
|
}
|
|
3746
4255
|
function buildResult(output, text) {
|
|
@@ -4335,30 +4844,30 @@ function urlModelsToolHandler(args, ctx, deps) {
|
|
|
4335
4844
|
})();
|
|
4336
4845
|
}
|
|
4337
4846
|
function parseUrlModelsInput(args) {
|
|
4338
|
-
var url = args
|
|
4847
|
+
var url = args['url'];
|
|
4339
4848
|
if (typeof url !== 'string' || url.length === 0) {
|
|
4340
4849
|
throw new Error('url-models: "url" is required and must be a non-empty string.');
|
|
4341
4850
|
}
|
|
4342
|
-
var keysOnly = args
|
|
4343
|
-
var load = args
|
|
4851
|
+
var keysOnly = args['keysOnly'] === true;
|
|
4852
|
+
var load = args['load'] === true;
|
|
4344
4853
|
if (keysOnly && load) {
|
|
4345
4854
|
throw new Error('url-models: "keysOnly" and "load" cannot be combined — "keysOnly" returns keys without loading documents.');
|
|
4346
4855
|
}
|
|
4347
4856
|
var models;
|
|
4348
|
-
if (args
|
|
4349
|
-
if (!Array.isArray(args
|
|
4857
|
+
if (args['models'] !== undefined) {
|
|
4858
|
+
if (!Array.isArray(args['models']) || args['models'].some(function(m) {
|
|
4350
4859
|
return typeof m !== 'string';
|
|
4351
4860
|
})) {
|
|
4352
4861
|
throw new Error('url-models: "models" must be an array of model-type strings.');
|
|
4353
4862
|
}
|
|
4354
|
-
models = args
|
|
4863
|
+
models = args['models'];
|
|
4355
4864
|
}
|
|
4356
4865
|
var currentUserUid;
|
|
4357
|
-
if (args
|
|
4358
|
-
if (typeof args
|
|
4866
|
+
if (args['currentUserUid'] !== undefined) {
|
|
4867
|
+
if (typeof args['currentUserUid'] !== 'string' || args['currentUserUid'].length === 0) {
|
|
4359
4868
|
throw new Error('url-models: "currentUserUid" must be a non-empty string.');
|
|
4360
4869
|
}
|
|
4361
|
-
currentUserUid = args
|
|
4870
|
+
currentUserUid = args['currentUserUid'];
|
|
4362
4871
|
}
|
|
4363
4872
|
return _object_spread$2(_object_spread_props$1(_object_spread$2({
|
|
4364
4873
|
url: url
|
|
@@ -5306,19 +5815,19 @@ function batchExecuteToolHandler(args, ctx, deps) {
|
|
|
5306
5815
|
// MARK: Input parsing
|
|
5307
5816
|
function parseBatchExecuteInput(args) {
|
|
5308
5817
|
var _args_format, _args_maxParallel;
|
|
5309
|
-
var uploadPath = args
|
|
5818
|
+
var uploadPath = args['uploadPath'];
|
|
5310
5819
|
if (typeof uploadPath !== 'string' || uploadPath.length === 0) {
|
|
5311
5820
|
throw new Error('batch-execute: "uploadPath" is required and must be a non-empty string.');
|
|
5312
5821
|
}
|
|
5313
|
-
var bucketId = args
|
|
5822
|
+
var bucketId = args['bucketId'];
|
|
5314
5823
|
if (bucketId != null && (typeof bucketId !== 'string' || bucketId.length === 0)) {
|
|
5315
5824
|
throw new Error('batch-execute: "bucketId" must be a non-empty string when provided.');
|
|
5316
5825
|
}
|
|
5317
|
-
var format = (_args_format = args
|
|
5826
|
+
var format = (_args_format = args['format']) !== null && _args_format !== void 0 ? _args_format : 'ndjson';
|
|
5318
5827
|
if (format !== 'json' && format !== 'ndjson') {
|
|
5319
5828
|
throw new Error('batch-execute: "format" must be "json" or "ndjson".');
|
|
5320
5829
|
}
|
|
5321
|
-
var maxParallel = (_args_maxParallel = args
|
|
5830
|
+
var maxParallel = (_args_maxParallel = args['maxParallel']) !== null && _args_maxParallel !== void 0 ? _args_maxParallel : DEFAULT_BATCH_EXECUTE_MAX_PARALLEL;
|
|
5322
5831
|
if (typeof maxParallel !== 'number' || !Number.isInteger(maxParallel) || maxParallel < 1) {
|
|
5323
5832
|
throw new Error('batch-execute: "maxParallel" must be a positive integer.');
|
|
5324
5833
|
}
|
|
@@ -5327,8 +5836,8 @@ function parseBatchExecuteInput(args) {
|
|
|
5327
5836
|
bucketId: bucketId !== null && bucketId !== void 0 ? bucketId : undefined,
|
|
5328
5837
|
format: format,
|
|
5329
5838
|
maxParallel: maxParallel,
|
|
5330
|
-
stopOnError: args
|
|
5331
|
-
deleteUploadOnSuccess: args
|
|
5839
|
+
stopOnError: args['stopOnError'] === true,
|
|
5840
|
+
deleteUploadOnSuccess: args['deleteUploadOnSuccess'] !== false
|
|
5332
5841
|
};
|
|
5333
5842
|
}
|
|
5334
5843
|
function readOperationsFile(input) {
|
|
@@ -5409,9 +5918,9 @@ function validateOperation(value, index) {
|
|
|
5409
5918
|
throw new Error("batch-execute: operation[".concat(index, "] must be an object."));
|
|
5410
5919
|
}
|
|
5411
5920
|
var candidate = value;
|
|
5412
|
-
var modelType = candidate
|
|
5413
|
-
var call = candidate
|
|
5414
|
-
var specifier = candidate
|
|
5921
|
+
var modelType = candidate['modelType'];
|
|
5922
|
+
var call = candidate['call'];
|
|
5923
|
+
var specifier = candidate['specifier'];
|
|
5415
5924
|
if (typeof modelType !== 'string' || modelType.length === 0) {
|
|
5416
5925
|
throw new Error("batch-execute: operation[".concat(index, '] is missing a non-empty "modelType".'));
|
|
5417
5926
|
}
|
|
@@ -5425,7 +5934,7 @@ function validateOperation(value, index) {
|
|
|
5425
5934
|
call: call,
|
|
5426
5935
|
modelType: modelType,
|
|
5427
5936
|
specifier: specifier !== null && specifier !== void 0 ? specifier : undefined,
|
|
5428
|
-
data: candidate
|
|
5937
|
+
data: candidate['data']
|
|
5429
5938
|
};
|
|
5430
5939
|
}
|
|
5431
5940
|
function collectPreflightErrors(operations, authorizeOperation) {
|
|
@@ -6053,17 +6562,19 @@ var McpServerFactoryService_1;
|
|
|
6053
6562
|
* Injectable factory that builds {@link McpServer} instances pre-wired to the
|
|
6054
6563
|
* call model dispatch chain.
|
|
6055
6564
|
*
|
|
6056
|
-
* The factory is invoked per Streamable HTTP request
|
|
6057
|
-
*
|
|
6058
|
-
*
|
|
6565
|
+
* The factory is invoked per Streamable HTTP request. That is the shape the MCP
|
|
6566
|
+
* SDK's 2026-07-28 entry (`createMcpHandler`) requires — it builds a fresh server
|
|
6567
|
+
* per request and has no session concept at all — and it is equally what the SDK
|
|
6568
|
+
* recommends for stateless 2025-era serving, so one factory backs both eras.
|
|
6059
6569
|
*/ var McpServerFactoryService = McpServerFactoryService_1 = /*#__PURE__*/ function() {
|
|
6060
|
-
function McpServerFactoryService(mcpConfig, dispatchService, modelApiGetService, roleReader, analyticsService, storageService) {
|
|
6570
|
+
function McpServerFactoryService(mcpConfig, dispatchService, modelApiGetService, roleReader, analyticsService, storageService, modelRolesTargetUidPredicate) {
|
|
6061
6571
|
_class_call_check$3(this, McpServerFactoryService);
|
|
6062
6572
|
_define_property$3(this, "mcpConfig", void 0);
|
|
6063
6573
|
_define_property$3(this, "dispatchService", void 0);
|
|
6064
6574
|
_define_property$3(this, "modelApiGetService", void 0);
|
|
6065
6575
|
_define_property$3(this, "roleReader", void 0);
|
|
6066
6576
|
_define_property$3(this, "storageService", void 0);
|
|
6577
|
+
_define_property$3(this, "modelRolesTargetUidPredicate", void 0);
|
|
6067
6578
|
_define_property$3(this, "_logger", new Logger(McpServerFactoryService_1.name));
|
|
6068
6579
|
_define_property$3(this, "_cachedTools", void 0);
|
|
6069
6580
|
_define_property$3(this, "_cachedStaticTools", void 0);
|
|
@@ -6083,6 +6594,7 @@ var McpServerFactoryService_1;
|
|
|
6083
6594
|
this.modelApiGetService = modelApiGetService;
|
|
6084
6595
|
this.roleReader = roleReader;
|
|
6085
6596
|
this.storageService = storageService;
|
|
6597
|
+
this.modelRolesTargetUidPredicate = modelRolesTargetUidPredicate;
|
|
6086
6598
|
this._analyticsService = analyticsService !== null && analyticsService !== void 0 ? analyticsService : noopMcpAnalyticsService();
|
|
6087
6599
|
}
|
|
6088
6600
|
_create_class$3(McpServerFactoryService, [
|
|
@@ -6133,7 +6645,7 @@ var McpServerFactoryService_1;
|
|
|
6133
6645
|
batchTool
|
|
6134
6646
|
]);
|
|
6135
6647
|
}
|
|
6136
|
-
server.server.setRequestHandler(
|
|
6648
|
+
server.server.setRequestHandler('tools/list', function() {
|
|
6137
6649
|
return _async_to_generator$2(function() {
|
|
6138
6650
|
var _this;
|
|
6139
6651
|
return _ts_generator$2(this, function(_state) {
|
|
@@ -6141,6 +6653,10 @@ var McpServerFactoryService_1;
|
|
|
6141
6653
|
return [
|
|
6142
6654
|
2,
|
|
6143
6655
|
{
|
|
6656
|
+
// McpToolListEntry types its schemas as opaque `object`: they are read from a manifest file
|
|
6657
|
+
// or produced by arktype's JSON Schema export, so the `type: 'object'` root the SDK's wire
|
|
6658
|
+
// type mandates holds at runtime but cannot be proven statically. Every schema reaching here
|
|
6659
|
+
// either came from arktypeToJsonSchemaForExport or defaulted to `{ type: 'object' }`.
|
|
6144
6660
|
tools: listedTools.map(function(tool) {
|
|
6145
6661
|
return _this._buildToolListEntry(tool, ctx, scopes);
|
|
6146
6662
|
})
|
|
@@ -6149,7 +6665,7 @@ var McpServerFactoryService_1;
|
|
|
6149
6665
|
});
|
|
6150
6666
|
}).call(_this);
|
|
6151
6667
|
});
|
|
6152
|
-
server.server.setRequestHandler(
|
|
6668
|
+
server.server.setRequestHandler('tools/call', function(request) {
|
|
6153
6669
|
return _async_to_generator$2(function() {
|
|
6154
6670
|
return _ts_generator$2(this, function(_state) {
|
|
6155
6671
|
return [
|
|
@@ -6349,6 +6865,14 @@ var McpServerFactoryService_1;
|
|
|
6349
6865
|
resolveIdentity: function resolveIdentity(modelType, auth) {
|
|
6350
6866
|
return getService.getModelIdentity(modelType, auth);
|
|
6351
6867
|
}
|
|
6868
|
+
}), createModelRolesTool({
|
|
6869
|
+
readRoleMaps: function readRoleMaps(params) {
|
|
6870
|
+
return getService.readRoleMaps(params);
|
|
6871
|
+
},
|
|
6872
|
+
resolveIdentity: function resolveIdentity(modelType, auth) {
|
|
6873
|
+
return getService.getModelIdentity(modelType, auth);
|
|
6874
|
+
},
|
|
6875
|
+
canTargetOtherUids: this.modelRolesTargetUidPredicate
|
|
6352
6876
|
}));
|
|
6353
6877
|
// `url-models` reuses the model-get read/identity path, so it is only offered when the get
|
|
6354
6878
|
// service is wired AND a route manifest with at least one state was loaded.
|
|
@@ -7102,7 +7626,9 @@ McpServerFactoryService = McpServerFactoryService_1 = __decorate([
|
|
|
7102
7626
|
__param(4, Optional()),
|
|
7103
7627
|
__param(4, Inject(MCP_ANALYTICS_SERVICE)),
|
|
7104
7628
|
__param(5, Optional()),
|
|
7105
|
-
__param(5, Inject(FirebaseServerStorageService))
|
|
7629
|
+
__param(5, Inject(FirebaseServerStorageService)),
|
|
7630
|
+
__param(6, Optional()),
|
|
7631
|
+
__param(6, Inject(MCP_MODEL_ROLES_TARGET_UID_PREDICATE))
|
|
7106
7632
|
], McpServerFactoryService);
|
|
7107
7633
|
|
|
7108
7634
|
function asyncGeneratorStep$1(gen, resolve, reject, _next, _throw, key, arg) {
|
|
@@ -7234,29 +7760,168 @@ function _ts_generator$1(thisArg, body) {
|
|
|
7234
7760
|
}
|
|
7235
7761
|
}
|
|
7236
7762
|
/**
|
|
7237
|
-
* Handles a single Streamable HTTP JSON-RPC request
|
|
7763
|
+
* Handles a single Streamable HTTP JSON-RPC request, building a fresh MCP server for it.
|
|
7764
|
+
*
|
|
7765
|
+
* Both protocol eras are served, each by its own leg:
|
|
7238
7766
|
*
|
|
7239
|
-
*
|
|
7240
|
-
*
|
|
7241
|
-
*
|
|
7242
|
-
*
|
|
7767
|
+
* - **2026-07-28 (modern)** — `createMcpHandler`, which is per-request and stateless by
|
|
7768
|
+
* construction: there is no `Mcp-Session-Id` and no transport bookkeeping.
|
|
7769
|
+
* - **2025-era (legacy)** — a `NodeStreamableHTTPServerTransport` in stateless mode, which is
|
|
7770
|
+
* byte-for-byte what this endpoint served before the SDK v2 upgrade.
|
|
7771
|
+
*
|
|
7772
|
+
* The legacy leg is wired by hand (the SDK's documented `isLegacyRequest` composition) rather
|
|
7773
|
+
* than left to `createMcpHandler`'s built-in `legacy: 'stateless'` fallback, because that
|
|
7774
|
+
* fallback builds its transport with `sessionIdGenerator` alone and therefore answers in
|
|
7775
|
+
* `text/event-stream`. See {@link handleLegacyMcpRequest} for why that framing is not viable
|
|
7776
|
+
* here.
|
|
7243
7777
|
*
|
|
7244
7778
|
* The caller is expected to have already validated the bearer token (via the
|
|
7245
7779
|
* OIDC bearer middleware) before this function runs.
|
|
7246
7780
|
*
|
|
7247
7781
|
* @param req - The Express request carrying the JSON-RPC body.
|
|
7248
7782
|
* @param res - The Express response.
|
|
7783
|
+
* @param buildServer - Factory producing the MCP server that backs this request.
|
|
7784
|
+
*/ function handleStreamableHttpMcpRequest(req, res, buildServer) {
|
|
7785
|
+
return _async_to_generator$1(function() {
|
|
7786
|
+
var probe;
|
|
7787
|
+
return _ts_generator$1(this, function(_state) {
|
|
7788
|
+
switch(_state.label){
|
|
7789
|
+
case 0:
|
|
7790
|
+
// Hand-wired compositions must reject non-JSON POST bodies themselves — neither the modern
|
|
7791
|
+
// entry's routing nor the legacy transport does it on our behalf once we classify up front.
|
|
7792
|
+
if (!isJsonContentType(req.headers['content-type'])) {
|
|
7793
|
+
res.status(415).json({
|
|
7794
|
+
statusCode: 415,
|
|
7795
|
+
message: 'Unsupported Media Type'
|
|
7796
|
+
});
|
|
7797
|
+
return [
|
|
7798
|
+
2
|
|
7799
|
+
];
|
|
7800
|
+
}
|
|
7801
|
+
return [
|
|
7802
|
+
4,
|
|
7803
|
+
toWebRequest(req, req.body)
|
|
7804
|
+
];
|
|
7805
|
+
case 1:
|
|
7806
|
+
probe = _state.sent();
|
|
7807
|
+
return [
|
|
7808
|
+
4,
|
|
7809
|
+
isLegacyRequest(probe)
|
|
7810
|
+
];
|
|
7811
|
+
case 2:
|
|
7812
|
+
if (!_state.sent()) return [
|
|
7813
|
+
3,
|
|
7814
|
+
4
|
|
7815
|
+
];
|
|
7816
|
+
return [
|
|
7817
|
+
4,
|
|
7818
|
+
handleLegacyMcpRequest(req, res, buildServer())
|
|
7819
|
+
];
|
|
7820
|
+
case 3:
|
|
7821
|
+
_state.sent();
|
|
7822
|
+
return [
|
|
7823
|
+
3,
|
|
7824
|
+
6
|
|
7825
|
+
];
|
|
7826
|
+
case 4:
|
|
7827
|
+
return [
|
|
7828
|
+
4,
|
|
7829
|
+
handleModernMcpRequest(req, res, buildServer)
|
|
7830
|
+
];
|
|
7831
|
+
case 5:
|
|
7832
|
+
_state.sent();
|
|
7833
|
+
_state.label = 6;
|
|
7834
|
+
case 6:
|
|
7835
|
+
return [
|
|
7836
|
+
2
|
|
7837
|
+
];
|
|
7838
|
+
}
|
|
7839
|
+
});
|
|
7840
|
+
})();
|
|
7841
|
+
}
|
|
7842
|
+
/**
|
|
7843
|
+
* Serves one 2026-07-28 request through `createMcpHandler`.
|
|
7844
|
+
*
|
|
7845
|
+
* `legacy: 'reject'` keeps this leg modern-only — 2025-era traffic never reaches it, having
|
|
7846
|
+
* already been routed to {@link handleLegacyMcpRequest}.
|
|
7847
|
+
*
|
|
7848
|
+
* `responseMode: 'json'` is the modern-leg equivalent of the legacy transport's
|
|
7849
|
+
* `enableJsonResponse`, keeping the endpoint on a single `application/json` body. Safe here
|
|
7850
|
+
* because no tool handler emits mid-call notifications, which are the only thing `'json'` drops.
|
|
7851
|
+
*
|
|
7852
|
+
* @param req - The Express request carrying the JSON-RPC body.
|
|
7853
|
+
* @param res - The Express response.
|
|
7854
|
+
* @param buildServer - Factory producing the MCP server that backs this request.
|
|
7855
|
+
*/ function handleModernMcpRequest(req, res, buildServer) {
|
|
7856
|
+
return _async_to_generator$1(function() {
|
|
7857
|
+
var handler;
|
|
7858
|
+
return _ts_generator$1(this, function(_state) {
|
|
7859
|
+
switch(_state.label){
|
|
7860
|
+
case 0:
|
|
7861
|
+
handler = createMcpHandler(buildServer, {
|
|
7862
|
+
legacy: 'reject',
|
|
7863
|
+
responseMode: 'json'
|
|
7864
|
+
});
|
|
7865
|
+
_state.label = 1;
|
|
7866
|
+
case 1:
|
|
7867
|
+
_state.trys.push([
|
|
7868
|
+
1,
|
|
7869
|
+
,
|
|
7870
|
+
3,
|
|
7871
|
+
5
|
|
7872
|
+
]);
|
|
7873
|
+
return [
|
|
7874
|
+
4,
|
|
7875
|
+
toNodeHandler(handler)(req, res, req.body)
|
|
7876
|
+
];
|
|
7877
|
+
case 2:
|
|
7878
|
+
_state.sent();
|
|
7879
|
+
return [
|
|
7880
|
+
3,
|
|
7881
|
+
5
|
|
7882
|
+
];
|
|
7883
|
+
case 3:
|
|
7884
|
+
return [
|
|
7885
|
+
4,
|
|
7886
|
+
handler.close()
|
|
7887
|
+
];
|
|
7888
|
+
case 4:
|
|
7889
|
+
_state.sent();
|
|
7890
|
+
return [
|
|
7891
|
+
7
|
|
7892
|
+
];
|
|
7893
|
+
case 5:
|
|
7894
|
+
return [
|
|
7895
|
+
2
|
|
7896
|
+
];
|
|
7897
|
+
}
|
|
7898
|
+
});
|
|
7899
|
+
})();
|
|
7900
|
+
}
|
|
7901
|
+
/**
|
|
7902
|
+
* Serves one 2025-era request through a stateless `NodeStreamableHTTPServerTransport`.
|
|
7903
|
+
*
|
|
7904
|
+
* `sessionIdGenerator: undefined` selects stateless mode: the transport binds the server,
|
|
7905
|
+
* processes one request, and is discarded.
|
|
7906
|
+
*
|
|
7907
|
+
* `enableJsonResponse: true` replies with a single `application/json` body instead of framing it
|
|
7908
|
+
* as `text/event-stream`. Stateless mode answers exactly one JSON-RPC message per request and the
|
|
7909
|
+
* controller only implements POST (there is no standalone SSE stream to keep open), so SSE framing
|
|
7910
|
+
* adds nothing while making the endpoint fragile behind proxies that buffer or rewrite streamed
|
|
7911
|
+
* responses — the failure that originally pushed the demo app off its dev proxy.
|
|
7912
|
+
*
|
|
7913
|
+
* @param req - The Express request carrying the JSON-RPC body.
|
|
7914
|
+
* @param res - The Express response.
|
|
7249
7915
|
* @param server - The MCP server instance to back the transport.
|
|
7250
|
-
|
|
7251
|
-
*/ function handleStreamableHttpMcpRequest(req, res, server) {
|
|
7916
|
+
*/ function handleLegacyMcpRequest(req, res, server) {
|
|
7252
7917
|
return _async_to_generator$1(function() {
|
|
7253
7918
|
var transport;
|
|
7254
7919
|
return _ts_generator$1(this, function(_state) {
|
|
7255
7920
|
switch(_state.label){
|
|
7256
7921
|
case 0:
|
|
7257
|
-
|
|
7258
|
-
|
|
7259
|
-
|
|
7922
|
+
transport = new NodeStreamableHTTPServerTransport({
|
|
7923
|
+
sessionIdGenerator: undefined,
|
|
7924
|
+
enableJsonResponse: true
|
|
7260
7925
|
});
|
|
7261
7926
|
res.on('close', function() {
|
|
7262
7927
|
void transport.close();
|
|
@@ -7448,9 +8113,11 @@ var McpController_1;
|
|
|
7448
8113
|
* which must include `'/mcp'` in its `protectedPaths`. By the time the request reaches
|
|
7449
8114
|
* this controller, `req.auth` is populated with the authenticated user's data.
|
|
7450
8115
|
*
|
|
7451
|
-
* Each request gets a fresh
|
|
7452
|
-
*
|
|
7453
|
-
*
|
|
8116
|
+
* Each request gets a fresh MCP server (stateless mode), which is adequate for Claude
|
|
8117
|
+
* custom-connector style usage. Both protocol eras are served — 2026-07-28 through the
|
|
8118
|
+
* SDK's per-request `createMcpHandler` entry, and 2025-era through a stateless Streamable
|
|
8119
|
+
* HTTP transport. A session-tracked variant can be layered on later if streaming tool
|
|
8120
|
+
* output becomes a requirement.
|
|
7454
8121
|
*/ var McpController = McpController_1 = /*#__PURE__*/ function() {
|
|
7455
8122
|
function McpController(factory) {
|
|
7456
8123
|
_class_call_check$2(this, McpController);
|
|
@@ -7463,15 +8130,12 @@ var McpController_1;
|
|
|
7463
8130
|
key: "handleMcpRequest",
|
|
7464
8131
|
value: function handleMcpRequest(req, res) {
|
|
7465
8132
|
return _async_to_generator(function() {
|
|
7466
|
-
var
|
|
8133
|
+
var _this, auth, error;
|
|
7467
8134
|
return _ts_generator(this, function(_state) {
|
|
7468
8135
|
switch(_state.label){
|
|
7469
8136
|
case 0:
|
|
8137
|
+
_this = this;
|
|
7470
8138
|
auth = req.auth;
|
|
7471
|
-
server = this.factory.createServer({
|
|
7472
|
-
auth: auth,
|
|
7473
|
-
rawRequest: req
|
|
7474
|
-
});
|
|
7475
8139
|
_state.label = 1;
|
|
7476
8140
|
case 1:
|
|
7477
8141
|
_state.trys.push([
|
|
@@ -7482,7 +8146,12 @@ var McpController_1;
|
|
|
7482
8146
|
]);
|
|
7483
8147
|
return [
|
|
7484
8148
|
4,
|
|
7485
|
-
handleStreamableHttpMcpRequest(req, res,
|
|
8149
|
+
handleStreamableHttpMcpRequest(req, res, function() {
|
|
8150
|
+
return _this.factory.createServer({
|
|
8151
|
+
auth: auth,
|
|
8152
|
+
rawRequest: req
|
|
8153
|
+
});
|
|
8154
|
+
})
|
|
7486
8155
|
];
|
|
7487
8156
|
case 2:
|
|
7488
8157
|
_state.sent();
|
|
@@ -7511,6 +8180,45 @@ var McpController_1;
|
|
|
7511
8180
|
});
|
|
7512
8181
|
}).call(this);
|
|
7513
8182
|
}
|
|
8183
|
+
},
|
|
8184
|
+
{
|
|
8185
|
+
/**
|
|
8186
|
+
* Rejects the Streamable HTTP transport's optional `GET` method, which opens a standalone SSE
|
|
8187
|
+
* stream. Not applicable in stateless mode. Separate from {@link handleUnsupportedDelete} because
|
|
8188
|
+
* NestJS binds one HTTP method per handler — stacking route decorators would silently drop one.
|
|
8189
|
+
*
|
|
8190
|
+
* @param res - The Express response to write the rejection to.
|
|
8191
|
+
*/ key: "handleUnsupportedGet",
|
|
8192
|
+
value: function handleUnsupportedGet(res) {
|
|
8193
|
+
this._rejectUnsupportedMethod(res);
|
|
8194
|
+
}
|
|
8195
|
+
},
|
|
8196
|
+
{
|
|
8197
|
+
/**
|
|
8198
|
+
* Rejects the Streamable HTTP transport's optional `DELETE` method, which tears down a session.
|
|
8199
|
+
* Not applicable in stateless mode — no session is ever issued.
|
|
8200
|
+
*
|
|
8201
|
+
* @param res - The Express response to write the rejection to.
|
|
8202
|
+
*/ key: "handleUnsupportedDelete",
|
|
8203
|
+
value: function handleUnsupportedDelete(res) {
|
|
8204
|
+
this._rejectUnsupportedMethod(res);
|
|
8205
|
+
}
|
|
8206
|
+
},
|
|
8207
|
+
{
|
|
8208
|
+
/**
|
|
8209
|
+
* Answers with a spec-conformant `405 Method Not Allowed` + `Allow` header. Without these
|
|
8210
|
+
* handlers NestJS answers `404`, which some clients treat as a hard failure rather than
|
|
8211
|
+
* "the server doesn't offer this".
|
|
8212
|
+
*
|
|
8213
|
+
* @param res - The Express response to write the rejection to.
|
|
8214
|
+
*/ key: "_rejectUnsupportedMethod",
|
|
8215
|
+
value: function _rejectUnsupportedMethod(res) {
|
|
8216
|
+
res.setHeader('Allow', 'POST');
|
|
8217
|
+
res.status(HttpStatus.METHOD_NOT_ALLOWED).json({
|
|
8218
|
+
statusCode: HttpStatus.METHOD_NOT_ALLOWED,
|
|
8219
|
+
message: 'Method Not Allowed'
|
|
8220
|
+
});
|
|
8221
|
+
}
|
|
7514
8222
|
}
|
|
7515
8223
|
]);
|
|
7516
8224
|
return McpController;
|
|
@@ -7520,6 +8228,14 @@ __decorate([
|
|
|
7520
8228
|
__param(0, Req()),
|
|
7521
8229
|
__param(1, Res())
|
|
7522
8230
|
], McpController.prototype, "handleMcpRequest", null);
|
|
8231
|
+
__decorate([
|
|
8232
|
+
Get(),
|
|
8233
|
+
__param(0, Res())
|
|
8234
|
+
], McpController.prototype, "handleUnsupportedGet", null);
|
|
8235
|
+
__decorate([
|
|
8236
|
+
Delete(),
|
|
8237
|
+
__param(0, Res())
|
|
8238
|
+
], McpController.prototype, "handleUnsupportedDelete", null);
|
|
7523
8239
|
McpController = McpController_1 = __decorate([
|
|
7524
8240
|
Controller('mcp'),
|
|
7525
8241
|
__param(0, Inject(McpServerFactoryService))
|
|
@@ -7605,6 +8321,13 @@ function _unsupported_iterable_to_array$2(o, minLen) {
|
|
|
7605
8321
|
* URIs must live at the host root. Apps need to exclude `.well-known/{*path}`
|
|
7606
8322
|
* from any global API route prefix (see `FIREBASE_SERVER_OIDC_ROUTES_FOR_GLOBAL_ROUTE_EXCLUDE`
|
|
7607
8323
|
* in `firebase-server/oidc` for the corresponding OIDC excludes).
|
|
8324
|
+
*
|
|
8325
|
+
* Because the document must be reachable at the origin root, the MCP endpoint has to be
|
|
8326
|
+
* exposed through a host that serves the app at `/` — Firebase Hosting, or the hosting
|
|
8327
|
+
* emulator in development. Pointing a client straight at the Functions emulator origin
|
|
8328
|
+
* (`http://localhost:<port>/<project>/<region>/<function>/mcp`) breaks discovery: that
|
|
8329
|
+
* runtime only routes `/<project>/<region>/<function>/…`, so nothing answers at the root
|
|
8330
|
+
* and a client that has not yet seen a 401 challenge cannot find the issuer.
|
|
7608
8331
|
*/ var McpWellKnownController = /*#__PURE__*/ function() {
|
|
7609
8332
|
function McpWellKnownController(mcpConfig, oidcProviderConfigService) {
|
|
7610
8333
|
_class_call_check$1(this, McpWellKnownController);
|
|
@@ -7615,12 +8338,26 @@ function _unsupported_iterable_to_array$2(o, minLen) {
|
|
|
7615
8338
|
}
|
|
7616
8339
|
_create_class$1(McpWellKnownController, [
|
|
7617
8340
|
{
|
|
7618
|
-
|
|
8341
|
+
/**
|
|
8342
|
+
* Serves both RFC 9728 discovery URLs — the primary form (§3.1), which inserts the resource's
|
|
8343
|
+
* path after the well-known prefix (`/.well-known/oauth-protected-resource/mcp`), and the bare
|
|
8344
|
+
* form (`/.well-known/oauth-protected-resource`) that clients probe as a fallback.
|
|
8345
|
+
*
|
|
8346
|
+
* The document is identical either way; the resource identity comes from
|
|
8347
|
+
* {@link McpModuleConfig.mcpUrl}, not from the request path. Serving the primary form means
|
|
8348
|
+
* discovery succeeds on a client's first probe rather than depending on it implementing the
|
|
8349
|
+
* fallback.
|
|
8350
|
+
*
|
|
8351
|
+
* @returns The protected-resource metadata document.
|
|
8352
|
+
*/ key: "getProtectedResourceMetadata",
|
|
7619
8353
|
value: function getProtectedResourceMetadata() {
|
|
7620
8354
|
var _this_mcpConfig = this.mcpConfig, mcpUrl = _this_mcpConfig.mcpUrl, oidcIssuer = _this_mcpConfig.oidcIssuer, scopesFilter = _this_mcpConfig.scopesSupported;
|
|
7621
|
-
// Base scope list is the
|
|
7622
|
-
//
|
|
7623
|
-
|
|
8355
|
+
// Base scope list is what the issuer grants an arbitrary client, NOT its full
|
|
8356
|
+
// `scopes_supported`: a dynamic-registration client copies this list verbatim onto
|
|
8357
|
+
// `/authorize`, and a provider-profile-gated scope in it would be hard-rejected at the
|
|
8358
|
+
// consent unlock gate (`access_denied`) for every client lacking that profile assignment.
|
|
8359
|
+
// The optional filter narrows the list further.
|
|
8360
|
+
var providerScopes = this.oidcProviderConfigService.clientRequestableScopesSupported;
|
|
7624
8361
|
var scopes = scopesFilter ? scopesFilter(providerScopes) : providerScopes;
|
|
7625
8362
|
return _object_spread({
|
|
7626
8363
|
resource: mcpUrl,
|
|
@@ -7636,7 +8373,10 @@ function _unsupported_iterable_to_array$2(o, minLen) {
|
|
|
7636
8373
|
return McpWellKnownController;
|
|
7637
8374
|
}();
|
|
7638
8375
|
__decorate([
|
|
7639
|
-
Get(
|
|
8376
|
+
Get([
|
|
8377
|
+
'oauth-protected-resource',
|
|
8378
|
+
'oauth-protected-resource/{*path}'
|
|
8379
|
+
])
|
|
7640
8380
|
], McpWellKnownController.prototype, "getProtectedResourceMetadata", null);
|
|
7641
8381
|
McpWellKnownController = __decorate([
|
|
7642
8382
|
Controller('.well-known'),
|
|
@@ -7946,4 +8686,4 @@ function _unsupported_iterable_to_array(o, minLen) {
|
|
|
7946
8686
|
};
|
|
7947
8687
|
}
|
|
7948
8688
|
|
|
7949
|
-
export { BATCH_EXECUTE_DISPATCH_CALL, BATCH_EXECUTE_DISPATCH_MODEL_TYPE, BATCH_EXECUTE_TOOL_NAME, DEFAULT_BATCH_EXECUTE_MAX_PARALLEL, DEFAULT_JSON_SCHEMA_GENERATION_OPTIONS, DEFAULT_MCP_ANALYTICS_EVENT_NAME, DEFAULT_MCP_PATH, DEFAULT_MCP_REASON_PARAMETER_DESCRIPTION, DEFAULT_MCP_REASON_PARAMETER_MAX_LENGTH, DEFAULT_MCP_REASON_PARAMETER_NAME, DEFAULT_MCP_REASON_PARAMETER_REQUIRED, DEFAULT_MCP_SERVER_INSTRUCTIONS, DEFAULT_MCP_SERVER_NAME, DEFAULT_SPECIFIER_KEY, DEFAULT_VOID_MCP_SUCCESS_VALUE, ENUM_INFO_DISPATCH_CALL, ENUM_INFO_DISPATCH_MODEL_TYPE, ENUM_INFO_TOOL_NAME, ENUM_TABLE_SCHEMA, FIREBASE_SERVER_MCP_ANALYTICS_CONFIG, FIREBASE_SERVER_MCP_ROUTES_FOR_GLOBAL_ROUTE_EXCLUDE, FirebaseServerMcpAnalyticsService, MAX_BATCH_EXECUTE_FILE_BYTES, MAX_BATCH_EXECUTE_OPERATIONS, MCP_ANALYTICS_SERVICE, MCP_AUTH_ROLE_READER, MCP_CALL_TYPE_ABBREVIATIONS, MCP_MANIFEST_VERSION, MCP_MODEL_GET_BATCH_SIZE, MCP_TOOL_NAME_MAX_LENGTH, MCP_TOOL_NAME_WARN_LENGTH, MCP_WRITE_TOOL_DESCRIPTION_PREFIX, MODEL_DECODE_DISPATCH_CALL, MODEL_DECODE_DISPATCH_MODEL_TYPE, MODEL_DECODE_TOOL_NAME, MODEL_GET_DISPATCH_CALL, MODEL_GET_DISPATCH_MODEL_TYPE, MODEL_GET_TOOL_NAME, MODEL_INFO_DISPATCH_CALL, MODEL_INFO_DISPATCH_MODEL_TYPE, MODEL_INFO_GROUPS_HINT, MODEL_INFO_TOOL_NAME, MODEL_INFO_UNGROUPED_LABEL, McpAnalyticsService, McpController, McpModuleConfig, McpServerFactoryService, McpWellKnownController, ROUTE_MANIFEST_VERSION, URL_MODELS_DISPATCH_CALL, URL_MODELS_DISPATCH_MODEL_TYPE, URL_MODELS_TOOL_NAME, abbreviateMcpCallType, appMcpAnalyticsModuleMetadata, applyMcpReasonParameterToSchema, applyWriteMarker, batchOperationCoordKey, buildDefaultMcpToolDescription, buildDisambiguatedMcpToolName, buildMcpToolName, buildStaticToolDefinition, buildStaticWireEntry, classifyVisibility, createBatchExecuteTool, createEnumInfoTool, createModelDecodeTool, createModelGetTool, createModelInfoTool, createUrlModelsTool, decodeFirestoreModelKey, extractMcpReasonFromArgs, findModelEntry, formatMcpToolErrorResponse, formatMcpToolResponse, generateMcpToolDefinitions, handleStreamableHttpMcpRequest, matchRouteManifestUrl, mcpManifestKey, mcpModuleMetadata, mcpSchemaDeclaresProperty, noopMcpAnalyticsService, parseUrlModelsPathname, readUrlModelsImpersonationUid, resolveEffectiveReadOnly, resolveEnumInfoOutput, resolveMcpReasonParameterConfig, resolveMcpToolAnnotations, resolveRequiredScope, validateMcpToolName };
|
|
8689
|
+
export { BATCH_EXECUTE_DISPATCH_CALL, BATCH_EXECUTE_DISPATCH_MODEL_TYPE, BATCH_EXECUTE_TOOL_NAME, DEFAULT_BATCH_EXECUTE_MAX_PARALLEL, DEFAULT_JSON_SCHEMA_GENERATION_OPTIONS, DEFAULT_MCP_ANALYTICS_EVENT_NAME, DEFAULT_MCP_PATH, DEFAULT_MCP_REASON_PARAMETER_DESCRIPTION, DEFAULT_MCP_REASON_PARAMETER_MAX_LENGTH, DEFAULT_MCP_REASON_PARAMETER_NAME, DEFAULT_MCP_REASON_PARAMETER_REQUIRED, DEFAULT_MCP_SERVER_INSTRUCTIONS, DEFAULT_MCP_SERVER_NAME, DEFAULT_SPECIFIER_KEY, DEFAULT_VOID_MCP_SUCCESS_VALUE, ENUM_INFO_DISPATCH_CALL, ENUM_INFO_DISPATCH_MODEL_TYPE, ENUM_INFO_TOOL_NAME, ENUM_TABLE_SCHEMA, FIREBASE_SERVER_MCP_ANALYTICS_CONFIG, FIREBASE_SERVER_MCP_ROUTES_FOR_GLOBAL_ROUTE_EXCLUDE, FirebaseServerMcpAnalyticsService, MAX_BATCH_EXECUTE_FILE_BYTES, MAX_BATCH_EXECUTE_OPERATIONS, MCP_ANALYTICS_SERVICE, MCP_AUTH_ROLE_READER, MCP_CALL_TYPE_ABBREVIATIONS, MCP_MANIFEST_VERSION, MCP_MODEL_GET_BATCH_SIZE, MCP_MODEL_ROLES_MAX_KEYS, MCP_MODEL_ROLES_TARGET_UID_PREDICATE, MCP_TOOL_NAME_MAX_LENGTH, MCP_TOOL_NAME_WARN_LENGTH, MCP_WRITE_TOOL_DESCRIPTION_PREFIX, MODEL_DECODE_DISPATCH_CALL, MODEL_DECODE_DISPATCH_MODEL_TYPE, MODEL_DECODE_TOOL_NAME, MODEL_GET_DISPATCH_CALL, MODEL_GET_DISPATCH_MODEL_TYPE, MODEL_GET_TOOL_NAME, MODEL_INFO_DISPATCH_CALL, MODEL_INFO_DISPATCH_MODEL_TYPE, MODEL_INFO_GROUPS_HINT, MODEL_INFO_TOOL_NAME, MODEL_INFO_UNGROUPED_LABEL, MODEL_ROLES_DISPATCH_CALL, MODEL_ROLES_DISPATCH_MODEL_TYPE, MODEL_ROLES_TOOL_NAME, McpAnalyticsService, McpController, McpModuleConfig, McpServerFactoryService, McpWellKnownController, ROUTE_MANIFEST_VERSION, URL_MODELS_DISPATCH_CALL, URL_MODELS_DISPATCH_MODEL_TYPE, URL_MODELS_TOOL_NAME, abbreviateMcpCallType, appMcpAnalyticsModuleMetadata, applyMcpReasonParameterToSchema, applyWriteMarker, batchOperationCoordKey, buildDefaultMcpToolDescription, buildDisambiguatedMcpToolName, buildMcpToolName, buildStaticToolDefinition, buildStaticWireEntry, classifyVisibility, createBatchExecuteTool, createEnumInfoTool, createModelDecodeTool, createModelGetTool, createModelInfoTool, createModelRolesTool, createUrlModelsTool, decodeFirestoreModelKey, extractMcpReasonFromArgs, findModelEntry, formatMcpToolErrorResponse, formatMcpToolResponse, generateMcpToolDefinitions, handleStreamableHttpMcpRequest, matchRouteManifestUrl, mcpManifestKey, mcpModuleMetadata, mcpSchemaDeclaresProperty, noopMcpAnalyticsService, parseUrlModelsPathname, readUrlModelsImpersonationUid, resolveEffectiveReadOnly, resolveEnumInfoOutput, resolveMcpReasonParameterConfig, resolveMcpToolAnnotations, resolveRequiredScope, validateMcpToolName };
|