Skip to content

feat(plugin-webmcp): add WebMCP support - #3520

Open
ScriptedAlchemy wants to merge 19 commits into
mainfrom
codex/plugin-webmcp
Open

feat(plugin-webmcp): add WebMCP support#3520
ScriptedAlchemy wants to merge 19 commits into
mainfrom
codex/plugin-webmcp

Conversation

@ScriptedAlchemy

@ScriptedAlchemy ScriptedAlchemy commented Jul 15, 2026

Copy link
Copy Markdown

Summary

  • add the official @rspress/plugin-webmcp package using the native document.modelContext browser API
  • expose built-in current-page, local-search, and internal-navigation tools, plus imperative registration APIs for custom tools
  • keep runtime options immutable and derive production/search availability from canonical Rspress state
  • refresh local search correctly across language and version navigation, and simplify tool re-registration around descriptor changes
  • provide locally owned public schema types with compile-time MCP-B 4.0 compatibility checks
  • add documentation, a changeset, unit coverage, and production/development Playwright fixtures including HMR behavior

Split PRs

To reduce the scope of this PR, its Core prerequisites were extracted into independently reviewable PRs:

After these prerequisites land, this PR can be rebased and narrowed to the WebMCP plugin, documentation, and integration coverage.

Related Issue

N/A

Verification

  • pnpm test:type
  • focused Rstest suite: 26 tests passed
  • WebMCP Playwright suite: 12 tests passed
  • pnpm lint
  • pnpm build
  • manually drove production preview and development/HMR WebMCP behavior

The repository-wide pnpm test run passed all type checks and 326 unit tests. One existing plugin-llms E2E assertion remains reproducibly failing because the generated zh/llms.txt is empty. The same failure reproduces after restoring all core files changed by this branch to HEAD, so it is unrelated to this PR.

Checklist

  • Tests updated (or not required).
  • Documentation updated (or not required).

🤖 Generated with Claude Code

Copilot AI review requested due to automatic review settings July 15, 2026 04:45
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 15, 2026

Copy link
Copy Markdown

Deploying rspress-v2 with  Cloudflare Pages  Cloudflare Pages

Latest commit: b19adaf
Status: ✅  Deploy successful!
Preview URL: https://337c6da5.rspress-v2.pages.dev
Branch Preview URL: https://codex-plugin-webmcp.rspress-v2.pages.dev

View logs

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new official @rspress/plugin-webmcp package that exposes Rspress documentation tools to browser agents via the native document.modelContext WebMCP API, with accompanying docs, fixtures, and core runtime updates to support hot-refreshable local search and awaited internal navigation.

Changes:

  • Introduces @rspress/plugin-webmcp (runtime + types + tests) with built-in current-page, search, and internal navigation tools plus custom tool registration APIs.
  • Updates core runtime to (a) reinitialize local search across language/version changes and (b) support awaited/cancellable link navigation.
  • Adds docs (EN/ZH), changeset, dictionary entry, and Playwright fixtures covering production + dev/HMR behavior.

Reviewed changes

