smooth-operator-mcp 3.0.6 → 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.
- package/README.md +9 -2
- package/dist/smooth-operator.mjs +952 -253
- package/dist/smooth-operator.mjs.map +2 -2
- package/docs/STEALTH-GUIDE.md +84 -0
- package/docs/mcp-server.md +47 -6
- package/package.json +10 -3
|
@@ -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/mcp-server.md
CHANGED
|
@@ -337,6 +337,14 @@ variables include:
|
|
|
337
337
|
| `SMOOTH_OPERATOR_ALLOWED_ORIGINS` | `localhost,127.0.0.1,[::1]` | HTTP Origin allowlist |
|
|
338
338
|
| `SMOOTH_OPERATOR_LOG_LEVEL` | `info` | `debug`, `info`, `warn`, or `error` |
|
|
339
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
|
+
|
|
340
348
|
### Fast operation mode
|
|
341
349
|
|
|
342
350
|
The default configuration is a native managed browser with page evaluation
|
|
@@ -427,6 +435,15 @@ individual descriptions and limits are returned by `tools/list`.
|
|
|
427
435
|
browser permissions. Page evaluation is available by default and can be
|
|
428
436
|
disabled explicitly with `SMOOTH_OPERATOR_ALLOW_EVAL=false`.
|
|
429
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
|
+
|
|
430
447
|
`browser_evaluate` is page JavaScript and is available by default (set
|
|
431
448
|
`SMOOTH_OPERATOR_ALLOW_EVAL=false` when it is not wanted). `browser_exec`
|
|
432
449
|
accepts only a JSON array of validated browser actions; it is not a shell,
|
|
@@ -450,6 +467,18 @@ revision. A snapshot failure is reported as `snapshot: null` with a bounded
|
|
|
450
467
|
accepts the same option at the top level and captures only one snapshot after
|
|
451
468
|
the final action.
|
|
452
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
|
+
|
|
453
482
|
`browser_extract` returns `offset`, `nextOffset`, `hasMore`, and `revision`.
|
|
454
483
|
Use `browser_page_next` with the returned offset and revision; a stale revision
|
|
455
484
|
returns the retryable `STALE_PAGE_SLICE` error instead of silently overlapping
|
|
@@ -464,6 +493,16 @@ network-log, and console-log operations are normalized before validation;
|
|
|
464
493
|
conflicting alias and canonical fields fail with their action index and field
|
|
465
494
|
names. A failed batch preserves bounded completed results and reports
|
|
466
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.
|
|
467
506
|
|
|
468
507
|
If browser teardown times out or fails, later browser work returns the
|
|
469
508
|
retryable `BROWSER_RECOVERY_REQUIRED` error. Call `browser_close_session` to
|
|
@@ -527,9 +566,10 @@ The server publishes read-only resources:
|
|
|
527
566
|
Resource output is bounded and follows the same redaction and policy rules as
|
|
528
567
|
tool output. The capabilities resource also reports the native defaults and
|
|
529
568
|
effective feature flags for local browser tools, page evaluation, stealth, and
|
|
530
|
-
behavioral timing. Its
|
|
531
|
-
|
|
532
|
-
|
|
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.
|
|
533
573
|
|
|
534
574
|
### Prompts
|
|
535
575
|
|
|
@@ -545,9 +585,10 @@ data directories, constructs the runtime, and registers the MCP surface. The
|
|
|
545
585
|
browser is connected or launched only when a browser operation requires it.
|
|
546
586
|
|
|
547
587
|
On SIGINT/SIGTERM, the server stops accepting HTTP requests, waits for active
|
|
548
|
-
requests up to a bounded grace period,
|
|
549
|
-
|
|
550
|
-
mode remains under the operator's
|
|
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.
|
|
551
592
|
|
|
552
593
|
To clean up a local installation:
|
|
553
594
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "smooth-operator-mcp",
|
|
3
|
-
"version": "3.0
|
|
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"
|
|
@@ -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.
|
|
49
|
-
"zod": "4.4
|
|
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"
|