AgentSkillsCN

webmcp-marketplace-plugins

创建 WebMCP 市场插件(桥接脚本),将 MCP 工具无缝接入任意网站。适用于以下场景:(1) 为特定网站创建全新市场插件;(2) 编写 webmcp-bridge.json 清单文件;(3) 编写调用 navigator.modelContext.registerTool() 的桥接脚本;(4) 选择用于脚本注入的 URL 匹配模式;(5) 了解插件的验证规则与约束条件;(6) 通过本地文件夹安装测试插件;(7) 将插件发布至 GitHub,供用户通过 user/repo@ref 进行安装。

SKILL.md
--- frontmatter
name: webmcp-marketplace-plugins
description: "Create WebMCP marketplace plugins (bridge scripts) that add MCP tools to any website. Use when: (1) Creating a new marketplace plugin for a specific website, (2) Writing a webmcp-bridge.json manifest, (3) Writing bridge scripts that call navigator.modelContext.registerTool(), (4) Choosing URL match patterns for script injection, (5) Understanding plugin validation rules and constraints, (6) Testing plugins via local folder install, (7) Publishing plugins to GitHub for installation via user/repo@ref."

WebMCP Marketplace Plugins

A marketplace plugin is a GitHub repo (or local folder) containing a webmcp-bridge.json manifest and JavaScript bridge scripts. Scripts are IIFEs that call navigator.modelContext.registerTool() to add MCP tools to websites.

Quick Start

Minimal plugin structure:

code
my-plugin/
├── webmcp-bridge.json
└── scripts/
    └── main.js

webmcp-bridge.json:

json
{
  "name": "my-plugin",
  "version": "1.0.0",
  "description": "What this plugin does",
  "author": "your-name",
  "license": "MIT",
  "scripts": [
    {
      "id": "main",
      "name": "Main Script",
      "description": "Brief description",
      "file": "scripts/main.js",
      "matches": ["*://example.com/*"],
      "runAt": "document_idle"
    }
  ]
}

scripts/main.js:

js
(function () {
  "use strict";
  if (!navigator.modelContext) return;

  navigator.modelContext.registerTool({
    name: "my_tool",
    description: "What this tool does",
    inputSchema: {
      type: "object",
      properties: {
        query: { type: "string", description: "Parameter description" },
      },
    },
    execute: async (args) => {
      // DOM access, fetch, localStorage — all standard browser APIs available
      return { result: "Tool output" };
    },
  });
})();

Manifest Reference

Top-level fields

FieldRequiredTypeDescription
nameYesstringPackage identifier (non-empty)
versionYesstringSemver (e.g. "1.0.0")
descriptionNostringShown in plugin management UI
authorNostringAuthor name
licenseNostringSPDX identifier
scriptsYesarrayNon-empty array of script entries

Script entry fields

FieldRequiredTypeDescription
idYesstringUnique within the package
nameNostringHuman-readable label for UI
descriptionNostringBrief description
fileYesstringPath relative to manifest
matchesYesstring[]URL match patterns (non-empty)
runAtNostring"document_idle" (default) or "document_start"

Match Patterns

Chrome extension match pattern syntax: scheme://host/path

PatternMatches
<all_urls>All HTTP/HTTPS URLs
*://mail.google.com/*Gmail (HTTP or HTTPS)
https://github.com/*GitHub HTTPS only
*://*.google.com/*All Google subdomains
https://example.com/app/*Specific path prefix
  • Scheme: http, https, or * (both)
  • Host: exact (example.com), wildcard subdomains (*.example.com), or * (any)
  • Path: /* (any), or a specific prefix

Script Authoring

Requirements

  1. Wrap in an IIFE: (function () { "use strict"; ... })();
  2. Guard with if (!navigator.modelContext) return;
  3. Use inputSchema (not schema) in the tool descriptor
  4. The execute callback receives a plain args object, return the result

WebMCP API

js
navigator.modelContext.registerTool(descriptor); // Register one tool
navigator.modelContext.unregisterTool(name); // Remove by name
navigator.modelContext.provideContext({ tools: [] }); // Batch register (array)
navigator.modelContext.clearContext(); // Remove all tools

Execution context

  • Scripts run in the MAIN world (full page JS/DOM access)
  • Injected via chrome.scripting.executeScript({ world: 'MAIN' })
  • The extension's content-main.js wraps ModelContext.prototype.registerTool at document_start, intercepting all registrations automatically
  • Scripts re-inject on navigation; no cleanup needed

runAt timing

  • document_idle (default): Injected after page load complete. Use for most plugins.
  • document_start: Injected during loading. Use only if intercepting early page behavior.

Common patterns

DOM scraping tool:

js
execute: async () => {
  const items = [...document.querySelectorAll(".item")];
  return { items: items.map((el) => ({ text: el.textContent, href: el.href })) };
};

Form interaction tool:

js
execute: async (args) => {
  document.querySelector("#search-input").value = args.query;
  document.querySelector("#search-form").submit();
  return { status: "submitted" };
};

Multiple tools in one script:

js
(function () {
  "use strict";
  if (!navigator.modelContext) return;

  navigator.modelContext.registerTool({ name: "tool_a" /* ... */ });
  navigator.modelContext.registerTool({ name: "tool_b" /* ... */ });
})();

Validation

Scripts are scanned for dangerous patterns on install. See references/validation-rules.md for the complete list of blocked patterns and obfuscation thresholds.

Key constraints:

  • No eval(), new Function(), document.write()
  • No dynamic <script> creation
  • No WebSocket connections to non-localhost hosts
  • No setAttribute("on...") for inline event handlers
  • Obfuscated code (heavy hex/unicode escapes, minified lines) triggers warnings
  • Syntax errors are NOT caught at install time (extension CSP blocks new Function); they surface at injection time

Testing

Local folder install

  1. Create folder with webmcp-bridge.json + scripts
  2. Open extension popup > Manage Plugins
  3. Click Load Folder, select the folder
  4. Navigate to a URL matching your patterns
  5. Tools appear in the extension badge and your MCP client

Dev browser

bash
bun run chrome       # Launch Chrome with extension pinned
bun run chrome:dev   # Chrome + CLI together

GitHub install

Push to GitHub, then install via user/repo@ref in the plugins page:

code
user/repo@v1.0.0     # tag (recommended)
user/repo@main        # branch
user/repo             # latest release or default branch

Working Example

See examples/marketplace/ in the webmcp-bridge repo for a complete working plugin that registers a hello_world tool on all URLs.