browser-smoke
Drives Google Chrome via Playwright, enabling agents to open URLs, take accessibility snapshots, click and type using refs, scrape pages with JavaScript, handle forms and dialogs, manage tabs, and capture screenshots or network activity in a dedicated Chrome profile.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@browser-smokeOpen http://localhost:3000 and take a screenshot"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Smoke
A Playwright browser your coding agent can drive: open a site, fill a form, scrape a page, or smoke-test a UI you just built.
MCP server id is smoke. In OpenCode the tools are smoke_browser_open, smoke_browser_snapshot, … Cursor and Claude Code call the same tools without the prefix (browser_open).
Results are compact JSON. Screenshots stay off unless you ask. The agent gets its own Google Chrome at ~/.browser-smoke/chrome-attach (not the Default profile where you already read Gmail, and not Playwright's testing Chromium). persist=false is the testing window. See What this is not.
Works with OpenCode, Cursor, Claude Code, and any MCP client.
Do not run npx smoke — that is a different npm package (a mock HTTP server). Install from this GitHub repo:
Quick start
Need Node.js 18+ and Python 3.10+. Chromium is installed by setup.
1. Install
npx github:sukirman1901/browser-smokePick local or global, then which host (OpenCode, Cursor, Claude Code, or all). Setup copies the MCP server, creates a venv, and installs Playwright Chromium. The MCP key it writes is smoke.
Restart the host after install (quit/reopen OpenCode, Cursor, or Claude Code).
Command | What it does |
| Interactive |
| This project, all three hosts |
| Cursor only |
| Claude Code only |
| OpenCode user config |
| Print the stdio MCP entry |
After a version upgrade, run the same command again so MCP files refresh, then restart the host.
2. First task
Paste this into the agent:
Use smoke: open https://example.com, take a snapshot, tell me the title and the first five links. Do not screenshot.3. How the agent should drive it
Same loop for a daily task and a smoke test (OpenCode names):
smoke_browser_openthe URL.smoke_browser_snapshot— this is the selector map:@1,@2,@3.Click or type those refs. After navigation, if a ref errors, snapshot again.
Prove the result with
smoke_browser_assert(text/url/visible/…). Snapshot is not the verdict.Several steps: one
smoke_browser_script(or onesmoke_browser_run). Do not chain eight MCP execute calls.Scrape with
smoke_browser_executereturning a small JSON array — notinnerHTML.Several URLs or tabs at once: one
smoke_browser_parallel. Do not chainopen_tab.Screenshot only for a visual bug. Never
screenshot_base64.
Related MCP server: Playwright Plus Python MCP
Daily task (window stays up)
This is the default. smoke_browser_open starts or reconnects Google Chrome at ~/.browser-smoke/chrome-attach (port 9222). You do not launch it by hand and you do not pass cdp=. Do not pass persist=true (it is already on).
smoke_browser_open url=https://example.com
smoke_browser_snapshot
smoke_browser_script js_code="await click('@1'); await type('@2', 'hi');"Leave the window. Next chat, smoke_browser_open the next URL — same Chrome, cookies kept. smoke_browser_close disconnects; it does not quit Chrome. Pass shutdown=true only when you want the window gone.
Named sessions (session=work) if two tasks must not share tabs. Then pass session= on every tool.
Helpers inside smoke_browser_script: open, click, type, snapshot, wait, assert, execute, press, hover, scroll, dialog, download, upload, select, switchTab. wait("load") and wait("#ready") are fine. wait timeout is milliseconds. assert({ expect: "text", text: "Saved" }) is the verdict. scroll(800) is down 800px; scroll('@3') brings that ref into view.
Smoke test (after you ship a feature)
Throwaway browser — must persist=false or you pollute the living profile.
smoke_browser_open url=http://localhost:5173 persist=false session=test
smoke_browser_snapshot
smoke_browser_run actions_json='[{"action":"type","selector":"@1","text":"test@test.com"},{"action":"click","selector":"@3"}]'
smoke_browser_assert expect=text text="..."
smoke_browser_console
smoke_browser_errors
smoke_browser_report results_json
smoke_browser_close shutdown=true session=testThe app must already be running. Failures should block. Debug with console, errors, then smoke_browser_network_capture mode=get (no headers). Screenshot last.
Visual regression (opt-in):
smoke_browser_screenshot_diff name=homepageWrites a baseline/diff under artifacts/. No PNG in the tool result unless you ask.
Scrape
smoke_browser_open url=https://example.com
smoke_browser_execute js_code="() => [...document.querySelectorAll('a')].slice(0,50).map(a => ({t:a.textContent.trim(), h:a.href}))"Several sites together (max 8). Do not open_tab in a loop — those wait on each other:
smoke_browser_parallel urls='["https://example.com","https://example.org"]' js_code="() => ({title: document.title, href: location.href})"Same JS on tabs already open: js_code only. Click/type still use the focused tab (switch_tab).
smoke_browser_close is optional; it does not quit the living window.
Keep a login (Playwright profile, not Chrome)
Default persist already keeps cookies in .browser-smoke/profiles/<session>. Log in once in that window.
Custom dir:
smoke_browser_open url=https://app.example.com user_data_dir=.browser-smoke/profileCookies live in that folder. Gmail already open in your Chrome will not appear here.
Need stock Chrome instead of bundled Chromium? channel=chrome (throwaway, not the living profile). cdp= attaches to a debug Chrome you launched.
Attach to a debug Chrome (cdp=)
Default browser_open already auto-starts ~/.browser-smoke/chrome-attach on port 9222. Use cdp= only for a Chrome you launched yourself on another port.
Chrome 136+ ignores --remote-debugging-port on the daily Default profile. chrome-attach is a separate dir on purpose.
Quit daily Chrome if it is using the same binary and you hit a lock (optional on macOS if you only open the debug profile).
Start debug Chrome (macOS):
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" \
--remote-debugging-port=9222 \
--user-data-dir="$HOME/.browser-smoke/chrome-attach" \
--no-first-run --no-default-browser-checkIn the agent:
smoke_browser_open url=https://example.com cdp=9222
smoke_browser_snapshot
smoke_browser_closecdp= also accepts http://127.0.0.1:9222 or a ws:// DevTools URL. You do not need persist=false. smoke_browser_close disconnects; it does not quit that Chrome. Do not combine cdp with channel.
Forms, files, dialogs, popups
Snapshot first, then:
smoke_browser_click selector=@4 dialog=accept
smoke_browser_click selector=@5 popup=true
smoke_browser_switch_tab index=0
smoke_browser_download url=https://images.unsplash.com/photo-xyz save_as=hero.jpg
smoke_browser_set_files selector=@7 paths=/abs/path/hero.jpg
smoke_browser_download selector=@8Prefer dialog=accept on the click that opens the alert. Arm the next dialog only when the trigger is not a click.
What this is not
You might expect | What you actually get |
Agent uses the Chrome window you are looking at | A separate Chrome profile: |
Gmail / cookies from your daily Default Chrome | Empty. Log in once inside the chrome-attach window (or you already did). |
Playwright “Chrome for Testing” on daily open | Only |
Window dies when the chat ends | Only if you |
Task Spaces / take over from the agent | Named MCP sessions. You do not share tabs with the agent |
Screenshot on every click | Path on disk only when |
| Different npm package. Install from the GitHub command above |
Tools
OpenCode names below. Cursor / Claude Code: drop the smoke_ prefix.
See the page
Tool | When to use |
| Default. Accessibility |
| Scrape / inspect, return JSON |
| Buttons/inputs/links without |
| Load, visible, URL glob, or |
| Pass/fail: |
Move around
Tool | When to use |
| Default = living Chromium. |
|
|
| One round trip with loops. Helper |
| JSON batch, no loops |
| Open/scrape up to 8 tabs at once. MCP tools still queue; this is the overlap |
| Extra tabs, one at a time. Prefer |
| Page scroll (default down 200px) or |
| Default leaves the living window. |
Click, type, files
Tool | When to use |
| CSS or |
| Fill, contenteditable chunk, drag |
| Dummy email/password for a smoke test |
|
|
| File input; save under |
| Next JS dialog if the trigger is not a click |
Evidence
Tool | When to use |
| Capped logs |
| Capture, block, mock |
| Visual, on demand |
| Cookies and storage |
| Writes |
| Hidden page in the same context |
screenshot=true on click/type/open writes a file path. screenshot_base64=true is an escape hatch.
Troubleshooting
Problem | Fix |
Chromium missing / launch error | Run the GitHub |
Tools look stale, or every click returns a screenshot | Run setup again and restart the host |
OpenCode shows | Old MCP key. Setup writes id |
Two Chromium windows | Default open is persist. Do not also pass |
Smoke test reused login cookies | Pass |
CDP connect failed / Chrome 136+ | Daily Gmail Chrome cannot be attached. Launch debug Chrome with a non-default |
| Use only one |
Connection refused | The target app is not running |
Python not found | Install Python 3.10+ |
Two sessions keep hitting the same tab | Pass |
Tabs still open one-by-one | One |
| That package is not this project. Use |
Development
git clone https://github.com/sukirman1901/browser-smoke.git
cd browser-smoke
python3 -m unittest discover -s tests -v
npm linkAfter npm link, the CLI is smoke (alias browser-smoke).
Releases: CHANGELOG.md. Latest is v1.6.0.
License
MIT
This server cannot be deployed
Maintenance
Related MCP Connectors
Discover Playwright workflows, start runs, and inspect results in Playrunner Cloud.
Provides cloud browser automation capabilities using Stagehand and Browserbase, enabling LLMs to i…
Stealth web automation for AI agents. Login, signup, navigate, screenshot.
Stealth web automation for AI agents. Login, signup, navigate, screenshot.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceEnables automated browser testing of web applications using Playwright, supporting user interactions, form submissions, console monitoring, network request inspection, and visual verification through screenshots.-
- AlicenseBqualityNot gradedmaintenanceEnables browser automation and web scraping through Playwright, supporting navigation, screenshots, element interaction, form filling, JavaScript execution, and content extraction.8Apache 2.0
- AlicenseNot gradedqualityDmaintenanceEnables browser automation using Playwright, allowing LLMs to interact with web pages, take screenshots, generate test code, scrape web pages, and execute JavaScript in a real browser environment.15,344 npmMIT
- AlicenseBqualityDmaintenanceEnables browser automation using Playwright, including navigation, screenshots, clicking, form filling, and JavaScript execution.8Apache 2.0