Skip to main content
Glama

MCP Browser Screenshot Server

BrowserInstance.jsโ€ข5.74 kB
/* * Copyright 2023 Google LLC. * Copyright (c) Microsoft Corporation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ import { mkdtemp } from 'fs/promises'; import os from 'os'; import path from 'path'; import { CDP_WEBSOCKET_ENDPOINT_REGEX, launch, } from '@puppeteer/browsers'; import debug from 'debug'; import WebSocket from 'ws'; import { MapperCdpConnection } from '../cdp/CdpConnection.js'; import { WebSocketTransport } from '../utils/WebsocketTransport.js'; import { MapperServerCdpConnection } from './MapperCdpConnection.js'; import { PipeTransport } from './PipeTransport.js'; import { getMapperTabSource } from './reader.js'; const debugInternal = debug('bidi:mapper:internal'); /** * BrowserProcess is responsible for running the browser and BiDi Mapper within * it. * 1. Launch Chromium (using Puppeteer for now). * 2. Get `BiDi-CDP` mapper JS binaries using `MapperReader`. * 3. Run `BiDi-CDP` mapper in launched browser using `MapperRunner`. * 4. Bind `BiDi-CDP` mapper to the `BiDi server` to forward messages from BiDi * Mapper to the client. */ export class BrowserInstance { #mapperCdpConnection; #browserProcess; static async run(chromeOptions, verbose) { const profileDir = await mkdtemp(path.join(os.tmpdir(), 'web-driver-bidi-server-')); // See https://github.com/GoogleChrome/chrome-launcher/blob/main/docs/chrome-flags-for-tools.md const chromeArguments = [ // keep-sorted start '--allow-browser-signin=false', '--disable-component-update', '--disable-default-apps', // For HttpsFirstBalancedModeAutoEnable, crbug.com/378022921. '--disable-features=DialMediaRouteProvider,TrackingProtection3pcd,HttpsFirstBalancedModeAutoEnable', '--disable-infobars', '--disable-notifications', '--disable-popup-blocking', '--disable-search-engine-choice-screen', '--enable-automation', '--no-default-browser-check', '--no-first-run', '--password-store=basic', '--use-mock-keychain', `--user-data-dir=${profileDir}`, // keep-sorted end ...(chromeOptions.chromeArgs.includes('--remote-debugging-pipe') ? [] : ['--remote-debugging-port=9222']), ...chromeOptions.chromeArgs, 'about:blank', ]; const executablePath = chromeOptions.chromeBinary ?? process.env['BROWSER_BIN']; if (!executablePath) { throw new Error('Could not find Chrome binary'); } const pipe = chromeArguments.includes('--remote-debugging-pipe'); const launchArguments = { executablePath, args: chromeArguments, env: process.env, pipe, }; debugInternal(`Launching browser`, { executablePath, args: chromeArguments, }); const browserProcess = launch(launchArguments); let cdpConnection; if (pipe) { cdpConnection = this.#establishPipeConnection(browserProcess); } else { const cdpEndpoint = await browserProcess.waitForLineOutput(CDP_WEBSOCKET_ENDPOINT_REGEX); // There is a conflict between prettier and eslint here. // prettier-ignore cdpConnection = await this.#establishCdpConnection(cdpEndpoint); } // 2. Get `BiDi-CDP` mapper JS binaries. const mapperTabSource = await getMapperTabSource(); // 3. Run `BiDi-CDP` mapper in launched browser using `MapperRunner`. const mapperCdpConnection = await MapperServerCdpConnection.create(cdpConnection, mapperTabSource, verbose); return new BrowserInstance(mapperCdpConnection, browserProcess); } constructor(mapperCdpConnection, browserProcess) { this.#mapperCdpConnection = mapperCdpConnection; this.#browserProcess = browserProcess; } async close() { // Close the mapper tab. this.#mapperCdpConnection.close(); // Close browser. await this.#browserProcess.close(); } bidiSession() { return this.#mapperCdpConnection.bidiSession(); } static #establishCdpConnection(cdpUrl) { return new Promise((resolve, reject) => { debugInternal('Establishing session with cdpUrl: ', cdpUrl); const ws = new WebSocket(cdpUrl); ws.once('error', reject); ws.on('open', () => { debugInternal('Session established.'); const transport = new WebSocketTransport(ws); const connection = new MapperCdpConnection(transport); resolve(connection); }); }); } static #establishPipeConnection(browserProcess) { debugInternal('Establishing pipe connection to browser process with pid: ', browserProcess.nodeProcess.pid); const { 3: pipeWrite, 4: pipeRead } = browserProcess.nodeProcess.stdio; const transport = new PipeTransport(pipeWrite, pipeRead); return new MapperCdpConnection(transport); } } //# sourceMappingURL=BrowserInstance.js.map

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/seabassgonzalez/mcp-browser-screenshot'

If you have feedback or need assistance with the MCP directory API, please join our Discord server