mcp-agent-browser 0.2.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 ADDED
@@ -0,0 +1,93 @@
1
+ # mcp-agent-browser
2
+
3
+ MCP server for the `agent-browser` CLI.
4
+
5
+ ## Install
6
+
7
+ Prerequisite: install the Vercel `agent-browser` CLI.
8
+ https://github.com/vercel-labs/agent-browser
9
+
10
+ ```bash
11
+ pnpm install
12
+ pnpm build
13
+ ```
14
+
15
+ Ensure Playwright browser binaries are installed:
16
+
17
+ ```bash
18
+ agent-browser install
19
+ ```
20
+
21
+ Configuration:
22
+ - `AGENT_BROWSER_BIN`: Override the `agent-browser` CLI path.
23
+ - `AGENT_BROWSER_MCP_LOG`: Write JSONL logs for all tool calls.
24
+ - `AGENT_BROWSER_MCP_TIMEOUT_MS`: Per-command timeout in ms (default: 30000).
25
+
26
+ ## Smoke test (stdio)
27
+
28
+ ```bash
29
+ npm run build
30
+ npm run smoke
31
+ ```
32
+
33
+ The smoke test sends a correct MCP `initialize` request (including `protocolVersion`) and then lists tools.
34
+
35
+ ## Run
36
+
37
+ ```bash
38
+ node dist/mcp.js
39
+ ```
40
+
41
+ ## Run with npx
42
+
43
+ Once published:
44
+
45
+ ```bash
46
+ npx mcp-agent-browser
47
+ ```
48
+
49
+ Electron/CDP usage:
50
+
51
+ ```bash
52
+ # Start Electron with a remote debugging port (example)
53
+ ./YourElectronApp --remote-debugging-port=9222
54
+
55
+ # Connect once, then run commands
56
+ agent-browser connect 9222
57
+
58
+ # Or pass --cdp on each command
59
+ agent-browser --cdp 9222 snapshot
60
+ ```
61
+
62
+ MCP usage with Electron/CDP:
63
+
64
+ ```json
65
+ { "name": "browser.connect", "arguments": { "port": 9222, "session": "agent1" } }
66
+ { "name": "browser.snapshot", "arguments": { "session": "agent1", "cdpPort": 9222 } }
67
+ ```
68
+
69
+ MCP JSON-RPC example (stdio):
70
+
71
+ ```json
72
+ { "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": { "name": "browser.connect", "arguments": { "port": 9222, "session": "agent1" } } }
73
+ { "jsonrpc": "2.0", "id": 2, "method": "tools/call", "params": { "name": "browser.snapshot", "arguments": { "session": "agent1", "cdpPort": 9222 } } }
74
+ ```
75
+
76
+ MCP tool payloads (decoded from `content.text`):
77
+
78
+ ```json
79
+ { "ok": true, "port": 9222 }
80
+ ```
81
+
82
+ ```json
83
+ {
84
+ "ok": true,
85
+ "elements": [{ "ref": "e1", "role": "button", "name": "Submit", "selectorHint": "@e1" }],
86
+ "raw": {
87
+ "snapshot": "...",
88
+ "refs": { "e1": { "role": "button", "name": "Submit" } }
89
+ }
90
+ }
91
+ ```
92
+
93
+ See `docs/mcp-agent-browser.md` for tool definitions, error handling, and configuration.
package/dist/mcp.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=mcp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":""}
package/dist/mcp.js ADDED
@@ -0,0 +1,536 @@
1
+ import { appendFile } from 'node:fs/promises';
2
+ import { execa } from 'execa';
3
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
4
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
5
+ import { CallToolRequestSchema, CancelledNotificationSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
6
+ const agentBrowserBin = process.env.AGENT_BROWSER_BIN || 'agent-browser';
7
+ const logPath = process.env.AGENT_BROWSER_MCP_LOG;
8
+ const timeoutMs = Number(process.env.AGENT_BROWSER_MCP_TIMEOUT_MS || 30000);
9
+ const activeRequests = new Map();
10
+ function toSelector(ref) {
11
+ if (ref.startsWith('@')) {
12
+ return ref;
13
+ }
14
+ return `@${ref}`;
15
+ }
16
+ function buildGlobalArgs(input) {
17
+ const args = [];
18
+ if (input?.headed) {
19
+ args.push('--headed');
20
+ }
21
+ if (input?.session) {
22
+ args.push('--session', input.session);
23
+ }
24
+ if (input?.cdpPort !== undefined) {
25
+ args.push('--cdp', String(input.cdpPort));
26
+ }
27
+ return args;
28
+ }
29
+ async function logCall(entry) {
30
+ if (!logPath) {
31
+ return;
32
+ }
33
+ const line = `${JSON.stringify(entry)}\n`;
34
+ await appendFile(logPath, line);
35
+ }
36
+ function errorResponse(code, message, details, retryable, requestId) {
37
+ return {
38
+ ok: false,
39
+ error: {
40
+ code,
41
+ message,
42
+ details,
43
+ retryable,
44
+ requestId,
45
+ },
46
+ };
47
+ }
48
+ async function runAgentBrowser(args, globalArgs, signal) {
49
+ const finalArgs = [...buildGlobalArgs(globalArgs), ...args, '--json'];
50
+ try {
51
+ const result = await execa(agentBrowserBin, finalArgs, {
52
+ maxBuffer: 50 * 1024 * 1024,
53
+ timeout: Number.isFinite(timeoutMs) && timeoutMs > 0 ? timeoutMs : undefined,
54
+ cancelSignal: signal,
55
+ });
56
+ const output = result.stdout.trim();
57
+ if (!output) {
58
+ return { success: false, error: result.stderr.trim() || 'Empty response from agent-browser' };
59
+ }
60
+ try {
61
+ return JSON.parse(output);
62
+ }
63
+ catch (error) {
64
+ const message = error instanceof Error ? error.message : 'Unknown parse error';
65
+ return {
66
+ success: false,
67
+ error: `Failed to parse agent-browser output: ${message}`,
68
+ data: { stdout: output, stderr: result.stderr },
69
+ };
70
+ }
71
+ }
72
+ catch (error) {
73
+ const err = error;
74
+ const cancelled = err.isCanceled === true || err.name === 'AbortError' || err.code === 'ABORT_ERR';
75
+ const details = {
76
+ exitCode: err.exitCode,
77
+ stderr: err.stderr,
78
+ stdout: err.stdout,
79
+ code: err.code,
80
+ timedOut: err.timedOut ?? false,
81
+ cancelled,
82
+ };
83
+ return {
84
+ success: false,
85
+ error: cancelled
86
+ ? 'Request cancelled'
87
+ : err.shortMessage || err.message || 'Failed to run agent-browser',
88
+ data: details,
89
+ };
90
+ }
91
+ }
92
+ function parseSnapshot(data) {
93
+ const snapshotData = data;
94
+ if (!snapshotData?.refs || typeof snapshotData.refs !== 'object') {
95
+ return { error: 'Snapshot missing refs', raw: snapshotData };
96
+ }
97
+ const refs = snapshotData.refs;
98
+ const elements = Object.entries(refs).map(([ref, info]) => ({
99
+ ref,
100
+ role: info.role,
101
+ name: info.name,
102
+ selectorHint: `@${ref}`,
103
+ }));
104
+ return { elements, raw: snapshotData };
105
+ }
106
+ function shouldRetry(message, details) {
107
+ const combined = [message, details?.stderr, details?.code].filter(Boolean).join(' ').toLowerCase();
108
+ if (details?.cancelled)
109
+ return false;
110
+ if (details?.timedOut)
111
+ return true;
112
+ if (!combined)
113
+ return false;
114
+ return (combined.includes('daemon') ||
115
+ combined.includes('timed out') ||
116
+ combined.includes('timeout') ||
117
+ combined.includes('connection refused') ||
118
+ combined.includes('econnrefused'));
119
+ }
120
+ const tools = [
121
+ {
122
+ name: 'browser.connect',
123
+ description: 'Connect to a CDP endpoint on the given port.',
124
+ inputSchema: {
125
+ type: 'object',
126
+ properties: {
127
+ port: { type: 'number' },
128
+ session: { type: 'string' },
129
+ requestId: { type: 'string' },
130
+ },
131
+ required: ['port'],
132
+ additionalProperties: false,
133
+ },
134
+ },
135
+ {
136
+ name: 'browser.open',
137
+ description: 'Navigate to a URL.',
138
+ inputSchema: {
139
+ type: 'object',
140
+ properties: {
141
+ url: { type: 'string' },
142
+ headed: { type: 'boolean' },
143
+ session: { type: 'string' },
144
+ requestId: { type: 'string' },
145
+ cdpPort: { type: 'number' },
146
+ viewport: {
147
+ type: 'object',
148
+ properties: { w: { type: 'number' }, h: { type: 'number' } },
149
+ required: ['w', 'h'],
150
+ additionalProperties: false,
151
+ },
152
+ },
153
+ required: ['url'],
154
+ additionalProperties: false,
155
+ },
156
+ },
157
+ {
158
+ name: 'browser.snapshot',
159
+ description: 'Get accessibility snapshot.',
160
+ inputSchema: {
161
+ type: 'object',
162
+ properties: {
163
+ interactive: { type: 'boolean' },
164
+ selector: { type: 'string' },
165
+ depth: { type: 'number' },
166
+ compact: { type: 'boolean' },
167
+ session: { type: 'string' },
168
+ requestId: { type: 'string' },
169
+ cdpPort: { type: 'number' },
170
+ },
171
+ additionalProperties: false,
172
+ },
173
+ },
174
+ {
175
+ name: 'browser.click',
176
+ description: 'Click an element by ref.',
177
+ inputSchema: {
178
+ type: 'object',
179
+ properties: {
180
+ ref: { type: 'string' },
181
+ session: { type: 'string' },
182
+ requestId: { type: 'string' },
183
+ cdpPort: { type: 'number' },
184
+ },
185
+ required: ['ref'],
186
+ additionalProperties: false,
187
+ },
188
+ },
189
+ {
190
+ name: 'browser.fill',
191
+ description: 'Fill an input by ref.',
192
+ inputSchema: {
193
+ type: 'object',
194
+ properties: {
195
+ ref: { type: 'string' },
196
+ text: { type: 'string' },
197
+ session: { type: 'string' },
198
+ requestId: { type: 'string' },
199
+ cdpPort: { type: 'number' },
200
+ },
201
+ required: ['ref', 'text'],
202
+ additionalProperties: false,
203
+ },
204
+ },
205
+ {
206
+ name: 'browser.get',
207
+ description: 'Get text, html, value, attr, title, url, count, or box.',
208
+ inputSchema: {
209
+ type: 'object',
210
+ properties: {
211
+ what: {
212
+ type: 'string',
213
+ enum: ['text', 'html', 'value', 'attr', 'title', 'url', 'count', 'box'],
214
+ },
215
+ ref: { type: 'string' },
216
+ selector: { type: 'string' },
217
+ attr: { type: 'string' },
218
+ session: { type: 'string' },
219
+ requestId: { type: 'string' },
220
+ cdpPort: { type: 'number' },
221
+ },
222
+ required: ['what'],
223
+ additionalProperties: false,
224
+ },
225
+ },
226
+ {
227
+ name: 'browser.screenshot',
228
+ description: 'Take a screenshot.',
229
+ inputSchema: {
230
+ type: 'object',
231
+ properties: {
232
+ path: { type: 'string' },
233
+ full: { type: 'boolean' },
234
+ session: { type: 'string' },
235
+ requestId: { type: 'string' },
236
+ cdpPort: { type: 'number' },
237
+ },
238
+ additionalProperties: false,
239
+ },
240
+ },
241
+ {
242
+ name: 'browser.wait',
243
+ description: 'Wait for time, selector, text, or URL pattern.',
244
+ inputSchema: {
245
+ type: 'object',
246
+ properties: {
247
+ ms: { type: 'number' },
248
+ ref: { type: 'string' },
249
+ text: { type: 'string' },
250
+ urlPattern: { type: 'string' },
251
+ session: { type: 'string' },
252
+ requestId: { type: 'string' },
253
+ cdpPort: { type: 'number' },
254
+ },
255
+ additionalProperties: false,
256
+ },
257
+ },
258
+ {
259
+ name: 'browser.close',
260
+ description: 'Close the browser session.',
261
+ inputSchema: {
262
+ type: 'object',
263
+ properties: {
264
+ session: { type: 'string' },
265
+ requestId: { type: 'string' },
266
+ cdpPort: { type: 'number' },
267
+ },
268
+ additionalProperties: false,
269
+ },
270
+ },
271
+ ];
272
+ const server = new Server({ name: 'agent-browser', version: '0.2.0' }, { capabilities: { tools: {} } });
273
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools }));
274
+ server.setNotificationHandler(CancelledNotificationSchema, async (notification) => {
275
+ const requestId = notification.params.requestId;
276
+ if (requestId === undefined || requestId === null) {
277
+ return;
278
+ }
279
+ const controller = activeRequests.get(requestId);
280
+ if (controller) {
281
+ controller.abort();
282
+ activeRequests.delete(requestId);
283
+ }
284
+ const logEntry = {
285
+ ts: new Date().toISOString(),
286
+ tool: 'notifications/cancelled',
287
+ requestId,
288
+ reason: notification.params.reason,
289
+ };
290
+ try {
291
+ await logCall(logEntry);
292
+ }
293
+ catch (error) {
294
+ const message = error instanceof Error ? error.message : 'Unknown error';
295
+ console.error(`[agent-browser-mcp] log failed: ${message}`);
296
+ }
297
+ });
298
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
299
+ const { name, arguments: args } = request.params;
300
+ const requestKey = request.id ?? args.requestId ?? null;
301
+ const abortController = new AbortController();
302
+ if (requestKey !== null && requestKey !== undefined) {
303
+ activeRequests.set(requestKey, abortController);
304
+ }
305
+ const start = Date.now();
306
+ const logEntry = {
307
+ ts: new Date().toISOString(),
308
+ tool: name,
309
+ args,
310
+ requestId: requestKey,
311
+ };
312
+ try {
313
+ switch (name) {
314
+ case 'browser.connect': {
315
+ const input = args;
316
+ const resp = await runAgentBrowser(['connect', String(input.port)], input, abortController.signal);
317
+ if (!resp.success) {
318
+ const details = resp.data;
319
+ const err = errorResponse(details?.cancelled ? 'cancelled' : 'cli_error', resp.error ?? 'agent-browser failed', resp.data, shouldRetry(resp.error, details), requestKey);
320
+ logEntry.response = err;
321
+ return { isError: true, content: [{ type: 'text', text: JSON.stringify(err, null, 2) }] };
322
+ }
323
+ const ok = { ok: true, port: input.port };
324
+ logEntry.response = ok;
325
+ return { content: [{ type: 'text', text: JSON.stringify(ok, null, 2) }] };
326
+ }
327
+ case 'browser.open': {
328
+ const input = args;
329
+ const openResp = await runAgentBrowser(['open', input.url], input, abortController.signal);
330
+ if (!openResp.success) {
331
+ const details = openResp.data;
332
+ const err = errorResponse(details?.cancelled ? 'cancelled' : 'cli_error', openResp.error ?? 'agent-browser failed', openResp.data, shouldRetry(openResp.error, details), requestKey);
333
+ logEntry.response = err;
334
+ return {
335
+ isError: true,
336
+ content: [{ type: 'text', text: JSON.stringify(err, null, 2) }],
337
+ };
338
+ }
339
+ if (input.viewport) {
340
+ const viewportResp = await runAgentBrowser(['set', 'viewport', String(input.viewport.w), String(input.viewport.h)], input, abortController.signal);
341
+ if (!viewportResp.success) {
342
+ const details = viewportResp.data;
343
+ const err = errorResponse(details?.cancelled ? 'cancelled' : 'cli_error', viewportResp.error ?? 'agent-browser failed', viewportResp.data, shouldRetry(viewportResp.error, details), requestKey);
344
+ logEntry.response = err;
345
+ return {
346
+ isError: true,
347
+ content: [{ type: 'text', text: JSON.stringify(err, null, 2) }],
348
+ };
349
+ }
350
+ }
351
+ const data = openResp.data;
352
+ const ok = { ok: true, url: data?.url ?? input.url };
353
+ logEntry.response = ok;
354
+ return { content: [{ type: 'text', text: JSON.stringify(ok, null, 2) }] };
355
+ }
356
+ case 'browser.snapshot': {
357
+ const input = args;
358
+ const commandArgs = ['snapshot'];
359
+ if (input.interactive)
360
+ commandArgs.push('-i');
361
+ if (input.compact)
362
+ commandArgs.push('-c');
363
+ if (input.depth !== undefined)
364
+ commandArgs.push('-d', String(input.depth));
365
+ if (input.selector)
366
+ commandArgs.push('-s', input.selector);
367
+ const resp = await runAgentBrowser(commandArgs, input, abortController.signal);
368
+ if (!resp.success) {
369
+ const details = resp.data;
370
+ const err = errorResponse(details?.cancelled ? 'cancelled' : 'cli_error', resp.error ?? 'agent-browser failed', resp.data, shouldRetry(resp.error, details), requestKey);
371
+ logEntry.response = err;
372
+ return { isError: true, content: [{ type: 'text', text: JSON.stringify(err, null, 2) }] };
373
+ }
374
+ const parsed = parseSnapshot(resp.data);
375
+ if ('error' in parsed) {
376
+ const err = errorResponse('invalid_response', parsed.error ?? 'Invalid snapshot response', parsed.raw, false, requestKey);
377
+ logEntry.response = err;
378
+ return { isError: true, content: [{ type: 'text', text: JSON.stringify(err, null, 2) }] };
379
+ }
380
+ const ok = { ok: true, elements: parsed.elements, raw: parsed.raw };
381
+ logEntry.response = ok;
382
+ return { content: [{ type: 'text', text: JSON.stringify(ok, null, 2) }] };
383
+ }
384
+ case 'browser.click': {
385
+ const input = args;
386
+ const resp = await runAgentBrowser(['click', toSelector(input.ref)], input, abortController.signal);
387
+ if (!resp.success) {
388
+ const details = resp.data;
389
+ const err = errorResponse(details?.cancelled ? 'cancelled' : 'cli_error', resp.error ?? 'agent-browser failed', resp.data, shouldRetry(resp.error, details), requestKey);
390
+ logEntry.response = err;
391
+ return { isError: true, content: [{ type: 'text', text: JSON.stringify(err, null, 2) }] };
392
+ }
393
+ const ok = { ok: true };
394
+ logEntry.response = ok;
395
+ return { content: [{ type: 'text', text: JSON.stringify(ok, null, 2) }] };
396
+ }
397
+ case 'browser.fill': {
398
+ const input = args;
399
+ const resp = await runAgentBrowser(['fill', toSelector(input.ref), input.text], input, abortController.signal);
400
+ if (!resp.success) {
401
+ const details = resp.data;
402
+ const err = errorResponse(details?.cancelled ? 'cancelled' : 'cli_error', resp.error ?? 'agent-browser failed', resp.data, shouldRetry(resp.error, details), requestKey);
403
+ logEntry.response = err;
404
+ return { isError: true, content: [{ type: 'text', text: JSON.stringify(err, null, 2) }] };
405
+ }
406
+ const ok = { ok: true };
407
+ logEntry.response = ok;
408
+ return { content: [{ type: 'text', text: JSON.stringify(ok, null, 2) }] };
409
+ }
410
+ case 'browser.get': {
411
+ const input = args;
412
+ const selector = input.ref ? toSelector(input.ref) : input.selector;
413
+ const needsSelector = ['text', 'html', 'value', 'attr', 'count', 'box'].includes(input.what);
414
+ if (needsSelector && !selector) {
415
+ const err = errorResponse('invalid_input', `browser.get ${input.what} requires ref or selector`, undefined, false, requestKey);
416
+ logEntry.response = err;
417
+ return { isError: true, content: [{ type: 'text', text: JSON.stringify(err, null, 2) }] };
418
+ }
419
+ if (input.what === 'attr' && !input.attr) {
420
+ const err = errorResponse('invalid_input', 'browser.get attr requires attr', undefined, false, requestKey);
421
+ logEntry.response = err;
422
+ return { isError: true, content: [{ type: 'text', text: JSON.stringify(err, null, 2) }] };
423
+ }
424
+ const commandArgs = ['get', input.what];
425
+ if (selector)
426
+ commandArgs.push(selector);
427
+ if (input.what === 'attr' && input.attr)
428
+ commandArgs.push(input.attr);
429
+ const resp = await runAgentBrowser(commandArgs, input, abortController.signal);
430
+ if (!resp.success) {
431
+ const details = resp.data;
432
+ const err = errorResponse(details?.cancelled ? 'cancelled' : 'cli_error', resp.error ?? 'agent-browser failed', resp.data, shouldRetry(resp.error, details), requestKey);
433
+ logEntry.response = err;
434
+ return { isError: true, content: [{ type: 'text', text: JSON.stringify(err, null, 2) }] };
435
+ }
436
+ const ok = { ok: true, value: resp.data };
437
+ logEntry.response = ok;
438
+ return { content: [{ type: 'text', text: JSON.stringify(ok, null, 2) }] };
439
+ }
440
+ case 'browser.screenshot': {
441
+ const input = args;
442
+ const commandArgs = ['screenshot'];
443
+ if (input.path)
444
+ commandArgs.push(input.path);
445
+ if (input.full)
446
+ commandArgs.push('--full');
447
+ const resp = await runAgentBrowser(commandArgs, input, abortController.signal);
448
+ if (!resp.success) {
449
+ const details = resp.data;
450
+ const err = errorResponse(details?.cancelled ? 'cancelled' : 'cli_error', resp.error ?? 'agent-browser failed', resp.data, shouldRetry(resp.error, details), requestKey);
451
+ logEntry.response = err;
452
+ return { isError: true, content: [{ type: 'text', text: JSON.stringify(err, null, 2) }] };
453
+ }
454
+ const data = resp.data;
455
+ const ok = input.path
456
+ ? { ok: true, path: data?.path ?? input.path }
457
+ : { ok: true, path: data?.path ?? null, base64: data?.base64 };
458
+ logEntry.response = ok;
459
+ return { content: [{ type: 'text', text: JSON.stringify(ok, null, 2) }] };
460
+ }
461
+ case 'browser.wait': {
462
+ const input = args;
463
+ const commandArgs = ['wait'];
464
+ if (input.ref) {
465
+ commandArgs.push(toSelector(input.ref));
466
+ }
467
+ else if (input.ms !== undefined) {
468
+ commandArgs.push(String(input.ms));
469
+ }
470
+ else if (input.text) {
471
+ commandArgs.push('--text', input.text);
472
+ }
473
+ else if (input.urlPattern) {
474
+ commandArgs.push('--url', input.urlPattern);
475
+ }
476
+ else {
477
+ const err = errorResponse('invalid_input', 'browser.wait requires ms, ref, text, or urlPattern', undefined, false, requestKey);
478
+ logEntry.response = err;
479
+ return { isError: true, content: [{ type: 'text', text: JSON.stringify(err, null, 2) }] };
480
+ }
481
+ const resp = await runAgentBrowser(commandArgs, input, abortController.signal);
482
+ if (!resp.success) {
483
+ const details = resp.data;
484
+ const err = errorResponse(details?.cancelled ? 'cancelled' : 'cli_error', resp.error ?? 'agent-browser failed', resp.data, shouldRetry(resp.error, details), requestKey);
485
+ logEntry.response = err;
486
+ return { isError: true, content: [{ type: 'text', text: JSON.stringify(err, null, 2) }] };
487
+ }
488
+ const ok = { ok: true };
489
+ logEntry.response = ok;
490
+ return { content: [{ type: 'text', text: JSON.stringify(ok, null, 2) }] };
491
+ }
492
+ case 'browser.close': {
493
+ const input = args;
494
+ const resp = await runAgentBrowser(['close'], input, abortController.signal);
495
+ if (!resp.success) {
496
+ const details = resp.data;
497
+ const err = errorResponse(details?.cancelled ? 'cancelled' : 'cli_error', resp.error ?? 'agent-browser failed', resp.data, shouldRetry(resp.error, details), requestKey);
498
+ logEntry.response = err;
499
+ return { isError: true, content: [{ type: 'text', text: JSON.stringify(err, null, 2) }] };
500
+ }
501
+ const ok = { ok: true };
502
+ logEntry.response = ok;
503
+ return { content: [{ type: 'text', text: JSON.stringify(ok, null, 2) }] };
504
+ }
505
+ default: {
506
+ const err = errorResponse('unknown_tool', `Unknown tool: ${name}`, undefined, false, requestKey);
507
+ logEntry.response = err;
508
+ return { isError: true, content: [{ type: 'text', text: JSON.stringify(err, null, 2) }] };
509
+ }
510
+ }
511
+ }
512
+ catch (error) {
513
+ const message = error instanceof Error ? error.message : 'Unknown error';
514
+ const err = errorResponse('server_error', message, undefined, false, requestKey);
515
+ logEntry.response = err;
516
+ return { isError: true, content: [{ type: 'text', text: JSON.stringify(err, null, 2) }] };
517
+ }
518
+ finally {
519
+ if (requestKey !== null && requestKey !== undefined) {
520
+ activeRequests.delete(requestKey);
521
+ }
522
+ const durationMs = Date.now() - start;
523
+ logEntry.durationMs = durationMs;
524
+ console.error(`[agent-browser-mcp] ${name} ${durationMs}ms`);
525
+ try {
526
+ await logCall(logEntry);
527
+ }
528
+ catch (error) {
529
+ const message = error instanceof Error ? error.message : 'Unknown error';
530
+ console.error(`[agent-browser-mcp] log failed: ${message}`);
531
+ }
532
+ }
533
+ });
534
+ const transport = new StdioServerTransport();
535
+ await server.connect(transport);
536
+ //# sourceMappingURL=mcp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.js","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,210 @@
1
+ # MCP Server: agent-browser
2
+
3
+ This project ships a Model Context Protocol server that exposes `agent-browser` as structured tools over stdio. The server returns JSON-only responses and wraps the CLI with consistent error handling and optional logging.
4
+
5
+ ## Install
6
+
7
+ Prerequisite: install the Vercel `agent-browser` CLI.
8
+ https://github.com/vercel-labs/agent-browser
9
+
10
+ ```bash
11
+ pnpm install
12
+ pnpm build
13
+ ```
14
+
15
+ Ensure Playwright browser binaries are installed:
16
+ ```bash
17
+ agent-browser install
18
+ ```
19
+
20
+ ## Run
21
+
22
+ ```bash
23
+ node dist/mcp.js
24
+ ```
25
+
26
+ Point your MCP client at the command above (stdio transport).
27
+
28
+ ## Run with npx
29
+
30
+ Once published:
31
+
32
+ ```bash
33
+ npx mcp-agent-browser
34
+ ```
35
+
36
+ ## Smoke test (stdio)
37
+
38
+ ```bash
39
+ npm run build
40
+ npm run smoke
41
+ ```
42
+
43
+ The smoke test includes a valid `initialize` request with `protocolVersion`, then lists tools.
44
+
45
+ ## Tools
46
+
47
+ All tools accept an optional `cdpPort` number to pass `--cdp <port>` to the CLI for Electron/CDP targets.
48
+
49
+ ### browser.connect
50
+
51
+ Input:
52
+ ```json
53
+ { "port": 9222, "session": "agent1", "requestId": "req-123" }
54
+ ```
55
+
56
+ Output:
57
+ ```json
58
+ { "ok": true, "port": 9222 }
59
+ ```
60
+
61
+ ### browser.open
62
+
63
+ Input:
64
+ ```json
65
+ { "url": "https://example.com", "headed": false, "session": "agent1", "requestId": "req-123", "cdpPort": 9222, "viewport": { "w": 1280, "h": 720 } }
66
+ ```
67
+
68
+ Output:
69
+ ```json
70
+ { "ok": true, "url": "https://example.com" }
71
+ ```
72
+
73
+ ### browser.snapshot
74
+
75
+ Input:
76
+ ```json
77
+ { "interactive": true, "selector": "#main", "depth": 4, "compact": true, "session": "agent1", "requestId": "req-123", "cdpPort": 9222 }
78
+ ```
79
+
80
+ Output:
81
+ ```json
82
+ {
83
+ "ok": true,
84
+ "elements": [{ "ref": "e1", "role": "button", "name": "Submit", "selectorHint": "@e1" }],
85
+ "raw": { "snapshot": "...", "refs": { "e1": { "role": "button", "name": "Submit" } } }
86
+ }
87
+ ```
88
+
89
+ ### browser.click
90
+
91
+ Input:
92
+ ```json
93
+ { "ref": "e1", "session": "agent1", "requestId": "req-123", "cdpPort": 9222 }
94
+ ```
95
+
96
+ Output:
97
+ ```json
98
+ { "ok": true }
99
+ ```
100
+
101
+ ### browser.fill
102
+
103
+ Input:
104
+ ```json
105
+ { "ref": "e3", "text": "user@example.com", "session": "agent1", "requestId": "req-123", "cdpPort": 9222 }
106
+ ```
107
+
108
+ Output:
109
+ ```json
110
+ { "ok": true }
111
+ ```
112
+
113
+ ### browser.get
114
+
115
+ Input:
116
+ ```json
117
+ { "what": "text", "ref": "e1", "session": "agent1", "requestId": "req-123", "cdpPort": 9222 }
118
+ ```
119
+
120
+ Output:
121
+ ```json
122
+ { "ok": true, "value": { "text": "Example Domain" } }
123
+ ```
124
+
125
+ ### browser.screenshot
126
+
127
+ Input:
128
+ ```json
129
+ { "path": "page.png", "full": true, "session": "agent1", "requestId": "req-123", "cdpPort": 9222 }
130
+ ```
131
+
132
+ Output:
133
+ ```json
134
+ { "ok": true, "path": "page.png" }
135
+ ```
136
+
137
+ If no path is provided, the server returns base64:
138
+ ```json
139
+ { "ok": true, "path": null, "base64": "..." }
140
+ ```
141
+
142
+ ### browser.wait
143
+
144
+ Input:
145
+ ```json
146
+ { "ms": 1000, "session": "agent1", "requestId": "req-123", "cdpPort": 9222 }
147
+ ```
148
+
149
+ Output:
150
+ ```json
151
+ { "ok": true }
152
+ ```
153
+
154
+ ### browser.close
155
+
156
+ Input:
157
+ ```json
158
+ { "session": "agent1", "cdpPort": 9222 }
159
+ ```
160
+
161
+ Output:
162
+ ```json
163
+ { "ok": true }
164
+ ```
165
+
166
+ ## Error Handling
167
+
168
+ Errors always return:
169
+ ```json
170
+ {
171
+ "ok": false,
172
+ "error": {
173
+ "code": "cli_error",
174
+ "message": "agent-browser failed",
175
+ "details": { "exitCode": 1, "stderr": "...", "stdout": "..." },
176
+ "retryable": false,
177
+ "requestId": "req-123"
178
+ }
179
+ }
180
+ ```
181
+
182
+ ## Cancellation
183
+
184
+ The server honors MCP `notifications/cancelled` with a matching `requestId`. In-flight calls using the same MCP request id (or an explicit `requestId` in tool args) will be aborted and return:
185
+
186
+ ```json
187
+ {
188
+ "ok": false,
189
+ "error": {
190
+ "code": "cancelled",
191
+ "message": "Request cancelled",
192
+ "retryable": false,
193
+ "requestId": "req-123"
194
+ }
195
+ }
196
+ ```
197
+
198
+ ## Configuration
199
+
200
+ Environment variables:
201
+ - `AGENT_BROWSER_BIN`: Override the `agent-browser` CLI path.
202
+ - `AGENT_BROWSER_MCP_LOG`: Write JSONL logs for all tool calls.
203
+ - `AGENT_BROWSER_MCP_TIMEOUT_MS`: Per-command timeout in ms (default: 30000).
204
+
205
+ The server inherits all `AGENT_BROWSER_*` environment variables used by the CLI.
206
+
207
+ ## Idempotency notes
208
+
209
+ - Read-only tools (`browser.snapshot`, `browser.get`, `browser.wait`, `browser.screenshot`) are safe to retry.
210
+ - Mutating tools (`browser.connect`, `browser.open`, `browser.click`, `browser.fill`, `browser.close`) accept `requestId` for correlation in logs but are not strictly idempotent.
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "mcp-agent-browser",
3
+ "version": "0.2.0",
4
+ "description": "MCP server for agent-browser",
5
+ "type": "module",
6
+ "main": "dist/mcp.js",
7
+ "bin": {
8
+ "mcp-agent-browser": "dist/mcp.js"
9
+ },
10
+ "files": [
11
+ "dist",
12
+ "docs"
13
+ ],
14
+ "scripts": {
15
+ "build": "tsc",
16
+ "dev": "tsx src/mcp.ts",
17
+ "prepublishOnly": "npm run build",
18
+ "start": "node dist/mcp.js",
19
+ "smoke": "node scripts/smoke.mjs",
20
+ "typecheck": "tsc --noEmit"
21
+ },
22
+ "license": "Apache-2.0",
23
+ "dependencies": {
24
+ "@modelcontextprotocol/sdk": "^1.10.0",
25
+ "execa": "^9.4.0"
26
+ },
27
+ "devDependencies": {
28
+ "@types/node": "^20.10.0",
29
+ "tsx": "^4.6.0",
30
+ "typescript": "^5.3.0"
31
+ }
32
+ }