Skip to content

Commit 53b3163

Browse files
authored
fix(mcp): keep Playwright MCP handshake nonblocking (#321)
* fix(mcp): keep Playwright MCP handshake nonblocking * fix(app): restore auth terminal checks * fix(lib): restore grok device auth command * fix(mcp): address coderabbit review comments
1 parent e7107a6 commit 53b3163

30 files changed

Lines changed: 489 additions & 148 deletions
299 KB
Loading
105 KB
Loading

packages/app/src/docker-git/api-client-auth.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@ import type {
2525
AuthGithubLoginCommand,
2626
AuthGithubLogoutCommand,
2727
AuthGithubStatusCommand,
28-
AuthGrokLogoutCommand,
29-
AuthGrokStatusCommand,
3028
AuthGitlabLoginCommand,
3129
AuthGitlabLogoutCommand,
32-
AuthGitlabStatusCommand
30+
AuthGitlabStatusCommand,
31+
AuthGrokLogoutCommand,
32+
AuthGrokStatusCommand
3333
} from "./frontend-lib/core/domain.js"
3434
import { resolvePathFromCwd } from "./frontend-lib/usecases/path-helpers.js"
3535
import type { ApiAuthRequiredError, ApiRequestError } from "./host-errors.js"

packages/app/src/docker-git/api-client.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,11 @@ export {
3131
githubLogin,
3232
githubLogout,
3333
githubStatus,
34-
grokLogout,
35-
grokStatus,
3634
gitlabLogin,
3735
gitlabLogout,
38-
gitlabStatus
36+
gitlabStatus,
37+
grokLogout,
38+
grokStatus
3939
} from "./api-client-auth.js"
4040
export {
4141
type ApiContainerTask,

packages/app/src/docker-git/cli/usage.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,12 @@ Container runtime env (set via .orch/env/project.env):
102102
MCP_PLAYWRIGHT_ISOLATED=1|0 Isolated browser contexts; default 0 shares the VNC session
103103
MCP_PLAYWRIGHT_CDP_GUARD=1|0 Guard CDP so MCP cannot close/crash shared Chromium (default: 1)
104104
MCP_PLAYWRIGHT_BLOCK_BROWSER_CLOSE=1|0 Block destructive Browser.close/crash CDP methods (default: 1)
105-
MCP_PLAYWRIGHT_CDP_ENDPOINT=http://... Override CDP endpoint (default: http://dg-<repo>-browser:9223)
106-
MCP_PLAYWRIGHT_RETRY_ATTEMPTS=<n> Retry attempts for nested browser startup wait (default: 10)
107-
MCP_PLAYWRIGHT_RETRY_DELAY=<seconds> Delay between retry attempts (default: 2)
105+
MCP_PLAYWRIGHT_CDP_ENDPOINT=http://... Override CDP endpoint (default: http://127.0.0.1:9223)
106+
MCP_PLAYWRIGHT_CDP_TIMEOUT=<ms> CDP connect timeout passed to Playwright MCP (default: 60000)
107+
MCP_PLAYWRIGHT_READY_ATTEMPTS=<n> Startup readiness attempts before disabling broken MCP (default: 60)
108+
MCP_PLAYWRIGHT_READY_DELAY=<seconds> Delay between startup readiness attempts (default: 1)
109+
MCP_PLAYWRIGHT_RETRY_ATTEMPTS=<n> Legacy CDP preflight attempts when CDP guard is disabled (default: 10)
110+
MCP_PLAYWRIGHT_RETRY_DELAY=<seconds> Delay between legacy preflight attempts (default: 2)
108111
109112
Auth providers:
110113
github, gh GitHub CLI auth (tokens saved to env file)

packages/app/src/docker-git/program-auth.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,19 @@ import {
99
githubLogin,
1010
githubLogout,
1111
githubStatus,
12-
grokLogout,
13-
grokStatus,
1412
gitlabLogin,
1513
gitlabLogout,
1614
gitlabStatus,
15+
grokLogout,
16+
grokStatus,
1717
type JsonValue,
1818
renderJsonPayload
1919
} from "./api-client.js"
2020
import { type ControllerRuntime, ensureControllerReady } from "./controller.js"
2121
import type { Command } from "./frontend-lib/core/domain.js"
2222
import type { ApiRequestError, CliError } from "./host-errors.js"
2323
import { terminalAuthTitle } from "./menu-auth-shared.js"
24-
import { attachTerminalSession } from "./terminal-session-client.js"
24+
import { attachTerminalSession, type TerminalSessionClientError } from "./terminal-session-client.js"
2525

2626
type OperationalCommand = Exclude<Command, { readonly _tag: "Help" }>
2727

@@ -111,7 +111,7 @@ const handleGrokLoginCommand = (
111111
) =>
112112
withControllerReady(
113113
createAuthTerminalSession("GrokOauth", command.label).pipe(
114-
Effect.flatMap((session) =>
114+
Effect.flatMap((session): Effect.Effect<void, ApiRequestError | TerminalSessionClientError> =>
115115
session === null
116116
? Effect.fail(missingAuthTerminalSessionError("GrokOauth"))
117117
: attachTerminalSession({

packages/app/src/lib/core/templates-entrypoint.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import { renderEntrypointGitConfig, renderEntrypointGitHooks } from "./templates
2727
import { renderEntrypointGrokConfig } from "./templates-entrypoint/grok.js"
2828
import { renderEntrypointDockerGitBootstrap } from "./templates-entrypoint/nested-docker-git.js"
2929
import { renderEntrypointOpenCodeConfig } from "./templates-entrypoint/opencode.js"
30+
import { renderEntrypointPlaywrightBrowserRuntime } from "./templates-entrypoint/playwright-browser.js"
3031
import { renderEntrypointProjectAgentRules } from "./templates-entrypoint/project-rules.js"
3132
import { renderEntrypointRtkConfig } from "./templates-entrypoint/rtk.js"
3233
import { renderEntrypointBackgroundTasks } from "./templates-entrypoint/tasks.js"
@@ -47,7 +48,6 @@ export const renderEntrypoint = (config: TemplateConfig): string =>
4748
renderEntrypointCodexHome(config),
4849
renderEntrypointCodexSharedAuth(config),
4950
renderEntrypointOpenCodeConfig(config),
50-
renderEntrypointMcpPlaywright(config),
5151
renderEntrypointZshShell(config),
5252
renderEntrypointZshUserRc(config),
5353
renderEntrypointPrompt(),
@@ -60,6 +60,8 @@ export const renderEntrypoint = (config: TemplateConfig): string =>
6060
renderEntrypointProjectAgentRules(),
6161
renderEntrypointAgentsNotice(config),
6262
renderEntrypointDockerSocket(config),
63+
renderEntrypointPlaywrightBrowserRuntime(config),
64+
renderEntrypointMcpPlaywright(config),
6365
renderEntrypointGitConfig(config),
6466
renderEntrypointClaudeConfig(config),
6567
renderEntrypointGeminiConfig(config),

packages/app/src/lib/core/templates-entrypoint/claude.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ const renderClaudeMcpPlaywrightConfig = (): string =>
193193
String.raw`# Claude Code: keep Playwright MCP config in sync with container settings
194194
CLAUDE_SETTINGS_FILE="${"$"}{CLAUDE_HOME_JSON:-$CLAUDE_CONFIG_DIR/.claude.json}"
195195
docker_git_sync_claude_playwright_mcp() {
196-
CLAUDE_SETTINGS_FILE="$CLAUDE_SETTINGS_FILE" MCP_PLAYWRIGHT_ENABLE="$MCP_PLAYWRIGHT_ENABLE" node - <<'NODE'
196+
CLAUDE_SETTINGS_FILE="$CLAUDE_SETTINGS_FILE" MCP_PLAYWRIGHT_ENABLE="${"$"}{MCP_PLAYWRIGHT_ENABLE:-0}" node - <<'NODE'
197197
const fs = require("node:fs")
198198
const path = require("node:path")
199199

packages/app/src/lib/core/templates-entrypoint/codex.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ EOF
9999
fi
100100
101101
if [[ -z "$MCP_PLAYWRIGHT_CDP_ENDPOINT" ]]; then
102-
MCP_PLAYWRIGHT_CDP_ENDPOINT="http://__SERVICE_NAME__-browser:9223"
102+
MCP_PLAYWRIGHT_CDP_ENDPOINT="http://127.0.0.1:9223"
103103
fi
104104
105105
# Replace the docker-git Playwright block to allow upgrades via --force without manual edits.

packages/app/src/lib/core/templates-entrypoint/gemini.ts

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -160,13 +160,6 @@ const geminiSettingsJsonTemplate = `{
160160
"selectedType": "oauth-personal"
161161
},
162162
"disableYoloMode": false
163-
},
164-
"mcpServers": {
165-
"playwright": {
166-
"command": "docker-git-playwright-mcp",
167-
"args": [],
168-
"trust": true
169-
}
170163
}
171164
}`
172165

@@ -204,10 +197,40 @@ if [[ -d /etc/sudoers.d ]]; then
204197
chmod 0440 /etc/sudoers.d/gemini-agent
205198
fi`
206199

207-
const renderGeminiMcpPlaywrightConfig = (_config: TemplateConfig): string =>
208-
String.raw`# Gemini CLI: keep Playwright MCP config in sync (TODO: Gemini CLI MCP integration format)
209-
# For now, Gemini CLI uses MCP via ~/.gemini/settings.json or command line.
210-
# We'll ensure it has the same Playwright capability as Claude/Codex once format is confirmed.`
200+
const renderGeminiMcpPlaywrightConfig = (): string =>
201+
String.raw`# Gemini CLI: keep Playwright MCP config in sync with container settings
202+
docker_git_sync_gemini_playwright_mcp() {
203+
GEMINI_CONFIG_SETTINGS_FILE="$GEMINI_CONFIG_SETTINGS_FILE" MCP_PLAYWRIGHT_ENABLE="${"$"}{MCP_PLAYWRIGHT_ENABLE:-0}" node - <<'NODE'
204+
const fs = require("node:fs")
205+
const path = require("node:path")
206+
const settingsPath = process.env.GEMINI_CONFIG_SETTINGS_FILE
207+
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value)
208+
if (typeof settingsPath !== "string" || settingsPath.length === 0) process.exit(0)
209+
210+
let settings = {}
211+
try {
212+
const parsed = JSON.parse(fs.readFileSync(settingsPath, "utf8"))
213+
if (isRecord(parsed)) settings = parsed
214+
} catch {}
215+
216+
const nextServers = { ...(isRecord(settings.mcpServers) ? settings.mcpServers : {}) }
217+
if (process.env.MCP_PLAYWRIGHT_ENABLE === "1") {
218+
nextServers.playwright = { command: "docker-git-playwright-mcp", args: [], trust: true }
219+
} else {
220+
delete nextServers.playwright
221+
}
222+
223+
const nextSettings = { ...settings }
224+
Object.keys(nextServers).length > 0 ? nextSettings.mcpServers = nextServers : delete nextSettings.mcpServers
225+
226+
if (JSON.stringify(settings) === JSON.stringify(nextSettings)) process.exit(0)
227+
228+
fs.mkdirSync(path.dirname(settingsPath), { recursive: true })
229+
fs.writeFileSync(settingsPath, JSON.stringify(nextSettings, null, 2) + "\n", { mode: 0o600 })
230+
NODE
231+
}
232+
233+
docker_git_sync_gemini_playwright_mcp`
211234

212235
const renderGeminiProfileSetup = (config: TemplateConfig): string =>
213236
String.raw`GEMINI_PROFILE="/etc/profile.d/gemini-config.sh"
@@ -311,7 +334,7 @@ export const renderEntrypointGeminiConfig = (config: TemplateConfig): string =>
311334
[
312335
renderGeminiAuthConfig(config),
313336
renderGeminiPermissionSettingsConfig(config),
314-
renderGeminiMcpPlaywrightConfig(config),
337+
renderGeminiMcpPlaywrightConfig(),
315338
renderGeminiSudoConfig(config),
316339
renderGeminiProfileSetup(config),
317340
renderEntrypointGeminiNotice(config)

0 commit comments

Comments
 (0)