diff --git a/src/mcp/prompts/core/init.ts b/src/mcp/prompts/core/init.ts index 6b90c9c3aa2..eed58bf0277 100644 --- a/src/mcp/prompts/core/init.ts +++ b/src/mcp/prompts/core/init.ts @@ -22,10 +22,6 @@ export const init = prompt( text: ` Your goal is to help the user setup Firebase services in this workspace. Firebase is a large platform with many potential uses, so you will: -1. Detect which Firebase services are already in use in the workspace, if any -2. Determine which new Firebase services will help the user build their app -3. Provision and configure the services requested by the user - ## Workspace Info Use this information to determine which Firebase services the user is already using (if any). @@ -41,9 +37,7 @@ ${config.readProjectFile("firebase.json", { fallback: "" }) \`\`\` -## Steps -Follow the steps below taking note of any user instructions provided above. - +## Steps. 1. If there is no active user, use the \`firebase_login\` tool to help them sign in. - If you run into issues logging the user in, suggest that they run \`${firebaseCliCommand} login --reauth\` in a separate terminal 2. 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: @@ -62,7 +56,7 @@ Follow the steps below taking note of any user instructions provided above. - If there is no app that matches that criteria, use the \`firebase_create_app\` tool to create the app with the appropriate platform - Do the following only for Flutter apps - Execute \`firebase --version\` to check if the Firebase CLI is installed - - If it isn't installed, run \`npm install -g firebase-tools\` to install it. If it is installed, skip to the next step. + - If it isn't installed, run \`npm install -g firebase-tools\` to install it. If it is installed, skip to the next step. - Install the Flutterfire CLI - Use the Flutterfire CLI tool to connect to the project - Use the Flutterfire CLI to register the appropriate applications based on the user's input @@ -73,17 +67,12 @@ Follow the steps below taking note of any user instructions provided above. 7. Set up the web Firebase SDK. Skip straight to #8 for Flutter and Android apps - Fetch the configuration for the specified app using the \`firebase_get_sdk_config\` tool. - Write the Firebase SDK config to a file - - Check what the latest version of the SDK is by running the command 'npm view firebase version' - - If the user app has a package.json, install via npm - - Run 'npm i firebase' + - If the user's app does not have a package.json, create a directory named public, and add a package.json to that directory + - Run 'npm i firebase' from the public directory - Import it into the app code: ''' import { initializeApp } from 'firebase/app'; ''' - - If the user app does not have a package.json, import via CDN: - ''' - import { initializeApp } from 'https://www.gstatic.com/firebasejs/12.3.0/firebase-app.js' - ''' 8. Read the guide for the appropriate services and follow the instructions. If no guides match the user's need, inform the user. - Use the Firebase \`read_resources\` tool to load the instructions for the service the developer chose in step 2 of this guide - [Backend Services](firebase://guides/init/backend): Read this resource to set up 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. diff --git a/src/mcp/resources/guides/init_auth.ts b/src/mcp/resources/guides/init_auth.ts index a10d91d1e2b..eae7de9e3b6 100644 --- a/src/mcp/resources/guides/init_auth.ts +++ b/src/mcp/resources/guides/init_auth.ts @@ -32,6 +32,7 @@ export const init_auth = resource( **Next Steps:** - **Security Rules**: If an app uses *Cloud Firestore database*, *Cloud Storage for Firebase*, or *Firebase Realtime Database*, then please update user-based Security Rules that are structured according to the app's specific requirements. - **App Deployment**: Deploy the app to production after Security Rules are verified to be working properly. +- Refer back to the FIREBASE_INIT_TODO.md or TODO tool for next steps `.trim(), }, ], diff --git a/src/mcp/resources/guides/init_backend.ts b/src/mcp/resources/guides/init_backend.ts index f7272160fea..60301d6c506 100644 --- a/src/mcp/resources/guides/init_backend.ts +++ b/src/mcp/resources/guides/init_backend.ts @@ -16,41 +16,16 @@ export const init_backend = resource( type: "text", text: ` -1. Determine based on what you already know about the user's project or by asking them which of the following services is appropriate. -2. Use the Firebase \`read_resources\` tool to load the guide to setup the product you choose. +Determine based on what you already know about the user's project or by asking them which of the following services is appropriate. +Then, use the Firebase \`read_resources\` tool to load the guide to setup the products you choose. -The user will likely need to setup Firestore, Authentication, and Hosting. Read the following guides in order: - 1. [Firestore](firebase://guides/init/firestore): read this to setup Firestore database - 2. [Authentication](firebase://guides/init/auth): read this to setup Firebase Authentication to support multi-user apps - 3. [Firestore Rules](firebase://guides/init/firestore_rules): read this to setup the \`firestore.rules\` file for securing your database - 4. [Hosting](firebase://guides/init/hosting): read this if the user would like to deploy to Firebase Hosting +The user will likely need to setup a database solution, Authentication, and Hosting. Read the following guides in order. -**firebase.json** -The firebase.json file is used to deploy Firebase products with the firebase deploy command. +1. [Hosting](firebase://guides/init/hosting): read this if the user would like to use Firebase Hosting for their web app. +2. [A Firebase database solution](firebase://guides/init/database): read this to choose and set up a database solution. +3. [Authentication](firebase://guides/init/auth): read this to setup Firebase Authentication to support multi-user apps -Here is an example firebase.json file with Firebase Hosting, Firestore, and Cloud Functions. Note that you do not need entries for services that the user isn't using. Do not remove sections from the user's firebase.json unless the user gives explicit permission. For more information, refer to [firebase.json file documentation](https://firebase.google.com/docs/cli/#the_firebasejson_file) -\`\`\`json -{ - "hosting": { - "public": "public", - "ignore": [ - "firebase.json", - "**/.*", - "**/node_modules/**" - ] - }, - "firestore": { - "rules": "firestore.rules", - "indexes": "firestore.indexes.json" - }, - "functions": { - "predeploy": [ - "npm --prefix "$RESOURCE_DIR" run lint", - "npm --prefix "$RESOURCE_DIR" run build" - ] - } -} -\`\`\` +Once you've set up these services, ask the user if they would like to deploy their site. If they say yes, run the command 'firebase deploy --force' to do so. `.trim(), }, ], diff --git a/src/mcp/resources/guides/init_data_connect.ts b/src/mcp/resources/guides/init_data_connect.ts index 35facb55cc2..0992b128280 100644 --- a/src/mcp/resources/guides/init_data_connect.ts +++ b/src/mcp/resources/guides/init_data_connect.ts @@ -15,15 +15,22 @@ export const init_data_connect = resource( uri, type: "text", text: ` -Create a file called \`data-connect.ts\`: +First, ask the user what they would like to name their service. +Then, ask the user to provide a description of the app they are trying to build. -\`\`\`ts -import { initializeApp } from "firebase/app"; -import { getDataConnect } from "firebase/data-connect"; +Call the 'firebase_init' tools with the features.dataconnect argument set to: + +{ + description: The description the user provided above, + service_id: The service ID the user provided + instance_id: -fdc + location_id: us-east4 + provision_cloudsql: true +} + +Next, check if there is a file named dataconnect/seed_data.gql. If there is, ask the user if they would like to seed their database with some generated test data. +If they say yes, use the dataconnect_execute tool to run the operation in that file. -const app = initializeApp({...}); -const db = getDataConnect(app); -\`\`\` `.trim(), }, ], diff --git a/src/mcp/resources/guides/init_database.ts b/src/mcp/resources/guides/init_database.ts new file mode 100644 index 00000000000..7fee6395763 --- /dev/null +++ b/src/mcp/resources/guides/init_database.ts @@ -0,0 +1,31 @@ +import { resource } from "../../resource"; + +export const init_database = resource( + { + uri: "firebase://guides/init/database", + name: "database_init_guide", + title: "Choosing the Right Firebase database product", + description: + "guides the coding agent through choosing between Firebase's database products: Firestore, Data Connect, and Realtime Database", + }, + async (uri) => { + return { + contents: [ + { + uri, + type: "text", + text: ` +1. Determine based on what you already know about the user's project or by asking them which of the following services should be used. +2. Use the Firebase \`read_resources\` tool to load the guide to setup the product you choose. + +## Available Services + +- [Data Connect - PostgreSQL](firebase://guides/init/data_connect): read this if the user needs robust relational querying capabilities or expressly indicates interest in a SQL database +- [Firestore](firebase://guides/init/firestore): read this if the user needs offline data or a mix of querying and realtime capabilities +- [Realtime Database](firebase://guides/init/rtdb): read this if the user is building a "multiplayer" app or game such as a collaborative whiteboard +`.trim(), + }, + ], + }; + }, +); diff --git a/src/mcp/resources/guides/init_firestore.ts b/src/mcp/resources/guides/init_firestore.ts index 84e6a6b3699..a6a51615d87 100644 --- a/src/mcp/resources/guides/init_firestore.ts +++ b/src/mcp/resources/guides/init_firestore.ts @@ -37,7 +37,8 @@ export const init_firestore = resource( **Next Steps:** - **Authentication**: Recommend implementing Firebase Authentication if the application handles sensitive user data or has open security rules. - **User Management**: Implement sign-up and sign-in flows to support user-based access control and update security rules accordingly. -- **Security Rules**: Configure user-based security rules based on your application's specific requirements. +- **Security Rules**: Read [Firestore Rules](firebase://guides/init/firestore_rules) to setup the \`firestore.rules\` file for securing your database. +- Refer back to the FIREBASE_INIT_TODO.md or TODO tool for next steps ### Default \`firestore.rules\` file: diff --git a/src/mcp/resources/guides/init_firestore_rules.ts b/src/mcp/resources/guides/init_firestore_rules.ts index 54ce52b4465..9e3389b6fff 100644 --- a/src/mcp/resources/guides/init_firestore_rules.ts +++ b/src/mcp/resources/guides/init_firestore_rules.ts @@ -29,10 +29,12 @@ ${config.readProjectFile("firestore.rules", { fallback: "" 3. Update queries in the user's app to use the updated security rules 4. Print the contents of the \`firestore.rules\` file, and then explain what they enforce below them (for example, what changes you've made to the rules, and what actions are allowed / prohibited on each entity). Ask the user for permission to deploy the rules. Do not continue until the user confirms. Deploy the security rules using \`firebase deploy --only firestore\` in the terminal. Do not tell the user to go to the console to deploy rules as this command will do it automatically. -For database entities that neatly fall into the "personal" and "public categories, you can use the personalData and publicData rules. Use the following firestore.rules file, and add a comment above 'personalData' and 'publicData' to note what entities apply to each rule. - **Next Steps:** - **App Deployment**: Deploy the app to production after Security Rules are verified to be working properly. +- Refer back to the FIREBASE_INIT_TODO.md or TODO tool for next steps + +For database entities that neatly fall into the "personal" and "public categories, you can use the personalData and publicData rules. Use the following firestore.rules file, and add a comment above 'personalData' and 'publicData' to note what entities apply to each rule. + \`\`\` rules_version = '2'; diff --git a/src/mcp/resources/guides/init_hosting.ts b/src/mcp/resources/guides/init_hosting.ts index 091631f52d4..1d567b72daf 100644 --- a/src/mcp/resources/guides/init_hosting.ts +++ b/src/mcp/resources/guides/init_hosting.ts @@ -17,17 +17,21 @@ export const init_hosting = resource( text: ` ### Configure Firebase Hosting +- If one does not already exist, create a public directory for the site. This is where the files for the site go. + If user project has a build step, this should be the output directory for that step. +- Add a 'hosting' block to firebase.json. The following is an example, but you should change the specific values to match the users directory structure. +\`\`\` + "hosting": { + "public": "public", + "ignore": [ + "firebase.json", + "**/.*", + "**/node_modules/**" + ] + }, +\`\`\` **Security Warning:** - Files included in the public folder of a hosting site are publicly accessible. Do not include sensitive API keys for services other than Firebase in these files. - -**When to Deploy:** -- Introduce Firebase Hosting when developers are ready to deploy their application to production. -- Alternative: Developers can deploy later using the \`/firebase:deploy\` command. - -**Deployment Process:** -- Request developer's permission before implementing Firebase Hosting -- Request developer's permission before deploying Firebase Hosting app to production. -- Configure Firebase Hosting and deploy the application to production `.trim(), }, ], diff --git a/src/mcp/resources/index.ts b/src/mcp/resources/index.ts index 2be6b1507c7..6f625530836 100644 --- a/src/mcp/resources/index.ts +++ b/src/mcp/resources/index.ts @@ -6,6 +6,8 @@ import { init_auth } from "./guides/init_auth"; import { init_backend } from "./guides/init_backend"; import { init_firestore } from "./guides/init_firestore"; import { init_firestore_rules } from "./guides/init_firestore_rules"; +import { init_data_connect } from "./guides/init_data_connect"; +import { init_database } from "./guides/init_database"; import { init_hosting } from "./guides/init_hosting"; import { ServerResource, ServerResourceTemplate } from "../resource"; import { trackGA4 } from "../../track"; @@ -13,6 +15,8 @@ import { trackGA4 } from "../../track"; export const resources = [ init_backend, init_ai, + init_database, + init_data_connect, init_firestore, init_firestore_rules, init_auth, diff --git a/src/mcp/tools/core/login.ts b/src/mcp/tools/core/login.ts index 1a0add06baa..b8f5798da4b 100644 --- a/src/mcp/tools/core/login.ts +++ b/src/mcp/tools/core/login.ts @@ -5,7 +5,7 @@ import { FirebaseMcpServer } from "../../../mcp"; import { toContent, mcpError } from "../../util"; import { User, UserCredentials } from "../../../types/auth"; const LoginInputSchema = z.object({ - authCode: z.string().optional().describe("The authorization code from the login flow"), + authCode: z.string().optional().describe("The authorization code from the login flow. If omitted, will instead direct the user to log in to get an auth code."), }); export type ServerWithLoginState = FirebaseMcpServer & { @@ -49,7 +49,7 @@ export const login = tool( uri: prototyper.uri, sessionId: prototyper.sessionId, }; - const humanReadable = `Please visit this URL to login: ${result.uri}\nYour session ID is: ${result.sessionId}\nInstruct the use to copy the authorization code from that link, and paste it into chat.\nThen, run this tool again with that as the authCode argument to complete the login.`; + const humanReadable = `Please visit this URL to login:\n(${result.uri})\nYour session ID is: ${result.sessionId}\nInstruct the use to copy the authorization code from that link, and paste it into chat.\nThen, run this tool again with that as the authCode argument to complete the login.`; return toContent(humanReadable); } },