Visitar URL original
feat(config): introduce layered ServerConfig for live reload by Lightning00Blade · Pull Request #3203 · ChromeDevTools/chrome-devtools-mcp · GitHub
Skip to content

feat(config): introduce layered ServerConfig for live reload - #3203

Merged
Lightning00Blade merged 1 commit into
mainfrom
cd4a-config/4a2-server-config
Oct 19, 2026
Merged

Lightning00Blade merged 1 commit into
mainfrom
cd4a-config/4a2-server-config

Conversation

@Lightning00Blade

@Lightning00Blade Lightning00Blade commented Oct 16, 2026 •

Copy link
Copy Markdown
Collaborator

Introduces a layered ServerConfig class to hold explicit CLI arguments, config file arguments, and resolved options separately during live config reloads. Most of the validation and default-resolution logic moved directly out of ConfigParser.ts into ServerConfig.ts.

Moved from ConfigParser.ts to ServerConfig.ts

  • ParsedArguments type (re-exported from ConfigParser.ts; channel and filesystemRoot are now typed as optional to match runtime behavior without as casts).
  • isMcpOptionKey and copyOption helpers (moved unchanged).
  • validateConflicts and validateImplications (moved unchanged from ConfigParser static methods to ServerConfig static methods).
  • applyDefaults (viaCli, channel, filesystemRoot, and CI / usage-statistics rules are unchanged; defaults are now parsed via yargs([]).options(baseOptions).parseSync([]) instead of an untyped loop with as unknown as ParsedArguments).
  • Reloadable option copy loop from ConfigParser.mergeReloadableOptions (moved into mergeLayer in ServerConfig.ts).

New / changed behavior

  • applyDefaults() drops unknown keys (filterExplicitArgs): Keys that are not in mcpOptions are now dropped when resolving arguments. Before this change, unknown CLI arguments stayed on the resolved ParsedArguments object returned by ConfigParser.parse() / ConfigParser.reload() after ConfigParser.warnUnknownArgs() logged the warning. Consumers that iterate over mcpOptions keys (such as telemetry computeFlagUsage()) do not change output, while callers inspecting Object.keys(resolved) no longer observe unknown CLI keys.
  • Layered ServerConfig: Stores cliArgs, fileArgs, configPath, env, and resolved separately (replacing the module-level explicitArgsByParsed WeakMap), so reloading a config file updates reloadable file options while preserving startup CLI flags and non-reloadable startup file options.
  • ReadonlyServerConfig, mergeReloadable(next, options), and commit(next): Components read .resolved through ReadonlyServerConfig, while the server computes a candidate reload via mergeReloadable(next, options) and commits it in place via commit(next). ServerConfig.prototype.mergeReloadable() and ServerConfig.prototype.commit() have no production caller in this PR (wired up in subsequent PRs in this stack).
  • ServerConfig.create: Factory method to construct ServerConfig from raw CLI and config-file layers.
  • ConfigParser.parseConfig() and reloadConfig(): Return ServerConfig while keeping parse() and reload() returning ParsedArguments for compatibility (ConfigParser.prototype.reloadConfig() is wired up in subsequent PRs in this stack).
  • mcpOptionsForViaCli and stripYargsPositionalArgs (src/config/mcp-options.ts): mcpOptionsForViaCli is exported directly as a satisfies constant (replacing getMcpOptionsForViaCli()), and stripYargsPositionalArgs is shared between ConfigParser.ts and ServerConfig.ts.

Stack created with GitHub Stacks CLI • Give Feedback 💬

@Lightning00Blade
Lightning00Blade force-pushed the cd4a-config/4a2-server-config branch 5 times, most recently from 7e479ed to 1e65719 Compare October 16, 2026 15:36
@Lightning00Blade
Lightning00Blade marked this pull request as ready for review October 16, 2026 15:37
@Lightning00Blade
Lightning00Blade force-pushed the cd4a-config/4a2-server-config branch from 1e65719 to 0365026 Compare October 16, 2026 15:43