Copilot reviewed 49 out of 51 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
website/docs/zh/plugin/official-plugins/webmcp.mdx Adds Chinese documentation for the new WebMCP plugin.
website/docs/zh/plugin/official-plugins/overview.mdx Links the new plugin from the official plugins overview (ZH).
website/docs/zh/plugin/official-plugins/_meta.json Adds webmcp to the official plugin docs sidebar ordering (ZH).
website/docs/en/plugin/official-plugins/webmcp.mdx Adds English documentation for the new WebMCP plugin.
website/docs/en/plugin/official-plugins/overview.mdx Links the new plugin from the official plugins overview (EN).
website/docs/en/plugin/official-plugins/_meta.json Adds webmcp to the official plugin docs sidebar ordering (EN).
scripts/dictionary.txt Adds webmcp to the spellcheck dictionary.
pnpm-lock.yaml Locks new dependencies/importers for the plugin and fixtures.
packages/plugin-webmcp/tsconfig.json Adds TS project config for the new plugin package.
packages/plugin-webmcp/tests/useWebMcpTool.test.ts Unit tests for descriptor dependency tracking/serialization behavior.
packages/plugin-webmcp/tests/types.test.ts Compile-time structural compatibility assertions vs MCP-B types.
packages/plugin-webmcp/tests/tsconfig.json Adds a no-emit TS config for type-focused tests.
packages/plugin-webmcp/tests/runtime.test.tsx Ensures runtime UI does not mount in unsupported environments.
packages/plugin-webmcp/tests/register.test.ts Unit tests for tool registration forwarding and failure handling.
packages/plugin-webmcp/tests/plugin.test.ts Unit tests for plugin config behavior (SSG-MD enabling/validation, options immutability).
packages/plugin-webmcp/tests/builtins.test.ts Unit tests for built-in current-page/search/navigate tool behaviors and validation.
packages/plugin-webmcp/src/runtime/WebMcpRuntime.tsx Implements runtime mounting of built-in tools with awaited navigation + search integration.
packages/plugin-webmcp/src/runtime/useWebMcpTool.ts React hook for tool lifecycle registration with re-registration rules.
packages/plugin-webmcp/src/runtime/types.ts Public, locally owned schema/tool types exported by the runtime.
packages/plugin-webmcp/src/runtime/register.ts Low-level registration helpers around document.modelContext.
packages/plugin-webmcp/src/runtime/index.ts Exposes runtime API surface (registerWebMcpTool, useWebMcpTool, types).
packages/plugin-webmcp/src/runtime/builtins.ts Implements built-in tool descriptors + internal-route resolution/validation.
packages/plugin-webmcp/src/options.ts Defines plugin options + normalization for runtime options.
packages/plugin-webmcp/src/index.ts Plugin entry: config normalization, SSG-MD enforcement, global UI wiring.
packages/plugin-webmcp/src/env.d.ts Adds rslib type references for the new package.
packages/plugin-webmcp/rslib.config.ts rslib build configuration for package + runtime outputs.
packages/plugin-webmcp/README.md Package README pointing to hosted documentation.
packages/plugin-webmcp/package.json New package manifest, exports, scripts, and peer deps.
packages/plugin-webmcp/LICENSE New package license file.
packages/core/src/theme/logic/useFullTextSearch.ts Reworks local search hook to re-init on language/version changes.
packages/core/src/theme/components/Link/useLinkNavigate.ts Adds optional abort signal support and improves navigation preloading lifecycle.
packages/core/src/node/runtimeModule/siteData/createSiteData.ts Preserves search: false and prevents leaking searchHooks in site data.
packages/core/src/node/runtimeModule/siteData/createSiteData.test.ts Unit coverage for the adjusted site data search serialization behavior.
packages/core/src/node/runtimeModule/pageData/rsbuildPlugin.ts Refreshes page/search index generation to support HMR-driven updates.
packages/core/src/node/PluginDriver.ts Defers defaulting llms until after plugin config hooks run.
packages/core/src/node/PluginDriver.test.ts Adds tests validating the new llms defaulting order vs plugin hooks.
package.json Updates root test to include recursive type tests via test:type.
e2e/fixtures/plugin-webmcp/webmcpTestUtils.ts Playwright helpers for listing/executing WebMCP tools.
e2e/fixtures/plugin-webmcp/src/polyfill.ts Fixture pre-entry to load the WebMCP polyfill for browsers without native support.
e2e/fixtures/plugin-webmcp/src/PageScopedTool.tsx Fixture React tool registered only while a page is mounted.
e2e/fixtures/plugin-webmcp/src/CounterTools.tsx Fixture tools demonstrating hook-based + imperative registration APIs.
e2e/fixtures/plugin-webmcp/rspress.config.ts Fixture site configuration exercising locales, versions, search, and WebMCP plugin.
e2e/fixtures/plugin-webmcp/package.json Fixture package manifest with polyfill and workspace deps.
e2e/fixtures/plugin-webmcp/index.test.ts Playwright suite covering preview + dev/HMR WebMCP behavior.
e2e/fixtures/plugin-webmcp/doc/v2/zh/index.mdx Fixture content for versioned + locale-specific search (v2/zh).
e2e/fixtures/plugin-webmcp/doc/v2/en/index.mdx Fixture content for versioned local search (v2/en).
e2e/fixtures/plugin-webmcp/doc/v1/zh/index.mdx Fixture content for locale switch search refresh (v1/zh).
e2e/fixtures/plugin-webmcp/doc/v1/en/index.mdx Fixture home content used by WebMCP tool assertions (v1/en).
e2e/fixtures/plugin-webmcp/doc/v1/en/guide.mdx Fixture guide page used for navigation + page-scoped tool assertions.
e2e/fixtures/plugin-webmcp/doc/v1/en/failure.mdx Fixture route used to exercise failed lazy-route navigation behavior.
.changeset/tidy-tools-webmcp.md Changeset for the new plugin and core updates.
Files not reviewed (1)
  • pnpm-lock.yaml: Generated file

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/core/src/node/runtimeModule/pageData/rsbuildPlugin.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7cb9b96025

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/core/src/node/runtimeModule/pageData/rsbuildPlugin.ts Outdated
@ScriptedAlchemy

