# Chrome DevTools MCP Helper - Development Notes

## ✅ BROWSER SHARING - SIMPLIFIED (2026-01-05)

Browser sharing simplified by removing custom lock files. Now uses Chrome's built-in mechanisms.

### How It Works (Simplified)

**Detection Priority:**
1. `DevToolsActivePort` - Chrome writes port and wsPath here (most accurate)
2. `SingletonLock` + port check - Chrome's lock file contains PID (fallback for Helium)

**First Launch:**
- `isBrowserRunning()` returns `{ running: false }`
- Launches Chrome with `--remote-debugging-port=9222`
- Browser listens on port 9222 for remote connections

**Subsequent Launches:**
- `isBrowserRunning()` checks DevToolsActivePort OR (SingletonLock + port)
- Returns `{ running: true, port: 9222 }`
- Connects via `--browserUrl http://127.0.0.1:9222`

### Key Changes (Simplified from Lock Files)

**REMOVED:**
- Custom lock files in `~/.chrome-devtools-mcp/.locks/`
- `RunLockData` interface with PIDs and timestamps
- `updateLockWithProcessInfo()` function
- `getFullLockData()` and lock file management

**NOW USING Chrome's Own Files:**
- `DevToolsActivePort` - port + wsPath (Chrome writes this)
- `SingletonLock` - symlink to `hostname-PID` (Chrome writes this)

### Test Commands

```bash
# Clear state (remove userDataDir to start fresh)
/bin/rm -rf ~/.chrome-devtools-mcp/default

# First launch - launches new browser
bun src/cli.ts navigate --url https://example.com --mcpType stdio

# Second launch - reuses browser via browserUrl
bun src/cli.ts navigate --url https://google.com --mcpType stdio
```

**Expected Output:**
- First: `[MCP Client] No running browser → launching new with --remote-debugging-port=9222`
- Subsequent: `[MCP Client] Browser running on port 9222 → connecting via http://127.0.0.1:9222`

---

## Architecture

**counter-script.ts (AITool - for library use)**
- Default transport: http mode
- Can be used by HTTP server, other tools, or direct library calls
- User can override with mcpType parameter

**cli.ts (CLI - for command-line use)**
- Default transport: stdio mode
- Each CLI invocation spawns fresh stdio subprocess
- Browser reuse via Chrome's built-in detection

## Browser Detection (NO CUSTOM LOCK FILES)

**browserPoolManager.ts uses Chrome's own files:**

1. **DevToolsActivePort**: Contains port and wsPath (most accurate)
2. **SingletonLock**: Symlink to `hostname-PID` (fallback for Chrome variants)

**Key Functions:**
- `isBrowserRunning(userDataDir)` - Check if browser running, returns port if found
- `readDevToolsActivePort(userDataDir)` - Parse DevToolsActivePort file
- `readSingletonLock(userDataDir)` - Parse PID from SingletonLock symlink
- `killBrowser(userDataDir)` - Kill browser by port

## Key Implementation Details

### browserPoolManager.ts

```typescript
export function isBrowserRunning(userDataDir: string) {
  // Method 1: Check DevToolsActivePort file (most accurate)
  const activePort = readDevToolsActivePort(userDataDir);
  if (activePort && isPortInUse(activePort.port)) {
    return { running: true, port: activePort.port, wsPath: activePort.wsPath };
  }

  // Method 2: Check SingletonLock + default port (for Helium, etc.)
  // SingletonLock is userDataDir-specific, so we can trust it
  const singletonPid = readSingletonLock(userDataDir);
  if (singletonPid && isPortInUse(DEFAULT_DEBUG_PORT)) {
    return { running: true, port: DEFAULT_DEBUG_PORT };
  }

  return { running: false };
}
```

### counter-script.ts (createChromeDevToolsClient)

```typescript
const browserStatus = isBrowserRunning(userDataDir);

if (browserStatus.running && browserStatus.port) {
  // Connect to existing browser
  const browserUrl = `http://127.0.0.1:${browserStatus.port}`;
  return createStdioToHttpClient({ browserUrl });
}

// Launch new browser with debug port
return createStdioToHttpClient({ userDataDir, debugPort: DEFAULT_DEBUG_PORT });
```

## Do NOT Use

- `--remote-debugging-pipe` (exclusive 1-to-1 connection, can't share)
- `--isolated` flag (creates new windows, defeats pooling)
- `--autoConnect` (mutually exclusive with executablePath)
- Custom lock files (Chrome's built-in files are sufficient)
- Raw port check without userDataDir verification (could connect to wrong browser)

## Decision Log

### 2026-01-05: Removed Custom Lock Files

**Question:** "why use run.lock we could do reuse browser process?"

**Answer:** Custom lock files were over-engineering. Chrome already provides:
1. `DevToolsActivePort` - written with port when using --remote-debugging-port
2. `SingletonLock` - symlink containing PID, userDataDir-specific

**Why NOT just check port 9222?**
- Port check alone can't verify the userDataDir
- Could connect to wrong browser if multiple userDataDirs exist
- SingletonLock is specific to each userDataDir

**Simplification:**
- Removed ~250 lines of custom lock file code
- Use Chrome's built-in state files
- Simpler code = fewer bugs
