@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 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.2](./CHANGELOG.md) · [npm](https://www.npmjs.com/package/@mindstone/mcp-server-browser-automation)
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
- - The `agent-browser` CLI on `PATH`, or `npx` available so the server can install it automatically.
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 requires the `agent-browser` CLI binary to control the browser.
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. **npx fallback**: If the binary is not found, the server automatically falls back to `npx -y agent-browser@0.33.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
- ```bash
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
@@ -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
- * Falls back to `npx -y agent-browser@<NPX_FALLBACK_VERSION>` if the binary is
25
- * not on PATH. Uses execFile (no shell) to prevent command injection.
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
@@ -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
- let resolvedBinary = null;
7
- function resolveAgentBrowser() {
8
- if (resolvedBinary)
9
- return resolvedBinary;
10
- // Default to the binary name — execFile will search PATH.
11
- // If not found (ENOENT), the caller falls back to npx.
12
- resolvedBinary = 'agent-browser';
13
- return resolvedBinary;
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
- * Falls back to `npx -y agent-browser@<NPX_FALLBACK_VERSION>` if the binary is
93
- * not on PATH. Uses execFile (no shell) to prevent command injection.
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 binary = resolveAgentBrowser();
105
- try {
110
+ const run = async (file, fileArgs) => {
106
111
  // execFile is safe against command injection (no shell interpretation)
107
- const result = await execFileAsync(binary, args, {
112
+ const result = await execFileAsync(file, fileArgs, {
108
113
  env,
109
114
  timeout: timeoutMs,
110
- maxBuffer: 10 * 1024 * 1024, // 10MB for large snapshots
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
- const err = error;
116
- // Binary not found on PATH — try npx fallback (pulls a pinned version
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
- // Timeout — name only the subcommand: the full argument vector may carry
143
- // sensitive values (URLs with userinfo, selectors, filenames, typed
144
- // values, evaluation scripts) and must not be echoed to the model.
145
- if (err.code === 'ERR_CHILD_PROCESS_STDIO_MAXBUFFER' || err.killed) {
146
- throw new ConnectorError(`Command timed out after ${timeoutMs}ms: agent-browser ${args[0]}`, 'TIMEOUT', 'The browser operation took too long. Try a simpler action or increase the timeout.');
147
- }
148
- // Other errors — include the (enveloped) stderr for diagnostics
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
- * Reset the resolved binary cache.
154
- * Primarily used for testing to reset state between test runs.
155
- */
156
- export function resetBinaryCache() {
157
- resolvedBinary = null;
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 CLI binary on PATH, or npx available for fallback
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 CLI binary on PATH, or npx available for fallback
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.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
  },