Skip to main content
Glama
SankofaForge

site-motion-capture

by SankofaForge

site-motion-capture

This MCP server captures live website motion on the rented Vast.ai GPU VM. It uses the existing Playwright recorder on that VM and copies the WebM video and jank report to the local machine. Each capture also leaves a persistent <name>.capture-cell.v2.json contract record beside those two artifacts.

Use design-inspiration to find candidate sites. Use this server after a site has been selected and its live behavior needs inspection.

In Antigravity, pass the returned local .webm path directly to native video understanding for the motion analysis step. Do not start the standalone gemini-vision MCP or upload the recording through the Gemini API for this workflow. Ask the native analyzer for a concise description and at most eight timestamped moments using the shape { description, moments: [{ timestamp_s, why }] }, then use those timestamps for frame extraction and implementation planning.

Tools

  • capture_site_motion records page load, scroll, and optional hover or click behavior. Desktop captures default to 1920×1080. It returns local and remote artifact paths in both content and MCP structuredContent. The contract includes URL/final URL, viewport and modes, worker and recorder metadata, consent, artifact sizes and SHA-256 hashes, media/jank validation, cleanup, and a complete, partial, or blocked status. The MCP keeps Playwright's WebM encoder at an 8 Mbps target so text and fine UI details remain readable. It rejects non-essential cookie consent by default and records the action in the jank report.

  • check_capture_gpu checks both nvidia-smi and the Chromium WebGL renderer.

Related MCP server: EasyPlaywrightMCP

Captures use consent_mode: "reject" by default. The public options are:

  • reject rejects non-essential cookies and records the action.

  • accept accepts all cookies only when consent_accept_approved: true is supplied explicitly. It fails closed otherwise.

  • none inspects consent state without waiting for or interacting with controls.

  • granular applies the settings, optional-cookie, and save selectors in order.

The recorder uses an unrecorded preflight context, then carries its storage state into the recorded context. It checks both contexts, including child frames. For reject, accept, and granular, a result is verified only when the consent surface is gone after the required action. dismissed is then true. If no safe control was found, the outcome is no-safe-action. If a surface remains or a blind spot prevents verification, the result is not verified. In none mode, no dialog means verified: true, dismissed: false, and outcome no-consent-surface. A present dialog means verified: false, dismissed: false, and outcome consent-surface-present. If a page blocks consent or scroll inspection, the recorder bounds that check and reports consent-check-timeout with a blind-spot entry; the video can still be published, but it must not be treated as consent-verified. The report keeps the mode, action, selector, phase, frame, reason, attempts, budget, and click count.

For an unusual control, pass consent_selector. It must be an explicit, stable CSS selector for the intended control. The same rule applies to hover_selector and click_selector. Selectors do not cross iframe boundaries. Automatic detection can miss shadow-DOM controls and controls hidden behind closed shadow roots.

consent_wait_ms sets how long the recorder waits for the dialog. Set consent_preflight: false to skip the unrecorded pass. Localization guidance must be written in English and include an explicit selector for each localized control. Do not depend on translated visible text alone.

Keep each capture within the 8-second interaction budget. The default discovery pass uses at most six clicks. Add explicit selectors for required interactions outside that pass. Automatic discovery is best-effort and does not prove that every interaction was captured.

The local name is a stable file stem for the copied .webm and .jank.json files. The matching <name>.capture-cell.v2.json is retained after staging cleanup. It is not the remote run ID. Keep the local name stable when comparing runs. Use the remote run ID for remote logs and cleanup. Unless output_dir or SITE_MOTION_OUTPUT_DIR is supplied, local artifacts are saved under artifacts/design-inspiration/site-motion-capture/ in the MCP client's current workspace. Use overwrite: false when available so an existing local capture is preserved. Cleanup reports one status per artifact: removed, missing, skipped, or failed. A cleanup failure does not erase the staged artifacts or the manifest. Set reduced_motion: true to propagate Playwright's prefers-reduced-motion: reduce emulation to the recorded context. Set mobile: true to use a 390×844 viewport with Playwright mobile and touch emulation. Captures without scrolling are marked partial because the visual workflow requires completed scroll evidence.

Transfer integrity requires non-zero files and matching size/SHA-256 values. The jank report must match the requested viewport and contain the complete jank-report.v1 fields. Media validation requires ffprobe to identify WebM, report a positive duration, and find at least one video stream. Missing or invalid media, jank, consent, scroll, GPU, or cleanup evidence cannot produce a complete capture.

