The same click can carry a different contract
A command line and an MCP tool can both express “click element e7.” That does not make their browser sessions, defaults, permissions, artifacts, or runtime results equivalent.
This guide ships an original, deterministic, zero-network contract-translation lab. It parses invented interface requests shaped only by pinned official documentation. It did not install or execute Playwright, start an MCP server, open a browser, visit a page, measure tokens or latency, or compare result quality.
Compare declared intent before runtime
The useful common record is deliberately small: action, target, origin boundary, expected condition, timeout and its provenance, artifact policy, and profile policy. Only action and target come from the two interface requests in the allowed click fixture. The remaining fields are an explicit local policy wrapper; the lab does not pretend those labels are official Playwright inputs.
| Field | CLI fixture | MCP fixture | Provenance |
|---|---|---|---|
| Action | click | browser_click | pinned official interface vocabulary |
| Target | e7 | target: e7 | synthetic request |
| Origin | loopback only | loopback only | local policy wrapper |
| Expected condition | status-ready | status-ready | local policy wrapper |
| Timeout | 5,000 | 5,000 | local policy wrapper, not an observed default |
| Artifacts | none | none | local policy wrapper |
| Profile | isolated | isolated | local policy wrapper |
The first case returns equivalent-declared-intent. That verdict means only that the normalized requests and explicit wrapper policy match. It is not evidence that two real browser runs would behave alike.
Three reasons not to say “equivalent”
The second fixture marks a mismatch because one envelope labels its timeout official-explicit while the other labels the same number local-policy. Equal numbers with different provenance are not normalized into agreement.
The third fixture compares a CLI screenshot request with an MCP click. They are incomparable: one creates an artifact and the other requests an interaction.
The fourth fixture uses a foreign origin and is rejected by the local loopback policy before comparison. That is a wrapper decision, not a claim that either upstream interface enforces this exact boundary.
For navigation requests, the lab also parses the actual target URL and requires its origin to equal that envelope’s declared loopback origin. A safe-looking wrapper cannot conceal a foreign navigation target.
The fifth fixture omits the CLI profile policy and is incomparable. An absent field is not silently filled from the other envelope or from an assumed default.
Run the inert comparison
Prerequisite: Node.js 24 or newer. Download the files into one directory, rename the script from .txt to .mjs, and run:
node browser-interface-contract-lab.mjs browser-interface-contracts.synthetic.json result.json
The script uses Node.js built-ins, makes no network request, and refuses to overwrite an existing result. Repository tests run the comparison twice in isolated output paths, assert identical result bytes, exercise malformed and unknown fields, and verify the published downloads are exact copies.
What was pinned
Read-only retrieval on September 20, 2026 pinned the official Playwright CLI README at tag v0.1.21, commit 74354ecc7a43da16d91a9bc54fa8db8283a3fcf5, and the official Playwright MCP README at tag v0.0.82, commit f1257a5a67aff872f947fae274759f7d54853862. The downloadable source record includes the raw URLs, whole-file SHA-256 digests, and short command/tool-name excerpts used to shape the inert fixtures.
Primary references:
- Playwright CLI documentation
- Playwright CLI repository
- Playwright MCP documentation
- Playwright MCP repository
- MCP tools specification, 2025-11-25
The MCP specification defines structured tools with schemas and optional annotations, but says annotations are hints rather than a trusted security boundary. A shared transport does not give unrelated tools shared semantics.
Review questions
- Which fields come from the upstream request, and which come from local policy?
- Are omitted defaults surfaced with provenance instead of guessed?
- Do both sides use the same origin, session/profile, timeout, artifact, and expected-condition policy?
- Is a mismatch reported instead of normalized away?
- Is runtime equivalence withheld until exact versions execute against the same controlled page and assertions?
The practical result is not “CLI beats MCP.” It is a reviewable translation boundary that can say same declared intent, mismatch, or incomparable without claiming an unperformed browser experiment.