@OrKoN OrKoN left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please check the following:

  1. Add tests for ServerConfig.commit() and ServerConfig.from() in src/config/ServerConfig.ts. No code or test in this PR calls them, so the PR does not verify their behavior.
  2. Add a note or test that ServerConfig.from() moves derived values (for example isolated, categoryExtensions, allowUnrestrictedPaths from viaCli, and usageStatistics: false from CI) into cliArgs. Later conflict and implication checks treat these derived values as explicit user input.
  3. Remove createMockServerConfig from tests/mocks.ts, or add it in the PR that uses it. No test calls it in this PR.
  4. Move the ServerConfig tests (validateConflicts, validateImplications, applyDefaults, mergeReloadable) into a new tests/config/ServerConfig.test.ts. The code under test now lives in src/config/ServerConfig.ts, not in mcp-options.ts.
  5. Keep one stripYargsPositionalArgs helper and import it in src/config/ConfigParser.ts and src/config/ServerConfig.ts. The PR copies the helper into two files with different signatures.
  6. In ConfigParser.#resolveConfig(), set #usageStatisticsNoticeShown = true only after ServerConfig.create() returns. At the moment, a validation error on the first parse prevents the notice on all later parses.
  7. Document in the PR description that applyDefaults() now drops keys that are not in mcpOptions (filterExplicitArgs). Before this change, unknown CLI arguments stayed in the resolved arguments after the warning.

@OrKoN OrKoN left a comment •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please check the following:

  1. Remove ServerConfig.from() from src/config/ServerConfig.ts, or rewrite it so it does not infer explicit input from resolved values. from() drops every value that equals the option default, so an explicit --isolated=false, --allow-unrestricted-paths=false, or --filesystemRoot=<os.tmpdir()> under viaCli is lost, and the next mergeReloadable() turns them into isolated: true, allowUnrestrictedPaths: true, filesystemRoot: undefined (verified locally); the last two widen filesystem access on reload.

  2. Drop the test ServerConfig.from() moves derived values into cliArgs so later conflict checks treat them as explicit input in tests/config/ServerConfig.test.ts together with item 1. It locks in a behavior that differs from create(): with create(), a reload that adds filesystemRoot to the config file is accepted, but after from() the derived allowUnrestrictedPaths: true rejects it as a conflict.

  3. Add a one-sentence comment above filesystemRoot: DEFAULT_FILESYSTEM_ROOT in parseDefaultArgs() in src/config/ServerConfig.ts that states why the yargs default is replaced. yargs copies the array default, and the viaCli branch in applyDefaults() compares filesystemRoot by reference with ===, so a reader cannot tell that the override is required.

  4. Move the "drop unknown CLI keys" behavior change (filterExplicitArgs() in src/config/ServerConfig.ts and its test) into its own PR, or state in the description which consumer (for example telemetry computeFlagUsage) changes output. The pre-submit checklist asks for one change per PR, and this change is independent from the layered config.

  5. Make ServerConfig.from() (if kept) and mergeReloadable() take env the same way create() does. from() falls back to process.env, so a config created by from() and later merged reads the developer's CI variable in tests.

  6. Rename the tests under describe('ServerConfig.commit()') and describe('ServerConfig.from()') in tests/config/ServerConfig.test.ts so the it title does not repeat the describe prefix. The current titles print as ServerConfig.commit() ServerConfig.commit() updates ....

@Lightning00Blade
Lightning00Blade force-pushed the cd4a-config/4a2-server-config branch from fecf603 to 11689d6 Compare October 19, 2026 11:32
Extracts configuration validation, default resolution, and reloadable layer merging into ServerConfig alongside ConfigParser.parseConfig() and ConfigParser.reloadConfig().

Behavior changes:
- ServerConfig.applyDefaults() now drops unknown CLI keys that are not in mcpOptions (via filterExplicitArgs) after ConfigParser.warnUnknownArgs() logs the warning. Previously, unknown CLI keys remained on the resolved ParsedArguments object. Consumers that iterate over mcpOptions keys (such as telemetry computeFlagUsage()) are unaffected, while callers inspecting Object.keys(resolved) no longer observe unknown CLI keys.
- ConfigParser.parseConfig(), ConfigParser.reloadConfig(), ServerConfig.mergeReloadable(), and ServerConfig.commit() are introduced for subsequent PRs in the stack that wire live config reload into McpServer, McpContext, and McpPage.
@Lightning00Blade
Lightning00Blade force-pushed the cd4a-config/4a2-server-config branch from 11689d6 to 2db2562 Compare October 19, 2026 12:10
@Lightning00Blade
Lightning00Blade added this pull request to the merge queue Oct 19, 2026
Merged via the queue into main with commit 37f1fda Oct 19, 2026
17 checks passed
@Lightning00Blade
Lightning00Blade deleted the cd4a-config/4a2-server-config branch October 19, 2026 12:27
zjdCander pushed a commit to zjdCander/chrome-devtools-mcp that referenced this pull request Oct 19, 2026
## Summary

