Skip to content

fix(mcp): defer project detection from constructor to start() - #11302

Open
ajperel wants to merge 1 commit into
mainfrom
ajp/fix_mcp_server_flaky_test
Open

ajperel wants to merge 1 commit into
mainfrom
ajp/fix_mcp_server_flaky_test

Conversation

@ajperel

@ajperel ajperel commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

Description

FirebaseMcpServer previously ran void this.detectProjectSetup() in its constructor. In unit tests that instantiate FirebaseMcpServer without calling start(), the 2-second fallback timers all fired mid-suite and ran repo-wide glob scans against process.cwd(), blocking the event loop and causing flaky timeouts in downstream suites such as throttler.spec.ts.

This moves detectProjectSetup() from the constructor to start() so constructing a server in tests starts no background timers or filesystem scans. Availability specs also reuse a single server instance per suite.

Scenarios Tested

  • Added unit tests verifying new FirebaseMcpServer({}) does not run project or feature detection until start() is called.
  • Ran the 23-server reproduction spec and the full Mocha suite under --trace-gc, confirming 0 allocation storms and all unit tests passing.

Sample Commands

firebase mcp

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request modifies the Firebase MCP server to asynchronously detect and cache the availability of the local firebase CLI, resolving an issue where it always suggested the npx fallback. It also defers project setup detection from the constructor to the start method and adds corresponding unit tests. Feedback on these changes suggests adding a timeout to the spawned CLI version check to prevent potential hangs, extracting magic strings and numbers into static constants as per the style guide, and catching errors on the unawaited detectProjectSetup call to avoid unhandled promise rejections.

Comment thread src/mcp/index.ts Outdated
Comment thread src/mcp/index.ts Outdated
Comment thread src/mcp/index.ts
}

async start(options?: { useSSE?: boolean; port?: number }): Promise<void> {
void this.detectProjectSetup();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Calling void this.detectProjectSetup() without awaiting or catching errors can lead to unhandled promise rejections if any of the underlying async operations (such as file system access or API calls) fail. This can crash the Node.js process or lead to silent failures. Let's catch and log any errors using this.logger.error.

    void this.detectProjectSetup().catch((err) => {
      this.logger.error(`Failed to detect project setup: ${err instanceof Error ? err.message : String(err)}`);
    });

@ajperel ajperel Oct 17, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pre-existing behavior unrelated to my test fix. Though maybe worth someone who works on MCP addressing.

### Description

`FirebaseMcpServer` previously ran `void this.detectProjectSetup()` in its constructor. In unit tests that instantiate `FirebaseMcpServer` without calling `start()`, the 2-second fallback timers all fired mid-suite and ran repo-wide `glob` scans against `process.cwd()`, blocking the event loop and causing flaky timeouts in downstream suites such as `throttler.spec.ts`.

This moves `detectProjectSetup()` from the constructor to `start()` so constructing a server in tests starts no background timers or filesystem scans. Availability specs also reuse a single server instance per suite.

### Scenarios Tested

- Added unit tests verifying `new FirebaseMcpServer({})` does not run project or feature detection until `start()` is called.
- Ran the 23-server reproduction spec and the full Mocha suite under `--trace-gc`, confirming 0 allocation storms and all unit tests passing.

### Sample Commands

```bash
firebase mcp
```
@ajperel
ajperel force-pushed the ajp/fix_mcp_server_flaky_test branch from 359743b to 332c571 Compare October 17, 2026 05:00
@ajperel ajperel changed the title fix(mcp): defer project detection to start() and fix CLI command check fix(mcp): defer project detection from constructor to start() Oct 17, 2026
@ajperel
ajperel requested a review from joehan October 17, 2026 05:01
Comment thread src/mcp/index.ts

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const testCommand = crossSpawn.sync("firebase --version");

Note on line 333: crossSpawn.sync("firebase --version") passes --version inside the executable name instead of the args array, so it always fails with ENOENT and falls back to npx firebase-tools@latest. We left this out of this PR to keep it focused on the flaky test fix. (When fixed separately, it should also run asynchronously and be cached once per process so it does not add a synchronous CLI startup.)

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant