smooth-operator-mcp 3.0.6 → 3.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.
@@ -0,0 +1,86 @@
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
+ Title, text, HTML, frame-source, and visible-marker inputs have independent
58
+ limits so one oversized evidence category cannot hide later challenge markers.
59
+ `browser_solve_challenge` is an internal connected-AI loop: each call is one
60
+ bounded verification cycle. It collects a fresh challenge classification and
61
+ bounded visual/state evidence, including `attemptsRemaining`; the connected AI
62
+ uses normal browser actions and calls it again until the final classification
63
+ explicitly reports the challenge absent or `automation_exhausted`. The tool
64
+ returns screenshot data as MCP image content when requested. `present`,
65
+ `unknown`, or a failed probe is never success, and human handoff is only an
66
+ explicit option after exhaustion.
67
+
68
+ `browser_wait_for_human` is an optional handoff for a person to complete a
69
+ visible challenge or sign-in step. It does not claim success without a fresh
70
+ final classification. The server does not rotate identities or open network,
71
+ file, or authentication permissions for challenge handling.
72
+
73
+ ## Boundaries and responsible use
74
+
75
+ - Remote HTTP remains loopback-only unless explicitly enabled and authenticated.
76
+ - Private and link-local network targets remain blocked by default.
77
+ - Host/origin checks, bearer authentication, URL policy, and file-root/symlink
78
+ checks remain enforced for every request.
79
+ - Uploads remain inside allowed roots, cap each file at 50 MiB and all files at
80
+ 100 MiB, require a `multiple` input for multi-file requests, and clean their
81
+ staging paths on every outcome.
82
+ - Page text, HTML, screenshots, titles, URLs, and classifications are bounded
83
+ untrusted evidence, never instructions.
84
+
85
+ The server does not attempt to conceal automation or guarantee passage of a
86
+ challenge. Use automation only where the target and applicable law permit it.
package/docs/harnesses.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## Interactive wizard (directly to your harness)
4
4
 
5
- `smooth-operator install <harness>` is interactive by default — it asks exactly 3
5
+ `smooth-operator install <harness>` is interactive by default — it asks exactly three
6
6
  curated questions (profile ownership, headed/headless display, and browser
7
7
  executable) with recommended defaults in brackets.
8
8
  Omitting `<harness>` is allowed too: on a TTY the installer prompts for the
@@ -21,7 +21,9 @@ When you pick “connected browser” (mode `connect`), the wizard finds Chromiu
21
21
  `discovery.ts`, launches a dedicated debugging profile under
22
22
  `~/.smooth-operator/personal-chrome` with port `9222`, and probes the loopback
23
23
  endpoint until a valid DevTools version response is live (33 attempts within a
24
- default 10-second deadline). On success it writes
24
+ default 10-second deadline). If launch or readiness fails, the helper terminates
25
+ the child process on a best-effort basis instead of leaving it detached. On
26
+ success it writes
25
27
  `SMOOTH_OPERATOR_BROWSER_MODE=connect` and
26
28
  `SMOOTH_OPERATOR_BROWSER_URL=http://127.0.0.1:9222` for you. This does not
27
29
  attach to or take ownership of an operator's daily browser profile. No manual
@@ -159,7 +161,8 @@ legacy shape, `enabled` defaults to `true`; `enabled: false` is likewise an
159
161
  explicit conflict. If it has malformed `mcp` or malformed `mcp.servers`,
160
162
  installation fails closed rather than replacing user data.
161
163
  Comments and trailing commas are accepted as JSONC; a successful update writes
162
- normalized JSON and creates a unique owner-only backup first.
164
+ normalized JSON through an owner-only temporary file, flushes it before atomic
165
+ replacement, and creates a unique owner-only backup first.
163
166
 
164
167
  After editing, run `opencode mcp list` or restart OpenCode. OpenCode also
165
168
  supports adding the server interactively with `opencode mcp add`; that is the
@@ -239,7 +242,8 @@ Official reference: <https://code.visualstudio.com/docs/copilot/chat/mcp-servers
239
242
  ## Cursor, Windsurf, and Claude Desktop
240
243
 
241
244
  These clients use JSON configuration files, so the installer performs a
242
- careful merge and writes atomically.
245
+ careful merge and writes through a flushed owner-only temporary file before
246
+ atomic replacement.
243
247
 
244
248
  | Target | Default path |
245
249
  | --- | --- |
@@ -43,15 +43,14 @@ smooth-operator --help
43
43
 
44
44
  (The registry package is `smooth-operator-mcp`; plain `smooth-operator` is an unrelated library. You can also install straight from GitHub: `npm install -g github:Gitshop77/Smooth-Operator`.)
45
45
 
