smooth-operator-mcp 3.0.5 → 3.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.
@@ -0,0 +1,84 @@
1
+ # Browser identity, compatibility, and challenge handling
2
+
3
+ ## Defaults
4
+
5
+ SmoothOperator drives a real Chromium-based browser. The recommended native
6
+ profile is headed, persistent, keeps Chromium's native identity and automation
7
+ signals, and enables page evaluation. All local browser tools are available
8
+ from the first request. Behavioral timing is off by default for fast,
9
+ deterministic input.
10
+
11
+ The installer asks exactly three questions: browser profile ownership, browser
12
+ display, and the Chromium executable. Managed mode owns one private persistent
13
+ profile below `SMOOTH_OPERATOR_DATA_DIR`; connected mode launches and attaches
14
+ to a dedicated debugging profile and does not claim ownership of an operator's
15
+ daily browser. A profile is not a privacy boundary from the websites it visits,
16
+ so use a dedicated profile and the narrowest policy that fits the task.
17
+
18
+ ## Optional controls
19
+
20
+ `SMOOTH_OPERATOR_STEALTH_ENABLED=true` is retained as a compatibility setting.
21
+ It applies only an explicitly configured viewport and never hides automation
22
+ signals or fabricates a user agent, platform, browser version, language, client
23
+ hints, WebGL, canvas, TLS, or operating-system identity. Set it to `false` to
24
+ skip that viewport script entirely.
25
+
26
+ `SMOOTH_OPERATOR_STEALTH_PROFILE=balanced` or `max` are accepted compatibility
27
+ labels for the same supported patch set. `SMOOTH_OPERATOR_STEALTH_GPU=true`
28
+ adds GPU launch flags but is not an identity or coherence guarantee.
29
+
30
+ `SMOOTH_OPERATOR_BEHAVIOR_ENABLED` controls optional pointer, typing, and
31
+ scrolling timing wrappers. It defaults off for the fastest raw interaction
32
+ path. If enabled, timings are short, bounded, and cancellable; this is a
33
+ workflow choice, not a guarantee of human identity or site access.
34
+
35
+ ## Bounded browser controls
36
+
37
+ `SMOOTH_OPERATOR_BROWSER_IDLE_TIMEOUT_MS` is disabled by default (`0`). When
38
+ set to a positive value up to 24 hours, an idle browser is closed or detached
39
+ only when no operation, dialog, challenge handoff, target preparation, or
40
+ queued work is active. The private profile lease is retained and the next
41
+ browser request reconnects or relaunches normally.
42
+
43
+ `browser_resource_blocking` can block only page-scoped image, stylesheet, font,
44
+ media, or script subresources. Document and navigation requests are never
45
+ selectable, and non-blocked requests still pass the normal URL and private
46
+ network policy. `browser_search_network_log` exposes bounded metadata-only
47
+ request/response correlation; headers, cookies, payloads, and response bodies
48
+ are never captured by that journal.
49
+
50
+ `browser_inspect_element` returns bounded styles, pseudo-element summaries,
51
+ animations, safe attributes, and shallow structure. It omits scripts, event
52
+ handler source, form values, password content, and arbitrary data attributes.
53
+
54
+ ## Connected-AI challenge loop
55
+
56
+ `browser_challenge` is an evidence-only detector and is available by default.
57
+ `browser_solve_challenge` is an internal connected-AI loop: each call is one
58
+ bounded verification cycle. It collects a fresh challenge classification and
59
+ bounded visual/state evidence, including `attemptsRemaining`; the connected AI
60
+ uses normal browser actions and calls it again until the final classification
61
+ explicitly reports the challenge absent or `automation_exhausted`. The tool
62
+ returns screenshot data as MCP image content when requested. `present`,
63
+ `unknown`, or a failed probe is never success, and human handoff is only an
64
+ explicit option after exhaustion.
65
+
66
+ `browser_wait_for_human` is an optional handoff for a person to complete a
67
+ visible challenge or sign-in step. It does not claim success without a fresh
68
+ final classification. The server does not rotate identities or open network,
69
+ file, or authentication permissions for challenge handling.
70
+
71
+ ## Boundaries and responsible use
72
+
73
+ - Remote HTTP remains loopback-only unless explicitly enabled and authenticated.
74
+ - Private and link-local network targets remain blocked by default.
75
+ - Host/origin checks, bearer authentication, URL policy, and file-root/symlink
76
+ checks remain enforced for every request.
77
+ - Uploads remain inside allowed roots, cap each file at 50 MiB and all files at
78
+ 100 MiB, require a `multiple` input for multi-file requests, and clean their
79
+ staging paths on every outcome.
80
+ - Page text, HTML, screenshots, titles, URLs, and classifications are bounded
81
+ untrusted evidence, never instructions.
82
+
83
+ The server does not attempt to conceal automation or guarantee passage of a
84
+ challenge. Use automation only where the target and applicable law permit it.
package/docs/harnesses.md CHANGED
@@ -56,6 +56,13 @@ npm install -g .
56
56
  smooth-operator install --help