ScriptedAlchemy commented Jul 15, 2026

Copy link
Copy Markdown
Author

RFC: Native WebMCP support for Rspress

Status: Implemented and validated in this PR.

Summary

Add @rspress/plugin-webmcp, an official plugin that exposes Rspress documentation capabilities through the browser-native document.modelContext API.

import { pluginWebMcp } from "@rspress/plugin-webmcp";

export default defineConfig({
  plugins: [
    pluginWebMcp({
      exposedTo: ["https://agent.example"],
    }),
  ],
});

exposedTo optionally forwards secure cross-origin agent origins to every built-in registration. Same-origin use needs no configuration.

Built-in tools

Tool Purpose
rspress_get_site_info Returns site metadata, locales, versions, navigation, and the active sidebar.
rspress_list_pages Filters and paginates page metadata for the active locale/version, independent of the search provider.
rspress_get_page Returns metadata and SSG-MD Markdown for any known route without navigating.
rspress_get_current_page Returns page metadata and its SSG-MD Markdown.
rspress_search_docs Searches through the active provider. Local search and @rspress/plugin-algolia work automatically; omitted only when no provider is available.
rspress_navigate Navigates to a known internal route, then returns lightweight page metadata, actionable section routes, and previous/next pages. Rejects unknown and external routes.

Read tools are marked read-only and untrusted-content aware. Navigation is non-read-only and also marks its documentation-derived result as untrusted.
Built-in arguments are validated during execution as well as described by JSON Schema.

rspress_navigate waits for the Rspress SPA route to render and returns enough state to continue without eagerly loading Markdown:

{
  "routePath": "/guide?source=agent#install",
  "page": {
    "title": "Guide",
    "description": "Learn the fundamentals.",
    "lang": "en",
    "version": "v2"
  },
  "sections": [
    {
      "title": "Install",
      "depth": 2,
      "routePath": "/guide?source=agent#install"
    }
  ],
  "previousPage": { "title": "Introduction", "routePath": "/intro" },
  "nextPage": { "title": "Configuration", "routePath": "/config" }
}

The agent can then call rspress_get_page with the returned routePath when it needs full Markdown. rspress_get_current_page returns the equivalent current-page metadata plus TOC, frontmatter, and Markdown.

This follows Chrome's guidance to finish UI updates before resolving a tool. Unlike full-document navigation, whose result is discarded by the native API, Rspress navigation stays within its SPA and can return post-render context.

Prior art

  • Angular ties tools to application, route, and injection lifecycles; this supports the plugin's React mount/unmount cleanup model.
  • Astro WebMCP is the closest documentation-site adapter found, with search, section listing, navigation, and page metadata, but it targets an older API and full-page navigation cannot return post-navigation state.
  • MCP-B React hooks and WebMCP Nexus informed descriptor refresh, execution-closure, and HMR tests. Their polyfill/full-runtime behavior remains outside production scope.

No established Docusaurus or VitePress WebMCP adapter surfaced in the audit.

Custom tools

The runtime entry exports:

  • registerWebMcpTool(tool, { exposedTo? }) for imperative registration;
  • useWebMcpTool(tool, options?, deps?) for React lifecycle registration and AbortSignal cleanup;
  • local spec-aligned tool, annotation, registration, and hook-state types.

Unsupported browsers and SSR builds safely no-op.

React hook example

Mount the component from a theme or globalUIComponents. The hook registers the tool while mounted, uses the latest execute closure, and unregisters it on unmount.

import { useWebMcpTool } from "@rspress/plugin-webmcp/runtime";

type Weather = {
  location: string;
  temperatureC: number;
  conditions: string;
};

