vm-relay
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@vm-relayUse a fresh VM to open our staging site and capture evidence of any interruptions during checkout."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
mcp-vm-relay
The Model Context Protocol front end of the VM relay, packaged as a Claude Code
plugin and as a pi package. pi-vm-relay,
which gave pi a native relay tool directly, is retired; mcp-vm-relay replaces
it for both Claude Code and pi, the latter loaded through pi-mcp-adapter. It
offers one relay tool: recorded, snapshot-evidenced interruptive
computer-use and browser-use in a fresh, dedicated VM. The agent judges
interruption; non-disruptive work stays with the agent's local tools. Nothing
here executes local computer-use, spawns subagents, targets physical machines,
records video, or attaches to existing browsers.
How it is built
The relay implementation lives in this repository: the manager
(src/manager.ts), the vm-service client, the registry with its OS-level lock,
the guest transfer and transport, the evidence package and its state merge, the
selected-environment profile, the console and saved-image contracts, the strict
tool contract (src/schema.ts), the action dispatch and bounded result
rendering (src/surface.ts), and the two guest programs
(src/guest/receiver.ts, src/guest/browser.ts). It was inherited from
pi-vm-relay at commit 8990123,
synchronized with its implementation through commit 0d69fc7 before that
project's retirement, and is maintained here as mcp-vm-relay's own
implementation from then on. src/server.ts binds the core to MCP over
standard input and output.
The committed dist/ holds server.mjs (the MCP server with the core bundled
in), the guest bundles the manager stages (receiver.mjs, browser.mjs) and
the doctor. Compiled relay-driver
code, the recorded-execution and evidence substrate, is bundled with hashes and
provenance in dist/build-info.json. Consumers load dist/; no build, SDK
checkout or network fetch happens at install time.
The Claude Code plugin provides what pi-vm-relay's native extension hooks used
to provide in pi. pi itself now reaches this same server as an MCP tool
through pi-mcp-adapter (see "Use with pi" below), so the relay tool's
identity and contract are shared; only the doctrine/skill/hook delivery
mechanism below is Claude-Code-specific.
In pi-vm-relay (retired, native pi extension) | Here (Claude Code plugin) |
a registered | MCP tool |
doctrine injected before each agent turn |
|
| skills |
prompt-composed enclosure | the |
typed image blocks in a run result, with pi's | MCP image content blocks in the tool result, with the MCP |
session shutdown pauses lease renewal | the same when the server's stdio closes or it is signalled: renewal pauses, the recording detaches, the VM is retained for an explicit |
the settled agent pauses renewal | none: MCP has no such hook, so the skill and agent say "finish or release before you return" |
Related MCP server: screenbox
Install
Use with Claude Code
Try it from a checkout:
claude --plugin-dir /path/to/mcp-vm-relayOr add this repository as a marketplace and install the plugin from it:
/plugin marketplace add WeZZard/mcp-vm-relay
/plugin install mcp-vm-relay@wezzardOnce loaded, the model sees the tools as
mcp__plugin_mcp-vm-relay_vm-relay__relay, …__relay_status and
…__relay_review. A subagent definition allows them by those names. The server
can also be configured directly in a project's .mcp.json with
node /path/to/mcp-vm-relay/dist/server.mjs, in which case the tools are
mcp__vm-relay__relay and so on.
Use with pi
pi install npm:@wezzard/mcp-vm-relayThis needs pi-mcp-adapter installed. The tool appears as relay, with the
two operator tools as relay_status and relay_review, with no host-specific
prefix.
Use with npx
npx -y @wezzard/mcp-vm-relayThis runs the MCP server directly on stdio, for a client that speaks MCP without a Claude Code plugin or pi package wrapper.
Prerequisites
Node 22+, Python 3 with fcntl for the registry lock, and for VM execution an
Apple-silicon Mac with Tart, a running
vm-service and prepared guest images.
Check readiness with node dist/doctor.mjs. It does not acquire a VM or
establish guest UI readiness. Guest execution needs Node and CuaDriver with
capture/input permissions; Linux requires native X11 and serve --no-overlay,
and browser actions additionally require guest Playwright and bundled
Chromium. Console viewing needs the vm-service guest-sharing backend and its
guest preparation; see docs/console.md here.
The tools
relay takes one required action. run and console-open accept and
require a reason; the other actions reject it and record structured lifecycle
facts. The contract, the evidence and the snapshot rules follow pi-vm-relay's
design. One difference in what the model is shown: the relay contract is a root
object with a root-level anyOf of strict per-action branches, and the
Anthropic API drops a root anyOf, so this server offers the projected object
and enforces the strict branches on every call before dispatch.
| Purpose |
| Find installed applications from image inventories by name and optional OS. |
| Default |
| Read versioned acquisition options (VNC backends) without allocation or ownership recovery. |
| Register the task, acquire a fresh VM and start its heartbeat; declare outputs before work. Optional |
| Resolve non-secret console status for the owned lease and environment. |
| Open explicitly user-requested viewing on the service host, with |
| Cancel the identified viewing attempt without releasing the VM. |
| Push and hash-check the runtime, support files, an opt-in workspace and the optional browser. Failed staging can be retried; a staged runtime accepts corrected executable paths; |
| One recorded exec, script, code, CUA or browser operation with optional |
| Retrieve one saved display image, declared application image or immutable image reference without input, capture, directory export or acquisition. |
| Pull only declared files or directories with source and host checksum verification. |
| Extract declared outputs, deliver and verify the snapshot package, destroy the VM and unregister. |
| Retain available evidence and abandon or destroy the VM. |
A run result carries the execution identity and outcome, the guest's bounded
standard output and error, for a browser event the parsed browser answer (the
settle facts, the landing or snapshot capture, or the text a read returned),
and, when the snapshot plan captured the after phase and delivery succeeded,
the saved after-image as an MCP image content block. The full receipt stays in
the evidence package.
relay_status returns this session's owned lease with its backend binding,
guest state, renewal state, console observation and last error, the staging
state and evidence path, plus the project directory, the VM service origin and
the selected environment; {"active": false} when nothing is owned.
relay_review verifies a delivered package and opens its viewer in the local
human-facing browser; human review remains pending.
Ownership, failure and recovery
One server session owns at most one VM. Another task needs a separate acquisition.
An operation failure retains the VM so the agent can inspect, repair and submit a new operation. Failed and uncertain operations are never automatically replayed.
Use
finishto deliver evidence and release, orreleaseto abandon explicitly. A failed delivery retains the VM; a release failure retains ownership until destruction is verified.When the session ends (the server's stdio closes or it is signalled), lease renewal pauses and the recording detaches; the VM is not destroyed. The backend TTL and grace period handle abandoned leases. Status reports the last confirmed expiration time.
A restarted server with the same
MCP_VM_RELAY_SESSIONreconciles its durable ownership and reattaches the recording session without replaying prior work. Context compaction does not reset VM state;probereports the owned state without relying on earlier messages.run.timeoutMsdefaults to 120,000 ms and accepts integers up to 3,600,000 ms. It bounds command execution, not the snapshot delay or the lease lifetime. A timeout reports confirmed termination or uncertainty and keeps the VM available.runwithkind: "exec"anddiagnostic: truerecords command diagnosis or repair without screenshots, for explicitly requested diagnosis when capture is unavailable. Before staging it runs through vm-service in the guest's default directory; after staging in the recording workspace. It cannot join a snapshot group and is not visual verification.After diagnosing damaged recording state,
stagewithresetRecording: truearchives the old recording and starts a new recording session in the same VM. An existing receiver lock refuses the reset until its operation is reconciled. Prior evidence paths remain in the owned status.
Browser events and page captures
Enable browser: {} in stage for a persistent fresh guest Playwright
page; the workspace must have Playwright available, or supply an absolute guest
browser.playwrightModule path. A run with kind: "browser" sends one event:
navigate, click, type, press, read, or snapshot. The guest-owned
server keeps the same page across calls, so the after-snapshot shows the live
result. It uses Playwright-managed bundled Chromium, never host Chrome or CDP.
Each event carries the run's timeoutMs as its own deadline; an event that
misses it, or whose caller disconnects, has its browser context closed so
pending input cannot land later, and the next event uses a fresh page. Nothing
is replayed.
The desktop snapshot pair is captured after a fixed, agent-declared interval. A web page is also captured from inside the browser, where the timing can be tied to the page's own state:
After every input event (
navigate,click,type,press) the guest server waits for the page to settle: the load event when the page navigated, then network idle, then loaded fonts, then two animation frames. The wait is bounded bybrowser.settleTimeoutMs(default 5000, at most 60000) and by what the event's deadline leaves for the capture, and the facts of the wait (loaded,networkIdle,fontsReady,timedOut,waitedMs) come back with the event assettled.An event that moved the page to a new address gets a landing capture of where it arrived. A
snapshotevent captures the settled page on demand, with an optional shortname.Each capture is a PNG of the viewport plus a JSON record beside it, named
c<seq>-<ISO-8601Z>-<landing|snapshot>-<name>. The record holds the settle facts, the operation, the file's SHA-256 and the console lines (including page errors) the page emitted since the previous capture.Captures land in
workspace/browser-captures. Staging the browser declares that directory as the extractionbrowser-captureswhen the agent did not, sofinishcarries the captures home underextractions/as byte-verified application attachments, andimagecan retrieve one of them by name and relative path. The dispatch-time snapshot pair contract is unchanged.A capture that fails after the input was dispatched is an error whose response says
dispatched: true; the run is then refused as any nonzero browser event is.
Saved images
A normal run returns its saved after-image as a typed image block whenever the
snapshot plan captures that phase: a standalone event or a text group's last
event. A first or intermediate group event and a diagnostic command do not
invent an image. Execution and image delivery are independent outcomes: a
completed command can have a failed delivery, and a delivered image does not
turn a failed command into a successful one. Either failure sets the MCP
isError flag while the content, image included, is kept. The delivery
identity (imageDelivery) leads the result text so it survives truncation.
If inline delivery fails, image retrieves the same saved image through one
closed selector; it never repeats input, creates a capture, exports the
consumer directory or acquires a VM:
{"action":"image","target":{"source":"display","sessionId":"<recording-session>","executionId":"<saved-execution>","phase":"after"}}
{"action":"image","target":{"source":"application","name":"browser-captures","path":"c000001-…-landing-navigate.png"}}
{"action":"image","target":{"source":"reference","imageId":"image-<64 lowercase hex digits>"}}Display selection needs
beforeorafter; a phase the plan did not request returnsnot-requested. Application selection needs an acquisition-time declaration: a directory declaration takes one relative file path, a file declaration omitspath. A reference resolves to the same original bytes or an explicit failure.Originals are limited to 64 MiB, 40,000,000 decoded pixels and 32,768 pixels per dimension; PNG, JPEG and WebP are accepted. The preview is at most 2,000 × 2,000 pixels and 4 MiB of base64. Presentation differs from pi here: pi resizes through its own image helper, while this core has no codec dependency. A PNG original is decoded and, when it exceeds the preview bounds, resampled in-process (area averaging,
node:zlib); a JPEG or WebP original has its container validated and passes through unchanged when within bounds, and is reportedpresentation-unavailableotherwise. No EXIF orientation is applied; dimensions are those stored. The presentation receipt records the policy, the original and preview dimensions, the MIME type, hash, size and whether bytes were transformed, beside the untouched original.Each delivery has a 90-second deadline and a shared budget of three byte-transfer attempts. Only transient transfer failures are retried; authorization, unsafe-path, capture, format and integrity failures are not. Recommend at most two explicit recovery calls for the same reference; if a required image still cannot be inspected, stop exploratory input and finish or release.
Immutable catalog entries bind each reference to the owner, enclosure, backend and original identity. Closed or sealed enclosures return
stale-reference; delivered originals remain readable with the host's file tools. Finalization materializes verified originals at canonical snapshot paths and preserves prior state when merging guest evidence.Attachment means the block was included in the result; it does not prove the model inspected it or that a human reviewed it.
Live console viewing
Acquisition never opens a viewer. acquisition-capabilities reads the
backend's VNC options; acquire with vnc: true checks OS availability and
requires a ready console and lease identity in the response. console-open is
permitted only following an explicit user request, requires userRequested: true, console_id, attempt_id, reason and expected, and opens on the
declared service host, not on a remote client. console-resolve refreshes the
non-secret observation; console-cancel closes managed viewing resources and
never releases the VM. Console status ready is guest preflight, not launch
success; transport connection, authentication, displayed pixels and human
confirmation are separate observations that console actions never establish.
On macOS the human must choose Standard sharing of the existing console, not a
new Log In session or a High Performance display; the relay never confirms
that selection, and server_enforced_view_only: false with session_binding: viewer-selection-unverified remain limitations after transport connects.
Failed or uncertain launches retain ownership; resolve or cancel the attempt
rather than replaying it. Console tests use mocked backends; no live viewer,
installation or platform acceptance is claimed here.
Selected environments
Set VM_ENVIRONMENT_FILE to a profile that binds a loopback vm-service
endpoint, an image repository, a Tart store and separate service, image and
relay state directories together. The profile is validated before use, is
authoritative over the individual MCP_VM_RELAY_* variables, and an invalid
selection fails rather than falling back. Leases are bound to their backend and
store: an owned lease restored under a different environment fails before any
backend operation, and destruction is verified with the selected Tart binary
and TART_HOME. docs/selected-environments.md documents the schema. The
bundle the profile exports to subprocesses is the canonical one vm-service
defines, so its relay entries keep the VM_RELAY_STATE_DIR and
VM_RELAY_URL names and the three runtimes agree; this server reads its own
settings from the profile.
Evidence and cleanup
Default output is relay-evidence/<unique-task>/ under the project, with
state/ (the guest journal, action records, receipts and snapshot PNGs),
host/ (reasons, submissions, transfer facts, receipts, diagnostics, image
deliveries and lifecycle events), extractions/ (declared files, including the
page captures), and manifest.json, summary.json, walkthrough.json,
index.html and OPENING.txt. Open index.html directly: no server, network,
VM or external assets are needed. Diagnostic commands appear in the walkthrough
as command-only steps without screenshots. finish verifies the package before
destroying the VM; a failed delivery removes only the derived files it created
and retains the VM for a corrected attempt. Cleanup checks the read-only host
Tart inventory (the selected one, when an environment is selected) before
claiming destruction. Leases default to 4 hours with a heartbeat; the
vm-service reaper is the final backstop for process death.
Configuration
MCP_VM_RELAY_PROJECT: the project directory (the plugin passes Claude Code's). Evidence lands underrelay-evidence/<task>/there.MCP_VM_RELAY_SESSION: an explicit session identity. By default each server process takes a fresh random one; a stable identity lets a restarted server reconcile and reattach the enclosure of the same identity.MCP_VM_RELAY_URL: the loopback vm-service origin, defaulthttp://localhost:6240. Non-loopback servers, redirects and physical targets are refused.MCP_VM_RELAY_STATE_DIR: host state, otherwise$XDG_STATE_HOME/mcp-vm-relayor~/.local/state/mcp-vm-relay, one subdirectory per session.MCP_VM_RELAY_REGISTRY: an explicit task registry file; otherwise an existing compatible~/AGENTS.mdVM table, or a private managedregistry.mdin the state directory.MCP_VM_RELAY_PYTHON: the Python 3 used for the registry lock; defaultpython3on PATH.VM_ENVIRONMENT_FILE: a selected environment profile; it overrides the URL, state directory and registry above and binds the Tart store.Guest files go to
/var/tmp/<UTC-timestamp>-mcp-vm-relay-<task>/, with the runtime inreceiver.mjs, support insupport/and work inworkspace/.
Development
Build relay-driver using its own instructions, then in this checkout:
npm ci
npm run setup:dev -- /absolute/path/to/built/relay-driver
npm run check # build, typecheck, testsThree tests need a sibling checkout beside this repository and skip with a
message when it is absent: the console fixture regeneration and the
environment parity test need ../vm-service, and the shared catalog text
corpus needs ../pilot-images. The JPEG and WebP presentation fixtures in
tests/fixtures/ were encoded once from the test's spatial PNG with a codec
outside this repository and are committed, because the core carries none.
End-to-end with headless Claude Code
npm run test:e2eThis runs claude --print with the plugin loaded from this checkout
(--plugin-dir), the model limited to the relay tools, and the server pointed
at a loopback stand-in for vm-service (tests/e2e/fixture-service.ts), which
keeps leases as records, runs the relay's own Node and transfer commands
locally, and fakes the desktop capture driver. Five cases run, each a separate
headless session: the status call (which also proves the server is pointed at
the stand-in before anything is acquired), an invalid call refused by the
contract, a full acquire, stage, exec, finish lifecycle with a verified package,
a browser lifecycle whose settle-waited page captures come home in the package,
and a lease abandoned when the session ends, which is retained with its renewal
paused rather than released. What is checked is what happened on disk and at
the service, not what the model said. The suite needs claude on PATH with an
account and spends a few model turns per case, so it is not part of npm test.
The relay-driver links are development-only. The tests run the manager, the
guest programs and the shipped server against fixture HTTP services, fake
Playwright pages and a real MCP client over stdio; no VM, desktop or user
registry is touched. Commit the regenerated dist/ with source changes.
Releasing
Cut a release with:
node scripts/bump.mjs X.Y.Z && git push --follow-tagsscripts/bump.mjs sets X.Y.Z as the version in package.json,
.claude-plugin/plugin.json and the pinned pi-mcp.json arg, refreshes
package-lock.json, rebuilds dist/, commits Release vX.Y.Z and creates the
annotated tag vX.Y.Z. It refuses to run against a dirty working tree or a
malformed version, and it never pushes — git push --follow-tags is a
separate, explicit step.
Pushing the tag triggers
.github/workflows/release.yml, which
rebuilds vmctl, checks the working build against a fresh one, and publishes
to npm using trusted publishing
(OIDC — no NPM_TOKEN secret involved), then creates the matching GitHub
release.
Trusted publishing has to be configured on npmjs.com, and npm requires the
package to already exist before you can do that. The first publish must
therefore be done by hand (npm publish --access public from a maintainer's
machine) before its trusted publisher can be configured for this workflow.
License
MIT — see LICENSE.
Available Tools
3 toolsrelayA
One VM enclosure interface. Required action; run and console-open require intent in reason. search: required application name, optional hard os linux/macos; exact, prefix, substring canonical-name/alias matching. Returns installed versions (possibly null), image keys, OS and architecture; truncated means whole installations were omitted. No allocation, boot, installation, capacity reservation or automatic image choice. Empty success is distinct from catalog errors. probe: default scope=host reports host permissions/activity, VM service availability and owned lifecycle state, not guest readiness. scope=guest checks executables on the owned guest before staging or after repair without installing software; capture/browser readiness remains unverified. Unknown is not idle. acquisition-capabilities: read-only versioned VNC options, no acquisition or ownership recovery. console-resolve: read-only status for the owned lease/environment. console-open: explicit user request only, require userRequested=true, console_id, attempt_id, reason and expected; opens on service-host only, never automatically at acquisition. console-cancel: require console_id and attempt_id; closes managed viewing resources, never releases the VM. Console actions are lifecycle operations without screenshots, not authentication/pixel/human evidence. Resolve uncertain attempts; never automatically replay open. Console status ready is guest preflight, not nested attempt success. macOS requires human Standard sharing of the existing console, not a new Log In session or High Performance display. Never auto-confirm selection; server_enforced_view_only=false and viewer-selection-unverified remain limitations even after transport connects. acquire: one fresh VM for this prompt-composed subagent, register ownership and heartbeat; require task, image and extractions (declare outputs up front, [] allowed); optional ttlHours/env/fullWorkspace/vnc (boolean, default false; prepares sharing without opening). stage: hash-check runtime and optional workspace/files/nodePath/cuaDriver/browser. Corrected setup can be retried after errors; a staged runtime accepts corrected executable paths. resetRecording=true explicitly archives existing recording evidence and starts a fresh recording on the same VM, refusing an existing receiver lock. Staging success does not prove capture readiness. Guest Node and driver must exist; support goes under support/. Linux needs native X11 and cua-driver serve --no-overlay. browser:{} enables fresh persistent guest Playwright; no download or CDP attachment. After every browser event the page is settle-waited (load, network idle, fonts, two frames; settleTimeoutMs, default 5000) and an event that changed the address gets a landing page capture; captures and their records land in workspace/browser-captures, declared as an extraction automatically. run: ONE admitted operation, require reason/kind/step/snapshots. exec needs argv; script needs localPath/language; code needs code/language; cua needs tool and optional args; browser needs one browser event: navigate, click, type, press, read, or snapshot (capture the settled page now, optional name). Do not hide multiple UI interactions in a script-level pair. Ordinary UI means real pointer/keyboard, not direct accessibility. Explicit afterIntervalMs required per event or on text group last, no defaults/stability detection. Choose semantics-appropriate waits, e.g. 100ms text, 500ms dialog, 16ms game, not prescribed values. Text groups are sender-declared consecutive first/member/last events. Failures retain the VM and allow agent-directed repair; never automatically replay uncertain input. timeoutMs defaults to 120000 and accepts integers 1..3600000 independently of snapshot delay. exec diagnostic=true explicitly records command diagnosis/repair without screenshot evidence, including before staging; do not claim visual verification. A run result carries the execution identity and outcome, the guest's bounded stdout/stderr, for a browser event the parsed browser answer (settled facts, landing or snapshot capture, read text), and the saved after-image as a typed image block when that phase was captured and delivered. image: retrieve one saved image without input, capture, directory export, or acquisition. target selects display (sessionId/executionId/phase), application (declared name and relative path for a directory), or reference (imageId). PNG/JPEG/WebP only; originals max64MiB, decoded max40M pixels; preview max2000x2000 and 4MiB base64 (PNG originals are resampled in-process; JPEG/WebP pass through only within bounds). Each image delivery has a 90s deadline and at most three eligible file-transfer attempts; recommend no more than two explicit reference recovery calls. Closed enclosures return stale-reference; delivered originals remain readable by host read. Attachment does not prove provider acceptance or inspection. extract: require names, pull only declared outputs, verify hashes and reject traversal/symlinks/changing sources. finish: extract declared outputs, deliver/verify a portable snapshot package then destroy/unregister; delivery, snapshots, execution and human review are separate. release: abandon, retain available evidence and destroy the owned VM without claiming success; safe to retry failed cleanup. Use finish or release explicitly when done. Session shutdown and agent completion pause renewal without destroying the VM; backend expiration handles abandoned leases. Inspect current owned state through probe after context compaction. Only selected-action fields are permitted; no default action. No physical/local UI targets, video API or spawn API. Text output is capped at 50 KiB / 2000 lines; larger responses are retained in a local file.
| Name | Required | Description | Default |
|---|---|---|---|
| os | No | ||
| env | No | Credential pack, default none; never baked into images. | |
| vnc | No | Prepare guest console sharing, default false. Never opens a viewer automatically. | |
| args | No | ||
| argv | No | ||
| code | No | ||
| kind | No | ||
| name | No | ||
| step | No | ||
| task | No | ||
| tool | No | ||
| files | No | ||
| image | No | Image key from relay action=probe, e.g. ubuntu2404 or macos26. | |
| names | No | ||
| scope | No | ||
| action | Yes | ||
| reason | No | Intent of this execution. Retained as evidence, never identity, authorization or a retry key. | |
| target | No | ||
| browser | No | ||
| expected | No | ||
| language | No | ||
| nodePath | No | Guest Node executable, default node; use image nvm path if needed. | |
| ttlHours | No | ||
| cuaDriver | No | Guest CUA executable; OS default when omitted. | |
| localPath | No | ||
| snapshots | No | Standalone event requires afterIntervalMs. Explicit consecutive text group uses first/member/last; last requires an interval. No inferred groups. | |
| timeoutMs | No | Execution timeout in milliseconds, default 120000, maximum 3600000. Independent of snapshot delay and lease TTL. | |
| workspace | No | Host directory copied to the guest workspace, opt-in. | |
| attempt_id | No | ||
| console_id | No | ||
| diagnostic | No | Explicit command diagnosis or repair without screenshot evidence, including before staging. Commands and outcomes remain recorded. Never claim visual verification. | |
| extractions | No | ||
| fullWorkspace | No | Explicit opt-in to deliver the entire workspace. | |
| userRequested | No | ||
| resetRecording | No | Explicitly archive the current recording and start a new session on the same VM. Retains prior evidence; refuses while the receiver lock exists. Use after diagnosing recording damage. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden, and it is exceptionally transparent: it discloses destruction (finish/release destroy or unregister the VM), permission/intent requirements (console-open requires userRequested=true and reason), failure semantics (safe to retry failed cleanup, never automatically replay uncertain input), and limits (staging success does not prove capture readiness, attachment does not prove provider acceptance).
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is very long, but nearly every sentence carries distinct, action-specific guidance and there is no filler. The action-name-led structure aids scanning, though a bulleted layout would improve readability and front-loading. Length is justified by the 13-action surface, no annotations, and no output schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with 35 parameters, no output schema, and no annotations, the description is remarkably complete: it covers the full lifecycle, prerequisites, side effects, timeout behavior, error distinctions (empty success vs catalog errors, stale-reference), output caps, and return semantics. No critical invocation detail appears missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is only 34%, so the description must compensate, and it does thoroughly. It maps the key parameters to their actions (task/image/extractions for acquire, argv/localPath/language/code/tool for run, target forms for image, snapshots group semantics, browser event fields) and adds defaults and constraints such as vnc false by default, timeoutMs 120000 default, and settleTimeoutMs 5000 default.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a concrete verb+resource: 'One VM enclosure interface' and then enumerates each action (search, probe, acquire, stage, run, image, extract, finish, release, console-*) with specific behavior for each. It sharply distinguishes internal actions and their scopes, even though it does not explicitly contrast relay_status/relay_review.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives rich action-level guidance: when to use probe ('Inspect current owned state through probe after context compaction'), when to choose finish vs release, when console-open is allowed, and many exclusions such as 'no default action' and 'never automatically replay open'. It does not explicitly route to its sibling tools relay_status and relay_review, so alternative-tool selection is implied rather than stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
relay_reviewB
Verify a delivered relay evidence package (all artifacts, hashes and references) and open its viewer in the local human-facing browser. Human review remains pending.
| Name | Required | Description | Default |
|---|---|---|---|
| directory | Yes | The package directory, absolute or relative to the project. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden. It mentions verifying and opening a viewer, but does not disclose that opening a browser is a side effect, nor does it state whether the operation is read-only or modifies state. The phrase 'Human review remains pending' hints at state but is insufficient. The lack of safety or side-effect disclosure is a notable gap for a tool that opens a local browser.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences with zero fluff. It front-loads the core action (verify) and immediately states the secondary action (open viewer) and a state note. Every word earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
While the tool is simple (1 param, no output schema), the description does not mention what the tool returns (e.g., success status, viewer URL) or any prerequisites (e.g., the package must already be delivered). It also omits any mention of side effects. For a tool with no output schema, the description should clarify the result, and it does not.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the schema description for 'directory' already explains it is the package directory. The tool description adds no extra meaning beyond that, so the baseline of 3 applies. No further parameter elaboration is needed.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the verb 'verify' and the resource 'delivered relay evidence package', and it also mentions opening the viewer. This distinguishes it from siblings relay and relay_status, which likely handle creation/status respectively, though it doesn't explicitly name them. The purpose is specific and unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies when to use it: to verify a delivered package and open the viewer. However, it does not explicitly state when not to use it or mention alternatives like relay_status for checking status. The usage context is clear but lacks explicit guidance on selecting this over siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
relay_statusA
Show this session's owned VM lease (backend binding, guest state, renewal, console observation, last error), staging state and evidence path, plus the project directory, the VM service origin and the selected environment in use; active:false when nothing is owned. Read-only; it does not touch the VM.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the burden of behavioral disclosure. It explicitly states the tool is read-only and does not touch the VM, and describes the active:false scenario. It also enumerates the visible fields, giving a solid picture of the tool's behavior, though it does not mention potential permission requirements or response format.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, information-dense sentence with no wasted words Tee, but it packs many items into a long run-on structure. While every detail earns its place, the content could be better organized (e.g., bullet-like formatting) for readability. Still, it is concise in the sense of having no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter read-only status tool, the description is remarkably complete. It lists every category of data shown (VM lease fields, staging state, evidence path, project directory, origin, environment), explains the active:false case, and declares read-only behavior. Nothing critical is missing for an agent to decide when and how to invoke it.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has zero parameters artist with 100% schema description coverage, so there is no parameter semantics burden on the description. Per the rubric, 0 parameters defaults to a baseline of 4 because the description need not compensate for undocumented parameters.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states a specific verb ('Show') and resource (this session's owned VM lease, staging state, project directory, etc.), giving a detailed list of what is displayed. It is definitely distinguishable from the relay tools by its read-only status-reporting nature, though it does not explicitly name a sibling for contrast.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides clear context: this is a status/read tool to inspect session-owned VM lease and related state, and explicitly notes 'Read-only; it does not touch the VM.' It also explains the active:false case when nothing is owned. However, it does not explicitly contrast usage with sibling tools relay or relay_review.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
3 tool updates
v0.3.1- First observed
relay - First observed
relay_review - First observed
relay_status
TDQS
Scored across 3 tools
The three top-level tools are clearly separated: relay performs actions, relay_status is a read-only status view, and relay_review verifies evidence packages. The main ambiguity is that relay's probe and console-resolve actions overlap somewhat with relay_status, but the descriptions make the distinction reasonably clear.
All tools share the 'relay' prefix and use underscore separation, so the naming is predictable. The main tool is simply 'relay' while the other two are 'relay_<noun>', which is a minor inconsistency but not confusing.
Three tools is a low but plausible top-level count. However, relay is overloaded with many sub-actions (acquire, stage, run, image, extract, finish, release, console operations), so the actual action surface is much larger than the count suggests and would benefit from more top-level decomposition.
The relay action surface covers the full VM lifecycle: acquire, stage, run, image retrieval, extraction, finish, release, and console operations. relay_status and relay_review fill the status and verification gaps, so there are no obvious dead ends for the stated VM evidence workflow.
Related MCP Connectors
- TabfleetOAuthcom.tabfleet
Launch, inspect, control, and share isolated cloud browsers for your agents.
Run in-product voice interviews with AI agents and analyze source-linked evidence.
Run multi-step tasks in a real Chrome browser: persistent environments, live view, human takeover.
Hosted MCP catalog with 30 tenant-isolated browser, RAG, AI, mail and media tools.
Related MCP Servers
- FlicenseNot gradedqualityCmaintenanceEnables autonomous desktop automation by delegating tasks to vision-based agents operating within cloud-based virtual machine sandboxes. It allows users to manage VMs, execute complex computer tasks, and receive text-based screen summaries across Linux, Windows, and macOS environments.2-
- AlicenseNot gradedqualityBmaintenanceProvides AI agents with isolated virtual desktops containing a real Chromium browser, enabling them to see, click, type, and navigate like a human, with features like snapshots and remote control.23AGPL 3.0
- AlicenseNot gradedqualityCmaintenanceEnables a Copilot Studio agent to operate a dedicated, disposable Windows VM by running commands, PowerShell scripts, file operations, and background jobs over authenticated HTTPS.MIT
- AlicenseNot gradedqualityBmaintenanceEnables an agent to drive a real browser while enforcing provenance-based gating so URLs and form values must trace to the user or an allowlist, never to untrusted page content.AGPL 3.0