opencode-webmcp
Click on "Install 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., "@opencode-webmcpshow available WebMCP tools on the current page"
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.
opencode-webmcp
MCP bridge connecting OpenCode to Chromium's WebMCP API.
Exposes WebMCP tools registered in a Chromium page as MCP tools consumable by any MCP client (OpenCode, Claude Code, etc.).
How It Works
OpenCode (MCP client)
↕ MCP stdio protocol
webmcp-bridge (MCP server)
↕ Puppeteer + CDP
Chromium (WebMCP enabled)
↕ monkey-patched document.modelContext
Web page with registered WebMCP toolsThe bridge launches Chromium with --enable-features=WebMCPTesting, navigates to a target page, discovers tools via the WebMCP API, and makes them available to MCP clients.
Monkey-patch: Chrome 150+ has a bug where page.webmcp.invokeTool() returns {} instead of the actual tool result. The bridge works around this by intercepting registerTool to capture execute functions and replacing executeTool to call the captured functions directly.
Related MCP server: openclaw-tools-mcp
Prerequisites
Node.js 18+
Chromium/Chrome with WebMCP support (Chrome 150+)
An MCP client (OpenCode, Claude Code, etc.)
Setup
git clone <repo-url> webmcp-bridge
cd webmcp-bridge
npm installUsage
Standalone
CHROME_PATH=/usr/bin/chromium \
WEBMCP_TARGET_URL="https://www.google.com" \
WEBMCP_HEADLESS=false \
node server.jsWith a config file
node server.js --config ./webmcp.yamlIf --config is omitted, the bridge looks for ./webmcp.yaml, ./webmcp.yml, or ./webmcp.json in the current working directory before falling back to environment variables.
Layered precedence (highest wins): CLI args → config file → environment variables → built-in defaults.
For example, node server.js --no-headless overrides headless: true in a config file, which overrides WEBMCP_HEADLESS=true in the environment.
Supported keys (camelCase): chromePath, targetUrl, headless, historyMax, logHistory.
Example webmcp.yaml:
chromePath: /usr/bin/chromium
targetUrl: https://www.google.com
headless: false
historyMax: 500
logHistory: falseOr webmcp.json:
{
"chromePath": "/usr/bin/chromium",
"targetUrl": "https://www.google.com",
"headless": false
}OpenCode (opencode.json)
{
"mcp": {
"webmcp-bridge": {
"command": ["node", "/path/to/webmcp-bridge/server.js"],
"enabled": true,
"type": "local",
"environment": {
"CHROME_PATH": "/usr/bin/chromium",
"WEBMCP_TARGET_URL": "about:blank",
"WEBMCP_HEADLESS": "false"
}
}
}
}Quick Start (OpenCode)
After adding the config above, restart OpenCode. The bridge tools are now available — just ask:
"Navigate to a WebMCP-enabled page and tell me what tools are available"
OpenCode calls webmcp_navigate → bridge opens the page → webmcp_status to show discovered tools. From there you can invoke any page tool, take screenshots, evaluate JS, or manage tabs conversationally.
For a full 8-step walkthrough (status → navigate → discover → invoke → screenshot → evaluate → history), see examples/GETTING_STARTED.md.
Environment Variables
Variable | Default | Description |
|
| Path to Chromium/Chrome executable |
|
| Initial page to navigate to |
|
| Run headless ( |
|
| Maximum number of tool invocations to keep in the in-memory history ring buffer |
|
| When |
|
| Scan the page DOM for declarative WebMCP tools ( |
Bridge-Native Tools
These tools are always available, regardless of what the page exposes:
Tool | Description |
| Navigate Chrome to a URL and refresh discovered WebMCP tools |
| Report connection status, current URL, and available tools |
| Execute arbitrary JavaScript in the page context |
| Call any WebMCP tool by name with arguments |
| Register sample tools ( |
| Capture a screenshot of the current page (PNG/JPEG, viewport/full-page/clip) and return it as an MCP image |
| Return recent tool invocations from the in-memory history buffer (most recent first; optional |
| Empty the in-memory history buffer |
| Open a new tab, optionally navigating to a URL; returns the new tabId |
| Make a specific tab the active tab |
| List all open tabs with |
| Close a tab by tabId (cannot close the last one) |
webmcp_screenshot example
Default (viewport PNG):
{ "name": "webmcp_screenshot", "arguments": {} }Full-page JPEG at quality 75:
{ "name": "webmcp_screenshot", "arguments": { "format": "jpeg", "quality": 75, "fullPage": true } }Region clip (200×100 at top-left):
{ "name": "webmcp_screenshot", "arguments": { "clip": { "x": 0, "y": 0, "width": 200, "height": 100 } } }Multi-Tab Sessions
The bridge can manage multiple Puppeteer tabs sharing a single browser context. Each tab has a UUID tabId; one tab is active at a time. Tools without tabId act on the active tab; pass tabId to target a specific tab without switching.
{ "name": "webmcp_open_tab", "arguments": { "url": "https://example.com" } }
// → { "tabId": "a1b2c3d4-…", "url": "https://example.com" }
{ "name": "webmcp_list_tabs", "arguments": {} }
// → { "count": 2, "tabs": [{ "tabId": "…", "url": "…", "title": "…", "isActive": true }, …] }
{ "name": "webmcp_switch_tab", "arguments": { "tabId": "a1b2c3d4-…" } }
{ "name": "webmcp_invoke_tool", "arguments": { "name": "search", "args": { "q": "weather" }, "tabId": "a1b2c3d4-…" } }
{ "name": "webmcp_close_tab", "arguments": { "tabId": "a1b2c3d4-…" } }Closing the last remaining tab returns an error. When the active tab is closed (with other tabs remaining), the next tab in the map becomes active.
Architecture
server.js— single-file MCP server using@modelcontextprotocol/sdkPuppeteer (
puppeteer-core) — drives Chromium via Chrome DevTools ProtocolMonkey-patch —
page.evaluateOnNewDocumentinjects a script that interceptsdocument.modelContext.registerToolandexecuteToolto capture actualexecutefunctionsDeclarative API scanner — also scans the DOM for
<form toolname="…">and synthesizes MCP tools from[toolname-target]attributes. Wired through a 100ms-debounced MutationObserver that flips a dirty flag whenever[toolname]attributes change. Imperative tools take precedence on name collisions.
Tool Annotations
MCP tool annotations (title, readOnlyHint, destructiveHint, idempotentHint, openWorldHint) are surfaced to MCP clients. Defaults for bridge-native tools:
Tool | readOnly | destructive | openWorld |
| false | false | true |
| true | false | false |
| false | true | true |
| (page-determined) | (page-determined) | (page-determined) |
| true | false | false |
| false | false | false |
| true | false | false |
| false | true | false |
| false | false | false |
Page-discovered tools forward their annotations to MCP clients as-is. The bridge never overrides page-supplied annotations. If a page calls registerTool("delete_account", { annotations: { destructiveHint: true } }), that annotation flows through to tools/list. Annotation changes on the page trigger notifications/tools/list_changed.
Clients that ignore the annotations field see no behavior change.
Declarative WebMCP API
Chrome's WebMCP API has two surfaces. The bridge handles both:
Imperative — pages call
document.modelContext.registerTool({ name, inputSchema, execute }).Declarative — pages annotate HTML with
toolname/toolname-targetattributes:<form toolname="search"> <input name="q" toolname-target="search.query" required> <input name="limit" toolname-target="search.limit" type="number"> <button>Search</button> </form>
The bridge synthesizes an MCP tool descriptor from this form. Invoking the tool fills the targeted fields with the provided arguments and dispatches a submit event on the form.
Name collisions: if the page registers an imperative tool with the same name, the imperative registration wins.
Opt-out: set WEBMCP_DECLARATIVE_SCAN=false to disable DOM scanning and the MutationObserver entirely.
Troubleshooting
"Failed to parse input arguments" — caused by
document.modelContext.executeTool()failing on the page side. The monkey-patch bypasses this by calling the captured executor directly."detached Frame" — the page was navigated away or closed. The bridge auto-recovers by creating a new page. Re-run the tool call.
No tools discovered — ensure the page has called
document.modelContext.registerTool()with tool definitions. Usewebmcp_evaluateto calldocument.modelContext.getTools()manually.CORS errors in test tools —
test_fetch_titleusesfetch()which is subject to page CSP. Test on a permissive origin.
License
MIT
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- Alicense-qualityBmaintenanceAn MCP server that runs in the browser, letting web pages register custom tools and prompts and expose them to an MCP client over WebSocket. Enables agents to drive UI, call page-scoped APIs, and get human-in-the-loop confirmation.Last updated6MIT
- Alicense-qualityFmaintenanceExposes OpenClaw tools (web search, page fetching, browser automation, PDF analysis, messaging, inter-agent communication, Canvas) as MCP tools for ACP agents.Last updated1The Unlicense
- Flicense-qualityDmaintenanceEnables websites to expose JavaScript functions as MCP tools, allowing AI agents to interact with the browser environment via a protocol and Chrome extension.Last updated1,072
- Flicense-qualityDmaintenanceBridges web browsers and Claude Code for seamless debugging workflows by receiving debug data from browser widgets and exposing it to Claude Code via MCP protocol.Last updated
Related MCP Connectors
Access Kernel's cloud-based browsers and app actions via MCP (remote HTTP + OAuth).
Browser MCP for logged-in tasks. Uses your Chrome — credentials stay local. Zero-token replay.
Live browser debugging for AI assistants — DOM, console, network via MCP.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/enihcam/opencode-webmcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server