feat: option to disable source maps (#2628)

allowing to disable DevTools source maps similar to what DevTools
settings allow in the UI.
This commit is contained in:
Alex Rudenko
2026-09-07 09:23:15 +00:00
committed by GitHub
parent 757b1fe9df
commit 4430a76c44
11 changed files with 141 additions and 1 deletions
+5
View File
@@ -180,6 +180,11 @@ The Chrome DevTools MCP server supports the following configuration option:
- **Type:** boolean
- **Default:** `true`
- **`--sourceMaps`/ `--source-maps`**
Whether to enable source maps in DevTools. Use --no-source-maps to disable.
- **Type:** boolean
- **Default:** `true`
- **`--screenshotFormat`/ `--screenshot-format`**
Override the default output format used by take_screenshot when the caller does not specify one. JPEG and WebP are ~3-5x smaller than PNG, which reduces transfer and storage size. To reduce context size use --screenshotMaxWidth / --screenshotMaxHeight, since image tokens scale with dimensions rather than encoded bytes. Unset preserves the existing default ("png").
- **Type:** string
+3
View File
@@ -58,6 +58,8 @@ interface McpContextOptions {
experimentalIncludeAllPages?: boolean;
// Whether CrUX data should be fetched.
performanceCrux: boolean;
// Whether source maps are enabled in DevTools.
sourceMaps?: boolean;
// The allow list of URL patterns to allow loading resources.
allowList?: string[];
// The block list of URL patterns to block loading resources.
@@ -567,6 +569,7 @@ export class McpContext implements Context {
page.browserContext(),
),
navigationTimeout: this.#options.navigationTimeout,
sourceMaps: this.#options.sourceMaps,
});
this.#mcpPages.set(page, mcpPage);
await mcpPage.init();
+6 -1
View File
@@ -138,6 +138,7 @@ export class McpPage implements ContextPage {
#hasNetworkBlockOrAllowlist: boolean;
#locatorClass: typeof Locator;
#navigationTimeout: number;
#sourceMaps: boolean;
constructor(
page: Page,
@@ -147,11 +148,13 @@ export class McpPage implements ContextPage {
locatorClass: typeof Locator;
isolatedContextName?: string;
navigationTimeout?: number;
sourceMaps?: boolean;
},
) {
this.#hasNetworkBlockOrAllowlist = options.hasNetworkBlockOrAllowlist;
this.#locatorClass = options.locatorClass;
this.#navigationTimeout = options.navigationTimeout ?? NAVIGATION_TIMEOUT;
this.#sourceMaps = options.sourceMaps ?? true;
this.pptrPage = page;
this.id = id;
this.isolatedContextName = options.isolatedContextName;
@@ -196,7 +199,9 @@ export class McpPage implements ContextPage {
}
try {
const session = await this.pptrPage.createCDPSession();
this.#devtoolsUniverse = await createTargetUniverse(session);
this.#devtoolsUniverse = await createTargetUniverse(session, {
sourceMaps: this.#sourceMaps,
});
} catch (e) {
logger?.('Failed to initialize DevTools universe', e);
}
+7
View File
@@ -269,6 +269,12 @@ export const mcpOptions = {
describe:
'Set to false to disable JavaScript execution. When disabled, evaluation tools (evaluate_script and slim evaluate) are disabled, the initScript parameter in navigate_page is turned off, and navigating to javascript:, data:, or vbscript: URLs is disallowed.',
},
sourceMaps: {
type: 'boolean',
default: true,
describe:
'Whether to enable source maps in DevTools. Use --no-source-maps to disable.',
},
clearcutEndpoint: {
type: 'string',
hidden: true,
@@ -535,6 +541,7 @@ export function parser(
'$0 --no-performance-crux',
'Disable CrUX (field data) integration in performance tools.',
],
['$0 --no-source-maps', 'Disable source maps in DevTools.'],
[
'$0 --no-javascript-evaluation',
'Disable JavaScript execution (disables evaluation tools, initScript in navigate_page, and navigating to javascript:, data:, or vbscript: URLs).',
+16
View File
@@ -137,8 +137,13 @@ export interface TargetUniverse {
session: CDPSession;
}
export interface CreateTargetUniverseOptions {
sourceMaps?: boolean;
}
export async function createTargetUniverse(
session: CDPSession,
options?: CreateTargetUniverseOptions,
): Promise<TargetUniverse> {
const settingStorage = new DevTools.Common.Settings.SettingsStorage({});
const universe = new DevTools.Foundation.Universe.Universe({
@@ -156,6 +161,17 @@ export async function createTargetUniverse(
supportsEmulation: false,
});
const sourceMaps = options?.sourceMaps ?? true;
const jsSourceMapsSetting = universe.settings.resolve(
DevTools.SDKSettings.jsSourceMapsEnabledSettingDescriptor,
);
jsSourceMapsSetting.set(sourceMaps);
const cssSourceMapsSetting = universe.settings.resolve(
DevTools.SDKSettings.cssSourceMapsEnabledSettingDescriptor,
);
cssSourceMapsSetting.set(sourceMaps);
const setting = universe.settings.resolve(
DevTools.SourceMapManager.lazyLoadingSettingDescriptor,
);
+1
View File
@@ -259,6 +259,7 @@ export class McpServer {
experimentalIncludeAllPages:
this.#serverArgs.experimentalIncludeAllPages,
performanceCrux: this.#serverArgs.performanceCrux,
sourceMaps: this.#serverArgs.sourceMaps,
allowList: allowlist,
blocklist: blocklist,
allowUnrestrictedPaths: this.#serverArgs.allowUnrestrictedPaths,
+8
View File
@@ -437,5 +437,13 @@
{
"name": "category_memory",
"flagType": "boolean"
},
{
"name": "source_maps_present",
"flagType": "boolean"
},
{
"name": "source_maps",
"flagType": "boolean"
}
]
+15
View File
@@ -38,6 +38,7 @@ describe('cli args parsing', () => {
memoryDebugging: false,
experimentalStructuredContent: false,
pageIdRouting: true,
sourceMaps: true,
};
it('parses with default args', async () => {
@@ -415,4 +416,18 @@ describe('cli args parsing', () => {
'https://b.com/*',
]);
});
it('parses source-maps flag', async () => {
const defaultParsed = parseArguments(['main.js']);
assert.strictEqual(defaultParsed.sourceMaps, true);
const disabledArgs = parseArguments(['--no-source-maps']);
assert.strictEqual(disabledArgs.sourceMaps, false);
const explicitFalseArgs = parseArguments(['--source-maps=false']);
assert.strictEqual(explicitFalseArgs.sourceMaps, false);
const explicitTrueArgs = parseArguments(['--source-maps=true']);
assert.strictEqual(explicitTrueArgs.sourceMaps, true);
});
});
+45
View File
@@ -152,6 +152,51 @@ describe('createTargetUniverse', () => {
);
});
});
it('enables source maps by default', async () => {
await withBrowser(async (browser, page) => {
const targetUniverse = await createTargetUniverse(
await page.createCDPSession(),
);
assert.ok(targetUniverse);
assert.strictEqual(
targetUniverse.universe.settings
.resolve(DevTools.SDKSettings.jsSourceMapsEnabledSettingDescriptor)
.get(),
true,
);
assert.strictEqual(
targetUniverse.universe.settings
.resolve(DevTools.SDKSettings.cssSourceMapsEnabledSettingDescriptor)
.get(),
true,
);
});
});
it('disables source maps when sourceMaps is false', async () => {
await withBrowser(async (browser, page) => {
const targetUniverse = await createTargetUniverse(
await page.createCDPSession(),
{sourceMaps: false},
);
assert.ok(targetUniverse);
assert.strictEqual(
targetUniverse.universe.settings
.resolve(DevTools.SDKSettings.jsSourceMapsEnabledSettingDescriptor)
.get(),
false,
);
assert.strictEqual(
targetUniverse.universe.settings
.resolve(DevTools.SDKSettings.cssSourceMapsEnabledSettingDescriptor)
.get(),
false,
);
});
});
});
describe('SymbolizedError', () => {
+33
View File
@@ -643,6 +643,39 @@ describe('console', () => {
});
});
it('does not apply source maps when sourceMaps is false', async () => {
server.addRoute('/main.min.js', (_req, res) => {
res.setHeader('Content-Type', 'text/javascript');
res.statusCode = 200;
res.end(`function n(){throw new Error("b00m!")}function o(){n()}(function n(){o()})();
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJiYXIiLCJFcnJvciIsImZvbyIsIklpZmUiXSwic291cmNlcyI6WyIuL21haW4uanMiXSwic291cmNlc0NvbnRlbnQiOlsiXG5mdW5jdGlvbiBiYXIoKSB7XG4gIHRocm93IG5ldyBFcnJvcignYjAwbSEnKTtcbn1cblxuZnVuY3Rpb24gZm9vKCkge1xuICBiYXIoKTtcbn1cblxuKGZ1bmN0aW9uIElpZmUoKSB7XG4gIGZvbygpO1xufSkoKTtcblxuIl0sIm1hcHBpbmdzIjoiQUFDQSxTQUFTQSxJQUNQLE1BQU0sSUFBSUMsTUFBTSxRQUNsQixDQUVBLFNBQVNDLElBQ1BGLEdBQ0YsRUFFQSxTQUFVRyxJQUNSRCxHQUNELEVBRkQiLCJpZ25vcmVMaXN0IjpbXX0=
`);
});
server.addHtmlRoute(
'/index.html',
`<script src="${server.getRoute('/main.min.js')}"></script>`,
);
await withMcpContext(
async (response, context) => {
const page = context.getSelectedMcpPage();
await page.pptrPage.goto(server.getRoute('/index.html'));
await getConsoleMessage.handler(
{params: {msgid: 1}, page: context.getSelectedMcpPage()},
response,
context,
);
const formattedResponse = await response.handle(context);
const rawText = getTextContent(formattedResponse.content[0]);
assert.ok(rawText.includes('main.min.js'));
assert.ok(!rawText.includes('main.js'));
},
{sourceMaps: false},
);
});
it('ignores frames from ignore listed URLs', async t => {
server.addHtmlRoute(
'/index.html',
+2
View File
@@ -161,6 +161,7 @@ export async function withMcpContext(
debug?: boolean;
autoOpenDevTools?: boolean;
performanceCrux?: boolean;
sourceMaps?: boolean;
executablePath?: string;
args?: string[];
blockedUrlPattern?: string[];
@@ -183,6 +184,7 @@ export async function withMcpContext(
{
experimentalDevToolsDebugging: false,
performanceCrux: options.performanceCrux ?? true,
sourceMaps: options.sourceMaps ?? true,
allowList: options.allowedUrlPattern,
blocklist: options.blockedUrlPattern,
allowUnrestrictedPaths: options.allowUnrestrictedPaths ?? false,