@mcp-b/webmcp-local-relay connects WebMCP tools running in browser tabs to desktop MCP clients (Claude Desktop, Cursor, Claude Code, Windsurf) via a localhost WebSocket relay and stdio transport.
Architecture
| Layer | Description |
|---|---|
LocalRelayMcpServer | MCP server exposing static and dynamic tools over stdio |
RelayBridgeServer | WebSocket server managing browser connections and routing calls |
| Widget iframe | Hidden iframe injected by embed.js into the host page |
| Host page | The webpage with WebMCP tools registered on navigator.modelContext |
Installation
Add this JSON block to your MCP client configuration:.mcpb bundle file is available from GitHub Releases for Claude Desktop (double-click to install).
Minimal example
CLI options
Static management tools
The relay always exposes four management tools:| Tool | Description |
|---|---|
webmcp_list_sources | Lists connected browser tabs with metadata: tab ID, origin, URL, title, icon, tool count |
webmcp_list_tools | Lists all relayed tools with source info |
webmcp_call_tool | Invokes a relayed tool by name with JSON arguments (for clients that do not support dynamic tool registration) |
webmcp_open_page | Opens a URL in the default browser or refreshes a connected source page by matching origin |
Dynamic tool registration
Tools registered on webpages are forwarded to the MCP server as first-class tools. Tool names are sanitized to the character set[a-zA-Z0-9_].
When multiple tabs register a tool with the same name, a short tab-ID suffix disambiguates them:
| Situation | Tool name |
|---|---|
| Single provider | get_issue |
| Multiple providers | search_ed93, search_a1b2 |
Browser embed
Add a script tag to expose a page’s WebMCP tools to the relay:navigator.modelContext, they are picked up automatically.
To use a custom relay port:
localhost. Tools are discovered via navigator.modelContext (or navigator.modelContextTesting as fallback) and forwarded to the relay.
Reconnection and client mode
The widget reconnects automatically using exponential backoff (1.5x multiplier) from 500ms up to 3000ms, stopping after 100 attempts. When a second relay instance starts and the port is in use (EADDRINUSE), it falls back to client mode. In client mode the relay connects as a WebSocket client to the existing server relay and proxies tool operations through it. If the server relay stops, the client promotes itself back to server mode. This lets multiple MCP clients share the same browser connections.
Runtime compatibility
The relay supports pages using:@mcp-b/global(recommended)@mcp-b/webmcp-polyfillwithnavigator.modelContextTesting
navigator.modelContext.listTools + callTool when present, and falls back to navigator.modelContextTesting.listTools + executeTool.
Security
- Binds to
127.0.0.1by default (loopback only). - Default
allowedOriginsis*, permitting any browser page to connect. Use--widget-originto restrict which host page origins can register tools. --widget-originvalidates the host page origin reported in the browserhellomessage, not the iframe origin.- Any local process can connect regardless of origin restrictions.
Exported API
The package exports the following for programmatic use:| Export | Kind | Description |
|---|---|---|
LocalRelayMcpServer | Class | MCP server with stdio transport and dynamic tool sync |
LocalRelayMcpServerOptions | Type | Construction options |
RelayBridgeServer | Class | WebSocket relay managing browser connections |
RelayBridgeServerOptions | Type | Bridge server options |
RelayRegistry | Class | Multi-source tool aggregation and deduplication |
AggregatedTool | Type | A tool resolved across multiple sources |
SourceInfo | Type | Metadata about a connected browser tab |
sanitizeName | Function | Sanitizes a tool name to [a-zA-Z0-9_] |
buildPublicToolName | Function | Builds a disambiguated public tool name |
extractSanitizedDomain | Function | Extracts and sanitizes domain from a URL |
parseCliOptions | Function | Parses CLI arguments |
CliOptions | Type | Parsed CLI option shape |
BrowserToRelayMessageSchema, RelayToBrowserMessageSchema, RelayClientToServerMessageSchema, RelayServerToClientMessageSchema, ServerHelloMessageSchema, and their corresponding TypeScript types.
Troubleshooting
| Problem | Fix |
|---|---|
No sources connected | Verify the page loaded embed.js and the relay process is running |
No tools listed | Verify tools are registered on the page’s WebMCP runtime. Confirm the runtime emits tool-change notifications (toolschanged or registerToolsChangedCallback) |
Tool not found | Tab reloaded or disconnected. Call webmcp_list_tools to refresh |
| Connection blocked | Verify --widget-origin matches the host page origin and the relay port matches data-relay-port |
Related
- Connect Desktop Agents with Local Relay (how-to guide)
- Desktop Agent Relay (tutorial)
- @mcp-b/global (runtime reference)
- Transports and Bridges (explanation)
