Skip to main content

Relay HTTP Control API

The relay service exposes a small authenticated HTTP API for direct browser-tool control of a connected Vibe Browser extension. It also exposes a standards-based MCP Streamable HTTP endpoint at /mcp — see Remote MCP endpoint below.

This API is intended for server-side automations that already know the extension uuid and secret and want a simple request/response surface without speaking the raw WebSocket protocol.

Authentication

Pass the extension secret using either:

  • Authorization: Bearer <secret>
  • X-Vibe-Secret: <secret>

If the UUID is unknown, the relay returns 404. If the UUID is known but the extension is currently offline, tool endpoints return 409. If the secret is wrong, the relay returns 401.

Endpoints

Assume base URL https://relay.api.vibebrowser.app.

Get extension status

curl -H "Authorization: Bearer $VIBE_BROWSER_SECRET" \
"https://relay.api.vibebrowser.app/api/v1/extensions/$VIBE_BROWSER_UUID/status"

Returns connection state, tool cache status, pending request count, and extension version.

List tools

Return cached tools:

curl -H "Authorization: Bearer $VIBE_BROWSER_SECRET" \
"https://relay.api.vibebrowser.app/api/v1/extensions/$VIBE_BROWSER_UUID/tools"

Refresh tools from the live extension first:

curl -H "Authorization: Bearer $VIBE_BROWSER_SECRET" \
"https://relay.api.vibebrowser.app/api/v1/extensions/$VIBE_BROWSER_UUID/tools?refresh=1"

Call one browser tool

curl -X POST \
-H "Authorization: Bearer $VIBE_BROWSER_SECRET" \
-H "Content-Type: application/json" \
"https://relay.api.vibebrowser.app/api/v1/extensions/$VIBE_BROWSER_UUID/call-tool" \
-d '{
"name": "navigate_to_url",
"arguments": {"url": "https://example.com"}
}'

Snapshot tools

curl -X POST \
-H "Authorization: Bearer $VIBE_BROWSER_SECRET" \
-H "Content-Type: application/json" \
"https://relay.api.vibebrowser.app/api/v1/extensions/$VIBE_BROWSER_UUID/call-tool" \
-d '{
"name": "take_snapshot",
"arguments": {"format": "accessibility_tree"}
}'

Notes

  • This API exposes browser tools, not the internal copilot chat/task loop.
  • Tool names and argument schemas come from the connected extension.
  • Call tools?refresh=1 before the first tool call in a new session when the tool surface may have changed.

CDP Compatibility Facade

The relay also exposes a small CDP-shaped compatibility facade for remote clients that prefer Chrome DevTools style verbs.

This is not a raw CDP tunnel. It is a narrow allowlisted mapping onto Vibe browser tools.

Version

curl -H "Authorization: Bearer $VIBE_BROWSER_SECRET" \
"https://relay.api.vibebrowser.app/api/v1/extensions/$VIBE_BROWSER_UUID/cdp/json/version"

List targets

curl -H "Authorization: Bearer $VIBE_BROWSER_SECRET" \
"https://relay.api.vibebrowser.app/api/v1/extensions/$VIBE_BROWSER_UUID/cdp/json/list"

Execute a CDP-compatible command

curl -X POST \
-H "Authorization: Bearer $VIBE_BROWSER_SECRET" \
-H "Content-Type: application/json" \
"https://relay.api.vibebrowser.app/api/v1/extensions/$VIBE_BROWSER_UUID/cdp/execute" \
-d '{
"id": 1,
"method": "Page.navigate",
"params": {
"pageId": 123,
"url": "https://example.com"
}
}'

Supported methods

  • Browser.getVersion
  • Target.getTargets
  • Target.createTarget
  • Target.closeTarget
  • Page.navigate
  • Page.reload
  • Page.captureScreenshot
  • Runtime.evaluate

Notes

  • Use Authorization: Bearer <secret> or X-Vibe-Secret for auth; query-string tokens are intentionally not supported.
  • Target.getTargets and cdp/json/list are backed by list_pages.
  • Page.captureScreenshot is backed by take_screenshot.
  • Runtime.evaluate is backed by evaluate_script and returns JSON-RPC style results.

Remote MCP endpoint (/mcp)

POST https://relay.api.vibebrowser.app/mcp is a standards-based MCP Streamable HTTP endpoint. It is stateless JSON mode: one JSON-RPC message in, one JSON-RPC response out. There is no SSE stream (GET /mcp returns 405) and no server-side session (Mcp-Session-Id is not issued; DELETE /mcp is a no-op 200).

