A local MCP server that gives Claude a full browser: screenshots, DOM inspection, WCAG color analysis, and page interaction β all via a persistent Puppeteer/Chromium session running in Docker.
smth exposes 16 MCP tools across three areas:
See β read and analyze any web page without interacting with it
browser_see_visual Β· browser_read_text Β· browser_see_dom Β· browser_see_fonts Β· browser_see_colors Β· browser_see_color_pairs
Act β drive the browser like a user
browser_launch Β· browser_goto Β· browser_click Β· browser_hover Β· browser_type
Compare β capture and diff DOM snapshots
browser_remember_dom Β· browser_doms Β· browser_dom_compare Β· fetch_dom_content Β· browser_list_devices
- Docker (Desktop or Engine)
- Claude Code (or any MCP client supporting Streamable HTTP or SSE transport)
git clone https://github.com/maxvolkel/smth.git
cd smth
docker compose up -dThe container starts on port 3000. Add .mcp.json to any project that should use it:
{
"mcpServers": {
"smth": { "type": "http", "url": "http://localhost:3000/mcp" }
}
}Then restart Claude Code. The mcp__smth__* tools will be available immediately.
To let smth open local HTML files from a project directory:
PAGES_DIR=/path/to/your/project docker compose up -d --force-recreateFiles are mounted read-only at /pages. Open them with their host path or file:///pages/filename.html.
browser_launch url="https://example.com"
browser_see_color_pairs
Returns every text/background color pair on the page with WCAG 2.2 contrast ratios and AA/AAA pass/fail flags. Instantly shows which combinations fail accessibility requirements.
fetch_dom_content url="https://example.com/article/123"
Opens the URL, automatically finds a peer page on the same site, computes what's shared (navigation, header, footer, sidebar), and returns only the unique content of the target page. No manual CSS exclusions needed.
browser_launch url="https://example.com"
browser_list_devices
browser_see_visual device="iPhone 15 Pro"
Emulates an iPhone 15 Pro (viewport, pixel ratio, user-agent) and returns an embedded screenshot directly visible to the model.
browser_launch url="https://example.com/login"
browser_see_dom lens=["code"]
browser_type id="username" text="myuser"
browser_type id="password" text="mypass"
browser_click selector="input[type=submit]"
browser_read_text
The code lens shows form fields, names, actions, and event handlers without layout noise. After filling and submitting, browser_read_text reads the resulting page.
browser_launch url="https://example.com/settings"
browser_remember_dom name="before" lens=["text"]
browser_click selector="#enable-toggle"
browser_remember_dom name="after" lens=["text"]
browser_dom_compare a="before" b="after"
Shows exactly which text appeared or disappeared after clicking the toggle β useful for verifying that a UI action had the expected effect.
Full documentation for every tool lives in doc/smth.md.
| Tool | Read-only | Description |
|---|---|---|
browser_list_devices |
yes | Lists device names for browser_see_visual |
browser_launch |
no | Starts a session, opens a URL |
browser_goto |
no | Navigates to a new URL in the existing session |
browser_read_text |
yes | Page text as Markdown + interactive element selectors |
browser_see_fonts |
yes | All fonts grouped by family, size, weight |
browser_see_colors |
yes | All computed colors with usage counts |
browser_see_color_pairs |
yes | Text/background pairs with WCAG contrast ratios |
browser_see_dom |
yes | Lens-filtered compact HTML or text search |
browser_click |
no | Clicks an element by id or CSS selector |
browser_hover |
no | Hovers and returns a before/after diff |
browser_type |
no | Types text into a form field |
browser_remember_dom |
no | Saves a named DOM snapshot |
browser_doms |
yes | Lists all saved snapshots |
browser_dom_compare |
yes | Diffs two snapshots or subtracts a background |
fetch_dom_content |
no | Opens a URL and returns only its foreground content |
browser_see_visual |
yes | Screenshot (viewport or full page, any device) |
docker compose up -d # start
docker compose down # stop
docker compose up -d --build # restart after code changes
docker compose logs -f # tail logsAfter a --force-recreate, the MCP session token is invalidated. The first tool call will get a Session not found error β just retry once; Claude Code re-establishes the session automatically.
Docker cannot reach the host's localhost. Use host.docker.internal instead:
# Wrong
browser_launch url="http://localhost:4000/"
# Correct
browser_launch url="http://host.docker.internal:4000/"
smth runs entirely on your local machine. It does not transmit any data to external services. The browser session is isolated inside a Docker container. No telemetry, no analytics, no network calls beyond what the pages you visit make themselves.