Repository navigation
Chrome Control MCP v1.4.0
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.
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_statusreports where this build is installed, which versions are present, and
what the stable link points at. It touches no network.browser_update_checkasks GitHub which release is newest.browser_update_applyinstalls 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.--installputs 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.--versionprints 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
tarexplicitly on Windows instead of taking the first one on PATH. A
POSIX tar earlier on PATH readsC:\...as a remote host and fails trying to reach a machine
calledC.
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
.vsixper platform beside the archives, andSHA256SUMS.txtcovers 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_layoutcovers version
names that try to escape the versions directory, version-number ordering, and the link swap.
test_updatercovers 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_version1.2.2,
installed_version1.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-x64VSIX 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:
--versionand--installload both shipped frameworks and build the managed layout, with
currenta real symbolic link toversions/1.4.0.browser_update_checkreaches 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-x64VSIX 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.