Skip to content

Commit 0fc5903

Browse files
authored
Update MCP prompts to fallback to npx firebase-tools if firebase isn't installed (#9261)
1 parent 8cf3685 commit 0fc5903

File tree

5 files changed

+24
-12
lines changed

5 files changed

+24
-12
lines changed

src/mcp/index.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ import { LoggingStdioServerTransport } from "./logging-transport";
4545
import { isFirebaseStudio } from "../env";
4646
import { timeoutFallback } from "../timeout";
4747
import { resolveResource, resources, resourceTemplates } from "./resources";
48+
import * as crossSpawn from "cross-spawn";
4849

4950
const SERVER_VERSION = "0.3.0";
5051

@@ -71,6 +72,7 @@ export class FirebaseMcpServer {
7172
detectedFeatures?: ServerFeature[];
7273
clientInfo?: { name?: string; version?: string };
7374
emulatorHubClient?: EmulatorHubClient;
75+
private cliCommand?: string;
7476

7577
// logging spec:
7678
// https://modelcontextprotocol.io/specification/2025-03-26/server/utilities/logging
@@ -294,9 +296,18 @@ export class FirebaseMcpServer {
294296
config: Config.load(options, true) || new Config({}, options),
295297
rc: loadRC(options),
296298
accountEmail,
299+
firebaseCliCommand: this._getFirebaseCliCommand(),
297300
};
298301
}
299302

