# How DesktopCommanderMCP Ensures Chrome Availability for PDF Generation with ensureChromeAvailable

> Learn how DesktopCommanderMCP ensures Chrome availability for PDF generation. This function checks cached builds, scans installs, and downloads Chrome automatically if needed.

- Repository: [Eduard Ruzga/DesktopCommanderMCP](https://github.com/wonderwhy-er/DesktopCommanderMCP)
- Tags: how-to-guide
- Published: 2026-07-10

---

**The `ensureChromeAvailable` function proactively guarantees a Chrome executable is present for PDF rendering by searching cached Puppeteer builds, scanning system installations, and automatically downloading Chrome via `@puppeteer/browsers` if necessary, all while running asynchronously during server startup to prevent blocking.**

DesktopCommanderMCP generates PDF documents from Markdown using the `md-to-pdf` library, which requires a Chrome or Chromium binary to render HTML content. Because environments like CI pipelines or minimal containers often lack Chrome, the codebase implements a robust availability strategy centered on the `ensureChromeAvailable` helper exported from [`src/tools/pdf/markdown.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/tools/pdf/markdown.ts).

## The Three-Tier Chrome Resolution Strategy

When invoked, `ensureChromeAvailable` triggers a background resolution process that attempts three distinct strategies in sequence. The logic is coordinated by `getChromePath`, which orchestrates the lookup while protecting against race conditions.

### 1. Cached Puppeteer Build Detection

The resolution first attempts `findPuppeteerChrome`, which scans Puppeteer's private cache directory for platform-specific Chrome binaries. If a compatible build exists, the function calls `pruneOldPuppeteerChromeBuilds` to remove outdated versions and caches the executable path in the module-level `cachedChromePath` variable. This avoids redundant downloads when PDF generation runs multiple times.

### 2. System Chrome Fallback

If no cached build exists, the code executes `findSystemChrome` to search hard-coded common installation paths across Windows, macOS, and Linux. This includes standard locations like `/usr/bin/google-chrome` on Linux or `/Applications/Google Chrome.app/Contents/MacOS/Google Chrome` on macOS. When found, this system path is cached for subsequent calls.

### 3. Automatic Chrome Installation

As a last resort, the `installChrome` function uses `@puppeteer/browsers` to download the latest stable Chrome build for the detected platform. The download runs with progress output directed to `stderr`, and upon completion, the new binary path is cached and old builds are pruned to conserve disk space.

## Caching and Concurrency Protection

The `getChromePath` function implements memoization to ensure the expensive resolution process runs only once. It guards concurrent invocations using a `chromeCheckPromise` variable that acts as a lock—subsequent calls await the same promise rather than triggering duplicate searches or downloads. The function returns `Promise<string | undefined>`, resolving to the executable path or `undefined` if all strategies fail.

## Server Integration and Background Execution

The function is invoked during server startup in [`src/index.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/index.ts) within the LSP server's `oninitialized` callback. This placement ensures Chrome detection runs only after the server has fully initialized, allowing the client to connect while the download proceeds in the background.

```typescript
// src/index.ts (simplified)
server.oninitialized = () => {
  // Fire-and-forget: server continues serving requests while Chrome downloads
  ensureChromeAvailable();
};

```

Because the call is fire-and-forget, the server remains responsive to other tool requests even if Chrome installation takes several minutes on a slow connection.

## Runtime PDF Generation

When PDF generation actually occurs, `parseMarkdownToPdf` calls `getChromePath` to retrieve the resolved executable path and injects it into the `launch_options` passed to `md-to-pdf`. If the path remains `undefined`—meaning Chrome is absent and automatic installation failed—the function throws a descriptive error directing the user to manual installation steps.

```typescript
// src/tools/pdf/markdown.ts
const chromePath = await getChromePath();
if (!chromePath) {
  throw new Error('Chrome is not available. Please install Chrome manually.');
}
// Inject into md-to-pdf options
const options = {
  launch_options: {
    executablePath: chromePath
  }
};

```

## Practical Implementation Examples

### Triggering Chrome Availability Checks

You can manually trigger the background check to ensure Chrome is ready before performing batch operations:

```typescript
import { ensureChromeAvailable } from './src/tools/pdf/markdown.js';

// Starts background resolution; returns immediately
ensureChromeAvailable();

// Proceed with other initialization logic
console.log('Server starting while Chrome resolves in background...');

```

### Converting Markdown to PDF

The public API abstracts Chrome management entirely, though it relies on the earlier availability check:

```typescript
import { parseMarkdownToPdf } from './src/tools/pdf/markdown.js';

async function generateDocument() {
  const markdown = '# Report\nGenerated content here.';

  const pdfBuffer = await parseMarkdownToPdf(markdown, {
    pdf_options: { format: 'A4', printBackground: true }
  });
  
  // pdfBuffer is a Node.js Buffer ready for file system or HTTP response
  return pdfBuffer;
}

```

## Summary

- **`ensureChromeAvailable`** initiates a three-tier resolution strategy (cache → system → download) during server startup.
- **Concurrency protection** via `chromeCheckPromise` prevents duplicate downloads when multiple PDF requests arrive simultaneously.
- **Background execution** in [`src/index.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/index.ts) ensures the MCP server remains responsive while Chrome installs.
- **Runtime injection** in `parseMarkdownToPdf` supplies the resolved `executablePath` to `md-to-pdf`, with clear error messaging if resolution fails.
- **Automatic maintenance** through build pruning keeps the Puppeteer cache from consuming excessive disk space.

## Frequently Asked Questions

### What happens if Chrome cannot be found or installed automatically?

If `findPuppeteerChrome`, `findSystemChrome`, and `installChrome` all fail, `getChromePath` returns `undefined`. When `parseMarkdownToPdf` subsequently runs, it detects this condition and throws a helpful error message instructing the user to install Chrome manually, preventing cryptic failures from `md-to-pdf`.

### Can I force the use of a system-installed Chrome instead of downloading a new build?

Yes. The resolution order prioritizes existing resources: if `findSystemChrome` locates a valid Chrome installation in standard system paths (such as `/usr/bin/chromium-browser` on Linux or `C:\Program Files\Google\Chrome\Application\chrome.exe` on Windows), that path is cached and used immediately, bypassing the download logic entirely.

### Does the server block while Chrome downloads?

No. The invocation in [`src/index.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/index.ts) uses a fire-and-forget pattern inside the `oninitialized` callback. The Promise returned by `ensureChromeAvailable` is not awaited, allowing the LSP server to complete initialization and serve other tool requests while Chrome downloads and installs in the background.

### How does the caching mechanism handle concurrent PDF generation requests?

The `getChromePath` function uses a module-level `chromeCheckPromise` variable to guard against race conditions. If multiple calls occur while Chrome is still being located or downloaded, all callers receive the same Promise and resolve simultaneously once the executable path is determined, preventing duplicate installations.