Skip to content

fix(claude-code): patch playwright MCP on every session start (#98) - #99

Merged
gatezh merged 1 commit into
masterfrom
fix-mcp-cache-mid-session
May 12, 2026
Merged

gatezh merged 1 commit into
masterfrom
fix-mcp-cache-mid-session

Conversation

@gatezh

@gatezh gatezh commented May 12, 2026

Copy link
Copy Markdown
Owner

What

Wires patch-playwright-mcp as a Claude Code SessionStart hook via an image-baked /etc/claude-code/managed-settings.json, so the patch runs before any MCP launches in every new or resumed session — not just at container start.

Why

Closes #98. The playwright plugin can auto-update mid-container-run, extracting a fresh cache dir whose .mcp.json defaults to --browser chrome and points at /opt/google/chrome/chrome (not shipped in this image). Existing postCreateCommand/postStartCommand wiring only patches cache dirs that exist at the moment they run — anything created later stays broken until the next container restart, producing:

Error: Chromium distribution 'chrome' is not found at /opt/google/chrome/chrome

SessionStart is the canonical Claude Code hook for "run before the first prompt of every session" and is documented to run synchronously before the model receives input, so by the time MCP launches the patched .mcp.json is already on disk.

The settings file lives at the Linux managed-settings path (/etc/claude-code/managed-settings.json) so it has highest precedence, sits outside the /home/node/.claude named volume, and survives volume re-creation across container rebuilds.

Changes

  • Add claude-code/.devcontainer/managed-settings.json — SessionStart hook entry invoking /usr/local/bin/patch-playwright-mcp on all session sources (startup, resume, clear, compact). Matcher omitted; the patch is idempotent and ~20 ms.
  • claude-code/.devcontainer/Dockerfile — COPY the new file to /etc/claude-code/managed-settings.json for both default and sandbox targets (shared base stage).
  • .github/workflows/build-claude-code.yml — extend the build trigger paths: filter to pick up managed-settings.json; add a jq -e assertion to the verify matrix on all four target × arch combinations confirming the hook is actually present in the published image.
  • claude-code/.devcontainer/devcontainer.json + claude-sandbox/devcontainer.json + init-plugins.sh — update comments to describe postCreateCommand/postStartCommand as defense in depth alongside the new hook, and add issue [BUG] patch-playwright-mcp misses mid-session plugin cache updates #98 cross-references.

Notes

  • No script changes. patch-playwright-mcp was already idempotent and looped over every cache dir; this PR only adds a third invocation cadence.
  • Existing devcontainers won't get the hook until they rebuild from a refreshed image. The Dockerfile change forces a latest rebuild; downstream projects pick it up on next image pull.
  • Verified canonical against upstream docs (2026-05-12):
    • SessionStart hook schema and stdin payload per code.claude.com/docs/en/hooks.
    • Linux managed-settings path per code.claude.com/docs/en/settings.
    • --browser chromium, --executable-path, --no-sandbox, --headless flags valid in @playwright/mcp v0.0.75 (README + upstream Dockerfile ENTRYPOINT).

Test plan

  • jq parse of managed-settings.json succeeds and verify-command predicate evaluates true locally.
  • hadolint clean on modified Dockerfile (against .hadolint.yaml).
  • actionlint clean on modified workflow.
  • CI build succeeds and the new jq -e verify assertion passes on all four target × arch combinations.
  • In a refreshed devcontainer, observe .mcp.json mtimes update at every session start (not just container start), and confirm mcp__plugin_playwright_playwright__* tools work after a mid-session plugin auto-update.

Closes #98.

Wires patch-playwright-mcp as a Claude Code SessionStart hook via image-baked
managed settings. Closes the mid-container-run gap where the playwright plugin
auto-updates after postStartCommand fires, leaving newly extracted cache dirs
pointing at the missing /opt/google/chrome/chrome binary until the next
container start.

postCreateCommand and postStartCommand wiring stays as defense-in-depth.
@gatezh
gatezh merged commit 65ef170 into master May 12, 2026
8 checks passed
gatezh added a commit that referenced this pull request May 13, 2026
…pping (#100)

The verify-command added in #99 embedded literal " around the expected path
inside a single-quoted jq filter. After GHA expansion into bash -c "...",
the inner " terminated and reopened the outer "..." rather than reaching
jq as a string delimiter, so jq received

    .hooks.SessionStart[0].hooks[0].command == /usr/local/bin/patch-playwright-mcp

and failed with "unexpected '/'". Switch to the printenv | grep -qx idiom
used since #93: jq -r prints the bare string value, grep -qx asserts an
exact match. No literal " inside the matrix value, so the value survives
both the YAML decode and the bash -c wrapping unchanged.
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.

[BUG] patch-playwright-mcp misses mid-session plugin cache updates

1 participant