Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.vertz.dev/llms.txt

Use this file to discover all available pages before exploring further.

The Vertz dev server exposes a built-in Model Context Protocol (MCP) server and an HTTP bridge that give AI coding agents real-time access to errors, rendered pages, API specs, audit logs, and more. Instead of guessing whether code works, agents can verify by inspecting the running app.

Quick setup

The MCP server is always available when the dev server is running — no extra flags needed:
vtz dev

Connect your AI tool

Add to your project’s .mcp.json:
{
  "mcpServers": {
    "vertz-dev": {
      "url": "http://localhost:3000/__vertz_mcp"
    }
  }
}
Claude Code auto-discovers the tools on connection.

Available tools

The dev server provides 21 MCP tools that agents can call — 9 observability tools and 12 browser interaction tools (11 connected-tab + 1 headless screenshot):

vertz_get_errors

Returns current compilation and runtime errors with file paths, line numbers, code snippets, and fix suggestions.
// No parameters needed
// Returns: { errors: [...], count: 2, category: "build" }
When to use: After every code change to verify nothing is broken. This is the single most important tool for agent workflows.

vertz_render_page

Server-side renders a URL and returns an HTML “text screenshot” with render timing and metadata.
{ "url": "/tasks" }
// Returns: rendered HTML + timing + SSR status
When to use: To verify what a page looks like after making UI changes, without needing a browser.

vertz_get_audit_log

Returns a unified timeline of all server events — API requests, SSR renders, compilations, file changes, and errors — with nanosecond-precision timestamps.
{ "last": 50, "type": "error,api_request", "since": "2026-04-05T14:30:00Z" }
All parameters are optional. type filters by event kind (comma-separated): api_request, ssr_render, compilation, file_change, error. since filters events after an ISO 8601 timestamp. When to use: To understand what happened in the server after a change — did the API return errors? Did SSR fail? Were there compilation issues?

vertz_get_diagnostics

Returns a health snapshot: uptime, compilation cache stats, module graph size, connected HMR clients, SSR pool metrics, and current errors.
// No parameters needed
When to use: To diagnose server health issues or understand the current state of the dev environment.

vertz_get_api_spec

Returns an OpenAPI 3.1 specification with all entity CRUD routes, service endpoints, request/response schemas, and access rules.
{ "filter": "tasks,users" }
filter is optional — comma-separated entity/service names to include. Without it, returns the full spec. When to use: To understand the API surface when writing frontend code or integration tests.

vertz_render_component

Renders a single component in isolation with optional props.
{ "file": "src/components/TaskCard.tsx", "props": { "title": "Buy milk" } }
When to use: To quickly check a component’s rendered output during iterative editing, without navigating to a page.

vertz_navigate

Triggers client-side navigation in the browser via the HMR WebSocket — no full page reload.
{ "to": "/tasks/123" }
When to use: To navigate the user’s browser to a specific page for visual verification.

vertz_get_events_url

Returns the WebSocket URL for real-time event push, so agents can subscribe to live updates instead of polling.
// No parameters needed
// Returns: { url: "ws://localhost:3000/__vertz_mcp/events" }

vertz_get_console (deprecated)

Use vertz_get_audit_log instead — it provides the same information in a more structured, filterable format.

Browser interaction tools

These tools let agents interact with the live browser page — clicking buttons, filling forms, reading page state — without needing a separate browser automation tool like Playwright.

vertz_browser_list_tabs

Lists all connected browser tabs with their current URL, title, and control status.
// No parameters needed
// Returns: { tabs: [{ id, url, title, controlled }] }

vertz_browser_connect

Connects to a browser tab for interactive control. Returns a session ID and an initial page snapshot showing all interactive elements.
{ "tabId": "tab-abc123" }
// tabId is optional — auto-connects if only one tab is open
// Returns: { sessionId, tab: { id, url, title }, snapshot: { ... } }

vertz_browser_disconnect

Releases a browser control session.
{ "sessionId": "sess-abc123" }

vertz_browser_snapshot

Returns a structured snapshot of the page: interactive elements with refs, form structure, focused element, and current values.
{ "sessionId": "sess-abc123", "maxElements": 50 }
// sessionId is optional if only one session is active
The snapshot includes:
  • Elements: inputs, buttons, selects, links, checkboxes — each with a stable ref for targeting
  • Forms: form elements with their field refs, action, and method
  • Focused element: which element currently has focus
  • URL and title: current page state

