Skip to content

Commit d59d608

Browse files
authored
Utilize GCA Agent Mode & Firebase MCP with FDC VSCode (#8880)
* Implement Firebase MCP agent * change to use cli code * feature complete * update prompt file location * fixes * add analytics * add todo
1 parent f215d64 commit d59d608

File tree

8 files changed

+89
-24
lines changed

8 files changed

+89
-24
lines changed

firebase-vscode/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
## NEXT
22

3+
- [Changed] Now integrates with GCA in its agentic mode, powered by the Gemini CLI. This brings the Firebase MCP Server directly into the VS Code environment, enabling developers to use natural language to generate application schemas and queries without manually invoking explicit tools.
4+
35
## 1.5.1
46

57
- Update internal `firebase-tools` dependency to 14.11.0

firebase-vscode/common/messaging/protocol.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,10 @@ export interface WebviewToExtensionParamsMap {
123123

124124
// called from execution panel
125125
rerunExecution: void;
126+
127+
/** Docs clicked for analytics */
128+
"docs.mcp.clicked": void;
129+
"docs.tos.clicked": void;
126130
}
127131

128132
export interface DataConnectResults {

firebase-vscode/src/analytics.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ export enum DATA_CONNECT_EVENT_NAME {
3939
GEMINI_SCHEMA_CALL = "gemini_schema_call",
4040
GEMINI_SUCCESS = "gemini_success",
4141
TRY_GEMINI_CLICKED = "try_gemini_clicked",
42+
TRY_FIREBASE_AGENT_CLICKED = "try_firebase_agent_in_gemini_clicked",
43+
MCP_DOCS_CLICKED = "mcp_docs_clicked",
44+
GIF_TOS_CLICKED = "gif_tos_clicked",
4245
}
4346

4447
export class AnalyticsLogger {
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { gemini, gemini as geminiToolModule } from "../../../../src/init/features/aitools/gemini";
2+
import * as vscode from "vscode";
3+
import { firebaseConfig } from "../config";
4+
import { ExtensionBrokerImpl } from "../../extension-broker";
5+
import { AnalyticsLogger, DATA_CONNECT_EVENT_NAME } from "../../analytics";
6+
7+
8+
9+
export function registerFirebaseMCP(broker: ExtensionBrokerImpl, analyticsLogger: AnalyticsLogger): vscode.Disposable {
10+
const geminiActivateSub = broker.on("firebase.activate.gemini", async () => {
11+
analyticsLogger.logger.logUsage(
12+
DATA_CONNECT_EVENT_NAME.TRY_FIREBASE_AGENT_CLICKED,
13+
);
14+
writeToGeminiConfig();
15+
await vscode.commands.executeCommand("cloudcode.gemini.chatView.focus");
16+
await vscode.commands.executeCommand("geminicodeassist.agent.chat.new"); // opens a new chat when an old one exists;
17+
});
18+
19+
const mcpDocsSub = broker.on("docs.mcp.clicked", () => {
20+
analyticsLogger.logger.logUsage(DATA_CONNECT_EVENT_NAME.MCP_DOCS_CLICKED);
21+
});
22+
const tosSub = broker.on("docs.tos.clicked", () => {
23+
analyticsLogger.logger.logUsage(DATA_CONNECT_EVENT_NAME.GIF_TOS_CLICKED);
24+
});
25+
26+
return vscode.Disposable.from(
27+
{ dispose: geminiActivateSub },
28+
{ dispose: mcpDocsSub },
29+
{ dispose: tosSub },
30+
);
31+
}
32+
33+
// Writes the Firebase MCP server to the gemini code assist config file
34+
export function writeToGeminiConfig() {
35+
36+
const config = firebaseConfig.value?.tryReadValue;
37+
if (!config) {
38+
vscode.window.showErrorMessage("Could not read firebase.json");
39+
// TODO: Consider writing to HOME_DIR in case of this failure
40+
return;
41+
}
42+
43+
geminiToolModule.configure(config, config.projectDir, [/** TODO: Create "dataconnect" .md file */]);
44+
}

firebase-vscode/src/data-connect/index.ts

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ import { AnalyticsLogger, DATA_CONNECT_EVENT_NAME } from "../analytics";
3535
import { emulators } from "../init/features";
3636
import { GCAToolClient } from "./ai-tools/gca-tool";
3737
import { GeminiToolController } from "./ai-tools/tool-controller";
38+
import {
39+
registerFirebaseMCP,
40+
writeToGeminiConfig,
41+
} from "./ai-tools/firebase-mcp";
3842

3943
class CodeActionsProvider implements vscode.CodeActionProvider {
4044
constructor(
@@ -159,23 +163,6 @@ export function registerFdc(
159163
context,
160164
);
161165

162-
/** Gemini Related activations */
163-
const toolController = new GeminiToolController(
164-
analyticsLogger,
165-
fdcService,
166-
dataConnectConfigs,
167-
);
168-
const gcaToolClient = new GCAToolClient(context, toolController);
169-
170-
gcaToolClient.activate();
171-
172-
broker.on("firebase.activate.gemini", () => {
173-
analyticsLogger.logger.logUsage(DATA_CONNECT_EVENT_NAME.TRY_GEMINI_CLICKED);
174-
vscode.commands.executeCommand("cloudcode.gemini.chatView.focus");
175-
});
176-
177-
/** End Gemini activations */
178-
179166
// register codelens
180167
const operationCodeLensProvider = new OperationCodeLensProvider(
181168
emulatorController,
@@ -249,6 +236,7 @@ export function registerFdc(
249236
registerFdcDeploy(broker, analyticsLogger),
250237
registerFdcSdkGeneration(broker, analyticsLogger),
251238
registerTerminalTasks(broker, analyticsLogger),
239+
registerFirebaseMCP(broker, analyticsLogger),
252240
operationCodeLensProvider,
253241

254242
vscode.languages.registerCodeLensProvider(
@@ -276,7 +264,6 @@ export function registerFdc(
276264
[{ scheme: "file", language: "yaml", pattern: "**/connector.yaml" }],
277265
configureSdkCodeLensProvider,
278266
),
279-
toolController,
280267
{
281268
dispose: () => {
282269
client.stop();

firebase-vscode/webpack.common.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,10 @@ const extensionConfig = {
183183
plugins: [
184184
new CopyPlugin({
185185
patterns: [
186+
{
187+
from: "../prompts",
188+
to: "./prompts",
189+
},
186190
{
187191
from: "../templates",
188192
to: "./templates",

firebase-vscode/webviews/SidebarApp.tsx

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -167,23 +167,40 @@ function DataConnect() {
167167
</a>
168168
</Label>
169169
<Spacer size="xlarge"></Spacer>
170-
<Label level={2}>Generate Schema and Operations (Preview)</Label>
170+
<Label level={2}>
171+
Develop your app with the Firebase Agent in Gemini (Preview)
172+
</Label>
171173
<Spacer size="medium"></Spacer>
172174
<VSCodeButton
173175
appearance="secondary"
174176
onClick={() => {
175177
broker.send("firebase.activate.gemini");
176178
}}
177179
>
178-
Try Gemini with @FirebaseDataConnect
180+
Build your schema and queries with AI
179181
</VSCodeButton>
180-
<Spacer size="xsmall" />
182+
<Spacer size="small" />
181183
<Label level={3}>
182-
See also:{" "}
183-
<a href="https://firebase.google.com/docs/gemini-in-firebase#how-gemini-in-firebase-uses-your-data">
184+
<a
185+
href="https://firebase.google.com/docs/gemini-in-firebase#how-gemini-in-firebase-uses-your-data"
186+
onClick={() => {
187+
broker.send("docs.tos.clicked");
188+
}}
189+
>
184190
Gemini in Firebase Usage and Terms
185191
</a>
186192
</Label>
193+
<Label level={3}>
194+
See also:{" "}
195+
<a
196+
href="https://firebase.google.com/docs/cli/mcp-server"
197+
onClick={() => {
198+
broker.send("docs.mcp.clicked");
199+
}}
200+
>
201+
Learn more about Firebase MCP
202+
</a>
203+
</Label>
187204
</>
188205
);
189206
}

src/init/features/aitools/promptUpdater.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,11 @@ import { Config } from "../../../config";
1010
import { confirm } from "../../../prompt";
1111
import * as utils from "../../../utils";
1212
import { logger } from "../../../logger";
13+
import { isVSCodeExtension } from "../../../vsCodeUtils";
14+
15+
const CLI_PROMPTS_DIR = path.join(__dirname, "../../../../prompts");
16+
const VSCODE_PROMPTS_DIR = path.join(__dirname, "./prompts"); // vscode sits in firebase-vscode/dist/ folder
1317

14-
const PROMPTS_DIR = path.join(__dirname, "../../../../prompts");
1518
const FIREBASE_TAG_REGEX = /<firebase_prompts(?:\s+hash="([^"]+)")?>([\s\S]*?)<\/firebase_prompts>/;
1619

1720
const PROMPT_FILES: Record<string, string> = {
@@ -149,6 +152,7 @@ export function getFeatureContent(feature: string): string {
149152
const filename = PROMPT_FILES[feature];
150153
if (!filename) return "";
151154

155+
const PROMPTS_DIR = isVSCodeExtension() ? VSCODE_PROMPTS_DIR : CLI_PROMPTS_DIR;
152156
const content = fs.readFileSync(path.join(PROMPTS_DIR, filename), "utf8");
153157
return content;
154158
}

0 commit comments

Comments
 (0)