npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@mcp-b/webmcp-local-relay

v2.1.0

Published

Local MCP relay for browser WebMCP tools via embed iframe and localhost WebSocket

Readme

WebMCP Local Relay

npm version

Use WebMCP tools from any website, right inside your AI client.

 Browser Tab                          Local Machine
┌──────────────────────┐             ┌──────────────────────┐
│                      │  WebSocket  │                      │
│   Website with       ├────────────▶  webmcp-local-relay   │
│   WebMCP tools       │  localhost  │   (MCP server)       │
│                      │             │                      │
└──────────────────────┘             └──────────┬───────────┘
                                                │
                                          stdio │ JSON-RPC
                                                │
                                     ┌──────────▼───────────┐
                                     │                      │
                                     │   Claude / Cursor /  │
                                     │   any MCP client     │
                                     │                      │
                                     └──────────────────────┘

Open a website that has WebMCP tools. Run the relay. The tools show up in your MCP client.

Install

{
  "mcpServers": {
    "webmcp-local-relay": {
      "command": "npx",
      "args": ["-y", "@mcp-b/webmcp-local-relay@latest"]
    }
  }
}

Add this to your MCP client config — works with Claude Desktop, Cursor, Windsurf, Claude Code, or anything that speaks MCP.

Use

Once connected, your AI client can see and call tools from any open browser tab that supports WebMCP:

  1. webmcp_list_sources — see which tabs are connected
  2. webmcp_list_tools — see all available tools
  3. Call any tool directly by name (e.g., create_issue, search_docs)

Tools appear and disappear automatically as you open, reload, and close tabs.

For Website Owners

Add one script tag to expose your page's WebMCP tools to the relay:

<script src="https://cdn.jsdelivr.net/npm/@mcp-b/webmcp-local-relay@latest/dist/browser/embed.js"></script>

That's it. If your page already registers tools on navigator.modelContext, they'll be picked up automatically.

New to WebMCP? Here's the full setup:

<script src="https://cdn.jsdelivr.net/npm/@mcp-b/global@latest/dist/index.iife.js"></script>
<script>
  navigator.modelContext.registerTool({
    name: 'get_page_title',
    description: 'Get the current page title',
    inputSchema: { type: 'object', properties: {} },
    execute: async () => ({ content: [{ type: 'text', text: document.title }] }),
  });
</script>
<script src="https://cdn.jsdelivr.net/npm/@mcp-b/webmcp-local-relay@latest/dist/browser/embed.js"></script>

Custom relay port:

<script
  src="https://cdn.jsdelivr.net/npm/@mcp-b/webmcp-local-relay@latest/dist/browser/embed.js"
  data-relay-port="9444"
></script>

Tool registration references:


Reference

Other Install Methods

The JSON config above works for most clients. Here are additional options:

Claude Desktop (MCPB bundle) — download the .mcpb file from GitHub Releases and double-click to install. No terminal needed.

Direct CLI — run the relay standalone:

npx @mcp-b/webmcp-local-relay

Exposed Tools

The relay exposes four static management tools that are always available:

| 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 — useful for clients that don't support dynamic tool registration | | webmcp_open_page | Opens a URL in the user's default browser, or refreshes a connected source page by matching origin |

Dynamic tools are registered directly on the MCP server using the original tool name, sanitized to [a-zA-Z0-9_]. When tools from different tabs share a name, a short tab-ID suffix is appended for disambiguation:

  • Single provider: get_issue
  • Multiple providers with the same name: search_ed93, search_a1b2

CLI Options

webmcp-local-relay [options]

  --host, -H               Bind host (default: 127.0.0.1)
  --port, -p               WebSocket port (default: 9333)
  --widget-origin          Allowed host page origin(s), comma-separated (default: *)
  --allowed-origin         Alias for --widget-origin
  --ws-origin              Alias for --widget-origin
  --help, -h               Show help

Examples:

# Default: loopback on port 9333
npx @mcp-b/webmcp-local-relay

# Custom port
npx @mcp-b/webmcp-local-relay --port 9444

# Restrict to tools from trusted host pages
npx @mcp-b/webmcp-local-relay --widget-origin https://myapp.com