vertz_browser_click

Clicks an element. Target can be an element ref from a snapshot, a CSS selector, or a text/name/label matcher.
{ "target": "submit-btn" }
{ "target": "#my-button" }
{ "target": { "text": "Save" } }
// Returns updated snapshot after the page settles

vertz_browser_type

Types text into an input or textarea.
{ "target": "email", "text": "user@example.com" }

vertz_browser_select

Selects an option in a <select> element.
{ "target": "priority", "value": "high" }

vertz_browser_fill_form

Fills multiple form fields at once. Handles text inputs, textareas, selects, checkboxes, and radio buttons.
{
  "target": "f1",
  "data": {
    "title": "My Task",
    "priority": "high",
    "assignee": "alice"
  }
}

vertz_browser_submit

Submits a form. Waits for navigation if it occurs (up to 2s).
{ "target": "f1" }
// Returns: snapshot + navigation info if URL changed

vertz_browser_press_key

Presses a keyboard key on the currently focused element.
{ "key": "Enter" }
{ "key": "Escape" }
{ "key": "Tab" }

vertz_browser_wait

Waits for a condition to be met in the browser, polling every 100ms.
{ "condition": { "text": "Task created" }, "timeoutMs": 5000 }
{ "condition": { "selector": ".success-message" } }
{ "condition": { "url": "/tasks" } }
{ "condition": { "absent": ".loading-spinner" } }

vertz_browser_screenshot

