@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.
- package/index.cjs.js +218 -31
- package/index.esm.js +217 -34
- package/mailgun/package.json +9 -9
- package/mcp/index.cjs.default.js +1 -0
- package/mcp/index.cjs.js +3646 -0
- package/mcp/index.cjs.mjs +2 -0
- package/mcp/index.d.ts +1 -0
- package/mcp/index.esm.js +3609 -0
- package/mcp/package.json +33 -0
- package/mcp/src/index.d.ts +1 -0
- package/mcp/src/lib/controller/index.d.ts +2 -0
- package/mcp/src/lib/controller/mcp.controller.d.ts +19 -0
- package/mcp/src/lib/controller/mcp.wellknown.controller.d.ts +25 -0
- package/mcp/src/lib/index.d.ts +5 -0
- package/mcp/src/lib/mcp.config.d.ts +100 -0
- package/mcp/src/lib/mcp.module.d.ts +49 -0
- package/mcp/src/lib/service/index.d.ts +8 -0
- package/mcp/src/lib/service/mcp.manifest.d.ts +150 -0
- package/mcp/src/lib/service/mcp.response-formatter.d.ts +36 -0
- package/mcp/src/lib/service/mcp.server.factory.d.ts +124 -0
- package/mcp/src/lib/service/mcp.tool-generator.d.ts +235 -0
- package/mcp/src/lib/service/mcp.visibility.d.ts +99 -0
- package/mcp/src/lib/service/tools/mcp.tool.model-decode.d.ts +87 -0
- package/mcp/src/lib/service/tools/mcp.tool.model-get.d.ts +81 -0
- package/mcp/src/lib/service/tools/mcp.tool.model-info.d.ts +84 -0
- package/mcp/src/lib/service/tools/mcp.tool.whoami.d.ts +72 -0
- package/mcp/src/lib/transport/index.d.ts +1 -0
- package/mcp/src/lib/transport/streamable-http.transport.d.ts +21 -0
- package/model/index.cjs.js +639 -266
- package/model/index.esm.js +640 -270
- package/model/package.json +9 -9
- package/model/src/lib/storagefile/extension/compress.pdf.d.ts +29 -1
- package/model/src/lib/storagefile/index.d.ts +1 -0
- package/model/src/lib/storagefile/storagefile.action.server.d.ts +29 -2
- package/model/src/lib/storagefile/storagefile.mcp.d.ts +32 -0
- package/model/src/lib/storagefile/storagefile.module.d.ts +20 -3
- package/oidc/index.cjs.js +322 -147
- package/oidc/index.esm.js +321 -148
- package/oidc/package.json +10 -10
- package/oidc/src/lib/controller/oidc.wellknown.controller.d.ts +6 -15
- package/oidc/src/lib/middleware/oauth-auth.middleware.d.ts +22 -2
- package/oidc/src/lib/middleware/oauth-auth.module.d.ts +57 -0
- package/oidc/src/lib/oidc.config.d.ts +73 -0
- package/oidc/src/lib/oidc.module.d.ts +44 -2
- package/package.json +16 -10
- package/src/lib/auth/auth.service.d.ts +16 -1
- package/src/lib/auth/auth.service.error.util.d.ts +24 -5
- package/src/lib/env/env.config.d.ts +16 -0
- package/src/lib/env/env.service.d.ts +9 -0
- package/src/lib/nest/controller/model/model.api.get.service.d.ts +35 -1
- package/src/lib/nest/env/env.service.d.ts +1 -0
- package/src/lib/nest/model/api.details.d.ts +116 -5
- package/src/lib/nest/model/crud.assert.function.d.ts +1 -1
- package/src/lib/nest/model/index.d.ts +1 -0
- package/src/lib/nest/model/invoke.model.function.d.ts +89 -0
- package/test/package.json +11 -11
- package/twilio/LICENSE +21 -0
- package/twilio/index.cjs.default.js +1 -0
- package/twilio/index.cjs.js +404 -0
- package/twilio/index.cjs.mjs +2 -0
- package/twilio/index.d.ts +1 -0
- package/twilio/index.esm.js +398 -0
- package/twilio/package.json +25 -0
- package/twilio/src/index.d.ts +1 -0
- package/twilio/src/lib/index.d.ts +1 -0
- package/twilio/src/lib/notification.send.service.twilio.d.ts +148 -0
- package/zoho/package.json +9 -9
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import { type Maybe } from '@dereekb/util';
|
|
2
|
+
import { type ModelApiDetailsResult, type OnCallModelFunctionApiDetails, type FirebaseServerAuthData, type McpToolDetailsBuilder } from '@dereekb/firebase-server';
|
|
3
|
+
import { type Request } from 'express';
|
|
4
|
+
import { type CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
|
5
|
+
import { type McpManifestToolEntry } from './mcp.manifest';
|
|
6
|
+
import { type McpToolFilterMetadata } from './mcp.visibility';
|
|
7
|
+
/**
|
|
8
|
+
* Frozen wire-shape entry returned on `tools/list`.
|
|
9
|
+
*
|
|
10
|
+
* Built once at boot per tool and reused for every request when no
|
|
11
|
+
* {@link McpToolDefinition.toolDetailsBuilder} is configured. Tools that opt in
|
|
12
|
+
* to dynamic details produce a fresh wire entry per request.
|
|
13
|
+
*/
|
|
14
|
+
export interface McpToolListEntry {
|
|
15
|
+
readonly name: string;
|
|
16
|
+
readonly description: string;
|
|
17
|
+
readonly inputSchema: object;
|
|
18
|
+
readonly outputSchema?: object;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* A single MCP tool definition generated from one (modelType, callType, specifier) triple.
|
|
22
|
+
*/
|
|
23
|
+
export interface McpToolDefinition {
|
|
24
|
+
/**
|
|
25
|
+
* Tool name advertised on `tools/list`.
|
|
26
|
+
*
|
|
27
|
+
* Format: `<modelType>-<callType>` for default (`_`) specifiers,
|
|
28
|
+
* `<modelType>-<callType>-<specifier>` for non-default specifiers.
|
|
29
|
+
*
|
|
30
|
+
* @example 'guestbook-create'
|
|
31
|
+
* @example 'profile-update-username'
|
|
32
|
+
* @example 'storageFile-invoke-recomputeChecksums'
|
|
33
|
+
*/
|
|
34
|
+
readonly name: string;
|
|
35
|
+
/**
|
|
36
|
+
* Human-readable description surfaced to MCP clients.
|
|
37
|
+
*
|
|
38
|
+
* Resolved from the build-time MCP manifest entry when present; otherwise auto-generated.
|
|
39
|
+
*/
|
|
40
|
+
readonly description: string;
|
|
41
|
+
/**
|
|
42
|
+
* JSON Schema for the tool input.
|
|
43
|
+
*
|
|
44
|
+
* Resolved in order: manifest entry's `inputSchema` (when a manifest is supplied) > handler's
|
|
45
|
+
* `inputType.toJsonSchema()` > `undefined`. `undefined` means the tool is skipped during
|
|
46
|
+
* registration; the gap is logged so it's visible.
|
|
47
|
+
*/
|
|
48
|
+
readonly inputSchema?: object;
|
|
49
|
+
/**
|
|
50
|
+
* JSON Schema for the tool output, when the manifest provides one. The wire `tools/list`
|
|
51
|
+
* response only includes this when the pinned MCP SDK type allows it.
|
|
52
|
+
*/
|
|
53
|
+
readonly outputSchema?: object;
|
|
54
|
+
/**
|
|
55
|
+
* The original handler-level API details. Carries response formatters, analytics
|
|
56
|
+
* config, etc. — the controller resolves Tier 1/2/3 response shape from this.
|
|
57
|
+
*
|
|
58
|
+
* `undefined` for statically-registered tools that don't go through the callModel chain.
|
|
59
|
+
*/
|
|
60
|
+
readonly details?: OnCallModelFunctionApiDetails;
|
|
61
|
+
/**
|
|
62
|
+
* The dispatch coordinates extracted from the position in the call model tree.
|
|
63
|
+
* The controller uses these to build the `OnCallTypedModelParams` envelope at call time.
|
|
64
|
+
*
|
|
65
|
+
* For statically-registered tools the coordinates are synthetic (they identify the tool to
|
|
66
|
+
* dynamic visibility predicates) but {@link staticHandler} runs instead of the callModel chain.
|
|
67
|
+
*/
|
|
68
|
+
readonly dispatch: McpToolDispatchTarget;
|
|
69
|
+
/**
|
|
70
|
+
* When present, the per-request controller calls this handler directly instead of going
|
|
71
|
+
* through the callModel dispatch chain. Used for built-in MCP tools (e.g. `model-get`) that
|
|
72
|
+
* read from the Firebase model surface without a corresponding `callModel` handler.
|
|
73
|
+
*/
|
|
74
|
+
readonly staticHandler?: McpStaticToolHandler;
|
|
75
|
+
/**
|
|
76
|
+
* Precomputed boot-time filter metadata consumed by the per-request `tools/list` filter.
|
|
77
|
+
*/
|
|
78
|
+
readonly filterMetadata: McpToolFilterMetadata;
|
|
79
|
+
/**
|
|
80
|
+
* The frozen `tools/list` wire entry for this tool, computed once at boot from the
|
|
81
|
+
* static description / inputSchema / outputSchema. The factory returns this verbatim
|
|
82
|
+
* when {@link toolDetailsBuilder} is `undefined`, avoiding a per-request allocation.
|
|
83
|
+
*/
|
|
84
|
+
readonly staticWireEntry: McpToolListEntry;
|
|
85
|
+
/**
|
|
86
|
+
* The handler's per-request builder, hoisted from `details.mcp.toolDetails` once at
|
|
87
|
+
* boot so the request hot path doesn't dereference through the details tree.
|
|
88
|
+
*
|
|
89
|
+
* `undefined` for tools that did not opt in (the common case) and for statically
|
|
90
|
+
* registered tools.
|
|
91
|
+
*/
|
|
92
|
+
readonly toolDetailsBuilder?: McpToolDetailsBuilder;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Per-request handler for a statically-registered MCP tool.
|
|
96
|
+
*
|
|
97
|
+
* Receives the raw tool arguments and the MCP request context (auth + raw request); returns the
|
|
98
|
+
* MCP `CallToolResult` envelope verbatim. The factory wraps the call in a try/catch so handlers
|
|
99
|
+
* may surface user-visible errors by throwing.
|
|
100
|
+
*/
|
|
101
|
+
export type McpStaticToolHandler = (args: Record<string, unknown>, ctx: McpStaticToolHandlerContext) => Promise<CallToolResult>;
|
|
102
|
+
/**
|
|
103
|
+
* Request-scoped context passed to {@link McpStaticToolHandler} implementations.
|
|
104
|
+
*
|
|
105
|
+
* Identical in shape to `McpRequestContext` but redeclared here so the tool generator does not
|
|
106
|
+
* depend on the server factory module (the dependency goes the other way).
|
|
107
|
+
*/
|
|
108
|
+
export interface McpStaticToolHandlerContext {
|
|
109
|
+
readonly auth?: FirebaseServerAuthData;
|
|
110
|
+
readonly rawRequest: Request;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* The (call, modelType, specifier) coordinate that resolves a generated MCP tool
|
|
114
|
+
* back to a single dispatch target on the underlying callModel chain.
|
|
115
|
+
*/
|
|
116
|
+
export interface McpToolDispatchTarget {
|
|
117
|
+
readonly call: string;
|
|
118
|
+
readonly modelType: string;
|
|
119
|
+
/**
|
|
120
|
+
* `undefined` when the handler isn't behind a specifier (default `_` entry on a
|
|
121
|
+
* non-specifier model type).
|
|
122
|
+
*/
|
|
123
|
+
readonly specifier?: string;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Options forwarded to {@link JsonSchemaRef.toJsonSchema}.
|
|
127
|
+
*
|
|
128
|
+
* Wraps the ArkType-specific fallback handlers so consumers can opt out of the
|
|
129
|
+
* default predicate / `undefinedAsClearable` behavior if their schema lib needs
|
|
130
|
+
* different options.
|
|
131
|
+
*/
|
|
132
|
+
export interface JsonSchemaGenerationOptions {
|
|
133
|
+
readonly [option: string]: unknown;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Default `toJsonSchema()` options.
|
|
137
|
+
*
|
|
138
|
+
* ArkType throws on predicate definitions and on `undefined` fields by default;
|
|
139
|
+
* these fallback handlers downgrade those errors so a partial schema is emitted
|
|
140
|
+
* for tools that mostly fit JSON Schema. The `unit` fallback covers `clearable(t)`
|
|
141
|
+
* from `@dereekb/model` (which expands to `t | undefined` and surfaces as an ArkType
|
|
142
|
+
* `unit: undefined` schema node).
|
|
143
|
+
*/
|
|
144
|
+
export declare const DEFAULT_JSON_SCHEMA_GENERATION_OPTIONS: JsonSchemaGenerationOptions;
|
|
145
|
+
/**
|
|
146
|
+
* Reason a tool was skipped during generation.
|
|
147
|
+
*/
|
|
148
|
+
export type McpToolGenerationSkipReason = 'missing_input_type' | 'schema_generation_failed';
|
|
149
|
+
/**
|
|
150
|
+
* One tool that was skipped during generation.
|
|
151
|
+
*/
|
|
152
|
+
export interface McpToolGenerationSkip {
|
|
153
|
+
readonly toolName: string;
|
|
154
|
+
readonly reason: McpToolGenerationSkipReason;
|
|
155
|
+
readonly dispatch: McpToolDispatchTarget;
|
|
156
|
+
readonly error?: Error;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Aggregated output of {@link generateMcpToolDefinitions}.
|
|
160
|
+
*/
|
|
161
|
+
export interface McpToolGenerationResult {
|
|
162
|
+
/**
|
|
163
|
+
* Tools that may be visible on `tools/list`, subject to the per-request filter.
|
|
164
|
+
* Excludes anything classified as `'never'` visible at boot.
|
|
165
|
+
*/
|
|
166
|
+
readonly tools: ReadonlyArray<McpToolDefinition>;
|
|
167
|
+
/**
|
|
168
|
+
* Tools whose `visibility` was classified as `'never'` at boot.
|
|
169
|
+
* Partitioned out so the per-request loop never touches them.
|
|
170
|
+
*/
|
|
171
|
+
readonly neverVisibleTools: ReadonlyArray<McpToolDefinition>;
|
|
172
|
+
/**
|
|
173
|
+
* Tools that could not be generated (no inputType, or `toJsonSchema()` threw).
|
|
174
|
+
* Surfaced so the caller can log them at startup.
|
|
175
|
+
*/
|
|
176
|
+
readonly skipped: ReadonlyArray<McpToolGenerationSkip>;
|
|
177
|
+
}
|
|
178
|
+
interface BuildStaticWireEntryInput {
|
|
179
|
+
readonly name: string;
|
|
180
|
+
readonly description: string;
|
|
181
|
+
readonly inputSchema?: object;
|
|
182
|
+
readonly outputSchema?: object;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Builds the frozen wire-shape entry used by the per-request `tools/list` hot path.
|
|
186
|
+
*
|
|
187
|
+
* Tools without an `inputSchema` default to `{ type: 'object' }` to match the runtime
|
|
188
|
+
* behaviour the factory used before the precompute optimisation existed.
|
|
189
|
+
*
|
|
190
|
+
* @param input - The tool name, description, and optional input/output schemas used to assemble the wire entry.
|
|
191
|
+
* @returns A frozen wire entry safe to share across requests.
|
|
192
|
+
*/
|
|
193
|
+
export declare function buildStaticWireEntry(input: BuildStaticWireEntryInput): McpToolListEntry;
|
|
194
|
+
/**
|
|
195
|
+
* The default specifier key used when a handler is not behind a specifier router.
|
|
196
|
+
*/
|
|
197
|
+
export declare const DEFAULT_SPECIFIER_KEY = "_";
|
|
198
|
+
/**
|
|
199
|
+
* Builds the MCP tool name for a (modelType, callType, specifier) triple.
|
|
200
|
+
*
|
|
201
|
+
* Apps can override the auto-generated name by setting
|
|
202
|
+
* {@link OnCallModelFunctionApiDetails.mcp.name} on the handler.
|
|
203
|
+
*
|
|
204
|
+
* @param modelType - The Firestore model type (e.g., `storageFile`).
|
|
205
|
+
* @param callType - The call type (e.g., `invoke`).
|
|
206
|
+
* @param specifier - The specifier key, or `_` / undefined for the default entry.
|
|
207
|
+
* @returns The hyphen-joined tool name advertised on `tools/list`.
|
|
208
|
+
*/
|
|
209
|
+
export declare function buildMcpToolName(modelType: string, callType: string, specifier?: Maybe<string>): string;
|
|
210
|
+
/**
|
|
211
|
+
* Builds the default description used when no build-time MCP manifest
|
|
212
|
+
* entry is available for the (modelType, callType, specifier) tuple.
|
|
213
|
+
*
|
|
214
|
+
* @param modelType - The Firestore model type segment used in the generated description.
|
|
215
|
+
* @param callType - The call type segment used in the generated description.
|
|
216
|
+
* @param specifier - The specifier segment, or `_` / undefined for the default entry.
|
|
217
|
+
* @returns A human-readable fallback description for the tool.
|
|
218
|
+
*/
|
|
219
|
+
export declare function buildDefaultMcpToolDescription(modelType: string, callType: string, specifier?: Maybe<string>): string;
|
|
220
|
+
/**
|
|
221
|
+
* Generates MCP tool definitions from a model-first API details tree.
|
|
222
|
+
*
|
|
223
|
+
* Walks each (modelType, callType, specifier) triple in the tree, calls
|
|
224
|
+
* `inputType.toJsonSchema(options)` for the schema, and applies any handler-level
|
|
225
|
+
* MCP `name` override. Descriptions and input/output schemas are pulled from the
|
|
226
|
+
* build-time manifest when supplied. Tools without an `inputType` are skipped and
|
|
227
|
+
* reported so callers can log the gap at startup.
|
|
228
|
+
*
|
|
229
|
+
* @param apiDetails - The model-first API details tree returned by `getModelApiDetails(callModelFn)`.
|
|
230
|
+
* @param options - Optional schema generation options forwarded to `toJsonSchema()`. Defaults to {@link DEFAULT_JSON_SCHEMA_GENERATION_OPTIONS}.
|
|
231
|
+
* @param manifest - Optional build-time manifest map; supplies overrides for descriptions and input/output schemas keyed by {@link mcpManifestKey}.
|
|
232
|
+
* @returns The list of generated tool definitions plus any skip reports.
|
|
233
|
+
*/
|
|
234
|
+
export declare function generateMcpToolDefinitions(apiDetails: ModelApiDetailsResult, options?: JsonSchemaGenerationOptions, manifest?: ReadonlyMap<string, McpManifestToolEntry>): McpToolGenerationResult;
|
|
235
|
+
export {};
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { type Maybe } from '@dereekb/util';
|
|
2
|
+
import { type CallModelOidcScope } from '@dereekb/firebase';
|
|
3
|
+
import { type McpToolVisibility, type McpVisibilityContext, type McpVisibilityRule } from '@dereekb/firebase-server';
|
|
4
|
+
/**
|
|
5
|
+
* Normalized classification of a {@link McpToolVisibility} value computed at boot.
|
|
6
|
+
*
|
|
7
|
+
* `'always'` keeps the tool (subject to scope/readOnly filters).
|
|
8
|
+
* `'never'` drops the tool from `tools/list` entirely — partitioned at boot so the per-request loop skips it.
|
|
9
|
+
* `'declarative'` carries a {@link McpVisibilityRule} checked per request without invoking user code.
|
|
10
|
+
* `'dynamic'` carries the original predicate; invoked per request inside try/catch.
|
|
11
|
+
*/
|
|
12
|
+
export type McpToolVisibilityKind = 'always' | 'never' | 'declarative' | 'dynamic';
|
|
13
|
+
/**
|
|
14
|
+
* Boot-time classification result for one tool's `visibility` field.
|
|
15
|
+
*
|
|
16
|
+
* Discriminated by {@link McpToolVisibilityKind} so consumers can narrow `rule` /
|
|
17
|
+
* `visibilityFn` presence without optional-chain assertions.
|
|
18
|
+
*/
|
|
19
|
+
export type ClassifiedMcpToolVisibility = ClassifiedMcpToolVisibilityAlways | ClassifiedMcpToolVisibilityNever | ClassifiedMcpToolVisibilityDeclarative | ClassifiedMcpToolVisibilityDynamic;
|
|
20
|
+
export interface ClassifiedMcpToolVisibilityAlways {
|
|
21
|
+
readonly visibilityKind: 'always';
|
|
22
|
+
}
|
|
23
|
+
export interface ClassifiedMcpToolVisibilityNever {
|
|
24
|
+
readonly visibilityKind: 'never';
|
|
25
|
+
}
|
|
26
|
+
export interface ClassifiedMcpToolVisibilityDeclarative {
|
|
27
|
+
readonly visibilityKind: 'declarative';
|
|
28
|
+
readonly rule: McpVisibilityRule;
|
|
29
|
+
}
|
|
30
|
+
export interface ClassifiedMcpToolVisibilityDynamic {
|
|
31
|
+
readonly visibilityKind: 'dynamic';
|
|
32
|
+
readonly visibilityFn: (context: McpVisibilityContext) => boolean;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Per-tool boot-time filter metadata. The per-request loop reads these fields directly.
|
|
36
|
+
*
|
|
37
|
+
* Discriminated by {@link McpToolVisibilityKind} so the request loop narrows to the
|
|
38
|
+
* exact variant carrying `rule` or `visibilityFn` without optional-chain assertions.
|
|
39
|
+
*/
|
|
40
|
+
export type McpToolFilterMetadata = McpToolFilterMetadataAlways | McpToolFilterMetadataNever | McpToolFilterMetadataDeclarative | McpToolFilterMetadataDynamic;
|
|
41
|
+
interface McpToolFilterMetadataBase {
|
|
42
|
+
/**
|
|
43
|
+
* OIDC scope required to invoke this tool. Precomputed from the dispatch call type.
|
|
44
|
+
* `undefined` for non-CRUD call types (apps gate those via their own preAssert if needed).
|
|
45
|
+
*/
|
|
46
|
+
readonly requiredScope?: CallModelOidcScope;
|
|
47
|
+
/**
|
|
48
|
+
* Effective read-only classification used by the module-level `readOnly` filter.
|
|
49
|
+
*
|
|
50
|
+
* Explicit handler `mcp.readOnly` wins. Otherwise inferred from the call type:
|
|
51
|
+
* `read`/`query` → true; `create`/`update`/`delete` → false; anything else → undefined.
|
|
52
|
+
* Unknown counts as a write for fail-safe filtering.
|
|
53
|
+
*/
|
|
54
|
+
readonly effectiveReadOnly?: boolean;
|
|
55
|
+
}
|
|
56
|
+
export interface McpToolFilterMetadataAlways extends McpToolFilterMetadataBase {
|
|
57
|
+
readonly visibilityKind: 'always';
|
|
58
|
+
}
|
|
59
|
+
export interface McpToolFilterMetadataNever extends McpToolFilterMetadataBase {
|
|
60
|
+
readonly visibilityKind: 'never';
|
|
61
|
+
}
|
|
62
|
+
export interface McpToolFilterMetadataDeclarative extends McpToolFilterMetadataBase {
|
|
63
|
+
readonly visibilityKind: 'declarative';
|
|
64
|
+
readonly rule: McpVisibilityRule;
|
|
65
|
+
}
|
|
66
|
+
export interface McpToolFilterMetadataDynamic extends McpToolFilterMetadataBase {
|
|
67
|
+
readonly visibilityKind: 'dynamic';
|
|
68
|
+
readonly visibilityFn: (context: McpVisibilityContext) => boolean;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Classifies a {@link McpToolVisibility} value into its normalized boot-time form.
|
|
72
|
+
*
|
|
73
|
+
* Defaults `undefined` to `'always'` so handlers without a visibility field stay visible.
|
|
74
|
+
*
|
|
75
|
+
* @param visibility - The raw visibility value from the handler's `mcp.visibility` field.
|
|
76
|
+
* @returns The discriminated classification used by the per-request filter loop.
|
|
77
|
+
*/
|
|
78
|
+
export declare function classifyVisibility(visibility?: McpToolVisibility): ClassifiedMcpToolVisibility;
|
|
79
|
+
/**
|
|
80
|
+
* Resolves the effective read-only classification for a handler.
|
|
81
|
+
*
|
|
82
|
+
* Explicit handler override wins. Otherwise infers from the call type. Returns
|
|
83
|
+
* `undefined` when neither source provides a definite classification.
|
|
84
|
+
*
|
|
85
|
+
* @param explicitReadOnly - The handler's explicit `mcp.readOnly` value, if any.
|
|
86
|
+
* @param callType - The dispatch call type used to infer read-only when no override is present.
|
|
87
|
+
* @returns The effective read-only flag, or `undefined` when neither source resolves a value.
|
|
88
|
+
*/
|
|
89
|
+
export declare function resolveEffectiveReadOnly(explicitReadOnly: Maybe<boolean>, callType: string): boolean | undefined;
|
|
90
|
+
/**
|
|
91
|
+
* Resolves the OIDC scope required to invoke a given call type, or `undefined` for
|
|
92
|
+
* non-CRUD calls. Thin re-export so the tool generator doesn't need to reach into
|
|
93
|
+
* `@dereekb/firebase` directly.
|
|
94
|
+
*
|
|
95
|
+
* @param callType - The dispatch call type to map to a CRUD OIDC scope.
|
|
96
|
+
* @returns The required scope for this call type, or `undefined` when no scope is enforced.
|
|
97
|
+
*/
|
|
98
|
+
export declare function resolveRequiredScope(callType: string): Maybe<CallModelOidcScope>;
|
|
99
|
+
export {};
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { type McpManifestModelEntry } from '../mcp.manifest';
|
|
2
|
+
import { type McpToolDefinition } from '../mcp.tool-generator';
|
|
3
|
+
/**
|
|
4
|
+
* Reserved tool name for the built-in `model-decode` static tool.
|
|
5
|
+
*/
|
|
6
|
+
export declare const MODEL_DECODE_TOOL_NAME = "model-decode";
|
|
7
|
+
/**
|
|
8
|
+
* Synthetic call type used in the tool's dispatch identity. Aligns with the dbx-cli `model-decode`
|
|
9
|
+
* command.
|
|
10
|
+
*/
|
|
11
|
+
export declare const MODEL_DECODE_DISPATCH_CALL = "decode";
|
|
12
|
+
/**
|
|
13
|
+
* Synthetic model type used in the tool's dispatch identity. Mirrors the other built-in static
|
|
14
|
+
* tools (`model-get`, `model-info`); apps avoiding collisions should not register a real model
|
|
15
|
+
* literally named "model".
|
|
16
|
+
*/
|
|
17
|
+
export declare const MODEL_DECODE_DISPATCH_MODEL_TYPE = "model";
|
|
18
|
+
/**
|
|
19
|
+
* Constructor dependencies for {@link createModelDecodeTool}.
|
|
20
|
+
*/
|
|
21
|
+
export interface CreateModelDecodeToolDeps {
|
|
22
|
+
/**
|
|
23
|
+
* Frozen catalog of Firestore models used to resolve segment prefixes.
|
|
24
|
+
*/
|
|
25
|
+
readonly manifest: readonly McpManifestModelEntry[];
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Shape of the `model-decode` tool input.
|
|
29
|
+
*/
|
|
30
|
+
export interface ModelDecodeToolInput {
|
|
31
|
+
readonly key: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* One segment of a decoded Firestore key. `model*` fields are absent when the
|
|
35
|
+
* segment's `prefix` isn't in the manifest.
|
|
36
|
+
*/
|
|
37
|
+
export interface DecodedKeySegment {
|
|
38
|
+
readonly prefix: string;
|
|
39
|
+
readonly id: string;
|
|
40
|
+
readonly modelType?: string;
|
|
41
|
+
readonly modelName?: string;
|
|
42
|
+
readonly modelGroup?: string;
|
|
43
|
+
readonly identityConst?: string;
|
|
44
|
+
readonly parentIdentityConst?: string;
|
|
45
|
+
readonly sourcePackage?: string;
|
|
46
|
+
readonly sourceFile?: string;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Output payload for the `model-decode` tool.
|
|
50
|
+
*/
|
|
51
|
+
export interface ModelDecodeToolOutput {
|
|
52
|
+
readonly key: string;
|
|
53
|
+
readonly leaf: DecodedKeySegment;
|
|
54
|
+
readonly ancestors: ReadonlyArray<DecodedKeySegment>;
|
|
55
|
+
readonly unresolvedPrefixes: ReadonlyArray<string>;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Builds the built-in `model-decode` MCP tool definition.
|
|
59
|
+
*
|
|
60
|
+
* Mirrors dbx-cli's `model-decode <key>` command:
|
|
61
|
+
* - Splits the supplied Firestore key on `/`, walks `[prefix, id]` pairs, and resolves each prefix
|
|
62
|
+
* against the manifest.
|
|
63
|
+
* - Supports subcollection paths (`parentPrefix/parentId/childPrefix/childId`).
|
|
64
|
+
*
|
|
65
|
+
* Output is delivered as both stringified JSON in `content[0].text` and `structuredContent` so
|
|
66
|
+
* MCP clients can consume either form.
|
|
67
|
+
*
|
|
68
|
+
* @param deps - The frozen model manifest loaded at boot from the MCP manifest JSON.
|
|
69
|
+
* @returns A statically-registered {@link McpToolDefinition} ready to be appended to the MCP
|
|
70
|
+
* server factory's tool registry.
|
|
71
|
+
*/
|
|
72
|
+
export declare function createModelDecodeTool(deps: CreateModelDecodeToolDeps): McpToolDefinition;
|
|
73
|
+
/**
|
|
74
|
+
* Splits `rawKey` on `/`, resolves each `[prefix, id]` pair against the manifest, and
|
|
75
|
+
* returns the leaf segment + ancestor chain.
|
|
76
|
+
*
|
|
77
|
+
* Mirrors the dbx-cli `decodeFirestoreModelKey` helper structurally; both implementations
|
|
78
|
+
* must stay in lockstep on segment count and resolution order.
|
|
79
|
+
*
|
|
80
|
+
* @param rawKey - The Firestore key string.
|
|
81
|
+
* @param manifest - The model manifest.
|
|
82
|
+
* @returns The decoded key with leaf, ancestors, and any unresolved prefixes.
|
|
83
|
+
* @throws {Error} When `rawKey` is empty or does not parse into an even number of `prefix/id` segments.
|
|
84
|
+
*
|
|
85
|
+
* @__NO_SIDE_EFFECTS__
|
|
86
|
+
*/
|
|
87
|
+
export declare function decodeFirestoreModelKey(rawKey: string, manifest: ReadonlyArray<McpManifestModelEntry>): ModelDecodeToolOutput;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { type Maybe } from '@dereekb/util';
|
|
2
|
+
import { type FirestoreModelIdentity, type FirestoreModelKey, type FirestoreModelType } from '@dereekb/firebase';
|
|
3
|
+
import { type ModelAccessMultiReadResult, type FirebaseServerAuthData } from '@dereekb/firebase-server';
|
|
4
|
+
import { type McpToolDefinition } from '../mcp.tool-generator';
|
|
5
|
+
/**
|
|
6
|
+
* Reserved tool name for the built-in `model-get` static tool.
|
|
7
|
+
*/
|
|
8
|
+
export declare const MODEL_GET_TOOL_NAME = "model-get";
|
|
9
|
+
/**
|
|
10
|
+
* Synthetic call type used in the tool's dispatch identity. Aligns with the dbx-cli `get`
|
|
11
|
+
* command and the `/api/model/:modelType/get` HTTP endpoint that backs it.
|
|
12
|
+
*/
|
|
13
|
+
export declare const MODEL_GET_DISPATCH_CALL = "get";
|
|
14
|
+
/**
|
|
15
|
+
* Synthetic model type used in the tool's dispatch identity. The tool itself isn't bound to a
|
|
16
|
+
* specific model type (the `modelType` is part of its input), so we use the literal "model" as
|
|
17
|
+
* the identity. Apps avoiding collision should not register a real model literally named
|
|
18
|
+
* "model".
|
|
19
|
+
*/
|
|
20
|
+
export declare const MODEL_GET_DISPATCH_MODEL_TYPE = "model";
|
|
21
|
+
/**
|
|
22
|
+
* Maximum number of keys per backend multi-read request. Matches
|
|
23
|
+
* `MAX_MODEL_ACCESS_MULTI_READ_KEYS` exported from `@dereekb/firebase-server`; mirrored as a
|
|
24
|
+
* local constant so the bundler doesn't have to follow the import chain just for one number.
|
|
25
|
+
*/
|
|
26
|
+
export declare const MCP_MODEL_GET_BATCH_SIZE = 50;
|
|
27
|
+
/**
|
|
28
|
+
* Per-batch read function. Identical signature to {@link ModelApiGetService.readDocuments} so the
|
|
29
|
+
* service method can be passed directly.
|
|
30
|
+
*/
|
|
31
|
+
export type McpModelGetReadDocuments = (modelType: FirestoreModelType, keys: FirestoreModelKey[], auth: Maybe<FirebaseServerAuthData>) => Promise<ModelAccessMultiReadResult>;
|
|
32
|
+
/**
|
|
33
|
+
* Lookup function that resolves a `modelType` to its registered {@link FirestoreModelIdentity}.
|
|
34
|
+
*
|
|
35
|
+
* Takes the request's auth so the wiring layer can build a real model context on first use
|
|
36
|
+
* (the underlying `getFirestoreCollection(context)` accessor is context-dependent). Returns
|
|
37
|
+
* `undefined` for unknown model types; the handler surfaces this as a user-visible error.
|
|
38
|
+
*/
|
|
39
|
+
export type McpModelGetResolveIdentity = (modelType: FirestoreModelType, auth: Maybe<FirebaseServerAuthData>) => Maybe<FirestoreModelIdentity>;
|
|
40
|
+
/**
|
|
41
|
+
* Constructor dependencies for {@link createModelGetTool}.
|
|
42
|
+
*/
|
|
43
|
+
export interface CreateModelGetToolDeps {
|
|
44
|
+
/**
|
|
45
|
+
* Reads a batch of model documents. Provided as a callback so the unit tests can mock it
|
|
46
|
+
* without instantiating the Nest DI container.
|
|
47
|
+
*/
|
|
48
|
+
readonly readDocuments: McpModelGetReadDocuments;
|
|
49
|
+
/**
|
|
50
|
+
* Resolves the registered identity for a model type so bare ids can be promoted into full
|
|
51
|
+
* `prefix/id` keys.
|
|
52
|
+
*/
|
|
53
|
+
readonly resolveIdentity: McpModelGetResolveIdentity;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Shape of the `model-get` tool input.
|
|
57
|
+
*/
|
|
58
|
+
export interface ModelGetToolInput {
|
|
59
|
+
readonly modelType: string;
|
|
60
|
+
readonly keys: ReadonlyArray<string>;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Builds the built-in `model-get` MCP tool definition.
|
|
64
|
+
*
|
|
65
|
+
* Mirrors dbx-cli's `get` / `get-many` behavior:
|
|
66
|
+
* - Accepts an array of keys; values containing `/` are treated as full keys and passed verbatim
|
|
67
|
+
* while bare ids are promoted to `${collectionName}/${id}` for root models.
|
|
68
|
+
* - Nested (subcollection) models reject bare ids since a parent path is required.
|
|
69
|
+
* - Auto-chunks at {@link MCP_MODEL_GET_BATCH_SIZE} keys per backend call, mirroring
|
|
70
|
+
* `getMultipleModelsOverHttpChunked` on the CLI side.
|
|
71
|
+
*
|
|
72
|
+
* The handler returns the same `{ results, errors }` shape produced by
|
|
73
|
+
* `ModelApiGetService.readDocuments`, exposed via both the text content block and
|
|
74
|
+
* `structuredContent` so MCP clients can consume either form.
|
|
75
|
+
*
|
|
76
|
+
* @param deps - Read-documents and identity-resolver callbacks (typically wired to
|
|
77
|
+
* `ModelApiGetService`).
|
|
78
|
+
* @returns A statically-registered {@link McpToolDefinition} ready to be appended to the MCP
|
|
79
|
+
* server factory's tool registry.
|
|
80
|
+
*/
|
|
81
|
+
export declare function createModelGetTool(deps: CreateModelGetToolDeps): McpToolDefinition;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { type McpManifestModelEntry } from '../mcp.manifest';
|
|
2
|
+
import { type McpToolDefinition } from '../mcp.tool-generator';
|
|
3
|
+
/**
|
|
4
|
+
* Reserved tool name for the built-in `model-info` static tool.
|
|
5
|
+
*/
|
|
6
|
+
export declare const MODEL_INFO_TOOL_NAME = "model-info";
|
|
7
|
+
/**
|
|
8
|
+
* Synthetic call type used in the tool's dispatch identity. Aligns with the dbx-cli `model-info`
|
|
9
|
+
* command.
|
|
10
|
+
*/
|
|
11
|
+
export declare const MODEL_INFO_DISPATCH_CALL = "info";
|
|
12
|
+
/**
|
|
13
|
+
* Synthetic model type used in the tool's dispatch identity. Mirrors {@link MODEL_GET_DISPATCH_MODEL_TYPE};
|
|
14
|
+
* apps avoiding collisions should not register a real model literally named "model".
|
|
15
|
+
*/
|
|
16
|
+
export declare const MODEL_INFO_DISPATCH_MODEL_TYPE = "model";
|
|
17
|
+
/**
|
|
18
|
+
* Constructor dependencies for {@link createModelInfoTool}.
|
|
19
|
+
*/
|
|
20
|
+
export interface CreateModelInfoToolDeps {
|
|
21
|
+
/**
|
|
22
|
+
* Frozen catalog of Firestore models exposed by the host app, sourced from the build-time
|
|
23
|
+
* manifest JSON.
|
|
24
|
+
*/
|
|
25
|
+
readonly manifest: readonly McpManifestModelEntry[];
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Shape of the `model-info` tool input. Omit `model` to list every model in the manifest.
|
|
29
|
+
*/
|
|
30
|
+
export interface ModelInfoToolInput {
|
|
31
|
+
readonly model?: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Summary row returned in list mode.
|
|
35
|
+
*/
|
|
36
|
+
export interface ModelInfoSummaryRow {
|
|
37
|
+
readonly modelType: string;
|
|
38
|
+
readonly modelName: string;
|
|
39
|
+
readonly modelGroup?: string;
|
|
40
|
+
readonly identityConst: string;
|
|
41
|
+
readonly collectionPrefix: string;
|
|
42
|
+
readonly parentIdentityConst?: string;
|
|
43
|
+
readonly sourcePackage: string;
|
|
44
|
+
readonly fieldCount: number;
|
|
45
|
+
readonly description?: string;
|
|
46
|
+
readonly read?: 'system' | 'owner' | 'admin-only' | 'permissions';
|
|
47
|
+
readonly serviceFactoryExport?: string;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Output payload for the `model-info` tool. `mode === 'list'` carries `models[]`;
|
|
51
|
+
* `mode === 'single'` carries the full `model` entry.
|
|
52
|
+
*/
|
|
53
|
+
export type ModelInfoToolOutput = {
|
|
54
|
+
readonly mode: 'list';
|
|
55
|
+
readonly models: ReadonlyArray<ModelInfoSummaryRow>;
|
|
56
|
+
} | {
|
|
57
|
+
readonly mode: 'single';
|
|
58
|
+
readonly model: McpManifestModelEntry;
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* Builds the built-in `model-info` MCP tool definition.
|
|
62
|
+
*
|
|
63
|
+
* Mirrors dbx-cli's `model-info [model]` command:
|
|
64
|
+
* - Without a `model` arg: returns a summary list (modelType, modelName, prefix, group, identity, field count).
|
|
65
|
+
* - With a `model` arg: matches by `modelType`, `identityConst`, or `collectionPrefix` and returns the full entry.
|
|
66
|
+
*
|
|
67
|
+
* Output is delivered as both stringified JSON in `content[0].text` and `structuredContent`
|
|
68
|
+
* so MCP clients can consume either form.
|
|
69
|
+
*
|
|
70
|
+
* @param deps - The frozen model manifest loaded at boot from the MCP manifest JSON.
|
|
71
|
+
* @returns A statically-registered {@link McpToolDefinition} ready to be appended to the MCP
|
|
72
|
+
* server factory's tool registry.
|
|
73
|
+
*/
|
|
74
|
+
export declare function createModelInfoTool(deps: CreateModelInfoToolDeps): McpToolDefinition;
|
|
75
|
+
/**
|
|
76
|
+
* Resolves a manifest entry by `modelType`, `identityConst`, or `collectionPrefix`.
|
|
77
|
+
*
|
|
78
|
+
* @param query - Identifier to look up.
|
|
79
|
+
* @param manifest - Model manifest to search.
|
|
80
|
+
* @returns The matching entry or `undefined`.
|
|
81
|
+
*
|
|
82
|
+
* @__NO_SIDE_EFFECTS__
|
|
83
|
+
*/
|
|
84
|
+
export declare function findModelEntry(query: string, manifest: ReadonlyArray<McpManifestModelEntry>): McpManifestModelEntry | undefined;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { type McpAuthRoleReader } from '../../mcp.config';
|
|
2
|
+
import { type McpManifestAuth } from '../mcp.manifest';
|
|
3
|
+
import { type McpToolDefinition } from '../mcp.tool-generator';
|
|
4
|
+
/**
|
|
5
|
+
* Reserved tool name for the built-in `whoami` static tool.
|
|
6
|
+
*/
|
|
7
|
+
export declare const WHOAMI_TOOL_NAME = "whoami";
|
|
8
|
+
/**
|
|
9
|
+
* Synthetic call type used in the tool's dispatch identity. Matches the
|
|
10
|
+
* pattern set by `model-info` — `read` (not `info`) so the visibility
|
|
11
|
+
* classifier treats the tool as a read.
|
|
12
|
+
*/
|
|
13
|
+
export declare const WHOAMI_DISPATCH_CALL = "read";
|
|
14
|
+
/**
|
|
15
|
+
* Synthetic model type used in the tool's dispatch identity.
|
|
16
|
+
*/
|
|
17
|
+
export declare const WHOAMI_DISPATCH_MODEL_TYPE = "auth";
|
|
18
|
+
/**
|
|
19
|
+
* Constructor dependencies for {@link createWhoamiTool}.
|
|
20
|
+
*/
|
|
21
|
+
export interface CreateWhoamiToolDeps {
|
|
22
|
+
/**
|
|
23
|
+
* Auth section loaded from the pre-rendered MCP manifest JSON. Drives the
|
|
24
|
+
* description text plus the role-detail enrichment for claim keys present
|
|
25
|
+
* on the live token.
|
|
26
|
+
*/
|
|
27
|
+
readonly auth: McpManifestAuth;
|
|
28
|
+
/**
|
|
29
|
+
* Optional role reader. When present, decodes the live token's claims into
|
|
30
|
+
* a {@link AuthRoleSet}; the resulting roles are returned alongside the
|
|
31
|
+
* claim details. When absent, `roles` is empty.
|
|
32
|
+
*/
|
|
33
|
+
readonly roleReader?: McpAuthRoleReader;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* One entry returned in `claimDetails`. Mirrors the `dbx_auth_list_app`
|
|
37
|
+
* formatter shape minus source paths.
|
|
38
|
+
*/
|
|
39
|
+
export interface WhoamiClaimDetail {
|
|
40
|
+
readonly key: string;
|
|
41
|
+
readonly interfaceName?: string;
|
|
42
|
+
readonly description: string;
|
|
43
|
+
readonly grantedRoles: readonly string[];
|
|
44
|
+
readonly inverse: boolean;
|
|
45
|
+
readonly tags: readonly string[];
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Output payload for the `whoami` tool.
|
|
49
|
+
*/
|
|
50
|
+
export interface WhoamiToolOutput {
|
|
51
|
+
readonly authenticated: boolean;
|
|
52
|
+
readonly uid?: string;
|
|
53
|
+
readonly email?: string;
|
|
54
|
+
readonly emailVerified?: boolean;
|
|
55
|
+
readonly app?: string;
|
|
56
|
+
readonly claims: Readonly<Record<string, unknown>>;
|
|
57
|
+
readonly roles: readonly string[];
|
|
58
|
+
readonly claimDetails: readonly WhoamiClaimDetail[];
|
|
59
|
+
readonly unknownClaimKeys: readonly string[];
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Builds the built-in `whoami` MCP tool definition. Returns the calling
|
|
63
|
+
* caller's `uid`, claims object, decoded role set, and rendered descriptions
|
|
64
|
+
* for every claim key actually present on the live token.
|
|
65
|
+
*
|
|
66
|
+
* Unauthenticated callers receive a structured `authenticated: false` result
|
|
67
|
+
* (no exception) so the tool can be used as a "do you see me?" probe.
|
|
68
|
+
*
|
|
69
|
+
* @param deps - The manifest's auth section + optional role reader.
|
|
70
|
+
* @returns A statically-registered {@link McpToolDefinition} to append to the MCP server factory's tool registry.
|
|
71
|
+
*/
|
|
72
|
+
export declare function createWhoamiTool(deps: CreateWhoamiToolDeps): McpToolDefinition;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './streamable-http.transport';
|