Skip to content

Commit c9e8510

Browse files
committed
feat: improve AI agent detection for MCP server
### Description Improve the reliability of AI agent detection when running as an MCP server by utilizing the client information provided during the MCP `initialize` request. This replaces the reliance on environment variables which were proving to be unreliable in some environments. ### Scenarios Tested - Verified that `detectAIAgent` returns "unknown" by default. - Verified that `detectAIAgent` returns mapped name from env vars. - Verified that `detectAIAgent` returns normalized MCP client name when in MCP mode. - Verified that it falls back to env vars if no client name is set in MCP mode. - Verified that MCP client name is ignored if not in MCP mode. ### Sample Commands Ran unit tests: npx mocha src/env.spec.ts
1 parent e28281f commit c9e8510

3 files changed

Lines changed: 66 additions & 1 deletion

File tree

src/env.spec.ts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { expect } from "chai";
2+
import { detectAIAgent, setFirebaseMcp, setMcpClientName } from "./env";
3+
4+
describe("env", () => {
5+
const originalEnv = { ...process.env };
6+
7+
beforeEach(() => {
8+
// Clear all well-known env vars
9+
delete process.env.ANTIGRAVITY_CLI_ALIAS;
10+
delete process.env.CLAUDECODE;
11+
delete process.env.CLINE_ACTIVE;
12+
delete process.env.CODEX_SANDBOX;
13+
delete process.env.CURSOR_AGENT;
14+
delete process.env.GEMINI_CLI;
15+
delete process.env.OPENCODE;
16+
17+
setFirebaseMcp(false);
18+
// We can't easily reset module-level variables if they don't have a reset function,
19+
// but passing empty string will make it falsy in detectAIAgent.
20+
setMcpClientName("");
21+
});
22+
23+
afterEach(() => {
24+
process.env = { ...originalEnv };
25+
});
26+
27+
describe("detectAIAgent", () => {
28+
it("should return unknown by default", () => {
29+
expect(detectAIAgent()).to.equal("unknown");
30+
});
31+
32+
it("should detect agent from env var", () => {
33+
process.env.CURSOR_AGENT = "true";
34+
expect(detectAIAgent()).to.equal("cursor");
35+
});
36+
37+
it("should detect agent from MCP client name when in MCP mode", () => {
38+
setFirebaseMcp(true);
39+
setMcpClientName("Claude Desktop");
40+
expect(detectAIAgent()).to.equal("claude_desktop");
41+
});
42+
43+
it("should fallback to env vars if in MCP mode but no client name set", () => {
44+
setFirebaseMcp(true);
45+
process.env.CURSOR_AGENT = "true";
46+
expect(detectAIAgent()).to.equal("cursor");
47+
});
48+
49+
it("should ignore MCP client name if not in MCP mode", () => {
50+
setMcpClientName("Claude Desktop");
51+
process.env.CURSOR_AGENT = "true";
52+
expect(detectAIAgent()).to.equal("cursor");
53+
});
54+
});
55+
});

src/env.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,17 @@ export function setFirebaseMcp(value: boolean) {
1717
isFirebaseMcpFlag = value;
1818
}
1919

20+
let mcpClientNameFlag: string | undefined;
21+
22+
export function setMcpClientName(name: string) {
23+
mcpClientNameFlag = name;
24+
}
25+
2026
// Detect if the CLI was invoked by a coding agent, based on well-known env vars.
2127
export function detectAIAgent(): string {
28+
if (isFirebaseMcp() && mcpClientNameFlag) {
29+
return mcpClientNameFlag.toLowerCase().replace(/ /g, "_");
30+
}
2231
if (process.env.ANTIGRAVITY_CLI_ALIAS) return "antigravity";
2332
if (process.env.CLAUDECODE) return "claude_code";
2433
if (process.env.CLINE_ACTIVE) return "cline";

src/mcp/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import { Config } from "../config";
3030
import { configstore } from "../configstore";
3131
import { EmulatorHubClient } from "../emulator/hubClient";
3232
import { Emulators } from "../emulator/types";
33-
import { isFirebaseStudio } from "../env";
33+
import { isFirebaseStudio, setMcpClientName } from "../env";
3434
import { Options } from "../options";
3535
import { getProjectId } from "../projectUtils";
3636
import { loadRC } from "../rc";
@@ -131,6 +131,7 @@ export class FirebaseMcpServer {
131131
const clientInfo = this.server.getClientVersion();
132132
this.clientInfo = clientInfo;
133133
if (clientInfo?.name) {
134+
setMcpClientName(clientInfo.name);
134135
void this.trackGA4("mcp_client_connected");
135136
}
136137
if (!this.clientInfo?.name) this.clientInfo = { name: "<unknown-client>" };

0 commit comments

Comments
 (0)