firebase-tools 14.27.0 → 15.1.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/lib/appUtils.js +14 -15
- package/lib/archiveDirectory.js +7 -45
- package/lib/bin/cli.js +35 -8
- package/lib/bin/mcp.js +46 -8
- package/lib/command.js +5 -1
- package/lib/commands/dataconnect-execute.js +1 -1
- package/lib/commands/dataconnect-sdk-generate.js +7 -5
- package/lib/commands/dataconnect-sql-diff.js +7 -5
- package/lib/commands/dataconnect-sql-grant.js +12 -12
- package/lib/commands/dataconnect-sql-migrate.js +6 -4
- package/lib/commands/dataconnect-sql-setup.js +6 -4
- package/lib/commands/dataconnect-sql-shell.js +6 -4
- package/lib/commands/firestore-backups-list.js +1 -1
- package/lib/commands/functions-config-clone.js +2 -2
- package/lib/commands/functions-config-export.js +137 -92
- package/lib/commands/functions-config-get.js +1 -2
- package/lib/commands/functions-config-set.js +2 -2
- package/lib/commands/functions-config-unset.js +2 -2
- package/lib/commands/help.js +1 -1
- package/lib/commands/index.js +15 -10
- package/lib/commands/init.js +8 -0
- package/lib/config.js +1 -5
- package/lib/dataconnect/load.js +18 -21
- package/lib/deploy/database/prepare.js +1 -3
- package/lib/deploy/functions/prepare.js +5 -1
- package/lib/deploy/functions/prepareFunctionsUpload.js +1 -2
- package/lib/deploy/functions/runtimes/node/index.js +11 -12
- package/lib/deploy/functions/runtimes/node/versioning.js +2 -2
- package/lib/deploy/functions/validate.js +49 -2
- package/lib/emulator/commandUtils.js +1 -1
- package/lib/emulator/controller.js +1 -2
- package/lib/emulator/databaseEmulator.js +1 -5
- package/lib/emulator/downloadableEmulatorInfo.json +30 -30
- package/lib/emulator/functionsEmulator.js +0 -40
- package/lib/emulator/functionsEmulatorRuntime.js +1 -118
- package/lib/emulator/functionsEmulatorShared.js +1 -6
- package/lib/experiments.js +8 -1
- package/lib/extensions/extensionsHelper.js +0 -1
- package/lib/frameworks/constants.js +1 -1
- package/lib/fsAsync.js +11 -3
- package/lib/functionsConfig.js +39 -1
- package/lib/gcp/cloudsql/cloudsqladmin.js +1 -1
- package/lib/index.js +44 -1
- package/lib/init/features/dataconnect/resolver.js +111 -0
- package/lib/init/features/index.js +4 -1
- package/lib/init/features/project.js +1 -0
- package/lib/init/index.js +5 -0
- package/lib/mcp/index.js +31 -22
- package/lib/mcp/tools/core/get_environment.js +4 -1
- package/lib/mcp/tools/dataconnect/compile.js +13 -7
- package/lib/mcp/tools/dataconnect/execute.js +10 -7
- package/lib/mcp/tools/dataconnect/generate_operation.js +7 -3
- package/lib/mcp/tools/index.js +53 -44
- package/package.json +1 -2
- package/lib/deploy/functions/runtimes/node/extractTriggers.js +0 -23
- package/lib/deploy/functions/runtimes/node/parseTriggers.js +0 -332
- package/lib/deploy/functions/runtimes/node/triggerParser.js +0 -72
- package/lib/functions/deprecationWarnings.js +0 -21
- package/lib/functions/runtimeConfigExport.js +0 -141
- package/lib/handlePreviewToggles.js +0 -38
- package/lib/parseBoltRules.js +0 -29
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.addSchemaToDataConnectYaml = exports.actuate = exports.askQuestions = void 0;
|
|
4
|
+
const clc = require("colorette");
|
|
5
|
+
const fs = require("fs-extra");
|
|
6
|
+
const path_1 = require("path");
|
|
7
|
+
const yaml = require("yaml");
|
|
8
|
+
const prompt_1 = require("../../../prompt");
|
|
9
|
+
const utils_1 = require("../../../utils");
|
|
10
|
+
const load_1 = require("../../../dataconnect/load");
|
|
11
|
+
const names_1 = require("../../../dataconnect/names");
|
|
12
|
+
const experiments = require("../../../experiments");
|
|
13
|
+
const cloudbilling_1 = require("../../../gcp/cloudbilling");
|
|
14
|
+
const track_1 = require("../../../track");
|
|
15
|
+
async function askQuestions(setup, config) {
|
|
16
|
+
var _a;
|
|
17
|
+
const resolverInfo = {
|
|
18
|
+
id: "",
|
|
19
|
+
uri: "",
|
|
20
|
+
serviceInfo: {},
|
|
21
|
+
};
|
|
22
|
+
const serviceInfos = await (0, load_1.loadAll)(setup.projectId || "", config);
|
|
23
|
+
if (!serviceInfos.length) {
|
|
24
|
+
throw new Error(`No Firebase Data Connect workspace found. Run ${clc.bold("firebase init dataconnect")} to set up a service and main schema.`);
|
|
25
|
+
}
|
|
26
|
+
else if (serviceInfos.length === 1) {
|
|
27
|
+
resolverInfo.serviceInfo = serviceInfos[0];
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
const choices = serviceInfos.map((si) => {
|
|
31
|
+
const serviceName = (0, names_1.parseServiceName)(si.serviceName);
|
|
32
|
+
return {
|
|
33
|
+
name: `${serviceName.location}/${serviceName.serviceId}`,
|
|
34
|
+
value: si,
|
|
35
|
+
};
|
|
36
|
+
});
|
|
37
|
+
resolverInfo.serviceInfo = await (0, prompt_1.select)({
|
|
38
|
+
message: "Which service would you like to set up a custom resolver for?",
|
|
39
|
+
choices,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
resolverInfo.id = await (0, prompt_1.input)({
|
|
43
|
+
message: `What ID would you like to use for your custom resolver?`,
|
|
44
|
+
default: (0, utils_1.newUniqueId)(`resolver`, ((_a = resolverInfo.serviceInfo.dataConnectYaml.schemas) === null || _a === void 0 ? void 0 : _a.map((sch) => sch.id || "")) || []),
|
|
45
|
+
});
|
|
46
|
+
resolverInfo.uri = `https://${resolverInfo.id}-${setup.projectNumber || "PROJECT_NUMBER"}.${resolverInfo.serviceInfo.dataConnectYaml.location}.run.app/graphql`;
|
|
47
|
+
(0, utils_1.logBullet)("Setting " +
|
|
48
|
+
clc.bold(resolverInfo.uri) +
|
|
49
|
+
" as the custom resolver URL. To change this, update your " +
|
|
50
|
+
clc.bold(`dataconnect.yaml`) +
|
|
51
|
+
" later.");
|
|
52
|
+
setup.featureInfo = setup.featureInfo || {};
|
|
53
|
+
setup.featureInfo.dataconnectResolver = resolverInfo;
|
|
54
|
+
}
|
|
55
|
+
exports.askQuestions = askQuestions;
|
|
56
|
+
async function actuate(setup, config) {
|
|
57
|
+
var _a;
|
|
58
|
+
if (!experiments.isEnabled("fdcwebhooks")) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
const resolverInfo = (_a = setup.featureInfo) === null || _a === void 0 ? void 0 : _a.dataconnectResolver;
|
|
62
|
+
if (!resolverInfo) {
|
|
63
|
+
throw new Error("Data Connect resolver feature ResolverRequiredInfo not provided");
|
|
64
|
+
}
|
|
65
|
+
const startTime = Date.now();
|
|
66
|
+
try {
|
|
67
|
+
actuateWithInfo(config, resolverInfo);
|
|
68
|
+
}
|
|
69
|
+
finally {
|
|
70
|
+
const source = "init_resolver";
|
|
71
|
+
void (0, track_1.trackGA4)("dataconnect_init", {
|
|
72
|
+
source,
|
|
73
|
+
project_status: setup.projectId
|
|
74
|
+
? (await (0, cloudbilling_1.isBillingEnabled)(setup))
|
|
75
|
+
? "blaze"
|
|
76
|
+
: "spark"
|
|
77
|
+
: "missing",
|
|
78
|
+
}, Date.now() - startTime);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
exports.actuate = actuate;
|
|
82
|
+
function actuateWithInfo(config, info) {
|
|
83
|
+
var _a;
|
|
84
|
+
const dataConnectYaml = JSON.parse(JSON.stringify((_a = info.serviceInfo) === null || _a === void 0 ? void 0 : _a.dataConnectYaml));
|
|
85
|
+
addSchemaToDataConnectYaml(dataConnectYaml, info);
|
|
86
|
+
info.serviceInfo.dataConnectYaml = dataConnectYaml;
|
|
87
|
+
const dataConnectYamlContents = yaml.stringify(dataConnectYaml);
|
|
88
|
+
const dataConnectYamlPath = (0, path_1.join)(info.serviceInfo.sourceDirectory, "dataconnect.yaml");
|
|
89
|
+
config.writeProjectFile((0, path_1.relative)(config.projectDir, dataConnectYamlPath), dataConnectYamlContents);
|
|
90
|
+
fs.ensureFileSync((0, path_1.join)(info.serviceInfo.sourceDirectory, `schema_${info.id}`, "schema.gql"));
|
|
91
|
+
}
|
|
92
|
+
function addSchemaToDataConnectYaml(dataConnectYaml, info) {
|
|
93
|
+
const secondarySchema = {
|
|
94
|
+
source: `./schema_${info.id}`,
|
|
95
|
+
id: info.id,
|
|
96
|
+
datasource: {
|
|
97
|
+
httpGraphql: {
|
|
98
|
+
uri: info.uri,
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
if (!dataConnectYaml.schemas) {
|
|
103
|
+
dataConnectYaml.schemas = [];
|
|
104
|
+
if (dataConnectYaml.schema) {
|
|
105
|
+
dataConnectYaml.schemas.push(dataConnectYaml.schema);
|
|
106
|
+
dataConnectYaml.schema = undefined;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
dataConnectYaml.schemas.push(secondarySchema);
|
|
110
|
+
}
|
|
111
|
+
exports.addSchemaToDataConnectYaml = addSchemaToDataConnectYaml;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.aiLogicActuate = exports.aiLogicAskQuestions = exports.aitools = exports.apptestingAcutate = exports.apptestingAskQuestions = exports.genkit = exports.apphosting = exports.dataconnectSdkActuate = exports.dataconnectSdkAskQuestions = exports.dataconnectActuate = exports.dataconnectAskQuestions = exports.hostingGithub = exports.remoteconfig = exports.project = exports.extensions = exports.emulators = exports.storageActuate = exports.storageAskQuestions = exports.hostingActuate = exports.hostingAskQuestions = exports.functions = exports.firestoreActuate = exports.firestoreAskQuestions = exports.databaseActuate = exports.databaseAskQuestions = exports.account = void 0;
|
|
3
|
+
exports.aiLogicActuate = exports.aiLogicAskQuestions = exports.aitools = exports.apptestingAcutate = exports.apptestingAskQuestions = exports.genkit = exports.apphosting = exports.dataconnectResolverActuate = exports.dataconnectResolverAskQuestions = exports.dataconnectSdkActuate = exports.dataconnectSdkAskQuestions = exports.dataconnectActuate = exports.dataconnectAskQuestions = exports.hostingGithub = exports.remoteconfig = exports.project = exports.extensions = exports.emulators = exports.storageActuate = exports.storageAskQuestions = exports.hostingActuate = exports.hostingAskQuestions = exports.functions = exports.firestoreActuate = exports.firestoreAskQuestions = exports.databaseActuate = exports.databaseAskQuestions = exports.account = void 0;
|
|
4
4
|
var account_1 = require("./account");
|
|
5
5
|
Object.defineProperty(exports, "account", { enumerable: true, get: function () { return account_1.doSetup; } });
|
|
6
6
|
var database_1 = require("./database");
|
|
@@ -33,6 +33,9 @@ Object.defineProperty(exports, "dataconnectActuate", { enumerable: true, get: fu
|
|
|
33
33
|
var sdk_1 = require("./dataconnect/sdk");
|
|
34
34
|
Object.defineProperty(exports, "dataconnectSdkAskQuestions", { enumerable: true, get: function () { return sdk_1.askQuestions; } });
|
|
35
35
|
Object.defineProperty(exports, "dataconnectSdkActuate", { enumerable: true, get: function () { return sdk_1.actuate; } });
|
|
36
|
+
var resolver_1 = require("./dataconnect/resolver");
|
|
37
|
+
Object.defineProperty(exports, "dataconnectResolverAskQuestions", { enumerable: true, get: function () { return resolver_1.askQuestions; } });
|
|
38
|
+
Object.defineProperty(exports, "dataconnectResolverActuate", { enumerable: true, get: function () { return resolver_1.actuate; } });
|
|
36
39
|
var apphosting_1 = require("./apphosting");
|
|
37
40
|
Object.defineProperty(exports, "apphosting", { enumerable: true, get: function () { return apphosting_1.doSetup; } });
|
|
38
41
|
var genkit_1 = require("./genkit");
|
|
@@ -88,6 +88,7 @@ async function usingProjectMetadata(setup, config, pm) {
|
|
|
88
88
|
}
|
|
89
89
|
_.set(setup.rcfile, "projects.default", pm.projectId);
|
|
90
90
|
setup.projectId = pm.projectId;
|
|
91
|
+
setup.projectNumber = pm.projectNumber;
|
|
91
92
|
setup.instance = (_a = pm.resources) === null || _a === void 0 ? void 0 : _a.realtimeDatabaseInstance;
|
|
92
93
|
setup.projectLocation = (_b = pm.resources) === null || _b === void 0 ? void 0 : _b.locationId;
|
|
93
94
|
utils.makeActiveProject(config.projectDir, pm.projectId);
|
package/lib/init/index.js
CHANGED
|
@@ -29,6 +29,11 @@ const featuresList = [
|
|
|
29
29
|
askQuestions: features.dataconnectSdkAskQuestions,
|
|
30
30
|
actuate: features.dataconnectSdkActuate,
|
|
31
31
|
},
|
|
32
|
+
{
|
|
33
|
+
name: "dataconnect:resolver",
|
|
34
|
+
askQuestions: features.dataconnectResolverAskQuestions,
|
|
35
|
+
actuate: features.dataconnectResolverActuate,
|
|
36
|
+
},
|
|
32
37
|
{ name: "functions", doSetup: features.functions },
|
|
33
38
|
{
|
|
34
39
|
name: "hosting",
|
package/lib/mcp/index.js
CHANGED
|
@@ -4,26 +4,27 @@ exports.FirebaseMcpServer = void 0;
|
|
|
4
4
|
const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
|
|
5
5
|
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
6
6
|
const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const index_1 = require("./tools/index");
|
|
10
|
-
const index_2 = require("./prompts/index");
|
|
11
|
-
const configstore_1 = require("../configstore");
|
|
7
|
+
const crossSpawn = require("cross-spawn");
|
|
8
|
+
const node_fs_1 = require("node:fs");
|
|
12
9
|
const command_1 = require("../command");
|
|
13
|
-
const requireAuth_1 = require("../requireAuth");
|
|
14
|
-
const projectUtils_1 = require("../projectUtils");
|
|
15
|
-
const errors_1 = require("./errors");
|
|
16
|
-
const track_1 = require("../track");
|
|
17
10
|
const config_1 = require("../config");
|
|
18
|
-
const
|
|
11
|
+
const configstore_1 = require("../configstore");
|
|
19
12
|
const hubClient_1 = require("../emulator/hubClient");
|
|
20
|
-
const node_fs_1 = require("node:fs");
|
|
21
|
-
const logging_transport_1 = require("./logging-transport");
|
|
22
13
|
const env_1 = require("../env");
|
|
14
|
+
const projectUtils_1 = require("../projectUtils");
|
|
15
|
+
const rc_1 = require("../rc");
|
|
16
|
+
const requireAuth_1 = require("../requireAuth");
|
|
23
17
|
const timeout_1 = require("../timeout");
|
|
18
|
+
const track_1 = require("../track");
|
|
19
|
+
const errors_1 = require("./errors");
|
|
20
|
+
const logging_transport_1 = require("./logging-transport");
|
|
21
|
+
const index_1 = require("./prompts/index");
|
|
24
22
|
const resources_1 = require("./resources");
|
|
25
|
-
const
|
|
23
|
+
const index_2 = require("./tools/index");
|
|
24
|
+
const types_1 = require("./types");
|
|
25
|
+
const util_1 = require("./util");
|
|
26
26
|
const availability_1 = require("./util/availability");
|
|
27
|
+
const cloudbilling_1 = require("../gcp/cloudbilling");
|
|
27
28
|
const SERVER_VERSION = "0.3.0";
|
|
28
29
|
const cmd = new command_1.Command("mcp");
|
|
29
30
|
const orderedLogLevels = [
|
|
@@ -55,6 +56,7 @@ class FirebaseMcpServer {
|
|
|
55
56
|
this.currentLogLevel = process.env.FIREBASE_MCP_DEBUG_LOG ? "debug" : undefined;
|
|
56
57
|
this.activeFeatures = options.activeFeatures;
|
|
57
58
|
this.startupRoot = options.projectRoot || process.env.PROJECT_ROOT;
|
|
59
|
+
this.enabledTools = options.enabledTools;
|
|
58
60
|
this.server = new index_js_1.Server({ name: "firebase", version: SERVER_VERSION });
|
|
59
61
|
this.server.registerCapabilities({
|
|
60
62
|
tools: { listChanged: true },
|
|
@@ -135,7 +137,8 @@ class FirebaseMcpServer {
|
|
|
135
137
|
this.logger.debug("detecting active features of Firebase MCP server...");
|
|
136
138
|
const projectId = (await this.getProjectId()) || "";
|
|
137
139
|
const accountEmail = await this.getAuthenticatedUser();
|
|
138
|
-
const
|
|
140
|
+
const isBillingEnabled = projectId ? await (0, cloudbilling_1.checkBillingEnabled)(projectId) : false;
|
|
141
|
+
const ctx = this._createMcpContext(projectId, accountEmail, isBillingEnabled);
|
|
139
142
|
const detected = await Promise.all(types_1.SERVER_FEATURES.map(async (f) => {
|
|
140
143
|
const availabilityCheck = (0, availability_1.getDefaultFeatureAvailabilityCheck)(f);
|
|
141
144
|
if (await availabilityCheck(ctx))
|
|
@@ -172,8 +175,9 @@ class FirebaseMcpServer {
|
|
|
172
175
|
const features = ((_a = this.activeFeatures) === null || _a === void 0 ? void 0 : _a.length) ? this.activeFeatures : this.detectedFeatures;
|
|
173
176
|
const projectId = (await this.getProjectId()) || "";
|
|
174
177
|
const accountEmail = await this.getAuthenticatedUser();
|
|
175
|
-
const
|
|
176
|
-
|
|
178
|
+
const isBillingEnabled = projectId ? await (0, cloudbilling_1.checkBillingEnabled)(projectId) : false;
|
|
179
|
+
const ctx = this._createMcpContext(projectId, accountEmail, isBillingEnabled);
|
|
180
|
+
return (0, index_2.availableTools)(ctx, features, this.enabledTools);
|
|
177
181
|
}
|
|
178
182
|
async getTool(name) {
|
|
179
183
|
const tools = await this.getAvailableTools();
|
|
@@ -184,8 +188,9 @@ class FirebaseMcpServer {
|
|
|
184
188
|
const features = ((_a = this.activeFeatures) === null || _a === void 0 ? void 0 : _a.length) ? this.activeFeatures : this.detectedFeatures;
|
|
185
189
|
const projectId = (await this.getProjectId()) || "";
|
|
186
190
|
const accountEmail = await this.getAuthenticatedUser();
|
|
187
|
-
const
|
|
188
|
-
|
|
191
|
+
const isBillingEnabled = projectId ? await (0, cloudbilling_1.checkBillingEnabled)(projectId) : false;
|
|
192
|
+
const ctx = this._createMcpContext(projectId, accountEmail, isBillingEnabled);
|
|
193
|
+
return (0, index_1.availablePrompts)(ctx, features);
|
|
189
194
|
}
|
|
190
195
|
async getPrompt(name) {
|
|
191
196
|
const prompts = await this.getAvailablePrompts();
|
|
@@ -218,7 +223,7 @@ class FirebaseMcpServer {
|
|
|
218
223
|
return null;
|
|
219
224
|
}
|
|
220
225
|
}
|
|
221
|
-
_createMcpContext(projectId, accountEmail) {
|
|
226
|
+
_createMcpContext(projectId, accountEmail, isBillingEnabled) {
|
|
222
227
|
const options = { projectDir: this.cachedProjectDir, cwd: this.cachedProjectDir };
|
|
223
228
|
return {
|
|
224
229
|
projectId: projectId,
|
|
@@ -227,6 +232,7 @@ class FirebaseMcpServer {
|
|
|
227
232
|
rc: (0, rc_1.loadRC)(options),
|
|
228
233
|
accountEmail,
|
|
229
234
|
firebaseCliCommand: this._getFirebaseCliCommand(),
|
|
235
|
+
isBillingEnabled,
|
|
230
236
|
};
|
|
231
237
|
}
|
|
232
238
|
_getFirebaseCliCommand() {
|
|
@@ -282,7 +288,8 @@ class FirebaseMcpServer {
|
|
|
282
288
|
if (err)
|
|
283
289
|
return err;
|
|
284
290
|
}
|
|
285
|
-
const
|
|
291
|
+
const isBillingEnabled = projectId ? await (0, cloudbilling_1.checkBillingEnabled)(projectId) : false;
|
|
292
|
+
const toolsCtx = this._createMcpContext(projectId, accountEmail, isBillingEnabled);
|
|
286
293
|
try {
|
|
287
294
|
const res = await tool.fn(toolArgs, toolsCtx);
|
|
288
295
|
await this.trackGA4("mcp_tool_call", {
|
|
@@ -332,7 +339,8 @@ class FirebaseMcpServer {
|
|
|
332
339
|
projectId = projectId || "";
|
|
333
340
|
const skipAutoAuthForStudio = (0, env_1.isFirebaseStudio)();
|
|
334
341
|
const accountEmail = await this.getAuthenticatedUser(skipAutoAuthForStudio);
|
|
335
|
-
const
|
|
342
|
+
const isBillingEnabled = projectId ? await (0, cloudbilling_1.checkBillingEnabled)(projectId) : false;
|
|
343
|
+
const promptsCtx = this._createMcpContext(projectId, accountEmail, isBillingEnabled);
|
|
336
344
|
try {
|
|
337
345
|
const messages = await prompt.fn(promptArgs, promptsCtx);
|
|
338
346
|
await this.trackGA4("mcp_get_prompt", {
|
|
@@ -366,7 +374,8 @@ class FirebaseMcpServer {
|
|
|
366
374
|
projectId = projectId || "";
|
|
367
375
|
const skipAutoAuthForStudio = (0, env_1.isFirebaseStudio)();
|
|
368
376
|
const accountEmail = await this.getAuthenticatedUser(skipAutoAuthForStudio);
|
|
369
|
-
const
|
|
377
|
+
const isBillingEnabled = projectId ? await (0, cloudbilling_1.checkBillingEnabled)(projectId) : false;
|
|
378
|
+
const resourceCtx = this._createMcpContext(projectId, accountEmail, isBillingEnabled);
|
|
370
379
|
const resolved = await (0, resources_1.resolveResource)(req.params.uri, resourceCtx);
|
|
371
380
|
if (!resolved) {
|
|
372
381
|
throw new types_js_1.McpError(types_js_1.ErrorCode.InvalidParams, `Resource '${req.params.uri}' could not be found.`);
|
|
@@ -15,6 +15,7 @@ function hydrateTemplate(config) {
|
|
|
15
15
|
: "<NONE>";
|
|
16
16
|
const projectConfigPath = config.projectConfigPath || "<NO CONFIG PRESENT>";
|
|
17
17
|
const geminiTosAccepted = config.geminiTosAccepted ? "Accepted" : "<NOT ACCEPTED>";
|
|
18
|
+
const billingEnabled = config.projectId ? (config.isBillingEnabled ? "Yes" : "No") : "N/A";
|
|
18
19
|
const authenticatedUser = config.authenticatedUser || "<NONE>";
|
|
19
20
|
const detectedApps = Object.entries(config.detectedAppIds).length > 0
|
|
20
21
|
? `\n\n${(0, js_yaml_1.dump)(config.detectedAppIds).trim()}\n`
|
|
@@ -30,6 +31,7 @@ Project Directory: ${config.projectDir}
|
|
|
30
31
|
Project Config Path: ${projectConfigPath}
|
|
31
32
|
Active Project ID: ${activeProject}
|
|
32
33
|
Gemini in Firebase Terms of Service: ${geminiTosAccepted}
|
|
34
|
+
Billing Enabled: ${billingEnabled}
|
|
33
35
|
Authenticated User: ${authenticatedUser}
|
|
34
36
|
Detected App IDs: ${detectedApps}
|
|
35
37
|
Available Project Aliases (format: '[alias]: [projectId]'): ${availableProjects}${hasOtherAccounts ? `\nAvailable Accounts: \n\n${availableAccounts}` : ""}
|
|
@@ -63,7 +65,7 @@ exports.get_environment = (0, tool_1.tool)("core", {
|
|
|
63
65
|
requiresAuth: false,
|
|
64
66
|
requiresProject: false,
|
|
65
67
|
},
|
|
66
|
-
}, async (_, { projectId, host, accountEmail, rc, config }) => {
|
|
68
|
+
}, async (_, { projectId, host, accountEmail, rc, config, isBillingEnabled }) => {
|
|
67
69
|
const aliases = projectId ? (0, projectUtils_1.getAliases)({ rc }, projectId) : [];
|
|
68
70
|
const geminiTosAccepted = !!configstore_1.configstore.get("gemini");
|
|
69
71
|
const projectFileExists = config.projectFileExists("firebase.json");
|
|
@@ -84,6 +86,7 @@ exports.get_environment = (0, tool_1.tool)("core", {
|
|
|
84
86
|
projectDir: host.cachedProjectDir,
|
|
85
87
|
projectConfigPath: projectFileExists ? config.path("firebase.json") : undefined,
|
|
86
88
|
geminiTosAccepted,
|
|
89
|
+
isBillingEnabled,
|
|
87
90
|
authenticatedUser: accountEmail || undefined,
|
|
88
91
|
projectAliasMap: rc.projects,
|
|
89
92
|
allAccounts,
|
|
@@ -3,8 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.compile = void 0;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
5
|
const tool_1 = require("../../tool");
|
|
6
|
-
const load_1 = require("../../../dataconnect/load");
|
|
7
6
|
const compile_1 = require("../../util/dataconnect/compile");
|
|
7
|
+
const load_1 = require("../../../dataconnect/load");
|
|
8
8
|
exports.compile = (0, tool_1.tool)("dataconnect", {
|
|
9
9
|
name: "build",
|
|
10
10
|
description: "Use this to compile Firebase Data Connect schema, operations, and/or connectors and check for build errors.",
|
|
@@ -16,7 +16,11 @@ exports.compile = (0, tool_1.tool)("dataconnect", {
|
|
|
16
16
|
service_id: zod_1.z
|
|
17
17
|
.string()
|
|
18
18
|
.optional()
|
|
19
|
-
.describe(
|
|
19
|
+
.describe(`Service ID of the Data Connect service to compile. Used to disambiguate when there are multiple Data Connect services in firebase.json.`),
|
|
20
|
+
location_id: zod_1.z
|
|
21
|
+
.string()
|
|
22
|
+
.optional()
|
|
23
|
+
.describe(`Data Connect Service location ID to disambiguate among multiple Data Connect services.`),
|
|
20
24
|
}),
|
|
21
25
|
annotations: {
|
|
22
26
|
title: "Compile Data Connect",
|
|
@@ -26,15 +30,17 @@ exports.compile = (0, tool_1.tool)("dataconnect", {
|
|
|
26
30
|
requiresProject: false,
|
|
27
31
|
requiresAuth: false,
|
|
28
32
|
},
|
|
29
|
-
}, async ({ service_id, error_filter }, { projectId, config }) => {
|
|
30
|
-
const
|
|
31
|
-
const errors = await (
|
|
32
|
-
|
|
33
|
+
}, async ({ service_id, location_id, error_filter }, { projectId, config }) => {
|
|
34
|
+
const serviceInfos = await (0, load_1.pickServices)(projectId, config, service_id || undefined, location_id || undefined);
|
|
35
|
+
const errors = (await Promise.all(serviceInfos.map(async (serviceInfo) => {
|
|
36
|
+
return await (0, compile_1.compileErrors)(serviceInfo.sourceDirectory, error_filter);
|
|
37
|
+
}))).flat();
|
|
38
|
+
if (errors.length > 0)
|
|
33
39
|
return {
|
|
34
40
|
content: [
|
|
35
41
|
{
|
|
36
42
|
type: "text",
|
|
37
|
-
text: `The following errors were encountered while compiling Data Connect
|
|
43
|
+
text: `The following errors were encountered while compiling Data Connect:\n\n${errors.join("\n")}`,
|
|
38
44
|
},
|
|
39
45
|
],
|
|
40
46
|
isError: true,
|
|
@@ -15,11 +15,14 @@ exports.execute = (0, tool_1.tool)("dataconnect", {
|
|
|
15
15
|
You can use the \`dataconnect_generate_operation\` tool to generate a query.
|
|
16
16
|
Example Data Connect schema and example queries can be found in files ending in \`.graphql\` or \`.gql\`.
|
|
17
17
|
`),
|
|
18
|
-
service_id: zod_1.z
|
|
19
|
-
.
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
service_id: zod_1.z
|
|
19
|
+
.string()
|
|
20
|
+
.optional()
|
|
21
|
+
.describe(`Service ID of the Data Connect service to compile. Used to disambiguate when there are multiple Data Connect services in firebase.json.`),
|
|
22
|
+
location_id: zod_1.z
|
|
23
|
+
.string()
|
|
24
|
+
.optional()
|
|
25
|
+
.describe(`Data Connect Service location ID to disambiguate among multiple Data Connect services.`),
|
|
23
26
|
variables_json: zod_1.z
|
|
24
27
|
.string()
|
|
25
28
|
.optional()
|
|
@@ -42,8 +45,8 @@ You can find candidate service_id in \`dataconnect.yaml\`
|
|
|
42
45
|
requiresProject: true,
|
|
43
46
|
requiresAuth: true,
|
|
44
47
|
},
|
|
45
|
-
}, async ({ query, service_id, variables_json: unparsedVariables, use_emulator, auth_token_json: unparsedAuthToken, }, { projectId, config, host }) => {
|
|
46
|
-
const serviceInfo = await (0, load_1.
|
|
48
|
+
}, async ({ query, service_id, location_id, variables_json: unparsedVariables, use_emulator, auth_token_json: unparsedAuthToken, }, { projectId, config, host }) => {
|
|
49
|
+
const serviceInfo = await (0, load_1.pickOneService)(projectId, config, service_id || undefined, location_id || undefined);
|
|
47
50
|
let apiClient;
|
|
48
51
|
if (use_emulator) {
|
|
49
52
|
apiClient = await (0, emulator_1.getDataConnectEmulatorClient)(host);
|
|
@@ -16,7 +16,11 @@ exports.generate_operation = (0, tool_1.tool)("dataconnect", {
|
|
|
16
16
|
service_id: zod_1.z
|
|
17
17
|
.string()
|
|
18
18
|
.optional()
|
|
19
|
-
.describe(
|
|
19
|
+
.describe(`Service ID of the Data Connect service to compile. Used to disambiguate when there are multiple Data Connect services in firebase.json.`),
|
|
20
|
+
location_id: zod_1.z
|
|
21
|
+
.string()
|
|
22
|
+
.optional()
|
|
23
|
+
.describe(`Data Connect Service location ID to disambiguate among multiple Data Connect services.`),
|
|
20
24
|
}),
|
|
21
25
|
annotations: {
|
|
22
26
|
title: "Generate Data Connect Operation",
|
|
@@ -27,8 +31,8 @@ exports.generate_operation = (0, tool_1.tool)("dataconnect", {
|
|
|
27
31
|
requiresAuth: true,
|
|
28
32
|
requiresGemini: true,
|
|
29
33
|
},
|
|
30
|
-
}, async ({ prompt, service_id }, { projectId, config }) => {
|
|
31
|
-
const serviceInfo = await (0, load_1.
|
|
34
|
+
}, async ({ prompt, service_id, location_id }, { projectId, config }) => {
|
|
35
|
+
const serviceInfo = await (0, load_1.pickOneService)(projectId, config, service_id || undefined, location_id || undefined);
|
|
32
36
|
const schema = await (0, fdcExperience_1.generateOperation)(prompt, serviceInfo.serviceName, projectId);
|
|
33
37
|
return (0, util_1.toContent)(schema);
|
|
34
38
|
});
|
package/lib/mcp/tools/index.js
CHANGED
|
@@ -1,20 +1,59 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.markdownDocsOfTools = exports.availableTools = void 0;
|
|
4
|
-
const index_1 = require("./
|
|
5
|
-
const index_2 = require("./
|
|
6
|
-
const index_3 = require("./
|
|
4
|
+
const index_1 = require("./apphosting/index");
|
|
5
|
+
const index_2 = require("./apptesting/index");
|
|
6
|
+
const index_3 = require("./auth/index");
|
|
7
7
|
const index_4 = require("./core/index");
|
|
8
|
-
const index_5 = require("./
|
|
9
|
-
const index_6 = require("./
|
|
10
|
-
const index_7 = require("./
|
|
11
|
-
const index_8 = require("./
|
|
12
|
-
const index_9 = require("./
|
|
13
|
-
const index_10 = require("./
|
|
14
|
-
const index_11 = require("./
|
|
15
|
-
const index_12 = require("./
|
|
16
|
-
|
|
17
|
-
|
|
8
|
+
const index_5 = require("./crashlytics/index");
|
|
9
|
+
const index_6 = require("./dataconnect/index");
|
|
10
|
+
const index_7 = require("./firestore/index");
|
|
11
|
+
const index_8 = require("./functions/index");
|
|
12
|
+
const index_9 = require("./messaging/index");
|
|
13
|
+
const index_10 = require("./realtime_database/index");
|
|
14
|
+
const index_11 = require("./remoteconfig/index");
|
|
15
|
+
const index_12 = require("./storage/index");
|
|
16
|
+
function addFeaturePrefix(feature, tools) {
|
|
17
|
+
return tools.map((tool) => (Object.assign(Object.assign({}, tool), { mcp: Object.assign(Object.assign({}, tool.mcp), { name: `${feature}_${tool.mcp.name}`, _meta: Object.assign(Object.assign({}, tool.mcp._meta), { feature }) }) })));
|
|
18
|
+
}
|
|
19
|
+
const tools = {
|
|
20
|
+
apphosting: addFeaturePrefix("apphosting", index_1.appHostingTools),
|
|
21
|
+
apptesting: addFeaturePrefix("apptesting", index_2.apptestingTools),
|
|
22
|
+
auth: addFeaturePrefix("auth", index_3.authTools),
|
|
23
|
+
core: addFeaturePrefix("firebase", index_4.coreTools),
|
|
24
|
+
crashlytics: addFeaturePrefix("crashlytics", index_5.crashlyticsTools),
|
|
25
|
+
database: addFeaturePrefix("realtimedatabase", index_10.realtimeDatabaseTools),
|
|
26
|
+
dataconnect: addFeaturePrefix("dataconnect", index_6.dataconnectTools),
|
|
27
|
+
firestore: addFeaturePrefix("firestore", index_7.firestoreTools),
|
|
28
|
+
functions: addFeaturePrefix("functions", index_8.functionsTools),
|
|
29
|
+
messaging: addFeaturePrefix("messaging", index_9.messagingTools),
|
|
30
|
+
remoteconfig: addFeaturePrefix("remoteconfig", index_11.remoteConfigTools),
|
|
31
|
+
storage: addFeaturePrefix("storage", index_12.storageTools),
|
|
32
|
+
};
|
|
33
|
+
const allToolsMap = new Map(Object.values(tools)
|
|
34
|
+
.flat()
|
|
35
|
+
.sort((a, b) => a.mcp.name.localeCompare(b.mcp.name))
|
|
36
|
+
.map((t) => [t.mcp.name, t]));
|
|
37
|
+
function getToolsByName(names) {
|
|
38
|
+
const selectedTools = new Set();
|
|
39
|
+
for (const toolName of names) {
|
|
40
|
+
const tool = allToolsMap.get(toolName);
|
|
41
|
+
if (tool) {
|
|
42
|
+
selectedTools.add(tool);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return Array.from(selectedTools);
|
|
46
|
+
}
|
|
47
|
+
function getToolsByFeature(serverFeatures) {
|
|
48
|
+
const features = new Set((serverFeatures === null || serverFeatures === void 0 ? void 0 : serverFeatures.length) ? serverFeatures : Object.keys(tools));
|
|
49
|
+
features.add("core");
|
|
50
|
+
return Array.from(features).flatMap((feature) => tools[feature] || []);
|
|
51
|
+
}
|
|
52
|
+
async function availableTools(ctx, activeFeatures, enabledTools) {
|
|
53
|
+
if (enabledTools === null || enabledTools === void 0 ? void 0 : enabledTools.length) {
|
|
54
|
+
return getToolsByName(enabledTools);
|
|
55
|
+
}
|
|
56
|
+
const allTools = getToolsByFeature(activeFeatures);
|
|
18
57
|
const availabilities = await Promise.all(allTools.map((t) => {
|
|
19
58
|
if (t.isAvailable) {
|
|
20
59
|
return t.isAvailable(ctx);
|
|
@@ -24,39 +63,9 @@ async function availableTools(ctx, activeFeatures) {
|
|
|
24
63
|
return allTools.filter((_, i) => availabilities[i]);
|
|
25
64
|
}
|
|
26
65
|
exports.availableTools = availableTools;
|
|
27
|
-
function getAllTools(activeFeatures) {
|
|
28
|
-
const toolDefs = [];
|
|
29
|
-
if (!(activeFeatures === null || activeFeatures === void 0 ? void 0 : activeFeatures.length)) {
|
|
30
|
-
activeFeatures = Object.keys(tools);
|
|
31
|
-
}
|
|
32
|
-
if (!activeFeatures.includes("core")) {
|
|
33
|
-
activeFeatures.unshift("core");
|
|
34
|
-
}
|
|
35
|
-
for (const key of activeFeatures) {
|
|
36
|
-
toolDefs.push(...tools[key]);
|
|
37
|
-
}
|
|
38
|
-
return toolDefs;
|
|
39
|
-
}
|
|
40
|
-
const tools = {
|
|
41
|
-
core: addFeaturePrefix("firebase", index_4.coreTools),
|
|
42
|
-
firestore: addFeaturePrefix("firestore", index_3.firestoreTools),
|
|
43
|
-
auth: addFeaturePrefix("auth", index_1.authTools),
|
|
44
|
-
dataconnect: addFeaturePrefix("dataconnect", index_2.dataconnectTools),
|
|
45
|
-
storage: addFeaturePrefix("storage", index_5.storageTools),
|
|
46
|
-
messaging: addFeaturePrefix("messaging", index_6.messagingTools),
|
|
47
|
-
functions: addFeaturePrefix("functions", index_12.functionsTools),
|
|
48
|
-
remoteconfig: addFeaturePrefix("remoteconfig", index_7.remoteConfigTools),
|
|
49
|
-
crashlytics: addFeaturePrefix("crashlytics", index_8.crashlyticsTools),
|
|
50
|
-
apptesting: addFeaturePrefix("apptesting", index_10.apptestingTools),
|
|
51
|
-
apphosting: addFeaturePrefix("apphosting", index_9.appHostingTools),
|
|
52
|
-
database: addFeaturePrefix("realtimedatabase", index_11.realtimeDatabaseTools),
|
|
53
|
-
};
|
|
54
|
-
function addFeaturePrefix(feature, tools) {
|
|
55
|
-
return tools.map((tool) => (Object.assign(Object.assign({}, tool), { mcp: Object.assign(Object.assign({}, tool.mcp), { name: `${feature}_${tool.mcp.name}`, _meta: Object.assign(Object.assign({}, tool.mcp._meta), { feature }) }) })));
|
|
56
|
-
}
|
|
57
66
|
function markdownDocsOfTools() {
|
|
58
67
|
var _a, _b, _c;
|
|
59
|
-
const allTools =
|
|
68
|
+
const allTools = getToolsByFeature([]);
|
|
60
69
|
let doc = `
|
|
61
70
|
| Tool Name | Feature Group | Description |
|
|
62
71
|
| --------- | ------------- | ----------- |`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "firebase-tools",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "15.1.0",
|
|
4
4
|
"description": "Command-Line Interface for Firebase",
|
|
5
5
|
"main": "./lib/index.js",
|
|
6
6
|
"mcpName": "io.github.firebase/firebase-mcp",
|
|
@@ -125,7 +125,6 @@
|
|
|
125
125
|
"stream-chain": "^2.2.4",
|
|
126
126
|
"stream-json": "^1.7.3",
|
|
127
127
|
"superstatic": "^10.0.0",
|
|
128
|
-
"tar": "^6.1.11",
|
|
129
128
|
"tcp-port-used": "^1.0.2",
|
|
130
129
|
"tmp": "^0.2.3",
|
|
131
130
|
"triple-beam": "^1.3.0",
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var extractTriggers = function (mod, triggers, prefix) {
|
|
3
|
-
prefix = prefix || "";
|
|
4
|
-
for (var funcName of Object.keys(mod)) {
|
|
5
|
-
var child = mod[funcName];
|
|
6
|
-
if (typeof child === "function" && child.__trigger && typeof child.__trigger === "object") {
|
|
7
|
-
if (funcName.indexOf("-") >= 0) {
|
|
8
|
-
throw new Error('Function name "' + funcName + '" is invalid. Function names cannot contain dashes.');
|
|
9
|
-
}
|
|
10
|
-
var trigger = {};
|
|
11
|
-
for (var key of Object.keys(child.__trigger)) {
|
|
12
|
-
trigger[key] = child.__trigger[key];
|
|
13
|
-
}
|
|
14
|
-
trigger.name = prefix + funcName;
|
|
15
|
-
trigger.entryPoint = trigger.name.replace(/-/g, ".");
|
|
16
|
-
triggers.push(trigger);
|
|
17
|
-
}
|
|
18
|
-
else if (typeof child === "object" && child !== null) {
|
|
19
|
-
extractTriggers(child, triggers, prefix + funcName + "-");
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
};
|
|
23
|
-
module.exports = extractTriggers;
|