Skip to content

Chrome Control MCP v1.4.0

Choose a tag to compare

@github-actions github-actions released this 23 Sep 02:57
· 57 commits to main since this release

Warning

Superseded. On Windows this release cannot attach the browser bridge at all.

The managed install is reached through current, a directory junction onto
versions/<version>. The bridge refuses any peer that is not running its own binary, and it
asked about itself and about its peer through two different calls: one reports the path a
process was launched through, the other reports what that path resolves to. Through a junction
those are two names for one file, so every relay refused every server:

The bridge is served by ...\versions\1.4.0\chrome_control_mcp.exe, but this relay is
...\current\chrome_control_mcp.exe.

This is the first release with the versioned install layout, so it is the first one the fault
could reach. Linux and macOS are unaffected: that half of the check already canonicalized both
paths. Fixed in v1.5.1.

Install the latest release instead.


Chrome Control MCP 1.4.0 makes updating this server stop being a chore you do by hand, and makes
installing it something the VS Code Marketplace can do for you.

The update path

Until now, updating meant closing whatever was using the server, replacing files, and then
repairing what the new path broke. The files that had to be replaced were the ones being executed,
and Windows does not allow that. Worse, the install directory carried the version number, so every
upgrade invalidated three things at once: the MCP client's command, Chrome's unpacked-extension
folder, and the native-messaging registration. The last of those costs a trip through
chrome://extensions, which is the one step nothing can automate.

Nothing locked is written now. Each version is installed into <root>/versions/<version> and a
current link is repointed at it -- a directory junction on Windows, a symbolic link on Linux and
macOS. A junction rather than a symbolic link because Windows asks for elevation or Developer Mode
for the latter, and updating has to stay a user-level operation.

Everything outside this program names a path under current, so installing a new version moves
none of them.

Added

  • browser_update_status reports where this build is installed, which versions are present, and
    what the stable link points at. It touches no network.
  • browser_update_check asks GitHub which release is newest.
  • browser_update_apply installs it. The running executable is never overwritten, so the update
    cannot fail on a locked file, and the new build takes effect the next time the client starts the
    server.
  • --install puts a copy of this program into the managed layout, registers the native host, and
    prints the command path and the Chrome extension folder as one line of JSON. It is how an
    unpacked release archive becomes an install without first configuring an MCP client. Run on a
    copy that is already installed, it repairs a registration another copy overwrote.
  • --version prints the build.

A copy running from a build tree or an unpacked download cannot update in place, because the file
that would have to be replaced is the one executing. The first browser_update_apply moves such a
copy into the managed layout and then installs the newest release on top of it. That move is the
only time the client's command path changes.

Install root is %LOCALAPPDATA%\Programs\ChromeControlMCP on Windows and sits under the per-user
data directory on Linux and macOS. CHROME_CONTROL_MCP_INSTALL_ROOT overrides it.

Integrity boundary

A download is checked against the SHA-256 published beside it in the same release, and a mismatch
is discarded rather than installed. That detects a truncated or corrupted transfer. It is not a
signature: the archive and the checksum come from one origin over one transport. This project still
ships no signing key and this release does not pretend otherwise.

VS Code Marketplace

Chrome Control MCP publishes as four platform-specific extensions -- win32-x64, linux-x64,
darwin-arm64, darwin-x64 -- each carrying the build for its platform, so installing needs no
second download and no path to configure.

The extension registers the server through the MCP server definition provider API rather than
writing an mcp.json, and points it at the stable link, so the registration stays correct after the
server updates itself. Marketplace updates and the server updating itself land in the same managed
install; whichever is newer is the one that runs.

The extension computes nothing about where the server lives. It runs --install and uses the path
that comes back, because a second copy of those rules in TypeScript would be free to drift from the
ones in the server without anything failing loudly.

Two commands: one repairs the install and its native-host registration, the other copies and opens
the folder Chrome has to be pointed at.

Fixed

  • browser_update_* would have been routed to the browser bridge, because everything named
    browser_* was. A question about this program's own install would have answered "the extension
    is not attached" -- exactly the state someone is in when they reach for it.
  • The path functions that decide whether a build is in a managed install used QDir::cdUp, which
    consults the filesystem and refuses a directory that does not exist. The answer to a question
    about the shape of a path depended on whether that path happened to be mounted.
  • Unpacking names the system tar explicitly on Windows instead of taking the first one on PATH. A
    POSIX tar earlier on PATH reads C:\... as a remote host and fails trying to reach a machine
    called C.

Changed

  • Release archives carry the Qt Network runtime and the platform's Qt TLS backend, which the update
    path needs to reach the release host. One backend per platform, not every one Qt built: the
    others carry runtime dependencies the package does not include, and a plugin that cannot load is
    a confusing failure rather than a fallback. The SPDX inventory is unchanged; both come from the
    qtbase source already recorded.
  • The version number has one home. The server, the updater, and the packaged archive read the CMake
    project version instead of keeping separate copies -- a stale copy inside an updater being the
    one place that silently does the wrong thing.
  • Releases publish a .vsix per platform beside the archives, and SHA256SUMS.txt covers them.
  • The full profile advertises 47 tools; the read-only profile advertises 12. browser_update_apply
    is absent from the read-only profile by design: it replaces the program on disk, which is a
    mutation whatever the browser profile says.

Verified

Windows 11 Pro 26200, MSVC 19.50, Qt 6.10.3, Node 24.13.0.

  • 12/12 native and extension suites, including two new ones. test_install_layout covers version
    names that try to escape the versions directory, version-number ordering, and the link swap.
    test_updater covers asset naming, checksum parsing, version comparison, and installing a staged
    release.
  • The link repoints while a server launched through it is running. The server keeps serving and
    exits 0, and the version it was launched from is left whole. That is the claim this release
    rests on, so it is tested twice: as a unit test holding a file open across the swap, and against
    a real server process.
  • A real update over the network. A deliberately older build fetched the published release,
    verified its SHA-256, unpacked it, and repointed the link: previous_version 1.2.2,
    installed_version 1.3.1.
  • Pruning leaves a version whose files are still open untouched rather than half-deleting it under
    the process running from it.
  • The packaged win32-x64 VSIX was unpacked and its bundled server run, including an HTTPS release
    check through the bundled TLS backend.

The Linux and macOS suites and the live-Chrome runs predate this release; GitHub Actions builds and
tests all three platforms on every push, and a local Linux and macOS re-run of the two new suites
is still outstanding.

macOS 15.7.4, Intel, against the published macos-x64 archive of this release:

  • --version and --install load both shipped frameworks and build the managed layout, with
    current a real symbolic link to versions/1.4.0.
  • browser_update_check reaches the release host over HTTPS through the bundled SecureTransport
    backend and reads this version back. That was the part most likely to differ on macOS, where a
    plugin has to resolve its own frameworks, and it is now observed rather than assumed.
  • The darwin-x64 VSIX packages from that same archive, and the binary inside the packaged
    extension loads with no dyld error.

Linux has not had the same end-to-end run: it builds, tests, and packages, and its archive now
carries the Qt and ICU libraries it needs, but no Linux machine has fetched and installed a release
through browser_update_apply.