Skip to content

Commit f85f4db

Browse files
antholeoleoleina
andauthored
use mcp logger API (#9434)
Co-authored-by: oleina <[email protected]>
1 parent 8211843 commit f85f4db

File tree

3 files changed

+51
-48
lines changed

3 files changed

+51
-48
lines changed

src/mcp/index.ts

Lines changed: 44 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -79,13 +79,6 @@ export class FirebaseMcpServer {
7979
// logging spec:
8080
// https://modelcontextprotocol.io/specification/2025-03-26/server/utilities/logging
8181
currentLogLevel?: LoggingLevel = process.env.FIREBASE_MCP_DEBUG_LOG ? "debug" : undefined;
82-
// the api of logging from a consumers perspective looks like `server.logger.warn("my warning")`.
83-
public readonly logger = Object.fromEntries(
84-
orderedLogLevels.map((logLevel) => [
85-
logLevel,
86-
(message: unknown) => this.log(logLevel, message),
87-
]),
88-
) as Record<LoggingLevel, (message: unknown) => Promise<void>>;
8982

9083
/** Create a special tracking function to avoid blocking everything on initialization notification. */
9184
private async trackGA4(
@@ -191,13 +184,13 @@ export class FirebaseMcpServer {
191184
if (this.cachedProjectDir) return this.cachedProjectDir;
192185
const storedRoot = this.getStoredClientConfig().projectRoot;
193186
this.cachedProjectDir = storedRoot || this.startupRoot || process.cwd();
194-
this.log("debug", "detected and cached project root: " + this.cachedProjectDir);
187+
this.logger.debug(`detected and cached project root: ${this.cachedProjectDir}`);
195188
return this.cachedProjectDir;
196189
}
197190

198191
async detectActiveFeatures(): Promise<ServerFeature[]> {
199192
if (this.detectedFeatures?.length) return this.detectedFeatures; // memoized
200-
this.log("debug", "detecting active features of Firebase MCP server...");
193+
this.logger.debug("detecting active features of Firebase MCP server...");
201194
const projectId = (await this.getProjectId()) || "";
202195
const accountEmail = await this.getAuthenticatedUser();
203196
const ctx = this._createMcpContext(projectId, accountEmail);
@@ -209,9 +202,8 @@ export class FirebaseMcpServer {
209202
}),
210203
);
211204
this.detectedFeatures = detected.filter((f) => !!f) as ServerFeature[];
212-
this.log(
213-
"debug",
214-
"detected features of Firebase MCP server: " + (this.detectedFeatures.join(", ") || "<none>"),
205+
this.logger.debug(
206+
`detected features of Firebase MCP server: ${this.detectedFeatures.join(", ") || "<none>"}`,
215207
);
216208
return this.detectedFeatures;
217209
}
@@ -295,12 +287,12 @@ export class FirebaseMcpServer {
295287

296288
async getAuthenticatedUser(skipAutoAuth: boolean = false): Promise<string | null> {
297289
try {
298-
this.log("debug", `calling requireAuth`);
290+
this.logger.debug("calling requireAuth");
299291
const email = await requireAuth(await this.resolveOptions(), skipAutoAuth);
300-
this.log("debug", `detected authenticated account: ${email || "<none>"}`);
292+
this.logger.debug(`detected authenticated account: ${email || "<none>"}`);
301293
return email ?? (skipAutoAuth ? null : "Application Default Credentials");
302294
} catch (e) {
303-
this.log("debug", `error in requireAuth: ${e}`);
295+
this.logger.debug(`error in requireAuth: ${e}`);
304296
return null;
305297
}
306298
}
@@ -330,7 +322,7 @@ export class FirebaseMcpServer {
330322
const hasActiveProject = !!(await this.getProjectId());
331323
await this.trackGA4("mcp_list_tools");
332324
const skipAutoAuthForStudio = isFirebaseStudio();
333-
this.log("debug", `skip auto-auth in studio environment: ${skipAutoAuthForStudio}`);
325+
this.logger.debug(`skip auto-auth in studio environment: ${skipAutoAuthForStudio}`);
334326
const availableTools = await this.getAvailableTools();
335327
return {
336328
tools: availableTools.map((t) => t.mcp),
@@ -491,35 +483,47 @@ export class FirebaseMcpServer {
491483
await this.server.connect(transport);
492484
}
493485

494-
log(level: LoggingLevel, message: unknown): void {
495-
let data = message;
486+
get logger() {
487+
const logAtLevel = (level: LoggingLevel, message: unknown): void => {
488+
let data = message;
496489

497-
// mcp protocol only takes jsons or it errors; for convienence, format
498-
// a a string into a json.
499-
if (typeof message === "string") {
500-
data = { message };
501-
}
490+
// mcp protocol only takes jsons or it errors; for convienence, format
491+
// a a string into a json.
492+
if (typeof message === "string") {
493+
data = { message };
494+
}
502495

503-
if (!this.currentLogLevel) {
504-
return;
505-
}
496+
if (!this.currentLogLevel) {
497+
return;
498+
}
506499

507-
if (orderedLogLevels.indexOf(this.currentLogLevel) > orderedLogLevels.indexOf(level)) {
508-
return;
509-
}
500+
if (orderedLogLevels.indexOf(this.currentLogLevel) > orderedLogLevels.indexOf(level)) {
501+
return;
502+
}
510503

511-
if (this._ready) {
512-
// once ready, flush all pending messages before sending the next message
513-
// this should only happen during startup
514-
while (this._pendingMessages.length) {
515-
const message = this._pendingMessages.shift();
516-
if (!message) continue;
517-
this.server.sendLoggingMessage({ level: message.level, data: message.data });
504+
if (this._ready) {
505+
// once ready, flush all pending messages before sending the next message
506+
// this should only happen during startup
507+
while (this._pendingMessages.length) {
508+
const message = this._pendingMessages.shift();
509+
if (!message) continue;
510+
this.server.sendLoggingMessage({
511+
level: message.level,
512+
data: message.data,
513+
});
514+
}
515+
516+
void this.server.sendLoggingMessage({ level, data });
517+
} else {
518+
this._pendingMessages.push({ level, data });
518519
}
520+
};
519521

520-
void this.server.sendLoggingMessage({ level, data });
521-
} else {
522-
this._pendingMessages.push({ level, data });
523-
}
522+
return Object.fromEntries(
523+
orderedLogLevels.map((logLevel) => [
524+
logLevel,
525+
(message: unknown) => logAtLevel(logLevel, message),
526+
]),
527+
) as Record<LoggingLevel, (message: unknown) => Promise<void>>;
524528
}
525529
}

src/mcp/util/apptesting/availability.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export async function isAppTestingAvailable(ctx: McpContext): Promise<boolean> {
1515
const supportedPlatforms = [Platform.FLUTTER, Platform.ANDROID, Platform.IOS];
1616

1717
if (!platforms.some((p) => supportedPlatforms.includes(p))) {
18-
host.log("debug", `Found no supported App Testing platforms.`);
18+
host.logger.debug("Found no supported App Testing platforms.");
1919
return false;
2020
}
2121

src/mcp/util/crashlytics/availability.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import * as path from "path";
77
* Returns a function that detects whether Crashlytics is available.
88
*/
99
export async function isCrashlyticsAvailable(ctx: McpContext): Promise<boolean> {
10-
ctx.host.log("debug", `Looking for whether crashlytics is installed...`);
10+
ctx.host.logger.debug("Looking for whether crashlytics is installed...");
1111
return await isCrashlyticsInstalled(ctx);
1212
}
1313

@@ -22,25 +22,24 @@ async function isCrashlyticsInstalled(ctx: McpContext): Promise<boolean> {
2222
!platforms.includes(Platform.ANDROID) &&
2323
!platforms.includes(Platform.IOS)
2424
) {
25-
host.log("debug", `Found no supported Crashlytics platforms.`);
25+
host.logger.debug("Found no supported Crashlytics platforms.");
2626
return false;
2727
}
2828

2929
if (platforms.includes(Platform.FLUTTER) && (await flutterAppUsesCrashlytics(projectDir))) {
30-
host.log("debug", `Found Flutter app using Crashlytics`);
30+
host.logger.debug("Found Flutter app using Crashlytics");
3131
return true;
3232
}
3333
if (platforms.includes(Platform.ANDROID) && (await androidAppUsesCrashlytics(projectDir))) {
34-
host.log("debug", `Found Android app using Crashlytics`);
34+
host.logger.debug("Found Android app using Crashlytics");
3535
return true;
3636
}
3737
if (platforms.includes(Platform.IOS) && (await iosAppUsesCrashlytics(projectDir))) {
38-
host.log("debug", `Found iOS app using Crashlytics`);
38+
host.logger.debug("Found iOS app using Crashlytics");
3939
return true;
4040
}
4141

42-
host.log(
43-
"debug",
42+
host.logger.debug(
4443
`Found supported platforms ${JSON.stringify(platforms)}, but did not find a Crashlytics dependency.`,
4544
);
4645
return false;

0 commit comments

Comments
 (0)