Skip to content

Programmatic Server API for in-process embedding #1038

@gsquared94

Description

@gsquared94

Is your feature request related to a problem? Please describe.

Feature Request: Programmatic Server API for in-process embedding

Context

Gemini CLI integrates chrome-devtools-mcp as a browser subagent. Currently we
spawn it via npx using StdioClientTransport, which works but has drawbacks:

  • Cold-start latency (npx download + process spawn)
  • stderr output leaking into the host CLI's terminal
  • A full process boundary for what could be in-process communication

We'd like to embed chrome-devtools-mcp in-process using the MCP SDK's
InMemoryTransport, but the current architecture makes this impossible.

What blocks in-process use today

  1. No programmatic APImain.js creates the McpServer, registers tools,
    and connects StdioServerTransport all at the top level. There's no exported
    function to create a configured server instance.

  2. CLI-coupled configuration — All options (headless, sessionMode,
    userDataDir, experimentalVision, etc.) are parsed from process.argv via
    yargs in cli.js. There's no way to pass options programmatically.

  3. Hardcoded transportStdioServerTransport is instantiated and
    connected at the top of main.js with no way to substitute
    InMemoryTransport.

  4. Process-level side effectsmain.js registers
    process.on('unhandledRejection'), sets up Clearcut telemetry, and prints
    disclaimers to console.error. These would pollute a host process.

Describe the solution you'd like

What we need

A programmatic entry point, something like:

import { createServer } from "chrome-devtools-mcp";

const server = await createServer({
  headless: false,
  experimentalVision: true,
  userDataDir: "~/.gemini/cli-browser-profile",
  usageStatistics: false,
  // ... other options currently parsed from CLI args
});

// Connect with any MCP transport
const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
await server.connect(serverTransport);

const client = new Client({ name: "my-app" });
await client.connect(clientTransport);

Key requirements

  • Options passed as a typed object instead of process.argv
  • No process.on handlers or console.error side effects
  • Transport provided by the caller (not hardcoded to stdio)
  • Returns the McpServer instance for the caller to connect

This would also benefit other embedders (VS Code extensions, Electron apps,
etc.) that want to use chrome-devtools-mcp without spawning a child process.

Describe alternatives you've considered

  • npx at runtime (current) — We spawn npx -y chrome-devtools-mcp@0.17.1 via StdioClientTransport. This works but adds cold-start latency, requires network access, and leaks stderr output into the host terminal. We've mitigated the stderr issue by setting stderr: 'pipe' on the transport.

  • Side-car bundle — Bundle chrome-devtools-mcp as a separate JS file alongside our CLI bundle using esbuild, then spawn with node chrome-devtools-mcp.js instead of npx. This eliminates the network dependency but still requires a child process (~8-9 MB bundle increase). We plan to implement this as a near-term improvement.

Additional context

Drafted with Gemini

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions