Skip to content

Commit d39d184

Browse files
authored
[MCP] Create list_projects tool + slight modifications to list_apps #2 (firebase#8610)
1 parent aba2118 commit d39d184

File tree

3 files changed

+64
-7
lines changed

3 files changed

+64
-7
lines changed

src/mcp/tools/core/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,14 @@ import { create_android_sha } from "./create_android_sha.js";
1010
import { init } from "./init.js";
1111
import { get_environment } from "./get_environment.js";
1212
import { update_environment } from "./update_environment.js";
13+
import { list_projects } from "./list_projects.js";
1314
// import { consult_assistant } from "./consult_assistant.js";
1415

1516
export const coreTools: ServerTool[] = [
1617
get_project,
1718
list_apps,
1819
get_admin_sdk_config,
20+
list_projects,
1921
get_sdk_config,
2022
create_project,
2123
create_app,

src/mcp/tools/core/list_apps.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ export const list_apps = tool(
99
description: "Retrieves apps registered in the current Firebase project.",
1010
inputSchema: z.object({
1111
platform: z
12-
.enum(["ios", "android", "web"])
13-
.optional()
12+
.enum(["ios", "android", "web", "all"])
13+
.default("all")
1414
.describe("the specific platform to list (omit to list all platforms)"),
1515
}),
1616
annotations: {
@@ -23,10 +23,15 @@ export const list_apps = tool(
2323
},
2424
},
2525
async ({ platform }, { projectId }) => {
26-
const apps = await listFirebaseApps(
27-
projectId,
28-
(platform?.toUpperCase() as AppPlatform) ?? AppPlatform.ANY,
29-
);
30-
return toContent(apps);
26+
try {
27+
const apps = await listFirebaseApps(
28+
projectId!,
29+
platform === "all" ? AppPlatform.ANY : (platform.toUpperCase() as AppPlatform),
30+
);
31+
return toContent(apps);
32+
} catch (err: any) {
33+
const originalMessage = err.original ? `: ${err.original.message}` : "";
34+
throw new Error(`Failed to list Firebase apps${originalMessage}`);
35+
}
3136
},
3237
);
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { z } from "zod";
2+
import { tool } from "../../tool.js";
3+
import { toContent } from "../../util.js";
4+
import { getFirebaseProjectPage } from "../../../management/projects.js";
5+
6+
const PROJECT_LIST_PAGE_SIZE = 20;
7+
8+
export const list_projects = tool(
9+
{
10+
name: "list_projects",
11+
description: "Retrieves a list of Firebase projects up to the specified total count.",
12+
inputSchema: z.object({
13+
page_size: z
14+
.number()
15+
.min(1)
16+
.default(PROJECT_LIST_PAGE_SIZE)
17+
.describe("the number of projects to list per page (defaults to 1000)"),
18+
page_token: z.string().optional().describe("the page token to start listing from"),
19+
}),
20+
annotations: {
21+
title: "List Firebase Projects",
22+
readOnlyHint: true,
23+
idempotentHint: true,
24+
},
25+
_meta: {
26+
requiresAuth: true,
27+
},
28+
},
29+
async ({ page_size, page_token }) => {
30+
try {
31+
const projectPage = await getFirebaseProjectPage(page_size, page_token);
32+
33+
return toContent(
34+
{
35+
projects: projectPage.projects,
36+
next_page_token: projectPage.nextPageToken,
37+
},
38+
{
39+
contentPrefix: `Here are ${projectPage.projects.length} Firebase projects${page_token ? " (continued)" : ""}:\n\n`,
40+
contentSuffix: projectPage.nextPageToken
41+
? "\nThere are more projects available. To see the next page, call this tool again with the next_page_token shown above."
42+
: "",
43+
},
44+
);
45+
} catch (err: any) {
46+
const originalMessage = err.original ? `: ${err.original.message}` : "";
47+
throw new Error(`Failed to list Firebase projects${originalMessage}`);
48+
}
49+
},
50+
);

0 commit comments

Comments
 (0)