feat(mcp): connect the user's signed-in Chrome through opencli-mcp - #5638
Conversation
Add Chrome as an MCP recommendation backed by the bundled opencli-mcp. One click stores a stdio connection and sends the user to the Chrome Web Store for the extension; the detail keeps a Connect Chrome action and follows the extension until it reaches the host. Chrome only installs extensions from the store, so that click cannot be removed. Everything else that `opencli-mcp setup` does runs inside Maka: - Maka runs opencli-mcp on its own Electron binary in Node mode, so users need no Node install. Two launchers under userData are rewritten on every start and are the only paths mcp.json and Chrome's host manifest hold; the executable itself moves on every AppImage launch. - Maka writes the Native Messaging manifest itself instead of calling opencli-mcp's registerHost, whose launcher runs process.execPath without ELECTRON_RUN_AS_NODE and would open a Maka window. Directory lists and identifiers are reused from the package. A manifest owned by another live install is left alone. - Chrome status comes from the host's health endpoint, not the MCP status: without the extension the server still starts in its embedded runtime and lists every tool. The built-in browser tools stay as they are: they drive the conversation's embedded browser without the user's logins; this connection drives the user's own Chrome. The notice generator now reads packages that a registry dependency ships inside itself and links by `file:`, which npm records without a version. Generated-by: Claude Code
A new desktop shared file grew the legacy AppShell renderer closure, which the architecture ratchet forbids. The status is part of the MCP bridge surface, so it lives with the other MCP bridge types. Generated-by: Claude Code
The Chrome native host registration calls reg.exe on Windows. Generated-by: Claude Code
… package opencli-mcp parses JavaScript through web-tree-sitter and loads only the grammar's wasm. The rebuilt native binding carried MSBuild intermediates under app.asar.unpacked whose paths exceed MAX_PATH once installed, which broke the Windows sandbox ACL walk and the uninstaller cleanup in the installer lifecycle check. Generated-by: Claude Code
0.0.18 keeps the stdio server usable when Chrome starts after Maka: tool calls report host_unavailable until the host appears instead of staying in an embedded runtime that never reaches it (jackwener/opencli-mcp#3). It also ships the adapter SDK inside the package under Apache-2.0 (jackwener/opencli-mcp#2), so the inferred MIT copyright override and the lockfile link handling for the separate SDK package go away. 0.0.17 added an exports map that lists only ./adapter-sdk. The host modules and CLI entry are now reached by file path from that export's package root; this holds for the pinned version and goes away once jackwener/opencli-mcp#5 gives embedders a public entry. The host command drops --native, which 0.0.18 no longer takes. Generated-by: Claude Code
…n tests apache#5510 added assertions on `TurnViewModel.assistant`, which apache#5559 had already removed, so `tsc -p packages/ui` fails on main and every job that builds @maka/ui fails with it. The answers now come from the turn's text timeline items. Each assertion keeps what it proved: the earlier snapshot still holds only the original answer, and the appended step shows up as its own text item. Generated-by: Claude Code
The models.dev refresh in apache#5678 gave Vercel's openai/gpt-5.1-thinking the minimal and xhigh efforts, but the Vercel Gateway test still pinned the previous snapshot's four levels. main's test job stopped at the packages/ui type error first, so this failure stayed hidden there. Generated-by: Claude Code
# Conflicts: # packages/ui/src/__tests__/transcript-projection.test.ts
Replace the generic pointer icon with Google Chrome's mark, vendored unchanged from Allogo (MIT) at the same pinned commit as the Notion and Linear marks. The renderer inventory records its upstream path and SHA-256 under the Allogo entry, and the trademark boundary now names Google Chrome: the mark only identifies the browser the connection drives. Generated-by: Claude Code
|
AI-assisted review by Codex of commit The Chrome icon update follows the existing image-rendering path, and the source inventory checks pass (5/5). Two P2 issues remain in the connection setup:
The Windows routing check used a simulated platform branch, not a real Windows browser session. The existing Windows test only compares the generated The adapter boundary looks reasonable, and these fixes should not require a deeper refactor. I recommend addressing both issues before merging. This is an automated review, not an independent human approval. |
…rations On Windows the store page always went to the default browser, so with Edge or Firefox as the default the extension could not be installed. Start chrome.exe from Chrome's install locations (per-machine and per-user) first, and fall back to the default browser only when none starts. Uninstalling a global opencli-mcp leaves its launcher and host manifest behind while removing the main.js the launcher runs. Maka treated the surviving launcher as a live install and never replaced the manifest, so Connect Chrome could not repair the connection. Another install now counts as live only while every absolute path its launcher quotes still exists. Generated-by: Claude Code
|
Thanks, both fixed in f44ff87.
|
The test's stand-in chrome.exe is a shell script, so it is skipped on Windows and has to be recorded in the Windows skip inventory. Generated-by: Claude Code
Summary
Maka's built-in browser tools drive the conversation's embedded browser, which has none of the user's logins. This PR adds the other half: an MCP connection to the user's own signed-in Chrome through opencli-mcp, bundled with Maka and set up from the MCP page.
Flow. 扩展 → MCP → 推荐 → Chrome +. The click stores a stdio connection and opens the Chrome Web Store page for the extension in Chrome, even when another browser is the default (on Windows,
chrome.exefrom its per-machine or per-user install location; the default browser only when Chrome is not found). The row shows 等待 Chrome (attention) and the detail keeps a 连接 Chrome action until the extension reaches the host. The page polls the host every 2 s while that is pending, so nothing needs refreshing.Why one store click remains. Chrome installs consumer extensions only from the Web Store; silent install exists only as enterprise policy. Everything else
opencli-mcp setupdoes now runs inside Maka:ELECTRON_RUN_AS_NODE. Two launchers underuserData/opencli-mcp/are rewritten on every start, and they are the only paths stored inmcp.jsonand in Chrome's host manifest. The executable path itself moves on every AppImage launch.registerHost. That function's launcher runsprocess.execPathwithoutELECTRON_RUN_AS_NODE, which under Electron would start a Maka window. The directory list, profile detection and identifiers are loaded from the package, not copied. A manifest that points at another live install (for example a globalopencli-mcp setup) is left alone; the stdio server reaches whichever host Chrome starts. An install counts as live only while every path its launcher runs still exists, so a launcher left behind by uninstalling the global package is replaced. Registration writes into Chrome's directories only when the user clicks./health, not from the MCP connection. Without the extension, the server still starts and lists all 18 tools, but every call returnshost_unavailable. Showing that as "connected" would hide the missing step until a call fails.The built-in
browser_*tools are unchanged. The two cover different scenarios: the embedded browser is visible inside Maka and has no logins; this connection drives the user's own Chrome.Packaging. opencli-mcp 0.0.18 is pinned exactly. Its
exportsmap lists only./adapter-sdk, so the CLI entry and the few host modules are reached by file path from that export's package root, and their types are declared inopencli-mcp.d.ts. The file path holds for the pinned version. jackwener/opencli-mcp#5 asks for a public entry and forstdioto register the host itself, which would remove the self-written manifest too.tree-sitter-javascript's native build output is excluded from the package: opencli-mcp loads only its wasm, and the build intermediates exceeded the Windows path limit in the installer.Chrome mark. The entry shows Google Chrome's mark, vendored unchanged from Allogo (MIT) at the same pinned commit as the Notion and Linear marks.
THIRD_PARTY_LICENSES.txtrecords its upstream path and SHA-256, whichsource-legal-inventory.test.mjschecks, and its trademark boundary now names Google Chrome: the mark only identifies the browser this connection drives.Unrelated test fix.
model-factory-thinking.test.tsstill pinned Vercel'sopenai/gpt-5.1-thinkingto the four efforts of the snapshot before #5678, which now declaresminimalandxhighas well. main'stestjob stopped at thepackages/uitype error first (fixed by #5697), so this failure only showed up here.Verification
opencli-chrome.test.ts: the POSIX launchers actually run an entry in Node mode, including a path that contains a quote (stdioandhost, with Chrome's appended origin ignored); Windows.cmdcontent; manifest targeting (Chrome always, other browsers only when their profile exists, a stale manifest overwritten, another live install kept, a global launcher whosemain.jswas removed replaced); on Windows the store page starts an installedchrome.exeinstead of the default browser, which is used only when no Chrome is found (a stand-inchrome.exe, so not run on a real Windows browser).module-hub-mcp-controller.test.ts: a configured Chrome server is polled until the extension connects, and polling then stops.mcp-preload-scope.test.tscovers the two new channels.ExtensionsMcpChrome(the click adds the server, starts connecting once, leaves 推荐) andExtensionsMcpChromeWaiting(the row shows 等待 Chrome and counts as needing attention, not "16 个工具"). Storybook smoke passes: 409 stories, 443 theme renders.electron-builder --mac dir):dist/main/opencli-chrome.jsloads fromapp.asarunderELECTRON_RUN_AS_NODE, writes launchers that point into the asar, and the writtenstdiolauncher answersinitialize.tab_listreturnshost_unavailable. About 3 s later the extension has respawned the host, and on the same sessiontab_listandtab_opensucceed. Disconnecting closes the tab that was opened.typecheck,typecheck:stories,format,lint,check:third-party-notices,audit-shipped-dependencies,windows:inventory.Not run:
AI use
Tool(s) and scope: Claude Code: investigation, implementation, tests, and this description.
Checklist
Does this PR entail a change in behavior?