The capture worker accepts HTTP(S) targets, including local and private addresses. It no longer requires a proxy, network namespace, or egress attestation. Browser service requests use the runner's ordinary network path.

The worker preserves its remote run directory when process exit or evidence validation is uncertain. It removes that directory only after the capture process exits and artifact validation finishes. A pending remote cleanup makes the capture partial while preserving local artifacts.

Performance acceptance

The comparison helper is offline. It never starts a capture. First collect a rollback baseline by manually selecting the rollback server, then collect the Browser Use candidate on the same runner and frozen fixture set. Record three cold and five warm four-cell runs for each route. Use the same documented cold and warm procedure for both routes. Each run must contain exactly one complete capture for desktop-full, desktop-reduced, mobile-full, and mobile-reduced.

For every cell, record elapsed milliseconds for the full capture stage, including capture, conversion, transfer, and local evidence validation. Set timeoutMs to that cell's existing workflow timeout and record whether it timed out. Record peak memory in bytes from the same runner-side process or cgroup measurement boundary for both routes. A cell that is incomplete, timed out, or exceeds its timeout invalidates the dataset.

Save the measurements as JSON using capture-performance.v1. The top-level runner contains non-empty id, machineFingerprint, and fixtureSetId; the same values must appear in each route's runner. Declare the absolute workspaceRoot containing the capture-cell manifests and their video/jank artifacts. machineFingerprint must identify the same OS image, CPU/GPU and driver, browser, Node, and FFmpeg. fixtureSetId identifies the frozen animation and consent fixtures. Record the exact cold and warm procedures in measurementProtocol.cold and measurementProtocol.warm. Each route has a runtime object with its own captureRuntime, captureRuntimeVersion, browserExecutable, browserVersion, browserUseVersion, and mediaToolVersion. A run has a unique id, temperature (cold or warm), and four captures, each containing cellId, status, timedOut, durationMs, timeoutMs, peakMemoryBytes, runId, workspace-relative manifestPath, and manifestSha256.

The comparator verifies each manifest hash and matching run/cell/complete status. It also checks that the referenced WebM and jank files remain inside the workspace and match their recorded sizes and hashes. The report retains the two route-specific runtime objects. It does not run ffprobe or independently revalidate WebM content; media validity comes from the already validated capture-cell manifest. The Node tests use synthetic manifest and artifact bytes to exercise the comparator only, not to claim live capture acceptance.

Run the comparison after collecting both datasets:

node scripts/compare-performance.mjs /path/to/capture-performance.v1.json

The helper rejects runner or fixture mismatches, missing or duplicate cells, wrong cold/warm sample counts, incomplete captures, altered or escaping artifacts, and timeout violations. It compares cold, warm, and combined samples against the rollback baseline: each cell's p95 duration and the p95 of the sum of four recorded durations per matrix. It also compares peak memory for every cell and matrix group. A pass requires every value to be at most 20% above baseline. With three cold and five warm runs, nearest-rank p95 is the slowest observation in each group. Keep the measurement file and report with the acceptance evidence; do not add them to source control.

Runtime

The server has no npm dependencies. The launcher sources ~/.zsh_secrets for the Vast API key and the Vast CLI environment. The API key does not appear in the MCP configuration.

The launcher requires an explicit worker configuration. Set VAST_INSTANCE_ID for Vast CLI resolution, or set SITE_MOTION_SSH_URL to an explicit ssh://user@host:port endpoint. There is no default instance. If neither is configured, tools return an isError: true blocked result with reason code capture-worker-unconfigured. Stale or unavailable workers return capture-worker-unavailable, and bounded preflight diagnostics never include API keys, tokens, passwords, or SSH URL passwords.

Before capture, the launcher verifies SSH reachability, the remote recorder at /workspace/site-motion-capture, capture.mjs, check-gpu-renderer.mjs, Node/Playwright, and ffprobe. GPU capture also requires a fresh check_capture_gpu result. Missing files, dependencies, GPU, WebGL, or a bounded SSH/preflight timeout return structured blocked errors and do not create local evidence artifacts.

The worker checks each HTTP or HTTPS request, including redirects and subresources. It blocks requests whose DNS answers include private or reserved addresses. For the starting host, the worker also requires a match with the bridge's DNS answers when the bridge returns IP addresses. Chromium resolves the host again when it connects, so a DNS change after the check can still affect the connection.

Related MCP Connectors

Related MCP Servers