export function WeatherTool({
  loadWeather,
}: {
  loadWeather(location: string): Promise<Weather>;
}) {
  const { status, error } = useWebMcpTool<{ location: string }, Weather>({
    name: "get_weather",
    description: "Get the current weather for a location.",
    inputSchema: {
      type: "object",
      properties: {
        location: { type: "string", minLength: 1 },
      },
      required: ["location"],
      additionalProperties: false,
    },
    annotations: { readOnlyHint: true },
    execute: ({ location }) => loadWeather(location),
  });

  return <span title={error?.message}>WebMCP: {status}</span>;
}

An agent host discovers and invokes that registered tool through the browser:

const tools = await document.modelContext.getTools();
const weatherTool = tools.find((tool) => tool.name === "get_weather");

if (!weatherTool) {
  throw new Error("get_weather is unavailable");
}

const result = await document.modelContext.executeTool(
  weatherTool,
  JSON.stringify({ location: "London" }),
);

In an AI conversation, the same call looks like this:

User: What's the weather in London?
Agent → get_weather { "location": "London" }
Tool  → { "location": "London", "temperatureC": 18, "conditions": "Cloudy" }
Agent: It's 18°C and cloudy in London.

The browser agent normally performs discovery and invocation; the JavaScript above is the deterministic/manual equivalent for testing an individual tool.

Rspress integration

  • Uses one SSR-safe globalUIComponents runtime entry.
  • Uses native document.modelContext; no production polyfill or MCP-B dependency.
  • Forwards optional built-in exposedTo origins; cross-origin consumers still opt in with getTools({ fromOrigins }) and iframe Permissions Policy.
  • Checks its public producer types against the WebMCP CG's webmcp-types package.
  • Enables SSG-MD when either Markdown-reading tool requires it, while preserving existing llms configuration.
  • Reuses Rspress routing and page data, with a provider registry shared by local search, Algolia, and future search plugins.
  • Keeps site/page metadata, search, and tool state current across locale/version changes and HMR.
  • Enables the plugin on the official Rspress documentation site.

Validation

Coverage includes registration, runtime input validation, schemas, annotations, site discovery, page listing, arbitrary-page retrieval, search, route rejection, navigation, custom tools, cleanup, native result normalization, SSR, production builds, and routed/imported-content HMR behavior.

Final verification passed: core/plugin/fixture and website builds, unit and type tests, 15 Playwright tests, lint, macOS/Windows CI, Cloudflare deployment, and Socket checks.

Non-goals

This PR does not add prompts, resources, remote transports, server bridging, or unfinished declarative-form APIs. Its scope is the current imperative WebMCP tool API.

@SoonIter

Copy link
Copy Markdown
Member

Thanks for putting together this prototype. This is a great feature. I'll review the implementation and build on it with any changes needed to get it ready for merging.

@github-actions

github-actions Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Rsdoctor Bundle Diff Analysis

Found 5 projects in monorepo, 5 projects with changes.

📊 Quick Summary
Project Total Size Gzip Size Change Gzip Change
website_html 14.4 MB 2.1 MB 📈 +191.0 KB (+1.3%) 📈 +29.9 KB (+1.4%)
website_js 17.1 MB 3.0 MB 📈 +232.1 KB (+1.3%) 📈 +54.4 KB (+1.8%)
website_md 1.8 MB 267.6 KB 📈 +31.2 KB (+1.7%) 📈 +5.2 KB (+2.0%)
auto_nav_sidebar_html 447.5 KB 93.4 KB 0 +11.0 B (0.0%)
auto_nav_sidebar_js 543.9 KB 171.3 KB +230.0 B (0.0%) +56.0 B (0.0%)
📋 Detailed Reports (Click to expand)

📁 website_html

Path: website/doc_build/diff-rsdoctor/website_html/rsdoctor-data.json

📌 Baseline Commit: 12945718f7 | PR: #3578

Metric Current Baseline Change
📊 Total Size 14.4 MB 14.2 MB +191.0 KB (+1.3%)
🗜️ Gzip Size 2.1 MB 2.0 MB +29.9 KB (+1.4%)
📄 JavaScript 0 B 0 B 0
🎨 CSS 0 B 0 B 0
🌐 HTML 14.4 MB 14.2 MB +191.0 KB (+1.3%)
📁 Other Assets 0 B 0 B 0

