brave-mcp 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +22 -5
  2. package/build/src/McpContext.js +12 -2
  3. package/build/src/McpPage.js +9 -4
  4. package/build/src/McpResponse.js +35 -17
  5. package/build/src/TextSnapshot.js +2 -2
  6. package/build/src/WaitForHelper.js +5 -0
  7. package/build/src/bin/brave-devtools-cli-options.js +228 -46
  8. package/build/src/bin/brave-devtools-mcp-cli-options.js +9 -5
  9. package/build/src/bin/brave-devtools-mcp-main.js +0 -5
  10. package/build/src/bin/brave-devtools.js +4 -13
  11. package/build/src/formatters/HeapSnapshotFormatter.js +3 -3
  12. package/build/src/index.js +93 -50
  13. package/build/src/telemetry/ClearcutLogger.js +12 -1
  14. package/build/src/third_party/index.js +2 -1
  15. package/build/src/third_party/issue-descriptions/genericFormModelContextMissingToolDescription.md +5 -0
  16. package/build/src/third_party/issue-descriptions/genericFormModelContextMissingToolName.md +5 -0
  17. package/build/src/third_party/issue-descriptions/genericFormModelContextParameterMissingName.md +5 -0
  18. package/build/src/third_party/issue-descriptions/genericFormModelContextParameterMissingTitleAndDescription.md +5 -0
  19. package/build/src/third_party/issue-descriptions/genericFormModelContextRequiredParameterMissingName.md +5 -0
  20. package/build/src/third_party/lighthouse-devtools-mcp-bundle.js +21716 -20261
  21. package/build/src/tools/categories.js +9 -3
  22. package/build/src/tools/console.js +2 -0
  23. package/build/src/tools/emulation.js +1 -0
  24. package/build/src/tools/extensions.js +5 -0
  25. package/build/src/tools/input.js +54 -1
  26. package/build/src/tools/lighthouse.js +15 -9
  27. package/build/src/tools/memory.js +4 -0
  28. package/build/src/tools/network.js +2 -0
  29. package/build/src/tools/pages.js +13 -5
  30. package/build/src/tools/performance.js +3 -0
  31. package/build/src/tools/screencast.js +4 -2
  32. package/build/src/tools/screenshot.js +1 -0
  33. package/build/src/tools/script.js +1 -0
  34. package/build/src/tools/slim/tools.js +3 -0
  35. package/build/src/tools/snapshot.js +2 -0
  36. package/build/src/tools/{inPage.js → thirdPartyDeveloper.js} +17 -17
  37. package/build/src/tools/tools.js +2 -2
  38. package/build/src/tools/webmcp.js +4 -4
  39. package/build/src/version.js +1 -1
  40. package/package.json +6 -7
  41. package/build/src/bin/cliDefinitions.js +0 -622
  42. package/build/src/third_party/THIRD_PARTY_NOTICES +0 -4297
  43. package/build/src/third_party/bundled-packages.json +0 -9
  44. package/build/src/utils/ExtensionRegistry.js +0 -35