Add a **Pre-submit checklist** section to `AGENTS.md`. Each item comes
from a recent review finding or a landed bug fix in this repository.

The checklist has five groups:

- **Scope and PR description**: one change per PR, title and commit type
match, description lists every behavior change and matches the diff,
`npm run gen` and `npm run format` ran.
- **Design**: fix in the lowest layer that owns the data, fix upstream
(Puppeteer, devtools-frontend) first, one helper for repeated code,
options objects instead of positional `undefined` arguments, validation
in Zod schemas.
- **Correctness and edge cases**: no stale state after a failed call,
artifacts written before a throw, abandoned async continuations, mutex
guards, file removal races, `dispose()` releases every resource, secrets
never reach logs, path parameters validated even when they parse as
URLs.
- **Tests**: every new function has a test, no vacuous assertions,
`notCalled` targets the first call after validation, exact-argument
assertions, reusable stubs in `tests/mocks.ts`, bounded timeouts, no
second CDP session for event waits.
- **Documentation and output**: tool descriptions state when a parameter
is ignored, skills stay generic, one-sentence inline comments.

Sources: review comments on ChromeDevTools#2679, ChromeDevTools#2797, ChromeDevTools#2859, ChromeDevTools#2881, ChromeDevTools#2901, ChromeDevTools#3048,
ChromeDevTools#3082, ChromeDevTools#3109, ChromeDevTools#3120, ChromeDevTools#3132, ChromeDevTools#3134, ChromeDevTools#3139, ChromeDevTools#3148, ChromeDevTools#3156, ChromeDevTools#3158, ChromeDevTools#3161,
ChromeDevTools#3182, ChromeDevTools#3183, ChromeDevTools#3186, ChromeDevTools#3187, ChromeDevTools#3188, ChromeDevTools#3189, ChromeDevTools#3192, ChromeDevTools#3196, ChromeDevTools#3197, ChromeDevTools#3198,
ChromeDevTools#3203, ChromeDevTools#3204, and fixes ChromeDevTools#3150, ChromeDevTools#3160, ChromeDevTools#3185, ChromeDevTools#3202, ChromeDevTools#3207, ChromeDevTools#3208.

Existing content in `AGENTS.md` is unchanged.

Closes ChromeDevTools#3222
github-merge-queue Bot pushed a commit that referenced this pull request Oct 22, 2026
🤖 I have created a release *beep* *boop*
---


##
[1.12.0](chrome-devtools-mcp-v1.11.0...chrome-devtools-mcp-v1.12.0)
(2026-10-22)


### 🎉 Features

