|
| 1 | +# Firebase MCP Server Contributing Guide |
| 2 | + |
| 3 | +## Overview |
| 4 | + |
| 5 | +The Firebase MCP server offers tools that LLMs can use when interacting with Firebase. |
| 6 | +The tools let you fetch important context about what is deployed to your project, |
| 7 | +access agents that can perform specialized tasks, or make minor modifications to your project. |
| 8 | + |
| 9 | +## Audience |
| 10 | + |
| 11 | +If you are a developer interested in contributing to the MCP server, this is the |
| 12 | +documentation for you! This guide describes how to be successful in contributing |
| 13 | +to our repository. |
| 14 | + |
| 15 | +## Getting Started |
| 16 | + |
| 17 | +The Firebase MCP server lives alongside the Firebase CLI in the [firebase/firebase-tools][gh-repo] repo. |
| 18 | +It lives here so that it can share code for authentication, API calls, and utilities with the CLI. |
| 19 | + |
| 20 | +External developers: If you're interested in contributing code, get started by |
| 21 | +[making a fork of the repository for your GitHub account](https://help.github.com/en/github/getting-started-with-github/fork-a-repo). |
| 22 | + |
| 23 | +Internal developers: Go to go/firebase-github-request and ask for access to this repo. You should work |
| 24 | +off of sepearate branches in this repo, to ensure that all CI runs correctly for you. |
| 25 | + |
| 26 | +### Contribution Process |
| 27 | + |
| 28 | +External developers: The preferred means of contribution to the MCP server is by creating a branch in your |
| 29 | +own fork, pushing your changes there, and submitting a Pull Request to the |
| 30 | +`master` branch of `firebase/firebase-tools`. |
| 31 | + |
| 32 | +Internal developers: Instead of working off of a fork, please make a branch on [firebase/firebase-tools][gh-repo] |
| 33 | +named <yourInitialsOrLDAP>-<feature> (for example, `jh-dataconnect-tools`) |
| 34 | + |
| 35 | +If your change is visible to users, it should be in the |
| 36 | +[changelog](https://github.com/firebase/firebase-tools/releases). Please |
| 37 | +add an entry to the `CHANGELOG.md` file. This log is emptied after every release |
| 38 | +and is used to generate the release notes posted in the |
| 39 | +[Releases](https://github.com/firebase/firebase-tools/releases) page. Markdown |
| 40 | +formatting is respected (using the GitHub style). |
| 41 | + |
| 42 | +NOTE: Any new files added to the repository **must** be written in TypeScript |
| 43 | +and **must** include unit tests. There are very few exceptions to this rule. |
| 44 | + |
| 45 | +After your Pull Request passes the tests and is approved by a Firebase CLI team |
| 46 | +member, they will merge your PR. Thank you for your contribution! |
| 47 | + |
| 48 | +### Setting up your development environment |
| 49 | + |
| 50 | +Please follow the instructions in the [CLI's CONTRIBUTING.md](https://github.com/firebase/firebase-tools/blob/master/CONTRIBUTING.md#setting-up-your-development-environment) to get your development environment set up. |
| 51 | + |
| 52 | +There are a few extra things to set up when developing the MCP server. |
| 53 | + |
| 54 | +### Testing with the MCP Inspector |
| 55 | + |
| 56 | +During early development, you will want to test that your tools outputs what you expect, without burning tokens. |
| 57 | +The easiest way to do this is the [MCP inspector](https://github.com/modelcontextprotocol/inspector). From a |
| 58 | +Firebase project directory, run: |
| 59 | + |
| 60 | +``` |
| 61 | +npx -y @modelcontextprotocol/inspector |
| 62 | +``` |
| 63 | + |
| 64 | +This will print out a localhost link to a simple testing UI. There, you can configure the MCP server |
| 65 | +and manually list and execute tools. |
| 66 | + |
| 67 | +``` |
| 68 | +Transport Type: STDIO |
| 69 | +Command: firebase |
| 70 | +Arguments: experimental:mcp |
| 71 | +
|
| 72 | +``` |
| 73 | + |
| 74 | +## Building MCP tools |
| 75 | + |
| 76 | +IMPORTANT: LLMs cannot handle large number of tools. Please consider whether the functionality |
| 77 | +you want to add can be added to an existing tool. |
| 78 | + |
| 79 | +### Setting up a new tool |
| 80 | + |
| 81 | +#### Create a file for your tool |
| 82 | + |
| 83 | +First, create a new file in `src/mcp/tools/<product>`. |
| 84 | +If your product does not have tools yet, create a new directory under `src/mcp/tools`/. |
| 85 | +If the tool is relevant for many Firebase products, put it under `core`. |
| 86 | + |
| 87 | +Tool files should be named `<product>/<foo_tool>`. The tool will then be listed as `<product>_<foo_tool>`. |
| 88 | + |
| 89 | +```typescript |
| 90 | +import { z } from "zod"; |
| 91 | +import { tool } from "../../tool.js"; |
| 92 | +import { mcpError, toContent } from "../../util.js"; |
| 93 | + |
| 94 | +export const foo_bar = tool( |
| 95 | + { |
| 96 | + name: "foo_bar", |
| 97 | + description: "Foos a bar. This description informs LLMs when to use this tool", |
| 98 | + inputSchema: z.object({ |
| 99 | + foo: z |
| 100 | + .string() |
| 101 | + .describe("The foo to bar. Parameter descriptions inform LLMs how to use this param."), |
| 102 | + }), |
| 103 | + annotations: { |
| 104 | + title: "Foo Bar", |
| 105 | + readOnlyHint: true, // True if this tool makes no changes to your local files or Firebase project. |
| 106 | + idempotentHint: false, // True if this tool can safely be run multiple times without redundant effects. |
| 107 | + destructiveHint: false, // True if this tool deletes files or data. |
| 108 | + openWorldHint: false, // Does this tool interact with open (ie the web) or closed systems (ie a Firestore DB) |
| 109 | + }, |
| 110 | + _meta: { |
| 111 | + requiresProject: true, // Does this tool require you to be in a Firebase project directory? |
| 112 | + requiresAuth: true, // Does this tool require you to be authenticated (usually via `firebase login`) |
| 113 | + requiresGemini: true, // Does this tool use Gemini in Firebase in any way? |
| 114 | + }, |
| 115 | + }, |
| 116 | + async ( |
| 117 | + { foo }, // Anything passed in inputSchema is avialable here. |
| 118 | + { projectId, accountEmail, config }, // See ServerToolContext for a complete list of available fields |
| 119 | + ) => { |
| 120 | + // Business logic for the tool |
| 121 | + let foo; |
| 122 | + try { |
| 123 | + const foo = await barFood(prompt, projectId); |
| 124 | + } catch (e: any) { |
| 125 | + // return mcpError to handle error cases |
| 126 | + return mcpError("Foo could not be barred"); |
| 127 | + } |
| 128 | + // Use toContent to return successes in a MCP friendly format. |
| 129 | + return toContent(schema); |
| 130 | + }, |
| 131 | +); |
| 132 | +``` |
| 133 | + |
| 134 | +Here are a few style notes: |
| 135 | + |
| 136 | +- Tool names |
| 137 | + - should not include product name |
| 138 | + - should be all lower-case letters |
| 139 | + - should be snake case |
| 140 | +- Descriptions |
| 141 | + - should be aimed at informing LLMs, not humans |
| 142 | + |
| 143 | +#### Load the command |
| 144 | + |
| 145 | +Next, go to `src/mcp/tools/<product>/index.ts`, and add your tool: |
| 146 | + |
| 147 | +```typescript |
| 148 | +import { foo_bar } from "./foo_bar" |
| 149 | + |
| 150 | +export const <product>Tools = [ |
| 151 | + foo_bar, |
| 152 | +]; |
| 153 | + |
| 154 | +``` |
| 155 | + |
| 156 | +If this is the first tool for this product, also go to `src/mcp/tools/index.ts` and add your product: |
| 157 | + |
| 158 | +```typescript |
| 159 | +import { <product>Tools } from "./<product>/index.js" |
| 160 | + |
| 161 | +const tools: Record<ServerFeature, ServerTool[]> = { |
| 162 | + // Exisitng tools here... |
| 163 | + <product>: addFeaturePrefix("<product>", <product>Tools), |
| 164 | +} |
| 165 | + |
| 166 | +``` |
| 167 | + |
| 168 | +### Update the README.md tool list |
| 169 | + |
| 170 | +Run the following command to add your new tool to the list in `src/mcp/README.md` |
| 171 | + |
| 172 | +``` |
| 173 | +node lib/bin/firebase.js experimental:mcp --generate-tool-list |
| 174 | +``` |
| 175 | + |
| 176 | +### Logging and terminal formatting |
| 177 | + |
| 178 | +The Firebase CLI has a central logger available in `src/logger`. You should |
| 179 | +never use `console.log()` in an MCP tool - STDOUT must only take structured MCP output. |
| 180 | + |
| 181 | +Any logs for your tool will be written to `firebase-debug.log` |
| 182 | + |
| 183 | +[gh-repo]: https://github.com/firebase/firebase-tools |
0 commit comments