patchright-cli 0.6.0__tar.gz → 0.8.0__tar.gz
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.
- {patchright_cli-0.6.0 → patchright_cli-0.8.0}/.claude-plugin/marketplace.json +1 -1
- {patchright_cli-0.6.0 → patchright_cli-0.8.0}/.gitignore +2 -0
- {patchright_cli-0.6.0 → patchright_cli-0.8.0}/CLAUDE.md +2 -2
- patchright_cli-0.8.0/GLOSSARY.md +58 -0
- {patchright_cli-0.6.0 → patchright_cli-0.8.0}/PKG-INFO +56 -7
- {patchright_cli-0.6.0 → patchright_cli-0.8.0}/README.md +51 -5
- patchright_cli-0.8.0/docs/mcp-architecture.svg +120 -0
- {patchright_cli-0.6.0 → patchright_cli-0.8.0}/pyproject.toml +6 -1
- {patchright_cli-0.6.0 → patchright_cli-0.8.0}/skills/patchright-cli/SKILL.md +171 -12
- patchright_cli-0.8.0/skills/patchright-cli/references/session-management.md +172 -0
- {patchright_cli-0.6.0 → patchright_cli-0.8.0}/skills/patchright-cli/references/snapshot-refs.md +56 -0
- {patchright_cli-0.6.0 → patchright_cli-0.8.0}/skills/patchright-cli/references/video-recording.md +31 -0
- {patchright_cli-0.6.0 → patchright_cli-0.8.0}/src/patchright_cli/__init__.py +1 -1
- {patchright_cli-0.6.0 → patchright_cli-0.8.0}/src/patchright_cli/cli.py +334 -17
- {patchright_cli-0.6.0 → patchright_cli-0.8.0}/src/patchright_cli/daemon.py +1291 -149
- patchright_cli-0.8.0/src/patchright_cli/dashboard.py +443 -0
- patchright_cli-0.8.0/src/patchright_cli/mcp_server.py +1325 -0
- patchright_cli-0.8.0/src/patchright_cli/ref_registry.py +316 -0
- {patchright_cli-0.6.0 → patchright_cli-0.8.0}/src/patchright_cli/snapshot.py +1 -1
- patchright_cli-0.8.0/tests/test_annotate.py +357 -0
- patchright_cli-0.8.0/tests/test_attach.py +455 -0
- patchright_cli-0.8.0/tests/test_cli_config.py +630 -0
- patchright_cli-0.8.0/tests/test_daemon_handlers.py +1239 -0
- {patchright_cli-0.6.0 → patchright_cli-0.8.0}/tests/test_e2e.py +94 -0
- patchright_cli-0.8.0/tests/test_mcp.py +172 -0
- patchright_cli-0.8.0/tests/test_packaging.py +39 -0
- patchright_cli-0.8.0/tests/test_profiles.py +430 -0
- patchright_cli-0.8.0/tests/test_ref_registry.py +522 -0
- patchright_cli-0.8.0/tests/test_tabs.py +401 -0
- patchright_cli-0.8.0/uv.lock +2953 -0
- patchright_cli-0.6.0/skills/patchright-cli/references/session-management.md +0 -106
- patchright_cli-0.6.0/src/patchright_cli/dashboard.py +0 -135
- patchright_cli-0.6.0/src/patchright_cli/ref_registry.py +0 -106
- patchright_cli-0.6.0/tests/test_cli_config.py +0 -203
- patchright_cli-0.6.0/tests/test_daemon_handlers.py +0 -543
- patchright_cli-0.6.0/tests/test_ref_registry.py +0 -137
- patchright_cli-0.6.0/uv.lock +0 -1154
- {patchright_cli-0.6.0 → patchright_cli-0.8.0}/.claude-plugin/skills/browser-automation.json +0 -0
- {patchright_cli-0.6.0 → patchright_cli-0.8.0}/.github/workflows/ci.yml +0 -0
- {patchright_cli-0.6.0 → patchright_cli-0.8.0}/.github/workflows/publish.yml +0 -0
- {patchright_cli-0.6.0 → patchright_cli-0.8.0}/.pre-commit-config.yaml +0 -0
- {patchright_cli-0.6.0 → patchright_cli-0.8.0}/CONTRIBUTING.md +0 -0
- {patchright_cli-0.6.0 → patchright_cli-0.8.0}/LICENSE +0 -0
- {patchright_cli-0.6.0 → patchright_cli-0.8.0}/Makefile +0 -0
- {patchright_cli-0.6.0 → patchright_cli-0.8.0}/docs/installation.md +0 -0
- {patchright_cli-0.6.0 → patchright_cli-0.8.0}/patchright-cli +0 -0
- {patchright_cli-0.6.0 → patchright_cli-0.8.0}/patchright-cli.cmd +0 -0
- {patchright_cli-0.6.0 → patchright_cli-0.8.0}/skills/patchright-cli/references/request-mocking.md +0 -0
- {patchright_cli-0.6.0 → patchright_cli-0.8.0}/skills/patchright-cli/references/running-code.md +0 -0
- {patchright_cli-0.6.0 → patchright_cli-0.8.0}/skills/patchright-cli/references/storage-state.md +0 -0
- {patchright_cli-0.6.0 → patchright_cli-0.8.0}/skills/patchright-cli/references/tracing.md +0 -0
- {patchright_cli-0.6.0 → patchright_cli-0.8.0}/src/patchright_cli/__main__.py +0 -0
- {patchright_cli-0.6.0 → patchright_cli-0.8.0}/tests/__init__.py +0 -0
- {patchright_cli-0.6.0 → patchright_cli-0.8.0}/tests/fixture.html +0 -0
|
@@ -57,10 +57,10 @@ CLI (cli.py) --TCP:9321--> Daemon (daemon.py) --Patchright--> Chrome
|
|
|
57
57
|
|
|
58
58
|
- Always uses persistent browser context (`launch_persistent_context`) with real Chrome (`channel="chrome"`), not Chromium
|
|
59
59
|
- Headed by default (headless is more detectable)
|
|
60
|
-
- Default daemon port: 9321, profiles stored at `~/.patchright-cli/profiles/<
|
|
60
|
+
- Default daemon port: 9321, profiles stored at `~/.patchright-cli/profiles/<profile-name>`; a session's profile defaults to its session name (`--profile=<name>` overrides, a value with `/` or `\` is a directory). One session per profile at a time
|
|
61
61
|
- CLI-daemon protocol: length-prefixed (4-byte big-endian `!I`) JSON over TCP
|
|
62
62
|
- CLI parses argv manually in `main()` — click is only used for `click.echo()`, not subcommands. New commands must be added to both `COMMANDS_HELP` dict and the `handle_command()` if/elif chain in daemon.py
|
|
63
|
-
- Version must be updated in
|
|
63
|
+
- Version must be updated in `pyproject.toml`, `src/patchright_cli/__init__.py` and `.claude-plugin/marketplace.json` (then run `uv lock` to sync the lock file; `tests/test_packaging.py` checks they match)
|
|
64
64
|
- `python -m patchright_cli` works via `__main__.py`
|
|
65
65
|
- Uses hatchling as build backend, ruff for linting (line-length=120, target py310)
|
|
66
66
|
- Ruff rules: E, F, I, W, UP, B, SIM (ignores E501, SIM105, E402)
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# patchright-cli
|
|
2
|
+
|
|
3
|
+
An anti-detect browser automation CLI: callers drive real Chrome through short commands sent to a long-running daemon.
|
|
4
|
+
|
|
5
|
+
## Sessions and browsers
|
|
6
|
+
|
|
7
|
+
**Session**:
|
|
8
|
+
A named handle on one browser context that callers drive with commands; selected with `-s`.
|
|
9
|
+
_Avoid_: Browser, instance, profile
|
|
10
|
+
|
|
11
|
+
**Default Session**:
|
|
12
|
+
The Session used when no `-s` is given.
|
|
13
|
+
|
|
14
|
+
**Launched Session**:
|
|
15
|
+
A Session whose Chrome patchright-cli started itself and therefore owns outright.
|
|
16
|
+
|
|
17
|
+
**Profile**:
|
|
18
|
+
A named, persistent store of browser state — cookies, storage, logins, history — that a Launched Session runs on; at most one Session uses a Profile at a time. Unless told otherwise, a Session's Profile is named after the Session.
|
|
19
|
+
_Avoid_: User data dir, profile directory, persistent context
|
|
20
|
+
|
|
21
|
+
**Attached Session**:
|
|
22
|
+
A Session connected to a Chrome that something else started, reached over CDP.
|
|
23
|
+
_Avoid_: Connected session, remote session
|
|
24
|
+
|
|
25
|
+
**Host**:
|
|
26
|
+
Whatever started and owns the Chrome an Attached Session connects to — a person, a script, or a product such as a workspace manager.
|
|
27
|
+
_Avoid_: External browser, owner
|
|
28
|
+
|
|
29
|
+
**Host Context**:
|
|
30
|
+
The Host's own browser context, carrying its profile's cookies, storage and logins; at most one Session may use a given Host Context.
|
|
31
|
+
_Avoid_: Default context, existing context, persistent context
|
|
32
|
+
|
|
33
|
+
**Isolated Context**:
|
|
34
|
+
A fresh browser context an Attached Session creates inside the Host's Chrome, sharing none of the Host's state.
|
|
35
|
+
_Avoid_: Incognito context
|
|
36
|
+
|
|
37
|
+
## Tabs and pages
|
|
38
|
+
|
|
39
|
+
**Page**:
|
|
40
|
+
One browser tab as Chrome sees it.
|
|
41
|
+
_Avoid_: Tab (except in the playwright-cli-compatible `tab-*` command names, which act on Pages)
|
|
42
|
+
|
|
43
|
+
**Tab**:
|
|
44
|
+
A named workspace inside a Session — its own Page, element refs and navigation history — selected with `--tab`.
|
|
45
|
+
_Avoid_: Lane, worker
|
|
46
|
+
|
|
47
|
+
**Default Tab**:
|
|
48
|
+
The Tab used when no `--tab` is given; it follows whichever Page is currently selected rather than owning one.
|
|
49
|
+
|
|
50
|
+
## Ending a Session
|
|
51
|
+
|
|
52
|
+
**Close**:
|
|
53
|
+
Ending a Session by destroying what it owns: its Tabs' Pages and, for a context it owns, the context itself.
|
|
54
|
+
_Avoid_: Quit, kill (except `kill-all`)
|
|
55
|
+
|
|
56
|
+
**Detach**:
|
|
57
|
+
Letting go of an Attached Session while leaving the Host's Chrome, and anything the Host owns, untouched.
|
|
58
|
+
_Avoid_: Disconnect, release
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: patchright-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8.0
|
|
4
4
|
Summary: Anti-detect browser automation CLI using Patchright (undetected Playwright fork)
|
|
5
5
|
Project-URL: Homepage, https://github.com/AhaiMk01/patchright-cli
|
|
6
6
|
Project-URL: Repository, https://github.com/AhaiMk01/patchright-cli
|
|
@@ -26,9 +26,12 @@ Requires-Dist: click
|
|
|
26
26
|
Requires-Dist: patchright
|
|
27
27
|
Requires-Dist: pyyaml
|
|
28
28
|
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: fastmcp<5,>=3.0; extra == 'dev'
|
|
29
30
|
Requires-Dist: pre-commit; extra == 'dev'
|
|
30
31
|
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
31
32
|
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
33
|
+
Provides-Extra: mcp
|
|
34
|
+
Requires-Dist: fastmcp<5,>=3.0; extra == 'mcp'
|
|
32
35
|
Description-Content-Type: text/markdown
|
|
33
36
|
|
|
34
37
|
# patchright-cli
|
|
@@ -149,7 +152,7 @@ graph LR
|
|
|
149
152
|
|-----------|------|
|
|
150
153
|
| **Daemon** (`daemon.py`) | Long-running process managing browser sessions via Patchright. Auto-starts on first `open`. |
|
|
151
154
|
| **CLI** (`cli.py`) | Thin client — connects, sends command, prints result, disconnects. Browser stays open. |
|
|
152
|
-
| **Snapshot** (`snapshot.py`) | `
|
|
155
|
+
| **Snapshot** (`snapshot.py`) | Playwright `aria_snapshot()` accessibility tree, annotated with sequential `[ref=eN]` handles for element targeting. |
|
|
153
156
|
|
|
154
157
|
---
|
|
155
158
|
|
|
@@ -159,9 +162,12 @@ graph LR
|
|
|
159
162
|
### Core
|
|
160
163
|
```bash
|
|
161
164
|
patchright-cli open [url] # Launch browser
|
|
162
|
-
patchright-cli open --
|
|
165
|
+
patchright-cli open --profile=work # Named profile any session can use (logins persist)
|
|
163
166
|
patchright-cli open --headless # Run headless
|
|
164
|
-
patchright-cli open --profile
|
|
167
|
+
patchright-cli open --profile=./dir # A value with / or \ is a profile directory
|
|
168
|
+
patchright-cli --tab <name> open <url> # Named tab: shared browser, own page/refs
|
|
169
|
+
patchright-cli open --mobile # Emulate a generic mobile device (Pixel 7)
|
|
170
|
+
patchright-cli open --device="Pixel 5" # Emulate a specific Playwright device
|
|
165
171
|
patchright-cli goto <url> # Navigate
|
|
166
172
|
patchright-cli click <ref> # Click element
|
|
167
173
|
patchright-cli click <ref> right # Right-click
|
|
@@ -180,8 +186,13 @@ patchright-cli drag <from> <to> # Drag and drop
|
|
|
180
186
|
patchright-cli snapshot # Accessibility snapshot
|
|
181
187
|
patchright-cli snapshot -i # Interactive elements only (recommended)
|
|
182
188
|
patchright-cli snapshot --depth=3 # Limit depth
|
|
189
|
+
patchright-cli snapshot --selector=CSS # Snapshot a CSS-scoped subtree
|
|
183
190
|
patchright-cli snapshot <ref> # Snapshot element subtree
|
|
184
191
|
patchright-cli snapshot --filename=f # Save to custom path
|
|
192
|
+
patchright-cli find "text" # Search snapshot for text
|
|
193
|
+
patchright-cli find --regex "a|b" # Search by regex
|
|
194
|
+
patchright-cli find "text" --all # Include text/paragraph nodes
|
|
195
|
+
patchright-cli find "text" --limit=50 # Cap hits (default 20)
|
|
185
196
|
patchright-cli eval <expr> # Run JavaScript
|
|
186
197
|
patchright-cli eval --file=script.js # Run JS from file
|
|
187
198
|
patchright-cli run-code <code> # Run JS with return value
|
|
@@ -190,6 +201,7 @@ patchright-cli screenshot # Page screenshot
|
|
|
190
201
|
patchright-cli screenshot --full-page # Full scrollable page
|
|
191
202
|
patchright-cli screenshot <ref> # Element screenshot
|
|
192
203
|
patchright-cli screenshot --filename=f # Save to custom path
|
|
204
|
+
patchright-cli screenshot --hires # Capture at device pixel ratio
|
|
193
205
|
patchright-cli close # Close session
|
|
194
206
|
```
|
|
195
207
|
|
|
@@ -198,6 +210,10 @@ patchright-cli close # Close session
|
|
|
198
210
|
patchright-cli go-back
|
|
199
211
|
patchright-cli go-forward
|
|
200
212
|
patchright-cli reload
|
|
213
|
+
patchright-cli wait 500 # Wait a fixed number of milliseconds
|
|
214
|
+
patchright-cli wait --url="**/dashboard" # Wait for the URL to match (`*` never crosses a `/`)
|
|
215
|
+
patchright-cli wait-for <ref> # Wait until an element is visible
|
|
216
|
+
patchright-cli wait-for <ref> --state=hidden
|
|
201
217
|
```
|
|
202
218
|
|
|
203
219
|
### Keyboard / Mouse
|
|
@@ -285,6 +301,9 @@ patchright-cli tracing-stop # Saves .zip trace file
|
|
|
285
301
|
patchright-cli video-start # Start video recording (CDP screencast)
|
|
286
302
|
patchright-cli video-stop # Stop and save video (requires ffmpeg for .webm)
|
|
287
303
|
patchright-cli video-stop --filename=recording.webm
|
|
304
|
+
patchright-cli show --annotate # Ask a human to mark up the page, wait for it
|
|
305
|
+
patchright-cli video-show-actions # Annotate each action in the recording
|
|
306
|
+
patchright-cli video-hide-actions # Stop annotating actions
|
|
288
307
|
patchright-cli pdf --filename=page.pdf
|
|
289
308
|
```
|
|
290
309
|
|
|
@@ -317,13 +336,15 @@ patchright-cli install --skills # Auto-install skills for detected AI age
|
|
|
317
336
|
|
|
318
337
|
### Sessions
|
|
319
338
|
```bash
|
|
320
|
-
patchright-cli -s=mysession open https://example.com
|
|
339
|
+
patchright-cli -s=mysession open https://example.com
|
|
321
340
|
patchright-cli -s=mysession click e6
|
|
322
341
|
patchright-cli -s=mysession close
|
|
323
342
|
patchright-cli list # List all sessions
|
|
324
343
|
patchright-cli close-all
|
|
325
344
|
patchright-cli kill-all
|
|
326
|
-
patchright-cli delete-data # Delete
|
|
345
|
+
patchright-cli delete-data # Delete the profile named after the session
|
|
346
|
+
patchright-cli profile-list # Profiles, size, and which session uses each
|
|
347
|
+
patchright-cli profile-delete <name> # Delete an idle named profile
|
|
327
348
|
patchright-cli --port=9322 open # Custom daemon port
|
|
328
349
|
```
|
|
329
350
|
|
|
@@ -354,6 +375,34 @@ patchright-cli install --skills
|
|
|
354
375
|
|
|
355
376
|
</details>
|
|
356
377
|
|
|
378
|
+
### MCP server
|
|
379
|
+
|
|
380
|
+
MCP support is optional so the base CLI install stays small:
|
|
381
|
+
|
|
382
|
+
```bash
|
|
383
|
+
pip install 'patchright-cli[mcp]'
|
|
384
|
+
|
|
385
|
+
# stdio (default)
|
|
386
|
+
patchright-cli mcp
|
|
387
|
+
|
|
388
|
+
# Streamable HTTP
|
|
389
|
+
patchright-cli mcp --http --host=127.0.0.1 --port=8000
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+

|
|
393
|
+
|
|
394
|
+
The HTTP endpoint is `/mcp`. Set `PATCHRIGHT_CLI_MCP_TOKEN` to require `Authorization: Bearer <token>` on every request, and always set it before binding to `0.0.0.0`.
|
|
395
|
+
|
|
396
|
+
File paths passed to MCP tools (uploads, state and cookie files, screenshot/PDF/snapshot output, profile directories) must be absolute and beneath the MCP root, so a client cannot reach arbitrary host files. Outputs without a path land in `<root>/output/`, which `browser_delete_output` can clean up. `patchright_eval` and `patchright_run_code` still run arbitrary JavaScript in the page, so protect HTTP deployments regardless.
|
|
397
|
+
|
|
398
|
+
| Variable | Default | Effect |
|
|
399
|
+
|---|---|---|
|
|
400
|
+
| `PATCHRIGHT_CLI_MCP_TOKEN` | unset (no auth) | Bearer token required by the HTTP transport |
|
|
401
|
+
| `PATCHRIGHT_CLI_MCP_ROOT` | working directory | Root that tool file paths must sit beneath |
|
|
402
|
+
| `PATCHRIGHT_CLI_MCP_UNRESTRICTED_FILESYSTEM` | unset | `1` drops the path check and enables `patchright_install_skills` |
|
|
403
|
+
| `PATCHRIGHT_CLI_MCP_HEADLESS` | unset (headed) | `1` makes `patchright_open` default to headless, for hosts without a display |
|
|
404
|
+
| `PATCHRIGHT_CLI_MCP_DAEMON_PORT` | `9321` | Daemon port the tools talk to |
|
|
405
|
+
|
|
357
406
|
### Skill docs
|
|
358
407
|
|
|
359
408
|
| File | Topic |
|
|
@@ -116,7 +116,7 @@ graph LR
|
|
|
116
116
|
|-----------|------|
|
|
117
117
|
| **Daemon** (`daemon.py`) | Long-running process managing browser sessions via Patchright. Auto-starts on first `open`. |
|
|
118
118
|
| **CLI** (`cli.py`) | Thin client — connects, sends command, prints result, disconnects. Browser stays open. |
|
|
119
|
-
| **Snapshot** (`snapshot.py`) | `
|
|
119
|
+
| **Snapshot** (`snapshot.py`) | Playwright `aria_snapshot()` accessibility tree, annotated with sequential `[ref=eN]` handles for element targeting. |
|
|
120
120
|
|
|
121
121
|
---
|
|
122
122
|
|
|
@@ -126,9 +126,12 @@ graph LR
|
|
|
126
126
|
### Core
|
|
127
127
|
```bash
|
|
128
128
|
patchright-cli open [url] # Launch browser
|
|
129
|
-
patchright-cli open --
|
|
129
|
+
patchright-cli open --profile=work # Named profile any session can use (logins persist)
|
|
130
130
|
patchright-cli open --headless # Run headless
|
|
131
|
-
patchright-cli open --profile
|
|
131
|
+
patchright-cli open --profile=./dir # A value with / or \ is a profile directory
|
|
132
|
+
patchright-cli --tab <name> open <url> # Named tab: shared browser, own page/refs
|
|
133
|
+
patchright-cli open --mobile # Emulate a generic mobile device (Pixel 7)
|
|
134
|
+
patchright-cli open --device="Pixel 5" # Emulate a specific Playwright device
|
|
132
135
|
patchright-cli goto <url> # Navigate
|
|
133
136
|
patchright-cli click <ref> # Click element
|
|
134
137
|
patchright-cli click <ref> right # Right-click
|
|
@@ -147,8 +150,13 @@ patchright-cli drag <from> <to> # Drag and drop
|
|
|
147
150
|
patchright-cli snapshot # Accessibility snapshot
|
|
148
151
|
patchright-cli snapshot -i # Interactive elements only (recommended)
|
|
149
152
|
patchright-cli snapshot --depth=3 # Limit depth
|
|
153
|
+
patchright-cli snapshot --selector=CSS # Snapshot a CSS-scoped subtree
|
|
150
154
|
patchright-cli snapshot <ref> # Snapshot element subtree
|
|
151
155
|
patchright-cli snapshot --filename=f # Save to custom path
|
|
156
|
+
patchright-cli find "text" # Search snapshot for text
|
|
157
|
+
patchright-cli find --regex "a|b" # Search by regex
|
|
158
|
+
patchright-cli find "text" --all # Include text/paragraph nodes
|
|
159
|
+
patchright-cli find "text" --limit=50 # Cap hits (default 20)
|
|
152
160
|
patchright-cli eval <expr> # Run JavaScript
|
|
153
161
|
patchright-cli eval --file=script.js # Run JS from file
|
|
154
162
|
patchright-cli run-code <code> # Run JS with return value
|
|
@@ -157,6 +165,7 @@ patchright-cli screenshot # Page screenshot
|
|
|
157
165
|
patchright-cli screenshot --full-page # Full scrollable page
|
|
158
166
|
patchright-cli screenshot <ref> # Element screenshot
|
|
159
167
|
patchright-cli screenshot --filename=f # Save to custom path
|
|
168
|
+
patchright-cli screenshot --hires # Capture at device pixel ratio
|
|
160
169
|
patchright-cli close # Close session
|
|
161
170
|
```
|
|
162
171
|
|
|
@@ -165,6 +174,10 @@ patchright-cli close # Close session
|
|
|
165
174
|
patchright-cli go-back
|
|
166
175
|
patchright-cli go-forward
|
|
167
176
|
patchright-cli reload
|
|
177
|
+
patchright-cli wait 500 # Wait a fixed number of milliseconds
|
|
178
|
+
patchright-cli wait --url="**/dashboard" # Wait for the URL to match (`*` never crosses a `/`)
|
|
179
|
+
patchright-cli wait-for <ref> # Wait until an element is visible
|
|
180
|
+
patchright-cli wait-for <ref> --state=hidden
|
|
168
181
|
```
|
|
169
182
|
|
|
170
183
|
### Keyboard / Mouse
|
|
@@ -252,6 +265,9 @@ patchright-cli tracing-stop # Saves .zip trace file
|
|
|
252
265
|
patchright-cli video-start # Start video recording (CDP screencast)
|
|
253
266
|
patchright-cli video-stop # Stop and save video (requires ffmpeg for .webm)
|
|
254
267
|
patchright-cli video-stop --filename=recording.webm
|
|
268
|
+
patchright-cli show --annotate # Ask a human to mark up the page, wait for it
|
|
269
|
+
patchright-cli video-show-actions # Annotate each action in the recording
|
|
270
|
+
patchright-cli video-hide-actions # Stop annotating actions
|
|
255
271
|
patchright-cli pdf --filename=page.pdf
|
|
256
272
|
```
|
|
257
273
|
|
|
@@ -284,13 +300,15 @@ patchright-cli install --skills # Auto-install skills for detected AI age
|
|
|
284
300
|
|
|
285
301
|
### Sessions
|
|
286
302
|
```bash
|
|
287
|
-
patchright-cli -s=mysession open https://example.com
|
|
303
|
+
patchright-cli -s=mysession open https://example.com
|
|
288
304
|
patchright-cli -s=mysession click e6
|
|
289
305
|
patchright-cli -s=mysession close
|
|
290
306
|
patchright-cli list # List all sessions
|
|
291
307
|
patchright-cli close-all
|
|
292
308
|
patchright-cli kill-all
|
|
293
|
-
patchright-cli delete-data # Delete
|
|
309
|
+
patchright-cli delete-data # Delete the profile named after the session
|
|
310
|
+
patchright-cli profile-list # Profiles, size, and which session uses each
|
|
311
|
+
patchright-cli profile-delete <name> # Delete an idle named profile
|
|
294
312
|
patchright-cli --port=9322 open # Custom daemon port
|
|
295
313
|
```
|
|
296
314
|
|
|
@@ -321,6 +339,34 @@ patchright-cli install --skills
|
|
|
321
339
|
|
|
322
340
|
</details>
|
|
323
341
|
|
|
342
|
+
### MCP server
|
|
343
|
+
|
|
344
|
+
MCP support is optional so the base CLI install stays small:
|
|
345
|
+
|
|
346
|
+
```bash
|
|
347
|
+
pip install 'patchright-cli[mcp]'
|
|
348
|
+
|
|
349
|
+
# stdio (default)
|
|
350
|
+
patchright-cli mcp
|
|
351
|
+
|
|
352
|
+
# Streamable HTTP
|
|
353
|
+
patchright-cli mcp --http --host=127.0.0.1 --port=8000
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+

|
|
357
|
+
|
|
358
|
+
The HTTP endpoint is `/mcp`. Set `PATCHRIGHT_CLI_MCP_TOKEN` to require `Authorization: Bearer <token>` on every request, and always set it before binding to `0.0.0.0`.
|
|
359
|
+
|
|
360
|
+
File paths passed to MCP tools (uploads, state and cookie files, screenshot/PDF/snapshot output, profile directories) must be absolute and beneath the MCP root, so a client cannot reach arbitrary host files. Outputs without a path land in `<root>/output/`, which `browser_delete_output` can clean up. `patchright_eval` and `patchright_run_code` still run arbitrary JavaScript in the page, so protect HTTP deployments regardless.
|
|
361
|
+
|
|
362
|
+
| Variable | Default | Effect |
|
|
363
|
+
|---|---|---|
|
|
364
|
+
| `PATCHRIGHT_CLI_MCP_TOKEN` | unset (no auth) | Bearer token required by the HTTP transport |
|
|
365
|
+
| `PATCHRIGHT_CLI_MCP_ROOT` | working directory | Root that tool file paths must sit beneath |
|
|
366
|
+
| `PATCHRIGHT_CLI_MCP_UNRESTRICTED_FILESYSTEM` | unset | `1` drops the path check and enables `patchright_install_skills` |
|
|
367
|
+
| `PATCHRIGHT_CLI_MCP_HEADLESS` | unset (headed) | `1` makes `patchright_open` default to headless, for hosts without a display |
|
|
368
|
+
| `PATCHRIGHT_CLI_MCP_DAEMON_PORT` | `9321` | Daemon port the tools talk to |
|
|
369
|
+
|
|
324
370
|
### Skill docs
|
|
325
371
|
|
|
326
372
|
| File | Topic |
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="470" viewBox="0 0 1200 470" role="img" aria-label="A remote MCP client sends tools/call over HTTP across a network boundary guarded by an optional Bearer token to the patchright-cli MCP server on the host. The server spawns one short-lived CLI process per call, which sends length-prefixed JSON over TCP to the long-lived daemon. The daemon drives real Chrome over CDP; headed Chrome draws on an Xvfb display and loads websites over HTTPS. Output files land in the root's output directory on the host.">
|
|
2
|
+
<style>
|
|
3
|
+
svg { --bg: #ffffff; --fg: #1b2230; --muted: #5d6778; --line: #c9cfd9; --accent: #c2410c; --host: #eef1f6;
|
|
4
|
+
color: var(--fg); font-family: -apple-system, "Segoe UI", Helvetica, Arial, sans-serif; }
|
|
5
|
+
@media (prefers-color-scheme: dark) {
|
|
6
|
+
svg { --bg: #0d1117; --fg: #e6edf3; --muted: #9aa4b4; --line: #3a4352; --accent: #fb923c; --host: #161b22; }
|
|
7
|
+
}
|
|
8
|
+
.bg { fill: var(--bg); }
|
|
9
|
+
.box { fill: var(--bg); stroke: currentColor; stroke-width: 1.4; }
|
|
10
|
+
.ghost { fill: var(--bg); stroke: var(--line); stroke-width: 1.2; }
|
|
11
|
+
.hostbg { fill: var(--host); stroke: var(--line); stroke-width: 1.2; }
|
|
12
|
+
.t { fill: currentColor; font-size: 14px; font-weight: 600; text-anchor: middle; }
|
|
13
|
+
.s { fill: var(--muted); font-size: 11.5px; text-anchor: middle; }
|
|
14
|
+
.m { fill: var(--muted); font-family: ui-monospace, Consolas, monospace; font-size: 11px; text-anchor: middle; }
|
|
15
|
+
.lbl { fill: currentColor; font-size: 12px; text-anchor: middle; paint-order: stroke; stroke: var(--bg); stroke-width: 5px; stroke-linejoin: round; }
|
|
16
|
+
.lbl.start { text-anchor: start; }
|
|
17
|
+
.region { fill: var(--muted); font-family: ui-monospace, Consolas, monospace; font-size: 11px; letter-spacing: 0.05em; text-transform: uppercase; }
|
|
18
|
+
.edge { stroke: currentColor; stroke-width: 1.4; fill: none; }
|
|
19
|
+
.edge.dim { stroke: var(--muted); stroke-dasharray: 4 3; }
|
|
20
|
+
.boundary { stroke: var(--accent); stroke-width: 1.6; stroke-dasharray: 6 5; }
|
|
21
|
+
.warn { fill: var(--accent); font-size: 12px; font-weight: 600; text-anchor: middle; paint-order: stroke; stroke: var(--bg); stroke-width: 5px; }
|
|
22
|
+
.head { fill: currentColor; }
|
|
23
|
+
.head.dim { fill: var(--muted); }
|
|
24
|
+
</style>
|
|
25
|
+
<rect class="bg" x="0" y="0" width="1200" height="470"/>
|
|
26
|
+
<defs>
|
|
27
|
+
<marker id="ah" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse">
|
|
28
|
+
<path class="head" d="M0,0 L10,5 L0,10 z"/>
|
|
29
|
+
</marker>
|
|
30
|
+
<marker id="ahd" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse">
|
|
31
|
+
<path class="head dim" d="M0,0 L10,5 L0,10 z"/>
|
|
32
|
+
</marker>
|
|
33
|
+
</defs>
|
|
34
|
+
|
|
35
|
+
<!-- host region -->
|
|
36
|
+
<rect class="hostbg" x="250" y="30" width="820" height="420" rx="10"/>
|
|
37
|
+
<text class="region" x="268" y="54">Host · container or server</text>
|
|
38
|
+
<text class="region" x="20" y="54">Remote machine</text>
|
|
39
|
+
<text class="region" x="1100" y="54">Internet</text>
|
|
40
|
+
|
|
41
|
+
<!-- trust boundary -->
|
|
42
|
+
<line class="boundary" x1="205" y1="24" x2="205" y2="456"/>
|
|
43
|
+
<text class="warn" x="205" y="300">trust boundary</text>
|
|
44
|
+
<text class="warn" x="205" y="317" style="font-weight:400">optional Bearer token</text>
|
|
45
|
+
|
|
46
|
+
<!-- client -->
|
|
47
|
+
<rect class="box" x="20" y="170" width="140" height="80" rx="6"/>
|
|
48
|
+
<text class="t" x="90" y="205">MCP client</text>
|
|
49
|
+
<text class="s" x="90" y="225">Claude Code, agents</text>
|
|
50
|
+
|
|
51
|
+
<!-- client <-> server -->
|
|
52
|
+
<line class="edge" x1="160" y1="195" x2="268" y2="195" marker-end="url(#ah)"/>
|
|
53
|
+
<text class="lbl" x="215" y="187">tools/call</text>
|
|
54
|
+
<line class="edge" x1="270" y1="228" x2="162" y2="228" marker-end="url(#ah)"/>
|
|
55
|
+
<text class="lbl" x="215" y="246">text · PNG · YAML</text>
|
|
56
|
+
|
|
57
|
+
<!-- MCP server -->
|
|
58
|
+
<rect class="box" x="270" y="170" width="170" height="80" rx="6"/>
|
|
59
|
+
<text class="t" x="355" y="198">MCP server</text>
|
|
60
|
+
<text class="m" x="355" y="217">mcp --http :8000/mcp</text>
|
|
61
|
+
<text class="s" x="355" y="236">checks session, paths</text>
|
|
62
|
+
|
|
63
|
+
<!-- server -> CLI -->
|
|
64
|
+
<line class="edge" x1="440" y1="210" x2="518" y2="210" marker-end="url(#ah)"/>
|
|
65
|
+
<text class="lbl" x="479" y="202">spawns</text>
|
|
66
|
+
|
|
67
|
+
<!-- CLI process stack -->
|
|
68
|
+
<rect class="ghost" x="536" y="158" width="160" height="80" rx="6"/>
|
|
69
|
+
<rect class="ghost" x="528" y="164" width="160" height="80" rx="6"/>
|
|
70
|
+
<rect class="box" x="520" y="170" width="160" height="80" rx="6"/>
|
|
71
|
+
<text class="t" x="600" y="198">CLI process</text>
|
|
72
|
+
<text class="m" x="600" y="217">python -m patchright_cli</text>
|
|
73
|
+
<text class="s" x="600" y="236">one per call, exits</text>
|
|
74
|
+
|
|
75
|
+
<!-- CLI -> daemon -->
|
|
76
|
+
<line class="edge" x1="696" y1="210" x2="778" y2="210" marker-end="url(#ah)"/>
|
|
77
|
+
<text class="lbl" x="737" y="202">TCP · JSON</text>
|
|
78
|
+
<text class="s" x="737" y="229">starts it</text>
|
|
79
|
+
<text class="s" x="737" y="243">if absent</text>
|
|
80
|
+
|
|
81
|
+
<!-- daemon -->
|
|
82
|
+
<rect class="box" x="780" y="170" width="120" height="80" rx="6"/>
|
|
83
|
+
<text class="t" x="840" y="198">Daemon</text>
|
|
84
|
+
<text class="m" x="840" y="217">127.0.0.1:9321</text>
|
|
85
|
+
<text class="s" x="840" y="236">long-lived</text>
|
|
86
|
+
|
|
87
|
+
<!-- daemon -> chrome -->
|
|
88
|
+
<line class="edge" x1="900" y1="210" x2="948" y2="210" marker-end="url(#ah)"/>
|
|
89
|
+
<text class="lbl" x="924" y="202">CDP</text>
|
|
90
|
+
|
|
91
|
+
<!-- chrome -->
|
|
92
|
+
<rect class="box" x="950" y="170" width="100" height="80" rx="6"/>
|
|
93
|
+
<text class="t" x="1000" y="205">Chrome</text>
|
|
94
|
+
<text class="s" x="1000" y="225">headed or headless</text>
|
|
95
|
+
|
|
96
|
+
<!-- xvfb -->
|
|
97
|
+
<rect class="ghost" x="950" y="72" width="100" height="48" rx="6"/>
|
|
98
|
+
<text class="t" x="1000" y="96" style="font-weight:500">Xvfb :99</text>
|
|
99
|
+
<text class="s" x="1000" y="112">headed only</text>
|
|
100
|
+
<line class="edge dim" x1="1000" y1="120" x2="1000" y2="168" marker-end="url(#ahd)"/>
|
|
101
|
+
<text class="lbl start" x="1008" y="149" style="fill:var(--muted)">DISPLAY</text>
|
|
102
|
+
|
|
103
|
+
<!-- chrome -> web -->
|
|
104
|
+
<line class="edge" x1="1050" y1="210" x2="1098" y2="210" marker-end="url(#ah)"/>
|
|
105
|
+
<text class="lbl" x="1075" y="202">HTTPS</text>
|
|
106
|
+
<rect class="box" x="1100" y="170" width="80" height="80" rx="6"/>
|
|
107
|
+
<text class="t" x="1140" y="214">Websites</text>
|
|
108
|
+
|
|
109
|
+
<!-- output dir -->
|
|
110
|
+
<rect class="box" x="520" y="350" width="380" height="60" rx="6"/>
|
|
111
|
+
<text class="m" x="710" y="375" style="fill:currentColor;font-size:12px"><root>/output/</text>
|
|
112
|
+
<text class="s" x="710" y="395">screenshots · PDFs · snapshots · state files</text>
|
|
113
|
+
|
|
114
|
+
<line class="edge" x1="840" y1="250" x2="840" y2="348" marker-end="url(#ah)"/>
|
|
115
|
+
<text class="lbl start" x="848" y="304">writes files</text>
|
|
116
|
+
<line class="edge dim" x1="600" y1="252" x2="600" y2="348" marker-end="url(#ahd)"/>
|
|
117
|
+
<text class="lbl start" x="608" y="304" style="fill:var(--muted)">cwd</text>
|
|
118
|
+
<polyline class="edge dim" points="355,250 355,380 518,380" marker-end="url(#ahd)"/>
|
|
119
|
+
<text class="lbl" x="437" y="372" style="fill:var(--muted)">delete_output</text>
|
|
120
|
+
</svg>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "patchright-cli"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.8.0"
|
|
4
4
|
description = "Anti-detect browser automation CLI using Patchright (undetected Playwright fork)"
|
|
5
5
|
license = "Apache-2.0"
|
|
6
6
|
requires-python = ">=3.10"
|
|
@@ -54,16 +54,21 @@ markers = [
|
|
|
54
54
|
]
|
|
55
55
|
|
|
56
56
|
[project.optional-dependencies]
|
|
57
|
+
mcp = [
|
|
58
|
+
"fastmcp>=3.0,<5",
|
|
59
|
+
]
|
|
57
60
|
dev = [
|
|
58
61
|
"pytest>=8.0",
|
|
59
62
|
"pytest-asyncio>=0.23",
|
|
60
63
|
"pre-commit",
|
|
64
|
+
"fastmcp>=3.0,<5",
|
|
61
65
|
]
|
|
62
66
|
|
|
63
67
|
[dependency-groups]
|
|
64
68
|
dev = [
|
|
65
69
|
"pytest>=8.0",
|
|
66
70
|
"pytest-asyncio>=0.23",
|
|
71
|
+
"fastmcp>=3.0,<5",
|
|
67
72
|
]
|
|
68
73
|
|
|
69
74
|
[tool.ruff]
|