Security

  • Binds to 127.0.0.1 by default (loopback only, not accessible from your network).
  • The default allowedOrigins is *, which permits any browser page to connect and register tools. This is convenient for development but means any website open in your browser can expose tools to the relay.
  • --widget-origin validates the host page origin reported in the browser hello message. This is the origin of the page that loaded embed.js (e.g., https://myapp.com), regardless of whether the widget iframe is served from CDN or self-hosted.
  • Recommended: Use --widget-origin to restrict which websites can register tools:
    # Only allow tools from myapp.com
    webmcp-local-relay --widget-origin https://myapp.com
    
    # Allow multiple origins
    webmcp-local-relay --widget-origin https://app1.com,https://app2.com
  • Only the host page origin is checked — any local process can connect regardless of origin restrictions.

Architecture

┌──────────────────────────────────────┐
│        MCP Client                    │
│   (Claude, Cursor, Windsurf, etc.)   │
└──────────────────┬───────────────────┘
                   │ stdio / JSON-RPC
┌──────────────────▼───────────────────┐
│        LocalRelayMcpServer           │
│   webmcp_list_sources                │
│   webmcp_list_tools                  │
│   webmcp_call_tool                   │
│   + dynamic tools from browser       │
└──────────────────┬───────────────────┘
                   │ WebSocket (ws://127.0.0.1:9333)
┌──────────────────▼───────────────────┐
│        RelayBridgeServer             │
│   Manages connections, routes calls  │
└──────────────────┬───────────────────┘
                   │ postMessage
┌──────────────────▼───────────────────┐
│        Widget iframe                 │
│   embed.js injects widget.html       │
└──────────────────┬───────────────────┘
                   │ navigator.modelContext
┌──────────────────▼───────────────────┐
│        Host page                     │
│   WebMCP runtime + registered tools  │
└──────────────────────────────────────┘

How it connects: The embed script injects a hidden iframe into the host page. The iframe opens a WebSocket to the relay on localhost. Tools are discovered via navigator.modelContext (or navigator.modelContextTesting as fallback) and forwarded to the relay, which registers them as standard MCP tools over stdio. If the relay is temporarily unavailable, the widget reconnects automatically using exponential backoff (1.5x multiplier) from 500ms up to 3000ms, stopping after 100 attempts.

Client mode: When a second relay instance starts and the port is already in use (EADDRINUSE), it automatically 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 later stops, the client attempts to promote itself back to server mode. This enables multiple MCP clients to share the same browser connections without manual configuration.

Runtime Compatibility

Supported page runtimes:

  1. @mcp-b/global (recommended)
  2. @mcp-b/webmcp-polyfill with navigator.modelContextTesting

Runtime dispatch behavior in the browser embed/widget layer:

  • Uses navigator.modelContext.listTools + callTool when present.
  • Falls back to navigator.modelContextTesting.listTools + executeTool.

WebMCP Standard Status

WebMCP is an emerging web platform proposal. This relay works today with polyfills and will support native browser implementations as they mature.

For Chromium/Chrome Canary native preview testing:

  1. Open chrome://flags/#enable-webmcp-testing
  2. Enable WebMCP for testing
  3. Restart the browser

Troubleshooting

| Problem | Fix | |---------|-----| | No sources connected | Ensure the page loaded embed.js and the relay process is running | | No tools listed | Ensure tools are registered on the page's WebMCP runtime. If tools register after load, confirm your runtime emits tool-change notifications (toolschanged or registerToolsChangedCallback) | | Tool not found | Tab reloaded or disconnected — call webmcp_list_tools again to refresh | | Connection blocked | Verify --widget-origin matches your host page's origin (e.g., https://myapp.com), and relay port matches data-relay-port |


Contributing

Project Layout

src/
├── cli.ts                 CLI entry point
├── cli-utils.ts           CLI argument parsing
├── mcpRelayServer.ts      MCP server (stdio + dynamic tool sync)
├── bridgeServer.ts        WebSocket relay server
├── registry.ts            Multi-source aggregation and deduplication
├── naming.ts              Tool name sanitization and namespacing
├── schemas.ts             Browser <-> relay protocol schemas
├── browser/embed.js       Script-tag loader for website owners
├── browser/widget.html    Hidden iframe bridge runtime
└── index.ts               Public API exports

Build and Test

From repository root:

pnpm install
pnpm --filter @mcp-b/webmcp-local-relay build
pnpm --filter @mcp-b/webmcp-local-relay test
pnpm --filter @mcp-b/webmcp-local-relay test:e2e

Build MCPB Bundle

pnpm --filter @mcp-b/webmcp-local-relay build:mcpb

Produces webmcp-local-relay-<version>.mcpb for distribution via Claude Desktop.

Plugin and Skill Files

| File | Purpose | |------|---------| | .claude-plugin/plugin.json | Claude Code plugin definition | | .claude-plugin/marketplace.json | Plugin marketplace metadata | | .mcp.json | MCP server configuration | | skills/webmcp-local-relay/SKILL.md | Claude Code skill documentation | | manifest.json | MCPB bundle manifest |

References

License

MIT