Microsoft's own Playwright image carries all three engines at 3.5 GB; this server calls chromium.launch and nothing else, ever. Node's own slim base plus Chromium installed on its own comes to 1.84 GB - most of that is the OS libraries --with-deps pulls in for a sandboxed Chromium to run at all, not the browser binary itself. One mistake made and caught while building this: installing under HOME=/tmp/browser-home, which is gone the instant the container starts, because /tmp is mounted as tmpfs. Moved to PLAYWRIGHT_BROWSERS_PATH=/ms-playwright, outside it - which is also where Microsoft's own image keeps browsers, and for the same reason. Verified under the production security constraints, not assumed to still hold on a different base: seccomp profile, cap_drop ALL plus cap_add SYS_CHROOT, read-only root, tmpfs /tmp, chromiumSandbox: true. Chromium launched sandboxed and navigated a real page under all of them together. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| src | ||
| test | ||
| .dockerignore | ||
| .gitignore | ||
| Dockerfile | ||
| README.md | ||
| package-lock.json | ||
| package.json | ||
| seccomp_profile.json | ||
README.md
browser-mcp
Playwright browser automation exposed only through MCP Streamable HTTP.
Security properties
- Exact-origin allowlist for top-level navigation and every intercepted HTTP(S) request.
- No filesystem/workspace mount.
- No arbitrary JavaScript evaluation, file upload, download, shell, or CDP tool.
- One isolated browser context per MCP session, destroyed when the session expires or is deleted.
- Bounded screenshots, text snapshots, console logs, network errors, request bodies, and session counts.
- API authentication is mandatory and browser-origin CORS is denied unless explicitly allowlisted.
The container runs as pwuser with the Chromium sandbox
enabled. The stack applies Playwright’s official default-derived
seccomp_profile.json, which permits the user-namespace
calls required by the sandbox, and restores only SYS_CHROOT
after dropping every capability. Keep the container on an internal
network that can reach only the development application. This is a
hardened browser worker, not a VM-grade boundary.
Tools
browser_navigate, browser_click,
browser_fill, browser_wait,
browser_snapshot, browser_screenshot,
browser_console_messages, and
browser_network_errors.
Configuration
Required environment variables:
BROWSER_MCP_API_KEYS: comma-separatedSUBJECT=TOKENvalues; tokens must contain at least 32 characters.BROWSER_MCP_ALLOWED_ORIGINS: comma-separated exact origins, for examplehttp://dev-server-worker:5173. An entry may carry a port range instead of a port —http://dev-server-worker:5200-5219— which is how one entry covers every port the dev server may hand to an execution. The host still has to match exactly; only the port varies, and only inside the declared range. An impossible range is refused at startup rather than at the first navigation.
The MCP endpoint is POST /mcp. Initialize first and
reuse the returned Mcp-Session-Id. Only Streamable HTTP is
implemented; there is no legacy SSE or stdio transport.
Run npm install and npm test for local
tests. The provided image already contains the matching Chromium
build.