This is the surface documented for AI clients in MCP Integration → Remote MCP. This page documents it at the protocol level for anyone integrating directly.

Authentication

Auth is a different credential from the /api/v1 API above — /mcp uses the extension's uuid only, the same identifier already used for WS agent connections (wss://relay.../<uuid>). The extension secret is not accepted here.

Precedence:

  1. X-Remote-Session: <uuid>
  2. Authorization: Bearer <uuid> (alias)

Both accept either the bare UUID or a full relay URL containing it (e.g. wss://relay.api.vibebrowser.app/<uuid>) — the trailing UUID is extracted.

Second-factor attach token (#1534)

The session UUID alone is not sufficient for a session that opted in to a per-session attach token (a second factor that closes the original IDOR). If the extension registered an attach token (a 64-lowercase-hex string, protocol v2), every agent — WebSocket and /mcp — must present the matching token:

  • Authorization: Bearer <token> (preferred), or
  • X-Vibe-Attach-Token: <token> (compatibility).

On /mcp, because Authorization: Bearer may already carry the session UUID, send the UUID via X-Remote-Session and the token via Authorization: Bearer (or just use X-Vibe-Attach-Token). Query-string tokens are never accepted.

Enforcement:

  • Per-session opt-in: if a session registered a token, a missing/invalid token is rejected regardless of the global switch — WebSocket agents are closed with code 4010 (generic reason), /mcp returns HTTP 401.
  • Global switch RELAY_REQUIRE_ATTACH_TOKEN (default false): when true, even token-less legacy sessions fail closed for token-less agents.
  • Revocation supersedes token auth: a revoked identifier is denied first (WS 4009, /mcp 403) even if a correct token is presented.
  • Token rotation evicts existing agents: when the extension rotates its attach token (explicitly, or detected on ordinary re-auth presenting a different token), every WebSocket agent still attached under the OLD token is closed with the distinct code 4011 "Attach token rotated" — not the generic 4010 used for auth failures, so a well-behaved agent can tell "you need a fresh token" apart from "you were never authorized" and reconnect with the new one. Any in-flight request for that agent is failed first with a generic error (never echoing token material). Rotating to the SAME token is a no-op — idempotent, no eviction.

Tokens are compared in constant time and are never logged or echoed in error bodies/close reasons. Structured, PII-free counters (ok/token, ok/legacy, denied/missing, denied/invalid) are exposed on GET /health under attachToken.counters, and rotation counters (detected, agentsClosed, pendingCleared) under attachToken.rotation.

Error codes

ConditionResponse
No X-Remote-Session / Authorization headerHTTP 401, { "error": "..." }
Revoked session identifierHTTP 403, { "error": "Session revoked" }
UUID not a known registered extensionHTTP 404, { "error": "..." }
Missing/invalid attach token for a token-enabled session (or token-less session while RELAY_REQUIRE_ATTACH_TOKEN=true)HTTP 401, { "error": "Unauthorized: attach token required" }
Malformed JSON bodyJSON-RPC -32700 (HTTP 200 — parse errors are still transport-successful)
Request body is a JSON array (batching)JSON-RPC -32600
Unknown methodJSON-RPC -32601
tools/list / tools/call while extension is offline or heartbeat-staleJSON-RPC -32002, message tells the user to open Chrome and check Settings → AI Agent Control → Remote
tools/call extension-side tool errorJSON-RPC -32000 with the extension's error text
tools/call while MAX_PENDING_PER_SESSION in-flight requests are already queuedJSON-RPC -32000 "Relay busy"

initialize always succeeds once the UUID is known/registered, even if the extension (Chrome) is currently offline, so client setup doesn't require Chrome to be open.

curl example

# initialize
curl -X POST https://relay.api.vibebrowser.app/mcp \
-H "Content-Type: application/json" \
-H "X-Remote-Session: $VIBE_BROWSER_UUID" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26"}}'

# tools/list
curl -X POST https://relay.api.vibebrowser.app/mcp \
-H "Content-Type: application/json" \
-H "X-Remote-Session: $VIBE_BROWSER_UUID" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}'

# tools/call
curl -X POST https://relay.api.vibebrowser.app/mcp \
-H "Content-Type: application/json" \
-H "X-Remote-Session: $VIBE_BROWSER_UUID" \
-d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"list_pages","arguments":{}}}'