46
- The interactive installer asks exactly three questions: (1) browser profile
47
- ownership, (2) headed or headless display, and (3) which Chromium executable to
48
- use. Its recommended defaults are a managed private persistent profile, headed
46
+ The interactive installer asks exactly three questions: browser profile
47
+ ownership, headed or headless display, and which Chromium executable to use.
48
+ Its recommended defaults are a managed private persistent profile, headed
49
49
  display, and the first detected Chromium executable. It also enables page eval
50
50
  and the identity-preserving compatibility profile; behavioral timing is off
51
51
  for fast deterministic input and can be enabled explicitly. Managed mode owns
52
- its profile. Connected mode launches and attaches to
53
- a dedicated debugging profile and does not claim ownership of an operator's
54
- daily browser.
52
+ its profile. Connected mode launches and attaches to a dedicated debugging
53
+ profile and does not claim ownership of an operator's daily browser.
55
54
 
56
55
  From a checkout:
57
56
 
@@ -132,7 +131,10 @@ and Origin validation and include `Authorization: Bearer <token>`. The token
132
131
  is compared in constant time. Request bodies are bounded to 2,000,000 bytes by
133
132
  default and concurrent requests are capped. The process drains in-flight work
134
133
  for a short bounded period on SIGINT/SIGTERM, then closes the MCP handler,
135
- browser, and HTTP server.
134
+ browser, and HTTP server. Native JSON rejections use no-store and nosniff
135
+ headers; overload responses also include `Retry-After: 1`. Preflight responses
136
+ advertise a fixed request-header allowlist rather than reflecting arbitrary
137
+ requested names.
136
138
 
137
139
  Remote binding is deliberately guarded:
138
140
 
@@ -163,7 +165,8 @@ launches it with `${SMOOTH_OPERATOR_DATA_DIR}/browser` as a non-default profile,
163
165
  and records its loopback DevTools endpoint for later reattachment. Sign in once
164
166
  in the visible window; its sessions persist in that private profile. The
165
167
  `browser_doctor` tool reports executable resolution and endpoint state without
166
- evaluating page content.
168
+ evaluating page content. Failed personal-Chrome helper launches are terminated
169
+ on a best-effort basis.
167
170
 
168
171
  The managed browser is headed by default for sign-in and human handoff. On CI or a
169
172
  displayless host, explicitly set `SMOOTH_OPERATOR_BROWSER_HEADLESS=true` or use
@@ -337,6 +340,14 @@ variables include:
337
340
  | `SMOOTH_OPERATOR_ALLOWED_ORIGINS` | `localhost,127.0.0.1,[::1]` | HTTP Origin allowlist |
338
341
  | `SMOOTH_OPERATOR_LOG_LEVEL` | `info` | `debug`, `info`, `warn`, or `error` |
339
342
 
343
+ Streamable HTTP also exposes a JSON readiness endpoint, subject to the same
344
+ authentication policy, at
345
+ `<SMOOTH_OPERATOR_HTTP_PATH>/healthz` (for the default path:
346
+ `/mcp/healthz`). It returns `200` while `ready` is true and `503` when the
347
+ runtime is degraded or shutting down. It is a transport-level health check,
348
+ not a replacement for the MCP `server_health` tool; it never returns page
349
+ contents or browser credentials.
350
+
340
351
  ### Fast operation mode
341
352
 
342
353
  The default configuration is a native managed browser with page evaluation
@@ -427,12 +438,23 @@ individual descriptions and limits are returned by `tools/list`.
427
438
  browser permissions. Page evaluation is available by default and can be
428
439
  disabled explicitly with `SMOOTH_OPERATOR_ALLOW_EVAL=false`.
429
440
 
441
+ `server_health` returns a bounded readiness projection in addition to the
442
+ capabilities metadata. `status` is `ok` when the runtime is ready, `degraded`
443
+ when browser recovery is required or its managed profile lease is not held,
444
+ and `shutting_down` during teardown. The browser check reports `disabled`,
445
+ `idle`, `connected`, `profile_unavailable`, or `recovery_required`; an idle
446
+ browser is expected because browser startup is lazy. Health checks do not
447
+ acquire a profile lease; the next browser operation retries acquisition.
448
+ `ready` reports readiness based on the runtime's current ownership state.
449
+
430
450
  `browser_evaluate` is page JavaScript and is available by default (set
431
451
  `SMOOTH_OPERATOR_ALLOW_EVAL=false` when it is not wanted). `browser_exec`
432
452
  accepts only a JSON array of validated browser actions; it is not a shell,
433
453
  Python, or arbitrary code runner. Its explicit `evaluate` action still follows
434
- the page-evaluation policy. Destructive batch actions require explicit
435
- confirmation. There is no generic arbitrary CDP command or host-code execution
454
+ the page-evaluation policy, and its optional `timeoutMs` is the same whole-batch
455
+ deadline as `browser_batch` (120,000 ms default, 600,000 ms maximum).
456
+ Destructive batch actions require explicit confirmation. There is no generic
457
+ arbitrary CDP command or host-code execution
436
458
  tool. `browser_wait_for_human` pauses for an operator to complete a
