From 3ff1f3d41b324634f55ccd831c820e834d2f4f25 Mon Sep 17 00:00:00 2001 From: Joe Hanley Date: Tue, 1 Sep 2026 10:06:36 -0700 Subject: [PATCH 1/2] feat(mcp): add humanReadableDescription to MCP tools ### Description Add `humanReadableDescription` to all MCP tools to provide concise 1-sentence summaries for human consumption, and use this field in `--generate-tool-list` output and documentation tables rather than the longer AI-oriented `description`. ### Scenarios Tested - Unit tests verify `humanReadableDescription` is attached to `ServerTool['mcp']`. - Unit tests verify `markdownDocsOfTools()` formats the table with `humanReadableDescription` and falls back to `description` when not present. - Ran fast test suite (`npm run mocha:fast`) and lint check (`npm run lint:changed-files`). ### Sample Commands ```bash firebase mcp --generate-tool-list ``` --- CHANGELOG.md | 1 + src/mcp/CONTRIBUTING.md | 5 +- src/mcp/README.md | 90 +++++++++---------- src/mcp/tool.spec.ts | 2 + src/mcp/tool.ts | 1 + src/mcp/tools/apphosting/fetch_logs.ts | 1 + src/mcp/tools/apphosting/list_backends.ts | 2 + src/mcp/tools/apptesting/tests.ts | 4 + src/mcp/tools/auth/get_users.ts | 2 + src/mcp/tools/auth/set_sms_region_policy.ts | 2 + src/mcp/tools/auth/update_user.ts | 2 + src/mcp/tools/core/create_android_sha.ts | 2 + src/mcp/tools/core/create_app.ts | 2 + src/mcp/tools/core/create_project.ts | 2 + src/mcp/tools/core/deploy.ts | 2 + src/mcp/tools/core/deploy_status.ts | 1 + src/mcp/tools/core/get_environment.ts | 2 + src/mcp/tools/core/get_project.ts | 2 + src/mcp/tools/core/get_sdk_config.ts | 2 + src/mcp/tools/core/get_security_rules.ts | 2 + src/mcp/tools/core/init.ts | 2 + src/mcp/tools/core/list_apps.ts | 1 + src/mcp/tools/core/list_projects.ts | 1 + src/mcp/tools/core/login.ts | 2 + src/mcp/tools/core/logout.ts | 1 + src/mcp/tools/core/read_resources.ts | 2 + src/mcp/tools/core/update_environment.ts | 2 + src/mcp/tools/core/validate_security_rules.ts | 2 + src/mcp/tools/crashlytics/events.ts | 4 + src/mcp/tools/crashlytics/issues.ts | 2 + src/mcp/tools/crashlytics/notes.ts | 4 + src/mcp/tools/crashlytics/reports.ts | 2 + src/mcp/tools/dataconnect/compile.ts | 2 + src/mcp/tools/dataconnect/execute.ts | 2 + src/mcp/tools/dataconnect/list_services.ts | 2 + src/mcp/tools/firestore/query_collection.ts | 2 + src/mcp/tools/functions/get_logs.ts | 2 + src/mcp/tools/functions/list_functions.ts | 1 + src/mcp/tools/index.spec.ts | 50 ++++++++++- src/mcp/tools/index.ts | 6 +- src/mcp/tools/messaging/send_message.ts | 2 + src/mcp/tools/realtime_database/get_data.ts | 1 + src/mcp/tools/realtime_database/set_data.ts | 2 + src/mcp/tools/remoteconfig/get_template.ts | 2 + src/mcp/tools/remoteconfig/update_template.ts | 2 + src/mcp/tools/storage/get_download_url.ts | 1 + 46 files changed, 183 insertions(+), 48 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 94615b20227..f0d87606547 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,4 @@ +- Add `humanReadableDescription` field to MCP tools and use it in `--generate-tool-list` output. - Fixed an issue where the Functions emulator replaced an IPC failure with an unrelated `TypeError` about stream chunk types, hiding why the runtime became unreachable (#10876). - [Added] Add -f, --force option to `firebase ext:migrate`. - [Fixed] Fix parameter type preservation and optional system parameter handling during extension updates in `firebase ext:migrate` diff --git a/src/mcp/CONTRIBUTING.md b/src/mcp/CONTRIBUTING.md index 4b36ef0cddd..9d099adfee4 100644 --- a/src/mcp/CONTRIBUTING.md +++ b/src/mcp/CONTRIBUTING.md @@ -92,9 +92,11 @@ import { tool } from "../../tool"; import { mcpError, toContent } from "../../util"; export const foo_bar = tool( + "", { name: "foo_bar", description: "Foos a bar. This description informs LLMs when to use this tool", + humanReadableDescription: "Foos a bar.", inputSchema: z.object({ foo: z .string() @@ -138,7 +140,8 @@ Here are a few style notes: - should be all lower-case letters - should be snake case - Descriptions - - should be aimed at informing LLMs, not humans + - `description` should be aimed at informing LLMs, not humans + - `humanReadableDescription` should be a short, 1 sentence description of what the tool does for human-facing documentation #### Load the command diff --git a/src/mcp/README.md b/src/mcp/README.md index 55b3f27a50b..2bbd6f68ef5 100644 --- a/src/mcp/README.md +++ b/src/mcp/README.md @@ -159,51 +159,51 @@ For more information, visit the [official Firebase MCP server documentation](htt The Firebase MCP server provides three types of capabilities: **Tools** (functions that perform actions), **Prompts** (reusable command templates), and **Resources** (documentation files for AI models). -| Tool Name | Feature Group | Description | -| -------------------------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| apphosting_fetch_logs | apphosting | Use this to fetch the most recent logs for a specified App Hosting backend. If `buildLogs` is specified, the logs from the build process for the latest build are returned. The most recent logs are listed first. | -| apphosting_list_backends | apphosting | Use this to retrieve a list of App Hosting backends in the current project. An empty list means that there are no backends. The `uri` is the public URL of the backend. A working backend will have a `managed_resources` array that will contain a `run_service` entry. That `run_service.service` is the resource name of the Cloud Run service serving the App Hosting backend. The last segment of that name is the service ID. `domains` is the list of domains that are associated with the backend. They either have type `CUSTOM` or `DEFAULT`. Every backend should have a `DEFAULT` domain. The actual domain that a user would use to connect to the backend is the last parameter of the domain resource name. If a custom domain is correctly set up, it will have statuses ending in `ACTIVE`. | -| auth_get_users | auth | Use this to retrieve one or more Firebase Auth users based on a list of UIDs or a list of emails. | -| auth_update_user | auth | Use this to disable, enable, or set a custom claim on a specific user's account. | -| auth_set_sms_region_policy | auth | Use this to set an SMS region policy for Firebase Authentication to restrict the regions which can receive text messages based on an ALLOW or DENY list of country codes. This policy will override any existing policies when set. | -| firebase_login | core | Use this to sign the user into the Firebase CLI and Firebase MCP server. This requires a Google Account, and sign in is required to create and work with Firebase Projects. | -| firebase_logout | core | Use this to sign the user out of the Firebase CLI and Firebase MCP server. | -| firebase_validate_security_rules | core | Use this to check Firebase Security Rules for Firestore, Storage, or Realtime Database for syntax and validation errors. | -| firebase_get_project | core | Use this to retrieve information about the currently active Firebase Project. | -| firebase_list_apps | core | Use this to retrieve a list of the Firebase Apps registered in the currently active Firebase project. Firebase Apps can be iOS, Android, or Web. | -| firebase_list_projects | core | Use this to retrieve a list of Firebase Projects that the signed-in user has access to. | -| firebase_get_sdk_config | core | Use this to retrieve the Firebase configuration information for a Firebase App. You must specify EITHER a platform OR the Firebase App ID for a Firebase App registered in the currently active Firebase Project. | -| firebase_create_project | core | Use this to create a new Firebase Project. | -| firebase_create_app | core | Use this to create a new Firebase App in the currently active Firebase Project. Firebase Apps can be iOS, Android, or Web. | -| firebase_create_android_sha | core | Use this to add the specified SHA certificate hash to the specified Firebase Android App. | -| firebase_get_environment | core | Use this to retrieve the current Firebase **environment** configuration for the Firebase CLI and Firebase MCP server, including current authenticated user, project directory, active Firebase Project, and more. All tools require the user to be authenticated, but not all information is required for all tools. Pay attention to the tool requirements for which pieces of information are required. | -| firebase_update_environment | core | Use this to update environment config for the Firebase CLI and Firebase MCP server, such as project directory, active project, active user account, accept terms of service, and more. Use `firebase_get_environment` to see the currently configured environment. | -| firebase_init | core | Use this to initialize selected Firebase services in the workspace (Cloud Firestore database, Firebase SQL Connect, Firebase Realtime Database, Firebase AI Logic). All services are optional; specify only the products you want to set up. You can initialize new features into an existing project directory, but re-initializing an existing feature may overwrite configuration. To deploy the initialized features, run the `firebase deploy` command after `firebase_init` tool. | -| firebase_get_security_rules | core | Use this to retrieve the security rules for a specified Firebase service. If there are multiple instances of that service in the product, the rules for the default instance are returned. | -| firebase_read_resources | core | Use this to read the contents of `firebase://` resources or list available resources | -| crashlytics_create_note | crashlytics | Add a note to an issue from crashlytics. | -| crashlytics_delete_note | crashlytics | Delete a note from a Crashlytics issue. | -| crashlytics_get_issue | crashlytics | Gets data for a Crashlytics issue, which can be used as a starting point for debugging. | -| crashlytics_list_events | crashlytics | Use this to list the most recent events matching the given filters.
Can be used to fetch sample crashes and exceptions for an issue,
which will include stack traces and other data useful for debugging. | -| crashlytics_batch_get_events | crashlytics | Gets specific events by resource name.
Can be used to fetch sample crashes and exceptions for an issue,
which will include stack traces and other data useful for debugging. | -| crashlytics_list_notes | crashlytics | Use this to list all notes for an issue in Crashlytics. | -| crashlytics_get_report | crashlytics | Use this to request numerical reports from Crashlytics. The result aggregates the sum of events and impacted users, grouped by a dimension appropriate for that report. Agents must read the [Firebase Crashlytics Reports Guide](firebase://guides/crashlytics/reports) using the `firebase_read_resources` tool before calling to understand critical prerequisites for requesting reports and how to interpret the results. | -| crashlytics_update_issue | crashlytics | Use this to update the state of Crashlytics issue. | -| realtimedatabase_get_data | realtimedatabase | Use this to retrieve data from the specified location in a Firebase Realtime Database. | -| realtimedatabase_set_data | realtimedatabase | Use this to write data to the specified location in a Firebase Realtime Database. | -| dataconnect_build | dataconnect | Use this to compile Firebase SQL Connect schema, operations, and/or connectors and check for build errors. | -| dataconnect_list_services | dataconnect | Use this to list existing local and backend Firebase SQL Connect services | -| dataconnect_execute | dataconnect | Use this to execute a GraphQL operation against a SQL Connect service or its emulator. | -| firestore_delete_document | firestore | Use this to delete Firestore documents from a database in the current project by full document paths. Use this if you know the exact path of a document. | -| firestore_get_documents | firestore | Use this to retrieve one or more Firestore documents from a database in the current project by full document paths. Use this if you know the exact path of a document. | -| firestore_list_collections | firestore | Use this to retrieve a list of collections from a Firestore database in the current project. | -| firestore_query_collection | firestore | Use this to retrieve one or more Firestore documents from a collection in a database in the current project by a collection with a full document path. Use this if you know the exact path of a collection and the filtering clause you would like for the document. | -| functions_get_logs | functions | Use this to retrieve a page of Cloud Functions log entries using Google Cloud Logging advanced filters. | -| functions_list_functions | functions | List all deployed functions in your Firebase project. | -| messaging_send_message | messaging | Use this to send a message to a Firebase Cloud Messaging registration token or topic. ONLY ONE of `registration_token` or `topic` may be supplied in a specific call. | -| remoteconfig_get_template | remoteconfig | Use this to retrieve the specified Firebase Remote Config template from the currently active Firebase Project. | -| remoteconfig_update_template | remoteconfig | Use this to publish a new remote config template or roll back to a specific version for the project | -| storage_get_object_download_url | storage | Use this to retrieve the download URL for an object in a Cloud Storage for Firebase bucket. | +| Tool Name | Feature Group | Description | +| -------------------------------- | ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| apphosting_fetch_logs | apphosting | Fetch recent service or build logs for an App Hosting backend. | +| apphosting_list_backends | apphosting | List App Hosting backends, traffic configurations, and custom domains in your project. | +| auth_get_users | auth | Retrieve Firebase Auth users by UID, email, phone number, or list all users. | +| auth_update_user | auth | Update a user's account by enabling/disabling it or setting custom claims. | +| auth_set_sms_region_policy | auth | Set an SMS region policy allowing or denying specific country codes for Firebase Authentication. | +| firebase_login | core | Sign the user into the Firebase CLI and MCP server or check current authentication status. | +| firebase_logout | core | Sign the user out of the Firebase CLI and MCP server. | +| firebase_validate_security_rules | core | Validate syntax and check for errors in Firestore, Storage, or Realtime Database security rules. | +| firebase_get_project | core | Retrieve metadata and configuration details for the currently active Firebase project. | +| firebase_list_apps | core | List all Firebase apps registered in the active project. | +| firebase_list_projects | core | List Firebase projects accessible by the authenticated user. | +| firebase_get_sdk_config | core | Retrieve SDK configuration details or config file contents for a registered Firebase app. | +| firebase_create_project | core | Create a new Firebase project or enable Firebase services on an existing Google Cloud project. | +| firebase_create_app | core | Create a new iOS, Android, or Web app in the active Firebase project. | +| firebase_create_android_sha | core | Add a SHA-1 or SHA-256 certificate hash to an Android app in the active Firebase project. | +| firebase_get_environment | core | Retrieve the current Firebase CLI and MCP environment configuration, active project, and authenticated user. | +| firebase_update_environment | core | Update environment settings such as project directory, active project, or active user account. | +| firebase_init | core | Initialize and configure Firebase services in your local project workspace. | +| firebase_get_security_rules | core | Retrieve the active security rules for Firestore, Storage, or Realtime Database. | +| firebase_read_resources | core | Read the contents of internal firebase:// documentation resources or list all available resources. | +| crashlytics_create_note | crashlytics | Add a note to a Crashlytics issue for an Android or iOS app. | +| crashlytics_delete_note | crashlytics | Delete a note from a Crashlytics issue for an Android or iOS app. | +| crashlytics_get_issue | crashlytics | Retrieve details and metadata for a specific Crashlytics issue. | +| crashlytics_list_events | crashlytics | List recent crash and exception events matching specified filters for an issue. | +| crashlytics_batch_get_events | crashlytics | Retrieve sample crash and exception events by resource name for debugging. | +| crashlytics_list_notes | crashlytics | List all notes attached to a Crashlytics issue for an Android or iOS app. | +| crashlytics_get_report | crashlytics | Generate aggregated numerical reports for Crashlytics issues and events. | +| crashlytics_update_issue | crashlytics | Update the state (OPEN or CLOSED) of a Crashlytics issue. | +| realtimedatabase_get_data | realtimedatabase | Read data from a specified path in the Firebase Realtime Database. | +| realtimedatabase_set_data | realtimedatabase | Write JSON data to a specified path in the Firebase Realtime Database. | +| dataconnect_build | dataconnect | Compile Firebase SQL Connect schemas, operations, and connectors to validate syntax and types. | +| dataconnect_list_services | dataconnect | List local and deployed Firebase SQL Connect services, schemas, and connectors. | +| dataconnect_execute | dataconnect | Execute a GraphQL query or mutation against a Firebase SQL Connect service or emulator. | +| firestore_delete_document | firestore | Use this to delete Firestore documents from a database in the current project by full document paths. Use this if you know the exact path of a document. | +| firestore_get_documents | firestore | Use this to retrieve one or more Firestore documents from a database in the current project by full document paths. Use this if you know the exact path of a document. | +| firestore_list_collections | firestore | Use this to retrieve a list of collections from a Firestore database in the current project. | +| firestore_query_collection | firestore | Query Firestore documents from a collection with optional filters and ordering. | +| functions_get_logs | functions | Retrieve and filter Cloud Functions log entries from Google Cloud Logging. | +| functions_list_functions | functions | List all deployed Cloud Functions in your Firebase project. | +| messaging_send_message | messaging | Send a Firebase Cloud Messaging push notification to a device registration token or topic. | +| remoteconfig_get_template | remoteconfig | Retrieve the active or specified version of the Firebase Remote Config template. | +| remoteconfig_update_template | remoteconfig | Publish a new Firebase Remote Config template or rollback to a previous version. | +| storage_get_object_download_url | storage | Retrieve the download URL for an object in a Cloud Storage bucket. | | Prompt Name | Feature Group | Description | | --------------------------------- | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | diff --git a/src/mcp/tool.spec.ts b/src/mcp/tool.spec.ts index eb3f2cb8653..09b72036af5 100644 --- a/src/mcp/tool.spec.ts +++ b/src/mcp/tool.spec.ts @@ -32,6 +32,7 @@ describe("tool", () => { { name: "test_tool", description: "A test tool", + humanReadableDescription: "A short human readable description.", inputSchema: z.object({}), outputSchema: z.object({ result: z.string() }), }, @@ -40,6 +41,7 @@ describe("tool", () => { expect(testTool.mcp.name).to.equal("test_tool"); expect(testTool.mcp.description).to.equal("A test tool"); + expect(testTool.mcp.humanReadableDescription).to.equal("A short human readable description."); expect(testTool.mcp.outputSchema).to.not.be.undefined; expect(testTool.mcp.outputSchema.properties.result.type).to.equal("string"); expect(testTool.fn).to.equal(testFn); diff --git a/src/mcp/tool.ts b/src/mcp/tool.ts index 1cef8f58cbb..e126b905255 100644 --- a/src/mcp/tool.ts +++ b/src/mcp/tool.ts @@ -23,6 +23,7 @@ export interface ServerTool { mcp: { name: string; description?: string; + humanReadableDescription?: string; inputSchema: any; outputSchema?: any; annotations?: { diff --git a/src/mcp/tools/apphosting/fetch_logs.ts b/src/mcp/tools/apphosting/fetch_logs.ts index 9439cab8081..881e8bcea6c 100644 --- a/src/mcp/tools/apphosting/fetch_logs.ts +++ b/src/mcp/tools/apphosting/fetch_logs.ts @@ -13,6 +13,7 @@ export const fetch_logs = tool( name: "fetch_logs", description: "Use this to fetch the most recent logs for a specified App Hosting backend. If `buildLogs` is specified, the logs from the build process for the latest build are returned. The most recent logs are listed first.", + humanReadableDescription: "Fetch recent service or build logs for an App Hosting backend.", inputSchema: z.object({ buildLogs: z .boolean() diff --git a/src/mcp/tools/apphosting/list_backends.ts b/src/mcp/tools/apphosting/list_backends.ts index 6d4e85cc550..a729f596b11 100644 --- a/src/mcp/tools/apphosting/list_backends.ts +++ b/src/mcp/tools/apphosting/list_backends.ts @@ -24,6 +24,8 @@ export const list_backends = tool( " Every backend should have a `DEFAULT` domain. " + " The actual domain that a user would use to connect to the backend is the last parameter of the domain resource name. " + " If a custom domain is correctly set up, it will have statuses ending in `ACTIVE`.", + humanReadableDescription: + "List App Hosting backends, traffic configurations, and custom domains in your project.", inputSchema: z.object({ location: z .string() diff --git a/src/mcp/tools/apptesting/tests.ts b/src/mcp/tools/apptesting/tests.ts index 2644205c1b8..21b394a54c9 100644 --- a/src/mcp/tools/apptesting/tests.ts +++ b/src/mcp/tools/apptesting/tests.ts @@ -49,6 +49,8 @@ export const run_tests = tool( { name: "run_test", description: `Run a remote test.`, + humanReadableDescription: + "Run an automated test case on a remote Android or iOS device via Firebase App Distribution.", inputSchema: z.object({ appId: ApplicationIdSchema, releaseBinaryFile: z.string().describe("Path to the binary release (APK)."), @@ -83,6 +85,8 @@ export const check_status = tool( name: "check_status", description: "Check the status of an apptesting release test and/or get available devices that can be used for automated tests ", + humanReadableDescription: + "Check the status of an automated release test or list available test devices.", inputSchema: z.object({ release_test_name: z .string() diff --git a/src/mcp/tools/auth/get_users.ts b/src/mcp/tools/auth/get_users.ts index a6621d97a90..c69ea7c27c7 100644 --- a/src/mcp/tools/auth/get_users.ts +++ b/src/mcp/tools/auth/get_users.ts @@ -9,6 +9,8 @@ export const get_users = tool( name: "get_users", description: "Use this to retrieve one or more Firebase Auth users based on a list of UIDs or a list of emails.", + humanReadableDescription: + "Retrieve Firebase Auth users by UID, email, phone number, or list all users.", inputSchema: z.object({ uids: z.array(z.string()).optional().describe("A list of user UIDs to retrieve."), emails: z.array(z.string()).optional().describe("A list of user emails to retrieve."), diff --git a/src/mcp/tools/auth/set_sms_region_policy.ts b/src/mcp/tools/auth/set_sms_region_policy.ts index f7dad87dbe7..6f51f7cfb87 100644 --- a/src/mcp/tools/auth/set_sms_region_policy.ts +++ b/src/mcp/tools/auth/set_sms_region_policy.ts @@ -9,6 +9,8 @@ export const set_sms_region_policy = tool( name: "set_sms_region_policy", description: "Use this to set an SMS region policy for Firebase Authentication to restrict the regions which can receive text messages based on an ALLOW or DENY list of country codes. This policy will override any existing policies when set.", + humanReadableDescription: + "Set an SMS region policy allowing or denying specific country codes for Firebase Authentication.", inputSchema: z.object({ policy_type: z .enum(["ALLOW", "DENY"]) diff --git a/src/mcp/tools/auth/update_user.ts b/src/mcp/tools/auth/update_user.ts index af5be9f3596..a93bed6affb 100644 --- a/src/mcp/tools/auth/update_user.ts +++ b/src/mcp/tools/auth/update_user.ts @@ -8,6 +8,8 @@ export const update_user = tool( { name: "update_user", description: "Use this to disable, enable, or set a custom claim on a specific user's account.", + humanReadableDescription: + "Update a user's account by enabling/disabling it or setting custom claims.", inputSchema: z.object({ uid: z.string().describe("the UID of the user to update"), disabled: z.boolean().optional().describe("true disables the user, false enables the user"), diff --git a/src/mcp/tools/core/create_android_sha.ts b/src/mcp/tools/core/create_android_sha.ts index 2701d562f97..921d9ecbf05 100644 --- a/src/mcp/tools/core/create_android_sha.ts +++ b/src/mcp/tools/core/create_android_sha.ts @@ -20,6 +20,8 @@ export const create_android_sha = tool( name: "create_android_sha", description: "Use this to add the specified SHA certificate hash to the specified Firebase Android App.", + humanReadableDescription: + "Add a SHA-1 or SHA-256 certificate hash to an Android app in the active Firebase project.", inputSchema: z.object({ app_id: z.string().describe("The Android app ID to add the SHA certificate to."), sha_hash: z.string().describe("The SHA certificate hash to add (SHA-1 or SHA-256)."), diff --git a/src/mcp/tools/core/create_app.ts b/src/mcp/tools/core/create_app.ts index 2bc800c80f8..aa39660613f 100644 --- a/src/mcp/tools/core/create_app.ts +++ b/src/mcp/tools/core/create_app.ts @@ -13,6 +13,8 @@ export const create_app = tool( name: "create_app", description: "Use this to create a new Firebase App in the currently active Firebase Project. Firebase Apps can be iOS, Android, or Web.", + humanReadableDescription: + "Create a new iOS, Android, or Web app in the active Firebase project.", inputSchema: z.object({ display_name: z .string() diff --git a/src/mcp/tools/core/create_project.ts b/src/mcp/tools/core/create_project.ts index ccd7ec09642..1cf1a400b27 100644 --- a/src/mcp/tools/core/create_project.ts +++ b/src/mcp/tools/core/create_project.ts @@ -29,6 +29,8 @@ export const create_project = tool( { name: "create_project", description: "Use this to create a new Firebase Project.", + humanReadableDescription: + "Create a new Firebase project or enable Firebase services on an existing Google Cloud project.", inputSchema: z.object({ project_id: z.string().describe("The project ID to create or use."), display_name: z diff --git a/src/mcp/tools/core/deploy.ts b/src/mcp/tools/core/deploy.ts index c29444d33ca..a075e16187c 100644 --- a/src/mcp/tools/core/deploy.ts +++ b/src/mcp/tools/core/deploy.ts @@ -23,6 +23,8 @@ export const deploy = tool( name: "deploy", description: "Deploy resources to your Firebase project, based on the contents of firebase.json.", + humanReadableDescription: + "Deploy Firebase services and resources configured in firebase.json to your project.", inputSchema: z.object({ only: z .string() diff --git a/src/mcp/tools/core/deploy_status.ts b/src/mcp/tools/core/deploy_status.ts index b102bbd6a9a..52f374f8800 100644 --- a/src/mcp/tools/core/deploy_status.ts +++ b/src/mcp/tools/core/deploy_status.ts @@ -8,6 +8,7 @@ export const deploy_status = tool( { name: "deploy_status", description: "Check the status of a background deployment job using its Job ID.", + humanReadableDescription: "Check the status and progress of a background deployment job.", inputSchema: z.object({ jobId: z.string().describe("The Job ID returned by the deploy tool"), }), diff --git a/src/mcp/tools/core/get_environment.ts b/src/mcp/tools/core/get_environment.ts index 229b990668e..3b5260c3b90 100644 --- a/src/mcp/tools/core/get_environment.ts +++ b/src/mcp/tools/core/get_environment.ts @@ -101,6 +101,8 @@ export const get_environment = tool( name: "get_environment", description: "Use this to retrieve the current Firebase **environment** configuration for the Firebase CLI and Firebase MCP server, including current authenticated user, project directory, active Firebase Project, and more. All tools require the user to be authenticated, but not all information is required for all tools. Pay attention to the tool requirements for which pieces of information are required.", + humanReadableDescription: + "Retrieve the current Firebase CLI and MCP environment configuration, active project, and authenticated user.", inputSchema: z.object({}), annotations: { title: "Get Firebase Environment Info", diff --git a/src/mcp/tools/core/get_project.ts b/src/mcp/tools/core/get_project.ts index c04a5a1af92..516f0a43e4c 100644 --- a/src/mcp/tools/core/get_project.ts +++ b/src/mcp/tools/core/get_project.ts @@ -8,6 +8,8 @@ export const get_project = tool( { name: "get_project", description: "Use this to retrieve information about the currently active Firebase Project.", + humanReadableDescription: + "Retrieve metadata and configuration details for the currently active Firebase project.", inputSchema: z.object({}), annotations: { title: "Get Current Firebase Project", diff --git a/src/mcp/tools/core/get_sdk_config.ts b/src/mcp/tools/core/get_sdk_config.ts index f4e09d14603..44d213fffad 100644 --- a/src/mcp/tools/core/get_sdk_config.ts +++ b/src/mcp/tools/core/get_sdk_config.ts @@ -10,6 +10,8 @@ export const get_sdk_config = tool( description: "Use this to retrieve the Firebase configuration information for a Firebase App. " + "You must specify EITHER a platform OR the Firebase App ID for a Firebase App registered in the currently active Firebase Project.", + humanReadableDescription: + "Retrieve SDK configuration details or config file contents for a registered Firebase app.", inputSchema: z.object({ platform: z .enum(["ios", "android", "web"]) diff --git a/src/mcp/tools/core/get_security_rules.ts b/src/mcp/tools/core/get_security_rules.ts index 2a5272fe6c0..71464bcbd74 100644 --- a/src/mcp/tools/core/get_security_rules.ts +++ b/src/mcp/tools/core/get_security_rules.ts @@ -13,6 +13,8 @@ export const get_security_rules = tool( description: "Use this to retrieve the security rules for a specified Firebase service. " + "If there are multiple instances of that service in the product, the rules for the default instance are returned.", + humanReadableDescription: + "Retrieve the active security rules for Firestore, Storage, or Realtime Database.", inputSchema: z.object({ type: z.enum(["firestore", "rtdb", "storage"]).describe("The service to get rules for."), // TODO: Add a resourceID argument that lets you choose non default buckets/dbs. diff --git a/src/mcp/tools/core/init.ts b/src/mcp/tools/core/init.ts index f6d528fd7de..c471b6f3ddb 100644 --- a/src/mcp/tools/core/init.ts +++ b/src/mcp/tools/core/init.ts @@ -21,6 +21,8 @@ export const init = tool( "Use this to initialize selected Firebase services in the workspace (Cloud Firestore database, Firebase SQL Connect, Firebase Realtime Database, Firebase AI Logic). All services are optional; specify only the products you want to set up. " + "You can initialize new features into an existing project directory, but re-initializing an existing feature may overwrite configuration. " + "To deploy the initialized features, run the `firebase deploy` command after `firebase_init` tool.", + humanReadableDescription: + "Initialize and configure Firebase services in your local project workspace.", inputSchema: z.object({ features: z.object({ database: z diff --git a/src/mcp/tools/core/list_apps.ts b/src/mcp/tools/core/list_apps.ts index a21b79fab21..406d7af133b 100644 --- a/src/mcp/tools/core/list_apps.ts +++ b/src/mcp/tools/core/list_apps.ts @@ -9,6 +9,7 @@ export const list_apps = tool( name: "list_apps", description: "Use this to retrieve a list of the Firebase Apps registered in the currently active Firebase project. Firebase Apps can be iOS, Android, or Web.", + humanReadableDescription: "List all Firebase apps registered in the active project.", inputSchema: z.object({ platform: z .enum(["ios", "android", "web", "all"]) diff --git a/src/mcp/tools/core/list_projects.ts b/src/mcp/tools/core/list_projects.ts index ad90085231a..4d1a6836fb3 100644 --- a/src/mcp/tools/core/list_projects.ts +++ b/src/mcp/tools/core/list_projects.ts @@ -11,6 +11,7 @@ export const list_projects = tool( name: "list_projects", description: "Use this to retrieve a list of Firebase Projects that the signed-in user has access to.", + humanReadableDescription: "List Firebase projects accessible by the authenticated user.", inputSchema: z.object({ page_size: z .number() diff --git a/src/mcp/tools/core/login.ts b/src/mcp/tools/core/login.ts index 5f267ef5c58..1a52b6b4dc4 100644 --- a/src/mcp/tools/core/login.ts +++ b/src/mcp/tools/core/login.ts @@ -61,6 +61,8 @@ export const login = tool( } \`\`\` `, + humanReadableDescription: + "Sign the user into the Firebase CLI and MCP server or check current authentication status.", inputSchema: LoginInputSchema, _meta: { requiresAuth: false, diff --git a/src/mcp/tools/core/logout.ts b/src/mcp/tools/core/logout.ts index 4220440aca0..0e818a9c002 100644 --- a/src/mcp/tools/core/logout.ts +++ b/src/mcp/tools/core/logout.ts @@ -15,6 +15,7 @@ export const logout = tool( { name: "logout", description: "Use this to sign the user out of the Firebase CLI and Firebase MCP server.", + humanReadableDescription: "Sign the user out of the Firebase CLI and MCP server.", inputSchema: z.object({ email: z .string() diff --git a/src/mcp/tools/core/read_resources.ts b/src/mcp/tools/core/read_resources.ts index 2ff6125af06..6a8178032d3 100644 --- a/src/mcp/tools/core/read_resources.ts +++ b/src/mcp/tools/core/read_resources.ts @@ -10,6 +10,8 @@ export const read_resources = tool( name: "read_resources", description: "Use this to read the contents of `firebase://` resources or list available resources", + humanReadableDescription: + "Read the contents of internal firebase:// documentation resources or list all available resources.", annotations: { title: "Read Firebase Resources", destructiveHint: false, diff --git a/src/mcp/tools/core/update_environment.ts b/src/mcp/tools/core/update_environment.ts index d78283e6c06..3f8f51dbc30 100644 --- a/src/mcp/tools/core/update_environment.ts +++ b/src/mcp/tools/core/update_environment.ts @@ -11,6 +11,8 @@ export const update_environment = tool( name: "update_environment", description: "Use this to update environment config for the Firebase CLI and Firebase MCP server, such as project directory, active project, active user account, accept terms of service, and more. Use `firebase_get_environment` to see the currently configured environment.", + humanReadableDescription: + "Update environment settings such as project directory, active project, or active user account.", inputSchema: z.object({ project_dir: z .string() diff --git a/src/mcp/tools/core/validate_security_rules.ts b/src/mcp/tools/core/validate_security_rules.ts index c75ebd5a852..dfbbed707f2 100644 --- a/src/mcp/tools/core/validate_security_rules.ts +++ b/src/mcp/tools/core/validate_security_rules.ts @@ -71,6 +71,8 @@ export const validate_security_rules = tool( name: "validate_security_rules", description: "Use this to check Firebase Security Rules for Firestore, Storage, or Realtime Database for syntax and validation errors.", + humanReadableDescription: + "Validate syntax and check for errors in Firestore, Storage, or Realtime Database security rules.", inputSchema: z.object({ type: z.enum(["firestore", "storage", "rtdb"]), source: z diff --git a/src/mcp/tools/crashlytics/events.ts b/src/mcp/tools/crashlytics/events.ts index 51523565b14..8d885dc21eb 100644 --- a/src/mcp/tools/crashlytics/events.ts +++ b/src/mcp/tools/crashlytics/events.ts @@ -125,6 +125,8 @@ export const list_events = tool( description: `Use this to list the most recent events matching the given filters. Can be used to fetch sample crashes and exceptions for an issue, which will include stack traces and other data useful for debugging.`, + humanReadableDescription: + "List recent crash and exception events matching specified filters for an issue.", inputSchema: z.object({ appId: ApplicationIdSchema, filter: EventFilterSchema, @@ -172,6 +174,8 @@ export const batch_get_events = tool( description: `Gets specific events by resource name. Can be used to fetch sample crashes and exceptions for an issue, which will include stack traces and other data useful for debugging.`, + humanReadableDescription: + "Retrieve sample crash and exception events by resource name for debugging.", inputSchema: z.object({ appId: ApplicationIdSchema, names: z diff --git a/src/mcp/tools/crashlytics/issues.ts b/src/mcp/tools/crashlytics/issues.ts index 0656777b746..aa190bbda06 100644 --- a/src/mcp/tools/crashlytics/issues.ts +++ b/src/mcp/tools/crashlytics/issues.ts @@ -13,6 +13,7 @@ export const get_issue = tool( { name: "get_issue", description: `Gets data for a Crashlytics issue, which can be used as a starting point for debugging.`, + humanReadableDescription: "Retrieve details and metadata for a specific Crashlytics issue.", inputSchema: z.object({ appId: ApplicationIdSchema, issueId: IssueIdSchema, @@ -50,6 +51,7 @@ export const update_issue = tool( { name: "update_issue", description: "Use this to update the state of Crashlytics issue.", + humanReadableDescription: "Update the state (OPEN or CLOSED) of a Crashlytics issue.", inputSchema: z.object({ appId: ApplicationIdSchema, issueId: IssueIdSchema, diff --git a/src/mcp/tools/crashlytics/notes.ts b/src/mcp/tools/crashlytics/notes.ts index dc483fed4d4..795ee744804 100644 --- a/src/mcp/tools/crashlytics/notes.ts +++ b/src/mcp/tools/crashlytics/notes.ts @@ -10,6 +10,7 @@ export const create_note = tool( name: "create_note", description: "Add a note to an issue from crashlytics. Only supported for mobile (Android and iOS) apps.", + humanReadableDescription: "Add a note to a Crashlytics issue for an Android or iOS app.", inputSchema: z.object({ appId: ApplicationIdSchema, issueId: IssueIdSchema, @@ -38,6 +39,8 @@ export const list_notes = tool( name: "list_notes", description: "Use this to list all notes for an issue in Crashlytics. Only supported for mobile (Android and iOS) apps.", + humanReadableDescription: + "List all notes attached to a Crashlytics issue for an Android or iOS app.", inputSchema: z.object({ appId: ApplicationIdSchema, issueId: IssueIdSchema, @@ -65,6 +68,7 @@ export const delete_note = tool( name: "delete_note", description: "Delete a note from a Crashlytics issue. Only supported for mobile (Android and iOS) apps.", + humanReadableDescription: "Delete a note from a Crashlytics issue for an Android or iOS app.", inputSchema: z.object({ appId: ApplicationIdSchema, issueId: IssueIdSchema, diff --git a/src/mcp/tools/crashlytics/reports.ts b/src/mcp/tools/crashlytics/reports.ts index 57c73dd18c7..6088f5d365b 100644 --- a/src/mcp/tools/crashlytics/reports.ts +++ b/src/mcp/tools/crashlytics/reports.ts @@ -44,6 +44,8 @@ export const get_report = tool( description: `Use this to request numerical reports from Crashlytics. The result aggregates the sum of events and impacted users, grouped by a dimension appropriate for that report. Agents must read the [Firebase Crashlytics Reports Guide](firebase://guides/crashlytics/reports) using the \`firebase_read_resources\` tool before calling to understand critical prerequisites for requesting reports and how to interpret the results. `.trim(), + humanReadableDescription: + "Generate aggregated numerical reports for Crashlytics issues and events.", inputSchema: ReportInputSchema, annotations: { title: "Get Crashlytics Report", diff --git a/src/mcp/tools/dataconnect/compile.ts b/src/mcp/tools/dataconnect/compile.ts index 06dbd5ed100..5f2bccde0c7 100644 --- a/src/mcp/tools/dataconnect/compile.ts +++ b/src/mcp/tools/dataconnect/compile.ts @@ -29,6 +29,8 @@ Resolves service directories defined in the project's \`firebase.json\` under \` "error_filter": "schema" } \`\`\``, + humanReadableDescription: + "Compile Firebase SQL Connect schemas, operations, and connectors to validate syntax and types.", inputSchema: z.object({ error_filter: z .enum(["all", "schema", "operations"]) diff --git a/src/mcp/tools/dataconnect/execute.ts b/src/mcp/tools/dataconnect/execute.ts index ed00bb8da4d..62a8f2fc1c7 100644 --- a/src/mcp/tools/dataconnect/execute.ts +++ b/src/mcp/tools/dataconnect/execute.ts @@ -13,6 +13,8 @@ export const execute = tool( name: "execute", description: "Use this to execute a GraphQL operation against a SQL Connect service or its emulator.", + humanReadableDescription: + "Execute a GraphQL query or mutation against a Firebase SQL Connect service or emulator.", inputSchema: z.object({ query: z.string().describe(`A Firebase SQL Connect GraphQL query or mutation to execute. You can use the \`dataconnect_generate_operation\` tool to generate a query. diff --git a/src/mcp/tools/dataconnect/list_services.ts b/src/mcp/tools/dataconnect/list_services.ts index 4d8e8e7179a..a443f9686bc 100644 --- a/src/mcp/tools/dataconnect/list_services.ts +++ b/src/mcp/tools/dataconnect/list_services.ts @@ -29,6 +29,8 @@ export const list_services = tool( { name: "list_services", description: "Use this to list existing local and backend Firebase SQL Connect services", + humanReadableDescription: + "List local and deployed Firebase SQL Connect services, schemas, and connectors.", inputSchema: z.object({}), annotations: { title: "List existing Firebase SQL Connect services", diff --git a/src/mcp/tools/firestore/query_collection.ts b/src/mcp/tools/firestore/query_collection.ts index 29402553acb..6df9bac7630 100644 --- a/src/mcp/tools/firestore/query_collection.ts +++ b/src/mcp/tools/firestore/query_collection.ts @@ -11,6 +11,8 @@ export const query_collection = tool( name: "query_collection", description: "Use this to retrieve one or more Firestore documents from a collection in a database in the current project by a collection with a full document path. Use this if you know the exact path of a collection and the filtering clause you would like for the document.", + humanReadableDescription: + "Query Firestore documents from a collection with optional filters and ordering.", inputSchema: z.object({ database: z .string() diff --git a/src/mcp/tools/functions/get_logs.ts b/src/mcp/tools/functions/get_logs.ts index 01afedb1435..7642c83d830 100644 --- a/src/mcp/tools/functions/get_logs.ts +++ b/src/mcp/tools/functions/get_logs.ts @@ -47,6 +47,8 @@ export const get_logs = tool( name: "get_logs", description: "Use this to retrieve a page of Cloud Functions log entries using Google Cloud Logging advanced filters.", + humanReadableDescription: + "Retrieve and filter Cloud Functions log entries from Google Cloud Logging.", inputSchema: z.object({ function_names: z .array(z.string()) diff --git a/src/mcp/tools/functions/list_functions.ts b/src/mcp/tools/functions/list_functions.ts index 44553631030..c909fa7568a 100644 --- a/src/mcp/tools/functions/list_functions.ts +++ b/src/mcp/tools/functions/list_functions.ts @@ -11,6 +11,7 @@ export const list_functions = tool( { name: "list_functions", description: "List all deployed functions in your Firebase project.", + humanReadableDescription: "List all deployed Cloud Functions in your Firebase project.", inputSchema: z.object({}), annotations: { title: "List Deployed Functions", diff --git a/src/mcp/tools/index.spec.ts b/src/mcp/tools/index.spec.ts index 075765f7723..32da1c865bd 100644 --- a/src/mcp/tools/index.spec.ts +++ b/src/mcp/tools/index.spec.ts @@ -1,7 +1,7 @@ import { expect } from "chai"; import * as sinon from "sinon"; import { McpContext } from "../types"; -import { availableTools, getRemoteToolsByFeature } from "./index"; +import { availableTools, getRemoteToolsByFeature, markdownDocsOfTools } from "./index"; import { ONEMCP_SERVERS } from "../onemcp/index"; import { OneMcpServer } from "../onemcp/onemcp_server"; @@ -141,3 +141,51 @@ describe("getRemoteToolsByFeature", () => { } }); }); + +describe("markdownDocsOfTools", () => { + let sandbox: sinon.SinonSandbox; + + beforeEach(() => { + sandbox = sinon.createSandbox(); + }); + + afterEach(() => { + sandbox.restore(); + }); + + it("should generate a markdown table containing all tools with humanReadableDescription", async () => { + sandbox.stub(OneMcpServer.prototype, "listTools").resolves([]); + + const doc = await markdownDocsOfTools(); + + expect(doc).to.include("| Tool Name | Feature Group | Description |"); + expect(doc).to.include("| --------- | ------------- | ----------- |"); + // Verify core tools use their humanReadableDescription + expect(doc).to.include( + "| firebase_login | core | Sign the user into the Firebase CLI and MCP server or check current authentication status. |", + ); + expect(doc).to.include( + "| firebase_logout | core | Sign the user out of the Firebase CLI and MCP server. |", + ); + expect(doc).to.include( + "| auth_get_users | auth | Retrieve Firebase Auth users by UID, email, phone number, or list all users. |", + ); + }); + + it("should fallback to description if humanReadableDescription is not provided", async () => { + const mockRemoteTool = { + mcp: { + name: "remote_tool_without_hrd", + description: "AI description only", + }, + }; + sandbox + .stub(OneMcpServer.prototype, "listTools") + .resolves([mockRemoteTool as unknown as import("../tool").ServerTool]); + + const doc = await markdownDocsOfTools(); + + expect(doc).to.include("remote_tool_without_hrd"); + expect(doc).to.include("AI description only"); + }); +}); diff --git a/src/mcp/tools/index.ts b/src/mcp/tools/index.ts index 68e839659b2..3613c0b3471 100644 --- a/src/mcp/tools/index.ts +++ b/src/mcp/tools/index.ts @@ -143,7 +143,11 @@ export async function markdownDocsOfTools(): Promise { if (feature === "firebase") { feature = "core"; } - const description = (tool.mcp?.description || "").replaceAll("\n", "
"); + const description = ( + tool.mcp?.humanReadableDescription || + tool.mcp?.description || + "" + ).replaceAll("\n", "
"); doc += ` | ${tool.mcp.name} | ${feature} | ${description} |`; } diff --git a/src/mcp/tools/messaging/send_message.ts b/src/mcp/tools/messaging/send_message.ts index 2af499aabd1..c1e71d7c460 100644 --- a/src/mcp/tools/messaging/send_message.ts +++ b/src/mcp/tools/messaging/send_message.ts @@ -9,6 +9,8 @@ export const send_message = tool( name: "send_message", description: "Use this to send a message to a Firebase Cloud Messaging registration token or topic. ONLY ONE of `registration_token` or `topic` may be supplied in a specific call.", + humanReadableDescription: + "Send a Firebase Cloud Messaging push notification to a device registration token or topic.", inputSchema: z.object({ registration_token: z .string() diff --git a/src/mcp/tools/realtime_database/get_data.ts b/src/mcp/tools/realtime_database/get_data.ts index ec5b9331069..25e6c16bea6 100644 --- a/src/mcp/tools/realtime_database/get_data.ts +++ b/src/mcp/tools/realtime_database/get_data.ts @@ -12,6 +12,7 @@ export const get_data = tool( name: "get_data", description: "Use this to retrieve data from the specified location in a Firebase Realtime Database.", + humanReadableDescription: "Read data from a specified path in the Firebase Realtime Database.", inputSchema: z.object({ databaseUrl: z .string() diff --git a/src/mcp/tools/realtime_database/set_data.ts b/src/mcp/tools/realtime_database/set_data.ts index 09aaf4a0c92..e1dc4689c35 100644 --- a/src/mcp/tools/realtime_database/set_data.ts +++ b/src/mcp/tools/realtime_database/set_data.ts @@ -13,6 +13,8 @@ export const set_data = tool( name: "set_data", description: "Use this to write data to the specified location in a Firebase Realtime Database.", + humanReadableDescription: + "Write JSON data to a specified path in the Firebase Realtime Database.", inputSchema: z.object({ databaseUrl: z .string() diff --git a/src/mcp/tools/remoteconfig/get_template.ts b/src/mcp/tools/remoteconfig/get_template.ts index 36b221c640c..e921ecf912f 100644 --- a/src/mcp/tools/remoteconfig/get_template.ts +++ b/src/mcp/tools/remoteconfig/get_template.ts @@ -9,6 +9,8 @@ export const get_template = tool( name: "get_template", description: "Use this to retrieve the specified Firebase Remote Config template from the currently active Firebase Project.", + humanReadableDescription: + "Retrieve the active or specified version of the Firebase Remote Config template.", inputSchema: z.object({ version_number: z .string() diff --git a/src/mcp/tools/remoteconfig/update_template.ts b/src/mcp/tools/remoteconfig/update_template.ts index 2b69300eb6b..af224d94647 100644 --- a/src/mcp/tools/remoteconfig/update_template.ts +++ b/src/mcp/tools/remoteconfig/update_template.ts @@ -11,6 +11,8 @@ export const update_template = tool( name: "update_template", description: "Use this to publish a new remote config template or roll back to a specific version for the project", + humanReadableDescription: + "Publish a new Firebase Remote Config template or rollback to a previous version.", inputSchema: z .object({ template: z.object({}).optional().describe("The Remote Config template object to publish."), diff --git a/src/mcp/tools/storage/get_download_url.ts b/src/mcp/tools/storage/get_download_url.ts index 9c84682da9a..30d9c4f4615 100644 --- a/src/mcp/tools/storage/get_download_url.ts +++ b/src/mcp/tools/storage/get_download_url.ts @@ -10,6 +10,7 @@ export const get_object_download_url = tool( name: "get_object_download_url", description: "Use this to retrieve the download URL for an object in a Cloud Storage for Firebase bucket.", + humanReadableDescription: "Retrieve the download URL for an object in a Cloud Storage bucket.", inputSchema: z.object({ bucket: z .string() From 13713ed77c0255480a6af5819e69937ba2464453 Mon Sep 17 00:00:00 2001 From: Joe Hanley Date: Tue, 1 Sep 2026 10:54:32 -0700 Subject: [PATCH 2/2] Update src/mcp/tools/index.ts Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/mcp/tools/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mcp/tools/index.ts b/src/mcp/tools/index.ts index 3613c0b3471..c2fdb7d2c39 100644 --- a/src/mcp/tools/index.ts +++ b/src/mcp/tools/index.ts @@ -144,8 +144,8 @@ export async function markdownDocsOfTools(): Promise { feature = "core"; } const description = ( - tool.mcp?.humanReadableDescription || - tool.mcp?.description || + tool.mcp.humanReadableDescription || + tool.mcp.description || "" ).replaceAll("\n", "
"); doc += `