303+
private _getFirebaseCliCommand(): string {
304+
if (!this.cliCommand) {
305+
const testCommand = crossSpawn.sync("firebase --version");
306+
this.cliCommand = testCommand.error ? "npx firebase-tools@latest" : "firebase";
307+
}
308+
return this.cliCommand;
309+
}
310+
300311
async mcpListTools(): Promise<ListToolsResult> {
301312
await Promise.all([this.detectActiveFeatures(), this.detectProjectRoot()]);
302313
const hasActiveProject = !!(await this.getProjectId());

src/mcp/prompts/core/deploy.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export const deploy = prompt(
1515
title: "Deploy to Firebase",
1616
},
1717
},
18-
async ({ prompt }, { config, projectId, accountEmail }) => {
18+
async ({ prompt }, { config, projectId, accountEmail, firebaseCliCommand }) => {
1919
return [
2020
{
2121
role: "user" as const,
@@ -41,7 +41,7 @@ ${prompt || "<the user didn't supply specific instructions>"}
4141
4242
Follow the steps below taking note of any user instructions provided above.
4343
44-
1. If there is no active user, prompt the user to run \`firebase login\` in an interactive terminal before continuing.
44+
1. If there is no active user, prompt the user to run \`${firebaseCliCommand} login\` in an interactive terminal before continuing.
4545
2. Analyze the source code in the current working directory to determine if this is a web app. If it isn't, end this process and tell the user "The /firebase:deploy command only works with web apps."
4646
3. Analyze the source code in the current working directory to determine if the app requires a server for Server-Side Rendering (SSR). This will determine whether or not to use Firebase App Hosting. Here are instructions to determine if the app needs a server:
4747
Objective: Analyze the provided codebase files to determine if the web application requires a backend for Server-Side Rendering (SSR). Your final output must be a clear "Yes" or "No" followed by a brief justification.
@@ -79,19 +79,19 @@ Follow the steps below taking note of any user instructions provided above.
7979
Example (No): "No, there are no dependencies or file structures that indicate the use of a server-side rendering framework."
8080
4. If there is no \`firebase.json\` file, manually create one based on whether the app requires SSR:
8181
4a. If the app requires SSR, configure Firebase App Hosting:
82-
Create \`firebase.json\ with an "apphosting" configuration, setting backendId to the app's name in package.json: \`{"apphosting": {"backendId": "<backendId>"}}\
82+
Create \`firebase.json\ with an "apphosting" configuration, setting backendId to the app's name in package.json: \`{"apphosting": {"backendId": "<backendId>"}}\
8383
4b. If the app does NOT require SSR, configure Firebase Hosting:
8484
Create \`firebase.json\ with a "hosting" configuration. Add a \`{"hosting": {"predeploy": "<build_script>"}}\` config to build before deploying.
8585
5. Check if there is an active Firebase project for this environment (the \`firebase_get_environment\` tool may be helpful). If there is, provide the active project ID to the user and ask them if they want to proceed using that project. If there is not an active project, give the user two options: Provide an existing project ID or create a new project. Only use the list_projects tool on user request. Wait for their response before proceeding.
8686
5a. If the user chooses to use an existing Firebase project, the \`firebase_list_projects\` tool may be helpful. Set the selected project as the active project (the \`firebase_update_environment\` tool may be helpful).
8787
5b. If the user chooses to create a new project, use the \`firebase_create_project \` tool. Then set the new project as the active project (the \`firebase_update_environment\` tool may be helpful).
88-
6. If firebase.json contains an "apphosting" configuration, check if a backend exists matching the provided backendId (the \`apphosting_list_backends\` tool may be helpful).
89-
If it doesn't exist, create one by running the \`firebase apphosting:backends:create --backend <backendId> --primary-region us-central1 --root-dir .\` shell.
90-
7. Only after making sure Firebase has been initialized, run the \`firebase deploy\` shell command to perform the deploy. This may take a few minutes.
88+
6. If firebase.json contains an "apphosting" configuration, check if a backend exists matching the provided backendId (the \`apphosting_list_backends\` tool may be helpful).
89+
If it doesn't exist, create one by running the \`${firebaseCliCommand} apphosting:backends:create --backend <backendId> --primary-region us-central1 --root-dir .\` shell.
90+
7. Only after making sure Firebase has been initialized, run the \`${firebaseCliCommand} deploy\` shell command to perform the deploy. This may take a few minutes.
9191
7a. If deploying to apphosting, tell the user the deployment will take a few minutes, and they can monitor deployment progress in the Firebase console: \`https://console.firebase.google.com/project/<projectId>/apphosting\`
9292
8. If the deploy has errors, attempt to fix them and ask the user clarifying questions as needed.
93-
9. If the deploy needs \`--force\` to run successfully, ALWAYS prompt the user before running \`firebase deploy --force\`.
94-
10. If only one specific feature is failing, use command \`firebase deploy --only <feature>\` as you debug.
93+
9. If the deploy needs \`--force\` to run successfully, ALWAYS prompt the user before running \`${firebaseCliCommand} deploy --force\`.
94+
10. If only one specific feature is failing, use command \`${firebaseCliCommand} deploy --only <feature>\` as you debug.
9595
11. If the deploy succeeds, your job is finished.
9696
`.trim(),
9797
},

src/mcp/prompts/core/init.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export const init = prompt(
1111
},
1212
},
1313
async (_, mcp) => {
14-
const { config, projectId, accountEmail } = mcp;
14+
const { config, projectId, accountEmail, firebaseCliCommand } = mcp;
1515

1616
const platform = await getPlatformFromFolder(config.projectDir);
1717

@@ -47,7 +47,7 @@ ${config.readProjectFile("firebase.json", { fallback: "<FILE DOES NOT EXIST>" })
4747
Follow the steps below taking note of any user instructions provided above.
4848
4949
1. If there is no active user, use the \`firebase_login\` tool to help them sign in.
50-
- If you run into issues logging the user in, suggest that they run \`npx firebase-tools login --reauth\` in a separate terminal
50+
- If you run into issues logging the user in, suggest that they run \`${firebaseCliCommand} login --reauth\` in a separate terminal
5151
2.1 Start by listing out the existing init options that are available to the user. Ask the user which set of services they would like to add to their app. Always enumerate them and list the options out explicitly for the user.
5252
1. Backend Services: Backend services for the app, such as setting up a database, adding a user-authentication sign up and login page, and deploying a web app to a production URL.
5353
- IMPORTANT: The backend setup guide is for web apps only. If the user requests backend setup for a mobile app (iOS, Android, or Flutter), inform them that this is not supported and do not use the backend setup guide. You can still assist with other requests.

src/mcp/prompts/crashlytics/connect.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export const connect = prompt(
99
title: "Access Crashlytics data",
1010
},
1111
},
12-
async (unused, { accountEmail }) => {
12+
async (unused, { accountEmail, firebaseCliCommand }) => {
1313
return [
1414
{
1515
role: "user" as const,
@@ -25,7 +25,7 @@ Active user: ${accountEmail || "<NONE>"}
2525
2626
1. **Make sure the user is logged in. No Crashlytics tools will work if the user is not logged in.**
2727
a. Use the \`firebase_get_environment\` tool to verify that the user is logged in.
28-
b. If the Firebase 'Active user' is set to <NONE>, instruct the user to run \`firebase login\`
28+
b. If the Firebase 'Active user' is set to <NONE>, instruct the user to run \`${firebaseCliCommand} login\`
2929
before continuing. Ignore other fields that are set to <NONE>. We are just making sure the
3030
user is logged in.
3131

src/mcp/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,5 @@ export interface McpContext {
2828
config: Config;
2929
host: FirebaseMcpServer;
3030
rc: RC;
31+
firebaseCliCommand: string;
3132
}

0 commit comments

Comments
 (0)