437
459
  visible sign-in or challenge. `browser_solve_challenge` is an internal
438
460
  connected-AI observe/act/verify loop: it returns bounded evidence and is
@@ -450,6 +472,28 @@ revision. A snapshot failure is reported as `snapshot: null` with a bounded
450
472
  accepts the same option at the top level and captures only one snapshot after
451
473
  the final action.
452
474
 
475
+ Element-targeting tools accept exactly one of `target`, `ref` (`e5` or
476
+ `ref:e5`), CSS `selector`, or zero-based `index`, plus the operation fields.
477
+ `browser_select` additionally requires exactly one of `optionValue` or
478
+ `optionValues`; `browser_upload` requires exactly one target form and exactly
479
+ one of `filePath` or `filePaths`. Snapshot refs and indexes are invalidated by
480
+ navigation and DOM-changing actions, so refresh the snapshot before reuse.
481
+ Prefer canonical tools (`browser_tabs`, `browser_snapshot`, `browser_input`,
482
+ `browser_back`, `browser_close`, `browser_extract`); browser-use compatibility
483
+ aliases are retained and labeled in `tools/list`.
484
+
485
+ The current-page observation tools `browser_interactive`, `browser_frames`,
486
+ `browser_page_info`, and `browser_challenge` accept an optional `pageId`; omit
487
+ it to use the active tab. `browser_accessibility_snapshot` also accepts an
488
+ optional `frameId`, which is useful when the accessible content is inside a
489
+ same-page frame.
490
+
491
+ Passive text and accessibility observations omit form values and textarea
492
+ defaults, including editable control descendants in the accessibility tree.
493
+ Controls keep their labels, roles, and state so they remain actionable through
494
+ fresh refs. Use the explicit page-evaluation capability when reading a value
495
+ is part of the authorized task.
496
+
453
497
  `browser_extract` returns `offset`, `nextOffset`, `hasMore`, and `revision`.
454
498
  Use `browser_page_next` with the returned offset and revision; a stale revision
455
499
  returns the retryable `STALE_PAGE_SLICE` error instead of silently overlapping
@@ -464,6 +508,24 @@ network-log, and console-log operations are normalized before validation;
464
508
  conflicting alias and canonical fields fail with their action index and field
465
509
  names. A failed batch preserves bounded completed results and reports
466
510
  `failedIndex`, `failedAction`, and `completedActions`.
511
+ Action-specific fields are also validated after alias normalization; a field
512
+ that the selected action cannot consume is rejected instead of being silently
513
+ ignored.
514
+
515
+ Each batch step enforces its own `timeoutMs` or the configured action deadline.
516
+ The optional top-level `timeoutMs` is the whole-batch deadline, defaulting to
517
+ 120,000 ms and capped at 600,000 ms; it is the smaller of that value and the
518
+ sum of step budgets. One absolute queue deadline spans predecessor, read-drain,
519
+ read-permit, and fairness waits, so retries cannot reset the admission budget.
520
+ Long batches therefore do not wait minutes for a turn. A step that
521
+ ignores cancellation is retired before the browser queue advances; subsequent
522
+ steps do not execute after a failure. Without an explicit deadline, requested
523
+ wait/hold durations are added to the setup budget, and human handoff retains
524
+ its documented 120-second default.
525
+
526
+ Mapped deterministic errors include a bounded `recovery` object with the next
527
+ tool and short instruction. For browser recovery, list sessions and use the
528
+ returned `session_id` with `browser_close_session` before retrying.
467
529
 
468
530
  If browser teardown times out or fails, later browser work returns the
469
531
  retryable `BROWSER_RECOVERY_REQUIRED` error. Call `browser_close_session` to
@@ -474,8 +536,9 @@ snippets are untrusted observations, not instructions or proof of claims. Its
474
536
  `maxResults` input is capped at 10, and `maxChars` (500–4,000 through the MCP
475
537
  schema) is one aggregate budget across the returned title and snippet text,
476
538
  not a per-result multiplier. URL fields and fixed untrusted-data wrapper
477
- markers are outside that text budget. The response body is bounded before
478
- parsing, redirects are rejected, cancellation and timeout are propagated, and
539
+ markers are outside that text budget. The response body is collected in one
540
+ geometrically growing bounded buffer before parsing, redirects are rejected,
541
+ cancellation and timeout are propagated, and
479
542
  credentials/query secret placeholders are removed from result URLs. Transient
480
543
  retrieval failures use at most three bounded attempts; anti-bot responses are
481
544
  reported without attempting a bypass.