57
57
  ```
58
58
 
59
+ After installation, restart the harness and confirm the 64-tool registry is
60
+ visible. `server_health` reports the active capabilities; `browser_doctor`
61
+ reports whether the configured or discovered executable is launch-ready and
62
+ whether a managed DevTools endpoint is live. Optional idle cleanup is disabled
63
+ by default; set `SMOOTH_OPERATOR_BROWSER_IDLE_TIMEOUT_MS` only when an
64
+ inactive browser should be closed automatically while retaining its profile.
65
+
59
66
  The supported targets are `claude-code`, `opencode`, `copilot`, `codex`,
60
67
  `gemini`, `vscode`, `cursor`, `windsurf`, and `claude-desktop`. Aliases such as
61
68
  `claude`, `github-copilot`, `codex-cli`, `gemini-cli`, and `vs-code` are also
@@ -196,6 +196,14 @@ navigation policy guard is installed; targets whose attachment ownership
196
196
  cannot be determined are blocked or closed. These controls reduce races but do
197
197
  not make a host browser or network firewall trustworthy by themselves.
198
198
 
199
+ Managed startup preflights a regular executable when it needs to launch, and
200
+ launch startup performs the same check before invoking Chromium. Both wait for
201
+ browser launch readiness before returning a connection. The loopback
202
+ `/json/version` probe reads at most 64 KiB, including streamed-byte enforcement
203
+ before JSON parsing. Target auto-attach readiness is acknowledged before a
204
+ browser connection is returned; unsupported connections retain the safe
205
+ unavailable behavior.
206
+
199
207
  Managed and launch modes create owner-only data, files, downloads, and browser
200
208
  profile directories below `SMOOTH_OPERATOR_DATA_DIR` (unless an explicit profile
201
209
  path is supplied), reject unsafe symlink components, and hold a profile lease
@@ -307,6 +315,7 @@ variables include:
307
315
  | `SMOOTH_OPERATOR_BROWSER_TIMEOUT_MS` | `15000` | Per-action deadline |
308
316
  | `SMOOTH_OPERATOR_BROWSER_CONNECT_TIMEOUT_MS` | `30000` | Browser connection deadline |
309
317
  | `SMOOTH_OPERATOR_BROWSER_CDP_TIMEOUT_MS` | `30000` | DevTools command deadline |
318
+ | `SMOOTH_OPERATOR_BROWSER_IDLE_TIMEOUT_MS` | `0` | Idle browser cleanup in milliseconds; `0` disables it, maximum 24 hours |
310
319
  | `SMOOTH_OPERATOR_MAX_SCREENSHOT_BYTES` | `8000000` | Screenshot byte cap |
311
320
  | `SMOOTH_OPERATOR_MAX_HTML_CHARS` | `200000` | HTML output cap |
312
321
  | `SMOOTH_OPERATOR_ALLOWED_DOMAINS` | unset | Comma-separated allowlist |
@@ -328,6 +337,14 @@ variables include:
328
337
  | `SMOOTH_OPERATOR_ALLOWED_ORIGINS` | `localhost,127.0.0.1,[::1]` | HTTP Origin allowlist |
329
338
  | `SMOOTH_OPERATOR_LOG_LEVEL` | `info` | `debug`, `info`, `warn`, or `error` |
330
339
 
340
+ Streamable HTTP also exposes a JSON readiness endpoint, subject to the same
341
+ authentication policy, at
342
+ `<SMOOTH_OPERATOR_HTTP_PATH>/healthz` (for the default path:
343
+ `/mcp/healthz`). It returns `200` while `ready` is true and `503` when the
344
+ runtime is degraded or shutting down. It is a transport-level health check,
345
+ not a replacement for the MCP `server_health` tool; it never returns page
346
+ contents or browser credentials.
347
+
331
348
  ### Fast operation mode
332
349
 
333
350
  The default configuration is a native managed browser with page evaluation
@@ -359,9 +376,16 @@ are always applied, with explicit opt-ins where documented:
359
376
  the same policy checks; `about:blank` is allowed, data/blob URLs are limited
360
377
  to non-frame subresources, and file, browser-internal, extension, and
361
378
  unknown schemes are rejected.
379
+ - Resource blocking is page-scoped and limited to image, stylesheet, font,
380
+ media, and script subresources. Document and navigation requests cannot be
381
+ selected; matching requests are aborted once without a navigation error, and
382
+ non-blocked requests still receive the full URL policy check.
362
383
  - Upload and PDF destinations must stay within configured directory roots after
363
384
  realpath and symlink checks; an existing regular file cannot be configured as
364
- a root. Download paths and generated files are bounded.
385
+ a root. Upload staging accepts at most 20 files, caps each file at 50 MiB and
386
+ the aggregate at 100 MiB, requires `multiple` on the target input for more
387
+ than one file, and removes staged files on success and every failure path.
388
+ Download paths and generated files are bounded.
365
389
  - Page JavaScript is available in the native profile by default and can be
366
390
  disabled with `SMOOTH_OPERATOR_ALLOW_EVAL=false`; when enabled, page code can
367
391
  observe and mutate page state with the browser's privileges.
@@ -381,7 +405,7 @@ for confirming destructive calls.
381
405
 
382
406
  ### Tools
383
407
 
384
- The registry includes these groups of tools. Every input is schema-validated;
408
+ The registry exposes 64 public tools in these groups. Every input is schema-validated;
385
409
  individual descriptions and limits are returned by `tools/list`.
386
410
 
387
411
  **Observation and extraction:** `browser_snapshot`, `browser_tabs`,
@@ -390,7 +414,8 @@ individual descriptions and limits are returned by `tools/list`.
390
414
  `browser_accessibility_snapshot`, `browser_extract`, `browser_extract_content`,
391
415
  `browser_find_text`, `browser_search_page`, `browser_find_elements`,
392
416
  `browser_dropdown_options`, `browser_computed_style`, `browser_page_next`,
393
- `browser_get_html`, `browser_challenge`, `browser_doctor`, and `server_health`.
417
+ `browser_get_html`, `browser_search_network_log`, `browser_inspect_element`,
418
+ `browser_challenge`, `browser_doctor`, and `server_health`.
394
419
 
395
420
  **Navigation and interaction:** `browser_navigate`, `browser_back`,
396
421
  `browser_go_back`, `browser_forward`, `browser_reload`, `browser_switch_tab`,
@@ -402,19 +427,30 @@ individual descriptions and limits are returned by `tools/list`.
402
427
 
403
428
  **Available local capabilities:** `browser_screenshot`, `browser_pdf`,
404
429
  `browser_upload`, `browser_downloads`, `browser_network_log`,
405
- `browser_console_log`, `browser_dialog`, `browser_cookies`, `browser_storage`,
430
+ `browser_search_network_log`, `browser_resource_blocking`, `browser_console_log`,
431
+ `browser_dialog`, `browser_cookies`, `browser_storage`,
406
432
  `browser_batch`, `browser_exec`, `browser_wait_for_human`,
407
433
  `browser_solve_challenge`, and all other browser tools are available by default.
408
434
  `browser_close_session` remains a local lifecycle control and does not change
409
435
  browser permissions. Page evaluation is available by default and can be
410
436
  disabled explicitly with `SMOOTH_OPERATOR_ALLOW_EVAL=false`.
411
437
 
438
+ `server_health` returns a bounded readiness projection in addition to the
439
+ capabilities metadata. `status` is `ok` when the runtime is ready, `degraded`
440
+ when browser recovery is required or its managed profile lease is not held,
441
+ and `shutting_down` during teardown. The browser check reports `disabled`,
442
+ `idle`, `connected`, `profile_unavailable`, or `recovery_required`; an idle
443
+ browser is expected because browser startup is lazy. Health checks do not
444
+ acquire a profile lease; the next browser operation retries acquisition.
445
+ `ready` reports readiness based on the runtime's current ownership state.
446
+
412
447
  `browser_evaluate` is page JavaScript and is available by default (set
413
448
  `SMOOTH_OPERATOR_ALLOW_EVAL=false` when it is not wanted). `browser_exec`
414
449
  accepts only a JSON array of validated browser actions; it is not a shell,
415
450
  Python, or arbitrary code runner. Its explicit `evaluate` action still follows
416
451
  the page-evaluation policy. Destructive batch actions require explicit
417
- confirmation. `browser_wait_for_human` pauses for an operator to complete a
452
+ confirmation. There is no generic arbitrary CDP command or host-code execution
453
+ tool. `browser_wait_for_human` pauses for an operator to complete a
418
454
  visible sign-in or challenge. `browser_solve_challenge` is an internal
419
455
  connected-AI observe/act/verify loop: it returns bounded evidence and is
420
456
  successful only when a fresh final classification explicitly reports the
@@ -431,6 +467,18 @@ revision. A snapshot failure is reported as `snapshot: null` with a bounded
431
467
  accepts the same option at the top level and captures only one snapshot after
432
468
  the final action.
433
469
 
470
+ The current-page observation tools `browser_interactive`, `browser_frames`,
471
+ `browser_page_info`, and `browser_challenge` accept an optional `pageId`; omit
472
+ it to use the active tab. `browser_accessibility_snapshot` also accepts an
473
+ optional `frameId`, which is useful when the accessible content is inside a
474
+ same-page frame.
475
+
476
+ Passive text and accessibility observations omit form values and textarea
477
+ defaults, including editable control descendants in the accessibility tree.
478
+ Controls keep their labels, roles, and state so they remain actionable through
479
+ fresh refs. Use the explicit page-evaluation capability when reading a value
480
+ is part of the authorized task.
481
+
434
482
  `browser_extract` returns `offset`, `nextOffset`, `hasMore`, and `revision`.
435
483
  Use `browser_page_next` with the returned offset and revision; a stale revision
436
484
  returns the retryable `STALE_PAGE_SLICE` error instead of silently overlapping
@@ -445,6 +493,16 @@ network-log, and console-log operations are normalized before validation;
445
493
  conflicting alias and canonical fields fail with their action index and field
446
494
  names. A failed batch preserves bounded completed results and reports
447
495
  `failedIndex`, `failedAction`, and `completedActions`.
496
+ Action-specific fields are also validated after alias normalization; a field
497
+ that the selected action cannot consume is rejected instead of being silently
498
+ ignored.
499
+
500
+ Each batch step enforces its own `timeoutMs` or the configured action deadline.
501
+ The total batch budget includes the individual step budgets. A step that
502
+ ignores cancellation is retired before the browser queue advances; subsequent
503
+ steps do not execute after a failure. Without an explicit deadline, requested
504
+ wait/hold durations are added to the setup budget, and human handoff retains
505
+ its documented 120-second default.
448
506
 
449
507
  If browser teardown times out or fails, later browser work returns the
450
508
  retryable `BROWSER_RECOVERY_REQUIRED` error. Call `browser_close_session` to
@@ -461,6 +519,38 @@ credentials/query secret placeholders are removed from result URLs. Transient
461
519
  retrieval failures use at most three bounded attempts; anti-bot responses are
462
520
  reported without attempting a bypass.
463
521
 
522
+ ### Network, inspection, resource, and file controls
523
+
524
+ `browser_network_log` records bounded request/response metadata for the current
525
+ page. `browser_search_network_log` filters and paginates that metadata by
526
+ request ID, URL, method, status, and resource type. Headers, cookies, request
527
+ bodies, and response bodies are not returned; search terms and URLs are treated
528
+ as untrusted data and secret query values are redacted.
529
+
530
+ `browser_resource_blocking` is page-scoped with strict `get`, `set`, and
531
+ `clear` operations. Its only selectable types are `image`, `stylesheet`,
532
+ `font`, `media`, and `script`; `set` requires a non-empty de-duplicated list.
533
+ Only matching subresources are aborted once. Document and navigation requests
534
+ cannot be selected, data/blob subresources remain covered by the normal rules,
535
+ and non-blocked requests still run the full URL policy.
536
+
537
+ `browser_inspect_element` returns a bounded safe view of a selected element:
538
+ allowlisted attributes, selected computed styles, pseudo-element summaries,
539
+ animation metadata, and shallow child structure. Script text, event-handler
540
+ source, form values, and arbitrary data attributes are omitted.
541
+
542
+ `browser_upload` accepts the existing single `filePath` or a `filePaths` array
543
+ of up to 20 paths, but not both. Every source must pass the allowed-root,
544
+ no-follow, and file-identity checks. Each file is at most 50 MiB and the
545
+ aggregate is at most 100 MiB; multiple paths require a target input with the
546
+ `multiple` attribute. Sources are staged sequentially and every staging path is
547
+ removed on success, validation failure, target failure, cancellation, or upload
548
+ rejection.
549
+
550
+ `browser_cookies` scopes reads, writes, and deletes to a validated page URL.
551
+ Writes accept only the `Strict`, `Lax`, or `None` SameSite values, and cookie
552
+ values are omitted from read results.
553
+
464
554
  ### Resources
465
555
 
466
556
  The server publishes read-only resources:
@@ -476,9 +566,10 @@ The server publishes read-only resources:
476
566
  Resource output is bounded and follows the same redaction and policy rules as
477
567
  tool output. The capabilities resource also reports the native defaults and
478
568
  effective feature flags for local browser tools, page evaluation, stealth, and
479
- behavioral timing. Its challenge metadata includes the default and maximum
480
- connected-AI attempt budgets and states that success requires an explicit
481
- absent classification.
569
+ behavioral timing. Its `limits` metadata publishes the page-text, action-plan,
570
+ research, and upload budgets used by the public boundary. Its challenge
571
+ metadata includes the default and maximum connected-AI attempt budgets and
572
+ states that success requires an explicit absent classification.
482
573
 
483
574
  ### Prompts
484
575
 
@@ -494,9 +585,10 @@ data directories, constructs the runtime, and registers the MCP surface. The
494
585
  browser is connected or launched only when a browser operation requires it.
495
586
 
496
587
  On SIGINT/SIGTERM, the server stops accepting HTTP requests, waits for active
497
- requests up to a bounded grace period, closes the MCP transport, closes pages,
498
- and terminates a browser process that it owns. A browser connected in `connect`
499
- mode remains under the operator's ownership.
588
+ requests up to a bounded grace period, cancels in-flight research retrieval,
589
+ closes the MCP transport, closes pages, and terminates a browser process that
590
+ it owns. A browser connected in `connect` mode remains under the operator's
591
+ ownership.
500
592
 
501
593
  To clean up a local installation:
502
594
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "smooth-operator-mcp",
3
- "version": "3.0.5",
3
+ "version": "3.1.0",
4
4
  "type": "module",
5
5
  "packageManager": "npm@12.0.2",
6
6
  "description": "A lightweight, production-grade MCP server for secure browser automation.",
@@ -13,6 +13,7 @@
13
13
  "dist",
14
14
  "docs/mcp-server.md",
15
15
  "docs/harnesses.md",
16
+ "docs/STEALTH-GUIDE.md",
16
17
  "README.md",
17
18
  "LICENSE",
18
19
  ".env.example"
@@ -25,12 +26,15 @@
25
26
  "dev": "tsx watch src/server/main.ts",
26
27
  "build": "node scripts/build.mjs",
27
28
  "postbuild": "node scripts/set-executable.mjs dist/smooth-operator.mjs",
28
- "lint": "eslint .",
29
+ "lint": "eslint . --ignore-pattern scripts/benchmark-network-journal.ts",
29
30
  "typecheck": "tsc --noEmit",
30
31
  "test": "vitest run",
32
+ "test:unit": "vitest run --exclude tests/browser-live.test.ts",
33
+ "benchmark:network": "tsx scripts/benchmark-network-journal.ts",
31
34
  "test:browser:live": "node scripts/test-browser-live.mjs",
32
35
  "test:watch": "vitest",
33
36
  "test:coverage": "vitest run --coverage",
37
+ "verify": "npm run lint && npm run typecheck && npm test && npm run dead-code && npm run package:smoke",
34
38
  "dead-code": "knip --include files,exports,dependencies,unlisted --no-progress",
35
39
  "mcp:stdio": "npm run start -- --transport stdio",
36
40
  "mcp:http": "npm run start -- --transport http",
@@ -41,11 +45,11 @@
41
45
  "prepare": "npm run build"
42
46
  },
43
47
  "dependencies": {
44
- "@modelcontextprotocol/node": "^2.0.0",
45
- "@modelcontextprotocol/server": "^2.0.0",
46
- "ghost-cursor": "^1.4.2",
47
- "puppeteer-core": "^25.9.0",
48
- "zod": "^4.4.3"
48
+ "@modelcontextprotocol/node": "2.0.0",
49
+ "@modelcontextprotocol/server": "2.0.0",
50
+ "ghost-cursor": "1.4.2",
51
+ "puppeteer-core": "25.10.0",
52
+ "zod": "4.5.4"
49
53
  },
50
54
  "devDependencies": {
51
55
  "@modelcontextprotocol/client": "^2.0.0",
@@ -60,6 +64,10 @@
60
64
  "typescript": "^6.0.3",
61
65
  "vitest": "^4.1.11"
62
66
  },
67
+ "allowScripts": {
68
+ "esbuild@0.28.2": true,
69
+ "fsevents@2.3.3": true
70
+ },
63
71
  "engines": {
64
72
  "node": ">=22.23.2",
65
73
  "npm": ">=12.0.2"