useWebMCP hook. The hook handles registration on mount and cleanup on unmount automatically. By the end, you will have a React component that exposes a tool to AI agents and shows execution state in the UI.
Prerequisites
- Node.js 22.12 or later
- A text editor
- A modern web browser
What we will build
A React app with a single component that:- Initializes the WebMCP polyfill
- Registers a
say_hellotool via theuseWebMCPhook - Shows execution count and results in the page
- Allows you to call the tool from both the UI and the browser console
Scaffold the project
Create a new React project with Vite:Install the WebMCP dependencies:
@mcp-b/webmcp-polyfill provides the navigator.modelContext runtime. usewebmcp provides the React hook for tool registration.Initialize the polyfill
Open Calling
src/main.tsx and add the polyfill initialization before createRoot:src/main.tsx
initializeWebMCPPolyfill() once at the top level makes navigator.modelContext available before any component mounts.Create the tool component
Replace the contents of The
src/App.tsx with:src/App.tsx
useWebMCP hook registers the tool when the component mounts and unregisters it when the component unmounts. The input schema is defined outside the component to prevent unnecessary re-registration on every render.Call the tool from the UI
Click the Run Tool Locally button. Notice the page updates:Click the button a few more times. The execution count increases with each click.
Verify the tool from the console
Open the browser console (F12) and verify the tool is registered:You should see an array containing your The output should be an object containing the tool response:Notice that the execution count in the UI also incremented, because the same underlying
say_hello tool. Now call it through the testing API:execute function ran.The complete files
What you learned
initializeWebMCPPolyfill()should be called once at app startup, before components mountuseWebMCPregisters a tool on mount and unregisters on unmount- Define input schemas outside the component (or memoize them) to avoid re-registration on each render
- The hook returns
state(withexecutionCount,lastResult,error,isExecuting) and anexecutefunction for local invocation - Tools registered via the hook are also callable through
navigator.modelContextTestingin the console
Next steps
- Try the Native Chrome Preview to use the browser’s built-in WebMCP API without a polyfill
- Connect a Desktop Agent to let Claude or Cursor call your tools
- See the
usewebmcpreference for the full hook API, output schemas, and advanced patterns
