feat: add an option to customize ffmpeg path (#1937)

This PR adds experimental flag to customize `experimentalScreencast`
that allows specifying a different path to the ffmpeg binary.
This commit is contained in:
Alex Rudenko
2026-04-22 14:22:20 +02:00
committed by GitHub
parent d50255778a
commit b377454b1b
5 changed files with 44 additions and 6 deletions
+4
View File
@@ -591,6 +591,10 @@ The Chrome DevTools MCP server supports the following configuration option:
Exposes experimental screencast tools (requires ffmpeg). Install ffmpeg https://www.ffmpeg.org/download.html and ensure it is available in the MCP server PATH.
- **Type:** boolean
- **`--experimentalFfmpegPath`/ `--experimental-ffmpeg-path`**
Path to ffmpeg executable for screencast recording.
- **Type:** string
- **`--experimentalWebmcp`/ `--experimental-webmcp`**
Set to true to enable debugging WebMCP tools. Requires Chrome 149+ with the following flags: `--enable-features=WebMCPTesting,DevToolsWebMCPSupport`
- **Type:** boolean
@@ -195,6 +195,11 @@ export const cliOptions = {
describe:
'Exposes experimental screencast tools (requires ffmpeg). Install ffmpeg https://www.ffmpeg.org/download.html and ensure it is available in the MCP server PATH.',
},
experimentalFfmpegPath: {
type: 'string',
describe: 'Path to ffmpeg executable for screencast recording.',
implies: 'experimentalScreencast',
},
experimentalWebmcp: {
type: 'boolean',
describe:
+4
View File
@@ -106,6 +106,10 @@
"name": "experimental_devtools_present",
"flagType": "boolean"
},
{
"name": "experimental_ffmpeg_path_present",
"flagType": "boolean"
},
{
"name": "experimental_include_all_pages",
"flagType": "boolean"
+3 -2
View File
@@ -20,7 +20,7 @@ async function generateTempFilePath(): Promise<string> {
return path.join(dir, `screencast.mp4`);
}
export const startScreencast = definePageTool({
export const startScreencast = definePageTool(args => ({
name: 'screencast_start',
description:
'Starts recording a screencast (video) of the selected page in mp4 format.',
@@ -56,6 +56,7 @@ export const startScreencast = definePageTool({
recorder = await page.pptrPage.screencast({
path: resolvedPath as `${string}.mp4`,
format: 'mp4' as const,
ffmpegPath: args?.experimentalFfmpegPath,
});
} catch (err) {
const message = err instanceof Error ? err.message : String(err);
@@ -74,7 +75,7 @@ export const startScreencast = definePageTool({
`Screencast recording started. The recording will be saved to ${resolvedPath}. Use ${stopScreencast.name} to stop recording.`,
);
},
});
}));
export const stopScreencast = definePageTool({
name: 'screencast_stop',
+28 -4
View File
@@ -9,6 +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 {startScreencast, stopScreencast} from '../../src/tools/screencast.js';
import {withMcpContext} from '../utils.js';
@@ -32,7 +33,7 @@ describe('screencast', () => {
.stub(selectedPage, 'screencast')
.resolves(mockRecorder as never);
await startScreencast.handler(
await startScreencast().handler(
{
params: {path: '/tmp/test-recording.mp4'},
page: context.getSelectedMcpPage(),
@@ -63,7 +64,7 @@ describe('screencast', () => {
.stub(selectedPage, 'screencast')
.resolves(mockRecorder as never);
await startScreencast.handler(
await startScreencast().handler(
{params: {}, page: context.getSelectedMcpPage()},
response,
context,
@@ -88,7 +89,7 @@ describe('screencast', () => {
const selectedPage = context.getSelectedPptrPage();
const screencastStub = sinon.stub(selectedPage, 'screencast');
await startScreencast.handler(
await startScreencast().handler(
{params: {}, page: context.getSelectedMcpPage()},
response,
context,
@@ -110,7 +111,7 @@ describe('screencast', () => {
sinon.stub(selectedPage, 'screencast').rejects(error);
await assert.rejects(
startScreencast.handler(
startScreencast().handler(
{
params: {path: '/tmp/test.mp4'},
page: context.getSelectedMcpPage(),
@@ -124,6 +125,29 @@ describe('screencast', () => {
assert.strictEqual(context.getScreenRecorder(), null);
});
});
it('passes ffmpegPath from args to puppeteer', async () => {
await withMcpContext(async (response, context) => {
const mockRecorder = createMockRecorder();
const selectedPage = context.getSelectedPptrPage();
const screencastStub = sinon
.stub(selectedPage, 'screencast')
.resolves(mockRecorder as never);
const experimentalFfmpegPath = '/custom/path/to/ffmpeg';
await startScreencast({
experimentalFfmpegPath,
} as ParsedArguments).handler(
{params: {}, page: context.getSelectedMcpPage()},
response,
context,
);
sinon.assert.calledOnce(screencastStub);
const callArgs = screencastStub.firstCall.args[0];
assert.strictEqual(callArgs?.ffmpegPath, experimentalFfmpegPath);
});
});
});
describe('screencast_stop', () => {