brave-mcp 0.1.2 → 0.2.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.
@@ -86,8 +86,8 @@ export const lighthouseAudit = definePageTool({
86
86
  const report = generateReport(lhr, format);
87
87
  const data = encoder.encode(report);
88
88
  if (outputDirPath) {
89
- const reportPath = path.join(outputDirPath, `report.${format}`);
90
- const { filename } = await context.saveFile(data, reportPath);
89
+ const reportPath = path.join(outputDirPath, `report`);
90
+ const { filename } = await context.saveFile(data, reportPath, `.${format}`);
91
91
  reportPaths.push(filename);
92
92
  }
93
93
  else {
@@ -4,6 +4,7 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
  import { zod } from '../third_party/index.js';
7
+ import { ensureExtension } from '../utils/files.js';
7
8
  import { ToolCategory } from './categories.js';
8
9
  import { definePageTool } from './ToolDefinition.js';
9
10
  export const takeMemorySnapshot = definePageTool({
@@ -21,7 +22,7 @@ export const takeMemorySnapshot = definePageTool({
21
22
  handler: async (request, response, _context) => {
22
23
  const page = request.page;
23
24
  await page.pptrPage.captureHeapSnapshot({
24
- path: request.params.filePath,
25
+ path: ensureExtension(request.params.filePath, '.heapsnapshot'),
25
26
  });
26
27
  response.appendResponseLine(`Heap snapshot saved to ${request.params.filePath}`);
27
28
  },
@@ -19,6 +19,7 @@ export const listPages = defineTool(args => {
19
19
  handler: async (_request, response) => {
20
20
  response.setIncludePages(true);
21
21
  response.setListInPageTools();
22
+ response.setListWebMcpTools();
22
23
  },
23
24
  };
24
25
  });
@@ -43,6 +44,7 @@ export const selectPage = defineTool({
43
44
  context.selectPage(page);
44
45
  response.setIncludePages(true);
45
46
  response.setListInPageTools();
47
+ response.setListWebMcpTools();
46
48
  if (request.params.bringToFront) {
47
49
  await page.pptrPage.bringToFront();
48
50
  }
@@ -179,7 +181,7 @@ export const navigatePage = definePageTool({
179
181
  response.appendResponseLine(`Successfully navigated to ${request.params.url}.`);
180
182
  }
181
183
  catch (error) {
182
- response.appendResponseLine(`Unable to navigate in the selected page: ${error.message}.`);
184
+ response.appendResponseLine(`Unable to navigate in the selected page: ${error.message}.`);
183
185
  }
184
186
  break;
185
187
  case 'back':
@@ -227,6 +229,7 @@ export const navigatePage = definePageTool({
227
229
  }
228
230
  response.setIncludePages(true);
229
231
  response.setListInPageTools();
232
+ response.setListWebMcpTools();
230
233
  },
231
234
  });
232
235
  export const resizePage = definePageTool({
@@ -142,7 +142,7 @@ async function stopTracingAndAppendOutput(page, response, context, filePath) {
142
142
  });
143
143
  });
144
144
  }
145
- const file = await context.saveFile(dataToWrite, filePath);
145
+ const file = await context.saveFile(dataToWrite, filePath, filePath.endsWith('.gz') ? '.json.gz' : '.json');
146
146
  response.appendResponseLine(`The raw trace data was saved to ${file.filename}.`);
147
147
  }
148
148
  const result = await parseRawTraceBuffer(traceEventsBuffer);
@@ -7,6 +7,7 @@ import fs from 'node:fs/promises';
7
7
  import os from 'node:os';
8
8
  import path from 'node:path';
9
9
  import { zod } from '../third_party/index.js';
10
+ import { ensureExtension } from '../utils/files.js';
10
11
  import { ToolCategory } from './categories.js';
11
12
  import { definePageTool } from './ToolDefinition.js';
12
13
  async function generateTempFilePath() {
@@ -33,7 +34,7 @@ export const startScreencast = definePageTool({
33
34
  return;
34
35
  }
35
36
  const filePath = request.params.path ?? (await generateTempFilePath());
36
- const resolvedPath = path.resolve(filePath);
37
+ const resolvedPath = ensureExtension(path.resolve(filePath), '.mp4');
37
38
  const page = request.page;
38
39
  let recorder;
39
40
  try {
@@ -67,8 +67,8 @@ export const screenshot = definePageTool({
67
67
  response.appendResponseLine("Took a screenshot of the current page's viewport.");
68
68
  }
69
69
  if (request.params.filePath) {
70
- const file = await context.saveFile(screenshot, request.params.filePath);
71
- response.appendResponseLine(`Saved screenshot to ${file.filename}.`);
70
+ const result = await context.saveFile(screenshot, request.params.filePath, `.${format}`);
71
+ response.appendResponseLine(`Saved screenshot to ${result.filename}.`);
72
72
  }
73
73
  else if (screenshot.length >= 2_000_000) {
74
74
  const { filepath } = await context.saveTemporaryFile(screenshot, `screenshot.${request.params.format}`);
@@ -18,6 +18,7 @@ import * as screenshotTools from './screenshot.js';
18
18
  import * as scriptTools from './script.js';
19
19
  import * as slimTools from './slim/tools.js';
20
20
  import * as snapshotTools from './snapshot.js';
21
+ import * as webmcpTools from './webmcp.js';
21
22
  export const createTools = (args) => {
22
23
  const rawTools = args.slim
23
24
  ? Object.values(slimTools)
@@ -36,6 +37,7 @@ export const createTools = (args) => {
36
37
  ...Object.values(screenshotTools),
37
38
  ...Object.values(scriptTools),
38
39
  ...Object.values(snapshotTools),
40
+ ...Object.values(webmcpTools),
39
41
  ];
40
42
  const tools = [];
41
43
  for (const tool of rawTools) {
@@ -0,0 +1,63 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { zod } from '../third_party/index.js';
7
+ import { ToolCategory } from './categories.js';
8
+ import { definePageTool } from './ToolDefinition.js';
9
+ export const listWebMcpTools = definePageTool({
10
+ name: 'list_webmcp_tools',
11
+ description: `Lists all WebMCP tools the page exposes.`,
12
+ annotations: {
13
+ category: ToolCategory.DEBUGGING,
14
+ readOnlyHint: true,
15
+ conditions: ['experimentalWebmcp'],
16
+ },
17
+ schema: {},
18
+ handler: async (_request, response, _context) => {
19
+ response.setListWebMcpTools();
20
+ },
21
+ });
22
+ export const executeWebMcpTool = definePageTool({
23
+ name: 'execute_webmcp_tool',
24
+ description: `Executes a WebMCP tool exposed by the page.`,
25
+ annotations: {
26
+ category: ToolCategory.DEBUGGING,
27
+ readOnlyHint: false,
28
+ conditions: ['experimentalWebmcp'],
29
+ },
30
+ schema: {
31
+ toolName: zod.string().describe('The name of the WebMCP tool to execute'),
32
+ input: zod
33
+ .string()
34
+ .optional()
35
+ .describe('The JSON-stringified parameters to pass to the WebMCP tool'),
36
+ },
37
+ handler: async (request, response) => {
38
+ const toolName = request.params.toolName;
39
+ let input = {};
40
+ if (request.params.input) {
41
+ try {
42
+ const parsed = JSON.parse(request.params.input);
43
+ if (typeof parsed === 'object' && parsed !== null) {
44
+ input = parsed;
45
+ }
46
+ else {
47
+ throw new Error('Parsed input is not an object');
48
+ }
49
+ }
50
+ catch (e) {
51
+ const errorMessage = e instanceof Error ? e.message : String(e);
52
+ throw new Error(`Failed to parse input as JSON: ${errorMessage}`);
53
+ }
54
+ }
55
+ const tools = request.page.pptrPage.webmcp.tools();
56
+ const tool = tools.find(t => t.name === toolName);
57
+ if (!tool) {
58
+ throw new Error(`Tool ${toolName} not found`);
59
+ }
60
+ const { status, output, errorText } = await tool.execute(input);
61
+ response.appendResponseLine(JSON.stringify({ status, output, errorText }, null, 2));
62
+ },
63
+ });
@@ -17,3 +17,7 @@ export async function saveTemporaryFile(data, filename) {
17
17
  throw new Error('Could not save a file', { cause: err });
18
18
  }
19
19
  }
20
+ export function ensureExtension(filepath, extension) {
21
+ const ext = path.extname(filepath);
22
+ return filepath.slice(0, filepath.length - ext.length) + extension;
23
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "brave-mcp",
3
- "version": "0.1.2",
3
+ "version": "0.2.0",
4
4
  "description": "MCP server for Brave DevTools",
5
5
  "type": "module",
6
6
  "bin": {
@@ -62,7 +62,7 @@
62
62
  "@types/yargs": "^17.0.33",
63
63
  "@typescript-eslint/eslint-plugin": "^8.43.0",
64
64
  "@typescript-eslint/parser": "^8.43.0",
65
- "chrome-devtools-frontend": "1.0.1611825",
65
+ "chrome-devtools-frontend": "1.0.1613625",
66
66
  "core-js": "3.49.0",
67
67
  "debug": "4.4.3",
68
68
  "eslint": "^9.35.0",
@@ -71,7 +71,7 @@
71
71
  "globals": "^17.0.0",
72
72
  "lighthouse": "13.1.0",
73
73
  "prettier": "^3.6.2",
74
- "puppeteer": "24.40.0",
74
+ "puppeteer": "24.41.0",
75
75
  "rollup": "4.60.1",
76
76
  "rollup-plugin-cleanup": "^3.2.1",
77
77
  "rollup-plugin-license": "^3.6.0",