feat(root)!: adopt upstream WebMCP core and simplify React hooks - #329
Merged
Merged
Conversation
Use the Community Group's webmcp-types package as the browser contract so the core hook can ship without MCP-B runtime or MCP SDK dependencies. Derive the MCP-B compatibility types from upstream instead of declaring Document.modelContext twice. Keep Standard Schema validation in the shared callback, using the validator supplied by the application. This preserves async validation, defaults, and transforms across local, native, and polyfill calls. Move MCP output schemas and response formatting into the React adapter. Add native and packed React 18/19 checks, preserve the enabled-hook and render-budget work already on main, and document the migration with runnable examples and explicit conversion/validation boundaries. BREAKING CHANGE: usewebmcp returns raw agent results and uses TResult generics. Import useWebMCP from @mcp-b/react-webmcp to retain outputSchema, MCP annotations, and automatic MCP response formatting. Refs: #317
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Exercise circular schema metadata through the public hook to ensure bad descriptors report registration errors and recover after correction. Cover returned Errors and non-Error rejections through both local and browser-triggered execution so failures never count as successful results. These regressions close the core hook's uncovered statement and line paths.
React does not run effects during server rendering, so DOM-presence checks inside the registration effect only add unreachable paths. Keep browser discovery in that effect and retain the isomorphic layout effect for SSR. Exercise browsers without navigator.modelContext by removing the legacy alias during the unsupported-browser test and restoring it afterward. Returning undefined from its getter did not cover an absent property. Packed React 18/19 server-rendering checks still verify imports and renders without DOM globals. Refs: https://react.dev/reference/react/useEffect#caveats
Compare four hooks against the same native WebMCP registry with five trials per StrictMode setting. Record every scenario so the pending-call chart can be checked against registration and completion behavior. Render light and dark figures with the shared design-system D3 components. Keep benchmark dependencies isolated from the published packages.
Keep examples first, then show the measured React commit counts and package boundaries. Link the full scenarios and feature comparison so the figures can be evaluated in context. Use light and dark screenshots with alt text, local paths in the docs, and permanent asset URLs for README rendering on GitHub and npm.
Show all four hooks in one compact bar table. Google's row explains that it tracks registration rather than running calls, so it has no comparable execution-state count. Remove the duplicate table and long captions. Reduce the package diagram to two choices while retaining D3, shared tokens, and both color themes.
Keep the working examples and package choices easy to scan. Link detailed state, schema, and lifecycle behavior to the existing references instead of repeating it throughout the introductions. Point README images at the compact figures, including Google's labeled row.
Surface registration calls and metadata-related React commits alongside execution updates. Google has comparable registration measurements, so excluding them made the previous figure an incomplete comparison. Include metadata registration counts in the generated results table and keep raw samples, metric groups, and shared bar scales explicit.
Replace the execution-only figure and alt text with the shared registration and execution measurements. Readers can compare Google directly without having to find the registration results in a separate methodology page.
Show one metric, component re-renders, for changing a tool and running calls. Sum call starts and completions so readers can compare the whole operation. Keep Google visible and name its missing execution state directly. Replace mixed registration and render columns with two shared-scale bar charts. Keep registration counts and methodology in the benchmark documentation.
Give readers a short comparison of all four hooks after the code example. Keep registration counts in one sentence and compare six concrete features. Remove the extra package diagram and replace adapter overview illustrations with direct links to the performance and feature comparisons.
Reuse the successful registration state so React can bail out when pending and success updates batch together. Previously, a fresh success object caused another consumer commit even though the registration status ended unchanged. Keep pending and error updates observable. Add StrictMode render budgets and deferred registration success, rejection, and recovery regressions. The old allocation fails the new budget with 20 commits; the fix needs only 10.
Rerun all forty comparison samples from the committed optimization. Both hooks now match MCP Cat at 10 commits for 10 metadata edits, while Google remains at 20. Execution and registration counts are unchanged. Regenerate both chart themes and record the updated measurement provenance.
Link both chart themes and benchmark details to the new measured results. Update accessible descriptions to reflect 10 metadata commits for both hooks.
Development test batching can hide registration and execution state commits. Add a native browser production lane for sequential calls, schema size, and tool count, and use it for the README chart. Keep raw timings and lifecycle counts to expose feature tradeoffs. Measure each production ESM hook bundle with React external and built-in dependencies included. Prebundle the remaining React test entries so Vite reloads cannot invalidate the existing render-budget checks.
Use measured production behavior for the README chart and preserve the development fixture. Document registration-status tradeoffs and pin samples to the tested harness source.
Pin the new chart and measurements so npm readers see the same comparison as the docs.
Successful metadata replacement previously rendered for pending and completed registration. Remove isRegistered and keep setup errors observable without those success-path updates. Cache schema conversion and its serialized key together so stable schemas avoid repeat work. Use one completion update for result, errors, and pending execution counts. Core agent failures now reject through the browser contract; the MCP adapter supplies its error response formatter. Keep asynchronous formatting inside the cancellation race and retain each call's committed config. Regression tests cover delayed registration, schema reuse, cancellation during formatting, concurrent completions, native Chrome failures, and packed React 18/19 client boundaries. The production harness now requires one parent commit and registration per changed tool. Validated the workspace build, typecheck, lint, unit suites, hook coverage, and native hook tests.
… package The shared form suite exercised the standalone installer through global's build, so the polyfill coverage report missed the moved implementation. Run that harness in the polyfill package and import its source entry directly. Derive the shared suite's browser types from the polyfill contract to avoid a reverse dependency on the MCP adapter. Keep the global harness for bridge coverage and update the documented conformance commands. Verified build, typecheck, lint, and unit tests. All 20 standalone tests pass; the retained declarative implementation has 88.75% line coverage.
…the declarative layer
… hooks with a real client
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Move the WebMCP core to the Community Group's upstream implementation and types, then build MCP-B extensions and React hooks on that contract. This removes duplicated browser behavior and gives the major release concrete migration instructions.
This is the improvements and cleanup PR. Plugin and guarded-consent features are tracked separately in #332, which builds on this branch and will need to incorporate the final core migration.
Package ownership
webmcp-types@mcp-b/webmcp-typesWebMCP; old top-level MCP-B exports move to the SDK.@mcp-b/webmcp-polyfill439c6c3until its official distribution is available; retains declarative forms until upstream has parity.@mcp-b/webmcp-ts-sdkBrowserMcpServeradapter.@mcp-b/globalusewebmcp@mcp-b/react-webmcpBoth legacy core package READMEs explain their eventual removal and recommend the upstream packages. No removal date is set. Standalone declarative-form users should keep
@mcp-b/webmcp-polyfilluntil upstream supports forms. Follow the official polyfill installation instructions for its distribution.Compatibility and intentional breaking changes
new BrowserMcpServer(info, options?)remains supported. It uses the page context and installs the polyfill when needed;{ native }remains optional. SDK, global, and transport packages remain separate.document.modelContext, a discovered tool descriptor, and object input. Imperative results are JSON strings; native declarative forms may return plain text. The MCP adapter and relay normalize both formats, while direct browser calls preserve the underlying result. Navigator aliases, the testing shim, legacy Chrome serialization paths, andinitializeWebMCPPolyfill()are removed. UseinstallWebMCP().McpServerdirectly.The target follows the WebMCP Community Group draft, with the vendored revision and upstream types defining the shipped implementation.
Migration notes
Nine changesets schedule the coordinated 6.0.0 release. They include before/after imports and calls, explicit generic mappings, validation changes, test-double updates, and frame/relay setup:
Cleanup and review scope
Standalone declarative forms
Keep the existing declarative implementation in
@mcp-b/webmcp-polyfillas a temporary layer around the unchanged upstream core. Both ESM installation and the standalone script bundle support annotated forms andSubmitEvent.agentInvoked/respondWith().@mcp-b/globalreuses this layer; cleanup preserves it. Existing native form hooks take precedence. No MCP SDK dependency is introduced into the polyfill.The shared form suite now runs against both the standalone polyfill and global bridge. The standalone harness runs inside the polyfill package so its source coverage is included in CI. A lifecycle regression covers repeated installation and form execution after bridge cleanup; a built-bundle check also verified duplicate IIFE loads and subsequent global cleanup.
Native form compatibility fix
The native extension CI lane caught an overly strict result decoder introduced during cleanup: native
respondWith()string responses are plain text, while imperative tool results are JSON-serialized. Chromium's form response handler explicitly supports both shapes. The SDK and relay now normalize plain text into MCP content without changing direct browser execution or suppressing execution failures. Regression coverage includes empty text, JSON strings, MCP envelopes, and both response formats through the relay.Validation
Commands run locally:
pnpm test:unitincludes isolated packed-package declarations and React 18/19 SSR checks. All 12 release-note code examples and the core/extension generic migration also passed strict TypeScript compilation. The Changesets plan confirms all 12 published packages advance from 5.1.0 to 6.0.0 without duplicate package summaries.The informational
pnpm audit:ci:highreport still lists four high-severity advisories in landing-page transitive dependencies (browserslist,sharp, andsmol-toml). The required critical audit reports zero critical advisories.Checklist