Headless pixel-perfect PNG of any route served by the dev server. Returns the image inline (the agent sees it) plus a local file path and URL that a human can click to open the PNG.
{ "url": "/" }
{ "url": "/tasks", "viewport": { "width": 375, "height": 667 } }
{ "url": "/tasks", "fullPage": true }
{ "url": "/", "crop": ".hero" }
{ "url": "/", "crop": { "text": "Get started" } }
{ "url": "/", "waitFor": "networkidle" }
Parameters
ParamTypeDefaultDescription
urlstring (required)Path (/, /tasks) or a same-origin URL (http://localhost:PORT/...). External hosts are rejected.
viewport{ width: number, height: number }1280x720Viewport size. Max 4096x4096.
fullPagebooleanfalseCapture the full scrollable page (uses captureBeyondViewport).
cropstring | { text | name | label: string }nullClip to a single element. CSS string or a single-key object using the same locator dialect as the other browser tools.
waitFor"domcontentloaded" | "networkidle" | "load""networkidle"When to take the screenshot. networkidle catches query() resolution.
Response Two MCP content blocks: an image block with the base64-encoded PNG and a text block with stringified metadata:
{
  "path": "/absolute/path/.vertz/artifacts/screenshots/2026-04-21T12-00-00Z-tasks-1280x720.png",
  "url": "http://localhost:3000/__vertz_artifacts/screenshots/2026-04-21T12-00-00Z-tasks-1280x720.png",
  "dimensions": { "width": 1280, "height": 720 },
  "pageUrl": "http://localhost:3000/tasks",
  "capturedInMs": 142
}
The returned image renders inline in the agent’s UI. The url field is a local dev-server link — share it with humans in chat messages; they can click it to open the PNG directly. Error codes (MCP isError: true with stringified JSON in the text block):
CodeWhen it fires
URL_INVALIDExternal host, protocol-relative URL, or malformed input
CHROME_LAUNCH_FAILEDNo Chrome / Chromium on the machine (set VERTZ_CHROME_PATH or install one)
NAVIGATION_FAILEDBrowser failed to navigate to the route
SELECTOR_INVALIDcrop was provided but is malformed (e.g., bad CSS)
SELECTOR_NOT_FOUNDcrop matched no element
CAPTURE_FAILEDScreenshot request itself failed
AUTH_REQUIREDFinal URL looked like an auth page (/login, /signin, /sign_in, etc.) — the tool refuses to silently return a login screen. See finalUrl in the error body to confirm.
Scope limits (v1)
  • Same-origin only. Paths and localhost / 127.0.0.1 / ::1 URLs pass; everything else returns URL_INVALID.
  • Public routes only. If the route redirects to an auth gate, the tool returns AUTH_REQUIRED rather than screenshotting the login screen. Authenticated-route capture ships in a later phase.
  • No session sharing. Each call launches an isolated Chromium page — cookies and local storage don’t carry over from the vertz_browser_* connected-tab tools.
Artifacts Every successful call writes one PNG to .vertz/artifacts/screenshots/ (gitignored). Filenames are <UTC-iso>-<slug>-<viewport>.png, lexicographically sortable so the newest is last:
.vertz/artifacts/screenshots/
├── 2026-04-21T11-48-12Z-1280x720.png
├── 2026-04-21T11-49-03Z-tasks-375x667.png
└── 2026-04-21T11-50-44Z-tasks-full.png
Tips
  • Before reporting a UI change as done, call vertz_browser_screenshot({ url: '<the-affected-route>' }) and compare against what the task asked for.
  • Check layout at mobile AND desktop with two calls that differ only in viewport.
  • Narrow noisy full-page captures with crop — either a CSS selector or { text: "..." }.
  • waitFor: "networkidle" is the safest default; use "domcontentloaded" only when you explicitly want to see a loading state.

Element targeting

All interaction tools accept flexible targeting:
FormatExampleDescription
Ref string"submit-btn"Element ref from the last snapshot (most reliable)
CSS selector"#my-button"Standard CSS selector via querySelector
Text match{ "text": "Save" }Find element by visible text content
Name match{ "name": "email" }Find element by name attribute
Label match{ "label": "Email" }Find input by its associated <label> text

Browser interaction workflow

1. vertz_browser_connect      → get session + initial snapshot
2. vertz_browser_fill_form    → fill the form fields
3. vertz_browser_submit       → submit and check navigation
4. vertz_browser_wait         → wait for success message
5. vertz_browser_disconnect   → release the session
If only one browser tab is open (the common case), you can omit both tabId in connect and sessionId in all subsequent calls — the tools auto-resolve to the single tab/session.

Real-time events

Instead of polling, agents can subscribe to a WebSocket stream for live updates:
ws://localhost:3000/__vertz_mcp/events
Or via the HTTP bridge (SSE):
GET http://localhost:3001/events

Event types

EventDescription
error_updateError state changed (new errors, errors cleared)
file_changeSource file was modified
hmr_updateHMR sent update to browser
ssr_refreshSSR module re-imported after file change
typecheck_updateType checker diagnostics updated
server_statusServer status change (sent on connect as handshake)

Filtering

Subscribe to specific events via query parameter:
ws://localhost:3000/__vertz_mcp/events?subscribe=error_update,typecheck_update

HTTP bridge

The HTTP bridge (--bridge-port) exposes the same capabilities as plain REST endpoints for tools that don’t support MCP or WebSocket:
MethodEndpointDescription
GET/healthBridge health check, lists available event types
GET/toolsTool discovery (list all available tools with descriptions)
POST/commandExecute a tool: { "tool": "vertz_get_errors", "args": {} }
GET/eventsSSE event stream (same events as WebSocket)

Example: calling a tool via the bridge

curl -X POST http://localhost:3001/command \
  -H 'Content-Type: application/json' \
  -d '{"tool": "vertz_get_errors", "args": {}}'
Response:
{ "ok": true, "result": { "errors": [], "count": 0 } }
The dev server tools are most effective when agents follow this pattern:
  1. Make a code change (edit a file)
  2. Check for errors — call vertz_get_errors to catch compilation/type issues immediately
  3. Check the audit log — call vertz_get_audit_log with type: "error" to see if runtime errors occurred
  4. Verify the UI — call vertz_render_page to see the rendered output
  5. Interact with the page — call vertz_browser_connect, then use click/type/fill_form/submit to test interactive behavior
  6. Only then report success — don’t tell the user “it works” until you’ve verified via the tools
This prevents the common failure mode where an agent says “Done!” but the app has a build error or renders a blank page.
For long-running development sessions, subscribe to the real-time event stream via WebSocket or SSE. This way the agent is notified immediately when errors appear, instead of discovering them later.

Diagnostic endpoints

These HTTP endpoints are always available (no MCP or bridge needed):
EndpointDescription
GET /__vertz_diagnosticsJSON health snapshot (uptime, cache, module graph, errors, SSR pool)
GET /__vertz_ai/errorsCurrent errors formatted for LLM consumption
GET /__vertz_ai/render?url=/pathSSR render for LLM consumption
GET /__vertz_ai/console?last=NRecent console output
POST /__vertz_ai/navigateNavigate the browser
These are the same underlying handlers as the MCP tools, exposed as direct HTTP endpoints for simpler integrations.