* add --maxNavigationSaved flag to configure retained navigation history
([#3018](#3018))
([a580d13](a580d13))
* add Kimi Code plugin manifest
([#3029](#3029))
([cd00b64](cd00b64))
* Analyze heap snapshots without a browser connection
([#3156](#3156))
([78c8320](78c8320))
* **config:** add --watchConfig to reload config file changes
([#3248](#3248))
([b48561f](b48561f))
* **config:** introduce layered ServerConfig for live reload
([#3203](#3203))
([37f1fda](37f1fda))
* **config:** share ReadonlyServerConfig with McpContext and McpPage
([#3204](#3204))
([0813bf3](0813bf3))
* **config:** support reloading blockedUrlPattern and allowedUrlPattern
([#3268](#3268))
([cc850f5](cc850f5))
* **context:** release disabled feature state on config reload
([#3049](#3049))
([c0140d1](c0140d1))
* Paginate by default in heap snapshot tools
([#3201](#3201))
([fb8375b](fb8375b))
* Paginate detailed diff in compare_heapsnapshots
([#3195](#3195))
([4a9dd53](4a9dd53))
* run independent tool calls in parallel with a TaskRunner
([#3243](#3243))
([8a8d877](8a8d877))
* run page-scoped tools on different pages in parallel
([#3252](#3252))
([f8f18ac](f8f18ac))
* **server:** add McpServer.applyConfig() to reload configuration
([#3051](#3051))
([f874aeb](f874aeb))
* **slim:** support filepath in slim mode screenshot
([#3296](#3296))
([d399c4a](d399c4a))
* Sort objects for class by self size in compare_heapsnapshots
([#3205](#3205))
([f8a18c6](f8a18c6))
* **tools:** support updating ToolHandler definitions in place
([#3050](#3050))
([8064138](8064138))
* **wait_for:** support opt-in visible text matching
([#3212](#3212))
([eef92da](eef92da))


### 🛠️ Fixes

* allow paths below a filesystem-root workspace root
([#3277](#3277))
([296ccef](296ccef))
* block evaluate_script while a dialog is open
([#3196](#3196))
([545bcbb](545bcbb))
* bound take_snapshot wait and clear the geolocation override
([#3265](#3265))
([6282f54](6282f54))
* **browser:** redact WebSocket headers from connection logs
([#2901](#2901))
([3a2f91e](3a2f91e))
* capture thrown transform errors as Zod validation issues
([#3242](#3242))
([0f95c21](0f95c21))
* clear handled dialog in McpPage.getDialog()
([#3241](#3241))
([2ab93a3](2ab93a3)),
closes
[#2958](#2958)
* **cli:** disallow --slim in CLI start options
([#2987](#2987))
([#3113](#3113))
([ae3f61c](ae3f61c))
* **cli:** do not forward tool args to start
([#3114](#3114))
([fef1598](fef1598))
* **cli:** serialize object daemon arguments
([#2797](#2797))
([f73a440](f73a440))
* close the tab opened by a failed new_page
([#2928](#2928))
([c174677](c174677))
* **config:** accept native JSON objects for wsHeaders in config files
([#3262](#3262))
([371e6c2](371e6c2))
* **console:** describe Map, Set, function, DOM node, symbol and cyclic
arguments
([#3199](#3199))
([968e4e5](968e4e5))
* **console:** include the reason of unhandled promise rejections
([#3148](#3148))
([f7cdf73](f7cdf73))
* defer focus emulation until a page is explicitly targeted
([#3230](#3230))
([35abe35](35abe35))
* disable Puppeteer signal handlers for launched browsers
([#3238](#3238))
([3afec73](3afec73)),
closes
[#3154](#3154)
* discover third-party developer tools before tool lookup
([#3208](#3208))
([2777fa0](2777fa0)),
closes
[#2973](#2973)
* discover third-party developer tools in page tools
([#3207](#3207))
([cf33529](cf33529)),
closes
[#2980](#2980)
* drop InlineTextBox nodes from text snapshots
([#3202](#3202))
([f8c775a](f8c775a))
* **emulate:** keep previous viewport when setViewport fails
([#3150](#3150))
([19d883c](19d883c))
* exclude source maps from the npm package
([#3295](#3295))
([d575da4](d575da4))
* keep surrogate pairs and emoji whole when truncating titles, names and
bodies
([#3215](#3215))
([058adcf](058adcf))
* let resourceTypes match CORS preflights and prefetches
([#3217](#3217))
([e342c6e](e342c6e))
* **lighthouse:** explain unsupported URL schemes in navigation mode
([#3144](#3144))
([c6ad84a](c6ad84a))
* **lighthouse:** fail the audit when Lighthouse reports a runtime error
([#3188](#3188))
([53ea78d](53ea78d))
* **lighthouse:** restore the emulated viewport after a navigation audit
([#3189](#3189))
([c777ece](c777ece))
* **network:** list only earlier hops in a request's redirect chain
([#3198](#3198))
([4675940](4675940))
* **network:** remove unsupported websocket from list_network_requests
filter
([#2961](#2961))
([#3282](#3282))
([8b119d9](8b119d9))
* **network:** reset page network emulation before applying URL
restrictions
([#3312](#3312))
([f25f3df](f25f3df))
* **pages:** reject devtools:// URLs in navigate_page and new_page
([#2935](#2935))
([#3128](#3128))
([c94c03d](c94c03d))
* **pages:** report the actual page size after resize_page
([#2998](#2998))
([#3132](#3132))
([f003056](f003056))
* **pages:** revert reporting the page size after resize_page
([#3308](#3308))
([186ea66](186ea66)),
closes
[#3306](#3306)
* **pagination:** return all items when pageSize is omitted and pageIdx
is 0
([#2996](#2996))
([#3134](#3134))
([3ad9115](3ad9115))
* **performance:** populate structuredContent for traceInsight in
performance_analyze_insight
([#2981](#2981))
([#3115](#3115))
([c2c6cc4](c2c6cc4))
* preserve unread page fallback across snapshots and deduplicate page
disposal
([#3161](#3161))
([8604365](8604365))
* print the no-roots temp-directory warning under default flags
([#2927](#2927))
([0dd8ed9](0dd8ed9))
* reject empty, extra, and unknown parts in geolocation and viewport
transforms
([#3097](#3097))
([#3120](#3120))
([3ea31fb](3ea31fb))
* resolve error causes on the session that reported the exception
([#3220](#3220))
([b2d37e8](b2d37e8))
* resolve service worker IDs for console messages
([#2881](#2881))
([3804a9a](3804a9a))
* return message when page exposes no 3p developer tools
([#3197](#3197))
([663f3c3](663f3c3)),
closes
[#3004](#3004)
* **script:** surface non-Error thrown and rejected values in
evaluate_script
([#2951](#2951))
([#3127](#3127))
([b1e6e68](b1e6e68))
* **security:** validate filesystem paths that parse as http/ws URLs
([#3186](#3186))
([91e112d](91e112d))
* **snapshot:** omit uid for accessibility nodes without backendNodeId
([#3187](#3187))
([9054351](9054351))
* stop active screencast on McpPage.dispose()
([#3160](#3160))
([558af81](558af81))
* stop get_network_request waiting forever for an unread no-store body
([#3216](#3216))
([c556be1](c556be1))
* surface nested error causes and autoConnect hint on connection failure
([#3111](#3111))
([d7f1e78](d7f1e78))
* treat 0.0.0.0 and [::] browser endpoints as local
([#3321](#3321))
([7d5f7de](7d5f7de))
* treat IPv4-mapped IPv6 loopback as localhost
([#3255](#3255))
([6cfb34c](6cfb34c))
* truncate data: URLs in accessibility snapshots
([#3292](#3292))
([11e7d47](11e7d47))
* validate type_text submitKey before typing
([#3185](#3185))
([c8615d7](c8615d7))
* **wait_for:** find text in dynamically attached iframes
([#3210](#3210))
([5f84888](5f84888))
* warn when screenshot dimensions exceed 16384px limit
([#2952](#2952))
([#3291](#3291))
([10455b7](10455b7))


### 📄 Documentation

* add a pre-submit checklist to AGENTS.md
([#3236](#3236))
([e96ee6c](e96ee6c))
* clarify URL pattern port and hostname matching
([#3287](#3287))
([4723335](4723335))
* **config:** note that hot-reloaded URL restrictions keep open targets
attached
([#3314](#3314))
([47db2b8](47db2b8))
* correct CLI availability of extension tools
([#2852](#2852))
([a7280ee](a7280ee))
* explain how to install skills, including the CLI skill
([#3274](#3274))
([46eb546](46eb546))
* remove experimental status from CLI and promote it in README
([#3273](#3273))
([0ced16b](0ced16b))
* require a rebase only when the branch has merge conflicts
([#3239](#3239))
([d1143ac](d1143ac))
* **skills:** clarify Lighthouse score scale and contrast workflow
([#3006](#3006))
([#3218](#3218))
([bf8c6d9](bf8c6d9))


### ⚡ Performance

* **cli:** load a small third-party bundle in the chrome-devtools CLI
([#3200](#3200))
([552e1f8](552e1f8))
* load the Lighthouse bundle on first use
([#3169](#3169))
([798f03a](798f03a))


### 🏗️ Refactor

* **config:** isolate scripts and unit tests from home config discovery
([#3256](#3256))
([65e6b97](65e6b97))
* **config:** lock slim and pageIdRouting options when viaCli is set
([#3257](#3257))
([384d9aa](384d9aa))
* **config:** pass ReadonlyServerConfig to BrowserManager and add
OptionGate
([#3267](#3267))
([98302f2](98302f2))
* **config:** simplify watchConfig and start watcher inside connect
([#3259](#3259))
([878c5f6](878c5f6))
* extract errorResult() and routedPageId() in ToolHandler
([#3251](#3251))
([9a6b03a](9a6b03a))
* import types and values from a module in one statement
([#3303](#3303))
([f4eaf1f](f4eaf1f))
* **lighthouse:** move Lighthouse runner methods to McpPage and add
bundle types
([#3283](#3283))
([e1823a2](e1823a2))
* list optional properties last in inline object types
([#3302](#3302))
([dc929c0](dc929c0))
* register all tools upfront across modes
([#3163](#3163))
([58f8d1f](58f8d1f))
* **response:** pass live ReadonlyServerConfig to McpResponse
([#3258](#3258))
([6042490](6042490))
* **tools:** add explicit factory types to tool definitions
([#3284](#3284))
([4d1d7b2](4d1d7b2))
* use #private names instead of the private modifier
([#3301](#3301))
([2e13311](2e13311))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants