WebKitUI MCP — Native WebKit for Mac
Provides an optional local Ollama ranker with think: false, strict budgets, and deterministic fallback, used for ranking observations during browser automation.
WebKitUI MCP
Native WebKit automation for Apple Silicon, exposed through MCP and designed for an LLM rather than a human.
This repository is a Swift rewrite. The retained TypeScript/Playwright files are prior art only and are not the implementation being extended.
What exists
Native
WKWebViewruntime using the persistent system WebKit data store for real authenticated sessions.MCP 2026-07-28 stdio server with legacy initialization compatibility.
Thirteen bounded tools, including authenticated native downloads, explicit page/element scrolling, and bounded text extraction for rendered virtualized logs.
Observation-scoped element symbols backed by semantic locator recipes and fresh action-time resolution.
Five separate addressing counters:
address_resolution_failed,address_now_ambiguous,logical_target_changed,node_replaced_but_semantic_locator_recovered, andcoordinate_invalidated_by_layout_change.Provenance attached to every serialized page string.
Observation-time privacy minimization: non-rendered controls are removed before bounding, sensitive/token-like fields never serialize values, and a sensitive select publishes neither its option labels, nor how many it has, nor the one currently chosen in it — a selected label is that control's value. The control is still reported, with its role and accessible name, so it can be handed to a human.
Checkpoint-plus-delta observation history and Minimal Failure Set coverage metrics.
Optional local Ollama ranker with
think: false, strict budgets, and deterministic fallback.Transaction ledger with preconditions, exact post-conditions, idempotency keys, indeterminate outcomes, receipts, and reconciliation without replay.
Human confirmation before every exposed click and open-world navigation. Navigation defaults to a server-owned native macOS dialog so a client cannot silently decline the round trip; MCP multi-round navigation remains opt-in.
browser_sessioncan set a bounded 320×240–3840×2160 CSS viewport and can navigate back, forward, or reload using WebKit's own history list. History movement is confirmed against the destination WebKit reports; reloading a page produced by a form submission is refused before confirmation to prevent replay.Camera, microphone, and geolocation requests are always denied by the native
WKUIDelegate. The observation names the requesting origin and permission, with repeated requests counted and distinct records bounded; there is no MCP operation that can grant one.The confirmation names the origin a submit control's data would reach, computed server-side from the freshly re-resolved element rather than from its accessible name, and says so explicitly when that origin differs from the page the operator is on. A submit button's
formactionoverrides its form'saction, so a control whose accessible name reads harmlessly can post elsewhere.Confirmations are counted in a rolling 60-second window. From the fifth, the dialog states how many have been requested; the twentieth is refused instead of presented, because a dialog a human clicks twenty times in a row has stopped being a gate.
Legacy MCP clients receive the same exact-action authority boundary through a server-owned native macOS confirmation dialog; the model cannot supply or forge the approval value.
Local human handoff:
handoff_startimmediately returns an opaque session-bound resume token while the actual WebKit session becomes a visible window.handoff_statusis non-blocking;handoff_resumeconsumes the token only after local confirmation and returns a fresh observation. The agent remains locked out throughout human control.An active human-control window can be brought forward again with
handoff_focuswithout changing who controls the page. Session status says whether that surface is currently presented, and restricted authentication status exposes only bounded rendering booleans—never page text, field values, private URL components, or network payloads.The packaged handoff app installs a native Edit menu, so standard first-responder shortcuts such as Command-X/C/V/A work inside WebKit form controls.
MCP sessions use a loopback SOCKS5 boundary, one per profile and shared by its sessions, with failover disabled: hostnames are resolved once, public addresses are pinned, and private/reserved destinations plus non-TCP SOCKS commands fail closed.
One process at a time controls the browser for the macOS account: the host lease belongs to that process and is released with its last session or on process death. The production CLI holds one session.
Private remote clients can use the app-owned broker plus a forced-command SSH relay; WebKit and authenticated profile data remain on the logged-in Mac.
Multiple relay clients may use the same long-lived broker concurrently, each in its own session and window, up to three, on the shared default profile. A session belongs to one client: another client gets
session_in_usewithwait_only=trueand cannot observe, navigate, act, invalidate addresses, or request duplicate user control in it. Ownership transfers after the owning client disconnects, or through a human-confirmedclient_handoff. Native confirmations are shown one at a time across the app, and each names the requesting agent as a quoted, self-reported name.Each independent task must call
browser_session(operation: "open")and keep its returnedsession_idfor all page operations. On a shared transport, a full broker refuses an open that would return an already-owned page. Status without an ID selects the caller's sole session; when it owns several, it asks for an explicit ID. A new client with spare capacity is directed to open its own page. Host lease metadata reports the broker's remaining session slots.While a person holds the human control window, a pop-up the page opens (a sign-in with Google or Apple, say) is a real window sharing the page's profile, protected proxy and
window.opener, at most four; all close when the agent resumes. Under agent control new windows stay refused and reported.The app broker owns one live browser across MCP client reconnects. Every reconnect invalidates observations, pending approvals, capabilities, and transaction coordinators before returning the preserved session handle.
The native host starts the AppKit event loop before MCP work and keeps the live
WKWebViewattached to one opaque window. Agent control orders that window out; human handoff presents the same view without reparenting it. A packaged visual smoke mode checks the actual WindowServer pixels.The stdio relay stays alive across broker restarts. It reconnects before the next undispatched request and never silently replays a request whose outcome became unknown during a restart.
Durable multi-client status works without a session ID and reports only privacy-safe holder metadata (client name/version, PID, age, inactivity and policy).
open(wait_timeout_ms: ...)can wait up to 60 seconds for the local host lease without stealing it; dead transports release their session owner.browser_session(operation: "client_handoff")can transfer an idle session only after local human confirmation and a final no-active-call check.A secretless SiliconPass fill can return
credential_not_found; WebkitUIMCP then offers a native human handoff for manual sign-in and addition/update in SiliconPass. No credential value crosses MCP, JSON, logs, or the clipboard.Web-content termination invalidates every observation immediately; recovery reloads the host-owned last URL without replaying an action. A forced-crash fixture verifies that an
HttpOnlyauthenticated cookie pluslocalStorageandsessionStoragesurvive in the same view/data-store lifetime.The macOS companion is a regular Dock app with a local activity window. It records only allowlisted MCP tool names, outcome, timestamp, duration and a bounded error type. Parameters, URLs, page content, credentials, cookies, keystrokes and response bodies are structurally absent. Owner-only JSONL files rotate automatically and can be exported or cleared from the app.
Related MCP server: mcp-browser
Deliberate limits
browser_actexposes click, native submit-control click, bounded non-sensitive input/textarea fill, Enter/Tab/Escape, blur, explicit input commit, and answering the one JavaScriptalert/confirm/promptdialog a page is suspended on (dialog_accept,dialog_dismiss,dialog_accept_value). A pending dialog is reported in the observation as untrusted site content, blocks every other operation until it is answered, is never answered automatically, and resolves to an explicit indeterminate outcome if nobody answers it.beforeunloadis out of scope: the public macOS SDK exposes no before-unload panel to an embedder. Native approval also routes public text fills through AppKit insertion with a measured trustedinputreceipt. Fill verifies both the freshly re-resolved semantic target's exact value and that its live validation state is not invalid. Other actions support exact URL or URL prefix, title, heading, exact/contains semantic text, checked, selected, enabled, semantic target absence (target_absentwithvalue="true"), value, validation state, character count, bounded state attributes, dialog, named panel, or selected-option postconditions. A same-URL SPA mutation returnssame_url_page_state_changedguidance instead of implying success. UI state never proves backend commit.browser_downloadconverts authenticated attachment responses toWKDownloadfrom either a fresh observed control or a protected same-origin URL fallback. It requires exact native confirmation plus a save-panel destination, never overwrites an existing file, and succeeds only after an on-disk receipt reports the HTTP status, suggested/final filename, MIME type, byte count, SHA-256, and decoded provisioning-profile UUID when available. Cookies, headers, and the absolute local destination path stay outside MCP.macOS file inputs use WebKit's native open-panel delegate. Selected regular files are bounded to 10 files and 50 MiB each; receipts may expose filenames, byte counts and SHA-256 values, but never local paths or file contents. A file-selection receipt is not provider acceptance: the action's independent postcondition must still verify the uploaded preview or saved state.
Fill dispatches normal
input/changeevents, so site handlers may autosave or cause server effects. It is destructive and human-confirmed; password controls require local human handoff.approval_mode: "native"sends confirmed click/submit and Enter/Tab/Escape through public AppKitNSEventhandling on the freshly re-resolvedWKWebViewtarget. An isolated message handler must observe the matching DOM event withevent.isTrusted == truebefore the receipt reports trust. Missing/mismatched receipts fail indeterminate; no flag is synthesized.approval_mode: "mcp", blur, and commit remain JavaScript-dispatched and report untrusted. Native public-text fill reports trust only when its matching AppKit insertion receipt is observed.Action results separately expose
confirmation_mode,dispatch_mode, andtrusted_gesture_state. Native confirmation alone never establishes event trust.Navigation readiness and rendered-content availability are separate. A document can reach
readyState=completeand mutation quiescence while remaining blank; navigation, observation, and text reads reportempty_or_unusablein that case and explicitly forbid treating the absence as page truth. A rendered textless canvas or media document remainsusable.browser_read_textreads only currently rendered virtualized lines. Use bounded scroll plus another read for additional ranges.No arbitrary JavaScript, raw CDP escape hatch, coordinate retry, proxy fleet, anti-bot bypass, or headless claim. A gate an agent can step around is not a gate: one JavaScript-evaluation call would do anything the confirmation exists to authorize one action at a time. Browserbase's MCP server also refuses JavaScript, so refusing it is not distinctive on its own; the combination surveyed for and not found elsewhere on 2026-09-09 is no JavaScript tool and a per-action gate and a real authenticated session.
Viewport resizing changes desktop CSS layout only. It does not emulate a mobile device—the public macOS SDK exposes no
WKWebViewContentModeAPI—andset_emulated_mediais deliberately absent because it does not help operate a person's site.Camera, microphone, and geolocation access cannot be granted through WebKitUI MCP. Requests are denied and reported in the next observation instead of leaving a page failure silent; use human control in a complete browser when the workflow requires one of those permissions.
No multiple tabs and no new-window handling. One session holds one exclusive host lease, which is what lets an approval refer to an unambiguous page.
No subresource or XHR request inspection. It is possible and it is not offered.
WKWebsiteDataStore.proxyConfigurationsis public from macOS 14 and is Apple DTS's own recommendation for reading aWKWebView's request contents, and a bundledWKWebExtensionwith thewebRequestpermission is public from macOS 15.4. Neither is free: the proxy route needs a trusted root certificate to see inside HTTPS, and the extension route reports no headers and cannot block. What is reported instead is narrow — the download receipt's HTTP status, and the egress proxy's accepted, blocked, pinned and timed-out connection counts. A main-frame navigation result carries no HTTP status today, and the proxy does not name the hosts it allowed or refused.Native AppKit dispatch is not a distinguishing feature and is not claimed as one.
safaridriverdispatchesNSEventthrough[window sendEvent:]exactly as this does, and the WebDriver specification requires every conformant driver to produce trusted events. What differs is the measurement: an action whose trusted DOM receipt is missing or mismatched fails indeterminate here, where Playwright's hit-target interceptor treats an absent event as success.The
WKFormInfosubmission gate is implemented, unit-tested, and does not fire. WebKit did not callwebView(_:willSubmitForm:submissionHandler:)on either macOS 27.0 build measured here,26A5416band26A5419a— not forsubmit(), not forrequestSubmit(), and not for a native trusted-gesture click. It is therefore not a second live gate and must not be read as one; it will decide if WebKit begins delivering the callback. The live defence against a submit control that posts to another site is the destination line in the confirmation.Registered cross-origin frames expose bounded rendered semantics with
THIRD_PARTY_EMBEDprovenance and a sanitized origin. Their geometry is explicitly frame-local;frameActionModes(or compactframe_action_modes) names eligible attempts even whenactionable=falsemeans no native pointer geometry. A confirmedhoverorselect_optionruns only as untrusted JavaScript in the exact child frame; non-sensitivepress_keyandfillcan use AppKit only when that frame returns a matching trusted DOM receipt. A native pointer click has no public frame-to-window coordinate transform, refuses before confirmation withcross_origin_native_geometry_unavailable, and points to live human handoff. This is bounded control reach, not proof of hosted checkout completion. Sensitive and authentication controls still require a human. Frames that cannot be evaluated, and frames beyond the bounded native registry, remain explicitly unreadable rather than being treated as empty page content.Some identity providers require a complete browser surface and do not render inside an app-embedded
WKWebView(for example a WebAuthn-only step without the browser passkey entitlement). Those returnfull_browser_requiredwith an internalsafari_compatibilityrequirement. Any already-restricted authentication origin may also usecompatibility_startas an explicit manual fallback when its native human handoff is present but unusable. The operation opens the exact private URL in Safari only after native confirmation; it never auto-switches merely because a page timed out, never replaces the native handoff, provides no Safari observation/control, and cannot return a Safari login to this MCP session. Complete the blocked workflow manually in the external browser. WebKitUI never copies cookies, passkeys, AutoFill data, or credentials between backends.takeSnapshotmay omit GPU-composited effects.No exactly-once or rollback claim for an uncooperative website.
Low concurrency is intentional because WKWebView has no per-view hard memory quota.
The protected network path is the MCP session registry or
WebKitRuntime(protectedWebsiteDataStore:); the lower-levelWebKitRuntime(websiteDataStore:)initializer is intentionally unprotected for fixtures and embedding.This is a bounded website-traffic control, not a complete process egress sandbox. The exact tested transports, exclusions and safe-use rule are in
docs/network-boundary.md.
Compared with the Safari MCP server
Apple's Safari MCP server ships inside safaridriver and is started with
safaridriver --mcp; Apple's own help text for the flag reads "Run as an MCP (Model
Context Protocol) server using stdio transport." It exposes seventeen tools — page
content, screenshots, network requests, console logs, JavaScript evaluation, DOM
interaction, viewport and media emulation, tab management. It needs two settings in two
different panes: "Show features for web developers" in Safari > Settings > Advanced, and
"Allow remote automation and external agents" in Safari > Settings > Developer. Apple's
floor is Safari 27 beta or Safari Technology Preview 247 or later, and Apple documents
Safari 27 beta on macOS 26 and macOS Sequoia as well as macOS 27, so it is not a macOS 27
requirement.
Apple aims it at web developers: it "gives your agent the ability to know how your code actually renders in the browser", and both sets of release notes file it under WebDriver > New Features. Apple also states it "runs entirely on your local machine and makes no network calls of its own" and that it "does not have access to your personal information in Safari (e.g. AutoFill or other browser activity)". For developing a site it is the better tool, it is included with Safari and Apple lists no separate price, and this project does not compete with it.
The difference is what happens when the site is not yours and you are signed in to it:
Safari MCP server | WebKitUI MCP | |
Purpose | inspect and debug a site you are developing | act on a site you are signed in to |
Approval | no confirmation step is documented, and none of the seventeen tools requests one | native macOS confirmation before every exposed click and open-world navigation |
Tool annotations | none: every tool carries only |
|
JavaScript evaluation | exposed as a tool | absent, with no CDP or coordinate fallback |
Session | Apple's WebDriver documentation states automation windows are "isolated from normal browsing windows, user settings, and preferences" and that a session "always starts from a clean slate" | its own |
Protocol | reports |
|
Network detail | full request inspection, including headers, body and timing | no per-request inspection: the download receipt's HTTP status, and the egress proxy's connection counts without host names |
Verification | inspection tools | an explicit postcondition per action, plus separate |
The isolation wording above is Apple's WebDriver documentation, about automation sessions generally. Apple has published no equivalent statement about the MCP server itself.
Both can be installed at once, and for most developers both should be.
Two things this project will not say about Apple's server, because Apple does not: that it cannot reach your cookies or your logged-in sessions — Apple's MCP post names AutoFill and "other browser activity" only — and that Apple states there is no confirmation step. The absence is documented; a denial is not.
Build and test
The product targets macOS 15+ on Apple silicon. Building the optional
WKJSHandle probe requires the macOS 27 SDK; those APIs stay feature-gated.
swift build -c release --arch arm64
xcrun swift-format lint --strict --recursive Sources Tests Package.swift
swift test --arch arm64
swift test -c release --arch arm64For a reproducible verification of the current checkout plus the signed local installation and its two-client transport:
scripts/verify-native-installed.shRun the server:
swift run -c release --arch arm64 webkitui-mcpBefore registration, run the secret-free local readiness check:
webkitui-mcp doctorIt checks the native confirmation helper, local owner-authentication policy, architecture, macOS version, and locally stored license state. It does not open a website, read browser data or credentials, authenticate the user, or contact the license service.
webkitui-mcp --help prints the stdio contract without starting the server.
The sibling webkitui-mcp-confirm helper owns legacy native dialogs so closing
an AppKit alert cannot terminate or corrupt the long-lived stdio server.
The process reads newline-delimited JSON-RPC from stdin, writes protocol responses only to stdout, and reserves stderr for diagnostics.
For a disposable direct process, install the CLI and register it normally:
release_bin="$(swift build --show-bin-path -c release --arch arm64)/webkitui-mcp"
release_dir="$(dirname "$release_bin")"
install -m 0755 "$release_bin" "$HOME/.local/bin/webkitui-mcp"
install -m 0755 "$release_dir/webkitui-mcp-confirm" "$HOME/.local/bin/webkitui-mcp-confirm"
codex mcp add webkitui-mcp -- "$HOME/.local/bin/webkitui-mcp"
claude mcp add --scope user webkitui-mcp -- "$HOME/.local/bin/webkitui-mcp"Install the two together and leave them side by side. Before showing a confirmation the server checks the helper next to it, and what it can demand depends on how the server itself is signed:
a notarized server pins its Developer ID team and the exact identifier the release script stamps, so nobody can drop a helper of their own beside it;
a server built from source is ad-hoc signed and has neither, so the check can only require that the helper sits next to it under its own name. That gives nothing away: whoever can write a helper beside an unsigned server can replace that server too.
Mixing the two is refused in both directions. If you re-sign one binary, re-sign the other with the same identity, or the confirmation will not appear and every navigation will fail closed.
Keyboard behaviour of the confirmation
The confirmation uses a nonactivating panel: it can receive keyboard input while the caller remains the active application, without adding a separate helper icon to the Dock. Two preferences, shared by a source build and the notarized app, decide what the keyboard may do:
# Return cancels and Escape closes after 1 s of initial keyboard focus (default).
defaults write com.lorislab.webkitui-mcp ConfirmationKeyboardDefault cancel
# Return/Escape have no default action; click, or Tab to a button then Space.
defaults write com.lorislab.webkitui-mcp ConfirmationKeyboardDefault none
# Arming delay for Return/Escape, 0 to 5 seconds (default 1).
defaults write com.lorislab.webkitui-mcp ConfirmationArmingDelaySeconds -float 2The arming delay starts after the initial display and key-window acquisition.
Queued Return/Escape input is checked against its original event timestamp. Initially no button has focus:
stray Return/Space press nothing, and Escape
is ignored until armed. Deliberately selecting a button with Tab and Space or
clicking still works. In none mode Escape stays disabled.
Approve is never a keyboard default and cannot be made one. No per-project or
per-session auto-approval exists; the design constraints for one are recorded
in docs/research/2026-09-01-goal-delegation-and-browser-addressing-sota.md.
For authenticated sessions that must survive Codex conversation reconnects, build the self-contained app instead:
scripts/package-preview.sh dist
scripts/verify-package-preview.sh distUnzip WebKitUI-MCP-0.6.24-preview.zip, move WebKitUI MCP.app to the
Applications folder, and open it. In the status window:
Enable Launch at Login. macOS may require approval in System Settings.
Copy and run the Codex setup command. It points to the relay embedded in the app bundle and the owner-only local Unix socket.
Keep the app in Applications after registration so the saved relay path remains valid.
The Activity journal button opens the local privacy-safe event history.
Its files live under ~/Library/Application Support/WebkitUIMCP/Activity with
owner-only permissions. Rotation retains at most seven 5 MiB archives plus the
active file. Clear removes activity files but preserves transaction
receipts; Export writes only the same redacted event schema.
The app uses Apple's Service Management API and does not install a mutable
plist in ~/Library/LaunchAgents. Prepare to uninstall disables Launch at
Login while preserving receipts and license data; then quit the app and move it
to the Trash. The preview archive is unsigned. Signing, notarization, clean-Mac
installation and publication are separate release gates.
Each MCP client receives isolated observations, confirmations, transactions,
and capability grants over the same durable browser. A logical
browser_session close detaches that client authority but deliberately keeps
the live browser; quitting the app destroys that in-memory page session.
Restart conversations opened before registration: MCP tool catalogs are fixed for a running conversation and are not retroactively replaced.
MCP flow
List the secretless persistent profile with
browser_session { operation: "profiles" }, thenbrowser_session { operation: "open", profile_id: "default" }.browser_navigateopens a native exact-destination approval dialog by default. Useapproval_mode: "mcp"only when the client reliably supports multi-round elicitation.browser_observe; useelement_scroll_into_view,browser_scroll, orbrowser_session { operation: "set_viewport", ... }, then observe again when needed.back,forward, andreloadare native-confirmed session operations.Use the fresh
observationIDandelementIDonce.For a login form, call
browser_fill_siliconpass. If it returnscredential_not_found, accept the native handoff and add or update the credential directly in SiliconPass.browser_actreturnsinput_required; approve the exact bound action.Read, export as canonical
ReceiptV1, or reconcile the receipt withbrowser_transaction. One redacted canonical object produces both JSON and Markdown; only the SHA-256 of the idempotency key is exported. Exported evidence never authorizes replay.
Large semantic pages can be read without oversized MCP results: browser_observe
supports role/name filters, maximum_elements, maximum_field_characters, and
element_offset; follow nextElementOffset until it is absent.
The enforced limits and the remaining release measurements are documented in
docs/performance-budgets.md.
The authority boundaries, attack paths, current controls and residual release
gates are maintained in
docs/security-threat-model.md.
Local data lifetimes and explicit-export boundaries are documented in
docs/privacy-retention.md.
The stable diagnostic allowlist and forbidden support data are documented in
docs/support-diagnostics.md.
The manual signed-update, rollback, support and incident rules are documented
in docs/release-maintenance-policy.md.
While a person holds the human control window, its bar offers Fill with
SiliconPass when the SiliconPass broker is installed. The person asks, not the
agent: WebKitUI binds the one visible password form in the frame being used,
including a restricted sign-in frame such as idmsa.apple.com, and SiliconPass
matches the saved sign-in by that frame's exact host. The values are typed into the
two fields through AppKit, so the page sees real input events; nothing is
submitted and nothing reaches MCP, logs or the agent.
SiliconPass credential release is deliberately stronger than ordinary browser
confirmation. After the exact native fill summary is approved, macOS evaluates
deviceOwnerAuthentication uses zero Touch ID reuse and delegates the
available authentication method to macOS. WebKitUI does not infer that Touch ID,
Apple Watch, password fallback, or closed-lid authentication will be available
on a particular Mac. If the Mac is locked or authentication UI cannot be
presented, WebKitUI receives only
user_presence_unavailable: no secret is released and no automatic retry is
performed.
The protected browser never connects to private address space. The one exception
is a service on the owner's Tailscale network: navigating to a name that resolves
only into 100.64.0.0/10 asks for a native Allow Tailscale Access confirmation
for that exact origin and port. Once allowed, the proxy connects to that host on that
port only, pinned against rebinding; every other private address, and the same name
on another port, stays refused. Grants last until the app quits. Any other private
destination returns privateNetworkDestination instead of an opaque WebKit error.
Restricted authentication origins such as idmsa.apple.com return only their
canonical origin and a local handoff requirement. Observe, text, capture,
scroll, credential fill, and actuation remain blocked until the human leaves
that origin. A cross-origin redirect is not reported as an ambiguous WebKit
failure: it returns redirect_requires_human_approval with source and target
origins only.
When App Store Connect embeds that restricted Apple Account origin, the sign-in
takes the native human handoff like any other restricted origin. It used to return
full_browser_required: the frame measured as stalled was a hidden-page defect of
the parked window (fixed 2026-09-23), not an engine limit.
Navigation blocks on an exact native macOS confirmation by default and returns
a normal terminal tool result. Human handoff is
two calls: the first transfers control to the visible window; after completing
the sensitive step, call browser_session { operation: "handoff", ... } again
and approve the native resume dialog. MCP 2026-07-28 clients continue to use
multi-round input_required results.
Use browser_session { operation: "handoff" } when a human must control the same local WebKit session. Declining resume leaves human control active.
If a previous handoff token survives while agent control is active, status and
handoff_start point to handoff for recovery. A local confirmation is required
before invalidating the old token and starting a new human handoff. A confirmed
tokenless resume also invalidates earlier tokens. Another client's handoff remains
excluded, and human work in progress is reported as wait-only.
When a click's cross-origin navigation is refused, the action result and status
report a navigation_blocker containing only the source and destination origins
and a human-handoff instruction. The click is not automatically replayed, and the
private authentication request is not exposed.
Semantic appearance and target absence postconditions require an unfiltered, untruncated baseline:
otherwise postcondition_baseline_incomplete refuses the action before dispatch.
Observe again with enough elements and field characters to establish absence.
Covered controls name the hit-tested covering element in coveredBy (compact:
covered_by). Name filters normalize common apostrophes; visible inline onclick
controls are included even without a pointer cursor. Identically sized link wrappers
without independent state or explicit handlers are omitted in favour of their link.
The handoff window becomes a regular foreground Mac app with a Dock icon and
uses the same rendered view as semantic observation and capture.
Linux headless lane
linux/ is a separate, ephemeral Playwright worker for disposable workloads on
a dedicated Linux VM. It does not inherit Mac cookies or passwords and it does
not replace native WebKit. Route authenticated sessions and human handoff to the
Mac; route public, unauthenticated headless work to Linux. See
linux/README.md and
docs/architecture/linux-headless-worker.md.
Evidence
Architecture:
docs/architecture/Private remote transport and deployment gates:
docs/architecture/private-remote-transport.mdDated research and NotebookLM audits:
docs/research/Same-Mac runtime benchmark:
Benchmarks/README.mdPublic/private publication boundary:
docs/architecture/public-private-boundary.mdVulnerability reporting and release invariants:
SECURITY.md
The dated adversarial corpus measurement records 53 deterministic tests across 57 concrete fixture executions for provenance, dialog truth, destinations, and export leakage. It measures those product boundaries, not human or model attack success.
The first measured local lane uses 30 runs of the same deterministic fixture at 2560×1600. It compares WKWebView with Playwright 1.61.1 driving installed Chrome 151. It does not yet measure full process-tree memory, visible-window behavior, authenticated task success, or Playwright's pinned Chromium binary; no broader superiority claim is made.
Licensing
WebKitUI MCP 0.6.22 Developer Preview is available under the
Business Source License 1.1. The source is readable, auditable and
modifiable; production use is granted for personal noncommercial, qualifying
noncommercial organization and evaluation use, and commercial production use
requires an agreement with the Licensor. This version converts to Apache 2.0 on
2030-08-28. See LICENSING.md for the exact scope, third-party
boundary and treatment of earlier revisions.
Safety
The model cannot mint capability handles. Page content never becomes trusted policy. Password values are omitted from observations. Unknown dispatch is indeterminate and is never automatically retried. No commit, push, deployment, or external account mutation is performed by the project itself.
Navigation actor attribution uses the first main-frame navigation within two seconds of an action. It is diagnostic evidence, not proof of causality or authorization: autonomous or more delayed navigation can be misattributed.
A disappearing or renamed Save/Done control cannot satisfy enabled_equals=false: that predicate requires the original semantic target to remain present and disabled. Use target_absent with value="true" for disappearance, or a heading/text predicate for the resulting page. Absence is proved only by a complete observation; it means the original semantic identity is no longer observed, and does not prove server-side persistence. An indeterminate result after dispatch requires inspection or receipt reconciliation, never automatic replay.
This server cannot be deployed
Maintenance
Related MCP Connectors
Browser MCP for logged-in tasks. Uses your Chrome — credentials stay local. Zero-token replay.
Stealth web automation for AI agents. Login, signup, navigate, screenshot.
Stealth web automation for AI agents. Login, signup, navigate, screenshot.
Browser agents and stealth cloud browsers for AI: run web tasks, fill forms, extract data.
Related MCP Servers
- AlicenseBqualityAmaintenanceNative Safari browser automation for AI agents. 80 tools via AppleScript — zero overhead, keeps logins, runs silently in background. Drop-in alternative to Chrome DevTools MCP with 40-60% less CPU/heat on Apple Silicon.98502 npm223MIT
- AlicenseNot gradedqualityCmaintenanceNative macOS browser (SwiftUI + WKWebView) that exposes an MCP server in-process so AI agents can drive a real local browser with the user's existing logged-in sessions. ~40 tools (navigate, click, fill, screenshot, eval_js, network log, accessibility tree). Local-only with bearer-token auth.2MIT
- AlicenseAqualityCmaintenanceSafari Web Extension + Node.js MCP bridge giving Claude Desktop full control over Safari — navigate, read pages, click elements, fill forms, and manage tabs. No Playwright or WebDriver dependency.131MIT
- AlicenseAqualityAmaintenanceMCP server that lets AI agents drive your real Chromium browser with your existing signed-in sessions, providing visible, local, and inspectable automation for tasks like navigation, clicking, typing, and form filling.251Apache 2.0