package/README.md CHANGED
@@ -586,7 +586,7 @@ If you run into any issues, checkout our [troubleshooting guide](./docs/troubles
586
586
 
587
587
  <!-- BEGIN AUTO GENERATED TOOLS -->
588
588
 
589
- - **Input automation** (9 tools)
589
+ - **Input automation** (10 tools)
590
590
  - [`click`](docs/tool-reference.md#click)
591
591
  - [`drag`](docs/tool-reference.md#drag)
592
592
  - [`fill`](docs/tool-reference.md#fill)
@@ -596,6 +596,7 @@ If you run into any issues, checkout our [troubleshooting guide](./docs/troubles
596
596
  - [`press_key`](docs/tool-reference.md#press_key)
597
597
  - [`type_text`](docs/tool-reference.md#type_text)
598
598
  - [`upload_file`](docs/tool-reference.md#upload_file)
599
+ - [`click_at`](docs/tool-reference.md#click_at)
599
600
  - **Navigation automation** (6 tools)
600
601
  - [`close_page`](docs/tool-reference.md#close_page)
601
602
  - [`list_pages`](docs/tool-reference.md#list_pages)
@@ -613,21 +614,32 @@ If you run into any issues, checkout our [troubleshooting guide](./docs/troubles
613
614
  - **Network** (2 tools)
614
615
  - [`get_network_request`](docs/tool-reference.md#get_network_request)
615
616
  - [`list_network_requests`](docs/tool-reference.md#list_network_requests)
616
- - **Debugging** (6 tools)
617
+ - **Debugging** (8 tools)
617
618
  - [`evaluate_script`](docs/tool-reference.md#evaluate_script)
618
619
  - [`get_console_message`](docs/tool-reference.md#get_console_message)
619
620
  - [`lighthouse_audit`](docs/tool-reference.md#lighthouse_audit)
620
621
  - [`list_console_messages`](docs/tool-reference.md#list_console_messages)
621
622
  - [`take_screenshot`](docs/tool-reference.md#take_screenshot)
622
623
  - [`take_snapshot`](docs/tool-reference.md#take_snapshot)
624
+ - [`screencast_start`](docs/tool-reference.md#screencast_start)
625
+ - [`screencast_stop`](docs/tool-reference.md#screencast_stop)
626
+ - **Memory** (4 tools)
627
+ - [`take_memory_snapshot`](docs/tool-reference.md#take_memory_snapshot)
628
+ - [`get_memory_snapshot_details`](docs/tool-reference.md#get_memory_snapshot_details)
629
+ - [`get_nodes_by_class`](docs/tool-reference.md#get_nodes_by_class)
630
+ - [`load_memory_snapshot`](docs/tool-reference.md#load_memory_snapshot)
623
631
  - **Extensions** (5 tools)
624
632
  - [`install_extension`](docs/tool-reference.md#install_extension)
625
633
  - [`list_extensions`](docs/tool-reference.md#list_extensions)
626
634
  - [`reload_extension`](docs/tool-reference.md#reload_extension)
627
635
  - [`trigger_extension_action`](docs/tool-reference.md#trigger_extension_action)
628
636
  - [`uninstall_extension`](docs/tool-reference.md#uninstall_extension)
629
- - **Memory** (1 tools)
630
- - [`take_memory_snapshot`](docs/tool-reference.md#take_memory_snapshot)
637
+ - **Third-party** (2 tools)
638
+ - [`execute_3p_developer_tool`](docs/tool-reference.md#execute_3p_developer_tool)
639
+ - [`list_3p_developer_tools`](docs/tool-reference.md#list_3p_developer_tools)
640
+ - **WebMCP** (2 tools)
641
+ - [`execute_webmcp_tool`](docs/tool-reference.md#execute_webmcp_tool)
642
+ - [`list_webmcp_tools`](docs/tool-reference.md#list_webmcp_tools)
631
643
 
632
644
  <!-- END AUTO GENERATED TOOLS -->
633
645
 
@@ -704,7 +716,7 @@ The Brave DevTools MCP server supports the following configuration options:
704
716
  Path to ffmpeg executable for screencast recording.
705
717
  - **Type:** string
706
718
 
707
- - **`--experimentalWebmcp`/ `--experimental-webmcp`**
719
+ - **`--categoryExperimentalWebmcp`/ `--category-experimental-webmcp`**
708
720
  Set to true to enable debugging WebMCP tools. Requires Chrome 149+ with the following flags: `--enable-features=WebMCPTesting,DevToolsWebMCPSupport`
709
721
  - **Type:** boolean
710
722
 
@@ -736,6 +748,11 @@ The Brave DevTools MCP server supports the following configuration options:
736
748
  - **Type:** boolean
737
749
  - **Default:** `false`
738
750
 
751
+ - **`--categoryExperimentalThirdParty`/ `--category-experimental-third-party`**
752
+ Set to true to enable third-party developer tools exposed by the inspected page itself
753
+ - **Type:** boolean
754
+ - **Default:** `false`
755
+
739
756
  - **`--performanceCrux`/ `--performance-crux`**
740
757
  Set to false to disable sending URLs from performance traces to CrUX API to get field performance data.
741
758
  - **Type:** boolean
@@ -4,8 +4,9 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
  import fs from 'node:fs/promises';
7
+ import os from 'node:os';
7
8
  import path from 'node:path';
8
- import { fileURLToPath } from 'node:url';
9
+ import { fileURLToPath, pathToFileURL } from 'node:url';
9
10
  import { UniverseManager } from './DevtoolsUtils.js';
10
11
  import { HeapSnapshotManager } from './HeapSnapshotManager.js';
11
12
  import { McpPage } from './McpPage.js';
@@ -91,7 +92,16 @@ export class McpContext {
91
92
  return context;
92
93
  }
93
94
  roots() {
94
- return this.#roots;
95
+ if (this.#roots === undefined) {
96
+ return undefined;
97
+ }
98
+ return [
99
+ ...this.#roots,
100
+ {
101
+ uri: pathToFileURL(os.tmpdir()).href,
102
+ name: 'temp',
103
+ },
104
+ ];
95
105
  }
96
106
  setRoots(roots) {
97
107
  this.#roots = roots;
@@ -30,7 +30,7 @@ export class McpPage {
30
30
  // Dialog
31
31
  #dialog;
32
32
  #dialogHandler;
33
- inPageTools;
33
+ thirdPartyDeveloperTools;
34
34
  constructor(page, id) {
35
35
  this.pptrPage = page;
36
36
  this.id = id;
@@ -48,8 +48,13 @@ export class McpPage {
48
48
  clearDialog() {
49
49
  this.#dialog = undefined;
50
50
  }
51
- getInPageTools() {
52
- return this.inPageTools;
51
+ throwIfDialogOpen() {
52
+ if (this.#dialog) {
53
+ throw new Error(`A dialog is open (${this.#dialog.type()}: ${this.#dialog.message()}).`);
54
+ }
55
+ }
56
+ getThirdPartyDeveloperTools() {
57
+ return this.thirdPartyDeveloperTools;
53
58
  }
54
59
  getWebMcpTools() {
55
60
  return this.pptrPage.webmcp.tools();
@@ -83,7 +88,7 @@ export class McpPage {
83
88
  dispose() {
84
89
  this.pptrPage.off('dialog', this.#dialogHandler);
85
90
  }
86
- async executeInPageTool(toolName, params, response) {
91
+ async executeThirdPartyDeveloperTool(toolName, params, response) {
87
92
  // Creates array of ElementHandles from the UIDs in the params.
88
93
  // We do not replace the uids with the ElementsHandles yet, because
89
94
  // the `evaluate` function only turns them into DOM elements if they
@@ -5,6 +5,7 @@
5
5
  */
6
6
  import { ConsoleFormatter } from './formatters/ConsoleFormatter.js';
7
7
  import { HeapSnapshotFormatter } from './formatters/HeapSnapshotFormatter.js';
8
+ import { isNodeLike } from './formatters/HeapSnapshotFormatter.js';
8
9
  import { IssueFormatter } from './formatters/IssueFormatter.js';
9
10
  import { NetworkFormatter } from './formatters/NetworkFormatter.js';
10
11
  import { SnapshotFormatter } from './formatters/SnapshotFormatter.js';
@@ -124,13 +125,14 @@ export class McpResponse {
124
125
  #networkRequestsOptions;
125
126
  #consoleDataOptions;
126
127
  #listExtensions;
127
- #listInPageTools;
128
+ #listThirdPartyDeveloperTools;
128
129
  #listWebMcpTools;
129
130
  #devToolsData;
130
131
  #tabId;
131
132
  #args;
132
133
  #page;
133
134
  #redactNetworkHeaders = true;
135
+ #error;
134
136
  constructor(args) {
135
137
  this.#args = args;
136
138
  }
@@ -161,9 +163,9 @@ export class McpResponse {
161
163
  setListExtensions() {
162
164
  this.#listExtensions = true;
163
165
  }
164
- setListInPageTools() {
165
- if (this.#args.categoryInPageTools) {
166
- this.#listInPageTools = true;
166
+ setListThirdPartyDeveloperTools() {
167
+ if (this.#args.categoryExperimentalThirdParty) {
168
+ this.#listThirdPartyDeveloperTools = true;
167
169
  }
168
170
  }
169
171
  setListWebMcpTools() {
@@ -204,6 +206,9 @@ export class McpResponse {
204
206
  includePreservedMessages: options?.includePreservedMessages,
205
207
  };
206
208
  }
209
+ setError(error) {
210
+ this.#error = error;
211
+ }
207
212
  attachNetworkRequest(reqId, options) {
208
213
  this.#attachedNetworkRequestId = reqId;
209
214
  this.#attachedNetworkRequestOptions = options;
@@ -254,6 +259,9 @@ export class McpResponse {
254
259
  get consoleMessagesTypes() {
255
260
  return this.#consoleDataOptions?.types;
256
261
  }
262
+ get error() {
263
+ return this.#error;
264
+ }
257
265
  appendResponseLine(value) {
258
266
  this.#textResponseLines.push(value);
259
267
  }
@@ -373,14 +381,14 @@ export class McpResponse {
373
381
  if (this.#listExtensions) {
374
382
  extensions = await context.listExtensions();
375
383
  }
376
- let inPageTools;
377
- if (this.#listInPageTools) {
384
+ let thirdPartyDeveloperTools;
385
+ if (this.#listThirdPartyDeveloperTools) {
378
386
  const page = this.#page ?? context.getSelectedMcpPage();
379
- inPageTools = await getToolGroup(page);
380
- page.inPageTools = inPageTools;
387
+ thirdPartyDeveloperTools = await getToolGroup(page);
388
+ page.thirdPartyDeveloperTools = thirdPartyDeveloperTools;
381
389
  }
382
390
  let webmcpTools;
383
- if (this.#listWebMcpTools && this.#args.experimentalWebmcp) {
391
+ if (this.#listWebMcpTools && this.#args.categoryExperimentalWebmcp) {
384
392
  const page = this.#page ?? context.getSelectedMcpPage();
385
393
  webmcpTools = page.getWebMcpTools();
386
394
  }
@@ -461,8 +469,9 @@ export class McpResponse {
461
469
  traceSummary: this.#attachedTraceSummary,
462
470
  extensions,
463
471
  lighthouseResult: this.#attachedLighthouseResult,
464
- inPageTools,
472
+ thirdPartyDeveloperTools,
465
473
  webmcpTools,
474
+ errorMessage: this.#error?.message,
466
475
  });
467
476
  }
468
477
  format(toolName, context, data) {
@@ -655,7 +664,10 @@ Call ${handleDialog.name} to handle it before continuing.`);
655
664
  }
656
665
  const nodes = this.#heapSnapshotOptions.nodes;
657
666
  if (nodes) {
658
- const paginationData = this.#dataWithPagination(nodes.items, this.#heapSnapshotOptions.pagination);
667
+ const sortedItems = nodes.items
668
+ .filter(isNodeLike)
669
+ .sort((a, b) => b.retainedSize - a.retainedSize);
670
+ const paginationData = this.#dataWithPagination(sortedItems, this.#heapSnapshotOptions.pagination);
659
671
  response.push(HeapSnapshotFormatter.formatNodes(paginationData.items));
660
672
  structuredContent.pagination = paginationData.pagination;
661
673
  response.push(...paginationData.info);
@@ -688,14 +700,16 @@ Call ${handleDialog.name} to handle it before continuing.`);
688
700
  response.push(extensionsMessage);
689
701
  }
690
702
  }
691
- if (this.#listInPageTools) {
692
- structuredContent.inPageTools = data.inPageTools ?? undefined;
693
- response.push('## In-page tools');
694
- if (!data.inPageTools || !data.inPageTools.tools) {
695
- response.push('No in-page tools available.');
703
+ if (this.#listThirdPartyDeveloperTools) {
704
+ structuredContent.thirdPartyDeveloperTools =
705
+ data.thirdPartyDeveloperTools ?? undefined;
706
+ response.push('## Third-party developer tools');
707
+ if (!data.thirdPartyDeveloperTools ||
708
+ !data.thirdPartyDeveloperTools.tools) {
709
+ response.push('No third-party developer tools available.');
696
710
  }
697
711
  else {
698
- const toolGroup = data.inPageTools;
712
+ const toolGroup = data.thirdPartyDeveloperTools;
699
713
  response.push(`${toolGroup.name}: ${toolGroup.description}`);
700
714
  response.push('Available tools:');
701
715
  const toolDefinitionsMessage = toolGroup.tools
@@ -760,6 +774,10 @@ Call ${handleDialog.name} to handle it before continuing.`);
760
774
  response.push('<no console messages found>');
761
775
  }
762
776
  }
777
+ if (data.errorMessage) {
778
+ response.push(`Error: ${data.errorMessage}`);
779
+ structuredContent.errorMessage = data.errorMessage;
780
+ }
763
781
  const text = {
764
782
  type: 'text',
765
783
  text: response.join('\n'),
@@ -99,8 +99,8 @@ export class TextSnapshot {
99
99
  return snapshot;
100
100
  }
101
101
  // ExtraHandles represent DOM nodes which might not be part of the accessibility tree, e.g. DOM nodes
102
- // returned by in-page tools. We insert them into the tree by finding the closest ancestor in the
103
- // tree and inserting the node as a child. The ancestor's child nodes are re-parented if necessary.
102
+ // returned by third-party developer tools. We insert them into the tree by finding the closest ancestor
103
+ // in the tree and inserting the node as a child. The ancestor's child nodes are re-parented if necessary.
104
104
  static async insertExtraNodes(page, idToNode, seenUniqueIds, snapshotId, idCounter, rootNodeWithId, seenBackendNodeIds, extraHandles) {
105
105
  const { uniqueBackendNodeIdToMcpId } = page;
106
106
  const createExtraNode = async (handle) => {
@@ -104,8 +104,10 @@ export class WaitForHelper {
104
104
  });
105
105
  }
106
106
  async waitForEventsAfterAction(action, options) {
107
+ let dialogOpened = false;
107
108
  if (options?.handleDialog) {
108
109
  const dialogHandler = (dialog) => {
110
+ dialogOpened = true;
109
111
  if (options.handleDialog === 'dismiss') {
110
112
  void dialog.dismiss();
111
113
  }
@@ -142,6 +144,9 @@ export class WaitForHelper {
142
144
  }
143
145
  try {
144
146
  await navigationFinished;
147
+ if (dialogOpened) {
148
+ return;
149
+ }
145
150
  // Wait for stable dom after navigation so we execute in
146
151
  // the correct context
147
152
  await this.waitForStableDom();