firebase-tools 14.2.0 → 14.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/lib/bin/cli.js +131 -0
  2. package/lib/bin/firebase.js +7 -123
  3. package/lib/bin/mcp.js +38 -0
  4. package/lib/commands/index.js +3 -0
  5. package/lib/commands/mcp.js +11 -0
  6. package/lib/dataconnect/build.js +1 -9
  7. package/lib/emulator/commandUtils.js +8 -6
  8. package/lib/emulator/downloadableEmulators.js +9 -9
  9. package/lib/emulator/env.js +27 -1
  10. package/lib/emulator/functionsEmulator.js +3 -4
  11. package/lib/emulator/hub.js +2 -1
  12. package/lib/emulator/ui.js +2 -7
  13. package/lib/experiments.js +3 -4
  14. package/lib/frameworks/index.js +4 -1
  15. package/lib/gcp/auth.js +56 -1
  16. package/lib/gcp/firestore.js +12 -1
  17. package/lib/hosting/api.js +4 -0
  18. package/lib/init/features/dataconnect/sdk.js +9 -7
  19. package/lib/init/features/genkit/index.js +59 -55
  20. package/lib/logger.js +11 -2
  21. package/lib/mcp/errors.js +15 -0
  22. package/lib/mcp/index.js +109 -0
  23. package/lib/mcp/tool.js +11 -0
  24. package/lib/mcp/tools/auth/disable_auth_user.js +30 -0
  25. package/lib/mcp/tools/auth/get_auth_user.js +29 -0
  26. package/lib/mcp/tools/auth/index.js +7 -0
  27. package/lib/mcp/tools/auth/set_auth_claims.js +34 -0
  28. package/lib/mcp/tools/core/get_firebase_directory.js +20 -0
  29. package/lib/mcp/tools/core/index.js +6 -0
  30. package/lib/mcp/tools/core/set_firebase_directory.js +33 -0
  31. package/lib/mcp/tools/dataconnect/index.js +5 -0
  32. package/lib/mcp/tools/dataconnect/list_dataconnect_services.js +23 -0
  33. package/lib/mcp/tools/firestore/converter.js +57 -0
  34. package/lib/mcp/tools/firestore/get_documents.js +48 -0
  35. package/lib/mcp/tools/firestore/get_firestore_rules.js +26 -0
  36. package/lib/mcp/tools/firestore/index.js +7 -0
  37. package/lib/mcp/tools/firestore/list_collections.js +30 -0
  38. package/lib/mcp/tools/index.js +14 -0
  39. package/lib/mcp/tools/project/get_project.js +22 -0
  40. package/lib/mcp/tools/project/get_sdk_config.js +38 -0
  41. package/lib/mcp/tools/project/index.js +7 -0
  42. package/lib/mcp/tools/project/list_apps.js +29 -0
  43. package/lib/mcp/types.js +4 -0
  44. package/lib/mcp/util.js +52 -0
  45. package/package.json +5 -2
  46. package/templates/init/dataconnect/connector.yaml +3 -0
