unbrowse 12.2.0 → 12.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/SKILL.md +54 -50
- package/dist/cli.js +16 -3
- package/package.json +1 -1
- package/references/tools.json +120 -367
package/README.md
CHANGED
|
@@ -22,12 +22,12 @@ unbrowse resume <runId> origin=SIN # answer on the same run
|
|
|
22
22
|
| `registry [query]`, `site <host>`, `openapi <host>` | Public compiled sites, a site's tools, its OpenAPI 3.1 document — no account |
|
|
23
23
|
| `call <host> <tool> [JSON]` | Run one site tool (`--set k=v`, `--deadline MS`, `--select a,b`, `--idempotency-key K`, `--end-user ID`) |
|
|
24
24
|
|
|
25
|
-
The CLI is the REST client. The remote MCP is a separate client; see the [install guide](https://github.com/unbrowse-ai/unbrowse
|
|
25
|
+
The CLI is the REST client. The remote MCP is a separate client; see the [install guide](https://github.com/unbrowse-ai/unbrowse/blob/main/docs/install.md).
|
|
26
26
|
|
|
27
27
|
Exit codes: 0 accepted/ok (check status and verified), 1 error, 2 input required, 3 sign-in or saved login needed, 4 not verified.
|
|
28
28
|
Env: `UNBROWSE_API_KEY`, `UNBROWSE_BASE_URL`. Node 18.17+, no dependencies.
|
|
29
29
|
|
|
30
|
-
Install
|
|
30
|
+
Install: `npx unbrowse login` (OAuth in your browser), then any command. Guide: [installation guide](https://github.com/unbrowse-ai/unbrowse/blob/main/docs/install.md).
|
|
31
31
|
|
|
32
32
|
The agent contract ships as `SKILL.md` with `references/` in this package. Full reference, docs and the whitepaper:
|
|
33
|
-
https://github.com/unbrowse-ai/unbrowse
|
|
33
|
+
https://github.com/unbrowse-ai/unbrowse
|
package/SKILL.md
CHANGED
|
@@ -1,37 +1,50 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: unbrowse
|
|
3
|
-
description: Search and call websites through Unbrowse's hosted API or remote MCP, reuse indexed site tools, read pages, and learn missing routes in its cloud browser. Use for structured website tasks, authenticated site access
|
|
3
|
+
description: Search and call websites through Unbrowse's hosted API or remote MCP, reuse indexed site tools, read pages, and learn missing routes in its cloud browser. Use for structured website tasks, and authenticated site access with Unbrowse.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Unbrowse
|
|
7
7
|
|
|
8
|
-
Use the hosted service at `https://unbrowse.ai`. Execution, indexed routes and website sessions stay server-side. This skill supplies operating guidance;
|
|
8
|
+
Use the hosted service at `https://unbrowse.ai`. Execution, indexed routes and website sessions stay server-side. This skill supplies operating guidance; signing in is OAuth, below.
|
|
9
9
|
|
|
10
|
-
##
|
|
10
|
+
## Onboarding: sign in with OAuth
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
Sign-in is OAuth in the person's browser: an emailed sign-in link, then **Allow**. No password, and nothing to paste. Never ask the person for a token or key in chat.
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
Check first, then sign in only what is missing:
|
|
15
|
+
|
|
16
|
+
1. MCP: if `unbrowse_discover` is in this session's tool list, the MCP is signed in.
|
|
17
|
+
2. CLI: `npx unbrowse whoami`. Exit 0 means signed in. Exit 3 means not signed in.
|
|
18
|
+
|
|
19
|
+
Sign in the MCP (agent hosts):
|
|
16
20
|
|
|
17
21
|
```sh
|
|
18
22
|
claude mcp add --transport http unbrowse https://unbrowse.ai/mcp
|
|
19
23
|
```
|
|
20
24
|
|
|
21
25
|
```json
|
|
22
|
-
{"mcpServers":{"unbrowse":{"url":"https://
|
|
26
|
+
{"mcpServers":{"unbrowse":{"url":"https://unbrowse.ai/mcp"}}}
|
|
23
27
|
```
|
|
24
28
|
|
|
25
|
-
|
|
29
|
+
The host runs the OAuth sign-in itself (in Claude Code: `/mcp`, pick `unbrowse`, Authenticate). Do not put a bearer header in the config; with one set, hosts skip OAuth. A URL in a config is not a signed-in session: until the host finishes OAuth, the Unbrowse tools are not listed.
|
|
30
|
+
|
|
31
|
+
Sign in the CLI:
|
|
26
32
|
|
|
27
33
|
```sh
|
|
28
34
|
npx skills add unbrowse-ai/unbrowse && npx unbrowse login
|
|
29
35
|
```
|
|
30
36
|
|
|
31
|
-
|
|
37
|
+
`unbrowse login` opens the sign-in page in the browser on this machine. The person enters their email, opens the link, presses **Allow**; the CLI prints `Signed in to https://unbrowse.ai (workspace ws_…)` and stores the token at `~/.config/unbrowse/cli.json` (mode 0600, refreshed automatically).
|
|
38
|
+
|
|
39
|
+
From an agent's shell (no terminal for the person): run `npx unbrowse login --no-open` in the background, give the person the `https://unbrowse.ai/authorize?…` link it prints, and wait for the `Signed in` line. The link returns to `127.0.0.1` on this machine, so the person must open it in a browser on the same machine. On a remote or headless box, use an API key instead (below). Any other command run with no sign-in starts the same browser sign-in when it has a terminal; without one it exits 3 and asks for `unbrowse login`.
|
|
40
|
+
|
|
41
|
+
Then the first call: `npx unbrowse run 'top stories on hacker news'`. The site requests go from the person's own IP by default; `--from-unbrowse` sends them from Unbrowse instead.
|
|
42
|
+
|
|
43
|
+
`npx unbrowse mcp` (a stdio MCP for hosts that need one) uses the CLI sign-in. A remote MCP in a host config uses only that host's own OAuth: one sign-in does not cover the other, and the CLI token does not go into an MCP config.
|
|
44
|
+
|
|
45
|
+
For automation and CI without a browser, set `UNBROWSE_API_KEY` from the caller's secret manager (create a key in the signed-in console at https://unbrowse.ai/app). Never put keys into committed config, prompts, command arguments or logs.
|
|
32
46
|
|
|
33
47
|
CLI and SDK: https://github.com/unbrowse-ai/unbrowse
|
|
34
|
-
For automation, supply an API key via `UNBROWSE_API_KEY` using the caller's secret manager. Do not put keys into committed config, prompts, command arguments or logs. Create a key in the signed-in console at https://unbrowse.ai/app.
|
|
35
48
|
|
|
36
49
|
## Host plugins
|
|
37
50
|
|
|
@@ -46,20 +59,20 @@ Hosts that need a stdio server or reject dotted tool names can run `npx unbrowse
|
|
|
46
59
|
|
|
47
60
|
## Choose the interface
|
|
48
61
|
|
|
49
|
-
- MCP: discovery, runs, page reading, cloud browsing, indexing
|
|
50
|
-
- CLI: `unbrowse discover`, `run`, `inspect`, `resume`, `registry`, `site`, `whoami`. `unbrowse run` never drives a website in a browser (the only browser it opens is the first-use sign-in). There is no `unbrowse browse` and no `unbrowse install`. `unbrowse help` describes the installed version.
|
|
62
|
+
- MCP: discovery, runs, page reading, cloud browsing, indexing and saved-login requests. These names are MCP tools. They are not CLI commands.
|
|
63
|
+
- CLI: `unbrowse discover`, `run`, `inspect`, `resume`, `scrape <url>` (one page as markdown), `index <url>` (teach a site; `index status`), `registry`, `site`, `whoami`. `scrape` and `index` need CLI 12.2.0 or later. `unbrowse run` never drives a website in a browser (the only browser it opens is the first-use sign-in). There is no `unbrowse browse` and no `unbrowse install`. `unbrowse help` describes the installed version.
|
|
51
64
|
- SDK: REST integration and scripting. Consult the public SDK docs for its supported methods; MCP tools and REST methods are not interchangeable names.
|
|
52
65
|
|
|
53
|
-
Core MCP tools: `
|
|
66
|
+
Core MCP tools: `unbrowse_discover`, `unbrowse_run`, `unbrowse_inspect`, `unbrowse_resume`, `unbrowse_cancel`, `unbrowse_scrape`, `unbrowse_map`, `unbrowse_sites`, `unbrowse_usage`, `unbrowse_credits`, `unbrowse_forget`, `unbrowse_learn`, `unbrowse_index`, `unbrowse_index_status`, `unbrowse_credentials_list`, `unbrowse_credentials_request`, `unbrowse_credentials_status`, `unbrowse_connect` (connect an app's own MCP server, such as Linear, Notion or GitHub, so its tools run as the person: an app with sign-in returns a link the person opens), and the cloud browser `unbrowse_browse_open`, `unbrowse_browse_snapshot`, `unbrowse_browse_act`, `unbrowse_browse_finish`, `unbrowse_browse_close`.
|
|
54
67
|
|
|
55
68
|
[references/tools.json](references/tools.json) contains the exported core MCP input schemas. The connected server's `tools/list` is authoritative: it also includes dynamic tools available to this user's workspace. Never invent a capability ID or input schema.
|
|
56
69
|
|
|
57
70
|
## Execute a task
|
|
58
71
|
|
|
59
|
-
1. Discover with `
|
|
60
|
-
2. Call the selected tool with its listed schema, or `
|
|
61
|
-
3. Inspect the returned status and actual result. `input_required` means answer the open requirements on the **same** run: `
|
|
62
|
-
4. `no_capability` means no reusable route matched. Follow `result.next`: `tool` is `
|
|
72
|
+
1. Discover with `unbrowse_discover {query}`. Inspect returned inputs, choices and hints. Prefer a healthy matching capability; `warm` means HTTP replay, `rendered` needs rendering. Check `unbrowse_sites` for saved session and login state when relevant. Public tools carry `version`, the Unbrowse version that generated them (YYYY.MM.DD); among equal matches the newest comes first, and `minVersion` leaves older ones out.
|
|
73
|
+
2. Call the selected tool with its listed schema, or `unbrowse_run {capability, input}`. A natural-language `task` can route when no ID was selected. Use a stable `idempotencyKey` for the same intended mutation. For a large answer pass `select` (MCP run tools, `unbrowse_resume`, `unbrowse_inspect`, `POST /api/v1/runs`): paths like `["results[].{id,title,price}", "total"]`. It narrows only what comes back, after verification; billing is unchanged. Results over 40,000 characters are shortened (`truncated: true`); `selectMissing` lists paths that matched nothing.
|
|
74
|
+
3. Inspect the returned status and actual result. `input_required` means answer the open requirements on the **same** run: `unbrowse_resume {runId, answers:{field:value}}`. For a choice, pass the listed option's value. Preserve revision checks when supplied.
|
|
75
|
+
4. `no_capability` means no reusable route matched. Follow `result.next`: `tool` is `unbrowse_index` (`POST /api/v1/index`, then `GET /api/v1/index/{jobId}`; CLI `unbrowse index <url>`). To answer now, read the page instead: `unbrowse_scrape` (CLI `unbrowse scrape <url>`). Call `unbrowse_browse_open` only when that name is in this session's tool list. Do not POST `/api/v1/browse/open`. It is not a route. Report unsupported or blocked sites honestly.
|
|
63
76
|
5. Only report completion from a verified result. `outcome_unknown` means a change may have occurred: inspect the effect receipt and destination before retrying. Cancellation stops future dispatches; it does not undo completed effects.
|
|
64
77
|
|
|
65
78
|
Do not infer business success from HTTP 200, tool transport success, a screenshot, or a generated plan. Do not promise universal coverage or browserless execution on every first request. Obtain the user's authorization for posting, sending, purchasing or other external writes.
|
|
@@ -68,46 +81,45 @@ Do not infer business success from HTTP 200, tool transport success, a screensho
|
|
|
68
81
|
|
|
69
82
|
When the person names a site:
|
|
70
83
|
|
|
71
|
-
1. If `
|
|
72
|
-
2. Look the host up (`
|
|
73
|
-
3. No tools: `
|
|
84
|
+
1. If `unbrowse_discover` is not in this session's tool list, the MCP is not signed in. Stop. Name the configured MCP URL and say the CLI login does not cover it.
|
|
85
|
+
2. Look the host up (`unbrowse_sites`, or CLI `unbrowse site <host>`). Tools already compiled: use one. Stop.
|
|
86
|
+
3. No tools: `unbrowse_index {url, focus}` or `POST /api/v1/index`. Poll `unbrowse_index_status` or `GET /api/v1/index/{jobId}`.
|
|
74
87
|
4. `status: failed` and `error.code: model_unavailable`: the indexing model is out of credit. Report the job id and the message. Do not browse instead, and do not start the same job again in a loop.
|
|
75
88
|
5. `status: done` with `indexed: 0` means nothing was learned. Say so. `indexed > 0` means call one tool and check the result.
|
|
76
89
|
|
|
77
90
|
A 202 from `/api/v1/index` is a job id, not a compiled tool.
|
|
78
91
|
|
|
79
|
-
##
|
|
92
|
+
## A site's tools over plain HTTP
|
|
80
93
|
|
|
81
|
-
|
|
94
|
+
Each compiled site is also a REST API, for code rather than an agent session:
|
|
82
95
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
4. Close sessions when finished. `browse.close` still indexes unless `discard:true`.
|
|
96
|
+
- `GET https://unbrowse.ai/api/v1/sites/<host>/openapi.json`: OpenAPI 3.1, one operation per tool, typed inputs, an `example` input it was verified with, every status and header. No key needed to read.
|
|
97
|
+
- `POST https://unbrowse.ai/api/v1/sites/<host>/call/<tool>` with the tool's inputs as the JSON body and `Authorization: Bearer <key>`. Options: `x-unbrowse-deadline-ms`, `Idempotency-Key`, `select`. `202` means `input_required`; `504 run_timeout` gives a `runId` to poll; `409 tool_quarantined` means use another tool.
|
|
98
|
+
- SDK: `new Unbrowse().callTool(host, tool, input)`.
|
|
87
99
|
|
|
88
|
-
|
|
100
|
+
Contract and examples: https://unbrowse.ai/docs/site-apis.md
|
|
89
101
|
|
|
90
|
-
|
|
102
|
+
## Read or learn a site
|
|
91
103
|
|
|
92
|
-
|
|
104
|
+
Prefer `unbrowse_discover` and a matching tool or `unbrowse_run` for structured data and site tasks. `unbrowse_scrape {url}` is a **last resort for static pages and documents**, only when no suitable API or learned tool is available. A PDF, .docx, .xls or .xlsx URL comes back as extracted markdown text (`metadata.pages` for PDFs; spreadsheets preserve sheet names, rows and formatted values). `metadata.truncated` marks bounded extraction; `formats: ["raw"]` returns the exact document bytes as base64; `unbrowse_map {url}` finds same-site URLs. A known URL or scrape's rendering support does not make it the default. For dynamic content, search, pagination or interaction with no matching route, use `unbrowse_index` or the available cloud browser tools to learn and replay the site's API:
|
|
93
105
|
|
|
94
|
-
|
|
106
|
+
1. `unbrowse_browse_open {url,task}` returns the page and element refs.
|
|
107
|
+
2. Use `browse.act` with the latest refs. For ordinary inputs, include a meaningful `name` such as `date` or `query`; exercise every filter the task needs. Refresh the snapshot after page changes.
|
|
108
|
+
3. Use `browse.finish {sessionId}` to return the final page and compile observed routes. Two sessions with different inputs help identify reusable parameters. Check `learnError` and `newTool`; browsing success alone does not prove a reusable route exists.
|
|
109
|
+
4. Close sessions when finished. `browse.close` still indexes unless `discard:true`.
|
|
95
110
|
|
|
96
|
-
|
|
97
|
-
- `unbrowse.replay.get {sid}` returns the summary: intent, outcome, drop-off reason, bugs and key moments.
|
|
98
|
-
- `unbrowse.replay.timeline {sid}` returns the session as text lines with times; narrow long ones with `from`/`to` or `kinds`.
|
|
99
|
-
- `unbrowse.replay.ask {question}` answers across sessions with citations (session and moment, with a link). Only cite what it returns.
|
|
111
|
+
To cover a whole site ahead of need, `unbrowse_index {url, focus?, maxCapabilities?}` starts a background job: Unbrowse's own agent performs the site's core read-only capabilities, proves each with a browserless replay and adds them to your tools. Follow it with `unbrowse_index_status {jobId}`. `maxCapabilities` caps every tool the job indexes (declared, sitemap page types and recorded flows together). A `focus` keeps only sitemap page types that match it, and none when it names flows such as paging, page size, filters or search. Query keys in the start URL (`?page=0&pageSize=100`) become the tool's inputs. `stoppedReason` says why a job ended. The time budget is extended once, by half, while tools are still being proven.
|
|
100
112
|
|
|
101
|
-
|
|
113
|
+
An existing HAR pair can be sent through `unbrowse_learn`. Only submit recordings the user authorized; HARs can contain private data. Private and loopback destinations are refused by the hosted service.
|
|
102
114
|
|
|
103
115
|
## Website sign-in
|
|
104
116
|
|
|
105
117
|
Unbrowse account sign-in and a website's saved login are separate. Never ask for passwords in chat or type credentials via ordinary tool arguments.
|
|
106
118
|
|
|
107
119
|
- On a login page, use `browse.act {sessionId,action:"autofill"}`, or `vault:"username"|"email"|"password"|"totp"` on a fill action. Values go directly from the vault to the site.
|
|
108
|
-
- Missing login: present the returned `signIn.url` or `details.url` save-login link. `
|
|
120
|
+
- Missing login: present the returned `signIn.url` or `details.url` save-login link. `unbrowse_credentials_request` can create one; `credentials.status` checks whether it was fulfilled. Resume only after it is ready.
|
|
109
121
|
- Do not bypass CAPTCHA, MFA or human verification. Present the supported handoff or report the blocker.
|
|
110
|
-
- Saved sessions are reused; do not sign in again merely because another task started.
|
|
122
|
+
- Saved sessions are reused automatically (the person can turn that off per site or for the whole workspace); do not sign in again merely because another task started.
|
|
111
123
|
|
|
112
124
|
Read-only secretless learned routes may be scrubbed and shared to the public registry. The owner can opt out in the console. Logins, private session values and writes are not public tool definitions.
|
|
113
125
|
|
|
@@ -116,25 +128,17 @@ Read-only secretless learned routes may be scrubbed and shared to the public reg
|
|
|
116
128
|
When the caller is an agent a builder runs for its own users, it uses an org key and names the user on every call: `X-Unbrowse-End-User: <that user's id>` (REST and MCP headers). Each user has their own logins and sessions.
|
|
117
129
|
|
|
118
130
|
- Always send the id of the user the task is for. Never reuse one user's id for another user's task, and never omit it: without it the call acts as the org itself, not any user.
|
|
119
|
-
- A `signIn.url` (a `/connect/…` link) is for that same user: deliver it to them, not to the builder or another user. They save the login there without an Unbrowse account; wait for `
|
|
131
|
+
- A `signIn.url` (a `/connect/…` link) is for that same user: deliver it to them, not to the builder or another user. They save the login there without an Unbrowse account; wait for `unbrowse_credentials_status` to be `fulfilled`, then call again.
|
|
120
132
|
- `org__…` tools are shared by the org's users (read-only, no logins); `my__…` tools are the current user's own.
|
|
121
133
|
- Quota errors are the org's balance, not the user's. Report them to the builder.
|
|
122
134
|
|
|
123
135
|
Guide: https://github.com/lekt9/unbrowse6/blob/master/docs/orgs.md
|
|
124
136
|
|
|
125
|
-
## Live canvas
|
|
126
|
-
|
|
127
|
-
When `unbrowse.canvas.read` and `.put` are listed, they connect to https://unbrowse.ai/app/canvas in the same signed-in workspace.
|
|
128
|
-
|
|
129
|
-
Use notes and plans for static text; results for source data; drafts for proposed responses. Give child cards `parentId` to unfold from a result. Read current card revisions before updating; supply `expectedRevision` and preserve human edits. Put source links beside factual claims. Label proposed text as a draft.
|
|
130
|
-
|
|
131
|
-
`canvas.put` creates cards, not external sends. Preparing reply drafts does not authorize posting them. Sending is reviewed separately in the canvas UI.
|
|
132
|
-
|
|
133
137
|
## Limits and recovery
|
|
134
138
|
|
|
135
|
-
- 401:
|
|
136
|
-
- `model_unavailable` on an index job: the indexing model is out of credit. Report the job id. No tools were compiled. This is not `
|
|
137
|
-
- Quota/payment error: show the returned limit and console link; do not retry payments blindly. When listed, `
|
|
139
|
+
- 401: sign that door in again with OAuth. CLI 401: `npx unbrowse login`. Remote MCP 401: the host's own OAuth for that server (Claude Code: `/mcp`). One sign-in does not fix the other.
|
|
140
|
+
- `model_unavailable` on an index job: the indexing model is out of credit. Report the job id. No tools were compiled. This is not `unbrowse_usage` and not the site.
|
|
141
|
+
- Quota/payment error: show the returned limit and console link; do not retry payments blindly. When listed, `unbrowse_credits` shows free/paid balances and can return a checkout link for the user. Opening a billing link does not authorize payment.
|
|
138
142
|
- Verification or login block: use the returned handoff; don't present a challenge page as source content.
|
|
139
143
|
- Timeout on a write: inspect the existing run before retrying.
|
|
140
|
-
- Pricing and quotas: consult the account's current plan and `
|
|
144
|
+
- Pricing and quotas: consult the account's current plan and `unbrowse_usage`; this skill does not fix prices.
|
package/dist/cli.js
CHANGED
|
@@ -120,7 +120,8 @@ class Unbrowse {
|
|
|
120
120
|
const deadline = Date.now() + (opts.timeoutMs ?? 600000);
|
|
121
121
|
let step = await this.run({ ...request, egress: "client" });
|
|
122
122
|
const sent = new Set;
|
|
123
|
-
|
|
123
|
+
let idle = 0;
|
|
124
|
+
while (isEgressStep(step) || isEgressWaiting(step)) {
|
|
124
125
|
const { egressId } = step;
|
|
125
126
|
if (Date.now() > deadline) {
|
|
126
127
|
await this.closeEgress(egressId).catch(() => {
|
|
@@ -128,6 +129,12 @@ class Unbrowse {
|
|
|
128
129
|
});
|
|
129
130
|
throw new UnbrowseError("client-egress run did not finish in time", 408, "timeout");
|
|
130
131
|
}
|
|
132
|
+
if (isEgressWaiting(step)) {
|
|
133
|
+
await new Promise((r) => setTimeout(r, Math.min(250 * 2 ** idle++, 2000)));
|
|
134
|
+
step = await this.egress(egressId);
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
idle = 0;
|
|
131
138
|
const fresh = step.requests.filter((r) => !sent.has(r.id));
|
|
132
139
|
if (!fresh.length) {
|
|
133
140
|
step = await this.egress(egressId);
|
|
@@ -152,7 +159,7 @@ class Unbrowse {
|
|
|
152
159
|
return;
|
|
153
160
|
try {
|
|
154
161
|
const next = await this.answerEgress(egressId, req.id, answer);
|
|
155
|
-
if (isEgressStep(next))
|
|
162
|
+
if (isEgressStep(next) || isEgressWaiting(next))
|
|
156
163
|
latest = next;
|
|
157
164
|
else
|
|
158
165
|
finished = next;
|
|
@@ -288,6 +295,12 @@ function normalizeHost(site) {
|
|
|
288
295
|
function isEgressStep(v) {
|
|
289
296
|
return !!v && typeof v === "object" && v.status === "egress_required";
|
|
290
297
|
}
|
|
298
|
+
function isEgressWaiting(v) {
|
|
299
|
+
if (!v || typeof v !== "object")
|
|
300
|
+
return false;
|
|
301
|
+
const o = v;
|
|
302
|
+
return typeof o.egressId === "string" && o.runId === undefined && o.status !== "egress_required";
|
|
303
|
+
}
|
|
291
304
|
async function sendEgress(send, req) {
|
|
292
305
|
const body = req.body === undefined ? undefined : req.bodyEncoding === "base64" ? base64ToBytes(req.body) : req.body;
|
|
293
306
|
const res = await send(req.url, { method: req.method, headers: req.headers, redirect: req.redirect, ...body !== undefined ? { body } : {} });
|
|
@@ -1432,7 +1445,7 @@ ${url.toString()}`);
|
|
|
1432
1445
|
|
|
1433
1446
|
// src/cli.ts
|
|
1434
1447
|
init_src();
|
|
1435
|
-
var VERSION = "12.2.
|
|
1448
|
+
var VERSION = "12.2.1";
|
|
1436
1449
|
var DEFAULT_ORIGIN = "https://unbrowse.ai";
|
|
1437
1450
|
var HELP = `unbrowse ${VERSION} — call websites as APIs through the Unbrowse API
|
|
1438
1451
|
|
package/package.json
CHANGED
package/references/tools.json
CHANGED
|
@@ -2,128 +2,8 @@
|
|
|
2
2
|
"endpoint": "https://unbrowse.ai/mcp",
|
|
3
3
|
"tools": [
|
|
4
4
|
{
|
|
5
|
-
"name": "
|
|
6
|
-
"description": "
|
|
7
|
-
"inputSchema": {
|
|
8
|
-
"type": "object",
|
|
9
|
-
"properties": {
|
|
10
|
-
"id": {
|
|
11
|
-
"type": "string",
|
|
12
|
-
"description": "Table id, e.g. \"leads\". Reuse it to append."
|
|
13
|
-
},
|
|
14
|
-
"title": {
|
|
15
|
-
"type": "string"
|
|
16
|
-
},
|
|
17
|
-
"columns": {
|
|
18
|
-
"type": "array",
|
|
19
|
-
"items": {
|
|
20
|
-
"type": "object",
|
|
21
|
-
"properties": {
|
|
22
|
-
"key": {
|
|
23
|
-
"type": "string"
|
|
24
|
-
},
|
|
25
|
-
"label": {
|
|
26
|
-
"type": "string"
|
|
27
|
-
}
|
|
28
|
-
},
|
|
29
|
-
"required": [
|
|
30
|
-
"key"
|
|
31
|
-
]
|
|
32
|
-
}
|
|
33
|
-
},
|
|
34
|
-
"rows": {
|
|
35
|
-
"type": "array",
|
|
36
|
-
"items": {
|
|
37
|
-
"type": "object"
|
|
38
|
-
},
|
|
39
|
-
"minItems": 1,
|
|
40
|
-
"maxItems": 200
|
|
41
|
-
},
|
|
42
|
-
"parentId": {
|
|
43
|
-
"type": "string"
|
|
44
|
-
}
|
|
45
|
-
},
|
|
46
|
-
"required": [
|
|
47
|
-
"id",
|
|
48
|
-
"rows"
|
|
49
|
-
],
|
|
50
|
-
"additionalProperties": false
|
|
51
|
-
}
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
"name": "unbrowse.canvas.read",
|
|
55
|
-
"description": "Read the signed-in user's live canvas, card revisions, selected context and conversation. Open /app/canvas to watch cards appear.",
|
|
56
|
-
"inputSchema": {
|
|
57
|
-
"type": "object",
|
|
58
|
-
"properties": {},
|
|
59
|
-
"additionalProperties": false
|
|
60
|
-
}
|
|
61
|
-
},
|
|
62
|
-
{
|
|
63
|
-
"name": "unbrowse.canvas.put",
|
|
64
|
-
"description": "Insert/update a live UI card on the user's canvas. kind: note, plan, results, draft, activity, table (data {columns:[{key,label}], rows:[{...}]}; to add rows use unbrowse.canvas.rows). Plain text for plans/notes; data for actual API results. Use parentId to unfold from a prior card. Draft action is optional: {capabilityId,input,bodyField}; the human reviews and sends in the UI. Never send from this tool. Updates require expectedRevision; human edits are protected. No HTML or JavaScript.",
|
|
65
|
-
"inputSchema": {
|
|
66
|
-
"type": "object",
|
|
67
|
-
"properties": {
|
|
68
|
-
"id": {
|
|
69
|
-
"type": "string"
|
|
70
|
-
},
|
|
71
|
-
"expectedRevision": {
|
|
72
|
-
"type": "integer"
|
|
73
|
-
},
|
|
74
|
-
"kind": {
|
|
75
|
-
"type": "string",
|
|
76
|
-
"enum": [
|
|
77
|
-
"note",
|
|
78
|
-
"plan",
|
|
79
|
-
"results",
|
|
80
|
-
"draft",
|
|
81
|
-
"activity",
|
|
82
|
-
"search",
|
|
83
|
-
"table"
|
|
84
|
-
]
|
|
85
|
-
},
|
|
86
|
-
"title": {
|
|
87
|
-
"type": "string"
|
|
88
|
-
},
|
|
89
|
-
"text": {
|
|
90
|
-
"type": "string"
|
|
91
|
-
},
|
|
92
|
-
"data": {},
|
|
93
|
-
"parentId": {
|
|
94
|
-
"type": "string"
|
|
95
|
-
},
|
|
96
|
-
"action": {
|
|
97
|
-
"type": "object",
|
|
98
|
-
"properties": {
|
|
99
|
-
"capabilityId": {
|
|
100
|
-
"type": "string"
|
|
101
|
-
},
|
|
102
|
-
"input": {
|
|
103
|
-
"type": "object"
|
|
104
|
-
},
|
|
105
|
-
"bodyField": {
|
|
106
|
-
"type": "string"
|
|
107
|
-
}
|
|
108
|
-
},
|
|
109
|
-
"required": [
|
|
110
|
-
"capabilityId",
|
|
111
|
-
"input",
|
|
112
|
-
"bodyField"
|
|
113
|
-
]
|
|
114
|
-
}
|
|
115
|
-
},
|
|
116
|
-
"required": [
|
|
117
|
-
"id",
|
|
118
|
-
"kind",
|
|
119
|
-
"title"
|
|
120
|
-
],
|
|
121
|
-
"additionalProperties": false
|
|
122
|
-
}
|
|
123
|
-
},
|
|
124
|
-
{
|
|
125
|
-
"name": "unbrowse.run",
|
|
126
|
-
"description": "Start a durable Unbrowse run by capability id or natural-language task. For a learned capability, pass `input` keyed by the inputs unbrowse.discover lists (e.g. {origin, destination, date, passenger}); anything missing is asked for on the same run. Fails with no_capability when nothing fits. result.next.tool is unbrowse.index (POST /api/v1/index). unbrowse.browse.open is only for a session whose tool list includes it. It is not a REST route, and the CLI does not open a browser.",
|
|
5
|
+
"name": "unbrowse_run",
|
|
6
|
+
"description": "Start a durable Unbrowse run by capability id or natural-language task. For a learned capability, pass `input` keyed by the inputs unbrowse_discover lists (e.g. {origin, destination, date, passenger}); anything missing is asked for on the same run. Fails with no_capability when nothing fits. result.next.tool is unbrowse_index (POST /api/v1/index). unbrowse_browse_open is only for a session whose tool list includes it. It is not a REST route, and the CLI does not open a browser.",
|
|
127
7
|
"inputSchema": {
|
|
128
8
|
"type": "object",
|
|
129
9
|
"properties": {
|
|
@@ -145,6 +25,16 @@
|
|
|
145
25
|
"type": "string"
|
|
146
26
|
}
|
|
147
27
|
},
|
|
28
|
+
"allowedDestinations": {
|
|
29
|
+
"type": "array",
|
|
30
|
+
"maxItems": 100,
|
|
31
|
+
"items": {
|
|
32
|
+
"type": "string",
|
|
33
|
+
"minLength": 1,
|
|
34
|
+
"maxLength": 253
|
|
35
|
+
},
|
|
36
|
+
"description": "Restrict this run, including resumed steps, to these exact destination hostnames."
|
|
37
|
+
},
|
|
148
38
|
"interactionMode": {
|
|
149
39
|
"type": "string",
|
|
150
40
|
"enum": [
|
|
@@ -162,13 +52,19 @@
|
|
|
162
52
|
"type": "string"
|
|
163
53
|
},
|
|
164
54
|
"description": "Keep only these parts of the result, e.g. [\"results[].{id,title,price}\", \"data.items[].name\", \"total\"]. Dots walk keys, [] maps over a list, [n] takes one item, a final {a,b} keeps several keys. Applied after the run is verified; billing is the same. Use it when a result is large (over 40,000 characters it is shortened)."
|
|
55
|
+
},
|
|
56
|
+
"deadlineMs": {
|
|
57
|
+
"type": "integer",
|
|
58
|
+
"minimum": 5000,
|
|
59
|
+
"maximum": 300000,
|
|
60
|
+
"description": "Answer within this many ms (default 60000). Past it the result is run_timeout with a runId: the run keeps going; poll unbrowse_inspect."
|
|
165
61
|
}
|
|
166
62
|
},
|
|
167
63
|
"additionalProperties": false
|
|
168
64
|
}
|
|
169
65
|
},
|
|
170
66
|
{
|
|
171
|
-
"name": "
|
|
67
|
+
"name": "unbrowse_inspect",
|
|
172
68
|
"description": "Inspect a run: status, requirements, verified result, known effects, routing explanation.",
|
|
173
69
|
"inputSchema": {
|
|
174
70
|
"type": "object",
|
|
@@ -190,7 +86,7 @@
|
|
|
190
86
|
}
|
|
191
87
|
},
|
|
192
88
|
{
|
|
193
|
-
"name": "
|
|
89
|
+
"name": "unbrowse_resume",
|
|
194
90
|
"description": "Answer the run's open requirements and continue the same run. Simplest: {runId, answers: {<affectedAction>: value}} — e.g. {\"origin\": \"CDG\"} or, for a choice, {\"selected_offer\": <an option's value>}. Answer several at once.",
|
|
195
91
|
"inputSchema": {
|
|
196
92
|
"type": "object",
|
|
@@ -250,7 +146,7 @@
|
|
|
250
146
|
}
|
|
251
147
|
},
|
|
252
148
|
{
|
|
253
|
-
"name": "
|
|
149
|
+
"name": "unbrowse_cancel",
|
|
254
150
|
"description": "Cancel a run. Returns a receipt of dispatched, uncertain and unstarted effects.",
|
|
255
151
|
"inputSchema": {
|
|
256
152
|
"type": "object",
|
|
@@ -265,8 +161,8 @@
|
|
|
265
161
|
}
|
|
266
162
|
},
|
|
267
163
|
{
|
|
268
|
-
"name": "
|
|
269
|
-
"description": "Compile browser traces or HAR files of a task done by hand into a reusable one-call capability. Send two or more traces with different inputs so Unbrowse can diff them into fillable parameters and trace values (csrf, ids, tokens) to the responses that produced them. Returns the harness YAML, the agent skill, and the capability id to pass to
|
|
164
|
+
"name": "unbrowse_learn",
|
|
165
|
+
"description": "Compile browser traces or HAR files of a task done by hand into a reusable one-call capability. Send two or more traces with different inputs so Unbrowse can diff them into fillable parameters and trace values (csrf, ids, tokens) to the responses that produced them. Returns the harness YAML, the agent skill, and the capability id to pass to unbrowse_run.",
|
|
270
166
|
"inputSchema": {
|
|
271
167
|
"type": "object",
|
|
272
168
|
"properties": {
|
|
@@ -288,8 +184,8 @@
|
|
|
288
184
|
}
|
|
289
185
|
},
|
|
290
186
|
{
|
|
291
|
-
"name": "
|
|
292
|
-
"description": "Open a cloud browser (patchright) on a URL when no capability fits yet. Recording is on from the first navigation, so doing the task here fulfils it now and teaches Unbrowse the site. Returns a snapshot of interactive elements with @refs.",
|
|
187
|
+
"name": "unbrowse_browse_open",
|
|
188
|
+
"description": "Open a cloud browser (patchright) on a URL when no capability fits yet. Recording is on from the first navigation, so doing the task here fulfils it now and teaches Unbrowse the site. Returns a snapshot of interactive elements with @refs. When you have the answer, or give up, call unbrowse_browse_finish (or unbrowse_browse_close): a session left open holds a browser until it idles out after 2 minutes.",
|
|
293
189
|
"inputSchema": {
|
|
294
190
|
"type": "object",
|
|
295
191
|
"properties": {
|
|
@@ -311,13 +207,18 @@
|
|
|
311
207
|
}
|
|
312
208
|
},
|
|
313
209
|
{
|
|
314
|
-
"name": "
|
|
315
|
-
"description": "Current page text and interactive elements with @refs. Refs change after every action; always act on the latest snapshot.",
|
|
210
|
+
"name": "unbrowse_browse_snapshot",
|
|
211
|
+
"description": "Current page text and interactive elements with @refs. When nextTextOffset is present, call again on the same session with textOffset to read the rest. Restart at offset 0 after navigation or page changes. Refs change after every action; always act on the latest snapshot.",
|
|
316
212
|
"inputSchema": {
|
|
317
213
|
"type": "object",
|
|
318
214
|
"properties": {
|
|
319
215
|
"sessionId": {
|
|
320
216
|
"type": "string"
|
|
217
|
+
},
|
|
218
|
+
"textOffset": {
|
|
219
|
+
"type": "integer",
|
|
220
|
+
"minimum": 0,
|
|
221
|
+
"description": "Character offset from nextTextOffset; omit to start at the beginning"
|
|
321
222
|
}
|
|
322
223
|
},
|
|
323
224
|
"required": [
|
|
@@ -326,8 +227,8 @@
|
|
|
326
227
|
}
|
|
327
228
|
},
|
|
328
229
|
{
|
|
329
|
-
"name": "
|
|
330
|
-
"description": "click | fill | select | check | press | wait on a @ref, or autofill. For fill, pass `name` as the business field (origin, date, email…) so the learned API gets readable inputs. For logins never ask the user for a password: `autofill` fills the page's login form (username or email, password, 2FA code) from the user's Unbrowse password manager, or fill one @ref with `vault: \"username\" | \"email\" | \"password\" | \"totp\"`. The values go straight into the page and never pass through you. If no login is saved for the site, the error carries a link: give it to the user, wait with
|
|
230
|
+
"name": "unbrowse_browse_act",
|
|
231
|
+
"description": "click | fill | select | check | press | wait on a @ref, or autofill. For fill, pass `name` as the business field (origin, date, email…) so the learned API gets readable inputs. For logins never ask the user for a password: `autofill` fills the page's login form (username or email, password, 2FA code) from the user's Unbrowse password manager, or fill one @ref with `vault: \"username\" | \"email\" | \"password\" | \"totp\"`. The values go straight into the page and never pass through you. If no login is saved for the site, or the user has not approved agent sign-ins there (approval_required), the error carries a link: give it to the user, wait with unbrowse_credentials_status, then repeat the action.",
|
|
331
232
|
"inputSchema": {
|
|
332
233
|
"type": "object",
|
|
333
234
|
"properties": {
|
|
@@ -367,7 +268,7 @@
|
|
|
367
268
|
},
|
|
368
269
|
"credential": {
|
|
369
270
|
"type": "string",
|
|
370
|
-
"description": "A vault:// login ref from
|
|
271
|
+
"description": "A vault:// login ref from unbrowse_credentials_list, when several are saved for the site"
|
|
371
272
|
},
|
|
372
273
|
"key": {
|
|
373
274
|
"type": "string"
|
|
@@ -383,7 +284,7 @@
|
|
|
383
284
|
}
|
|
384
285
|
},
|
|
385
286
|
{
|
|
386
|
-
"name": "
|
|
287
|
+
"name": "unbrowse_forget",
|
|
387
288
|
"description": "Delete one of your own learned capabilities (a shortcut that answers the wrong thing, or is no longer wanted), or unpin a public one from your tools. You cannot delete another workspace's capability.",
|
|
388
289
|
"inputSchema": {
|
|
389
290
|
"type": "object",
|
|
@@ -400,22 +301,34 @@
|
|
|
400
301
|
}
|
|
401
302
|
},
|
|
402
303
|
{
|
|
403
|
-
"name": "
|
|
404
|
-
"description": "The user's saved logins (Unbrowse password manager): site, label, masked username/email hints and which fields are saved. Never values — logins are filled into pages with
|
|
304
|
+
"name": "unbrowse_credentials_list",
|
|
305
|
+
"description": "The user's saved logins (Unbrowse password manager): site, label, masked username/email hints and which fields are saved. Never values — logins are filled into pages with unbrowse_browse_act (autofill, or vault on a field) and used by learned capabilities automatically. Pass `origin` (the site you need) — a workspace can hold thousands of logins. Answers one page (default 50) with `total`; pass `nextCursor` back as `cursor` for the next page.",
|
|
405
306
|
"inputSchema": {
|
|
406
307
|
"type": "object",
|
|
407
308
|
"properties": {
|
|
408
309
|
"origin": {
|
|
409
310
|
"type": "string",
|
|
410
|
-
"description": "Only logins usable on this site, e.g. https://github.com"
|
|
311
|
+
"description": "Only logins usable on this site, e.g. https://github.com. Pass it whenever you know the site."
|
|
312
|
+
},
|
|
313
|
+
"query": {
|
|
314
|
+
"type": "string",
|
|
315
|
+
"description": "Only logins whose site, label or masked username/email contains this text"
|
|
316
|
+
},
|
|
317
|
+
"limit": {
|
|
318
|
+
"type": "number",
|
|
319
|
+
"description": "Logins per page (default 50, at most 500)"
|
|
320
|
+
},
|
|
321
|
+
"cursor": {
|
|
322
|
+
"type": "string",
|
|
323
|
+
"description": "The nextCursor of the previous page"
|
|
411
324
|
}
|
|
412
325
|
},
|
|
413
326
|
"additionalProperties": false
|
|
414
327
|
}
|
|
415
328
|
},
|
|
416
329
|
{
|
|
417
|
-
"name": "
|
|
418
|
-
"description": "Ask the user to save a login you need, without seeing it: returns a one-time link to give them. They open it, sign in to Unbrowse and save the username/email, password and optional 2FA seed. Then call
|
|
330
|
+
"name": "unbrowse_credentials_request",
|
|
331
|
+
"description": "Ask the user to save a login you need, without seeing it: returns a one-time link to give them. They open it, sign in to Unbrowse and save the username/email, password and optional 2FA seed. Then call unbrowse_credentials_status.",
|
|
419
332
|
"inputSchema": {
|
|
420
333
|
"type": "object",
|
|
421
334
|
"properties": {
|
|
@@ -447,8 +360,8 @@
|
|
|
447
360
|
}
|
|
448
361
|
},
|
|
449
362
|
{
|
|
450
|
-
"name": "
|
|
451
|
-
"description": "Whether the user has
|
|
363
|
+
"name": "unbrowse_credentials_status",
|
|
364
|
+
"description": "Whether the user has answered a request: a login request (cr_…: pending, fulfilled, declined, expired) or a sign-in approval (ap_…: pending, approved, denied, expired). Waits up to `waitSeconds` (default 20, max 50) for it to change.",
|
|
452
365
|
"inputSchema": {
|
|
453
366
|
"type": "object",
|
|
454
367
|
"properties": {
|
|
@@ -466,8 +379,8 @@
|
|
|
466
379
|
}
|
|
467
380
|
},
|
|
468
381
|
{
|
|
469
|
-
"name": "
|
|
470
|
-
"description": "End the session. Returns the page the task ended on and compiles every recorded session for this site into a learned.* capability you can call with
|
|
382
|
+
"name": "unbrowse_browse_finish",
|
|
383
|
+
"description": "End the session. Returns the page the task ended on and compiles every recorded session for this site into a learned.* capability you can call with unbrowse_run next time — no browser.",
|
|
471
384
|
"inputSchema": {
|
|
472
385
|
"type": "object",
|
|
473
386
|
"properties": {
|
|
@@ -489,7 +402,7 @@
|
|
|
489
402
|
}
|
|
490
403
|
},
|
|
491
404
|
{
|
|
492
|
-
"name": "
|
|
405
|
+
"name": "unbrowse_browse_close",
|
|
493
406
|
"description": "End a browser session. It is still indexed (passive learning) unless discard is true.",
|
|
494
407
|
"inputSchema": {
|
|
495
408
|
"type": "object",
|
|
@@ -507,14 +420,14 @@
|
|
|
507
420
|
}
|
|
508
421
|
},
|
|
509
422
|
{
|
|
510
|
-
"name": "
|
|
511
|
-
"description": "Read one page
|
|
423
|
+
"name": "unbrowse_scrape",
|
|
424
|
+
"description": "Read one page or document, or one URL of a site's own JSON API. For a task on a site (search, listings, prices, filters) call unbrowse_run { task } first: it runs a learned tool, or browses and learns one. A JSON API URL read with formats [\"raw\"] is learned as your tool and returned as newTool: call that tool next time instead of scraping or searching for the endpoint. A page that needs a browser is rendered; when its content came from the site's own data request, that request is learned as your tool too (newTool), otherwise the answer's next says how unbrowse_run or unbrowse_browse_* learn it. Returns clean markdown (main content only by default), links and metadata. Rendering is a compatibility fallback for page reads, not a reason to choose scrape for dynamic sites. Kept sign-ins follow the person's reuse settings. A PDF, Word (.docx) or Excel (.xls/.xlsx) URL comes back as extracted text in markdown, with metadata.pages for PDFs and metadata.truncated when extraction limits apply (up to 20 MB, over HTTP). Every answer carries metadata.status (the page's real HTTP status; statusCode is the same value), timing {ms, httpMs, renderMs, queuedMs} and attempts (HTTP tries). It never runs past deadlineMs (default 45 s): then it fails scrape_timeout (HTTP 504) with details.stage (http or render). A bot wall fails fast as blocked with details {stage, reason, timing, attempts, httpStatus, renderStatus}; a page that met a bot wall over HTTP and in the browser answers blocked at once for 10 minutes, with details.retryAfter (seconds) and cachedAt. A known URL alone is not a reason to choose scrape. One verified call.",
|
|
512
425
|
"inputSchema": {
|
|
513
426
|
"type": "object",
|
|
514
427
|
"properties": {
|
|
515
428
|
"url": {
|
|
516
429
|
"type": "string",
|
|
517
|
-
"description": "
|
|
430
|
+
"description": "A page, document or JSON API URL, e.g. https://docs.rs/serde or https://api.example.com/v1/items?q=x"
|
|
518
431
|
},
|
|
519
432
|
"formats": {
|
|
520
433
|
"type": "array",
|
|
@@ -528,7 +441,7 @@
|
|
|
528
441
|
"raw"
|
|
529
442
|
]
|
|
530
443
|
},
|
|
531
|
-
"description": "What to return (default: markdown). raw: the response body as sent (JSON APIs, feeds), over HTTP only, never rendered"
|
|
444
|
+
"description": "What to return (default: markdown). raw: the response body as sent (JSON APIs, feeds), over HTTP only (with the kept session, if any), never rendered; a first-party JSON answer is learned as a tool (newTool)"
|
|
532
445
|
},
|
|
533
446
|
"onlyMainContent": {
|
|
534
447
|
"type": "boolean",
|
|
@@ -553,6 +466,12 @@
|
|
|
553
466
|
"type": "string"
|
|
554
467
|
},
|
|
555
468
|
"description": "Extra request headers, limited to accept, accept-language, referer, origin, x-requested-with, x-ig-app-id, x-asbd-id; others are ignored"
|
|
469
|
+
},
|
|
470
|
+
"deadlineMs": {
|
|
471
|
+
"type": "number",
|
|
472
|
+
"minimum": 5000,
|
|
473
|
+
"maximum": 120000,
|
|
474
|
+
"description": "Overall time budget in milliseconds (default 45000, clamped to 5000–120000). Past it the call fails scrape_timeout (HTTP 504) with details.stage http or render, never later"
|
|
556
475
|
}
|
|
557
476
|
},
|
|
558
477
|
"required": [
|
|
@@ -562,8 +481,8 @@
|
|
|
562
481
|
}
|
|
563
482
|
},
|
|
564
483
|
{
|
|
565
|
-
"name": "
|
|
566
|
-
"description": "List a site's URLs: the sitemaps its robots.txt names (or /sitemap.xml, following one level of sitemap indexes), then the links on the given page. Same-site only. Filter with search. Use it to
|
|
484
|
+
"name": "unbrowse_map",
|
|
485
|
+
"description": "List a site's URLs: the sitemaps its robots.txt names (or /sitemap.xml, following one level of sitemap indexes), then the links on the given page. Same-site only. Filter with search. Use it to locate a relevant URL; prefer API discovery and replay, with scrape only as a last resort for static content. One verified call.",
|
|
567
486
|
"inputSchema": {
|
|
568
487
|
"type": "object",
|
|
569
488
|
"properties": {
|
|
@@ -587,7 +506,7 @@
|
|
|
587
506
|
}
|
|
588
507
|
},
|
|
589
508
|
{
|
|
590
|
-
"name": "
|
|
509
|
+
"name": "unbrowse_sites",
|
|
591
510
|
"description": "What Unbrowse knows about each website this workspace has touched, before you act: access (public, or only behind a sign-in), the kept signed-in session (active, expired, logged_out or none — and when), the last sign-in, whether a login is saved, the tools already learned there and public tools, and any bot check that blocked it. Check it first: an active session means no sign-in is needed; a learned tool means no browsing is needed. Pass a site for one, or nothing for all.",
|
|
592
511
|
"inputSchema": {
|
|
593
512
|
"type": "object",
|
|
@@ -601,7 +520,37 @@
|
|
|
601
520
|
}
|
|
602
521
|
},
|
|
603
522
|
{
|
|
604
|
-
"name": "
|
|
523
|
+
"name": "unbrowse_connect",
|
|
524
|
+
"description": "Connect an app with its own MCP server (Linear, Notion, Slack, GitHub… about 7,000) or through Composio's sign-in (Gmail, Google Calendar, Drive, Docs, Sheets) to this workspace, so its tools appear in your tool list as <app>__<tool> and run with the person's own account. `search` finds apps; `app` connects one: an open server connects at once, an app with sign-in returns a link the person opens (you never see their password or token), a key app returns where the person saves the key. `url` adds any other remote MCP server by its https address (with `name`): an open one connects at once, one with OAuth returns a sign-in link, one that takes a key says where the person saves it. With no arguments: the connected apps. `disconnect: true` removes one and revokes its token.",
|
|
525
|
+
"inputSchema": {
|
|
526
|
+
"type": "object",
|
|
527
|
+
"properties": {
|
|
528
|
+
"app": {
|
|
529
|
+
"type": "string",
|
|
530
|
+
"description": "The app's domain or name, e.g. linear.app, notion.so, Slack; or a connected custom server's id (custom-<name>) to disconnect it"
|
|
531
|
+
},
|
|
532
|
+
"url": {
|
|
533
|
+
"type": "string",
|
|
534
|
+
"description": "Add a remote MCP server that is not in the catalog, by its https:// address"
|
|
535
|
+
},
|
|
536
|
+
"name": {
|
|
537
|
+
"type": "string",
|
|
538
|
+
"description": "A short name for the server added by `url` (its tools are listed as custom_<name>__<tool>)"
|
|
539
|
+
},
|
|
540
|
+
"search": {
|
|
541
|
+
"type": "string",
|
|
542
|
+
"description": "Find apps by name, domain or category, e.g. project management"
|
|
543
|
+
},
|
|
544
|
+
"disconnect": {
|
|
545
|
+
"type": "boolean",
|
|
546
|
+
"description": "Remove the connection to `app` and revoke its token"
|
|
547
|
+
}
|
|
548
|
+
},
|
|
549
|
+
"additionalProperties": false
|
|
550
|
+
}
|
|
551
|
+
},
|
|
552
|
+
{
|
|
553
|
+
"name": "unbrowse_credits",
|
|
605
554
|
"description": "This workspace's credits: the free monthly allowance left (pays for Unbrowse's own verified calls only; resets monthly) and paid credits (bought by the user; never expire), plus recent credit history and the top-up link. 1 credit = one verified call = $0.001. Pass a pack (p10 = $10 → 10,000, p50 = $50 → 50,000, p200 = $200 → 200,000) to get a Stripe Checkout link for the user to open — you never pay or see card details.",
|
|
606
555
|
"inputSchema": {
|
|
607
556
|
"type": "object",
|
|
@@ -620,7 +569,7 @@
|
|
|
620
569
|
}
|
|
621
570
|
},
|
|
622
571
|
{
|
|
623
|
-
"name": "
|
|
572
|
+
"name": "unbrowse_usage",
|
|
624
573
|
"description": "This workspace's metered usage for the current month: verified calls billed, how many were rendered (and the hosted renderer's passthrough cost), the monthly quota and what remains. Only verified successes bill; failed, refused, challenged and input_required runs are free.",
|
|
625
574
|
"inputSchema": {
|
|
626
575
|
"type": "object",
|
|
@@ -629,8 +578,8 @@
|
|
|
629
578
|
}
|
|
630
579
|
},
|
|
631
580
|
{
|
|
632
|
-
"name": "
|
|
633
|
-
"description": "Index a website on purpose: Unbrowse's own agent opens the site in a cloud browser, performs its core read-only capabilities (search, listings, item pages, filters…), compiles each into a tool and proves it with a browserless replay. Runs in the background (minutes); returns a jobId for
|
|
581
|
+
"name": "unbrowse_index",
|
|
582
|
+
"description": "Index a website on purpose: Unbrowse's own agent opens the site in a cloud browser, performs its core read-only capabilities (search, listings, item pages, filters…), compiles each into a tool and proves it with a browserless replay. Runs in the background (minutes); returns a jobId for unbrowse_index_status. The tools land in your tool list (and, when shared, in the public registry). Use it before a user needs a site, so their first call is instant. Never signs in or changes anything on the site.",
|
|
634
583
|
"inputSchema": {
|
|
635
584
|
"type": "object",
|
|
636
585
|
"properties": {
|
|
@@ -640,11 +589,11 @@
|
|
|
640
589
|
},
|
|
641
590
|
"focus": {
|
|
642
591
|
"type": "string",
|
|
643
|
-
"description": "Optional: what to cover, in plain words (\"product search and store stock\")"
|
|
592
|
+
"description": "Optional: what to cover, in plain words (\"product search and store stock\"). Only sitemap page types that match it are indexed, and none when it names flows (paging, page size, filters, search); the agent records the named flow twice with different values so its inputs (page, pageSize, filters) become parameters."
|
|
644
593
|
},
|
|
645
594
|
"maxCapabilities": {
|
|
646
595
|
"type": "number",
|
|
647
|
-
"description": "At most this many tools
|
|
596
|
+
"description": "At most this many tools in all (max 12): when given, the site's declared tools, its sitemap page types and the flows the agent records count together and never exceed it. Left out: up to 6 recorded flows plus up to 8 sitemap page types."
|
|
648
597
|
},
|
|
649
598
|
"public": {
|
|
650
599
|
"type": "boolean",
|
|
@@ -658,7 +607,7 @@
|
|
|
658
607
|
}
|
|
659
608
|
},
|
|
660
609
|
{
|
|
661
|
-
"name": "
|
|
610
|
+
"name": "unbrowse_index_status",
|
|
662
611
|
"description": "An index job's progress: queued, running, done or failed, the steps taken and every tool indexed (inputs, whether it runs without a browser, verified, public id). Waits up to `waitSeconds` (default 20, max 50) for it to finish. Without a jobId, lists your recent jobs.",
|
|
663
612
|
"inputSchema": {
|
|
664
613
|
"type": "object",
|
|
@@ -674,13 +623,17 @@
|
|
|
674
623
|
}
|
|
675
624
|
},
|
|
676
625
|
{
|
|
677
|
-
"name": "
|
|
678
|
-
"description": "Search the caller's private space (connected public and passworded sites as flat primitives) and the public registry (second priority, connect-on-the-fly). Each capability carries `hints.health` (healthy, degraded, untested, failing, ...) from its recent runs.
|
|
626
|
+
"name": "unbrowse_discover",
|
|
627
|
+
"description": "Search the caller's private space (connected public and passworded sites as flat primitives) and the public registry (second priority, connect-on-the-fly). Each capability carries `hints.health` (healthy, degraded, untested, failing, ...) from its recent runs. Only tools that can work for this caller are offered: public tools that are failing are left out unless the query names their site, public tools quarantined by the periodic check are left out entirely (calling one answers tool_quarantined with why), your own tools quarantined by their runs are left out (`withheld.quarantined` lists their ids), and tools that need a sign-in are offered only when you have a saved login, live session or connected account for their site (`withheld.signIn` names each site and the call that connects it: unbrowse_credentials_request, or unbrowse_connect for an app — including a connected app whose sign-in was refused, `reconnect: true`). Apps in `public` that need an account are listed only once you have one. A tool marked `personal` runs signed in as the person: its answers are their account's. `withheld.count` says how many were left out; for a failing site unbrowse_browse_open learns a fresh route. Public tools carry `version`, the Unbrowse version that generated them (YYYY.MM.DD); among equal matches the newest comes first.",
|
|
679
628
|
"inputSchema": {
|
|
680
629
|
"type": "object",
|
|
681
630
|
"properties": {
|
|
682
631
|
"query": {
|
|
683
632
|
"type": "string"
|
|
633
|
+
},
|
|
634
|
+
"minVersion": {
|
|
635
|
+
"type": "string",
|
|
636
|
+
"description": "Leave out public tools generated by an Unbrowse version older than this, e.g. \"2026.09.28\"."
|
|
684
637
|
}
|
|
685
638
|
},
|
|
686
639
|
"required": [
|
|
@@ -689,109 +642,13 @@
|
|
|
689
642
|
}
|
|
690
643
|
},
|
|
691
644
|
{
|
|
692
|
-
"name": "
|
|
693
|
-
"description": "
|
|
694
|
-
"inputSchema": {
|
|
695
|
-
"type": "object",
|
|
696
|
-
"properties": {
|
|
697
|
-
"source": {
|
|
698
|
-
"type": "string",
|
|
699
|
-
"enum": [
|
|
700
|
-
"visitor",
|
|
701
|
-
"agent"
|
|
702
|
-
],
|
|
703
|
-
"description": "visitor: people on unbrowse.ai (admins only); agent: cloud-browser sessions"
|
|
704
|
-
},
|
|
705
|
-
"site": {
|
|
706
|
-
"type": "string",
|
|
707
|
-
"description": "Only sessions on this site, e.g. unbrowse.ai"
|
|
708
|
-
},
|
|
709
|
-
"outcome": {
|
|
710
|
-
"type": "string",
|
|
711
|
-
"enum": [
|
|
712
|
-
"converted",
|
|
713
|
-
"signed_up",
|
|
714
|
-
"abandoned",
|
|
715
|
-
"error",
|
|
716
|
-
"completed",
|
|
717
|
-
"learned",
|
|
718
|
-
"failed"
|
|
719
|
-
]
|
|
720
|
-
},
|
|
721
|
-
"hasError": {
|
|
722
|
-
"type": "boolean",
|
|
723
|
-
"description": "Only sessions with a page error or a failed request"
|
|
724
|
-
},
|
|
725
|
-
"tag": {
|
|
726
|
-
"type": "string"
|
|
727
|
-
},
|
|
728
|
-
"from": {
|
|
729
|
-
"type": "number",
|
|
730
|
-
"description": "Sessions started at or after this time (epoch ms)"
|
|
731
|
-
},
|
|
732
|
-
"to": {
|
|
733
|
-
"type": "number",
|
|
734
|
-
"description": "Sessions started before this time (epoch ms)"
|
|
735
|
-
},
|
|
736
|
-
"limit": {
|
|
737
|
-
"type": "number",
|
|
738
|
-
"description": "At most this many (default 20, max 100)"
|
|
739
|
-
}
|
|
740
|
-
},
|
|
741
|
-
"additionalProperties": false
|
|
742
|
-
}
|
|
743
|
-
},
|
|
744
|
-
{
|
|
745
|
-
"name": "unbrowse.replay.search",
|
|
746
|
-
"description": "Search what happened in recorded sessions, in plain words (\"pricing page then left\", \"captcha\", \"checkout error\"). Returns the matching moments: session, time into it, a snippet and a link that opens the replay there. Visitor sessions (people on unbrowse.ai) are for unbrowse.ai admins only; agent sessions are your workspace's own. Your own cloud-browser sessions (unbrowse.browse.open … finish) become replays too, with sid \"a_<browse session id>\".",
|
|
645
|
+
"name": "search",
|
|
646
|
+
"description": "Search Unbrowse for the website tools and pages that answer a query. Returns {results: [{id, title, url}]}; read one with fetch. A page URL in the query comes back as a result too. To run a tool with inputs, use unbrowse_run.",
|
|
747
647
|
"inputSchema": {
|
|
748
648
|
"type": "object",
|
|
749
649
|
"properties": {
|
|
750
650
|
"query": {
|
|
751
651
|
"type": "string"
|
|
752
|
-
},
|
|
753
|
-
"source": {
|
|
754
|
-
"type": "string",
|
|
755
|
-
"enum": [
|
|
756
|
-
"visitor",
|
|
757
|
-
"agent"
|
|
758
|
-
],
|
|
759
|
-
"description": "visitor: people on unbrowse.ai (admins only); agent: cloud-browser sessions"
|
|
760
|
-
},
|
|
761
|
-
"site": {
|
|
762
|
-
"type": "string",
|
|
763
|
-
"description": "Only sessions on this site, e.g. unbrowse.ai"
|
|
764
|
-
},
|
|
765
|
-
"outcome": {
|
|
766
|
-
"type": "string",
|
|
767
|
-
"enum": [
|
|
768
|
-
"converted",
|
|
769
|
-
"signed_up",
|
|
770
|
-
"abandoned",
|
|
771
|
-
"error",
|
|
772
|
-
"completed",
|
|
773
|
-
"learned",
|
|
774
|
-
"failed"
|
|
775
|
-
]
|
|
776
|
-
},
|
|
777
|
-
"hasError": {
|
|
778
|
-
"type": "boolean",
|
|
779
|
-
"description": "Only sessions with a page error or a failed request"
|
|
780
|
-
},
|
|
781
|
-
"tag": {
|
|
782
|
-
"type": "string"
|
|
783
|
-
},
|
|
784
|
-
"from": {
|
|
785
|
-
"type": "number",
|
|
786
|
-
"description": "Sessions started at or after this time (epoch ms)"
|
|
787
|
-
},
|
|
788
|
-
"to": {
|
|
789
|
-
"type": "number",
|
|
790
|
-
"description": "Sessions started before this time (epoch ms)"
|
|
791
|
-
},
|
|
792
|
-
"limit": {
|
|
793
|
-
"type": "number",
|
|
794
|
-
"description": "At most this many (default 20, max 100)"
|
|
795
652
|
}
|
|
796
653
|
},
|
|
797
654
|
"required": [
|
|
@@ -801,121 +658,17 @@
|
|
|
801
658
|
}
|
|
802
659
|
},
|
|
803
660
|
{
|
|
804
|
-
"name": "
|
|
805
|
-
"description": "
|
|
806
|
-
"inputSchema": {
|
|
807
|
-
"type": "object",
|
|
808
|
-
"properties": {
|
|
809
|
-
"sid": {
|
|
810
|
-
"type": "string",
|
|
811
|
-
"description": "The session id from list or search"
|
|
812
|
-
}
|
|
813
|
-
},
|
|
814
|
-
"required": [
|
|
815
|
-
"sid"
|
|
816
|
-
],
|
|
817
|
-
"additionalProperties": false
|
|
818
|
-
}
|
|
819
|
-
},
|
|
820
|
-
{
|
|
821
|
-
"name": "unbrowse.replay.timeline",
|
|
822
|
-
"description": "A session as text, one line per thing that happened (pages, clicks, typing with values masked, scrolls, errors, rage and dead clicks, agent steps), each with its time into the session. Narrow long sessions with from/to (ms into the session) or kinds. Visitor sessions (people on unbrowse.ai) are for unbrowse.ai admins only; agent sessions are your workspace's own. Your own cloud-browser sessions (unbrowse.browse.open … finish) become replays too, with sid \"a_<browse session id>\".",
|
|
823
|
-
"inputSchema": {
|
|
824
|
-
"type": "object",
|
|
825
|
-
"properties": {
|
|
826
|
-
"sid": {
|
|
827
|
-
"type": "string"
|
|
828
|
-
},
|
|
829
|
-
"from": {
|
|
830
|
-
"type": "number",
|
|
831
|
-
"description": "ms into the session"
|
|
832
|
-
},
|
|
833
|
-
"to": {
|
|
834
|
-
"type": "number",
|
|
835
|
-
"description": "ms into the session"
|
|
836
|
-
},
|
|
837
|
-
"kinds": {
|
|
838
|
-
"type": "array",
|
|
839
|
-
"items": {
|
|
840
|
-
"type": "string",
|
|
841
|
-
"enum": [
|
|
842
|
-
"nav",
|
|
843
|
-
"click",
|
|
844
|
-
"input",
|
|
845
|
-
"scroll",
|
|
846
|
-
"error",
|
|
847
|
-
"console",
|
|
848
|
-
"network",
|
|
849
|
-
"rage",
|
|
850
|
-
"dead",
|
|
851
|
-
"agent",
|
|
852
|
-
"shot",
|
|
853
|
-
"end"
|
|
854
|
-
]
|
|
855
|
-
}
|
|
856
|
-
}
|
|
857
|
-
},
|
|
858
|
-
"required": [
|
|
859
|
-
"sid"
|
|
860
|
-
],
|
|
861
|
-
"additionalProperties": false
|
|
862
|
-
}
|
|
863
|
-
},
|
|
864
|
-
{
|
|
865
|
-
"name": "unbrowse.replay.ask",
|
|
866
|
-
"description": "Ask a question across recorded sessions (\"why do people leave the pricing page?\", \"why did my learns on ikea fail?\"). Answers only from what the sessions show, with citations: each names a session and a moment, with a link that opens the replay there. Visitor sessions (people on unbrowse.ai) are for unbrowse.ai admins only; agent sessions are your workspace's own. Your own cloud-browser sessions (unbrowse.browse.open … finish) become replays too, with sid \"a_<browse session id>\".",
|
|
661
|
+
"name": "fetch",
|
|
662
|
+
"description": "Read one search result in full by its id. A page URL comes back as the page's main text (markdown, read over HTTP or rendered when the site needs a browser); a tool id comes back as what the tool does, its inputs and the unbrowse_run call that runs it.",
|
|
867
663
|
"inputSchema": {
|
|
868
664
|
"type": "object",
|
|
869
665
|
"properties": {
|
|
870
|
-
"
|
|
871
|
-
"type": "string"
|
|
872
|
-
},
|
|
873
|
-
"source": {
|
|
874
|
-
"type": "string",
|
|
875
|
-
"enum": [
|
|
876
|
-
"visitor",
|
|
877
|
-
"agent"
|
|
878
|
-
],
|
|
879
|
-
"description": "visitor: people on unbrowse.ai (admins only); agent: cloud-browser sessions"
|
|
880
|
-
},
|
|
881
|
-
"site": {
|
|
882
|
-
"type": "string",
|
|
883
|
-
"description": "Only sessions on this site, e.g. unbrowse.ai"
|
|
884
|
-
},
|
|
885
|
-
"outcome": {
|
|
886
|
-
"type": "string",
|
|
887
|
-
"enum": [
|
|
888
|
-
"converted",
|
|
889
|
-
"signed_up",
|
|
890
|
-
"abandoned",
|
|
891
|
-
"error",
|
|
892
|
-
"completed",
|
|
893
|
-
"learned",
|
|
894
|
-
"failed"
|
|
895
|
-
]
|
|
896
|
-
},
|
|
897
|
-
"hasError": {
|
|
898
|
-
"type": "boolean",
|
|
899
|
-
"description": "Only sessions with a page error or a failed request"
|
|
900
|
-
},
|
|
901
|
-
"tag": {
|
|
666
|
+
"id": {
|
|
902
667
|
"type": "string"
|
|
903
|
-
},
|
|
904
|
-
"from": {
|
|
905
|
-
"type": "number",
|
|
906
|
-
"description": "Sessions started at or after this time (epoch ms)"
|
|
907
|
-
},
|
|
908
|
-
"to": {
|
|
909
|
-
"type": "number",
|
|
910
|
-
"description": "Sessions started before this time (epoch ms)"
|
|
911
|
-
},
|
|
912
|
-
"limit": {
|
|
913
|
-
"type": "number",
|
|
914
|
-
"description": "At most this many (default 20, max 100)"
|
|
915
668
|
}
|
|
916
669
|
},
|
|
917
670
|
"required": [
|
|
918
|
-
"
|
|
671
|
+
"id"
|
|
919
672
|
],
|
|
920
673
|
"additionalProperties": false
|
|
921
674
|
}
|