MCP server that bridges browser WebMCP tools to desktop AI apps. Connects to Chrome via Playwright and exposes 26 browser automation tools + WebMCP meta-tools over the Model Context Protocol.
npm install -g @tech-sumit/mcp-webmcpOr run directly with npx (no install needed):
npx -y @tech-sumit/mcp-webmcpAdd to your MCP client config (~/.cursor/mcp.json or Claude Desktop):
{
"mcpServers": {
"mcp-webmcp": {
"command": "npx",
"args": ["-y", "@tech-sumit/mcp-webmcp", "--launch"]
}
}
}The server launches Chrome Beta with WebMCP enabled on startup. All 26 tools are immediately available.
{
"mcpServers": {
"mcp-webmcp": {
"command": "npx",
"args": ["-y", "@tech-sumit/mcp-webmcp"]
}
}
}Without --launch, all 26 tools are registered but no browser is started. The AI agent calls the browser_launch tool when it needs a browser. This gives the client full control over when and how the browser is launched.
graph TD
subgraph mcp_webmcp ["MCP-WebMCP Server"]
PB["PlaywrightBrowserSource<br/>24 browser tools + 2 WebMCP meta-tools"]
TR[ToolRegistry]
MCP["MCP Server"]
end
subgraph transport ["Transport Layer"]
STDIO["stdio<br/>(default, for mcp.json)"]
HTTP["HTTP /mcp<br/>:3100 (optional)"]
end
subgraph browser_modes ["Browser Connection"]
Launch["--launch<br/>chromium.launch()"]
CDP["CDP :9222<br/>connectOverCDP()"]
end
Launch --> PB
CDP --> PB
PB --> TR
TR --> MCP
MCP --> STDIO
MCP --> HTTP
STDIO --> Cursor["Cursor"]
STDIO --> Claude["Claude Desktop"]
HTTP --> Any["Any MCP Client"]
| Mode | How it works | When to use |
|---|---|---|
--launch flag |
Launches Chrome on startup via chromium.launch(). Injects --enable-features=WebMCPTesting automatically. |
Zero-config setup. Browser ready immediately. |
browser_launch tool (default) |
No browser on startup. AI agent calls browser_launch tool when needed. |
Agent controls when to open the browser. |
| Transport | How to use | When to use |
|---|---|---|
| stdio | Run mcp-webmcp (no subcommand) |
For mcp.json / npx. Client spawns process, communicates via stdin/stdout. |
| HTTP | Run mcp-webmcp start |
For hosted/manual usage. Streamable HTTP on /mcp endpoint. |
| Requirement | Details |
|---|---|
| Node.js | v18+ |
| Chrome | Version 146+ (Beta or Canary). Stable Chrome will not work until WebMCP ships. |
# macOS — Chrome Beta
/Applications/Google\ Chrome\ Beta.app/Contents/MacOS/Google\ Chrome\ Beta --version
# macOS — Chrome Canary
/Applications/Google\ Chrome\ Canary.app/Contents/MacOS/Google\ Chrome\ Canary --version
# Linux
google-chrome-beta --version
# Windows
"C:\Program Files\Google\Chrome Beta\Application\chrome.exe" --versionThe server validates Chrome >= 146 on startup and will throw a clear error if the version is too old.
Add to ~/.cursor/mcp.json:
{
"mcpServers": {
"mcp-webmcp": {
"command": "npx",
"args": ["-y", "@tech-sumit/mcp-webmcp"]
}
}
}Add "--launch" to args if you want Chrome to open on startup.
Add to ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"mcp-webmcp": {
"command": "npx",
"args": ["-y", "@tech-sumit/mcp-webmcp"]
}
}
}{
"mcpServers": {
"mcp-webmcp": {
"command": "node",
"args": ["/path/to/dist/cli.js"]
}
}
}For manual or hosted usage, run the server as an HTTP endpoint:
mcp-webmcp start [--launch] [--port 3100]Connect your MCP client to http://localhost:3100/mcp.
mcp-webmcp config cursor # writes ~/.cursor/mcp.json
mcp-webmcp config claude # writes Claude Desktop config| Flag | Description | Default |
|---|---|---|
--launch |
Launch browser on startup (otherwise use browser_launch tool) |
false |
--channel <ch> |
Browser channel: chrome, chrome-beta, chrome-canary, msedge, msedge-beta, msedge-dev |
chrome-beta |
--headless |
Run browser in headless mode | false |
--url <url> |
Navigate to URL after launch | (none) |
graph TD
subgraph browser_auto ["Browser Automation (24 tools)"]
direction LR
Nav["Navigation<br/>navigate, back, forward, reload"]
State["Page State<br/>url, snapshot, screenshot<br/>console_logs, network_requests"]
Interact["Interaction<br/>click, type, fill, hover<br/>select_option, press_key, focus"]
Scroll["Scrolling<br/>scroll"]
Tabs["Tab Management<br/>tab_list, tab_new<br/>tab_select, tab_close"]
JS["JavaScript<br/>evaluate"]
Wait["Wait<br/>wait"]
Lifecycle["Lifecycle<br/>launch"]
end
subgraph webmcp_meta ["WebMCP Meta-Tools (2 tools)"]
direction LR
List["webmcp_list_tools<br/>Discover page tools"]
Call["webmcp_call_tool<br/>Execute page tools"]
end
| Tool | Description |
|---|---|
browser_launch |
Launch a new browser window (closes existing). Supported channels: chrome, chrome-beta, chrome-canary, msedge. Cross-platform. |
browser_navigate |
Navigate to a URL |
browser_back |
Go back in history |
browser_forward |
Go forward in history |
browser_reload |
Reload current page |
browser_url |
Get current URL and title |
browser_snapshot |
Accessibility tree with [ref=N] markers for element targeting |
browser_screenshot |
Take a PNG screenshot |
browser_console_logs |
Get buffered console log messages |
browser_network_requests |
Get buffered network requests with status codes |
browser_click |
Click an element by ref |
browser_type |
Type text character by character |
browser_fill |
Clear and fill an input field |
browser_hover |
Hover over an element |
browser_select_option |
Select a dropdown option |
browser_press_key |
Press a keyboard key |
browser_focus |
Focus an element |
browser_scroll |
Scroll page or element |
browser_tab_list |
List all open tabs |
browser_tab_new |
Open a new tab |
browser_tab_select |
Switch to a tab |
browser_tab_close |
Close a tab |
browser_evaluate |
Execute JavaScript in page context |
browser_wait |
Wait for time or CSS selector |
| Tool | Description |
|---|---|
webmcp_list_tools |
List WebMCP tools registered on the active page |
webmcp_call_tool |
Execute a WebMCP tool by name on the active page |
WebMCP tools are dynamic — they change as the user navigates between pages. Always call webmcp_list_tools before webmcp_call_tool to discover what's available.
sequenceDiagram
participant Agent
participant Server
participant Page
Agent->>Server: browser_snapshot
Server->>Page: ariaSnapshot()
Page-->>Server: Accessibility tree
Note over Server: Assigns [ref=N] to each element
Server-->>Agent: Annotated snapshot
Note over Agent: Picks ref=5 for Submit button
Agent->>Server: browser_click {ref: 5}
Note over Server: Resolves ref=5 via getByRole().nth()
Server->>Page: Click resolved locator
Page-->>Server: Done
Server-->>Agent: Clicked button Submit ref=5
Run as stdio MCP server. This is what mcp.json invokes.
mcp-webmcp [options]| Option | Description | Default |
|---|---|---|
--launch |
Launch browser on startup (otherwise use browser_launch tool) |
false |
--channel <ch> |
Browser channel | chrome-beta |
--headless |
Launch in headless mode | false |
--url <url> |
Initial URL to open | (none) |
--extension |
Enable Chrome extension WebSocket bridge | false |
--ws-port <port> |
Extension WebSocket port | 8765 |
--no-browser-tools |
Disable Playwright browser tools | false |
Start the MCP server over HTTP.
mcp-webmcp start [options]Same options as stdio mode, plus:
| Option | Description | Default |
|---|---|---|
--port <port> |
HTTP server port | 3100 |
List all WebMCP tools from connected browser tabs (uses CDP directly).
mcp-webmcp list-tools [--host localhost] [--port 9222]Execute a WebMCP tool by name.
mcp-webmcp call-tool searchFlights '{"from":"SFO","to":"JFK"}'Write MCP client configuration (stdio-based).
mcp-webmcp config cursor # writes ~/.cursor/mcp.json
mcp-webmcp config claude # writes Claude Desktop configThis demo shows the full flow: an AI agent uses browser_launch to open Chrome, navigates to a WebMCP-enabled restaurant page, discovers the book_table_le_petit_bistro tool, and books a table — all via MCP.
sequenceDiagram
participant Agent as AI Agent (Cursor)
participant MCP as MCP-WebMCP
participant Chrome as Chrome Browser
participant Page as Le Petit Bistro
Agent->>MCP: browser_launch {channel: "chrome-beta"}
MCP->>Chrome: chromium.launch()
Chrome-->>MCP: Browser ready
MCP-->>Agent: "Launched chrome-beta"
Agent->>MCP: browser_navigate {url: "localhost:5173"}
MCP->>Chrome: page.goto()
Chrome-->>MCP: Page loaded
MCP-->>Agent: "Le Petit Bistro"
Agent->>MCP: webmcp_list_tools
MCP->>Page: navigator.modelContextTesting.listTools()
Page-->>MCP: [{name: "book_table_le_petit_bistro", ...}]
MCP-->>Agent: Tool schema with inputs
Agent->>MCP: webmcp_call_tool {name: "book_table_le_petit_bistro", ...}
MCP->>Page: navigator.modelContextTesting.executeTool(...)
Page-->>MCP: "Reservation confirmed"
MCP-->>Agent: "Hello Sumit, We look forward to welcoming you..."
browser_launchopens Chrome Beta with--enable-features=WebMCPTestingbrowser_navigateloads the Le Petit Bistro reservation formwebmcp_list_toolsdiscoversbook_table_le_petit_bistroand its full input schema (name, phone, date, time, guests, seating, requests)webmcp_call_toolbooks the table — the form auto-fills and a confirmation modal appears: "Reservation Received — Bon Appetit!"
flowchart TD
Problem(["Something went wrong"]) --> Q0{"Using --launch mode?"}
Q0 -- Yes --> Q0a{"Chrome Beta/Canary<br/>installed?"}
Q0a -- No --> F0["Install Chrome Beta<br/>chrome.google.com/beta"]
Q0a -- Yes --> Q3
Q0 -- No --> Q1{"Can you reach Chrome?<br/>curl localhost:9222/json/version"}
Q1 -- No --> F1["Launch Chrome with<br/>--remote-debugging-port=9222"]
Q1 -- Yes --> Q2{"Chrome version >= 146?"}
Q2 -- No --> F2["Install Chrome Beta/Canary"]
Q2 -- Yes --> Q3{"Server starts?"}
Q3 -- No --> F3["Check error message in stderr"]
Q3 -- Yes --> Q4{"MCP client connects?"}
Q4 -- No --> F4["Check mcp.json config<br/>Toggle MCP off/on"]
Q4 -- Yes --> Q5{"WebMCP tools work?"}
Q5 -- No --> F5["Ensure --enable-features=WebMCPTesting<br/>(--launch adds it automatically)"]
Q5 -- Yes --> OK(["Everything working"])
Your Chrome is older than 146. Install Chrome Beta or Canary:
Chrome was not launched with --enable-features=WebMCPTesting. If using CDP mode, close all Chrome windows and relaunch with the flag. Launch mode (--launch) adds this flag automatically.
Chrome is not running with --remote-debugging-port=9222, or it has no tabs open. Use --launch mode instead, or verify with:
curl http://localhost:9222/json/versionThe browser connection was lost. Use browser_launch tool to start a new browser, or restart the MCP server.
Playwright waits for web fonts to load before taking screenshots. The server uses a 10-second timeout to avoid hanging.
Elements in position: fixed overlays may not be scrollable into view. The server automatically retries with force: true to click at the element's coordinates directly.
pnpm install # install dependencies
pnpm build # compile with tsup → dist/
pnpm dev # watch mode
pnpm start # run HTTP server (CDP mode)
pnpm start:stdio # run stdio server
pnpm typecheck # tsc --noEmit
pnpm lint # eslint
pnpm test # vitest
pnpm format # prettierMIT