@pablovitasso/szkrabok
v1.1.2
Published
Production-grade MCP browser automation layer with persistent sessions and stealth capabilities
Maintainers
Readme
Szkrabok
MCP server supplementing microsoft/playwright-mcp with persistent sessions, stealth mode, and scripted automation.
Core Enhancements:
- Named Sessions: Persistent cookies, localStorage, and Chromium profiles.
- Profile Cloning: Ephemeral session clones — template profile is deep-cloned to
$TMPDIR, browser runs against the clone, clone is destroyed on close. Zero contamination of the template. - Stealth: Integrated
playwright-extra+ stealth plugin and anti-bot CDP patches. - Deterministic Ports: Fixed CDP ports per session for
connectOverCDP().
Tools & Capabilities
1. session_manage
Manage browser sessions. Actions: open (launch/resume), close (save/delete), list (all), delete (templates; globs support), endpoint (CDP/WS). open + isClone:true returns a clone ID; use this ID for subsequent calls.
action (required):
open|close|list|delete|endpointsessionName: Session name or glob (delete only). For clones, use the ID returned by
open(isClone:true), not the template name. Required for open/close/delete/endpoint, not for listurl: URL to navigate after opening (open only)
launchOptions (open only):
- preset: Preset name. Mutually exclusive with userAgent/viewport/locale/timezone. See Presets
- stealth: Enable stealth mode, default
true - disableWebGL: Disable WebGL, default
false - headless: Run headless
- userAgent: Custom UA string
- viewport:
{ width, height } - locale: BCP 47 locale
- timezone: IANA timezone
- isClone: Create an ephemeral clone of the template session. The returned
sessionNameis a generated id. Clone dir is deleted on close; no state is saved. Template must be closed before cloning.
Examples:
- With preset:
{ preset: "desktop-chrome-win", headless: false, stealth: true } - With explicit fields:
{ userAgent: "...", viewport: { width: 1280, height: 800 }, locale: "en-US", timezone: "America/New_York", headless: false } - Note:
presetis mutually exclusive withuserAgent,viewport,locale,timezone.headlessandstealthare always allowed alongside either.
Returns: { success, sessionName, url, reused, preset, label, isClone, templateSession, cdpEndpoint }
When isClone: true is set in launchOptions, the returned sessionName is a generated id (e.g. myprofile-1748234205-a3f2c1b0). Use that id for all subsequent calls. On close, the clone dir is deleted and no state is saved.
2. session_run_test
Composite single-command primitive: open/clone session → navigate → run tests → apply post-policy. Deterministic invariants: per-name lock prevents concurrent page mutation, navigation barrier waits for networkidle, workers forced to 1.
- session (required):
- name (required): logical session name
- mode:
clone(default, ephemeral) |template(persistent) - templateConflict:
fail(default) |close-first|clone-from-live— what to do when template is open in clone mode - enforceLaunchOptionsMatch: hard-fail if open session has different launchOptions config hash, default
false - launchOptions: same options as
session_manage open - navigation:
{ policy: "always"|"ifBlank"|"never", url, timeout }— navigates before test;urlrequired when policy is not"never"
- test (required): same as
browser_run_test—spec,grep,params,config,project,reportFile - postPolicy:
{ action: "destroy"|"save"|"keep", recreateCloneOnKeep: false }— defaultdestroyfor clone,savefor template
Returns: { session: { logicalName, runtimeName, mode }, test: { passed, failed, ... } } or { error, phase: "session"|"test"|"postPolicy" } on failure.
3. browser_scrape
Scrape current page into LLM-ready text.
- sessionName (required)
- selectors: CSS selectors to target. Omit for auto (main or body)
Returns: { raw: [{ tag, text }], llmFriendly, tokenCountEstimate }
4. browser_run
Execute Playwright JS on session page.
- sessionName (required)
- code: Inline async function as string. Mutually exclusive with
path - path: Path to
.mjsfile. Mutually exclusive withcode - fn: Named export from path, default
"default" - args: Object passed as second param to function
Returns: { result, url }
5. browser_run_test
Run .spec.js tests via CDP. Requires scaffold_init and open session.
- sessionName (required)
- files: File/directory paths for playwright test
- grep: Filter tests by name (regex)
- params: Key/value → uppercased env vars (e.g.
{url:"..."}→process.env.URL) - config: Config path, default
playwright.config.js - project: Playwright project name
- keepOpen: Reconnect session after test if MCP context invalidated, default
false - reportFile: Repo-relative JSON report path. Default:
sessions/<sessionName>/last-run.json. Returns resolved path
Returns: { passed, failed, skipped, tests: [{ title, status, error, result }], log, reportFile }
Run from VSCode with Playwright extension — no MCP required:
// tests/playwright/e2e/rebrowser.spec.js
import { test, expect } from './fixtures.js';
test('rebrowser-check', async ({ page }) => {
await page.goto('https://bot-detector.rebrowser.net/');
// ... test logic
});Full example: tests/playwright/e2e/rebrowser.spec.js
6. scaffold_init
Init szkrabok project (idempotent). Prerequisite for browser runs.
- dir: Target directory, default cwd
- name: Package name, default dirname
- preset:
minimal(config only) orfull(fixtures + specs) - install: Run npm install after, default
false
Returns: { created, skipped, merged, installed, warnings }
Presets
default, chromium-honest, desktop-chrome-win, desktop-chrome-mac, desktop-firefox-win, desktop-safari-mac, mobile-iphone-15, mobile-android-chrome, tablet-ipad-pro
IDE Integration
Run Playwright tests directly from VSCode while using MCP-managed sessions:
// tests/playwright/e2e/rebrowser-mcp.spec.js
import { test, expect } from 'playwright/test';
import { mcpConnect } from '@szkrabok/runtime';
const SESSION = 'rebrowser-mcp-harness';
test('rebrowser-check via MCP', async () => {
const mcp = await mcpConnect(SESSION, { launchOptions: { headless: true } });
try {
const result = await mcp.browser_run_test({ files: ['tests/playwright/e2e/rebrowser.spec.js'] });
expect(result.passed).toBe(8);
} finally {
await mcp.close();
}
});Full example: tests/playwright/e2e/rebrowser-mcp.spec.js
Setup
Install
Global (all projects):
claude mcp add --scope user szkrabok -- npx -y @pablovitasso/szkrabok
gemini mcp add --scope user szkrabok npx -y @pablovitasso/szkrabok
kilo mcp add szkrabok npx -y @pablovitasso/szkrabok(Cursor: use UI → Features → MCP)
This project only:
claude mcp add szkrabok -- npx -y @pablovitasso/szkrabokShared config (Claude Desktop / Gemini / Kilo / Cursor) — add to config file:
{
"mcpServers": {
"szkrabok": {
"command": "npx",
"args": ["-y", "@pablovitasso/szkrabok"]
}
}
}Locations: Claude Desktop → claude_desktop_config.json, Gemini → ~/.gemini/settings.json, Kilo → mcp_settings.json, Cursor → UI
OpenCode:
{ "mcp": { "szkrabok": { "type": "local", "command": ["npx", "-y", "@pablovitasso/szkrabok"], "enabled": true } } }Codex (TOML):
[mcp_servers.szkrabok]
command = "npx"
args = ["-y", "@pablovitasso/szkrabok"]New project:
npx @pablovitasso/szkrabok initBrowser not found? Run
szkrabok detect-browserto find installed browsers, orszkrabok install-browserto install Playwright's Chromium. Requires Node.js ≥ 20.
Configure
Optionally create szkrabok.config.local.toml in your project root to set a custom browser binary or user agent:
[default]
executablePath = "/path/to/your/chrome"
overrideUserAgent = true
userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36"
log_level = "debug"Config discovery — the server finds your TOML automatically. Priority order:
SZKRABOK_CONFIGenv var (absolute path to a.tomlfile)SZKRABOK_ROOTenv var (walk-up within that dir)- MCP roots sent by the client at handshake (walk-up within each root)
process.cwd()walk-up (CLI / fallback)~/.config/szkrabok/config.toml- empty defaults
Place szkrabok.config.toml or szkrabok.config.local.toml anywhere in your project tree and it will be found as long as the MCP client sends that project's directory as a root.
Usage
scaffold_init { "dir": "/path/to/project", "preset": "full" }
# Option A — manual session lifecycle
session_manage { "action": "open", "sessionName": "my-session", "url": "https://example.com" }
browser_scrape { "sessionName": "my-session" }
browser_run_test { "sessionName": "my-session", "files": ["automation/example.spec.js"] }
session_manage { "action": "close", "sessionName": "my-session" }
# Option B — composite single command (session_run_test)
session_run_test {
"session": { "name": "my-session", "navigation": { "policy": "always", "url": "https://example.com" } },
"test": { "spec": "automation/example.spec.js" }
}CLI
szkrabok is both the MCP server and the CLI. With no arguments it starts the MCP server; with a subcommand it runs the CLI:
szkrabok open <profile> # Launch browser, print CDP endpoint, stay alive
szkrabok open <profile> --clone # Clone template into ephemeral copy; clone destroyed on exit
szkrabok session list # Show all sessions (active + stored)
szkrabok session inspect <id> # Dump cookie/localStorage counts
szkrabok session delete <id> # Delete a session (supports glob: "cfg-*", "*")
szkrabok session delete "*" # Delete all stored sessions
szkrabok session cleanup --days 30 # Delete sessions unused for N days
szkrabok endpoint <sessionName> # Print CDP + WS endpoints
szkrabok detect-browser # List usable Chrome/Chromium installations
szkrabok install-browser # Install Playwright's ChromiumProject Structure
@szkrabok/runtime(packages/runtime/): Browser bootstrap, stealth, session pool, MCP client (mcpConnect,spawnClient, codegen).- Config:
szkrabok.config.toml(defaults) deep-merged withszkrabok.config.local.toml(machine-specific, gitignored). - Release:
npm run deps:updateupdates dependencies,npm run release:patchbumps version + tags, thennpm run release:publish.
Documentation
| Doc | Contents | |-----|----------| | docs/architecture.md | Layer map, file layout, session lifecycle, invariants | | docs/development.md | Adding tools, CLI design, release workflow | | docs/testing.md | Test categories, how to run, writing specs | | docs/mcp-client-library.md | MCP client library and codegen | | docs/scaffold-init.md | scaffold_init presets and template structure |
