Full Example
Production-ready React example with useWebMCP() hooks
@mcp-b/react-webmcp instead of @mcp-b/global directly—it handles lifecycle automatically and provides Zod validation. This guide covers SSR-specific challenges when using WebMCP with Next.js App Router.
The fundamental challenge
WebMCP relies on browser APIs (navigator.modelContext, postMessage, DOM access) that do not exist on the server. Next.js App Router defaults to Server Components, which means:
- Tools cannot be registered in Server Components
- The
@mcp-b/globalpolyfill must run on the client - Any component using
useWebMCPoruseWebMCPPromptmust be a Client Component
Polyfill placement
The@mcp-b/global polyfill must be imported in a Client Component before any tools are registered. Import it at the highest layout that contains your tools—but not necessarily at the root.
If the polyfill isn’t working, you’ll see:
navigator.modelContext is undefined- Tools don’t appear in the MCP inspector
- No errors, but tools simply don’t register
Client components are required
Every WebMCP hook needs'use client':
useWebMCP()- tool registrationuseWebMCPPrompt()- prompt registrationuseWebMCPResource()- resource registrationuseWebMCPContext()- context registrationuseMcpClient()- MCP client access
Embedded agent setup
The embedded agent uses browser APIs and must be loaded client-side only using dynamic import:ssr: false is required because the embedded agent accesses window, document, and other browser APIs. Server-side rendering will crash with “window is not defined”.Avoiding duplicate components
Next.js App Router supports nested layouts. If you add the embedded agent to multiple layouts, it will render multiple times:Tool registration with context
WebMCP tools frequently need access to application state. This creates a dependency chain:Navigation tools
Tools can navigate using Next.js router:In Next.js App Router, the root layout persists across navigations. Tools registered in root layout stay registered, while tools in page components unmount/remount on navigation.
Common errors
'navigator.modelContext is undefined'
'navigator.modelContext is undefined'
'window is not defined'
'window is not defined'
Cause: Browser-only code running during SSRSolution:
'Cannot read properties of undefined (reading registerTool)'
'Cannot read properties of undefined (reading registerTool)'
Cause: Polyfill hasn’t initialized yetSolution:
Tools not appearing
Tools not appearing
Possible Causes:
- Component using
useWebMCPisn’t mounted - Component is a Server Component (missing
'use client') - Tool registration is conditional and condition is false
- Polyfill loaded after tools tried to register
Duplicate tools or agents
Duplicate tools or agents
Cause: Component mounted multiple times (e.g., in nested layouts)Solution: Only render WebMCP components in ONE layout. Use React DevTools to check component tree for duplicates.
Deployment checklist
Before deploying your WebMCP + Next.js app:- Root layout is a Server Component (no
'use client') to preserve SSR - Feature layout(s) have
'use client'and import@mcp-b/global - All components using WebMCP hooks have
'use client' - Embedded agent uses
dynamic()with{ ssr: false } - Embedded agent is rendered in only ONE layout
- Tools that need context are inside their Provider
- Environment variables use
NEXT_PUBLIC_prefix for client access
Recommended architecture
- Root layout stays a Server Component (SSR preserved)
- Polyfill loads in feature layouts where tools are used
- Tools have access to context (feature layout)
- Agent renders once (feature layout only)
- Pages can still use Server Components for data fetching
