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.
- package/README.md +22 -5
- package/build/src/McpContext.js +12 -2
- package/build/src/McpPage.js +9 -4
- package/build/src/McpResponse.js +35 -17
- package/build/src/TextSnapshot.js +2 -2
- package/build/src/WaitForHelper.js +5 -0
- package/build/src/bin/brave-devtools-cli-options.js +228 -46
- package/build/src/bin/brave-devtools-mcp-cli-options.js +9 -5
- package/build/src/bin/brave-devtools-mcp-main.js +0 -5
- package/build/src/bin/brave-devtools.js +4 -13
- package/build/src/formatters/HeapSnapshotFormatter.js +3 -3
- package/build/src/index.js +93 -50
- package/build/src/telemetry/ClearcutLogger.js +12 -1
- package/build/src/third_party/index.js +2 -1
- package/build/src/third_party/issue-descriptions/genericFormModelContextMissingToolDescription.md +5 -0
- package/build/src/third_party/issue-descriptions/genericFormModelContextMissingToolName.md +5 -0
- package/build/src/third_party/issue-descriptions/genericFormModelContextParameterMissingName.md +5 -0
- package/build/src/third_party/issue-descriptions/genericFormModelContextParameterMissingTitleAndDescription.md +5 -0
- package/build/src/third_party/issue-descriptions/genericFormModelContextRequiredParameterMissingName.md +5 -0
- package/build/src/third_party/lighthouse-devtools-mcp-bundle.js +21716 -20261
- package/build/src/tools/categories.js +9 -3
- package/build/src/tools/console.js +2 -0
- package/build/src/tools/emulation.js +1 -0
- package/build/src/tools/extensions.js +5 -0
- package/build/src/tools/input.js +54 -1
- package/build/src/tools/lighthouse.js +15 -9
- package/build/src/tools/memory.js +4 -0
- package/build/src/tools/network.js +2 -0
- package/build/src/tools/pages.js +13 -5
- package/build/src/tools/performance.js +3 -0
- package/build/src/tools/screencast.js +4 -2
- package/build/src/tools/screenshot.js +1 -0
- package/build/src/tools/script.js +1 -0
- package/build/src/tools/slim/tools.js +3 -0
- package/build/src/tools/snapshot.js +2 -0
- package/build/src/tools/{inPage.js → thirdPartyDeveloper.js} +17 -17
- package/build/src/tools/tools.js +2 -2
- package/build/src/tools/webmcp.js +4 -4
- package/build/src/version.js +1 -1
- package/package.json +6 -7
- package/build/src/bin/cliDefinitions.js +0 -622
- package/build/src/third_party/THIRD_PARTY_NOTICES +0 -4297
- package/build/src/third_party/bundled-packages.json +0 -9
- 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** (
|
|
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** (
|
|
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
|
-
- **
|
|
630
|
-
- [`
|
|
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
|
-
- **`--
|
|
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
|
package/build/src/McpContext.js
CHANGED
|
@@ -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
|
-
|
|
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;
|
package/build/src/McpPage.js
CHANGED
|
@@ -30,7 +30,7 @@ export class McpPage {
|
|
|
30
30
|
// Dialog
|
|
31
31
|
#dialog;
|
|
32
32
|
#dialogHandler;
|
|
33
|
-
|
|
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
|
-
|
|
52
|
-
|
|
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
|
|
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
|
package/build/src/McpResponse.js
CHANGED
|
@@ -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
|
-
#
|
|
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
|
-
|
|
165
|
-
if (this.#args.
|
|
166
|
-
this.#
|
|
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
|
|
377
|
-
if (this.#
|
|
384
|
+
let thirdPartyDeveloperTools;
|
|
385
|
+
if (this.#listThirdPartyDeveloperTools) {
|
|
378
386
|
const page = this.#page ?? context.getSelectedMcpPage();
|
|
379
|
-
|
|
380
|
-
page.
|
|
387
|
+
thirdPartyDeveloperTools = await getToolGroup(page);
|
|
388
|
+
page.thirdPartyDeveloperTools = thirdPartyDeveloperTools;
|
|
381
389
|
}
|
|
382
390
|
let webmcpTools;
|
|
383
|
-
if (this.#listWebMcpTools && this.#args.
|
|
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
|
-
|
|
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
|
|
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.#
|
|
692
|
-
structuredContent.
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
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.
|
|
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
|
|
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();
|