@unbrowse/sdk 12.0.0 → 12.1.0
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 +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +84 -0
- package/dist/mcp.d.ts +60 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ TypeScript client for the Unbrowse API (`https://unbrowse.ai/api/v1`). Node 18.1
|
|
|
4
4
|
or any runtime with `fetch`. No dependencies. The `unbrowse` CLI is built on it.
|
|
5
5
|
|
|
6
6
|
```bash
|
|
7
|
-
npm install https://github.com/unbrowse-ai/unbrowse
|
|
7
|
+
npm install https://github.com/unbrowse-ai/unbrowse/releases/download/v12.0.1/unbrowse-sdk-12.0.1.tgz
|
|
8
8
|
```
|
|
9
9
|
|
|
10
10
|
```ts
|
package/dist/index.d.ts
CHANGED
|
@@ -2,3 +2,5 @@ export { DEFAULT_BASE_URL, Unbrowse, UnbrowseError, normalizeHost } from "./clie
|
|
|
2
2
|
export type { LoginView, UnbrowseOptions } from "./client.ts";
|
|
3
3
|
export type * from "./types.ts";
|
|
4
4
|
export { cursorInstallLink, mcpCommands, vscodeInstallLink } from "./mcp-install.ts";
|
|
5
|
+
export { DEFAULT_MCP_URL, MCP_PROTOCOL_VERSION, UnbrowseMcp, parseRpcBody, resultText } from "./mcp.ts";
|
|
6
|
+
export type { McpContent, McpOptions, McpTool, McpToolResult } from "./mcp.ts";
|
package/dist/index.js
CHANGED
|
@@ -175,12 +175,96 @@ function mcpCommands(url) {
|
|
|
175
175
|
json: JSON.stringify({ mcpServers: { unbrowse: { url } } }, null, 2)
|
|
176
176
|
};
|
|
177
177
|
}
|
|
178
|
+
// src/mcp.ts
|
|
179
|
+
var DEFAULT_MCP_URL = "https://unbrowse.ai/mcp";
|
|
180
|
+
var MCP_PROTOCOL_VERSION = "2025-11-25";
|
|
181
|
+
var env2 = (name) => (typeof process !== "undefined" ? process.env?.[name] : undefined) || undefined;
|
|
182
|
+
function parseRpcBody(text) {
|
|
183
|
+
const trimmed = text.trim();
|
|
184
|
+
if (trimmed.startsWith("{"))
|
|
185
|
+
return JSON.parse(trimmed);
|
|
186
|
+
const events = trimmed.split(/\n\n+/).flatMap((block) => {
|
|
187
|
+
const data = block.split(`
|
|
188
|
+
`).filter((l) => l.startsWith("data:")).map((l) => l.slice(5).trimStart()).join(`
|
|
189
|
+
`);
|
|
190
|
+
return data ? [data] : [];
|
|
191
|
+
});
|
|
192
|
+
if (!events.length)
|
|
193
|
+
throw new UnbrowseError("Empty MCP response", 502, "mcp_empty");
|
|
194
|
+
return JSON.parse(events[events.length - 1]);
|
|
195
|
+
}
|
|
196
|
+
function resultText(result) {
|
|
197
|
+
const text = result.content?.filter((c) => c.type === "text" && typeof c.text === "string").map((c) => c.text).join(`
|
|
198
|
+
`);
|
|
199
|
+
return text || (result.structuredContent === undefined ? "" : JSON.stringify(result.structuredContent));
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
class UnbrowseMcp {
|
|
203
|
+
url;
|
|
204
|
+
apiKey;
|
|
205
|
+
endUser;
|
|
206
|
+
client;
|
|
207
|
+
fetchImpl;
|
|
208
|
+
nextId = 1;
|
|
209
|
+
constructor(opts = {}) {
|
|
210
|
+
this.url = (opts.url ?? env2("UNBROWSE_MCP_URL") ?? DEFAULT_MCP_URL).replace(/\/+$/, "");
|
|
211
|
+
this.apiKey = opts.apiKey ?? env2("UNBROWSE_API_KEY");
|
|
212
|
+
this.endUser = opts.endUser ?? env2("UNBROWSE_END_USER");
|
|
213
|
+
this.client = opts.client ?? "sdk";
|
|
214
|
+
this.fetchImpl = opts.fetch ?? ((...a) => globalThis.fetch(...a));
|
|
215
|
+
}
|
|
216
|
+
async rpc(method, params) {
|
|
217
|
+
const res = await this.fetchImpl(this.url, {
|
|
218
|
+
method: "POST",
|
|
219
|
+
headers: {
|
|
220
|
+
...this.apiKey ? { authorization: `Bearer ${this.apiKey}` } : {},
|
|
221
|
+
...this.endUser ? { "x-unbrowse-end-user": this.endUser } : {},
|
|
222
|
+
"content-type": "application/json",
|
|
223
|
+
accept: "application/json, text/event-stream",
|
|
224
|
+
"mcp-protocol-version": MCP_PROTOCOL_VERSION,
|
|
225
|
+
"user-agent": `unbrowse-${this.client}`
|
|
226
|
+
},
|
|
227
|
+
body: JSON.stringify({ jsonrpc: "2.0", id: this.nextId++, method, ...params ? { params } : {} })
|
|
228
|
+
});
|
|
229
|
+
const text = await res.text();
|
|
230
|
+
if (!res.ok) {
|
|
231
|
+
let body = {};
|
|
232
|
+
try {
|
|
233
|
+
body = JSON.parse(text);
|
|
234
|
+
} catch {}
|
|
235
|
+
const err = typeof body.error === "object" ? body.error : undefined;
|
|
236
|
+
throw new UnbrowseError(err?.message ?? body.error_description ?? (res.statusText || `HTTP ${res.status}`), res.status, err?.code ?? (typeof body.error === "string" ? body.error : "http_error"), body);
|
|
237
|
+
}
|
|
238
|
+
const msg = parseRpcBody(text);
|
|
239
|
+
if (msg.error)
|
|
240
|
+
throw new UnbrowseError(msg.error.message, 200, msg.error.data?.code ?? `rpc_${msg.error.code}`, msg.error);
|
|
241
|
+
return msg.result;
|
|
242
|
+
}
|
|
243
|
+
async listTools() {
|
|
244
|
+
const tools = [];
|
|
245
|
+
let cursor;
|
|
246
|
+
do {
|
|
247
|
+
const page = await this.rpc("tools/list", cursor ? { cursor } : undefined);
|
|
248
|
+
tools.push(...page.tools);
|
|
249
|
+
cursor = page.nextCursor;
|
|
250
|
+
} while (cursor);
|
|
251
|
+
return tools;
|
|
252
|
+
}
|
|
253
|
+
callTool(name, args = {}) {
|
|
254
|
+
return this.rpc("tools/call", { name, arguments: args });
|
|
255
|
+
}
|
|
256
|
+
}
|
|
178
257
|
export {
|
|
179
258
|
DEFAULT_BASE_URL,
|
|
259
|
+
DEFAULT_MCP_URL,
|
|
260
|
+
MCP_PROTOCOL_VERSION,
|
|
180
261
|
Unbrowse,
|
|
181
262
|
UnbrowseError,
|
|
263
|
+
UnbrowseMcp,
|
|
182
264
|
cursorInstallLink,
|
|
183
265
|
mcpCommands,
|
|
184
266
|
normalizeHost,
|
|
267
|
+
parseRpcBody,
|
|
268
|
+
resultText,
|
|
185
269
|
vscodeInstallLink
|
|
186
270
|
};
|
package/dist/mcp.d.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { Json } from "./types.ts";
|
|
2
|
+
export declare const DEFAULT_MCP_URL = "https://unbrowse.ai/mcp";
|
|
3
|
+
/** Sent as `Mcp-Protocol-Version`. The hosted server refuses 2025-06-18 on its streaming path. */
|
|
4
|
+
export declare const MCP_PROTOCOL_VERSION = "2025-11-25";
|
|
5
|
+
export type McpOptions = {
|
|
6
|
+
/** API key (`ub_live_…`) or OAuth access token. Defaults to `UNBROWSE_API_KEY`. */
|
|
7
|
+
apiKey?: string;
|
|
8
|
+
/** Defaults to `UNBROWSE_MCP_URL`, then https://unbrowse.ai/mcp. */
|
|
9
|
+
url?: string;
|
|
10
|
+
/** Org keys: the end user the call is for (`X-Unbrowse-End-User`). */
|
|
11
|
+
endUser?: string;
|
|
12
|
+
fetch?: typeof globalThis.fetch;
|
|
13
|
+
/** Client name sent on the wire (User-Agent suffix). */
|
|
14
|
+
client?: string;
|
|
15
|
+
};
|
|
16
|
+
export type McpTool = {
|
|
17
|
+
name: string;
|
|
18
|
+
description?: string;
|
|
19
|
+
inputSchema: {
|
|
20
|
+
type: "object";
|
|
21
|
+
properties?: Record<string, Json>;
|
|
22
|
+
required?: string[];
|
|
23
|
+
} & Record<string, unknown>;
|
|
24
|
+
};
|
|
25
|
+
export type McpContent = {
|
|
26
|
+
type: string;
|
|
27
|
+
text?: string;
|
|
28
|
+
} & Record<string, unknown>;
|
|
29
|
+
export type McpToolResult = {
|
|
30
|
+
content: McpContent[];
|
|
31
|
+
structuredContent?: Json;
|
|
32
|
+
isError?: boolean;
|
|
33
|
+
};
|
|
34
|
+
/** The JSON-RPC message in a response body: plain JSON, or the last `data:` event of an SSE stream. */
|
|
35
|
+
export declare function parseRpcBody(text: string): {
|
|
36
|
+
result?: unknown;
|
|
37
|
+
error?: {
|
|
38
|
+
code: number;
|
|
39
|
+
message: string;
|
|
40
|
+
data?: {
|
|
41
|
+
code?: string;
|
|
42
|
+
} & Record<string, unknown>;
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
/** Plain text of a tool result: its text parts, else its structured content as JSON. */
|
|
46
|
+
export declare function resultText(result: McpToolResult): string;
|
|
47
|
+
export declare class UnbrowseMcp {
|
|
48
|
+
readonly url: string;
|
|
49
|
+
private apiKey?;
|
|
50
|
+
private endUser?;
|
|
51
|
+
private client;
|
|
52
|
+
private fetchImpl;
|
|
53
|
+
private nextId;
|
|
54
|
+
constructor(opts?: McpOptions);
|
|
55
|
+
/** One JSON-RPC call. MCP errors become UnbrowseError with the server's `data.code` (e.g. `browser_capacity`). */
|
|
56
|
+
rpc<T>(method: string, params?: Record<string, unknown>): Promise<T>;
|
|
57
|
+
/** Every tool this key can call: the core tools plus the workspace's learned and indexed ones. */
|
|
58
|
+
listTools(): Promise<McpTool[]>;
|
|
59
|
+
callTool(name: string, args?: Record<string, unknown>): Promise<McpToolResult>;
|
|
60
|
+
}
|
package/package.json
CHANGED