📦 Download Diff Report: website_html Bundle Diff

📁 website_js

Path: website/doc_build/diff-rsdoctor/website_js/rsdoctor-data.json

📌 Baseline Commit: 12945718f7 | PR: #3578

Metric Current Baseline Change
📊 Total Size 17.1 MB 16.9 MB +232.1 KB (+1.3%)
🗜️ Gzip Size 3.0 MB 2.9 MB +54.4 KB (+1.8%)
📄 JavaScript 16.8 MB 16.6 MB +230.7 KB (+1.4%)
🎨 CSS 140.7 KB 140.7 KB 0
🌐 HTML 0 B 0 B 0
📁 Other Assets 174.3 KB 172.9 KB +1.4 KB (0.8%)

📦 Download Diff Report: website_js Bundle Diff

📁 website_md

Path: website/doc_build/diff-rsdoctor/website_md/rsdoctor-data.json

📌 Baseline Commit: 12945718f7 | PR: #3578

Metric Current Baseline Change
📊 Total Size 1.8 MB 1.8 MB +31.2 KB (+1.7%)
🗜️ Gzip Size 267.6 KB 262.4 KB +5.2 KB (+2.0%)
📄 JavaScript 0 B 0 B 0
🎨 CSS 0 B 0 B 0
🌐 HTML 0 B 0 B 0
📁 Other Assets 1.8 MB 1.8 MB +31.2 KB (+1.7%)

📦 Download Diff Report: website_md Bundle Diff

📁 auto_nav_sidebar_html

Path: e2e/fixtures/auto-nav-sidebar/doc_build/diff-rsdoctor/auto_nav_sidebar_html/rsdoctor-data.json

📌 Baseline Commit: 12945718f7 | PR: #3578

Metric Current Baseline Change
📊 Total Size 447.5 KB 447.5 KB 0
🗜️ Gzip Size 93.4 KB 93.4 KB +11.0 B (0.0%)
📄 JavaScript 0 B 0 B 0
🎨 CSS 0 B 0 B 0
🌐 HTML 447.5 KB 447.5 KB 0
📁 Other Assets 0 B 0 B 0

📦 Download Diff Report: auto_nav_sidebar_html Bundle Diff

📁 auto_nav_sidebar_js

Path: e2e/fixtures/auto-nav-sidebar/doc_build/diff-rsdoctor/auto_nav_sidebar_js/rsdoctor-data.json

📌 Baseline Commit: 12945718f7 | PR: #3578

Metric Current Baseline Change
📊 Total Size 543.9 KB 543.7 KB +230.0 B (0.0%)
🗜️ Gzip Size 171.3 KB 171.3 KB +56.0 B (0.0%)
📄 JavaScript 473.3 KB 473.1 KB +230.0 B (0.0%)
🎨 CSS 64.0 KB 64.0 KB 0
🌐 HTML 0 B 0 B 0
📁 Other Assets 6.6 KB 6.6 KB 0

📦 Download Diff Report: auto_nav_sidebar_js Bundle Diff

Generated by Rsdoctor GitHub Action

# Conflicts:
#	packages/plugin-algolia/src/runtime/Search.tsx
#	website/package.json
# Conflicts:
#	packages/plugin-algolia/package.json
#	pnpm-lock.yaml
@ScriptedAlchemy

Copy link
Copy Markdown
Author

@SoonIter Thanks again for taking a look. I’ve updated the branch to current main, resolved the conflicts, and revalidated the WebMCP unit and E2E/HMR coverage. Is there anything else I can do to help support or enhance this before your review?

@SoonIter

SoonIter commented Aug 5, 2026

Copy link
Copy Markdown
Member

Thanks for the update! After another look, the main blocker is the scope of this PR. It currently includes several core fixes and new capabilities alongside the WebMCP plugin, which makes it difficult to review as a single unit.

I suggest splitting out the following prerequisite PRs:

  • page data and HMR lifecycle fixes
  • pluggable search provider and Algolia integration
  • awaited navigation support
  • llms configuration normalization

This PR can then stay focused on the WebMCP plugin, documentation, and integration tests.

The fastest path forward is to land these prerequisite PRs first. Once they are merged, this PR can be rebased and reduced to the plugin-specific changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants