Protocol

SDK, then remote MCP.

Unbrowse is an authenticated action surface. The SDK is the product. MCP is a thin remote harness over it. Agent Skills are the YAML those harnesses already are.

Canonical REST

All agent traffic goes through /api/v1. The authenticated principal determines the workspace — a caller-supplied workspace id is never authority.

POST /api/v1/runs
GET  /api/v1/runs/:id
POST /api/v1/runs/:id/responses
POST /api/v1/runs/:id/cancel
GET  /api/v1/runs/:id/events
POST /api/v1/capabilities/search
POST /api/v1/accounts/connections   { origin, username, password } → vault:// ref
POST /api/v1/accounts/register      { origin, username } → generated, vaulted
GET  /api/v1/vault                  refs + audit, never secrets
POST /api/v1/learn                  { har | traces, goal?, title? } → learned.* capability
GET  /api/v1/learned
GET  /api/v1/learned/:id/harness.yaml
GET  /api/v1/learned/:id/skill.md
GET  /api/v1/usage                  verified calls this month, rendered, passthrough, quota
GET  /api/v1/sites?q=                compiled sites (public registry) with tool counts
GET  /api/v1/sites/:host             that site's tools
GET  /api/v1/sites/:host/openapi.json  OpenAPI 3.1: one operation per tool, typed input and output
POST /api/v1/sites/:host/call/:tool  run a tool (same metered, verified run)
     /api/v1/sites/:host/mcp         the site as its own MCP server

Authorization: Bearer ub_live_…

TypeScript SDK

import { Unbrowse } from "@unbrowse/sdk";

const ub = new Unbrowse({
  apiKey: process.env.UNBROWSE_API_KEY!,
  baseUrl: "https://v3.unbrowse.ai/api/v1",
});

const run = await ub.run({
  task: "top stories on Hacker News",
  interactionMode: "unattended",
  idempotencyKey: "hn-1",
});

if (run.status === "input_required") {
  await ub.resume(run.runId, run.stateRevision, [{
    requirementId: run.requirements[0].id,
    expectedRevision: run.requirements[0].revision,
    action: "accept",
    values: { export_format: "csv" },
  }]);
}

MCP tools

Remote MCP at /mcp is Streamable HTTP (Grok, Claude, Cursor). /api/mcp is the same adapter over JSON-RPC. authorization and run actor. When three or fewer skills match, dedicated unbrowse.skill.* tools are listed with slot schemas from the harness YAML.

Sites as tools

Unbrowse is a browser engine and a compiler: it compiles a website's own requests into an API, and the API into tools. Every compiled site is an MCP server at /api/v1/sites/<host>/mcp and an OpenAPI 3.1 document at /api/v1/sites/<host>/openapi.json; each tool carries its input schema and an output schema learned from verified responses. The public registry holds pre-indexed sites (search and page reads, re-verified on a schedule); your own learned capabilities appear as my__… tools in the main server, and public ones you use stay in your tool list.

Statuses

succeeded
Declared business outcome independently verified. HTTP 200 is not enough.
input_required
Waiting on a versioned requirement. Not a capability failure. Resume the same run.
outcome_unknown
A mutation may have landed. Automatic mutating retries stay suspended until reconciliation.
failed / cancelled
Known effects are retained. Cancellation cannot unsend a delivered request.

Harness YAML

unbrowse/v1alpha1 packages declare slots, operations, bindings, guards and independent outcome checks. YAML is authoring; the runtime executes a typed IR. No eval, no shell, no website-provided expressions.