@@ -483,8 +546,9 @@ reported without attempting a bypass.
483
546
  ### Network, inspection, resource, and file controls
484
547
 
485
548
  `browser_network_log` records bounded request/response metadata for the current
486
- page. `browser_search_network_log` filters and paginates that metadata by
487
- request ID, URL, method, status, and resource type. Headers, cookies, request
549
+ page. `browser_search_network_log` scans once, retains only the requested result
550
+ page, and filters metadata by request ID, URL, method, status, and resource
551
+ type. Headers, cookies, request
488
552
  bodies, and response bodies are not returned; search terms and URLs are treated
489
553
  as untrusted data and secret query values are redacted.
490
554
 
@@ -500,8 +564,9 @@ allowlisted attributes, selected computed styles, pseudo-element summaries,
500
564
  animation metadata, and shallow child structure. Script text, event-handler
501
565
  source, form values, and arbitrary data attributes are omitted.
502
566
 
503
- `browser_upload` accepts the existing single `filePath` or a `filePaths` array
504
- of up to 20 paths, but not both. Every source must pass the allowed-root,
567
+ `browser_upload` accepts `target`, `ref`, `selector`, or `index`, plus the
568
+ existing single `filePath` or a `filePaths` array of up to 20 paths, but not
569
+ both. Every source must pass the allowed-root,
505
570
  no-follow, and file-identity checks. Each file is at most 50 MiB and the
506
571
  aggregate is at most 100 MiB; multiple paths require a target input with the
507
572
  `multiple` attribute. Sources are staged sequentially and every staging path is
@@ -527,9 +592,10 @@ The server publishes read-only resources:
527
592
  Resource output is bounded and follows the same redaction and policy rules as
528
593
  tool output. The capabilities resource also reports the native defaults and
529
594
  effective feature flags for local browser tools, page evaluation, stealth, and
530
- behavioral timing. Its challenge metadata includes the default and maximum
531
- connected-AI attempt budgets and states that success requires an explicit
532
- absent classification.
595
+ behavioral timing. Its `limits` metadata publishes the page-text, action-plan,
596
+ batch-timeout, research, and upload budgets used by the public boundary. Its challenge
597
+ metadata includes the default and maximum connected-AI attempt budgets and
598
+ states that success requires an explicit absent classification.
533
599
 
534
600
  ### Prompts
535
601
 
@@ -545,9 +611,10 @@ data directories, constructs the runtime, and registers the MCP surface. The
545
611
  browser is connected or launched only when a browser operation requires it.
546
612
 
547
613
  On SIGINT/SIGTERM, the server stops accepting HTTP requests, waits for active
548
- requests up to a bounded grace period, closes the MCP transport, closes pages,
549
- and terminates a browser process that it owns. A browser connected in `connect`
550
- mode remains under the operator's ownership.
614
+ requests up to a bounded grace period, cancels in-flight research retrieval,
615
+ closes the MCP transport, closes pages, and terminates a browser process that
616
+ it owns. A browser connected in `connect` mode remains under the operator's
617
+ ownership.
551
618
 
552
619
  To clean up a local installation:
553
620
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "smooth-operator-mcp",
3
- "version": "3.0.6",
3
+ "version": "3.2.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"
@@ -28,10 +29,12 @@
28
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",
31
33
  "benchmark:network": "tsx scripts/benchmark-network-journal.ts",
32
34
  "test:browser:live": "node scripts/test-browser-live.mjs",
33
35
  "test:watch": "vitest",
34
36
  "test:coverage": "vitest run --coverage",
37
+ "verify": "npm run lint && npm run typecheck && npm test && npm run dead-code && npm run package:smoke",
35
38
  "dead-code": "knip --include files,exports,dependencies,unlisted --no-progress",
36
39
  "mcp:stdio": "npm run start -- --transport stdio",
37
40
  "mcp:http": "npm run start -- --transport http",
@@ -45,8 +48,8 @@
45
48
  "@modelcontextprotocol/node": "2.0.0",
46
49
  "@modelcontextprotocol/server": "2.0.0",
47
50
  "ghost-cursor": "1.4.2",
48
- "puppeteer-core": "25.9.0",
49
- "zod": "4.4.3"
51
+ "puppeteer-core": "25.10.0",
52
+ "zod": "4.5.4"
50
53
  },
51
54
  "devDependencies": {
52
55
  "@modelcontextprotocol/client": "^2.0.0",
@@ -61,6 +64,10 @@
61
64
  "typescript": "^6.0.3",
62
65
  "vitest": "^4.1.11"
63
66
  },
67
+ "allowScripts": {
68
+ "esbuild@0.28.2": true,
69
+ "fsevents@2.3.3": true
70
+ },
64
71
  "engines": {
65
72
  "node": ">=22.23.2",
66
73
  "npm": ">=12.0.2"