diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index 7bbde5828..5c14d376c 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,12 +1,12 @@ { - "name": "chrome-devtools-mcp", - "version": "0.23.0", - "description": "Reliable automation, in-depth debugging, and performance analysis in Chrome using Chrome DevTools and Puppeteer", + "name": "brave-mcp", + "version": "0.1.0", + "description": "Reliable automation, in-depth debugging, and performance analysis in Brave using DevTools and Puppeteer", "mcpServers": { - "chrome-devtools": { + "brave-devtools": { "command": "npx", "args": [ - "chrome-devtools-mcp@latest" + "brave-mcp@latest" ] } } diff --git a/.gitignore b/.gitignore index 2ea3f0b63..cae2a93b4 100644 --- a/.gitignore +++ b/.gitignore @@ -148,4 +148,7 @@ build/ log.txt -.DS_Store \ No newline at end of file +.DS_Store + +# AI tooling (local only) +.claude/ \ No newline at end of file diff --git a/.mcp.json b/.mcp.json index 017b717db..d034438cf 100644 --- a/.mcp.json +++ b/.mcp.json @@ -1,8 +1,8 @@ { "mcpServers": { - "chrome-devtools": { + "brave-devtools": { "command": "npx", - "args": ["chrome-devtools-mcp@latest"] + "args": ["brave-mcp@latest"] } } } diff --git a/README.md b/README.md index 9d18f1ab5..9edc1e2ca 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,13 @@ -# Chrome DevTools for Agents +# Brave MCP -[![npm chrome-devtools-mcp package](https://img.shields.io/npm/v/chrome-devtools-mcp.svg)](https://npmjs.org/package/chrome-devtools-mcp) +> Fork of [ChromeDevTools/chrome-devtools-mcp](https://github.com/ChromeDevTools/chrome-devtools-mcp) ported to **Brave Browser**. +> +> npm: `brave-mcp` · repo: `triuzzi/brave-devtools-mcp` -Chrome DevTools for Agents (`chrome-devtools-mcp`) lets your coding agent (such as Gemini, Claude, Cursor or Copilot) -control and inspect a live Chrome browser. It acts as a Model-Context-Protocol +`brave-mcp` lets your coding agent (such as Claude, Cursor, Gemini or Copilot) +control and inspect a live Brave browser. It acts as a Model-Context-Protocol (MCP) server, giving your AI coding assistant access to the full power of -Chrome DevTools for reliable automation, in-depth debugging, and performance analysis. +DevTools for reliable automation, in-depth debugging, and performance analysis. A [CLI](docs/cli.md) is also provided for use without MCP. ## [Tool reference](./docs/tool-reference.md) | [Changelog](./CHANGELOG.md) | [Contributing](./CONTRIBUTING.md) | [Troubleshooting](./docs/troubleshooting.md) | [Design Principles](./docs/design-principles.md) @@ -19,78 +21,185 @@ A [CLI](docs/cli.md) is also provided for use without MCP. check browser console messages (with source-mapped stack traces). - **Reliable automation**. Uses [puppeteer](https://github.com/puppeteer/puppeteer) to automate actions in - Chrome and automatically wait for action results. + Brave and automatically wait for action results. ## Disclaimers -`chrome-devtools-mcp` exposes content of the browser instance to the MCP clients +`brave-devtools-mcp` exposes content of the browser instance to the MCP clients allowing them to inspect, debug, and modify any data in the browser or DevTools. Avoid sharing sensitive or personal information that you don't want to share with MCP clients. -`chrome-devtools-mcp` officially supports Google Chrome and [Chrome for Testing](https://developer.chrome.com/blog/chrome-for-testing/) only. -Other Chromium-based browsers may work, but this is not guaranteed, and you may encounter unexpected behavior. Use at your own discretion. -We are committed to providing fixes and support for the latest version of [Extended Stable Chrome](https://chromiumdash.appspot.com/schedule). - Performance tools may send trace URLs to the Google CrUX API to fetch real-user -experience data. This helps provide a holistic performance picture by -presenting field data alongside lab data. This data is collected by the [Chrome -User Experience Report (CrUX)](https://developer.chrome.com/docs/crux). To disable -this, run with the `--no-performance-crux` flag. +experience data. To disable this, run with the `--no-performance-crux` flag. + +Usage statistics from the upstream project are **disabled by default** in this fork. +You can explicitly enable them with `--usage-statistics` if desired. + +## Requirements + +- [Node.js](https://nodejs.org/) v20.19 or a newer [latest maintenance LTS](https://github.com/nodejs/Release#release-schedule) version. +- [Brave Browser](https://brave.com/) current release version or newer. +- [npm](https://www.npmjs.com/) -## **Usage statistics** +> **Note:** Do **not** use `chrome-devtools-mcp@latest` from npm — that installs Google's Chrome-oriented server. This fork is `brave-mcp`. -Google collects usage statistics (such as tool invocation success rates, latency, and environment information) to improve the reliability and performance of Chrome DevTools MCP. +## Setup -Data collection is **enabled by default**. You can opt-out by passing the `--no-usage-statistics` flag when starting the server: +### Quick start (via npm) ```json -"args": ["-y", "chrome-devtools-mcp@latest", "--no-usage-statistics"] +{ + "mcpServers": { + "brave-devtools": { + "command": "npx", + "args": ["-y", "brave-mcp@latest"] + } + } +} ``` -Google handles this data in accordance with the [Google Privacy Policy](https://policies.google.com/privacy). +Add this to your MCP client config and you're done. Works with **Claude Code** (`~/.mcp.json`), **Cursor** (Settings → MCP), **VS Code Copilot**, and any other MCP client. -Google's collection of usage statistics for Chrome DevTools MCP is independent from the Chrome browser's usage statistics. Opting out of Chrome metrics does not automatically opt you out of this tool, and vice-versa. +### From source (for development) -Collection is disabled if `CHROME_DEVTOOLS_MCP_NO_USAGE_STATISTICS` or `CI` env variables are set. +```sh +git clone https://github.com/triuzzi/brave-devtools-mcp.git +cd brave-devtools-mcp +npm install +npm run build +``` -## Update checks +Run `npm run build` again after `git pull` when you update the repo. -By default, the server periodically checks the npm registry for updates and logs a notification when a newer version is available. -You can disable these update checks by setting the `CHROME_DEVTOOLS_MCP_NO_UPDATE_CHECKS` environment variable. +Then point your MCP config at the built CLI with an **absolute path**: -## Requirements +```json +{ + "mcpServers": { + "brave-devtools": { + "command": "node", + "args": [ + "/absolute/path/to/brave-devtools-mcp/build/src/bin/brave-devtools-mcp.js" + ] + } + } +} +``` -- [Node.js](https://nodejs.org/) v20.19 or a newer [latest maintenance LTS](https://github.com/nodejs/Release#release-schedule) version. -- [Chrome](https://www.google.com/chrome/) current stable version or newer. -- [npm](https://www.npmjs.com/) +This works with **Claude Code** (`~/.mcp.json`), **Cursor** (Settings → MCP → New MCP Server, or `mcp.json`), **VS Code Copilot**, and any other MCP client. -## Getting started +If Brave is not detected automatically, set `BRAVE_PATH`: + +```json +{ + "mcpServers": { + "brave-devtools": { + "command": "node", + "args": ["/absolute/path/to/brave-devtools-mcp/build/src/bin/brave-devtools-mcp.js"], + "env": { + "BRAVE_PATH": "/Applications/Brave Browser.app/Contents/MacOS/Brave Browser" + } + } + } +} +``` + +### 3. Choose your connection mode + +The server has two modes: **launch a new instance** (default) or **attach to your existing Brave window**. -Add the following config to your MCP client: +#### Mode A: Launch a new instance (default) + +With the basic config above, the server spawns a dedicated Brave instance with its own profile. Your existing Brave windows are untouched. This is the simplest mode — no extra setup needed. + +#### Mode B: Attach to your existing Brave window + +If you want the MCP server to control the Brave window you already have open (same tabs, cookies, logins), you need to start Brave with remote debugging enabled. + +**Step 1:** Quit Brave completely, then relaunch with the debugging flag: + +```sh +# macOS +open -a "Brave Browser" --args --remote-debugging-port=9222 + +# Linux +brave-browser --remote-debugging-port=9222 + +# Windows +"C:\Program Files\BraveSoftware\Brave-Browser\Application\brave.exe" --remote-debugging-port=9222 +``` + +> **Tip:** To always start Brave with remote debugging, add `--remote-debugging-port=9222` to Brave's launch shortcut or shell alias so you never have to think about it again. + +**Step 2:** Add `--browserUrl` to your MCP config: ```json { "mcpServers": { - "chrome-devtools": { + "brave-devtools": { "command": "npx", - "args": ["-y", "chrome-devtools-mcp@latest"] + "args": ["-y", "brave-mcp@latest", "--browserUrl", "http://localhost:9222"] } } } ``` -> [!NOTE] -> Using `chrome-devtools-mcp@latest` ensures that your MCP client will always use the latest version of the Chrome DevTools MCP server. +Or if running from source: + +```json +{ + "mcpServers": { + "brave-devtools": { + "command": "node", + "args": [ + "/absolute/path/to/brave-devtools-mcp/build/src/bin/brave-devtools-mcp.js", + "--browserUrl", "http://localhost:9222" + ] + } + } +} +``` + +Without `--browserUrl`, the server will always launch a new instance. With it, the server attaches to your running Brave instead. + +> **Warning:** The remote debugging port lets any application on your machine control the browser. Be mindful of sensitive websites while it's open. + +### All CLI options + +Run `--help` to see every flag: + +```sh +node /absolute/path/to/brave-devtools-mcp/build/src/bin/brave-devtools-mcp.js --help +``` + +## Testing + +An integration test suite exercises all 29 MCP tools against a running Brave instance: + +```sh +# Launch Brave with remote debugging +open -a "Brave Browser" --args --remote-debugging-port=9222 + +# Run all 36 test cases +npm run test:brave +``` + +Tests cover navigation, snapshots, screenshots, script execution, input automation (click/fill/drag/upload), dialogs, console, network, emulation, performance tracing, memory snapshots, and Lighthouse audits. -If you are interested in doing only basic browser tasks, use the `--slim` mode: +## Getting started + +If you are interested in only basic browser tasks, use `--slim` mode: ```json { "mcpServers": { - "chrome-devtools": { - "command": "npx", - "args": ["-y", "chrome-devtools-mcp@latest", "--slim", "--headless"] + "brave-devtools": { + "command": "node", + "args": [ + "/absolute/path/to/brave-devtools-mcp/build/src/bin/brave-devtools-mcp.js", + "--slim", "--headless" + ] } } } @@ -463,13 +572,13 @@ Go to `Settings | AI | Manage MCP Servers` -> `+ Add` to [add an MCP Server](htt Enter the following prompt in your MCP Client to check if everything is working: ``` -Check the performance of https://developers.chrome.com +Check the performance of https://example.com ``` -Your MCP client should open the browser and record a performance trace. +Your MCP client should open Brave (or attach to the running instance) and record a performance trace. > [!NOTE] -> The MCP server will start the browser automatically once the MCP client uses a tool that requires a running browser instance. Connecting to the Chrome DevTools MCP server on its own will not automatically start the browser. +> The MCP server will start the browser automatically once the MCP client uses a tool that requires a running browser instance. Connecting to the Brave DevTools MCP server on its own will not automatically start the browser. ## Tools @@ -524,7 +633,7 @@ If you run into any issues, checkout our [troubleshooting guide](./docs/troubles ## Configuration -The Chrome DevTools MCP server supports the following configuration option: +The Brave DevTools MCP server supports the following configuration options: @@ -693,143 +802,26 @@ You can also run `npx chrome-devtools-mcp@latest --help` to see all available co ### User data directory -`chrome-devtools-mcp` starts a Chrome's stable channel instance using the following user +`brave-devtools-mcp` starts a Brave release channel instance using the following user data directory: -- Linux / macOS: `$HOME/.cache/chrome-devtools-mcp/chrome-profile-$CHANNEL` -- Windows: `%HOMEPATH%/.cache/chrome-devtools-mcp/chrome-profile-$CHANNEL` +- Linux / macOS: `$HOME/.cache/brave-devtools-mcp/brave-profile-$CHANNEL` +- Windows: `%HOMEPATH%/.cache/brave-devtools-mcp/brave-profile-$CHANNEL` The user data directory is not cleared between runs and shared across -all instances of `chrome-devtools-mcp`. Set the `isolated` option to `true` +all instances of `brave-devtools-mcp`. Set the `isolated` option to `true` to use a temporary user data dir instead which will be cleared automatically after the browser is closed. -### Connecting to a running Chrome instance - -By default, the Chrome DevTools MCP server will start a new Chrome instance with a dedicated profile. This might not be ideal in all situations: - -- If you would like to maintain the same application state when alternating between manual site testing and agent-driven testing. -- When the MCP needs to sign into a website. Some accounts may prevent sign-in when the browser is controlled via WebDriver (the default launch mechanism for the Chrome DevTools MCP server). -- If you're running your LLM inside a sandboxed environment, but you would like to connect to a Chrome instance that runs outside the sandbox. - -In these cases, start Chrome first and let the Chrome DevTools MCP server connect to it. There are two ways to do so: - -- **Automatic connection (available in Chrome 144)**: best for sharing state between manual and agent-driven testing. -- **Manual connection via remote debugging port**: best when running inside a sandboxed environment. - -#### Automatically connecting to a running Chrome instance - -**Step 1:** Set up remote debugging in Chrome - -In Chrome (\>= M144), do the following to set up remote debugging: - -1. Navigate to `chrome://inspect/#remote-debugging` to enable remote debugging. -2. Follow the dialog UI to allow or disallow incoming debugging connections. - -**Step 2:** Configure Chrome DevTools MCP server to automatically connect to a running Chrome Instance - -To connect the `chrome-devtools-mcp` server to the running Chrome instance, use -`--autoConnect` command line argument for the MCP server. - -The following code snippet is an example configuration for gemini-cli: - -```json -{ - "mcpServers": { - "chrome-devtools": { - "command": "npx", - "args": ["chrome-devtools-mcp@latest", "--autoConnect"] - } - } -} -``` - -**Step 3:** Test your setup - -Make sure your browser is running. Open gemini-cli and run the following prompt: - -```none -Check the performance of https://developers.chrome.com -``` - -> [!NOTE] -> The autoConnect option requires the user to start Chrome. If the user has multiple active profiles, the MCP server will connect to the default profile (as determined by Chrome). The MCP server has access to all open windows for the selected profile. - -The Chrome DevTools MCP server will try to connect to your running Chrome -instance. It shows a dialog asking for user permission. - -Clicking **Allow** results in the Chrome DevTools MCP server opening -[developers.chrome.com](http://developers.chrome.com) and taking a performance -trace. - -#### Manual connection using port forwarding - -You can connect to a running Chrome instance by using the `--browser-url` option. This is useful if you are running the MCP server in a sandboxed environment that does not allow starting a new Chrome instance. - -Here is a step-by-step guide on how to connect to a running Chrome instance: - -**Step 1: Configure the MCP client** - -Add the `--browser-url` option to your MCP client configuration. The value of this option should be the URL of the running Chrome instance. `http://127.0.0.1:9222` is a common default. - -```json -{ - "mcpServers": { - "chrome-devtools": { - "command": "npx", - "args": [ - "chrome-devtools-mcp@latest", - "--browser-url=http://127.0.0.1:9222" - ] - } - } -} -``` - -**Step 2: Start the Chrome browser** - -> [!WARNING] -> Enabling the remote debugging port opens up a debugging port on the running browser instance. Any application on your machine can connect to this port and control the browser. Make sure that you are not browsing any sensitive websites while the debugging port is open. - -Start the Chrome browser with the remote debugging port enabled. Make sure to close any running Chrome instances before starting a new one with the debugging port enabled. The port number you choose must be the same as the one you specified in the `--browser-url` option in your MCP client configuration. - -For security reasons, [Chrome requires you to use a non-default user data directory](https://developer.chrome.com/blog/remote-debugging-port) when enabling the remote debugging port. You can specify a custom directory using the `--user-data-dir` flag. This ensures that your regular browsing profile and data are not exposed to the debugging session. - -**macOS** - -```bash -/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port=9222 --user-data-dir=/tmp/chrome-profile-stable -``` - -**Linux** - -```bash -/usr/bin/google-chrome --remote-debugging-port=9222 --user-data-dir=/tmp/chrome-profile-stable -``` - -**Windows** - -```bash -"C:\Program Files\Google\Chrome\Application\chrome.exe" --remote-debugging-port=9222 --user-data-dir="%TEMP%\chrome-profile-stable" -``` - -**Step 3: Test your setup** - -After configuring the MCP client and starting the Chrome browser, you can test your setup by running a simple prompt in your MCP client: - -``` -Check the performance of https://developers.chrome.com -``` - -Your MCP client should connect to the running Chrome instance and receive a performance report. +### Connecting to a running Brave instance -If you hit VM-to-host port forwarding issues, see the “Remote debugging between virtual machine (VM) and host fails” section in [`docs/troubleshooting.md`](./docs/troubleshooting.md#remote-debugging-between-virtual-machine-vm-and-host-fails). +See [Mode B: Attach to your existing Brave window](#mode-b-attach-to-your-existing-brave-window) in the Setup section above. -For more details on remote debugging, see the [Chrome DevTools documentation](https://developer.chrome.com/docs/devtools/remote-debugging/). +For VM-to-host port forwarding issues, see [`docs/troubleshooting.md`](./docs/troubleshooting.md#remote-debugging-between-virtual-machine-vm-and-host-fails). -### Debugging Chrome on Android +### Debugging on Android -Please consult [these instructions](./docs/debugging-android.md). +Please consult [these instructions](./docs/debugging-android.md) (originally written for Chrome, but applicable to any Chromium browser). ## Known limitations diff --git a/docs/cli.md b/docs/cli.md index a0d8d291c..db8ff156f 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -1,36 +1,36 @@ -# Chrome DevTools CLI +# Brave DevTools CLI -The `chrome-devtools-mcp` package includes an **experimental** CLI interface that allows you to interact with the browser directly from your terminal. This is particularly useful for debugging or when you want an agent to generate scripts that automate browser actions. +The `brave-devtools-mcp` package includes an **experimental** CLI interface that allows you to interact with the browser directly from your terminal. This is particularly useful for debugging or when you want an agent to generate scripts that automate browser actions. ## Getting started -Install the package globally to make the `chrome-devtools` command available: +Install the package globally to make the `brave-devtools` command available: ```sh -npm i chrome-devtools-mcp@latest -g -chrome-devtools status # check if install worked. +npm i brave-devtools-mcp@latest -g +brave-devtools status # check if install worked. ``` ## How it works -The CLI acts as a client to a background `chrome-devtools-mcp` daemon (uses Unix sockets on Linux/Mac and named pipes on Windows). +The CLI acts as a client to a background `brave-devtools-mcp` daemon (uses Unix sockets on Linux/Mac and named pipes on Windows). - **Automatic Start**: The first time you call a tool (e.g., `list_pages`), the CLI automatically starts the MCP server and the browser in the background if they aren't already running. - **Persistence**: The same background instance is reused for subsequent commands, preserving the browser state (open pages, cookies, etc.). -- **Manual Control**: You can explicitly manage the background process using `start`, `stop`, and `status`. The `start` command forwards all subsequent arguments to the underlying MCP server (e.g., `--headless`, `--userDataDir`) but not all args are supported. Run `chrome-devtools start --help` for supported args. Headless is enabled by default. Isolated is enabled by default unless `--userDataDir` is provided. +- **Manual Control**: You can explicitly manage the background process using `start`, `stop`, and `status`. The `start` command forwards all subsequent arguments to the underlying MCP server (e.g., `--headless`, `--userDataDir`) but not all args are supported. Run `brave-devtools start --help` for supported args. Headless is enabled by default. Isolated is enabled by default unless `--userDataDir` is provided. ```sh # Check if the daemon is running -chrome-devtools status +brave-devtools status # Navigate the current page to a URL -chrome-devtools navigate_page "https://google.com" +brave-devtools navigate_page url --url "https://google.com" # Take a screenshot and save it to a file -chrome-devtools take_screenshot --filePath screenshot.png +brave-devtools take_screenshot --filePath screenshot.png # Stop the background daemon when finished -chrome-devtools stop +brave-devtools stop ``` ## Command Usage @@ -39,7 +39,7 @@ The CLI only supports tools available in the MCP server without additional argum Thus, `--categoryExtensions` tools are currently not available in the CLI. ```sh -chrome-devtools [arguments] [flags] +brave-devtools [arguments] [flags] ``` - **Required Arguments**: Passed as positional arguments. @@ -50,25 +50,25 @@ chrome-devtools [arguments] [flags] **New Page and Navigation:** ```sh -chrome-devtools new_page "https://example.com" -chrome-devtools navigate_page "https://web.dev" --type url +brave-devtools new_page "https://example.com" +brave-devtools navigate_page url --url "https://web.dev" ``` **Interaction:** ```sh # Click an element by its UID from a snapshot -chrome-devtools click "element-uid-123" +brave-devtools click "element-uid-123" # Fill a form field -chrome-devtools fill "input-uid-456" "search query" +brave-devtools fill "input-uid-456" "search query" ``` **Analysis:** ```sh # Run a Lighthouse audit (defaults to navigation mode) -chrome-devtools lighthouse_audit --mode snapshot +brave-devtools lighthouse_audit --mode snapshot ``` ## Output format @@ -76,7 +76,7 @@ chrome-devtools lighthouse_audit --mode snapshot By default, the CLI outputs a human-readable summary of the tool's result. For programmatic use, you can request raw JSON: ```sh -chrome-devtools list_pages --output-format=json +brave-devtools list_pages --output-format=json ``` ## Troubleshooting @@ -84,13 +84,13 @@ chrome-devtools list_pages --output-format=json If the CLI hangs or fails to connect, try stopping the background process: ```sh -chrome-devtools stop +brave-devtools stop ``` For more verbose logs, set the `DEBUG` environment variable: ```sh -DEBUG=* chrome-devtools list_pages +DEBUG=* brave-devtools list_pages ``` ## CLI generation @@ -98,5 +98,5 @@ DEBUG=* chrome-devtools list_pages Implemented in `scripts/generate-cli.ts`. Some commands are excluded from CLI generation such as `wait_for` and `fill_form`. -`chrome-devtools-mcp` args are also filtered in `src/bin/chrome-devtools.ts` +`brave-devtools-mcp` args are also filtered in `src/bin/brave-devtools.ts` because not all args make sense in a CLI interface. diff --git a/package-lock.json b/package-lock.json index 25ef83e12..8d6a7117f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,16 +1,17 @@ { - "name": "chrome-devtools-mcp", - "version": "0.23.0", + "name": "brave-mcp", + "version": "0.2.2", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "chrome-devtools-mcp", - "version": "0.23.0", + "name": "brave-mcp", + "version": "0.2.2", "license": "Apache-2.0", "bin": { - "chrome-devtools": "build/src/bin/chrome-devtools.js", - "chrome-devtools-mcp": "build/src/bin/chrome-devtools-mcp.js" + "brave-devtools": "build/src/bin/brave-devtools.js", + "brave-devtools-mcp": "build/src/bin/brave-devtools-mcp.js", + "brave-mcp": "build/src/bin/brave-devtools-mcp.js" }, "devDependencies": { "@eslint/js": "^9.35.0", diff --git a/package.json b/package.json index 5b85e00c1..d35ae71bc 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,12 @@ { - "name": "chrome-devtools-mcp", - "version": "0.23.0", - "description": "MCP server for Chrome DevTools", + "name": "brave-mcp", + "version": "0.2.2", + "description": "MCP server for Brave DevTools", "type": "module", "bin": { - "chrome-devtools-mcp": "./build/src/bin/chrome-devtools-mcp.js", - "chrome-devtools": "./build/src/bin/chrome-devtools.js" + "brave-mcp": "./build/src/bin/brave-devtools-mcp.js", + "brave-devtools-mcp": "./build/src/bin/brave-devtools-mcp.js", + "brave-devtools": "./build/src/bin/brave-devtools.js" }, "main": "./build/src/index.js", "scripts": { @@ -24,6 +25,7 @@ "test:no-build": "node scripts/test.mjs", "test:only": "npm run build && node scripts/test.mjs --test-only", "test:update-snapshots": "npm run build && node scripts/test.mjs --test-update-snapshots", + "test:brave": "npm run build && node tests/e2e/brave-integration.test.mjs", "prepare": "node --experimental-strip-types scripts/prepare.ts", "verify-server-json-version": "node --experimental-strip-types scripts/verify-server-json-version.ts", "update-lighthouse": "node --experimental-strip-types scripts/update-lighthouse.ts", @@ -38,14 +40,14 @@ "!*.tsbuildinfo", "!*.js.map" ], - "repository": "ChromeDevTools/chrome-devtools-mcp", - "author": "Google LLC", + "repository": "triuzzi/brave-devtools-mcp", + "author": "Emanuele Triuzzi", "license": "Apache-2.0", "bugs": { - "url": "https://github.com/ChromeDevTools/chrome-devtools-mcp/issues" + "url": "https://github.com/triuzzi/brave-devtools-mcp/issues" }, - "homepage": "https://github.com/ChromeDevTools/chrome-devtools-mcp#readme", - "mcpName": "io.github.ChromeDevTools/chrome-devtools-mcp", + "homepage": "https://github.com/triuzzi/brave-devtools-mcp#readme", + "mcpName": "io.github.triuzzi/brave-devtools-mcp", "devDependencies": { "@eslint/js": "^9.35.0", "@google/genai": "^1.37.0", diff --git a/scripts/eval_gemini.ts b/scripts/eval_gemini.ts index bd5bafdb7..5fa49037c 100644 --- a/scripts/eval_gemini.ts +++ b/scripts/eval_gemini.ts @@ -101,7 +101,7 @@ async function runSingleScenario( // Path to the compiled MCP server const serverPath = path.join( ROOT_DIR, - 'build/src/bin/chrome-devtools-mcp.js', + 'build/src/bin/brave-devtools-mcp.js', ); if (!fs.existsSync(serverPath)) { throw new Error( diff --git a/scripts/generate-cli.ts b/scripts/generate-cli.ts index c5db4974d..5b2937a28 100644 --- a/scripts/generate-cli.ts +++ b/scripts/generate-cli.ts @@ -10,7 +10,7 @@ import path from 'node:path'; import {Client} from '@modelcontextprotocol/sdk/client/index.js'; import {StdioClientTransport} from '@modelcontextprotocol/sdk/client/stdio.js'; -import {parseArguments} from '../build/src/bin/chrome-devtools-mcp-cli-options.js'; +import {parseArguments} from '../build/src/bin/brave-devtools-mcp-cli-options.js'; import {labels} from '../build/src/tools/categories.js'; import {createTools} from '../build/src/tools/tools.js'; @@ -20,11 +20,11 @@ const OUTPUT_PATH = path.join( ); async function fetchTools() { - console.log('Connecting to chrome-devtools-mcp to fetch tools...'); + console.log('Connecting to brave-devtools-mcp to fetch tools...'); // Use the local build of the server const serverPath = path.join( import.meta.dirname, - '../build/src/bin/chrome-devtools-mcp.js', + '../build/src/bin/brave-devtools-mcp.js', ); const transport = new StdioClientTransport({ diff --git a/scripts/generate-docs.ts b/scripts/generate-docs.ts index 4be8fcbd7..b08953f0b 100644 --- a/scripts/generate-docs.ts +++ b/scripts/generate-docs.ts @@ -11,8 +11,8 @@ import {StdioClientTransport} from '@modelcontextprotocol/sdk/client/stdio.js'; import type {Tool} from '@modelcontextprotocol/sdk/types.js'; import {get_encoding} from 'tiktoken'; -import {cliOptions} from '../build/src/bin/chrome-devtools-mcp-cli-options.js'; -import type {ParsedArguments} from '../build/src/bin/chrome-devtools-mcp-cli-options.js'; +import {cliOptions} from '../build/src/bin/brave-devtools-mcp-cli-options.js'; +import type {ParsedArguments} from '../build/src/bin/brave-devtools-mcp-cli-options.js'; import { ToolCategory, OFF_BY_DEFAULT_CATEGORIES, @@ -28,7 +28,7 @@ async function measureServer(args: string[]) { // 1. Connect to your actual MCP server const transport = new StdioClientTransport({ command: 'node', - args: ['./build/src/bin/chrome-devtools-mcp.js', ...args], // Point to your built MCP server + args: ['./build/src/bin/brave-devtools-mcp.js', ...args], // Point to your built MCP server }); const client = new Client( diff --git a/scripts/update_metrics.ts b/scripts/update_metrics.ts index 6408782f3..b65b412e6 100644 --- a/scripts/update_metrics.ts +++ b/scripts/update_metrics.ts @@ -10,7 +10,7 @@ import * as path from 'node:path'; import { cliOptions, parseArguments, -} from '../build/src/bin/chrome-devtools-mcp-cli-options.js'; +} from '../build/src/bin/brave-devtools-mcp-cli-options.js'; import { getPossibleFlagMetrics, type FlagMetric, diff --git a/server.json b/server.json index 81578ab56..70ed1d248 100644 --- a/server.json +++ b/server.json @@ -1,19 +1,19 @@ { "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json", - "name": "io.github.ChromeDevTools/chrome-devtools-mcp", - "title": "Chrome DevTools MCP", - "description": "MCP server for Chrome DevTools", + "name": "io.github.triuzzi/brave-mcp", + "title": "Brave MCP", + "description": "MCP server for Brave Browser DevTools", "repository": { - "url": "https://github.com/ChromeDevTools/chrome-devtools-mcp", + "url": "https://github.com/triuzzi/brave-devtools-mcp", "source": "github" }, - "version": "0.23.0", + "version": "0.2.0", "packages": [ { "registryType": "npm", "registryBaseUrl": "https://registry.npmjs.org", - "identifier": "chrome-devtools-mcp", - "version": "0.23.0", + "identifier": "brave-mcp", + "version": "0.2.0", "transport": { "type": "stdio" }, diff --git a/src/McpResponse.ts b/src/McpResponse.ts index a5153d401..a15ae3b8c 100644 --- a/src/McpResponse.ts +++ b/src/McpResponse.ts @@ -6,7 +6,7 @@ import type {WebMCPTool} from 'puppeteer-core'; -import type {ParsedArguments} from './bin/chrome-devtools-mcp-cli-options.js'; +import type {ParsedArguments} from './bin/brave-devtools-mcp-cli-options.js'; import {ConsoleFormatter} from './formatters/ConsoleFormatter.js'; import {HeapSnapshotFormatter} from './formatters/HeapSnapshotFormatter.js'; import {IssueFormatter} from './formatters/IssueFormatter.js'; diff --git a/src/bin/chrome-devtools-cli-options.ts b/src/bin/brave-devtools-cli-options.ts similarity index 100% rename from src/bin/chrome-devtools-cli-options.ts rename to src/bin/brave-devtools-cli-options.ts diff --git a/src/bin/chrome-devtools-mcp-cli-options.ts b/src/bin/brave-devtools-mcp-cli-options.ts similarity index 71% rename from src/bin/chrome-devtools-mcp-cli-options.ts rename to src/bin/brave-devtools-mcp-cli-options.ts index 09a78d8cb..b59a89f61 100644 --- a/src/bin/chrome-devtools-mcp-cli-options.ts +++ b/src/bin/brave-devtools-mcp-cli-options.ts @@ -11,7 +11,7 @@ export const cliOptions = { autoConnect: { type: 'boolean', description: - 'If specified, automatically connects to a browser (Chrome 144+) running locally from the user data directory identified by the channel param (default channel is stable). Requires the remote debugging server to be started in the Chrome instance via chrome://inspect/#remote-debugging.', + 'If specified, automatically connects to a Brave instance running locally from the user data directory identified by the channel param (default channel is release). Requires the remote debugging server to be started in the Brave instance via brave://inspect/#remote-debugging.', conflicts: ['isolated', 'executablePath'], default: false, coerce: (value: boolean | undefined) => { @@ -24,7 +24,7 @@ export const cliOptions = { browserUrl: { type: 'string', description: - 'Connect to a running, debuggable Chrome instance (e.g. `http://127.0.0.1:9222`). For more details see: https://github.com/ChromeDevTools/chrome-devtools-mcp#connecting-to-a-running-chrome-instance.', + 'Connect to a running, debuggable Brave instance (e.g. `http://127.0.0.1:9222`).', alias: 'u', conflicts: ['wsEndpoint'], coerce: (url: string | undefined) => { @@ -42,7 +42,7 @@ export const cliOptions = { wsEndpoint: { type: 'string', description: - 'WebSocket endpoint to connect to a running Chrome instance (e.g., ws://127.0.0.1:9222/devtools/browser/). Alternative to --browserUrl.', + 'WebSocket endpoint to connect to a running Brave instance (e.g., ws://127.0.0.1:9222/devtools/browser/). Alternative to --browserUrl.', alias: 'w', conflicts: ['browserUrl'], coerce: (url: string | undefined) => { @@ -94,7 +94,7 @@ export const cliOptions = { }, executablePath: { type: 'string', - description: 'Path to custom Chrome executable.', + description: 'Path to custom Brave executable. Can also be set via BRAVE_PATH environment variable.', conflicts: ['browserUrl', 'wsEndpoint'], alias: 'e', }, @@ -106,14 +106,14 @@ export const cliOptions = { userDataDir: { type: 'string', description: - 'Path to the user data directory for Chrome. Default is $HOME/.cache/chrome-devtools-mcp/chrome-profile$CHANNEL_SUFFIX_IF_NON_STABLE', + 'Path to the user data directory for Brave. Default is $HOME/.cache/brave-devtools-mcp/brave-profile$CHANNEL_SUFFIX_IF_NON_RELEASE', conflicts: ['browserUrl', 'wsEndpoint', 'isolated'], }, channel: { type: 'string', description: - 'Specify a different Chrome channel that should be used. The default is the stable channel version.', - choices: ['canary', 'dev', 'beta', 'stable'] as const, + 'Specify a different Brave channel that should be used. The default is the release channel.', + choices: ['release', 'beta', 'nightly', 'dev'] as const, conflicts: ['browserUrl', 'wsEndpoint', 'executablePath'], }, logFile: { @@ -124,7 +124,7 @@ export const cliOptions = { viewport: { type: 'string', describe: - 'Initial viewport size for the Chrome instances started by the server. For example, `1280x720`. In headless mode, max size is 3840x2160px.', + 'Initial viewport size for the Brave instances started by the server. For example, `1280x720`. In headless mode, max size is 3840x2160px.', coerce: (arg: string | undefined) => { if (arg === undefined) { return; @@ -141,7 +141,7 @@ export const cliOptions = { }, proxyServer: { type: 'string', - description: `Proxy server configuration for Chrome passed as --proxy-server when launching the browser. See https://www.chromium.org/developers/design-documents/network-settings/ for details.`, + description: `Proxy server configuration for Brave passed as --proxy-server when launching the browser. See https://www.chromium.org/developers/design-documents/network-settings/ for details.`, }, acceptInsecureCerts: { type: 'boolean', @@ -203,17 +203,17 @@ export const cliOptions = { experimentalWebmcp: { type: 'boolean', describe: - 'Set to true to enable debugging WebMCP tools. Requires Chrome 149+ with the following flags: `--enable-features=WebMCPTesting,DevToolsWebMCPSupport`', + 'Set to true to enable debugging WebMCP tools. Requires Brave with the following flags: `--enable-features=WebMCPTesting,DevToolsWebMCPSupport`', }, - chromeArg: { + braveArg: { type: 'array', describe: - 'Additional arguments for Chrome. Only applies when Chrome is launched by chrome-devtools-mcp.', + 'Additional arguments for Brave. Only applies when Brave is launched by brave-devtools-mcp.', }, - ignoreDefaultChromeArg: { + ignoreDefaultBraveArg: { type: 'array', describe: - 'Explicitly disable default arguments for Chrome. Only applies when Chrome is launched by chrome-devtools-mcp.', + 'Explicitly disable default arguments for Brave. Only applies when Brave is launched by brave-devtools-mcp.', }, categoryEmulation: { type: 'boolean', @@ -251,9 +251,9 @@ export const cliOptions = { }, usageStatistics: { type: 'boolean', - default: true, + default: false, describe: - 'Set to false to opt-out of usage statistics collection. Google collects usage data to improve the tool, handled under the Google Privacy Policy (https://policies.google.com/privacy). This is independent from Chrome browser metrics. Disabled if `CHROME_DEVTOOLS_MCP_NO_USAGE_STATISTICS` or `CI` env variables are set.', + 'Usage statistics collection (disabled by default in this fork).', }, clearcutEndpoint: { type: 'string', @@ -278,7 +278,7 @@ export const cliOptions = { viaCli: { type: 'boolean', describe: - 'Set by Chrome DevTools CLI if the MCP server is started via the CLI client (this arg exists for usage stats)', + 'Set by Brave DevTools CLI if the MCP server is started via the CLI client (this arg exists for usage stats)', hidden: true, }, redactNetworkHeaders: { @@ -293,50 +293,48 @@ export type ParsedArguments = ReturnType; export function parseArguments(version: string, argv = process.argv) { const yargsInstance = yargs(hideBin(argv)) - .scriptName('npx chrome-devtools-mcp@latest') + .scriptName('npx brave-devtools-mcp@latest') .options(cliOptions) .check(args => { - // We can't set default in the options else - // Yargs will complain if ( !args.channel && !args.browserUrl && !args.wsEndpoint && !args.executablePath ) { - args.channel = 'stable'; + args.channel = 'release'; } return true; }) .example([ [ '$0 --browserUrl http://127.0.0.1:9222', - 'Connect to an existing browser instance via HTTP', + 'Connect to an existing Brave instance via HTTP', ], [ '$0 --wsEndpoint ws://127.0.0.1:9222/devtools/browser/abc123', - 'Connect to an existing browser instance via WebSocket', + 'Connect to an existing Brave instance via WebSocket', ], [ `$0 --wsEndpoint ws://127.0.0.1:9222/devtools/browser/abc123 --wsHeaders '{"Authorization":"Bearer token"}'`, 'Connect via WebSocket with custom headers', ], - ['$0 --channel beta', 'Use Chrome Beta installed on this system'], - ['$0 --channel canary', 'Use Chrome Canary installed on this system'], - ['$0 --channel dev', 'Use Chrome Dev installed on this system'], - ['$0 --channel stable', 'Use stable Chrome installed on this system'], + ['$0 --channel beta', 'Use Brave Beta installed on this system'], + ['$0 --channel nightly', 'Use Brave Nightly installed on this system'], + ['$0 --channel dev', 'Use Brave Dev installed on this system'], + ['$0 --channel release', 'Use release Brave installed on this system'], ['$0 --logFile /tmp/log.txt', 'Save logs to a file'], ['$0 --help', 'Print CLI options'], [ '$0 --viewport 1280x720', - 'Launch Chrome with the initial viewport size of 1280x720px', + 'Launch Brave with the initial viewport size of 1280x720px', ], [ - `$0 --chrome-arg='--no-sandbox' --chrome-arg='--disable-setuid-sandbox'`, - 'Launch Chrome without sandboxes. Use with caution.', + `$0 --brave-arg='--no-sandbox' --brave-arg='--disable-setuid-sandbox'`, + 'Launch Brave without sandboxes. Use with caution.', ], [ - `$0 --ignore-default-chrome-arg='--disable-extensions'`, + `$0 --ignore-default-brave-arg='--disable-extensions'`, 'Disable the default arguments provided by Puppeteer. Use with caution.', ], ['$0 --no-category-emulation', 'Disable tools in the emulation category'], @@ -351,19 +349,11 @@ export function parseArguments(version: string, argv = process.argv) { ], [ '$0 --auto-connect', - 'Connect to a stable Chrome instance (Chrome 144+) running instead of launching a new instance', - ], - [ - '$0 --auto-connect --channel=canary', - 'Connect to a canary Chrome instance (Chrome 144+) running instead of launching a new instance', - ], - [ - '$0 --no-usage-statistics', - 'Do not send usage statistics https://github.com/ChromeDevTools/chrome-devtools-mcp#usage-statistics.', + 'Connect to a release Brave instance running instead of launching a new instance', ], [ - '$0 --no-performance-crux', - 'Disable CrUX (field data) integration in performance tools.', + '$0 --auto-connect --channel=nightly', + 'Connect to a nightly Brave instance running instead of launching a new instance', ], [ '$0 --slim', diff --git a/src/bin/chrome-devtools-mcp-main.ts b/src/bin/brave-devtools-mcp-main.ts similarity index 68% rename from src/bin/chrome-devtools-mcp-main.ts rename to src/bin/brave-devtools-mcp-main.ts index 46100ed94..16d15d37a 100644 --- a/src/bin/chrome-devtools-mcp-main.ts +++ b/src/bin/brave-devtools-mcp-main.ts @@ -12,41 +12,36 @@ import {createMcpServer, logDisclaimers} from '../index.js'; import {logger, saveLogsToFile} from '../logger.js'; import {computeFlagUsage} from '../telemetry/flagUtils.js'; import {StdioServerTransport} from '../third_party/index.js'; -import {checkForUpdates} from '../utils/check-for-updates.js'; import {VERSION} from '../version.js'; -import {cliOptions, parseArguments} from './chrome-devtools-mcp-cli-options.js'; - -await checkForUpdates( - 'Run `npm install chrome-devtools-mcp@latest` to update.', -); +import {cliOptions, parseArguments} from './brave-devtools-mcp-cli-options.js'; export const args = parseArguments(VERSION); const logFile = args.logFile ? saveLogsToFile(args.logFile) : undefined; if ( process.env['CI'] || - process.env['CHROME_DEVTOOLS_MCP_NO_USAGE_STATISTICS'] + process.env['BRAVE_DEVTOOLS_MCP_NO_USAGE_STATISTICS'] ) { console.error( - "turning off usage statistics. process.env['CI'] || process.env['CHROME_DEVTOOLS_MCP_NO_USAGE_STATISTICS'] is set.", + "turning off usage statistics. process.env['CI'] || process.env['BRAVE_DEVTOOLS_MCP_NO_USAGE_STATISTICS'] is set.", ); args.usageStatistics = false; } -if (process.env['CHROME_DEVTOOLS_MCP_CRASH_ON_UNCAUGHT'] !== 'true') { +if (process.env['BRAVE_DEVTOOLS_MCP_CRASH_ON_UNCAUGHT'] !== 'true') { process.on('unhandledRejection', (reason, promise) => { logger('Unhandled promise rejection', promise, reason); }); } -logger(`Starting Chrome DevTools MCP Server v${VERSION}`); +logger(`Starting Brave DevTools MCP Server v${VERSION}`); const {server, clearcutLogger} = await createMcpServer(args, { logFile, }); const transport = new StdioServerTransport(); await server.connect(transport); -logger('Chrome DevTools MCP Server connected'); +logger('Brave DevTools MCP Server connected'); logDisclaimers(args); void clearcutLogger?.logDailyActiveIfNeeded(); void clearcutLogger?.logServerStart(computeFlagUsage(args, cliOptions)); diff --git a/src/bin/brave-devtools-mcp.ts b/src/bin/brave-devtools-mcp.ts new file mode 100644 index 000000000..c889a585b --- /dev/null +++ b/src/bin/brave-devtools-mcp.ts @@ -0,0 +1,36 @@ +#!/usr/bin/env node + +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +process.title = 'brave-devtools-mcp'; + +import {version} from 'node:process'; + +const [major, minor] = version.substring(1).split('.').map(Number); + +if (major === 20 && minor < 19) { + console.error( + `ERROR: \`brave-devtools-mcp\` does not support Node ${process.version}. Please upgrade to Node 20.19.0 LTS or a newer LTS.`, + ); + process.exit(1); +} + +if (major === 22 && minor < 12) { + console.error( + `ERROR: \`brave-devtools-mcp\` does not support Node ${process.version}. Please upgrade to Node 22.12.0 LTS or a newer LTS.`, + ); + process.exit(1); +} + +if (major < 20) { + console.error( + `ERROR: \`brave-devtools-mcp\` does not support Node ${process.version}. Please upgrade to Node 20.19.0 LTS or a newer LTS.`, + ); + process.exit(1); +} + +await import('./brave-devtools-mcp-main.js'); diff --git a/src/bin/chrome-devtools.ts b/src/bin/brave-devtools.ts similarity index 91% rename from src/bin/chrome-devtools.ts rename to src/bin/brave-devtools.ts index 84a96c086..43d8e0a64 100644 --- a/src/bin/chrome-devtools.ts +++ b/src/bin/brave-devtools.ts @@ -6,7 +6,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -process.title = 'chrome-devtools'; +process.title = 'brave-devtools'; import process from 'node:process'; @@ -24,11 +24,11 @@ import {hideBin, yargs, type CallToolResult} from '../third_party/index.js'; import {checkForUpdates} from '../utils/check-for-updates.js'; import {VERSION} from '../version.js'; -import {commands} from './chrome-devtools-cli-options.js'; -import {cliOptions, parseArguments} from './chrome-devtools-mcp-cli-options.js'; +import {commands} from './brave-devtools-cli-options.js'; +import {cliOptions, parseArguments} from './brave-devtools-mcp-cli-options.js'; await checkForUpdates( - 'Run `npm install -g chrome-devtools-mcp@latest` and `chrome-devtools start` to update and restart the daemon.', + 'Run `npm install -g brave-devtools-mcp@latest` and `brave-devtools start` to update and restart the daemon.', ); async function start(args: string[], sessionId: string) { @@ -72,11 +72,11 @@ startCliOptions.isolated!.description = 'If specified, creates a temporary user-data-dir that is automatically cleaned up after the browser is closed. Defaults to true unless userDataDir is provided.'; const y = yargs(hideBin(process.argv)) - .scriptName('chrome-devtools') + .scriptName('brave-devtools') .showHelpOnFail(true) - .usage('chrome-devtools [...args] --flags') + .usage('brave-devtools [...args] --flags') .usage( - `Run 'chrome-devtools --help' for help on the specific command.`, + `Run 'brave-devtools --help' for help on the specific command.`, ) .option('sessionId', { type: 'string', @@ -92,7 +92,7 @@ const y = yargs(hideBin(process.argv)) y.command( 'start', - 'Start or restart chrome-devtools-mcp', + 'Start or restart brave-devtools-mcp', y => y .options(startCliOptions) @@ -120,11 +120,11 @@ y.command( y.command( 'status', - 'Checks if chrome-devtools-mcp is running', + 'Checks if brave-devtools-mcp is running', y => y, async argv => { if (isDaemonRunning(argv.sessionId)) { - console.log('chrome-devtools-mcp daemon is running.'); + console.log('brave-devtools-mcp daemon is running.'); const response = await sendCommand( { method: 'status', @@ -148,7 +148,7 @@ y.command( process.exit(1); } } else { - console.log('chrome-devtools-mcp daemon is not running.'); + console.log('brave-devtools-mcp daemon is not running.'); } process.exit(0); }, @@ -156,7 +156,7 @@ y.command( y.command( 'stop', - 'Stop chrome-devtools-mcp if any', + 'Stop brave-devtools-mcp if any', y => y, async argv => { const sessionId = argv.sessionId as string; diff --git a/src/bin/check-latest-version.ts b/src/bin/check-latest-version.ts index eb45674df..56907aad3 100644 --- a/src/bin/check-latest-version.ts +++ b/src/bin/check-latest-version.ts @@ -13,7 +13,7 @@ const cachePath = process.argv[2]; if (cachePath) { try { const response = await fetch( - 'https://registry.npmjs.org/chrome-devtools-mcp/latest', + 'https://registry.npmjs.org/brave-mcp/latest', ); const data = response.ok ? await response.json() : null; diff --git a/src/bin/chrome-devtools-mcp.ts b/src/bin/chrome-devtools-mcp.ts deleted file mode 100644 index 4f6a4f284..000000000 --- a/src/bin/chrome-devtools-mcp.ts +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env node - -/** - * @license - * Copyright 2025 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -process.title = 'chrome-devtools-mcp'; - -import {version} from 'node:process'; - -const [major, minor] = version.substring(1).split('.').map(Number); - -if (major === 20 && minor < 19) { - console.error( - `ERROR: \`chrome-devtools-mcp\` does not support Node ${process.version}. Please upgrade to Node 20.19.0 LTS or a newer LTS.`, - ); - process.exit(1); -} - -if (major === 22 && minor < 12) { - console.error( - `ERROR: \`chrome-devtools-mcp\` does not support Node ${process.version}. Please upgrade to Node 22.12.0 LTS or a newer LTS.`, - ); - process.exit(1); -} - -if (major < 20) { - console.error( - `ERROR: \`chrome-devtools-mcp\` does not support Node ${process.version}. Please upgrade to Node 20.19.0 LTS or a newer LTS.`, - ); - process.exit(1); -} - -await import('./chrome-devtools-mcp-main.js'); diff --git a/src/browser.ts b/src/browser.ts index 7deea75b4..1331e1cab 100644 --- a/src/browser.ts +++ b/src/browser.ts @@ -12,7 +12,6 @@ import path from 'node:path'; import {logger} from './logger.js'; import type { Browser, - ChromeReleaseChannel, LaunchOptions, Target, } from './third_party/index.js'; @@ -20,18 +19,23 @@ import {puppeteer} from './third_party/index.js'; let browser: Browser | undefined; +export type Channel = 'release' | 'beta' | 'nightly' | 'dev'; + function makeTargetFilter(enableExtensions = false) { - const ignoredPrefixes = new Set(['chrome://', 'chrome-untrusted://']); + const ignoredPrefixes = new Set([ + 'chrome://', + 'chrome-untrusted://', + 'brave://', + ]); if (!enableExtensions) { ignoredPrefixes.add('chrome-extension://'); } return function targetFilter(target: Target): boolean { - if (target.url() === 'chrome://newtab/') { + if (target.url() === 'brave://newtab/' || target.url() === 'chrome://newtab/') { return true; } - // Could be the only page opened in the browser. - if (target.url().startsWith('chrome://inspect')) { + if (target.url().startsWith('brave://inspect') || target.url().startsWith('chrome://inspect')) { return true; } for (const prefix of ignoredPrefixes) { @@ -43,6 +47,130 @@ function makeTargetFilter(enableExtensions = false) { }; } +function resolveBraveExecutablePath(channel?: Channel): string { + const envPath = process.env['BRAVE_PATH']; + if (envPath) { + if (!fs.existsSync(envPath)) { + throw new Error(`BRAVE_PATH points to ${envPath} but that file does not exist.`); + } + return envPath; + } + + const platform = os.platform(); + + if (platform === 'darwin') { + const paths: Record = { + release: '/Applications/Brave Browser.app/Contents/MacOS/Brave Browser', + beta: '/Applications/Brave Browser Beta.app/Contents/MacOS/Brave Browser Beta', + nightly: '/Applications/Brave Browser Nightly.app/Contents/MacOS/Brave Browser Nightly', + dev: '/Applications/Brave Browser Dev.app/Contents/MacOS/Brave Browser Dev', + }; + const resolved = paths[channel ?? 'release']; + if (fs.existsSync(resolved)) { + return resolved; + } + throw new Error( + `Could not find Brave Browser (${channel ?? 'release'}) at ${resolved}. Install Brave or set the BRAVE_PATH environment variable.`, + ); + } + + if (platform === 'linux') { + const paths: Record = { + release: ['brave-browser', 'brave-browser-stable'], + beta: ['brave-browser-beta'], + nightly: ['brave-browser-nightly'], + dev: ['brave-browser-dev'], + }; + const candidates = paths[channel ?? 'release']; + for (const candidate of candidates) { + try { + const resolvedPath = execSync(`which ${candidate}`, {encoding: 'utf8'}).trim(); + if (resolvedPath) { + return resolvedPath; + } + } catch { + // try next candidate + } + } + throw new Error( + `Could not find Brave Browser (${channel ?? 'release'}) in PATH. Install Brave or set the BRAVE_PATH environment variable.`, + ); + } + + if (platform === 'win32') { + const programFiles = process.env['PROGRAMFILES'] ?? 'C:\\Program Files'; + const localAppData = process.env['LOCALAPPDATA'] ?? ''; + const paths: Record = { + release: [ + path.join(programFiles, 'BraveSoftware', 'Brave-Browser', 'Application', 'brave.exe'), + path.join(localAppData, 'BraveSoftware', 'Brave-Browser', 'Application', 'brave.exe'), + ], + beta: [ + path.join(programFiles, 'BraveSoftware', 'Brave-Browser-Beta', 'Application', 'brave.exe'), + path.join(localAppData, 'BraveSoftware', 'Brave-Browser-Beta', 'Application', 'brave.exe'), + ], + nightly: [ + path.join(programFiles, 'BraveSoftware', 'Brave-Browser-Nightly', 'Application', 'brave.exe'), + path.join(localAppData, 'BraveSoftware', 'Brave-Browser-Nightly', 'Application', 'brave.exe'), + ], + dev: [ + path.join(programFiles, 'BraveSoftware', 'Brave-Browser-Dev', 'Application', 'brave.exe'), + path.join(localAppData, 'BraveSoftware', 'Brave-Browser-Dev', 'Application', 'brave.exe'), + ], + }; + const candidates = paths[channel ?? 'release']; + for (const candidate of candidates) { + if (fs.existsSync(candidate)) { + return candidate; + } + } + throw new Error( + `Could not find Brave Browser (${channel ?? 'release'}). Install Brave or set the BRAVE_PATH environment variable.`, + ); + } + + throw new Error(`Unsupported platform: ${platform}`); +} + +function resolveBraveUserDataDir(channel?: Channel): string { + const platform = os.platform(); + const home = os.homedir(); + + if (platform === 'darwin') { + const dirs: Record = { + release: path.join(home, 'Library', 'Application Support', 'BraveSoftware', 'Brave-Browser'), + beta: path.join(home, 'Library', 'Application Support', 'BraveSoftware', 'Brave-Browser-Beta'), + nightly: path.join(home, 'Library', 'Application Support', 'BraveSoftware', 'Brave-Browser-Nightly'), + dev: path.join(home, 'Library', 'Application Support', 'BraveSoftware', 'Brave-Browser-Dev'), + }; + return dirs[channel ?? 'release']; + } + + if (platform === 'linux') { + const configDir = process.env['XDG_CONFIG_HOME'] ?? path.join(home, '.config'); + const dirs: Record = { + release: path.join(configDir, 'BraveSoftware', 'Brave-Browser'), + beta: path.join(configDir, 'BraveSoftware', 'Brave-Browser-Beta'), + nightly: path.join(configDir, 'BraveSoftware', 'Brave-Browser-Nightly'), + dev: path.join(configDir, 'BraveSoftware', 'Brave-Browser-Dev'), + }; + return dirs[channel ?? 'release']; + } + + if (platform === 'win32') { + const localAppData = process.env['LOCALAPPDATA'] ?? path.join(home, 'AppData', 'Local'); + const dirs: Record = { + release: path.join(localAppData, 'BraveSoftware', 'Brave-Browser', 'User Data'), + beta: path.join(localAppData, 'BraveSoftware', 'Brave-Browser-Beta', 'User Data'), + nightly: path.join(localAppData, 'BraveSoftware', 'Brave-Browser-Nightly', 'User Data'), + dev: path.join(localAppData, 'BraveSoftware', 'Brave-Browser-Dev', 'User Data'), + }; + return dirs[channel ?? 'release']; + } + + throw new Error(`Unsupported platform: ${platform}`); +} + export async function ensureBrowserConnected(options: { browserURL?: string; wsEndpoint?: string; @@ -72,45 +200,35 @@ export async function ensureBrowserConnected(options: { } else if (options.browserURL) { connectOptions.browserURL = options.browserURL; } else if (channel || options.userDataDir) { - const userDataDir = options.userDataDir; - if (userDataDir) { - autoConnect = true; - // TODO: re-expose this logic via Puppeteer. - const portPath = path.join(userDataDir, 'DevToolsActivePort'); - try { - const fileContent = await fs.promises.readFile(portPath, 'utf8'); - const [rawPort, rawPath] = fileContent - .split('\n') - .map(line => { - return line.trim(); - }) - .filter(line => { - return !!line; - }); - if (!rawPort || !rawPath) { - throw new Error(`Invalid DevToolsActivePort '${fileContent}' found`); - } - const port = parseInt(rawPort, 10); - if (isNaN(port) || port <= 0 || port > 65535) { - throw new Error(`Invalid port '${rawPort}' found`); - } - const browserWSEndpoint = `ws://127.0.0.1:${port}${rawPath}`; - connectOptions.browserWSEndpoint = browserWSEndpoint; - } catch (error) { - throw new Error( - `Could not connect to Chrome in ${userDataDir}. Check if Chrome is running and remote debugging is enabled by going to chrome://inspect/#remote-debugging.`, - { - cause: error, - }, - ); + const userDataDir = options.userDataDir ?? resolveBraveUserDataDir(channel); + autoConnect = true; + const portPath = path.join(userDataDir, 'DevToolsActivePort'); + try { + const fileContent = await fs.promises.readFile(portPath, 'utf8'); + const [rawPort, rawPath] = fileContent + .split('\n') + .map(line => { + return line.trim(); + }) + .filter(line => { + return !!line; + }); + if (!rawPort || !rawPath) { + throw new Error(`Invalid DevToolsActivePort '${fileContent}' found`); } - } else { - if (!channel) { - throw new Error('Channel must be provided if userDataDir is missing'); + const port = parseInt(rawPort, 10); + if (isNaN(port) || port <= 0 || port > 65535) { + throw new Error(`Invalid port '${rawPort}' found`); } - connectOptions.channel = ( - channel === 'stable' ? 'chrome' : `chrome-${channel}` - ) as ChromeReleaseChannel; + const browserWSEndpoint = `ws://127.0.0.1:${port}${rawPath}`; + connectOptions.browserWSEndpoint = browserWSEndpoint; + } catch (error) { + throw new Error( + `Could not connect to Brave in ${userDataDir}. Check if Brave is running and remote debugging is enabled by going to brave://inspect/#remote-debugging.`, + { + cause: error, + }, + ); } } else { throw new Error( @@ -123,7 +241,7 @@ export async function ensureBrowserConnected(options: { browser = await puppeteer.connect(connectOptions); } catch (err) { throw new Error( - `Could not connect to Chrome. ${autoConnect ? `Check if Chrome is running and remote debugging is enabled by going to chrome://inspect/#remote-debugging.` : `Check if Chrome is running.`}`, + `Could not connect to Brave. ${autoConnect ? `Check if Brave is running and remote debugging is enabled by going to brave://inspect/#remote-debugging.` : `Check if Brave is running.`}`, { cause: err, }, @@ -145,15 +263,14 @@ interface McpLaunchOptions { width: number; height: number; }; - chromeArgs?: string[]; - ignoreDefaultChromeArgs?: string[]; + braveArgs?: string[]; + ignoreDefaultBraveArgs?: string[]; devtools: boolean; enableExtensions?: boolean; viaCli?: boolean; } export function detectDisplay(): void { - // Only detect display on Linux/UNIX. if (os.platform() === 'win32' || os.platform() === 'darwin') { return; } @@ -171,18 +288,20 @@ export function detectDisplay(): void { } export async function launch(options: McpLaunchOptions): Promise { - const {channel, executablePath, headless, isolated} = options; + const {channel, headless, isolated} = options; const profileDirName = - channel && channel !== 'stable' - ? `chrome-profile-${channel}` - : 'chrome-profile'; + channel && channel !== 'release' + ? `brave-profile-${channel}` + : 'brave-profile'; + + const executablePath = options.executablePath ?? resolveBraveExecutablePath(channel); let userDataDir = options.userDataDir; if (!isolated && !userDataDir) { userDataDir = path.join( os.homedir(), '.cache', - options.viaCli ? 'chrome-devtools-mcp-cli' : 'chrome-devtools-mcp', + options.viaCli ? 'brave-devtools-mcp-cli' : 'brave-devtools-mcp', profileDirName, ); await fs.promises.mkdir(userDataDir, { @@ -191,25 +310,18 @@ export async function launch(options: McpLaunchOptions): Promise { } const args: LaunchOptions['args'] = [ - ...(options.chromeArgs ?? []), + ...(options.braveArgs ?? []), '--hide-crash-restore-bubble', ]; const ignoreDefaultArgs: LaunchOptions['ignoreDefaultArgs'] = - options.ignoreDefaultChromeArgs ?? false; + options.ignoreDefaultBraveArgs ?? false; if (headless) { args.push('--screen-info={3840x2160}'); } - let puppeteerChannel: ChromeReleaseChannel | undefined; if (options.devtools) { args.push('--auto-open-devtools-for-tabs'); } - if (!executablePath) { - puppeteerChannel = - channel && channel !== 'stable' - ? (`chrome-${channel}` as ChromeReleaseChannel) - : 'chrome'; - } if (!headless) { detectDisplay(); @@ -217,7 +329,6 @@ export async function launch(options: McpLaunchOptions): Promise { try { const browser = await puppeteer.launch({ - channel: puppeteerChannel, targetFilter: makeTargetFilter(options.enableExtensions), executablePath, defaultViewport: null, @@ -231,8 +342,6 @@ export async function launch(options: McpLaunchOptions): Promise { enableExtensions: options.enableExtensions, }); if (options.logFile) { - // FIXME: we are probably subscribing too late to catch startup logs. We - // should expose the process earlier or expose the getRecentLogs() getter. browser.process()?.stderr?.pipe(options.logFile); browser.process()?.stdout?.pipe(options.logFile); } @@ -269,5 +378,3 @@ export async function ensureBrowserLaunched( browser = await launch(options); return browser; } - -export type Channel = 'stable' | 'canary' | 'beta' | 'dev'; diff --git a/src/daemon/daemon.ts b/src/daemon/daemon.ts index e6cb8bd08..003cded18 100644 --- a/src/daemon/daemon.ts +++ b/src/daemon/daemon.ts @@ -54,7 +54,7 @@ let server: Server | null = null; async function setupMCPClient() { console.log('Setting up MCP client connection...'); - // Create stdio transport for chrome-devtools-mcp + // Create stdio transport for brave-devtools-mcp mcpTransport = new StdioClientTransport({ command: process.execPath, args: [INDEX_SCRIPT_PATH, ...mcpServerArgs], diff --git a/src/daemon/utils.ts b/src/daemon/utils.ts index 83f69d265..1ecfc937b 100644 --- a/src/daemon/utils.ts +++ b/src/daemon/utils.ts @@ -17,11 +17,11 @@ export const INDEX_SCRIPT_PATH = path.join( import.meta.dirname, '..', 'bin', - 'chrome-devtools-mcp.js', + 'brave-devtools-mcp.js', ); -const APP_NAME = 'chrome-devtools-mcp'; -export const DAEMON_CLIENT_NAME = 'chrome-devtools-cli-daemon'; +const APP_NAME = 'brave-devtools-mcp'; +export const DAEMON_CLIENT_NAME = 'brave-devtools-cli-daemon'; // Using these paths due to strict limits on the POSIX socket path length. export function getSocketPath(sessionId: string): string { diff --git a/src/index.ts b/src/index.ts index 9f522f63b..a5d0dcf1e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,7 +6,7 @@ import type fs from 'node:fs'; -import type {parseArguments} from './bin/chrome-devtools-mcp-cli-options.js'; +import type {parseArguments} from './bin/brave-devtools-mcp-cli-options.js'; import type {Channel} from './browser.js'; import {ensureBrowserConnected, ensureBrowserLaunched} from './browser.js'; import {loadIssueDescriptions} from './issue-descriptions.js'; @@ -49,8 +49,8 @@ export async function createMcpServer( const server = new McpServer( { - name: 'chrome_devtools', - title: 'Chrome DevTools MCP server', + name: 'brave_devtools', + title: 'Brave DevTools MCP server', version: VERSION, }, {capabilities: {logging: {}}}, @@ -92,12 +92,12 @@ export async function createMcpServer( let context: McpContext; async function getContext(): Promise { - const chromeArgs: string[] = (serverArgs.chromeArg ?? []).map(String); - const ignoreDefaultChromeArgs: string[] = ( - serverArgs.ignoreDefaultChromeArg ?? [] + const braveArgs: string[] = (serverArgs.braveArg ?? []).map(String); + const ignoreDefaultBraveArgs: string[] = ( + serverArgs.ignoreDefaultBraveArg ?? [] ).map(String); if (serverArgs.proxyServer) { - chromeArgs.push(`--proxy-server=${serverArgs.proxyServer}`); + braveArgs.push(`--proxy-server=${serverArgs.proxyServer}`); } const devtools = serverArgs.experimentalDevtools ?? false; const browser = @@ -106,7 +106,6 @@ export async function createMcpServer( browserURL: serverArgs.browserUrl, wsEndpoint: serverArgs.wsEndpoint, wsHeaders: serverArgs.wsHeaders, - // Important: only pass channel, if autoConnect is true. channel: serverArgs.autoConnect ? (serverArgs.channel as Channel) : undefined, @@ -121,8 +120,8 @@ export async function createMcpServer( userDataDir: serverArgs.userDataDir, logFile: options.logFile, viewport: serverArgs.viewport, - chromeArgs, - ignoreDefaultChromeArgs, + braveArgs, + ignoreDefaultBraveArgs, acceptInsecureCerts: serverArgs.acceptInsecureCerts, devtools, enableExtensions: serverArgs.categoryExtensions, @@ -316,7 +315,7 @@ export async function createMcpServer( export const logDisclaimers = (args: ReturnType) => { console.error( - `chrome-devtools-mcp exposes content of the browser instance to the MCP clients allowing them to inspect, + `brave-devtools-mcp exposes content of the browser instance to the MCP clients allowing them to inspect, debug, and modify any data in the browser or DevTools. Avoid sharing sensitive or personal information that you do not want to share with MCP clients.`, ); @@ -329,9 +328,7 @@ Avoid sharing sensitive or personal information that you do not want to share wi if (!args.slim && args.usageStatistics) { console.error( - ` -Google collects usage statistics to improve Chrome DevTools MCP. To opt-out, run with --no-usage-statistics. -For more details, visit: https://github.com/ChromeDevTools/chrome-devtools-mcp#usage-statistics`, + `Usage statistics are enabled. To opt-out, run with --no-usage-statistics.`, ); } }; diff --git a/src/telemetry/flagUtils.ts b/src/telemetry/flagUtils.ts index fdaa4ed96..9c57c6a36 100644 --- a/src/telemetry/flagUtils.ts +++ b/src/telemetry/flagUtils.ts @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import type {cliOptions} from '../bin/chrome-devtools-mcp-cli-options.js'; +import type {cliOptions} from '../bin/brave-devtools-mcp-cli-options.js'; import {toSnakeCase} from '../utils/string.js'; import type {FlagUsage} from './types.js'; diff --git a/src/telemetry/persistence.ts b/src/telemetry/persistence.ts index 5b133649b..61e598399 100644 --- a/src/telemetry/persistence.ts +++ b/src/telemetry/persistence.ts @@ -19,7 +19,7 @@ const STATE_FILE_NAME = 'telemetry_state.json'; function getDataFolder(): string { const homedir = os.homedir(); const {env} = process; - const name = 'chrome-devtools-mcp'; + const name = 'brave-devtools-mcp'; if (process.platform === 'darwin') { return path.join(homedir, 'Library', 'Application Support', name); diff --git a/src/tools/ToolDefinition.ts b/src/tools/ToolDefinition.ts index 91c42dcc2..d81d47436 100644 --- a/src/tools/ToolDefinition.ts +++ b/src/tools/ToolDefinition.ts @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import type {ParsedArguments} from '../bin/chrome-devtools-mcp-cli-options.js'; +import type {ParsedArguments} from '../bin/brave-devtools-mcp-cli-options.js'; import type {AggregatedInfoWithUid} from '../HeapSnapshotManager.js'; import type {McpPage} from '../McpPage.js'; import {zod} from '../third_party/index.js'; diff --git a/src/tools/screencast.ts b/src/tools/screencast.ts index ce7143425..c47b10bf6 100644 --- a/src/tools/screencast.ts +++ b/src/tools/screencast.ts @@ -16,7 +16,7 @@ import {ToolCategory} from './categories.js'; import {definePageTool} from './ToolDefinition.js'; async function generateTempFilePath(): Promise { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), 'chrome-devtools-mcp-')); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), 'brave-devtools-mcp-')); return path.join(dir, `screencast.mp4`); } diff --git a/src/tools/tools.ts b/src/tools/tools.ts index b3477b906..37418198f 100644 --- a/src/tools/tools.ts +++ b/src/tools/tools.ts @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import type {ParsedArguments} from '../bin/chrome-devtools-mcp-cli-options.js'; +import type {ParsedArguments} from '../bin/brave-devtools-mcp-cli-options.js'; import * as consoleTools from './console.js'; import * as emulationTools from './emulation.js'; diff --git a/src/utils/check-for-updates.ts b/src/utils/check-for-updates.ts index c1e59e0bb..8bde4a45a 100644 --- a/src/utils/check-for-updates.ts +++ b/src/utils/check-for-updates.ts @@ -25,7 +25,7 @@ export function resetUpdateCheckFlagForTesting() { } export async function checkForUpdates(message: string) { - if (isChecking || process.env['CHROME_DEVTOOLS_MCP_NO_UPDATE_CHECKS']) { + if (isChecking || process.env['BRAVE_DEVTOOLS_MCP_NO_UPDATE_CHECKS']) { return; } isChecking = true; @@ -33,7 +33,7 @@ export async function checkForUpdates(message: string) { const cachePath = path.join( os.homedir(), '.cache', - 'chrome-devtools-mcp', + 'brave-devtools-mcp', 'latest.json', ); diff --git a/src/utils/files.ts b/src/utils/files.ts index 00083dfe1..e0b6097a4 100644 --- a/src/utils/files.ts +++ b/src/utils/files.ts @@ -9,7 +9,7 @@ import os from 'node:os'; import path from 'node:path'; export async function getTempFilePath(filename: string) { - const dir = await fs.mkdtemp(path.join(os.tmpdir(), 'chrome-devtools-mcp-')); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), 'brave-devtools-mcp-')); const filepath = path.join(dir, filename); return filepath; diff --git a/src/version.ts b/src/version.ts index adc5a5696..52d66ea4a 100644 --- a/src/version.ts +++ b/src/version.ts @@ -4,7 +4,4 @@ * SPDX-License-Identifier: Apache-2.0 */ -// If moved update release-please config -// x-release-please-start-version -export const VERSION = '0.23.0'; -// x-release-please-end +export const VERSION = '0.2.2'; diff --git a/tests/McpResponse.test.ts b/tests/McpResponse.test.ts index 295450b49..00b1be869 100644 --- a/tests/McpResponse.test.ts +++ b/tests/McpResponse.test.ts @@ -12,7 +12,7 @@ import {describe, it} from 'node:test'; import sinon from 'sinon'; -import type {ParsedArguments} from '../src/bin/chrome-devtools-mcp-cli-options.js'; +import type {ParsedArguments} from '../src/bin/brave-devtools-mcp-cli-options.js'; import type {McpContext} from '../src/McpContext.js'; import type {McpResponse} from '../src/McpResponse.js'; import {replaceHtmlElementsWithUids} from '../src/McpResponse.js'; diff --git a/tests/browser.test.ts b/tests/browser.test.ts index b0835bf96..edaab6f0b 100644 --- a/tests/browser.test.ts +++ b/tests/browser.test.ts @@ -86,7 +86,7 @@ describe('browser', () => { userDataDir: folderPath, executablePath: executablePath(), devtools: false, - chromeArgs: ['--remote-debugging-port=0'], + braveArgs: ['--remote-debugging-port=0'], }); try { const connectedBrowser = await ensureBrowserConnected({ diff --git a/tests/check-for-updates.test.ts b/tests/check-for-updates.test.ts index 13a8fc039..e86e082e5 100644 --- a/tests/check-for-updates.test.ts +++ b/tests/check-for-updates.test.ts @@ -31,8 +31,8 @@ describe('checkForUpdates', () => { resetUpdateCheckFlagForTesting(); }); - it('does nothing if CHROME_DEVTOOLS_MCP_NO_UPDATE_CHECKS is set', async () => { - process.env['CHROME_DEVTOOLS_MCP_NO_UPDATE_CHECKS'] = 'true'; + it('does nothing if BRAVE_DEVTOOLS_MCP_NO_UPDATE_CHECKS is set', async () => { + process.env['BRAVE_DEVTOOLS_MCP_NO_UPDATE_CHECKS'] = 'true'; const warnStub = sinon.stub(console, 'warn'); const spawnStub = sinon.stub(child_process, 'spawn'); @@ -46,7 +46,7 @@ describe('checkForUpdates', () => { assert.ok(readFileStub.notCalled); assert.ok(statStub.notCalled); - delete process.env['CHROME_DEVTOOLS_MCP_NO_UPDATE_CHECKS']; + delete process.env['BRAVE_DEVTOOLS_MCP_NO_UPDATE_CHECKS']; }); it('notifies if cache exists and version is different', async () => { diff --git a/tests/cli.test.ts b/tests/cli.test.ts index 95f9da824..b3530acdc 100644 --- a/tests/cli.test.ts +++ b/tests/cli.test.ts @@ -7,7 +7,7 @@ import assert from 'node:assert'; import {describe, it} from 'node:test'; -import {parseArguments} from '../src/bin/chrome-devtools-mcp-cli-options.js'; +import {parseArguments} from '../src/bin/brave-devtools-mcp-cli-options.js'; describe('cli args parsing', () => { const defaultArgs = { @@ -23,8 +23,8 @@ describe('cli args parsing', () => { autoConnect: undefined, 'performance-crux': true, performanceCrux: true, - 'usage-statistics': true, - usageStatistics: true, + 'usage-statistics': false, + usageStatistics: false, 'redact-network-headers': false, redactNetworkHeaders: false, }; @@ -35,8 +35,8 @@ describe('cli args parsing', () => { ...defaultArgs, _: [], headless: false, - $0: 'npx chrome-devtools-mcp@latest', - channel: 'stable', + $0: 'npx brave-devtools-mcp@latest', + channel: 'release', }); }); @@ -51,7 +51,7 @@ describe('cli args parsing', () => { ...defaultArgs, _: [], headless: false, - $0: 'npx chrome-devtools-mcp@latest', + $0: 'npx brave-devtools-mcp@latest', 'browser-url': 'http://localhost:3000', browserUrl: 'http://localhost:3000', u: 'http://localhost:3000', @@ -63,16 +63,16 @@ describe('cli args parsing', () => { 'node', 'main.js', '--user-data-dir', - '/tmp/chrome-profile', + '/tmp/brave-profile', ]); assert.deepStrictEqual(args, { ...defaultArgs, _: [], headless: false, - $0: 'npx chrome-devtools-mcp@latest', - channel: 'stable', - 'user-data-dir': '/tmp/chrome-profile', - userDataDir: '/tmp/chrome-profile', + $0: 'npx brave-devtools-mcp@latest', + channel: 'release', + 'user-data-dir': '/tmp/brave-profile', + userDataDir: '/tmp/brave-profile', }); }); @@ -87,11 +87,11 @@ describe('cli args parsing', () => { ...defaultArgs, _: [], headless: false, - $0: 'npx chrome-devtools-mcp@latest', + $0: 'npx brave-devtools-mcp@latest', 'browser-url': undefined, browserUrl: undefined, u: undefined, - channel: 'stable', + channel: 'release', }); }); @@ -100,16 +100,16 @@ describe('cli args parsing', () => { 'node', 'main.js', '--executablePath', - '/tmp/test 123/chrome', + '/tmp/test 123/brave', ]); assert.deepStrictEqual(args, { ...defaultArgs, _: [], headless: false, - $0: 'npx chrome-devtools-mcp@latest', - 'executable-path': '/tmp/test 123/chrome', - e: '/tmp/test 123/chrome', - executablePath: '/tmp/test 123/chrome', + $0: 'npx brave-devtools-mcp@latest', + 'executable-path': '/tmp/test 123/brave', + e: '/tmp/test 123/brave', + executablePath: '/tmp/test 123/brave', }); }); @@ -124,8 +124,8 @@ describe('cli args parsing', () => { ...defaultArgs, _: [], headless: false, - $0: 'npx chrome-devtools-mcp@latest', - channel: 'stable', + $0: 'npx brave-devtools-mcp@latest', + channel: 'release', viewport: { width: 888, height: 777, @@ -133,42 +133,42 @@ describe('cli args parsing', () => { }); }); - it('parses chrome args', async () => { + it('parses brave args', async () => { const args = parseArguments('1.0.0', [ 'node', 'main.js', - `--chrome-arg='--no-sandbox'`, - `--chrome-arg='--disable-setuid-sandbox'`, + `--brave-arg='--no-sandbox'`, + `--brave-arg='--disable-setuid-sandbox'`, ]); assert.deepStrictEqual(args, { ...defaultArgs, _: [], headless: false, - $0: 'npx chrome-devtools-mcp@latest', - channel: 'stable', - 'chrome-arg': ['--no-sandbox', '--disable-setuid-sandbox'], - chromeArg: ['--no-sandbox', '--disable-setuid-sandbox'], + $0: 'npx brave-devtools-mcp@latest', + channel: 'release', + 'brave-arg': ['--no-sandbox', '--disable-setuid-sandbox'], + braveArg: ['--no-sandbox', '--disable-setuid-sandbox'], }); }); - it('parses ignore chrome args', async () => { + it('parses ignore brave args', async () => { const args = parseArguments('1.0.0', [ 'node', 'main.js', - `--ignore-default-chrome-arg='--disable-extensions'`, - `--ignore-default-chrome-arg='--disable-cancel-all-touches'`, + `--ignore-default-brave-arg='--disable-extensions'`, + `--ignore-default-brave-arg='--disable-cancel-all-touches'`, ]); assert.deepStrictEqual(args, { ...defaultArgs, _: [], headless: false, - $0: 'npx chrome-devtools-mcp@latest', - channel: 'stable', - 'ignore-default-chrome-arg': [ + $0: 'npx brave-devtools-mcp@latest', + channel: 'release', + 'ignore-default-brave-arg': [ '--disable-extensions', '--disable-cancel-all-touches', ], - ignoreDefaultChromeArg: [ + ignoreDefaultBraveArg: [ '--disable-extensions', '--disable-cancel-all-touches', ], @@ -186,7 +186,7 @@ describe('cli args parsing', () => { ...defaultArgs, _: [], headless: false, - $0: 'npx chrome-devtools-mcp@latest', + $0: 'npx brave-devtools-mcp@latest', 'ws-endpoint': 'ws://127.0.0.1:9222/devtools/browser/abc123', wsEndpoint: 'ws://127.0.0.1:9222/devtools/browser/abc123', w: 'ws://127.0.0.1:9222/devtools/browser/abc123', @@ -204,7 +204,7 @@ describe('cli args parsing', () => { ...defaultArgs, _: [], headless: false, - $0: 'npx chrome-devtools-mcp@latest', + $0: 'npx brave-devtools-mcp@latest', 'ws-endpoint': 'wss://example.com:9222/devtools/browser/abc123', wsEndpoint: 'wss://example.com:9222/devtools/browser/abc123', w: 'wss://example.com:9222/devtools/browser/abc123', @@ -236,8 +236,8 @@ describe('cli args parsing', () => { ...defaultArgs, _: [], headless: false, - $0: 'npx chrome-devtools-mcp@latest', - channel: 'stable', + $0: 'npx brave-devtools-mcp@latest', + channel: 'release', 'category-emulation': false, categoryEmulation: false, }); @@ -248,19 +248,17 @@ describe('cli args parsing', () => { ...defaultArgs, _: [], headless: false, - $0: 'npx chrome-devtools-mcp@latest', - channel: 'stable', + $0: 'npx brave-devtools-mcp@latest', + channel: 'release', 'auto-connect': true, autoConnect: true, }); }); it('parses usage statistics flag', async () => { - // Test default (should be true). const defaultArgs = parseArguments('1.0.0', ['node', 'main.js']); - assert.strictEqual(defaultArgs.usageStatistics, true); + assert.strictEqual(defaultArgs.usageStatistics, false); - // Test enabling it const enabledArgs = parseArguments('1.0.0', [ 'node', 'main.js', @@ -268,7 +266,6 @@ describe('cli args parsing', () => { ]); assert.strictEqual(enabledArgs.usageStatistics, true); - // Test disabling it const disabledArgs = parseArguments('1.0.0', [ 'node', 'main.js', @@ -281,7 +278,6 @@ describe('cli args parsing', () => { const defaultArgs = parseArguments('1.0.0', ['node', 'main.js']); assert.strictEqual(defaultArgs.performanceCrux, true); - // force enable const enabledArgs = parseArguments('1.0.0', [ 'node', 'main.js', diff --git a/tests/daemon/utils.test.ts b/tests/daemon/utils.test.ts index 4be3baa27..123d60fd8 100644 --- a/tests/daemon/utils.test.ts +++ b/tests/daemon/utils.test.ts @@ -7,7 +7,7 @@ import assert from 'node:assert'; import {describe, it} from 'node:test'; -import type {ParsedArguments} from '../../src/bin/chrome-devtools-mcp-cli-options.js'; +import type {ParsedArguments} from '../../src/bin/brave-devtools-mcp-cli-options.js'; import {serializeArgs} from '../../src/daemon/utils.js'; import type {YargsOptions} from '../../src/third_party/index.js'; diff --git a/tests/e2e/brave-integration.test.html b/tests/e2e/brave-integration.test.html new file mode 100644 index 000000000..97f7ebdea --- /dev/null +++ b/tests/e2e/brave-integration.test.html @@ -0,0 +1,26 @@ + +Brave MCP Test Page + +

Brave DevTools MCP Test

+
+ + + + + + + + + + +
+
Drag
+
Drop
+
+ + + diff --git a/tests/e2e/brave-integration.test.mjs b/tests/e2e/brave-integration.test.mjs new file mode 100644 index 000000000..c1dc06ebb --- /dev/null +++ b/tests/e2e/brave-integration.test.mjs @@ -0,0 +1,452 @@ +/** + * Brave DevTools MCP — Integration Test Suite + * + * Tests all 29 MCP tools against a running Brave instance. + * + * Prerequisites: + * 1. Build the project: npm run build + * 2. Launch Brave with remote debugging: + * open -a "Brave Browser" --args --remote-debugging-port=9222 + * 3. Run: npm run test:brave + * + * The test opens a local HTML fixture, exercises every tool, then cleans up. + */ + +import {Client} from '@modelcontextprotocol/sdk/client/index.js'; +import {StdioClientTransport} from '@modelcontextprotocol/sdk/client/stdio.js'; +import path from 'node:path'; +import {fileURLToPath} from 'node:url'; +import fs from 'node:fs'; +import os from 'node:os'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const SERVER_PATH = path.resolve(__dirname, '../../build/src/bin/brave-devtools-mcp.js'); +const FIXTURE_PATH = path.resolve(__dirname, 'brave-integration.test.html'); +const TMP = os.tmpdir(); + +const TOOL_TIMEOUT_MS = 30_000; +const PERF_TIMEOUT_MS = 60_000; + +async function withTimeout(promise, ms, label) { + let timer; + const timeout = new Promise((_, reject) => { + timer = setTimeout(() => reject(new Error(`Timed out after ${ms}ms`)), ms); + }); + try { + return await Promise.race([promise, timeout]); + } finally { + clearTimeout(timer); + } +} + +const transport = new StdioClientTransport({ + command: process.execPath, + args: [ + SERVER_PATH, + '--browserUrl', 'http://127.0.0.1:9222', + '--no-usage-statistics', + '--no-performance-crux', + ], +}); + +const client = new Client({name: 'brave-integration-test', version: '1.0.0'}); +await client.connect(transport); + +const passed = []; +const failed = []; +const skipped = []; + +async function test(name, fn, timeoutMs = TOOL_TIMEOUT_MS) { + try { + const result = await withTimeout(fn(), timeoutMs, name); + const text = result?.content?.map(c => c.text || '[image]').join(' ') || ''; + if (result?.isError) { + failed.push({name, error: text.slice(0, 300)}); + console.log(` FAIL ${name}`); + console.log(` ${text.slice(0, 200)}`); + } else { + passed.push(name); + console.log(` PASS ${name}`); + } + return {result, text}; + } catch (e) { + failed.push({name, error: e.message?.slice(0, 300)}); + console.log(` FAIL ${name}`); + console.log(` ${e.message?.slice(0, 200)}`); + return {result: null, text: ''}; + } +} + +function skip(name, reason) { + skipped.push({name, reason}); + console.log(` SKIP ${name}: ${reason}`); +} + +function findUid(snapText, label) { + for (const line of snapText.split('\n')) { + if (line.includes(label)) { + const m = line.match(/uid=(\S+)/); + if (m) return m[1]; + } + } + return null; +} + +async function call(name, args) { + return client.callTool({name, arguments: args}); +} + +console.log(''); +console.log('================================================'); +console.log(' BRAVE DEVTOOLS MCP — INTEGRATION TEST SUITE'); +console.log('================================================'); +console.log(''); + +let testPageId = null; + +// ── 1. Navigation & Pages (tools: new_page, list_pages, select_page, navigate_page) ── + +console.log('--- Navigation & Pages ---'); + +await test('01. new_page', () => + call('new_page', {url: `file://${FIXTURE_PATH}`}) +); + +{ + const {text} = await test('02. list_pages', () => + call('list_pages', {}) + ); + const match = text.match(/(\d+):.*brave-integration\.test\.html/); + testPageId = match ? parseInt(match[1]) : null; + if (testPageId === null) { + console.log(' WARN Could not find test page ID in list_pages output'); + } +} + +if (testPageId !== null) { + await test('03. select_page', () => + call('select_page', {pageId: testPageId}) + ); +} else { + skip('03. select_page', 'test page not found'); +} + +await test('04. navigate_page (reload)', () => + call('navigate_page', {type: 'reload'}) +); + +await new Promise(r => setTimeout(r, 1500)); + +// ── 2. Snapshots & Screenshots (tools: take_snapshot, take_screenshot) ── + +console.log('\n--- Snapshots & Screenshots ---'); + +let snapText = ''; +{ + const {text} = await test('05. take_snapshot', () => + call('take_snapshot', {}) + ); + snapText = text; +} + +await test('06. take_screenshot (png)', () => + call('take_screenshot', {filePath: path.join(TMP, 'brave-mcp-test.png')}) +); + +await test('07. take_screenshot (jpeg + quality)', () => + call('take_screenshot', {format: 'jpeg', quality: 80, filePath: path.join(TMP, 'brave-mcp-test.jpg')}) +); + +await test('08. take_screenshot (fullPage)', () => + call('take_screenshot', {fullPage: true, filePath: path.join(TMP, 'brave-mcp-test-full.png')}) +); + +// ── 3. Script Execution (tool: evaluate_script) ── + +console.log('\n--- Script Execution ---'); + +await test('09. evaluate_script (return value)', () => + call('evaluate_script', {function: '() => document.title'}) +); + +await test('10. evaluate_script (DOM access)', () => + call('evaluate_script', {function: '() => document.getElementById("heading").textContent'}) +); + +// ── 4. Input Automation (tools: click, fill, fill_form, hover, type_text, press_key, drag, upload_file) ── + +console.log('\n--- Input Automation ---'); + +const nameUid = findUid(snapText, 'textbox "Name"'); +const emailUid = findUid(snapText, 'textbox "Email"'); +const browserSelectUid = findUid(snapText, 'combobox "Browser"') || findUid(snapText, 'combobox'); +const headingUid = findUid(snapText, 'heading "Brave DevTools MCP Test"'); +const dragUid = findUid(snapText, 'StaticText "Drag"'); +const dropUid = findUid(snapText, 'StaticText "Drop"'); +const submitUid = findUid(snapText, 'button "Submit"'); + +if (nameUid) { + await test('11. click', () => + call('click', {uid: nameUid}) + ); + await test('12. fill (text input)', () => + call('fill', {uid: nameUid, value: 'Test User'}) + ); +} else { + skip('11. click', 'name input uid not found in snapshot'); + skip('12. fill (text input)', 'name input uid not found in snapshot'); +} + +if (emailUid) { + await test('13. fill (email input)', () => + call('fill', {uid: emailUid, value: 'test@brave.com'}) + ); +} else { + skip('13. fill (email input)', 'email input uid not found in snapshot'); +} + +if (browserSelectUid) { + await test('14. fill (select)', () => + call('fill', {uid: browserSelectUid, value: 'Chrome'}) + ); +} else { + skip('14. fill (select)', 'select uid not found in snapshot'); +} + +if (nameUid && emailUid) { + await test('15. fill_form (multi-field)', () => + call('fill_form', { + elements: [ + {uid: nameUid, value: 'Emanuele'}, + {uid: emailUid, value: 'ema@brave.test'}, + ], + }) + ); +} else { + skip('15. fill_form (multi-field)', 'form input uids not found'); +} + +if (headingUid) { + await test('16. hover', () => + call('hover', {uid: headingUid}) + ); +} else { + skip('16. hover', 'heading uid not found'); +} + +await test('17. type_text', () => + call('type_text', {text: 'Hello Brave!'}) +); + +await test('18. press_key (single)', () => + call('press_key', {key: 'Tab'}) +); + +await test('19. press_key (combo)', () => + call('press_key', {key: 'Control+A'}) +); + +if (dragUid && dropUid) { + await test('20. drag', () => + call('drag', {from_uid: dragUid, to_uid: dropUid}) + ); +} else { + skip('20. drag', `drag/drop uids not found (drag=${dragUid}, drop=${dropUid})`); +} + +const fileUid = findUid(snapText, 'button "Choose File"') || findUid(snapText, 'fileupload'); + +if (fileUid) { + await test('21. upload_file', () => + call('upload_file', {uid: fileUid, filePath: FIXTURE_PATH}) + ); +} else { + skip('21. upload_file', 'file input uid not found in snapshot'); +} + +// ── 5. Dialog (tool: handle_dialog) ── + +console.log('\n--- Dialog ---'); + +// Trigger an alert with a long delay so the evaluate_script returns first, +// then wait for the dialog to appear before calling handle_dialog. +await call('evaluate_script', {function: '() => { window.__dialogTimer = setTimeout(() => alert("Test dialog"), 500); return "timer set"; }'}); +await new Promise(r => setTimeout(r, 2000)); + +await test('22. handle_dialog (accept)', () => + call('handle_dialog', {action: 'accept'}) +); + +// ── 6. Wait (tool: wait_for) ── + +console.log('\n--- Wait ---'); + +await test('23. wait_for', () => + call('wait_for', {text: ['Brave DevTools MCP Test'], timeout: 5000}) +); + +// ── 7. Console (tools: list_console_messages, get_console_message) ── + +console.log('\n--- Console ---'); + +{ + const {text} = await test('24. list_console_messages', () => + call('list_console_messages', {}) + ); + const msgMatch = text.match(/msgid=(\d+)/); + if (msgMatch) { + await test('25. get_console_message', () => + call('get_console_message', {msgid: parseInt(msgMatch[1])}) + ); + } else { + skip('25. get_console_message', 'no console messages captured'); + } +} + +// ── 8. Network (tools: list_network_requests, get_network_request) ── + +console.log('\n--- Network ---'); + +{ + const {text} = await test('26. list_network_requests', () => + call('list_network_requests', {}) + ); + const reqMatch = text.match(/reqid=(\d+)/); + if (reqMatch) { + await test('27. get_network_request', () => + call('get_network_request', {reqid: parseInt(reqMatch[1])}) + ); + } else { + skip('27. get_network_request', 'no network requests captured'); + } +} + +// ── 9. Emulation (tools: emulate, resize_page) ── + +console.log('\n--- Emulation ---'); + +await test('28. emulate (dark mode)', () => + call('emulate', {colorScheme: 'dark'}) +); + +await test('29. emulate (reset)', () => + call('emulate', {colorScheme: 'auto'}) +); + +await test('30. resize_page', () => + call('resize_page', {width: 1024, height: 768}) +); + +// ── 10. Performance (tools: performance_start_trace, performance_stop_trace, performance_analyze_insight) ── +// Navigate to a real page so the trace produces network/rendering insights. + +console.log('\n--- Performance ---'); + +await call('navigate_page', {type: 'url', url: 'https://example.com'}); +await new Promise(r => setTimeout(r, 2000)); + +const tracePath = path.join(TMP, 'brave-mcp-test-trace.json'); + +// start_trace with autoStop returns the trace summary including insight set IDs. +// stop_trace returns only the visualization image. +{ + const {text: startText} = await test('31. performance_start_trace', () => + call('performance_start_trace', {reload: true, autoStop: true, filePath: tracePath}), + PERF_TIMEOUT_MS, + ); + + await test('32. performance_stop_trace', () => + call('performance_stop_trace', {filePath: path.join(TMP, 'brave-mcp-test-trace.json.gz')}), + PERF_TIMEOUT_MS, + ); + + // The start_trace output contains: "## insight set id: NAVIGATION_0" + const insightSetMatch = startText.match(/insight set id:\s*(\S+)/); + // Available insight names from the trace (e.g., LCPBreakdown, NetworkDependencyTree) + const insightNameMatch = startText.match(/insight name:\s*(\S+)/); + + if (insightSetMatch && insightNameMatch) { + await test('33. performance_analyze_insight', () => + call('performance_analyze_insight', { + insightSetId: insightSetMatch[1], + insightName: insightNameMatch[1], + }), + PERF_TIMEOUT_MS, + ); + } else { + failed.push({name: '33. performance_analyze_insight', error: `insight set or name not found (set=${insightSetMatch?.[1]}, name=${insightNameMatch?.[1]})`}); + console.log(' FAIL 33. performance_analyze_insight'); + console.log(` insight set or name not found in trace output`); + } +} + +// Navigate back to test fixture for remaining tests +await call('navigate_page', {type: 'url', url: `file://${FIXTURE_PATH}`}); +await new Promise(r => setTimeout(r, 1000)); + +// ── 11. Memory (tool: take_memory_snapshot) ── + +console.log('\n--- Memory ---'); + +const heapPath = path.join(TMP, 'brave-mcp-test-heap.heapsnapshot'); +await test('34. take_memory_snapshot', () => + call('take_memory_snapshot', {filePath: heapPath}), + PERF_TIMEOUT_MS, +); + +// ── 12. Lighthouse (tool: lighthouse_audit) ── + +console.log('\n--- Lighthouse ---'); + +await test('35. lighthouse_audit', () => + call('lighthouse_audit', {mode: 'snapshot', device: 'desktop', outputDirPath: TMP}), + PERF_TIMEOUT_MS, +); + +// ── 13. Cleanup (tool: close_page) ── + +console.log('\n--- Cleanup ---'); + +if (testPageId !== null) { + await test('36. close_page', () => + call('close_page', {pageId: testPageId}) + ); +} + +for (const f of [ + path.join(TMP, 'brave-mcp-test.png'), + path.join(TMP, 'brave-mcp-test.jpg'), + path.join(TMP, 'brave-mcp-test-full.png'), + tracePath, + path.join(TMP, 'brave-mcp-test-trace.json.gz'), + heapPath, +]) { + try { fs.unlinkSync(f); } catch { /* ignore */ } +} + +// ── Report ────────────────────────────────────── + +const total = passed.length + failed.length + skipped.length; +console.log(''); +console.log('================================================'); +console.log(` RESULTS: ${passed.length} passed, ${failed.length} failed, ${skipped.length} skipped (${total} total)`); +console.log('================================================'); + +if (failed.length > 0) { + console.log('\nFailed:'); + for (const f of failed) { + console.log(` ${f.name}`); + console.log(` ${f.error.slice(0, 250)}`); + } +} + +if (skipped.length > 0) { + console.log('\nSkipped:'); + for (const s of skipped) { + console.log(` ${s.name}: ${s.reason}`); + } +} + +console.log(''); +await client.close(); +process.exit(failed.length > 0 ? 1 : 0); diff --git a/tests/e2e/chrome-devtools-disclaimers.test.ts b/tests/e2e/chrome-devtools-disclaimers.test.ts index 7810b4f8e..ea26b2e7c 100644 --- a/tests/e2e/chrome-devtools-disclaimers.test.ts +++ b/tests/e2e/chrome-devtools-disclaimers.test.ts @@ -32,7 +32,7 @@ describe('chrome-devtools', () => { `start command failed: ${result.stderr}`, ); assert( - result.stderr.includes('chrome-devtools-mcp exposes content'), + result.stderr.includes('brave-devtools-mcp exposes content'), 'Disclaimer not found in stderr on start', ); }); diff --git a/tests/e2e/telemetry.test.ts b/tests/e2e/telemetry.test.ts index dc02a4a25..a1ebd052d 100644 --- a/tests/e2e/telemetry.test.ts +++ b/tests/e2e/telemetry.test.ts @@ -13,7 +13,7 @@ import {describe, it} from 'node:test'; import type {ChromeDevToolsMcpExtension} from '../../src/telemetry/types'; -const SERVER_PATH = path.resolve('build/src/bin/chrome-devtools-mcp.js'); +const SERVER_PATH = path.resolve('build/src/bin/brave-devtools-mcp.js'); interface MockServerContext { server: http.Server; diff --git a/tests/index.test.ts b/tests/index.test.ts index fae2d2e85..e7b7a20c7 100644 --- a/tests/index.test.ts +++ b/tests/index.test.ts @@ -31,7 +31,7 @@ describe('e2e', () => { const transport = new StdioClientTransport({ command: 'node', args: [ - 'build/src/bin/chrome-devtools-mcp.js', + 'build/src/bin/brave-devtools-mcp.js', '--headless', '--isolated', '--executable-path', diff --git a/tests/telemetry/flagUtils.test.ts b/tests/telemetry/flagUtils.test.ts index 692ec0746..3e05577a9 100644 --- a/tests/telemetry/flagUtils.test.ts +++ b/tests/telemetry/flagUtils.test.ts @@ -7,7 +7,7 @@ import assert from 'node:assert/strict'; import {describe, it} from 'node:test'; -import type {cliOptions} from '../../src/bin/chrome-devtools-mcp-cli-options.js'; +import type {cliOptions} from '../../src/bin/brave-devtools-mcp-cli-options.js'; import { computeFlagUsage, getPossibleFlagMetrics, diff --git a/tests/third_party_notices.test.js.snapshot b/tests/third_party_notices.test.js.snapshot index ca5c749e4..ea1ca84bf 100644 --- a/tests/third_party_notices.test.js.snapshot +++ b/tests/third_party_notices.test.js.snapshot @@ -1,31 +1,4 @@ exports[`THIRD_PARTY_NOTICES > matches snapshot if exists 1`] = ` -Name: urlpattern-polyfill -URL: https://github.com/kenchris/urlpattern-polyfill -Version: -License: MIT - -Copyright 2020 Intel Corporation - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - --------------------- DEPENDENCY DIVIDER -------------------- - Name: core-js URL: https://core-js.io Version: @@ -321,30 +294,6 @@ Permission to use, copy, modify, and/or distribute this software for any purpose THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. --------------------- DEPENDENCY DIVIDER -------------------- - -Name: semver -URL: git+https://github.com/npm/node-semver.git -Version: -License: ISC - -The ISC License - -Copyright (c) Isaac Z. Schlueter and Contributors - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR -IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - -------------------- DEPENDENCY DIVIDER -------------------- Name: debug @@ -880,6 +829,30 @@ URL: https://github.com/puppeteer/puppeteer/tree/main/packages/browsers Version: License: Apache-2.0 +-------------------- DEPENDENCY DIVIDER -------------------- + +Name: semver +URL: git+https://github.com/npm/node-semver.git +Version: +License: ISC + +The ISC License + +Copyright (c) Isaac Z. Schlueter and Contributors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + -------------------- DEPENDENCY DIVIDER -------------------- Name: proxy-agent diff --git a/tests/tools/console.test.ts b/tests/tools/console.test.ts index 90c23de23..263309da4 100644 --- a/tests/tools/console.test.ts +++ b/tests/tools/console.test.ts @@ -7,7 +7,7 @@ import assert from 'node:assert'; import {before, describe, it} from 'node:test'; -import type {ParsedArguments} from '../../src/bin/chrome-devtools-mcp-cli-options.js'; +import type {ParsedArguments} from '../../src/bin/brave-devtools-mcp-cli-options.js'; import {loadIssueDescriptions} from '../../src/issue-descriptions.js'; import {McpResponse} from '../../src/McpResponse.js'; import {TextSnapshot} from '../../src/TextSnapshot.js'; diff --git a/tests/tools/extensions.test.ts b/tests/tools/extensions.test.ts index 59580ddd8..788dc78ae 100644 --- a/tests/tools/extensions.test.ts +++ b/tests/tools/extensions.test.ts @@ -10,7 +10,7 @@ import {afterEach, describe, it} from 'node:test'; import sinon from 'sinon'; -import type {ParsedArguments} from '../../src/bin/chrome-devtools-mcp-cli-options.js'; +import type {ParsedArguments} from '../../src/bin/brave-devtools-mcp-cli-options.js'; import {listConsoleMessages} from '../../src/tools/console.js'; import { installExtension, diff --git a/tests/tools/inPage.test.ts b/tests/tools/inPage.test.ts index 413efe396..fd0a4b36c 100644 --- a/tests/tools/inPage.test.ts +++ b/tests/tools/inPage.test.ts @@ -9,7 +9,7 @@ import {describe, it} from 'node:test'; import sinon from 'sinon'; -import type {ParsedArguments} from '../../src/bin/chrome-devtools-mcp-cli-options.js'; +import type {ParsedArguments} from '../../src/bin/brave-devtools-mcp-cli-options.js'; import type {McpContext} from '../../src/McpContext.js'; import type {McpResponse} from '../../src/McpResponse.js'; import {TextSnapshot} from '../../src/TextSnapshot.js'; diff --git a/tests/tools/input.test.ts b/tests/tools/input.test.ts index b0033ec4d..4f61aab57 100644 --- a/tests/tools/input.test.ts +++ b/tests/tools/input.test.ts @@ -9,7 +9,7 @@ import fs from 'node:fs/promises'; import path from 'node:path'; import {describe, it} from 'node:test'; -import type {ParsedArguments} from '../../src/bin/chrome-devtools-mcp-cli-options.js'; +import type {ParsedArguments} from '../../src/bin/brave-devtools-mcp-cli-options.js'; import {McpResponse} from '../../src/McpResponse.js'; import {TextSnapshot} from '../../src/TextSnapshot.js'; import { diff --git a/tests/tools/pages.test.ts b/tests/tools/pages.test.ts index f1128afd2..5b194bcd9 100644 --- a/tests/tools/pages.test.ts +++ b/tests/tools/pages.test.ts @@ -11,7 +11,7 @@ import {afterEach, describe, it} from 'node:test'; import type {Dialog} from 'puppeteer-core'; import sinon from 'sinon'; -import type {ParsedArguments} from '../../src/bin/chrome-devtools-mcp-cli-options.js'; +import type {ParsedArguments} from '../../src/bin/brave-devtools-mcp-cli-options.js'; import { listPages, newPage, diff --git a/tests/tools/pagesNavigateAllowlist.test.ts b/tests/tools/pagesNavigateAllowlist.test.ts index 98da02d79..b644eae60 100644 --- a/tests/tools/pagesNavigateAllowlist.test.ts +++ b/tests/tools/pagesNavigateAllowlist.test.ts @@ -7,7 +7,7 @@ import assert from 'node:assert'; import {describe, it} from 'node:test'; -import type {ParsedArguments} from '../../src/bin/chrome-devtools-mcp-cli-options.js'; +import type {ParsedArguments} from '../../src/bin/brave-devtools-mcp-cli-options.js'; import {navigatePage} from '../../src/tools/pages.js'; import {serverHooks} from '../server.js'; import {withMcpContext} from '../utils.js'; diff --git a/tests/tools/screencast.test.ts b/tests/tools/screencast.test.ts index d60ec7db1..75f23dd57 100644 --- a/tests/tools/screencast.test.ts +++ b/tests/tools/screencast.test.ts @@ -9,7 +9,7 @@ import {describe, it, afterEach} from 'node:test'; import sinon from 'sinon'; -import type {ParsedArguments} from '../../src/bin/chrome-devtools-mcp-cli-options.js'; +import type {ParsedArguments} from '../../src/bin/brave-devtools-mcp-cli-options.js'; import {startScreencast, stopScreencast} from '../../src/tools/screencast.js'; import {withMcpContext} from '../utils.js'; diff --git a/tests/tools/script.test.ts b/tests/tools/script.test.ts index c87048fbe..b61fb692a 100644 --- a/tests/tools/script.test.ts +++ b/tests/tools/script.test.ts @@ -8,7 +8,7 @@ import assert from 'node:assert'; import path from 'node:path'; import {describe, it} from 'node:test'; -import type {ParsedArguments} from '../../src/bin/chrome-devtools-mcp-cli-options.js'; +import type {ParsedArguments} from '../../src/bin/brave-devtools-mcp-cli-options.js'; import {TextSnapshot} from '../../src/TextSnapshot.js'; import {installExtension} from '../../src/tools/extensions.js'; import {evaluateScript} from '../../src/tools/script.js'; diff --git a/tests/tools/webmcp.test.ts b/tests/tools/webmcp.test.ts index 5d91849f7..a31cce102 100644 --- a/tests/tools/webmcp.test.ts +++ b/tests/tools/webmcp.test.ts @@ -7,7 +7,7 @@ import assert from 'node:assert'; import {describe, it} from 'node:test'; -import type {ParsedArguments} from '../../src/bin/chrome-devtools-mcp-cli-options.js'; +import type {ParsedArguments} from '../../src/bin/brave-devtools-mcp-cli-options.js'; import type {McpPage} from '../../src/McpPage.js'; import {listPages, navigatePage, selectPage} from '../../src/tools/pages.js'; import {executeWebMcpTool} from '../../src/tools/webmcp.js'; diff --git a/tests/utils.ts b/tests/utils.ts index c8bc1a204..2ecd8f7fe 100644 --- a/tests/utils.ts +++ b/tests/utils.ts @@ -22,7 +22,7 @@ import type { } from 'puppeteer-core'; import sinon from 'sinon'; -import type {ParsedArguments} from '../src/bin/chrome-devtools-mcp-cli-options.js'; +import type {ParsedArguments} from '../src/bin/brave-devtools-mcp-cli-options.js'; import {McpContext} from '../src/McpContext.js'; import {McpResponse} from '../src/McpResponse.js'; import {TextSnapshot} from '../src/TextSnapshot.js'; @@ -350,7 +350,7 @@ export function getMockBrowser(): Browser { } as Browser; } -export const CLI_PATH = path.resolve('build/src/bin/chrome-devtools.js'); +export const CLI_PATH = path.resolve('build/src/bin/brave-devtools.js'); export async function runCli( args: string[], @@ -381,14 +381,14 @@ export async function assertDaemonIsNotRunning(sessionId?: string) { const result = await runCli(['status'], sessionId); assert.strictEqual( result.stdout, - 'chrome-devtools-mcp daemon is not running.\n', + 'brave-devtools-mcp daemon is not running.\n', ); } export async function assertDaemonIsRunning(sessionId?: string) { const result = await runCli(['status'], sessionId); assert.ok( - result.stdout.startsWith('chrome-devtools-mcp daemon is running.\n'), - 'chrome-devtools-mcp daemon is not running', + result.stdout.startsWith('brave-devtools-mcp daemon is running.\n'), + 'brave-devtools-mcp daemon is not running', ); }