opera-browser-cli 0.1.27

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.
@@ -0,0 +1,379 @@
1
+ /**
2
+ * Persistent MCP bridge server for opera-browser-cli.
3
+ *
4
+ * Spawns opera-devtools-mcp as a child process and maintains a single
5
+ * persistent MCP session. Exposes a simple HTTP API:
6
+ * POST /call { name, args } → { result }
7
+ * GET /tools → [{ name, description }]
8
+ * GET /health → { status: "ok" }
9
+ *
10
+ * Writes a PID file to ~/.opera-browser-cli/bridge.pid on startup.
11
+ */
12
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
13
+ import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
14
+ import { LoggingMessageNotificationSchema } from "@modelcontextprotocol/sdk/types.js";
15
+ import { createServer, } from "node:http";
16
+ import { existsSync, mkdirSync, unlinkSync, writeFileSync } from "node:fs";
17
+ import { join, resolve } from "node:path";
18
+ import { homedir } from "node:os";
19
+ const DEFAULT_PORT = Number.parseInt(process.env.OPERA_CLI_PORT ?? "9224", 10);
20
+ const STATE_DIR = join(homedir(), ".opera-browser-cli");
21
+ const PID_FILE = join(STATE_DIR, "bridge.pid");
22
+ const OPERA_AI_TIMEOUT = 300_000; // 5 minutes
23
+ const OPERA_AI_TOOLS = new Set([
24
+ "opera_chat",
25
+ "opera_do",
26
+ "opera_research",
27
+ "opera_make",
28
+ ]);
29
+ export async function isBridgeClientConnected(client) {
30
+ try {
31
+ await client.listTools();
32
+ return true;
33
+ }
34
+ catch {
35
+ return false;
36
+ }
37
+ }
38
+ function writePidFile(port) {
39
+ mkdirSync(STATE_DIR, { recursive: true });
40
+ writeFileSync(PID_FILE, JSON.stringify({ pid: process.pid, port }));
41
+ }
42
+ function removePidFile() {
43
+ try {
44
+ unlinkSync(PID_FILE);
45
+ }
46
+ catch {
47
+ // Already gone — fine
48
+ }
49
+ }
50
+ export function getErrorMessage(error) {
51
+ return error instanceof Error ? error.message : String(error);
52
+ }
53
+ export function extractToolText(content) {
54
+ return content
55
+ .filter((block) => block.type === "text" && typeof block.text === "string")
56
+ .map((block) => block.text)
57
+ .join("\n");
58
+ }
59
+ function getToolContent(result) {
60
+ if (!result ||
61
+ typeof result !== "object" ||
62
+ !("content" in result) ||
63
+ !Array.isArray(result.content)) {
64
+ return [];
65
+ }
66
+ return result.content;
67
+ }
68
+ export function parseBridgeCallPayload(body) {
69
+ let payload;
70
+ try {
71
+ payload = JSON.parse(body);
72
+ }
73
+ catch {
74
+ throw new Error("Invalid bridge request payload");
75
+ }
76
+ if (typeof payload.name !== "string" || payload.name.length === 0) {
77
+ throw new Error("Invalid bridge request payload");
78
+ }
79
+ if (payload.args === undefined) {
80
+ return { name: payload.name, args: {} };
81
+ }
82
+ if (payload.args === null ||
83
+ typeof payload.args !== "object" ||
84
+ Array.isArray(payload.args)) {
85
+ throw new Error("Invalid bridge request payload");
86
+ }
87
+ return { name: payload.name, args: payload.args };
88
+ }
89
+ export function resolveBridgeScript(importMetaDir) {
90
+ const builtScript = resolve(importMetaDir, "../bin/opera-browser-cli-bridge.js");
91
+ const sourceScript = builtScript.replace(/\.js$/, ".ts");
92
+ return existsSync(sourceScript) ? sourceScript : builtScript;
93
+ }
94
+ async function readRequestBody(req) {
95
+ let body = "";
96
+ for await (const chunk of req) {
97
+ body += typeof chunk === "string" ? chunk : chunk.toString("utf-8");
98
+ }
99
+ return body;
100
+ }
101
+ function writeJson(res, statusCode, payload) {
102
+ res.statusCode = statusCode;
103
+ res.end(JSON.stringify(payload));
104
+ }
105
+ async function handleToolsRequest(client, res) {
106
+ const result = await client.listTools();
107
+ writeJson(res, 200, result.tools.map((tool) => ({
108
+ name: tool.name,
109
+ description: tool.description,
110
+ })));
111
+ }
112
+ async function handleCallRequest(client, req, res, captureNextId) {
113
+ const body = await readRequestBody(req);
114
+ const payload = parseBridgeCallPayload(body);
115
+ const isStreamable = OPERA_AI_TOOLS.has(payload.name);
116
+ let mcpRequestId;
117
+ if (isStreamable && captureNextId) {
118
+ const controller = new AbortController();
119
+ let timer = setTimeout(() => controller.abort(), OPERA_AI_TIMEOUT);
120
+ // Register the capture BEFORE calling callTool so the synchronous
121
+ // transport.send fires into our queue before we await the result.
122
+ const idCapture = captureNextId();
123
+ const callPromise = client.callTool({ name: payload.name, arguments: payload.args }, undefined, { signal: controller.signal, timeout: OPERA_AI_TIMEOUT * 2 });
124
+ // Suppress unhandled-rejection if idCapture rejects (e.g. transport closes
125
+ // before transport.send fires in a future SDK version). The rejection will
126
+ // propagate through the `await idCapture` below and close the response.
127
+ callPromise.catch(() => { });
128
+ try {
129
+ mcpRequestId = await idCapture; // resolves as soon as transport.send fires
130
+ }
131
+ catch (error) {
132
+ clearTimeout(timer);
133
+ throw error;
134
+ }
135
+ requestLoggers.set(mcpRequestId, (chunk) => {
136
+ clearTimeout(timer);
137
+ timer = setTimeout(() => controller.abort(), OPERA_AI_TIMEOUT);
138
+ res.write(JSON.stringify({ log: chunk }) + "\n");
139
+ });
140
+ try {
141
+ const result = await callPromise;
142
+ const text = extractToolText(getToolContent(result));
143
+ res.statusCode = 200;
144
+ res.end(JSON.stringify({ result: text }));
145
+ }
146
+ catch (error) {
147
+ res.statusCode = 500;
148
+ res.end(JSON.stringify({ error: getErrorMessage(error) }));
149
+ }
150
+ finally {
151
+ clearTimeout(timer);
152
+ requestLoggers.delete(mcpRequestId);
153
+ }
154
+ return;
155
+ }
156
+ // Non-streaming path (unchanged).
157
+ try {
158
+ const result = await client.callTool({ name: payload.name, arguments: payload.args }, undefined);
159
+ const text = extractToolText(getToolContent(result));
160
+ res.statusCode = 200;
161
+ res.end(JSON.stringify({ result: text }));
162
+ }
163
+ catch (error) {
164
+ res.statusCode = 500;
165
+ res.end(JSON.stringify({ error: getErrorMessage(error) }));
166
+ }
167
+ }
168
+ export async function handleBridgeRequest(client, req, res, captureNextId) {
169
+ res.setHeader("Content-Type", "application/json");
170
+ if (req.method === "GET" && req.url === "/health") {
171
+ if (await isBridgeClientConnected(client)) {
172
+ writeJson(res, 200, { status: "ok" });
173
+ }
174
+ else {
175
+ writeJson(res, 503, { error: "Not connected" });
176
+ }
177
+ return;
178
+ }
179
+ try {
180
+ if (req.method === "GET" && req.url === "/tools") {
181
+ await handleToolsRequest(client, res);
182
+ return;
183
+ }
184
+ if (req.method === "POST" && req.url === "/call") {
185
+ await handleCallRequest(client, req, res, captureNextId);
186
+ return;
187
+ }
188
+ }
189
+ catch (error) {
190
+ writeJson(res, 500, { error: getErrorMessage(error) });
191
+ return;
192
+ }
193
+ writeJson(res, 404, { error: "not found" });
194
+ }
195
+ export function createBridgeServer(client, captureNextId) {
196
+ return createServer((req, res) => {
197
+ void handleBridgeRequest(client, req, res, captureNextId);
198
+ });
199
+ }
200
+ function logBridgeMessage(message) {
201
+ process.stderr.write(`[opera-browser-cli] ${message}\n`);
202
+ }
203
+ function writeReadySignal() {
204
+ process.stdout.write("READY\n");
205
+ }
206
+ export function buildTransportArgs() {
207
+ const args = [];
208
+ const browserUrl = process.env.OPERA_CLI_BROWSER_URL;
209
+ const userDataDir = process.env.OPERA_CLI_USER_DATA_DIR;
210
+ const executablePath = process.env.OPERA_CLI_EXECUTABLE_PATH;
211
+ if (browserUrl) {
212
+ // Connect to an existing browser instance — skip --isolated and --headless
213
+ // since the user manages the browser lifecycle externally.
214
+ args.push(`--browserUrl=${browserUrl}`);
215
+ }
216
+ else {
217
+ if (executablePath) {
218
+ args.push(`--executablePath=${executablePath}`);
219
+ }
220
+ if (userDataDir) {
221
+ // Persistent profile — skip --isolated so the profile is preserved.
222
+ args.push(`--userDataDir=${userDataDir}`);
223
+ // Puppeteer adds --use-mock-keychain and --password-store=basic by default,
224
+ // which prevent the browser from decrypting cookies stored with the real
225
+ // macOS Keychain. Drop them so a persistent profile stays logged in.
226
+ args.push("--ignore-default-chrome-arg=--use-mock-keychain");
227
+ args.push("--ignore-default-chrome-arg=--password-store=basic");
228
+ args.push("--ignore-default-chrome-arg=--disable-extensions");
229
+ args.push("--ignore-default-chrome-arg=--disable-component-extensions-with-background-pages");
230
+ args.push("--show-component-extension-options");
231
+ }
232
+ else {
233
+ args.push("--isolated");
234
+ }
235
+ if (process.env.OPERA_CLI_HEADED !== "1") {
236
+ args.push("--headless");
237
+ }
238
+ }
239
+ const extraChromeArgs = process.env.OPERA_CLI_CHROME_ARGS;
240
+ if (extraChromeArgs) {
241
+ for (const arg of extraChromeArgs.trim().split(/\s+/)) {
242
+ args.push(`--chrome-arg=${arg}`);
243
+ }
244
+ }
245
+ return args;
246
+ }
247
+ function createTransport() {
248
+ const bin = process.env.OPERA_CLI_MCP_BIN ?? "opera-devtools-mcp";
249
+ const args = buildTransportArgs();
250
+ if (bin.endsWith(".js")) {
251
+ return new StdioClientTransport({
252
+ command: "node",
253
+ args: [bin, ...args],
254
+ });
255
+ }
256
+ return new StdioClientTransport({ command: bin, args });
257
+ }
258
+ const requestLoggers = new Map();
259
+ /**
260
+ * Wraps transport.send to intercept outgoing JSON-RPC request IDs so each
261
+ * streaming callTool call can register its own log writer before the first
262
+ * notification arrives.
263
+ *
264
+ * INVARIANT: The MCP SDK's Client.request() calls transport.send() synchronously
265
+ * inside its Promise constructor (see @modelcontextprotocol/sdk shared/protocol.js).
266
+ * This means callTool() triggers transport.send before yielding, allowing us to
267
+ * capture the ID before any concurrent handler can interleave.
268
+ * Verify this invariant when upgrading @modelcontextprotocol/sdk.
269
+ */
270
+ export function wrapTransportForIdCapture(transport) {
271
+ const queue = [];
272
+ // Cast origSend to the full Transport.send signature so we can forward the
273
+ // options argument even though StdioClientTransport currently ignores it.
274
+ const origSend = transport.send.bind(transport);
275
+ // Forward send — preserve the options parameter so future SDK versions that
276
+ // use TransportSendOptions over stdio are not silently broken.
277
+ transport.send = (async (msg, options) => {
278
+ if ("id" in msg && "method" in msg && queue.length > 0) {
279
+ queue.shift().resolve(String(msg.id));
280
+ }
281
+ return origSend(msg, options);
282
+ });
283
+ // Latent safety net: if a future SDK version makes transport.send async,
284
+ // reject any queued capture so callers do not hang. In the current SDK the
285
+ // queue is always empty by the time onclose can fire (transport.send is
286
+ // called synchronously before the first await in Client.request). The primary
287
+ // protection against a dead-transport hang is the runBridge onclose handler
288
+ // that calls shutdown(); this drain is a belt-and-suspenders fallback.
289
+ const origOnClose = transport.onclose;
290
+ transport.onclose = () => {
291
+ const err = new Error("MCP transport disconnected");
292
+ while (queue.length > 0)
293
+ queue.shift().reject(err);
294
+ origOnClose?.();
295
+ };
296
+ return () => new Promise((resolve, reject) => queue.push({ resolve, reject }));
297
+ }
298
+ function createBridgeClient() {
299
+ const client = new Client({ name: "opera-browser-cli-bridge", version: "1.0.0" });
300
+ client.setNotificationHandler(LoggingMessageNotificationSchema, (notification) => {
301
+ // opera-devtools-mcp sets `logger` to String(extra.requestId) so the bridge
302
+ // can route the chunk to the correct HTTP response. `data` stays a plain
303
+ // string so non-bridge MCP hosts (Claude Desktop, VS Code, etc.) render it
304
+ // as readable text without any change.
305
+ const { data, logger } = notification.params;
306
+ if (logger && requestLoggers.has(logger)) {
307
+ const chunk = typeof data === "string" ? data : JSON.stringify(data);
308
+ requestLoggers.get(logger)(chunk);
309
+ }
310
+ // No matching logger: notification is from a non-Opera tool or an older
311
+ // server version — silently ignore.
312
+ });
313
+ return client;
314
+ }
315
+ async function closeServer(server) {
316
+ await new Promise((resolve, reject) => {
317
+ server.close((error) => {
318
+ if (error) {
319
+ reject(error);
320
+ }
321
+ else {
322
+ resolve();
323
+ }
324
+ });
325
+ });
326
+ }
327
+ export async function runBridge(port = DEFAULT_PORT) {
328
+ const transport = createTransport();
329
+ const captureNextId = wrapTransportForIdCapture(transport);
330
+ const client = createBridgeClient();
331
+ await client.connect(transport);
332
+ logBridgeMessage("Connected to opera-devtools-mcp");
333
+ const server = createBridgeServer(client, captureNextId);
334
+ server.listen(port, "127.0.0.1", () => {
335
+ writePidFile(port);
336
+ logBridgeMessage(`Listening on http://127.0.0.1:${port}`);
337
+ writeReadySignal();
338
+ });
339
+ let shuttingDown = false;
340
+ const shutdown = async () => {
341
+ if (shuttingDown)
342
+ return;
343
+ shuttingDown = true;
344
+ removePidFile();
345
+ await closeServer(server);
346
+ await client.close();
347
+ await transport.close();
348
+ process.exit(0);
349
+ };
350
+ // If opera-devtools-mcp exits (transport closes), shut the bridge down too.
351
+ // Without this, the bridge would keep accepting HTTP requests and hang on any
352
+ // streaming call: captureNextId() queues a resolver, callTool() early-rejects
353
+ // without calling transport.send, and `await idCapture` never resolves.
354
+ // Chain after the drain handler already installed by wrapTransportForIdCapture.
355
+ const afterDrain = transport.onclose;
356
+ transport.onclose = () => {
357
+ afterDrain?.();
358
+ void shutdown();
359
+ };
360
+ // Kill our entire process group on exit so opera-devtools-mcp children
361
+ // don't survive as orphans. The bridge is spawned with detached:true,
362
+ // making it a process group leader — all children share our PGID.
363
+ process.on("exit", () => {
364
+ removePidFile();
365
+ try {
366
+ process.kill(-process.pid, "SIGTERM");
367
+ }
368
+ catch {
369
+ // Already dead or not a group leader
370
+ }
371
+ });
372
+ process.on("SIGTERM", () => {
373
+ void shutdown();
374
+ });
375
+ process.on("SIGINT", () => {
376
+ void shutdown();
377
+ });
378
+ }
379
+ //# sourceMappingURL=bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bridge.js","sourceRoot":"","sources":["../../src/bridge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,74 @@
1
+ type CliStdout = Pick<NodeJS.WriteStream, "write">;
2
+ export type MainOptions = {
3
+ argv?: string[];
4
+ stdout?: CliStdout;
5
+ };
6
+ export declare const TOP_HELP = "usage: opera-browser-cli [command] [args] [flags]\ncommands[41]:\n open <url>, snapshot, screenshot <path>, click @<uid>, fill @<uid> <text>,\n type <text>, press <key>, scroll <dir>, back, wait <ms|text>, eval <js>,\n run,\n hover @<uid>, drag @<from> @<to>, fillform @<uid>=<val>..., dialog <action>,\n upload @<uid> <path>, pages, newpage <url>, selectpage <id>, closepage <id>,\n resize <w> <h>, emulate, console, console-get <id>, network,\n network-get [id], lighthouse, perf-start, perf-stop,\n perf-insight <set> <name>, heap <path>, start, stop,\n chat <prompt>, invoke-do <prompt>, make <prompt>, research <prompt>,\n setup, logs, doctor\n\nflags[2]:\n --help, -v/-V/--version\n\nenvironment:\n OPERA_CLI_HEADED Set to 1 to run Chrome in headed (visible) mode\n OPERA_CLI_CHROME_ARGS Whitespace-separated Chrome flags forwarded to the browser\n (no shell-style quoting; flags with spaces are not supported)\n e.g. \"--enable-gpu --ignore-gpu-blocklist\"\n OPERA_CLI_PORT Bridge server port (default: 9224)\n OPERA_CLI_BROWSER_URL Connect to an existing Chrome instance instead of launching one\n e.g. \"http://127.0.0.1:9222\"\n OPERA_CLI_USER_DATA_DIR Persistent Chrome profile directory (skips --isolated mode)\n e.g. \"/path/to/.chrome-profile\"\n OPERA_CLI_EXECUTABLE_PATH Path to a custom browser binary (e.g. Opera Neon)\n OPERA_CLI_DISABLE_HOOKS Set to 1 to skip auto-installing session hooks\n\n Environment variables can also be set in ~/.opera-browser-cli/config (KEY=VALUE, one per line).\n Run `opera-browser-cli setup` to configure interactively.\n\nopera ai:\n chat, invoke-do, make, and research require Opera Neon with an active sign-in.\n Run `opera-browser-cli setup` to configure the Opera Neon executable path, or set\n OPERA_CLI_EXECUTABLE_PATH=\"/Applications/Opera Neon Developer.app/Contents/MacOS/Opera\".\n\ngpu:\n Headless Chrome cannot access hardware GPU on most Linux systems.\n For GPU-accelerated WebGL, use headed mode with GPU flags:\n OPERA_CLI_HEADED=1\n OPERA_CLI_CHROME_ARGS=\"--enable-gpu --ignore-gpu-blocklist\"\n For WebGPU, Vulkan must also be enabled (required for the Dawn backend):\n OPERA_CLI_CHROME_ARGS=\"--enable-gpu --ignore-gpu-blocklist --enable-unsafe-webgpu --enable-features=Vulkan\"\n\ntips:\n Pipe output through grep/head to extract specific data from large pages.\n";
7
+ export declare function getCommandHelp(command: string): string | null;
8
+ export interface ScreenshotArgs {
9
+ filePath: string | null;
10
+ uid: string | undefined;
11
+ fullPage: boolean;
12
+ format: string | undefined;
13
+ }
14
+ export declare function parseScreenshotArgs(args: string[]): ScreenshotArgs;
15
+ export declare function formatScreenshotOutput(filePath: string): string;
16
+ /** Parse MCP list_pages markdown into structured data. */
17
+ export declare function parsePagesList(text: string): {
18
+ id: number;
19
+ url: string;
20
+ selected: boolean;
21
+ }[];
22
+ /** Format raw MCP text result as AXI output: labeled block + truncation + suggestions. */
23
+ export declare function formatMcpResult(label: string, text: string, suggestions: string[]): string;
24
+ export declare function parseFillFormArgs(args: string[]): {
25
+ entries: {
26
+ uid: string;
27
+ value: string;
28
+ }[];
29
+ };
30
+ export interface EmulateArgs extends Record<string, unknown> {
31
+ viewport?: string;
32
+ colorScheme?: string;
33
+ networkConditions?: string;
34
+ cpuThrottlingRate?: number;
35
+ geolocation?: string;
36
+ userAgent?: string;
37
+ }
38
+ export declare function parseEmulateArgs(args: string[]): EmulateArgs;
39
+ export declare function parseConsoleArgs(args: string[]): {
40
+ types?: string[];
41
+ pageSize?: number;
42
+ pageIdx?: number;
43
+ };
44
+ export declare function parseNetworkArgs(args: string[]): {
45
+ resourceTypes?: string[];
46
+ pageSize?: number;
47
+ pageIdx?: number;
48
+ };
49
+ export declare function parseNetworkGetArgs(args: string[]): {
50
+ reqid?: number;
51
+ responseFilePath?: string;
52
+ requestFilePath?: string;
53
+ };
54
+ export declare function parseLighthouseArgs(args: string[]): {
55
+ device?: string;
56
+ mode?: string;
57
+ outputDirPath?: string;
58
+ };
59
+ export declare function parsePerfStartArgs(args: string[]): {
60
+ reload?: boolean;
61
+ autoStop?: boolean;
62
+ filePath?: string;
63
+ };
64
+ /** Wrap plain JS expressions for MCP evaluate_script, but pass functions through unchanged. */
65
+ export declare function wrapJsExpression(js: string): string;
66
+ export declare function formatStopOutput(wasStopped: boolean): string;
67
+ declare const VALID_RESEARCH_TYPES: readonly ["local", "one-minute", "deep"];
68
+ type ResearchType = (typeof VALID_RESEARCH_TYPES)[number];
69
+ export declare function parseResearchArgs(args: string[]): {
70
+ prompt: string;
71
+ researchType?: ResearchType;
72
+ };
73
+ export declare function main(options?: MainOptions | string[]): Promise<void>;
74
+ export {};