Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 4 additions & 15 deletions src/mcp/prompts/core/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,6 @@
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).
Expand All @@ -38,12 +34,10 @@

\`\`\`json
${config.readProjectFile("firebase.json", { fallback: "<FILE DOES NOT EXIST>" })}
\`\`\`

Check warning on line 37 in src/mcp/prompts/core/init.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Invalid type "any" of template literal expression


## 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:
Expand All @@ -62,7 +56,7 @@
- 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
Expand All @@ -73,17 +67,12 @@
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.
Expand Down
1 change: 1 addition & 0 deletions src/mcp/resources/guides/init_auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
},
],
Expand Down
39 changes: 7 additions & 32 deletions src/mcp/resources/guides/init_backend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
},
],
Expand Down
21 changes: 14 additions & 7 deletions src/mcp/resources/guides/init_data_connect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: <serviceId>-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(),
},
],
Expand Down
31 changes: 31 additions & 0 deletions src/mcp/resources/guides/init_database.ts
Original file line number Diff line number Diff line change
@@ -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(),
},
],
};
},
);
3 changes: 2 additions & 1 deletion src/mcp/resources/guides/init_firestore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@
**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:

Expand All @@ -60,7 +61,7 @@
},
);

function getTomorrowDate() {

Check warning on line 64 in src/mcp/resources/guides/init_firestore.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Missing return type on function
const tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);
// Month is 0-indexed, so add 1
Expand Down
6 changes: 4 additions & 2 deletions src/mcp/resources/guides/init_firestore_rules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
Contents of the user's current \`firestore.rules\` file:

\`\`\`
${config.readProjectFile("firestore.rules", { fallback: "<FILE DOES NOT EXIST>" })}

Check warning on line 24 in src/mcp/resources/guides/init_firestore_rules.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Invalid type "any" of template literal expression
\`\`\`

1. Create the personalData and publicData security rules (seen below). If they have existing \`firestore.rules\`, integrate these with the user's existing rules.
Expand All @@ -29,10 +29,12 @@
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';

Expand Down
22 changes: 13 additions & 9 deletions src/mcp/resources/guides/init_hosting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
},
],
Expand Down
4 changes: 4 additions & 0 deletions src/mcp/resources/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,17 @@
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";

export const resources = [
init_backend,
init_ai,
init_database,
init_data_connect,
init_firestore,
init_firestore_rules,
init_auth,
Expand All @@ -21,10 +25,10 @@

export const resourceTemplates = [docs];

export async function resolveResource(

Check warning on line 28 in src/mcp/resources/index.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Missing JSDoc comment
uri: string,
ctx: McpContext,
track: boolean = true,

Check warning on line 31 in src/mcp/resources/index.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Type boolean trivially inferred from a boolean literal, remove type annotation
): Promise<
| ({
result: ReadResourceResult;
Expand Down
4 changes: 2 additions & 2 deletions src/mcp/tools/core/login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
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."),

Check failure on line 8 in src/mcp/tools/core/login.ts

View workflow job for this annotation

GitHub Actions / unit (20)

Replace `.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."` with `⏎····.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.",⏎····`

Check failure on line 8 in src/mcp/tools/core/login.ts

View workflow job for this annotation

GitHub Actions / unit (22)

Replace `.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."` with `⏎····.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.",⏎····`

Check failure on line 8 in src/mcp/tools/core/login.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Replace `.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."` with `⏎····.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.",⏎····`

Check failure on line 8 in src/mcp/tools/core/login.ts

View workflow job for this annotation

GitHub Actions / unit (20)

Replace `.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."` with `⏎····.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 & {
Expand Down Expand Up @@ -39,9 +39,9 @@
const user = creds.user as User;
return toContent(`Successfully logged in as ${user.email}`);
} catch (e: any) {
delete serverWithState.authorize;

Check warning on line 42 in src/mcp/tools/core/login.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Unexpected any. Specify a different type
return mcpError(`Login failed: ${e.message}`);
}

Check warning on line 44 in src/mcp/tools/core/login.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Unsafe member access .message on an `any` value

Check warning on line 44 in src/mcp/tools/core/login.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Invalid type "any" of template literal expression
} else {
const prototyper = await loginPrototyper();
serverWithState.authorize = prototyper.authorize;
Expand All @@ -49,7 +49,7 @@
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);
}
},
Expand Down
Loading