@mindstone/mcp-server-browser-automation 0.2.2 → 0.2.4
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 +7 -10
- package/dist/browser-client.d.ts +3 -7
- package/dist/browser-client.js +59 -66
- package/dist/index.d.ts +3 -1
- package/dist/index.js +3 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ Browser control you can watch: open pages, sign in, click around, fill forms, ta
|
|
|
9
9
|
|
|
10
10
|
## Status
|
|
11
11
|
|
|
12
|
-
- **Version:** [0.2.
|
|
12
|
+
- **Version:** [0.2.4](./CHANGELOG.md) · [npm](https://www.npmjs.com/package/@mindstone/mcp-server-browser-automation)
|
|
13
13
|
- **Auth:** None ([`server.json`](./server.json))
|
|
14
14
|
- **Tools:** [21](./src/tools/) (navigation, observation, interaction, sessions, files)
|
|
15
15
|
- **Surface:** browser-automation
|
|
@@ -44,7 +44,7 @@ Response (trimmed):
|
|
|
44
44
|
|
|
45
45
|
- Node.js 20+
|
|
46
46
|
- npm
|
|
47
|
-
-
|
|
47
|
+
- Nothing else to install for the CLI: the server ships `agent-browser` as a dependency.
|
|
48
48
|
|
|
49
49
|
<!-- BEGIN INSTALL_LINKS: do not edit by hand; regenerated by scripts/gen-install-links.mjs -->
|
|
50
50
|
## One-click install
|
|
@@ -94,20 +94,16 @@ npm install -g @mindstone/mcp-server-browser-automation
|
|
|
94
94
|
mcp-server-browser-automation
|
|
95
95
|
```
|
|
96
96
|
|
|
97
|
-
This server
|
|
97
|
+
This server uses the `agent-browser` CLI to control the browser.
|
|
98
98
|
|
|
99
99
|
### Binary Resolution
|
|
100
100
|
|
|
101
|
-
1. **PATH lookup** (preferred): If `agent-browser` is on your PATH, it is used directly.
|
|
102
|
-
2. **
|
|
101
|
+
1. **PATH lookup** (preferred): If an `agent-browser` executable is on your PATH, it is used directly.
|
|
102
|
+
2. **Bundled copy**: Otherwise the server runs the `agent-browser` package it ships as a dependency (pinned to 0.33.2), with the same Node that runs the server. No shell and no `npx` are involved, so this works the same on Windows, macOS and Linux.
|
|
103
103
|
|
|
104
104
|
### Installing agent-browser
|
|
105
105
|
|
|
106
|
-
|
|
107
|
-
npm install -g agent-browser
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
Or let the npx fallback handle it automatically (slower on first use due to download).
|
|
106
|
+
Nothing to do: installing this server installs `agent-browser` with it. A separate executable on PATH takes precedence. On Windows, npm's `.cmd` shims cannot be used, so the bundled copy runs instead.
|
|
111
107
|
|
|
112
108
|
## Configuration
|
|
113
109
|
|
|
@@ -117,6 +113,7 @@ No API keys or credentials are required. The server communicates with the browse
|
|
|
117
113
|
|---|---|---|
|
|
118
114
|
| `AGENT_BROWSER_SESSION_NAME` | No | Session name for browser persistence (default: `mcp`) |
|
|
119
115
|
| `AGENT_BROWSER_SHOW_WINDOW` | No | Set to `false` to run without a visible browser window. Default is visible (`true`). |
|
|
116
|
+
| `AGENT_BROWSER_AUTOSAVE_INTERVAL_MS` | No | Periodic session autosave interval in milliseconds (needs `agent-browser` 0.31.2 or later). Default `0` (off), because each periodic save briefly opens a tab that brings a visible browser window in front of other apps. The session is still saved when the browser closes (`browser_close`). Any value you set is passed through as-is; an empty or non-numeric value gets the CLI's 30-second default. The `agent-browser` daemon reads it when it starts, so an already-running daemon keeps its previous setting until it exits (for example after `browser_close`). |
|
|
120
117
|
| `MCP_WORKSPACE_PATH` | No | Workspace directory that `browser_pdf` writes into and `browser_upload` reads from. Defaults to the system temp directory. See [Security notes](#security-notes). |
|
|
121
118
|
|
|
122
119
|
### MCP Host Configuration
|
package/dist/browser-client.d.ts
CHANGED
|
@@ -21,13 +21,9 @@ export interface ExecOptions {
|
|
|
21
21
|
* on the CLI — passing one would be a CLI error — so headless is the absence
|
|
22
22
|
* of `--headed`.
|
|
23
23
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
24
|
+
* Runs an `agent-browser` executable from PATH when there is one; otherwise
|
|
25
|
+
* runs the connector's own agent-browser dependency with this Node. Both use
|
|
26
|
+
* execFile with no shell, so no argument is ever interpreted by a shell.
|
|
26
27
|
*/
|
|
27
28
|
export declare function execAgentBrowser(args: string[], options?: ExecOptions): Promise<ExecResult>;
|
|
28
|
-
/**
|
|
29
|
-
* Reset the resolved binary cache.
|
|
30
|
-
* Primarily used for testing to reset state between test runs.
|
|
31
|
-
*/
|
|
32
|
-
export declare function resetBinaryCache(): void;
|
|
33
29
|
//# sourceMappingURL=browser-client.d.ts.map
|
package/dist/browser-client.js
CHANGED
|
@@ -1,16 +1,23 @@
|
|
|
1
1
|
import { execFile } from 'node:child_process';
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
2
3
|
import { promisify } from 'node:util';
|
|
3
4
|
import { ConnectorError, DEFAULT_TIMEOUT_MS, SESSION_NAME } from './types.js';
|
|
4
5
|
import { wrapUntrusted } from './untrusted-content.js';
|
|
5
6
|
const execFileAsync = promisify(execFile);
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
const MAX_BUFFER = 10 * 1024 * 1024; // 10MB for large snapshots
|
|
8
|
+
let bundledEntry = null;
|
|
9
|
+
/**
|
|
10
|
+
* Path to the JS entry of the agent-browser package this connector depends
|
|
11
|
+
* on. Run with `process.execPath` rather than through an npm `.cmd` shim or
|
|
12
|
+
* npx: on Windows, execFile cannot start a shim without a shell, and npx
|
|
13
|
+
* reaches the CLI through cmd.exe, which cuts arguments at the first newline.
|
|
14
|
+
* Throws MODULE_NOT_FOUND when the dependency is missing.
|
|
15
|
+
*/
|
|
16
|
+
function resolveBundledEntry() {
|
|
17
|
+
if (!bundledEntry) {
|
|
18
|
+
bundledEntry = createRequire(import.meta.url).resolve('agent-browser/bin/agent-browser.js');
|
|
19
|
+
}
|
|
20
|
+
return bundledEntry;
|
|
14
21
|
}
|
|
15
22
|
function buildEnv() {
|
|
16
23
|
const env = { ...process.env };
|
|
@@ -18,6 +25,16 @@ function buildEnv() {
|
|
|
18
25
|
if (!env.AGENT_BROWSER_SESSION_NAME) {
|
|
19
26
|
env.AGENT_BROWSER_SESSION_NAME = SESSION_NAME;
|
|
20
27
|
}
|
|
28
|
+
// A session name turns on the CLI's periodic autosave (every 30s by
|
|
29
|
+
// default, agent-browser >= 0.31.2). Each save opens a temporary tab, which
|
|
30
|
+
// brings a visible browser window in front of the user's other apps.
|
|
31
|
+
// Save-on-close still persists the session, so periodic saves stay off
|
|
32
|
+
// unless the host sets an interval. A host value, including an empty
|
|
33
|
+
// string, passes through untouched; the CLI treats empty or non-numeric
|
|
34
|
+
// values as its 30s default. The daemon reads this only when it starts.
|
|
35
|
+
if (env.AGENT_BROWSER_AUTOSAVE_INTERVAL_MS === undefined) {
|
|
36
|
+
env.AGENT_BROWSER_AUTOSAVE_INTERVAL_MS = '0';
|
|
37
|
+
}
|
|
21
38
|
return env;
|
|
22
39
|
}
|
|
23
40
|
/**
|
|
@@ -44,18 +61,6 @@ function resolveHeaded(optionHeaded, env) {
|
|
|
44
61
|
return false;
|
|
45
62
|
return true;
|
|
46
63
|
}
|
|
47
|
-
/**
|
|
48
|
-
* Pinned version of agent-browser used by the npx fallback.
|
|
49
|
-
*
|
|
50
|
-
* Why pinned: keeps fallback behavior reproducible. Bump when verified against
|
|
51
|
-
* a newer release. Do not use `latest` — npx caches by spec, and an unpinned
|
|
52
|
-
* spec produces flaky behavior across machines.
|
|
53
|
-
*
|
|
54
|
-
* 0.33.2 verified 2026-08-05 against the connector's full command surface
|
|
55
|
-
* (open, snapshot -i, screenshot, pdf, get url/title/text, tab, click/fill/
|
|
56
|
-
* type/press/scroll/select/hover, eval, back/forward, wait, close).
|
|
57
|
-
*/
|
|
58
|
-
const NPX_FALLBACK_VERSION = '0.33.2';
|
|
59
64
|
/**
|
|
60
65
|
* Build the ConnectorError message for a failed CLI invocation.
|
|
61
66
|
*
|
|
@@ -89,8 +94,9 @@ function cliFailureMessage(command, stderr, stdout) {
|
|
|
89
94
|
* on the CLI — passing one would be a CLI error — so headless is the absence
|
|
90
95
|
* of `--headed`.
|
|
91
96
|
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
97
|
+
* Runs an `agent-browser` executable from PATH when there is one; otherwise
|
|
98
|
+
* runs the connector's own agent-browser dependency with this Node. Both use
|
|
99
|
+
* execFile with no shell, so no argument is ever interpreted by a shell.
|
|
94
100
|
*/
|
|
95
101
|
export async function execAgentBrowser(args, options) {
|
|
96
102
|
const timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
@@ -101,59 +107,46 @@ export async function execAgentBrowser(args, options) {
|
|
|
101
107
|
if (resolveHeaded(options?.headed, env) && args.length > 0) {
|
|
102
108
|
args = [args[0], '--headed', ...args.slice(1)];
|
|
103
109
|
}
|
|
104
|
-
const
|
|
105
|
-
try {
|
|
110
|
+
const run = async (file, fileArgs) => {
|
|
106
111
|
// execFile is safe against command injection (no shell interpretation)
|
|
107
|
-
const result = await execFileAsync(
|
|
112
|
+
const result = await execFileAsync(file, fileArgs, {
|
|
108
113
|
env,
|
|
109
114
|
timeout: timeoutMs,
|
|
110
|
-
maxBuffer:
|
|
115
|
+
maxBuffer: MAX_BUFFER,
|
|
116
|
+
// GUI hosts should not open a console window for each CLI call on Windows.
|
|
117
|
+
windowsHide: true,
|
|
111
118
|
});
|
|
112
119
|
return { stdout: result.stdout, stderr: result.stderr ?? '' };
|
|
120
|
+
};
|
|
121
|
+
try {
|
|
122
|
+
return await run('agent-browser', args);
|
|
113
123
|
}
|
|
114
124
|
catch (error) {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
// from the npm cache / registry).
|
|
118
|
-
if (err.code === 'ENOENT') {
|
|
119
|
-
try {
|
|
120
|
-
const npxResult = await execFileAsync('npx', ['-y', `agent-browser@${NPX_FALLBACK_VERSION}`, ...args], {
|
|
121
|
-
env,
|
|
122
|
-
timeout: timeoutMs + 15_000, // extra time for npx install
|
|
123
|
-
maxBuffer: 10 * 1024 * 1024,
|
|
124
|
-
});
|
|
125
|
-
return { stdout: npxResult.stdout, stderr: npxResult.stderr ?? '' };
|
|
126
|
-
}
|
|
127
|
-
catch (npxError) {
|
|
128
|
-
const npxErr = npxError;
|
|
129
|
-
// Distinguish: npx itself missing (true binary-not-found) vs
|
|
130
|
-
// agent-browser ran but returned non-zero (CLI error surfaced via npx).
|
|
131
|
-
if (npxErr.code === 'ENOENT') {
|
|
132
|
-
throw new ConnectorError(`agent-browser binary not found on PATH and npx is also unavailable: ${npxErr.message ?? String(npxErr)}`, 'BINARY_NOT_FOUND', 'Install agent-browser: npm install -g agent-browser\n' +
|
|
133
|
-
'Or ensure npx is available on PATH.');
|
|
134
|
-
}
|
|
135
|
-
// npx ran but the underlying CLI exited non-zero — propagate as CLI_ERROR
|
|
136
|
-
// with the (enveloped) stderr for diagnosis.
|
|
137
|
-
throw new ConnectorError(cliFailureMessage(args[0], npxErr.stderr, npxErr.stdout), 'CLI_ERROR', 'The agent-browser CLI command failed (via npx fallback). ' +
|
|
138
|
-
'Check the error details above. ' +
|
|
139
|
-
'For best performance, install agent-browser globally: npm install -g agent-browser');
|
|
140
|
-
}
|
|
125
|
+
if (error.code !== 'ENOENT') {
|
|
126
|
+
throw classifyFailure(error, args[0], timeoutMs);
|
|
141
127
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
throw new ConnectorError(cliFailureMessage(args[0], err.stderr, err.stdout), 'CLI_ERROR', 'The agent-browser CLI command failed. Check that agent-browser is installed and the browser session is active.');
|
|
128
|
+
}
|
|
129
|
+
// Not on PATH: run the bundled copy.
|
|
130
|
+
try {
|
|
131
|
+
return await run(process.execPath, [resolveBundledEntry(), ...args]);
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
throw classifyFailure(error, args[0], timeoutMs);
|
|
150
135
|
}
|
|
151
136
|
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
137
|
+
function classifyFailure(error, command, timeoutMs) {
|
|
138
|
+
const err = error;
|
|
139
|
+
// Timeout — name only the subcommand: the full argument vector may carry
|
|
140
|
+
// sensitive values (URLs with userinfo, selectors, filenames, typed
|
|
141
|
+
// values, evaluation scripts) and must not be echoed to the model.
|
|
142
|
+
if (err.code === 'ERR_CHILD_PROCESS_STDIO_MAXBUFFER' || err.killed) {
|
|
143
|
+
return new ConnectorError(`Command timed out after ${timeoutMs}ms: agent-browser ${command}`, 'TIMEOUT', 'The browser operation took too long. Try a simpler action or increase the timeout.');
|
|
144
|
+
}
|
|
145
|
+
// Neither a PATH executable nor the bundled dependency could be started.
|
|
146
|
+
if (err.code === 'MODULE_NOT_FOUND' || err.code === 'ENOENT') {
|
|
147
|
+
return new ConnectorError('agent-browser is not on PATH and the copy bundled with this connector could not be found', 'BINARY_NOT_FOUND', "This connector's installation is incomplete. Reinstall the connector.");
|
|
148
|
+
}
|
|
149
|
+
// Other errors — include the (enveloped) stderr for diagnostics
|
|
150
|
+
return new ConnectorError(cliFailureMessage(command, err.stderr, err.stdout), 'CLI_ERROR', 'The agent-browser CLI command failed. Check that agent-browser is installed and the browser session is active.');
|
|
158
151
|
}
|
|
159
152
|
//# sourceMappingURL=browser-client.js.map
|
package/dist/index.d.ts
CHANGED
|
@@ -7,10 +7,12 @@
|
|
|
7
7
|
* Sessions persist automatically between invocations.
|
|
8
8
|
*
|
|
9
9
|
* Requirements:
|
|
10
|
-
* - agent-browser
|
|
10
|
+
* - agent-browser executable on PATH, or the bundled dependency run with this Node
|
|
11
11
|
*
|
|
12
12
|
* Environment variables:
|
|
13
13
|
* - AGENT_BROWSER_SESSION_NAME: Session name for persistence (default: "mcp")
|
|
14
|
+
* - AGENT_BROWSER_AUTOSAVE_INTERVAL_MS: Periodic session autosave interval in ms (default: "0", off;
|
|
15
|
+
* the session is still saved on close). Read when the agent-browser daemon starts.
|
|
14
16
|
* - MCP_DISABLE_GRACEFUL_FS=1: Disable the graceful-fs EMFILE mitigation patch
|
|
15
17
|
*/
|
|
16
18
|
import './installGracefulFs.js';
|
package/dist/index.js
CHANGED
|
@@ -7,10 +7,12 @@
|
|
|
7
7
|
* Sessions persist automatically between invocations.
|
|
8
8
|
*
|
|
9
9
|
* Requirements:
|
|
10
|
-
* - agent-browser
|
|
10
|
+
* - agent-browser executable on PATH, or the bundled dependency run with this Node
|
|
11
11
|
*
|
|
12
12
|
* Environment variables:
|
|
13
13
|
* - AGENT_BROWSER_SESSION_NAME: Session name for persistence (default: "mcp")
|
|
14
|
+
* - AGENT_BROWSER_AUTOSAVE_INTERVAL_MS: Periodic session autosave interval in ms (default: "0", off;
|
|
15
|
+
* the session is still saved on close). Read when the agent-browser daemon starts.
|
|
14
16
|
* - MCP_DISABLE_GRACEFUL_FS=1: Disable the graceful-fs EMFILE mitigation patch
|
|
15
17
|
*/
|
|
16
18
|
// MUST be the very first import — installs the graceful-fs EMFILE mitigation
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mindstone/mcp-server-browser-automation",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"mcpName": "io.github.mindstone/mcp-server-browser-automation",
|
|
5
5
|
"description": "Browser automation MCP server — visible-by-default browser control via accessibility snapshots, navigation, form filling, screenshots, and tab management. Set AGENT_BROWSER_SHOW_WINDOW=false to run quietly.",
|
|
6
6
|
"license": "FSL-1.1-MIT",
|
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
35
|
+
"agent-browser": "0.33.2",
|
|
35
36
|
"graceful-fs": "^4.2.11",
|
|
36
37
|
"zod": "^3.23.0"
|
|
37
38
|
},
|