@@ -78,19 +78,21 @@ async function askQuestions(setup, config) {
78
78
  const newConnectorYaml = await generateSdkYaml(targetPlatform, connectorYaml, connectorInfo.directory, appDir);
79
79
  if (targetPlatform === types_1.Platform.WEB) {
80
80
  const unusedFrameworks = fileUtils_1.SUPPORTED_FRAMEWORKS.filter((framework) => { var _a; return !((_a = newConnectorYaml.generate) === null || _a === void 0 ? void 0 : _a.javascriptSdk[framework]); });
81
- const hasFrameworkEnabled = unusedFrameworks.length < fileUtils_1.SUPPORTED_FRAMEWORKS.length;
82
81
  if (unusedFrameworks.length > 0) {
83
82
  const additionalFrameworks = await (0, prompt_1.prompt)(setup, [
84
83
  {
85
84
  type: "checkbox",
86
85
  name: "fdcFrameworks",
87
- message: `Which ${hasFrameworkEnabled ? "additional " : ""}frameworks would you like to generate SDKs for? ` +
86
+ message: `Which frameworks would you like to generate SDKs for? ` +
88
87
  "Press Space to select features, then Enter to confirm your choices.",
89
- choices: unusedFrameworks.map((frameworkStr) => ({
90
- value: frameworkStr,
91
- name: frameworkStr,
92
- checked: false,
93
- })),
88
+ choices: fileUtils_1.SUPPORTED_FRAMEWORKS.map((frameworkStr) => {
89
+ var _a, _b;
90
+ return ({
91
+ value: frameworkStr,
92
+ name: frameworkStr,
93
+ checked: (_b = (_a = newConnectorYaml === null || newConnectorYaml === void 0 ? void 0 : newConnectorYaml.generate) === null || _a === void 0 ? void 0 : _a.javascriptSdk) === null || _b === void 0 ? void 0 : _b[frameworkStr],
94
+ });
95
+ }),
94
96
  },
95
97
  ]);
96
98
  for (const framework of additionalFrameworks.fdcFrameworks) {
@@ -15,32 +15,43 @@ const logger_1 = require("../../../logger");
15
15
  const error_1 = require("../../../error");
16
16
  const utils_1 = require("../../../utils");
17
17
  const UNKNOWN_VERSION_TOO_HIGH = "2.0.0";
18
+ const MIN_VERSION = "0.6.0";
18
19
  const LATEST_TEMPLATE = "1.0.0";
19
- async function getGenkitVersion() {
20
- let genkitVersion;
21
- let templateVersion = LATEST_TEMPLATE;
22
- let useInit = false;
23
- let stopInstall = false;
24
- if (process.env.GENKIT_DEV_VERSION && typeof process.env.GENKIT_DEV_VERSION === "string") {
25
- semver.parse(process.env.GENKIT_DEV_VERSION);
26
- genkitVersion = process.env.GENKIT_DEV_VERSION;
27
- }
28
- else {
29
- try {
30
- genkitVersion = await (0, spawn_1.spawnWithOutput)("npm", ["view", "genkit", "version"]);
20
+ async function getPackageVersion(packageName, envVariable) {
21
+ const envVal = process.env[envVariable];
22
+ if (envVal && typeof envVal === "string") {
23
+ if (semver.parse(envVal)) {
24
+ return envVal;
31
25
  }
32
- catch (err) {
33
- throw new error_1.FirebaseError("Unable to determine which genkit version to install.\n" +
34
- `npm Error: ${(0, error_1.getErrMsg)(err)}\n\n` +
35
- "For a possible workaround run\n npm view genkit version\n" +
36
- "and then set an environment variable:\n" +
37
- " export GENKIT_DEV_VERSION=<output from previous command>\n" +
38
- "and run `firebase init genkit` again");
26
+ else {
27
+ throw new error_1.FirebaseError(`Invalid version string '${envVal}' specified in ${envVariable}`);
28
+ }
29
+ }
30
+ try {
31
+ const output = await (0, spawn_1.spawnWithOutput)("npm", ["view", packageName, "version"]);
32
+ if (!output) {
33
+ throw new error_1.FirebaseError(`Unable to determine ${packageName} version to install`);
39
34
  }
35
+ return output;
40
36
  }
41
- if (!genkitVersion) {
42
- throw new error_1.FirebaseError("Unable to determine genkit version to install");
37
+ catch (err) {
38
+ throw new error_1.FirebaseError(`Unable to determine which version of ${packageName} to install.\n` +
39
+ `npm Error: ${(0, error_1.getErrMsg)(err)}\n\n` +
40
+ "For a possible workaround run\n npm view " +
41
+ packageName +
42
+ " version\n" +
43
+ "and then set an environment variable:\n" +
44
+ ` export ${envVariable}=<output from previous command>\n` +
45
+ "and run `firebase init genkit` again");
43
46
  }
47
+ }
48
+ async function getGenkitInfo() {
49
+ let templateVersion = LATEST_TEMPLATE;
50
+ let stopInstall = false;
51
+ const genkitVersion = await getPackageVersion("genkit", "GENKIT_DEV_VERSION");
52
+ const cliVersion = await getPackageVersion("genkit-cli", "GENKIT_CLI_DEV_VERSION");
53
+ const vertexVersion = await getPackageVersion("@genkit-ai/vertexai", "GENKIT_VERTEX_VERSION");
54
+ const googleAiVersion = await getPackageVersion("@genkit-ai/googleai", "GENKIT_GOOGLEAI_VERSION");
44
55
  if (semver.gte(genkitVersion, UNKNOWN_VERSION_TOO_HIGH)) {
45
56
  const continueInstall = await (0, prompt_1.confirm)({
46
57
  message: clc.yellow(`WARNING: The latest version of Genkit (${genkitVersion}) isn't supported by this\n` +
@@ -56,24 +67,32 @@ async function getGenkitVersion() {
56
67
  else if (semver.gte(genkitVersion, "1.0.0-rc.1")) {
57
68
  templateVersion = "1.0.0";
58
69
  }
59
- else if (semver.gte(genkitVersion, "0.6.0")) {
70
+ else if (semver.gte(genkitVersion, MIN_VERSION)) {
60
71
  templateVersion = "0.9.0";
61
72
  }
62
73
  else {
63
- templateVersion = "";
64
- useInit = true;
65
- }
66
- return { genkitVersion, templateVersion, useInit, stopInstall };
74
+ throw new error_1.FirebaseError(`The requested version of Genkit (${genkitVersion}) is no ` +
75
+ `longer supported. Please specify a newer version.`);
76
+ }
77
+ return {
78
+ genkitVersion,
79
+ cliVersion,
80
+ vertexVersion,
81
+ googleAiVersion,
82
+ templateVersion,
83
+ stopInstall,
84
+ };
67
85
  }
68
- function showStartMessage(config, command) {
86
+ function showStartMessage(setup, command) {
87
+ logger_1.logger.info();
69
88
  logger_1.logger.info("\nLogin to Google Cloud using:");
70
- logger_1.logger.info(clc.bold(clc.green(` gcloud auth application-default login --project ${config.options.project}\n`)));
89
+ logger_1.logger.info(clc.bold(clc.green(` gcloud auth application-default login --project ${setup.projectId || "your-project-id"}\n`)));
71
90
  logger_1.logger.info("Then start the Genkit developer experience by running:");
72
91
  logger_1.logger.info(clc.bold(clc.green(` ${command}`)));
73
92
  }
74
93
  async function doSetup(setup, config, options) {
75
94
  var _a;
76
- const genkitInfo = await getGenkitVersion();
95
+ const genkitInfo = await getGenkitInfo();
77
96
  if (genkitInfo.stopInstall) {
78
97
  (0, utils_1.logLabeledWarning)("genkit", "Stopped Genkit initialization");
79
98
  return;
@@ -108,31 +127,16 @@ async function doSetup(setup, config, options) {
108
127
  },
109
128
  ])).choice;
110
129
  try {
111
- (0, utils_1.logLabeledBullet)("genkit", `Installing Genkit CLI version ${genkitInfo.genkitVersion}`);
130
+ (0, utils_1.logLabeledBullet)("genkit", `Installing Genkit CLI version ${genkitInfo.cliVersion}`);
112
131
  if (installType === "globally") {
113
- if (genkitInfo.useInit) {
114
- await (0, spawn_1.wrapSpawn)("npm", ["install", "-g", `genkit@${genkitInfo.genkitVersion}`], projectDir);
115
- await (0, spawn_1.wrapSpawn)("genkit", ["init", "-p", "firebase"], projectDir);
116
- logger_1.logger.info("Start the Genkit developer experience by running:");
117
- logger_1.logger.info(` cd ${setup.functions.source} && genkit start`);
118
- }
119
- else {
120
- await (0, spawn_1.wrapSpawn)("npm", ["install", "-g", `genkit-cli@${genkitInfo.genkitVersion}`], projectDir);
121
- await genkitSetup(options, genkitInfo, projectDir);
122
- showStartMessage(config, `cd ${setup.functions.source} && npm run genkit:start`);
123
- }
132
+ await (0, spawn_1.wrapSpawn)("npm", ["install", "-g", `genkit-cli@${genkitInfo.cliVersion}`], projectDir);
133
+ await genkitSetup(options, genkitInfo, projectDir);
134
+ showStartMessage(setup, `cd ${setup.functions.source} && npm run genkit:start`);
124
135
  }
125
136
  else {
126
- if (genkitInfo.useInit) {
127
- await (0, spawn_1.wrapSpawn)("npm", ["install", `genkit@${genkitInfo.genkitVersion}`, "--save-dev"], projectDir);
128
- await (0, spawn_1.wrapSpawn)("npx", ["genkit", "init", "-p", "firebase"], projectDir);
129
- showStartMessage(config, `cd ${setup.functions.source} && npx genkit start`);
130
- }
131
- else {
132
- await (0, spawn_1.wrapSpawn)("npm", ["install", `genkit-cli@${genkitInfo.genkitVersion}`, "--save-dev"], projectDir);
133
- await genkitSetup(options, genkitInfo, projectDir);
134
- showStartMessage(config, `cd ${setup.functions.source} && npm run genkit:start`);
135
- }
137
+ await (0, spawn_1.wrapSpawn)("npm", ["install", `genkit-cli@${genkitInfo.cliVersion}`, "--save-dev"], projectDir);
138
+ await genkitSetup(options, genkitInfo, projectDir);
139
+ showStartMessage(setup, `cd ${setup.functions.source} && npm run genkit:start`);
136
140
  }
137
141
  }
138
142
  catch (err) {
@@ -151,17 +155,17 @@ async function ensureVertexApiEnabled(options) {
151
155
  return await (0, ensureApiEnabled_1.ensure)(projectId, VERTEX_AI_URL, "aiplatform", silently);
152
156
  }
153
157
  exports.ensureVertexApiEnabled = ensureVertexApiEnabled;
154
- function getModelOptions(genkitVersion) {
158
+ function getModelOptions(genkitInfo) {
155
159
  const modelOptions = {
156
160
  vertexai: {
157
161
  label: "Google Cloud Vertex AI",
158
162
  plugin: "@genkit-ai/vertexai",
159
- package: `@genkit-ai/vertexai@${genkitVersion}`,
163
+ package: `@genkit-ai/vertexai@${genkitInfo.vertexVersion}`,
160
164
  },
161
165
  googleai: {
162
166
  label: "Google AI",
163
167
  plugin: "@genkit-ai/googleai",
164
- package: `@genkit-ai/googleai@${genkitVersion}`,
168
+ package: `@genkit-ai/googleai@${genkitInfo.googleAiVersion}`,
165
169
  },
166
170
  none: { label: "None", plugin: undefined, package: undefined },
167
171
  };
@@ -208,7 +212,7 @@ function getBasePackages(genkitVersion) {
208
212
  const externalDevPackages = ["typescript", "tsx"];
209
213
  async function genkitSetup(options, genkitInfo, projectDir) {
210
214
  var _a, _b;
211
- const modelOptions = getModelOptions(genkitInfo.genkitVersion);
215
+ const modelOptions = getModelOptions(genkitInfo);
212
216
  const supportedModels = Object.keys(modelOptions);
213
217
  const answer = await inquirer.prompt([
214
218
  {
package/lib/logger.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.logger = exports.vsceLogEmitter = void 0;
3
+ exports.silenceStdout = exports.logger = exports.vsceLogEmitter = void 0;
4
4
  const winston = require("winston");
5
5
  const vsCodeUtils_1 = require("./vsCodeUtils");
6
6
  const events_1 = require("events");
@@ -46,6 +46,15 @@ function maybeUseVSCodeLogger(logger) {
46
46
  return logger;
47
47
  }
48
48
  const rawLogger = winston.createLogger();
49
- rawLogger.add(new winston.transports.Console({ silent: true }));
49
+ rawLogger.add(new winston.transports.Console({
50
+ silent: true,
51
+ consoleWarnLevels: ["debug", "warn"],
52
+ }));
50
53
  rawLogger.exitOnError = false;
51
54
  exports.logger = maybeUseVSCodeLogger(annotateDebugLines(expandErrors(rawLogger)));
55
+ function silenceStdout() {
56
+ exports.logger = winston.createLogger({
57
+ silent: true,
58
+ });
59
+ }
60
+ exports.silenceStdout = silenceStdout;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.mcpAuthError = exports.NO_PROJECT_ERROR = void 0;
4
+ const util_1 = require("./util");
5
+ exports.NO_PROJECT_ERROR = (0, util_1.mcpError)('No active project was found. Use the `set_firebase_directory` tool to set the project directory to an absolute folder location containing a firebase.json config file. Alternatively, change the MCP server config to add [...,"--dir","/absolute/path/to/project/directory"] in its command-line arguments.', "PRECONDITION_FAILED");
6
+ function mcpAuthError() {
7
+ const cmd = (0, util_1.commandExistsSync)("firebase") ? "firebase" : "npx -y firebase-tools";
8
+ return (0, util_1.mcpError)(`The user is not currently logged into the Firebase CLI, which is required to use this tool. Please instruct the user to execute this shell command to sign in or to configure [Application Default Credentials][ADC] on their machine.
9
+ \`\`\`sh
10
+ ${cmd} login
11
+ \`\`\`
12
+
13
+ [ADC]: https://cloud.google.com/docs/authentication/application-default-credentials`);
14
+ }
15
+ exports.mcpAuthError = mcpAuthError;
@@ -0,0 +1,109 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FirebaseMcpServer = void 0;
4
+ const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
5
+ const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
6
+ const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
7
+ const util_js_1 = require("./util.js");
8
+ const index_js_2 = require("./tools/index.js");
9
+ const configstore_js_1 = require("../configstore.js");
10
+ const index_js_3 = require("./tools/core/index.js");
11
+ const command_js_1 = require("../command.js");
12
+ const requireAuth_js_1 = require("../requireAuth.js");
13
+ const projectUtils_js_1 = require("../projectUtils.js");
14
+ const errors_js_1 = require("./errors.js");
15
+ const SERVER_VERSION = "0.0.1";
16
+ const PROJECT_ROOT_KEY = "mcp.projectRoot";
17
+ const cmd = new command_js_1.Command("experimental:mcp").before(requireAuth_js_1.requireAuth);
18
+ class FirebaseMcpServer {
19
+ constructor(options) {
20
+ var _a, _b, _c;
21
+ this.activeFeatures = options.activeFeatures;
22
+ this.server = new index_js_1.Server({ name: "firebase", version: SERVER_VERSION });
23
+ this.server.registerCapabilities({ tools: { listChanged: true } });
24
+ this.server.setRequestHandler(types_js_1.ListToolsRequestSchema, this.mcpListTools.bind(this));
25
+ this.server.setRequestHandler(types_js_1.CallToolRequestSchema, this.mcpCallTool.bind(this));
26
+ this.projectRoot =
27
+ (_c = (_b = (_a = options.projectRoot) !== null && _a !== void 0 ? _a : configstore_js_1.configstore.get(PROJECT_ROOT_KEY)) !== null && _b !== void 0 ? _b : process.env.PROJECT_ROOT) !== null && _c !== void 0 ? _c : process.cwd();
28
+ if (options.projectRoot)
29
+ this.fixedRoot = true;
30
+ }
31
+ get availableTools() {
32
+ var _a;
33
+ const toolDefs = this.fixedRoot ? [] : [...index_js_3.coreTools];
34
+ const activeFeatures = ((_a = this.activeFeatures) === null || _a === void 0 ? void 0 : _a.length)
35
+ ? this.activeFeatures
36
+ : Object.keys(index_js_2.tools);
37
+ for (const key of activeFeatures || []) {
38
+ toolDefs.push(...index_js_2.tools[key]);
39
+ }
40
+ return toolDefs;
41
+ }
42
+ getTool(name) {
43
+ return this.availableTools.find((t) => t.mcp.name === name) || null;
44
+ }
45
+ async mcpListTools() {
46
+ const hasActiveProject = !!(await this.getProjectId());
47
+ return {
48
+ tools: this.availableTools.map((t) => t.mcp),
49
+ _meta: {
50
+ projectRoot: this.projectRoot,
51
+ projectDetected: hasActiveProject,
52
+ authenticated: await this.getAuthenticated(),
53
+ activeFeatures: this.activeFeatures,
54
+ },
55
+ };
56
+ }
57
+ setProjectRoot(newRoot) {
58
+ if (newRoot === null) {
59
+ configstore_js_1.configstore.delete(PROJECT_ROOT_KEY);
60
+ this.projectRoot = process.env.PROJECT_ROOT || process.cwd();
61
+ void this.server.sendToolListChanged();
62
+ return;
63
+ }
64
+ configstore_js_1.configstore.set(PROJECT_ROOT_KEY, newRoot);
65
+ this.projectRoot = newRoot;
66
+ void this.server.sendToolListChanged();
67
+ }
68
+ async resolveOptions() {
69
+ const options = { cwd: this.projectRoot };
70
+ await cmd.prepare(options);
71
+ return options;
72
+ }
73
+ async getProjectId() {
74
+ return (0, projectUtils_js_1.getProjectId)(await this.resolveOptions());
75
+ }
76
+ async getAuthenticated() {
77
+ try {
78
+ await (0, requireAuth_js_1.requireAuth)(await this.resolveOptions());
79
+ return true;
80
+ }
81
+ catch (e) {
82
+ return false;
83
+ }
84
+ }
85
+ async mcpCallTool(request) {
86
+ var _a, _b;
87
+ const toolName = request.params.name;
88
+ const toolArgs = request.params.arguments;
89
+ const tool = this.getTool(toolName);
90
+ if (!tool)
91
+ throw new Error(`Tool '${toolName}' could not be found.`);
92
+ const projectId = await this.getProjectId();
93
+ if (((_a = tool.mcp._meta) === null || _a === void 0 ? void 0 : _a.requiresAuth) && !(await this.getAuthenticated()))
94
+ return (0, errors_js_1.mcpAuthError)();
95
+ if (((_b = tool.mcp._meta) === null || _b === void 0 ? void 0 : _b.requiresProject) && !projectId)
96
+ return errors_js_1.NO_PROJECT_ERROR;
97
+ try {
98
+ return tool.fn(toolArgs, { projectId: await this.getProjectId(), host: this });
99
+ }
100
+ catch (err) {
101
+ return (0, util_js_1.mcpError)(err);
102
+ }
103
+ }
104
+ async start() {
105
+ const transport = new stdio_js_1.StdioServerTransport();
106
+ await this.server.connect(transport);
107
+ }
108
+ }
109
+ exports.FirebaseMcpServer = FirebaseMcpServer;
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.tool = void 0;
4
+ const zod_to_json_schema_1 = require("zod-to-json-schema");
5
+ function tool(options, fn) {
6
+ return {
7
+ mcp: Object.assign(Object.assign({}, options), { inputSchema: (0, zod_to_json_schema_1.zodToJsonSchema)(options.inputSchema) }),
8
+ fn,
9
+ };
10
+ }
11
+ exports.tool = tool;
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.disable_auth_user = void 0;
4
+ const zod_1 = require("zod");
5
+ const tool_js_1 = require("../../tool.js");
6
+ const util_js_1 = require("../../util.js");
7
+ const auth_js_1 = require("../../../gcp/auth.js");
8
+ exports.disable_auth_user = (0, tool_js_1.tool)({
9
+ name: "disable_auth_user",
10
+ description: "Disables or enables a user based on a UID.",
11
+ inputSchema: zod_1.z.object({
12
+ uid: zod_1.z.string().describe("The localId or UID of the user to disable or enable"),
13
+ disabled: zod_1.z.boolean().describe("true disables the user, false enables the user"),
14
+ }),
15
+ annotations: {
16
+ title: "Disable or enable a particular user",
17
+ destructiveHint: true,
18
+ idempotentHint: true,
19
+ },
20
+ _meta: {
21
+ requiresAuth: true,
22
+ requiresProject: true,
23
+ },
24
+ }, async ({ uid, disabled }, { projectId }) => {
25
+ const res = await (0, auth_js_1.disableUser)(projectId, uid, disabled);
26
+ if (res) {
27
+ return (0, util_js_1.toContent)(`User ${uid} as been ${disabled ? "disabled" : "enabled"}`);
28
+ }
29
+ return (0, util_js_1.toContent)(`Failed to ${disabled ? "disable" : "enable"} user ${uid}`);
30
+ });
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.get_auth_user = void 0;
4
+ const zod_1 = require("zod");
5
+ const tool_js_1 = require("../../tool.js");
6
+ const util_js_1 = require("../../util.js");
7
+ const auth_js_1 = require("../../../gcp/auth.js");
8
+ exports.get_auth_user = (0, tool_js_1.tool)({
9
+ name: "get_auth_user",
10
+ description: "Retrieves a user based on an email address, phone number, or UID.",
11
+ inputSchema: zod_1.z.object({
12
+ email: zod_1.z.string().optional(),
13
+ phoneNumber: zod_1.z.string().optional(),
14
+ uid: zod_1.z.string().optional(),
15
+ }),
16
+ annotations: {
17
+ title: "Get information about 1 user.",
18
+ readOnlyHint: true,
19
+ },
20
+ _meta: {
21
+ requiresAuth: true,
22
+ requiresProject: true,
23
+ },
24
+ }, async ({ email, phoneNumber, uid }, { projectId }) => {
25
+ if (email === undefined && phoneNumber === undefined && uid === undefined) {
26
+ return (0, util_js_1.mcpError)(`No user identifier supplied in get_auth_user tool`);
27
+ }
28
+ return (0, util_js_1.toContent)(await (0, auth_js_1.findUser)(projectId, email, phoneNumber, uid));
29
+ });
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.authTools = void 0;
4
+ const get_auth_user_js_1 = require("./get_auth_user.js");
5
+ const disable_auth_user_js_1 = require("./disable_auth_user.js");
6
+ const set_auth_claims_js_1 = require("./set_auth_claims.js");
7
+ exports.authTools = [get_auth_user_js_1.get_auth_user, disable_auth_user_js_1.disable_auth_user, set_auth_claims_js_1.set_auth_claim];
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.set_auth_claim = void 0;
4
+ const zod_1 = require("zod");
5
+ const tool_js_1 = require("../../tool.js");
6
+ const util_js_1 = require("../../util.js");
7
+ const auth_js_1 = require("../../../gcp/auth.js");
8
+ exports.set_auth_claim = (0, tool_js_1.tool)({
9
+ name: "set_auth_claims",
10
+ description: "Sets custom claims on a specific user's account. Use to create trusted values associated with a user e.g. marking them as an admin. Claims are limited in size and should be succinct in name and value.",
11
+ inputSchema: zod_1.z.object({
12
+ uid: zod_1.z.string().describe("the UID of the user to update"),
13
+ claim: zod_1.z.string().describe("the name (key) of the claim to update, e.g. 'admin'"),
14
+ value: zod_1.z
15
+ .union([
16
+ zod_1.z.string(),
17
+ zod_1.z.number(),
18
+ zod_1.z.boolean(),
19
+ zod_1.z.record(zod_1.z.union([zod_1.z.string(), zod_1.z.number(), zod_1.z.boolean()])),
20
+ zod_1.z.array(zod_1.z.union([zod_1.z.string(), zod_1.z.number(), zod_1.z.boolean()])),
21
+ ])
22
+ .describe("the value of the custom claim"),
23
+ }),
24
+ annotations: {
25
+ title: "Set custom Firebase Auth claim",
26
+ idempotentHint: true,
27
+ },
28
+ _meta: {
29
+ requiresAuth: true,
30
+ requiresProject: true,
31
+ },
32
+ }, async ({ uid, claim, value }, { projectId }) => {
33
+ return (0, util_js_1.toContent)(await (0, auth_js_1.setCustomClaim)(projectId, uid, { [claim]: value }, { merge: true }));
34
+ });
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.get_firebase_directory = void 0;
4
+ const zod_1 = require("zod");
5
+ const tool_js_1 = require("../../tool.js");
6
+ const util_js_1 = require("../../util.js");
7
+ const detectProjectRoot_js_1 = require("../../../detectProjectRoot.js");
8
+ exports.get_firebase_directory = (0, tool_js_1.tool)({
9
+ name: "get_firebase_directory",
10
+ description: "Gets the current Firebase project directory. If this has been set using the `set_firebase_directory` tool it will return that, otherwise it will look for a PROJECT_ROOT environment variable or the current working directory of the running Firebase MCP server.",
11
+ inputSchema: zod_1.z.object({}),
12
+ annotations: {
13
+ title: "Get Firebase Project Directory",
14
+ readOnlyHint: true,
15
+ },
16
+ }, (_, { host }) => {
17
+ if (!(0, detectProjectRoot_js_1.detectProjectRoot)({ cwd: host.projectRoot }))
18
+ return Promise.resolve((0, util_js_1.mcpError)(`There is no detected 'firebase.json' in directory '${host.projectRoot}'. Please use the 'set_firebase_directory' tool to activate a Firebase project directory.`));
19
+ return Promise.resolve((0, util_js_1.toContent)(`The current Firebase project directory is '${host.projectRoot}'.`));
20
+ });
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.coreTools = void 0;
4
+ const get_firebase_directory_1 = require("./get_firebase_directory");
5
+ const set_firebase_directory_1 = require("./set_firebase_directory");
6
+ exports.coreTools = [get_firebase_directory_1.get_firebase_directory, set_firebase_directory_1.set_firebase_directory];
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.set_firebase_directory = void 0;
4
+ const zod_1 = require("zod");
5
+ const tool_js_1 = require("../../tool.js");
6
+ const util_js_1 = require("../../util.js");
7
+ const fs_1 = require("fs");
8
+ const path_1 = require("path");
9
+ exports.set_firebase_directory = (0, tool_js_1.tool)({
10
+ name: "set_firebase_directory",
11
+ description: "Sets the project directory for the Firebase MCP server to utilize for project detection and authentication. This should be a directory with a `firebase.json` file in it. This information is persisted between sessions.",
12
+ inputSchema: zod_1.z.object({
13
+ dir: zod_1.z
14
+ .string()
15
+ .nullable()
16
+ .describe("the absolute path of the directory. set to null to 'unset' the value and fall back to the working directory"),
17
+ }),
18
+ annotations: {
19
+ title: "Set Firebase Project Directory",
20
+ idempotentHint: true,
21
+ },
22
+ }, ({ dir }, { host }) => {
23
+ if (dir === null) {
24
+ host.setProjectRoot(null);
25
+ return Promise.resolve((0, util_js_1.toContent)(`Firebase MCP project directory setting deleted. New project root is: ${host.projectRoot || "unset"}`));
26
+ }
27
+ if (!(0, fs_1.existsSync)(dir))
28
+ return Promise.resolve((0, util_js_1.mcpError)(`Directory '${dir}' does not exist.`));
29
+ if (!(0, fs_1.existsSync)((0, path_1.join)(dir, "firebase.json")))
30
+ return Promise.resolve((0, util_js_1.mcpError)(`Directory '${dir}' does not contain a 'firebase.json' file.`));
31
+ host.setProjectRoot(dir);
32
+ return Promise.resolve((0, util_js_1.toContent)(`Firebase MCP project directory set to '${dir}'.`));
33
+ });
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.dataconnectTools = void 0;
4
+ const list_dataconnect_services_js_1 = require("./list_dataconnect_services.js");
5
+ exports.dataconnectTools = [list_dataconnect_services_js_1.list_dataconnect_services];
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.list_dataconnect_services = void 0;
4
+ const zod_1 = require("zod");
5
+ const tool_js_1 = require("../../tool.js");
6
+ const util_js_1 = require("../../util.js");
7
+ const client = require("../../../dataconnect/client");
8
+ exports.list_dataconnect_services = (0, tool_js_1.tool)({
9
+ name: "list_dataconnect_services",
10
+ description: "List the Firebase Data Connect services available in the current project.",
11
+ inputSchema: zod_1.z.object({}),
12
+ annotations: {
13
+ title: "List the Firebase Data Connect Services that's available in the backend",
14
+ readOnlyHint: true,
15
+ },
16
+ _meta: {
17
+ requiresProject: true,
18
+ requiresAuth: true,
19
+ },
20
+ }, async (_, { projectId }) => {
21
+ const services = await client.listAllServices(projectId);
22
+ return (0, util_js_1.toContent)(services, { format: "yaml" });
23
+ });
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.firestoreDocumentToJson = void 0;
4
+ const logger_1 = require("../../../logger");
5
+ function firestoreValueToJson(firestoreValue) {
6
+ var _a, _b;
7
+ if ("nullValue" in firestoreValue)
8
+ return null;
9
+ if ("booleanValue" in firestoreValue)
10
+ return firestoreValue.booleanValue;
11
+ if ("integerValue" in firestoreValue) {
12
+ const num = Number(firestoreValue.integerValue);
13
+ if (num > Number.MAX_SAFE_INTEGER || num < Number.MIN_SAFE_INTEGER) {
14
+ return firestoreValue.integerValue;
15
+ }
16
+ return num;
17
+ }
18
+ if ("doubleValue" in firestoreValue)
19
+ return firestoreValue.doubleValue;
20
+ if ("timestampValue" in firestoreValue)
21
+ return { __type__: "Timestamp", value: firestoreValue.timestampValue };
22
+ if ("stringValue" in firestoreValue)
23
+ return firestoreValue.stringValue;
24
+ if ("bytesValue" in firestoreValue)
25
+ return firestoreValue.bytesValue;
26
+ if ("referenceValue" in firestoreValue)
27
+ return { __type__: "Reference", value: firestoreValue.referenceValue };
28
+ if ("geoPointValue" in firestoreValue)
29
+ return {
30
+ __type__: "GeoPoint",
31
+ value: [firestoreValue.geoPointValue.latitude, firestoreValue.geoPointValue.longitude],
32
+ };
33
+ if ("arrayValue" in firestoreValue)
34
+ return (_b = (_a = firestoreValue.arrayValue.values) === null || _a === void 0 ? void 0 : _a.map((v) => firestoreValueToJson(v))) !== null && _b !== void 0 ? _b : [];
35
+ if ("mapValue" in firestoreValue) {
36
+ const map = firestoreValue.mapValue.fields || {};
37
+ const obj = {};
38
+ for (const key of Object.keys(map)) {
39
+ obj[key] = firestoreValueToJson(map[key]);
40
+ }
41
+ return obj;
42
+ }
43
+ logger_1.logger.warn("Unhandled Firestore Value type encountered:", firestoreValue);
44
+ return undefined;
45
+ }
46
+ function firestoreDocumentToJson(firestoreDoc) {
47
+ const nameParts = firestoreDoc.name.split("/documents/");
48
+ const path = nameParts.length > 1 ? nameParts[nameParts.length - 1] : "";
49
+ const result = { __path__: path };
50
+ if (firestoreDoc.fields) {
51
+ for (const key of Object.keys(firestoreDoc.fields)) {
52
+ result[key] = firestoreValueToJson(firestoreDoc.fields[key]);
53
+ }
54
+ }
55
+ return result;
56
+ }
57
+ exports.firestoreDocumentToJson = firestoreDocumentToJson;