@mcp-b/react-webmcp 0.0.0-beta-20260109203913
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +670 -0
- package/dist/index.d.ts +1113 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/package.json +92 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 mcp-b contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,670 @@
|
|
|
1
|
+
# @mcp-b/react-webmcp
|
|
2
|
+
|
|
3
|
+
> React hooks for Model Context Protocol (MCP) - Let AI agents like Claude, ChatGPT, Cursor, and Copilot control your React components
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@mcp-b/react-webmcp)
|
|
6
|
+
[](https://www.npmjs.com/package/@mcp-b/react-webmcp)
|
|
7
|
+
[](https://opensource.org/licenses/MIT)
|
|
8
|
+
[](https://www.typescriptlang.org/)
|
|
9
|
+
[](https://reactjs.org/)
|
|
10
|
+
|
|
11
|
+
📖 **[Full Documentation](https://docs.mcp-b.ai/packages/react-webmcp)** | 🚀 **[Quick Start](https://docs.mcp-b.ai/quickstart)** | ⚛️ **[AI Framework Integration](https://docs.mcp-b.ai/ai-frameworks)**
|
|
12
|
+
|
|
13
|
+
**@mcp-b/react-webmcp** provides React hooks that expose your components as AI-callable tools via the Model Context Protocol. Build AI-powered React applications where Claude, ChatGPT, Gemini, Cursor, and Copilot can interact with your app's functionality.
|
|
14
|
+
|
|
15
|
+
## Why Use @mcp-b/react-webmcp?
|
|
16
|
+
|
|
17
|
+
| Feature | Benefit |
|
|
18
|
+
|---------|---------|
|
|
19
|
+
| **React-First Design** | Hooks follow React patterns with automatic cleanup and StrictMode support |
|
|
20
|
+
| **Type-Safe with Zod** | Full TypeScript support with Zod schema validation for inputs/outputs |
|
|
21
|
+
| **Two-Way Integration** | Both expose tools TO AI agents AND consume tools FROM MCP servers |
|
|
22
|
+
| **Execution State Tracking** | Built-in loading, success, and error states for UI feedback |
|
|
23
|
+
| **Works with Any AI** | Compatible with Claude, ChatGPT, Gemini, Cursor, Copilot, and any MCP client |
|
|
24
|
+
|
|
25
|
+
## Use Cases
|
|
26
|
+
|
|
27
|
+
- **AI-Controllable Dashboards**: Let AI agents filter data, generate reports, and navigate views
|
|
28
|
+
- **Form Automation**: Expose form submission as tools for AI-powered data entry
|
|
29
|
+
- **E-commerce Integration**: AI agents can search products, add to cart, and checkout
|
|
30
|
+
- **Content Management**: Let AI edit, publish, and organize content in your CMS
|
|
31
|
+
- **Data Visualization**: AI can adjust chart parameters, zoom, and export visualizations
|
|
32
|
+
|
|
33
|
+
## Features
|
|
34
|
+
|
|
35
|
+
### Provider Hooks (Registering Tools)
|
|
36
|
+
- **Type-Safe**: Full TypeScript support with Zod schema validation
|
|
37
|
+
- **State-Aware**: Track execution state (loading, success, error) for UI feedback
|
|
38
|
+
- **React-Native**: Designed for React's lifecycle, including StrictMode compatibility
|
|
39
|
+
- **Developer-Friendly**: Intuitive API with comprehensive examples
|
|
40
|
+
|
|
41
|
+
### Client Hooks (Consuming Tools)
|
|
42
|
+
- **MCP Client Provider**: Connect to MCP servers and consume their tools
|
|
43
|
+
- **Real-time Updates**: Listen for tool list changes via MCP notifications
|
|
44
|
+
- **Connection Management**: Automatic connection handling with reconnect support
|
|
45
|
+
- **Type-Safe Tool Calls**: Full TypeScript support for client operations
|
|
46
|
+
|
|
47
|
+
## Installation
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
pnpm add @mcp-b/react-webmcp zod
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
For client functionality, you'll also need:
|
|
54
|
+
```bash
|
|
55
|
+
pnpm add @mcp-b/transports @modelcontextprotocol/sdk
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Prerequisites
|
|
59
|
+
|
|
60
|
+
**For Provider Hooks:** Requires the global `navigator.modelContext` API. Install `@mcp-b/global` or use a browser that implements the Web Model Context API.
|
|
61
|
+
|
|
62
|
+
**For Client Hooks:** Requires an MCP server to connect to (e.g., one created with `@mcp-b/global` or the Model Context Protocol SDK).
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
# Part 1: Provider API (Registering Tools)
|
|
67
|
+
|
|
68
|
+
Use these hooks to expose tools from your React app that AI agents can discover and call.
|
|
69
|
+
|
|
70
|
+
## Quick Start - Provider
|
|
71
|
+
|
|
72
|
+
### Basic Tool Registration
|
|
73
|
+
|
|
74
|
+
```tsx
|
|
75
|
+
import { useWebMCP } from '@mcp-b/react-webmcp';
|
|
76
|
+
import { z } from 'zod';
|
|
77
|
+
|
|
78
|
+
function PostsPage() {
|
|
79
|
+
const likeTool = useWebMCP({
|
|
80
|
+
name: 'posts_like',
|
|
81
|
+
description: 'Like a post by ID. Increments the like count.',
|
|
82
|
+
inputSchema: {
|
|
83
|
+
postId: z.string().uuid().describe('The post ID to like'),
|
|
84
|
+
},
|
|
85
|
+
annotations: {
|
|
86
|
+
title: 'Like Post',
|
|
87
|
+
readOnlyHint: false,
|
|
88
|
+
idempotentHint: true,
|
|
89
|
+
},
|
|
90
|
+
handler: async (input) => {
|
|
91
|
+
await api.posts.like(input.postId);
|
|
92
|
+
return { success: true, postId: input.postId };
|
|
93
|
+
},
|
|
94
|
+
formatOutput: (result) => `Post ${result.postId} liked successfully!`,
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
return (
|
|
98
|
+
<div>
|
|
99
|
+
{likeTool.state.isExecuting && <Spinner />}
|
|
100
|
+
{likeTool.state.error && <ErrorAlert error={likeTool.state.error} />}
|
|
101
|
+
{/* Your UI */}
|
|
102
|
+
</div>
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Tool with Output Schema (Recommended)
|
|
108
|
+
|
|
109
|
+
**Output schemas are essential for modern AI integrations** - they enable AI agents to return structured, type-safe responses:
|
|
110
|
+
|
|
111
|
+
```tsx
|
|
112
|
+
import { useWebMCP } from '@mcp-b/react-webmcp';
|
|
113
|
+
import { z } from 'zod';
|
|
114
|
+
|
|
115
|
+
function ProductSearch() {
|
|
116
|
+
const searchTool = useWebMCP({
|
|
117
|
+
name: 'products_search',
|
|
118
|
+
description: 'Search for products in the catalog',
|
|
119
|
+
inputSchema: {
|
|
120
|
+
query: z.string().describe('Search query'),
|
|
121
|
+
maxResults: z.number().min(1).max(50).default(10),
|
|
122
|
+
category: z.enum(['electronics', 'clothing', 'books']).optional(),
|
|
123
|
+
},
|
|
124
|
+
// Output schema enables structured responses
|
|
125
|
+
outputSchema: {
|
|
126
|
+
products: z.array(z.object({
|
|
127
|
+
id: z.string(),
|
|
128
|
+
name: z.string(),
|
|
129
|
+
price: z.number(),
|
|
130
|
+
inStock: z.boolean(),
|
|
131
|
+
})),
|
|
132
|
+
total: z.number().describe('Total matching products'),
|
|
133
|
+
hasMore: z.boolean(),
|
|
134
|
+
},
|
|
135
|
+
handler: async ({ query, maxResults, category }) => {
|
|
136
|
+
const results = await api.products.search({ query, maxResults, category });
|
|
137
|
+
return {
|
|
138
|
+
products: results.items,
|
|
139
|
+
total: results.totalCount,
|
|
140
|
+
hasMore: results.totalCount > maxResults,
|
|
141
|
+
};
|
|
142
|
+
},
|
|
143
|
+
// Format for text display (structuredContent is auto-generated from return value)
|
|
144
|
+
formatOutput: (result) => `Found ${result.total} products`,
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
return (
|
|
148
|
+
<div>
|
|
149
|
+
{searchTool.state.isExecuting && <Spinner />}
|
|
150
|
+
{searchTool.state.lastResult && (
|
|
151
|
+
<p>Found {searchTool.state.lastResult.total} products</p>
|
|
152
|
+
)}
|
|
153
|
+
</div>
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
**Why use output schemas?**
|
|
159
|
+
- AI providers compile schemas to TypeScript, enabling type-safe code generation
|
|
160
|
+
- Responses are validated against the schema
|
|
161
|
+
- Better AI reasoning about expected output format
|
|
162
|
+
|
|
163
|
+
### Context Tool
|
|
164
|
+
|
|
165
|
+
Expose read-only context to AI:
|
|
166
|
+
|
|
167
|
+
```tsx
|
|
168
|
+
import { useWebMCPContext } from '@mcp-b/react-webmcp';
|
|
169
|
+
|
|
170
|
+
function PostDetailPage() {
|
|
171
|
+
const { postId } = useParams();
|
|
172
|
+
const { data: post } = useQuery(['post', postId], () => fetchPost(postId));
|
|
173
|
+
|
|
174
|
+
useWebMCPContext(
|
|
175
|
+
'context_current_post',
|
|
176
|
+
'Get the currently viewed post ID and metadata',
|
|
177
|
+
() => ({
|
|
178
|
+
postId,
|
|
179
|
+
title: post?.title,
|
|
180
|
+
author: post?.author,
|
|
181
|
+
tags: post?.tags,
|
|
182
|
+
})
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
return <div>{/* Post UI */}</div>;
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## Provider API Reference
|
|
190
|
+
|
|
191
|
+
### `useWebMCP`
|
|
192
|
+
|
|
193
|
+
Main hook for registering MCP tools with full control over behavior and state.
|
|
194
|
+
|
|
195
|
+
```tsx
|
|
196
|
+
function useWebMCP<
|
|
197
|
+
TInputSchema extends Record<string, z.ZodTypeAny> = Record<string, never>,
|
|
198
|
+
TOutputSchema extends Record<string, z.ZodTypeAny> = Record<string, never>
|
|
199
|
+
>(
|
|
200
|
+
config: WebMCPConfig<TInputSchema, TOutputSchema>,
|
|
201
|
+
deps?: DependencyList
|
|
202
|
+
): WebMCPReturn<TOutputSchema>
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
`InferOutput<TOutputSchema>` is the output type inferred from `outputSchema`.
|
|
206
|
+
|
|
207
|
+
#### Configuration Options
|
|
208
|
+
|
|
209
|
+
| Option | Type | Required | Description |
|
|
210
|
+
|--------|------|----------|-------------|
|
|
211
|
+
| `name` | `string` | ✓ | Unique tool identifier (e.g., 'posts_like') |
|
|
212
|
+
| `description` | `string` | ✓ | Human-readable description for AI |
|
|
213
|
+
| `inputSchema` | `Record<string, ZodType>` | - | Input validation using Zod schemas |
|
|
214
|
+
| `outputSchema` | `Record<string, ZodType>` | - | Output schema for structured responses (recommended) |
|
|
215
|
+
| `annotations` | `ToolAnnotations` | - | Metadata hints for the AI |
|
|
216
|
+
| `handler` | `(input) => Promise<TOutput>` | ✓ | Function that executes the tool |
|
|
217
|
+
| `formatOutput` | `(output) => string` | - | Custom output formatter |
|
|
218
|
+
| `onSuccess` | `(result, input) => void` | - | Success callback |
|
|
219
|
+
| `onError` | `(error, input) => void` | - | Error handler callback |
|
|
220
|
+
|
|
221
|
+
#### Memoization and `deps` (important)
|
|
222
|
+
|
|
223
|
+
`useWebMCP` uses reference equality to decide when to re-register a tool. Inline
|
|
224
|
+
objects/arrays/functions can cause constant re-registration.
|
|
225
|
+
|
|
226
|
+
Bad:
|
|
227
|
+
```tsx
|
|
228
|
+
useWebMCP({
|
|
229
|
+
name: 'counter',
|
|
230
|
+
description: `Count: ${count}`,
|
|
231
|
+
outputSchema: { count: z.number() },
|
|
232
|
+
handler: async () => ({ count }),
|
|
233
|
+
});
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
Good:
|
|
237
|
+
```tsx
|
|
238
|
+
const OUTPUT_SCHEMA = { count: z.number() };
|
|
239
|
+
const description = useMemo(() => `Count: ${count}`, [count]);
|
|
240
|
+
|
|
241
|
+
useWebMCP(
|
|
242
|
+
{
|
|
243
|
+
name: 'counter',
|
|
244
|
+
description,
|
|
245
|
+
outputSchema: OUTPUT_SCHEMA,
|
|
246
|
+
handler: async () => ({ count }),
|
|
247
|
+
},
|
|
248
|
+
[count]
|
|
249
|
+
);
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
`deps` behaves like `useEffect` dependencies (reference comparison). Prefer
|
|
253
|
+
primitive values or memoized objects to avoid unnecessary re-registrations.
|
|
254
|
+
|
|
255
|
+
`handler` is stored in a ref to avoid re-registration when it changes. If you
|
|
256
|
+
memoize `handler` with stale dependencies, you'll still capture stale values.
|
|
257
|
+
|
|
258
|
+
#### Return Value
|
|
259
|
+
|
|
260
|
+
```tsx
|
|
261
|
+
interface WebMCPReturn<TOutputSchema> {
|
|
262
|
+
state: {
|
|
263
|
+
isExecuting: boolean; // Currently running
|
|
264
|
+
lastResult: InferOutput<TOutputSchema> | null; // Last successful result
|
|
265
|
+
error: Error | null; // Last error
|
|
266
|
+
executionCount: number; // Total executions
|
|
267
|
+
};
|
|
268
|
+
execute: (input: unknown) => Promise<InferOutput<TOutputSchema>>; // Manual execution
|
|
269
|
+
reset: () => void; // Reset state
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### `useWebMCPContext`
|
|
274
|
+
|
|
275
|
+
Simplified hook for read-only context exposure:
|
|
276
|
+
|
|
277
|
+
```tsx
|
|
278
|
+
function useWebMCPContext<T>(
|
|
279
|
+
name: string,
|
|
280
|
+
description: string,
|
|
281
|
+
getValue: () => T
|
|
282
|
+
): WebMCPReturn
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
# Part 2: Client API (Consuming Tools)
|
|
288
|
+
|
|
289
|
+
Use these hooks to connect to MCP servers and call their tools from your React app.
|
|
290
|
+
|
|
291
|
+
## Quick Start - Client
|
|
292
|
+
|
|
293
|
+
### Connecting to an MCP Server
|
|
294
|
+
|
|
295
|
+
```tsx
|
|
296
|
+
import { McpClientProvider, useMcpClient } from '@mcp-b/react-webmcp';
|
|
297
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
298
|
+
import { TabClientTransport } from '@mcp-b/transports';
|
|
299
|
+
|
|
300
|
+
// Create client and transport
|
|
301
|
+
const client = new Client({ name: 'MyApp', version: '1.0.0' });
|
|
302
|
+
const transport = new TabClientTransport('mcp', { clientInstanceId: 'my-app' });
|
|
303
|
+
|
|
304
|
+
function App() {
|
|
305
|
+
return (
|
|
306
|
+
<McpClientProvider client={client} transport={transport}>
|
|
307
|
+
<ToolConsumer />
|
|
308
|
+
</McpClientProvider>
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
function ToolConsumer() {
|
|
313
|
+
const { client, tools, isConnected, capabilities } = useMcpClient();
|
|
314
|
+
|
|
315
|
+
const handleCallTool = async () => {
|
|
316
|
+
const result = await client.callTool({
|
|
317
|
+
name: 'posts_like',
|
|
318
|
+
arguments: { postId: '123' }
|
|
319
|
+
});
|
|
320
|
+
console.log('Result:', result.content[0].text);
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
return (
|
|
324
|
+
<div>
|
|
325
|
+
<p>Connected: {isConnected ? 'Yes' : 'No'}</p>
|
|
326
|
+
<p>Available Tools: {tools.length}</p>
|
|
327
|
+
<ul>
|
|
328
|
+
{tools.map(tool => (
|
|
329
|
+
<li key={tool.name}>{tool.name} - {tool.description}</li>
|
|
330
|
+
))}
|
|
331
|
+
</ul>
|
|
332
|
+
<button onClick={handleCallTool} disabled={!isConnected}>
|
|
333
|
+
Call Tool
|
|
334
|
+
</button>
|
|
335
|
+
</div>
|
|
336
|
+
);
|
|
337
|
+
}
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
### Listening for Tool List Changes
|
|
341
|
+
|
|
342
|
+
```tsx
|
|
343
|
+
function ToolList() {
|
|
344
|
+
const { tools, isConnected, capabilities } = useMcpClient();
|
|
345
|
+
|
|
346
|
+
// Tools automatically update when server sends notifications
|
|
347
|
+
// if capabilities.tools.listChanged is true
|
|
348
|
+
|
|
349
|
+
return (
|
|
350
|
+
<div>
|
|
351
|
+
<h3>Tools ({tools.length})</h3>
|
|
352
|
+
{capabilities?.tools?.listChanged && (
|
|
353
|
+
<p>✓ Server supports real-time tool updates</p>
|
|
354
|
+
)}
|
|
355
|
+
{tools.map(tool => (
|
|
356
|
+
<div key={tool.name}>
|
|
357
|
+
<h4>{tool.name}</h4>
|
|
358
|
+
<p>{tool.description}</p>
|
|
359
|
+
</div>
|
|
360
|
+
))}
|
|
361
|
+
</div>
|
|
362
|
+
);
|
|
363
|
+
}
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
## Client API Reference
|
|
367
|
+
|
|
368
|
+
### `McpClientProvider`
|
|
369
|
+
|
|
370
|
+
Provider component that manages an MCP client connection.
|
|
371
|
+
|
|
372
|
+
```tsx
|
|
373
|
+
interface McpClientProviderProps {
|
|
374
|
+
children: ReactNode;
|
|
375
|
+
client: Client; // MCP client instance
|
|
376
|
+
transport: Transport; // Transport for connection
|
|
377
|
+
opts?: RequestOptions; // Optional connection options
|
|
378
|
+
}
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
#### Example Transports
|
|
382
|
+
|
|
383
|
+
```tsx
|
|
384
|
+
// Connect to same-page MCP server (via @mcp-b/global)
|
|
385
|
+
import { TabClientTransport } from '@mcp-b/transports';
|
|
386
|
+
const transport = new TabClientTransport('mcp', { clientInstanceId: 'my-app' });
|
|
387
|
+
|
|
388
|
+
// Connect to Chrome extension MCP server
|
|
389
|
+
import { ExtensionClientTransport } from '@mcp-b/transports';
|
|
390
|
+
const transport = new ExtensionClientTransport({ portName: 'mcp' });
|
|
391
|
+
|
|
392
|
+
// In-memory connection (for testing)
|
|
393
|
+
import { InMemoryTransport } from '@modelcontextprotocol/sdk/inMemory.js';
|
|
394
|
+
const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
### `useMcpClient`
|
|
398
|
+
|
|
399
|
+
Hook to access the MCP client context. Must be used within `McpClientProvider`.
|
|
400
|
+
|
|
401
|
+
```tsx
|
|
402
|
+
interface McpClientContextValue {
|
|
403
|
+
client: Client; // MCP client instance
|
|
404
|
+
tools: Tool[]; // Available tools from server
|
|
405
|
+
resources: Resource[]; // Available resources
|
|
406
|
+
isConnected: boolean; // Connection status
|
|
407
|
+
isLoading: boolean; // Currently connecting
|
|
408
|
+
error: Error | null; // Connection error
|
|
409
|
+
capabilities: ServerCapabilities | null; // Server capabilities
|
|
410
|
+
reconnect: () => Promise<void>; // Manual reconnection
|
|
411
|
+
}
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
#### Calling Tools
|
|
415
|
+
|
|
416
|
+
```tsx
|
|
417
|
+
function MyComponent() {
|
|
418
|
+
const { client, isConnected } = useMcpClient();
|
|
419
|
+
|
|
420
|
+
const callTool = async () => {
|
|
421
|
+
if (!isConnected) return;
|
|
422
|
+
|
|
423
|
+
try {
|
|
424
|
+
const result = await client.callTool({
|
|
425
|
+
name: 'my_tool',
|
|
426
|
+
arguments: { foo: 'bar' }
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
// Extract text from result
|
|
430
|
+
const text = result.content
|
|
431
|
+
.filter(c => c.type === 'text')
|
|
432
|
+
.map(c => c.text)
|
|
433
|
+
.join('\n');
|
|
434
|
+
|
|
435
|
+
console.log(text);
|
|
436
|
+
} catch (error) {
|
|
437
|
+
console.error('Tool call failed:', error);
|
|
438
|
+
}
|
|
439
|
+
};
|
|
440
|
+
|
|
441
|
+
return <button onClick={callTool}>Call Tool</button>;
|
|
442
|
+
}
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
---
|
|
446
|
+
|
|
447
|
+
# Complete Example: Both Provider and Client
|
|
448
|
+
|
|
449
|
+
This example shows a React app that both exposes tools AND consumes tools from an MCP server.
|
|
450
|
+
|
|
451
|
+
```tsx
|
|
452
|
+
import '@mcp-b/global'; // Provides navigator.modelContext
|
|
453
|
+
import { McpClientProvider, useWebMCP, useMcpClient } from '@mcp-b/react-webmcp';
|
|
454
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
455
|
+
import { TabClientTransport } from '@mcp-b/transports';
|
|
456
|
+
import { z } from 'zod';
|
|
457
|
+
|
|
458
|
+
// Create client to consume tools
|
|
459
|
+
const client = new Client({ name: 'MyApp', version: '1.0.0' });
|
|
460
|
+
const transport = new TabClientTransport('mcp', { clientInstanceId: 'my-app' });
|
|
461
|
+
|
|
462
|
+
function App() {
|
|
463
|
+
return (
|
|
464
|
+
<McpClientProvider client={client} transport={transport}>
|
|
465
|
+
<ToolProvider />
|
|
466
|
+
<ToolConsumer />
|
|
467
|
+
</McpClientProvider>
|
|
468
|
+
);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// Component that REGISTERS tools
|
|
472
|
+
function ToolProvider() {
|
|
473
|
+
const [count, setCount] = useState(0);
|
|
474
|
+
|
|
475
|
+
// Expose a tool that increments the counter
|
|
476
|
+
useWebMCP({
|
|
477
|
+
name: 'increment_counter',
|
|
478
|
+
description: 'Increment the counter',
|
|
479
|
+
inputSchema: {
|
|
480
|
+
amount: z.number().default(1)
|
|
481
|
+
},
|
|
482
|
+
handler: async ({ amount }) => {
|
|
483
|
+
setCount(prev => prev + amount);
|
|
484
|
+
return { newValue: count + amount };
|
|
485
|
+
}
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
return <div>Counter: {count}</div>;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// Component that CONSUMES tools
|
|
492
|
+
function ToolConsumer() {
|
|
493
|
+
const { client, tools, isConnected } = useMcpClient();
|
|
494
|
+
const [result, setResult] = useState('');
|
|
495
|
+
|
|
496
|
+
const callIncrementTool = async () => {
|
|
497
|
+
const res = await client.callTool({
|
|
498
|
+
name: 'increment_counter',
|
|
499
|
+
arguments: { amount: 5 }
|
|
500
|
+
});
|
|
501
|
+
setResult(res.content[0].text);
|
|
502
|
+
};
|
|
503
|
+
|
|
504
|
+
return (
|
|
505
|
+
<div>
|
|
506
|
+
<p>Available Tools: {tools.map(t => t.name).join(', ')}</p>
|
|
507
|
+
<button onClick={callIncrementTool} disabled={!isConnected}>
|
|
508
|
+
Call increment_counter Tool
|
|
509
|
+
</button>
|
|
510
|
+
{result && <p>Result: {result}</p>}
|
|
511
|
+
</div>
|
|
512
|
+
);
|
|
513
|
+
}
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
---
|
|
517
|
+
|
|
518
|
+
# Migration from @mcp-b/mcp-react-hooks
|
|
519
|
+
|
|
520
|
+
If you're migrating from the deprecated `@mcp-b/mcp-react-hooks` package:
|
|
521
|
+
|
|
522
|
+
## What Changed
|
|
523
|
+
|
|
524
|
+
- **Server providers removed**: `McpServerProvider` and `McpMemoryProvider` are gone
|
|
525
|
+
- **Everything in one package**: Both client and provider hooks are now in `@mcp-b/react-webmcp`
|
|
526
|
+
- **Tool registration**: Use `useWebMCP` instead of server providers
|
|
527
|
+
- **Client unchanged**: `McpClientProvider` and `useMcpClient` work the same way
|
|
528
|
+
|
|
529
|
+
## Migration Guide
|
|
530
|
+
|
|
531
|
+
### Before (mcp-react-hooks)
|
|
532
|
+
|
|
533
|
+
```tsx
|
|
534
|
+
import { McpClientProvider, useMcpClient } from '@mcp-b/mcp-react-hooks';
|
|
535
|
+
import { McpServerProvider, useMcpServer } from '@mcp-b/mcp-react-hooks';
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
### After (react-webmcp)
|
|
539
|
+
|
|
540
|
+
```tsx
|
|
541
|
+
// Client hooks - same API
|
|
542
|
+
import { McpClientProvider, useMcpClient } from '@mcp-b/react-webmcp';
|
|
543
|
+
|
|
544
|
+
// For registering tools, use useWebMCP instead of server providers
|
|
545
|
+
import { useWebMCP } from '@mcp-b/react-webmcp';
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
### Converting Server to Provider
|
|
549
|
+
|
|
550
|
+
**Before:**
|
|
551
|
+
```tsx
|
|
552
|
+
function MyApp() {
|
|
553
|
+
const { registerTool } = useMcpServer();
|
|
554
|
+
|
|
555
|
+
useEffect(() => {
|
|
556
|
+
const tool = registerTool('my_tool', { description: '...' }, handler);
|
|
557
|
+
return () => tool.remove();
|
|
558
|
+
}, []);
|
|
559
|
+
}
|
|
560
|
+
```
|
|
561
|
+
|
|
562
|
+
**After:**
|
|
563
|
+
```tsx
|
|
564
|
+
function MyApp() {
|
|
565
|
+
useWebMCP({
|
|
566
|
+
name: 'my_tool',
|
|
567
|
+
description: '...',
|
|
568
|
+
handler: handler
|
|
569
|
+
});
|
|
570
|
+
// Auto-registers and cleans up on unmount
|
|
571
|
+
}
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
---
|
|
575
|
+
|
|
576
|
+
# Best Practices
|
|
577
|
+
|
|
578
|
+
### Tool Naming
|
|
579
|
+
- Use verb-noun format: `posts_like`, `graph_navigate`, `table_filter`
|
|
580
|
+
- Prefix with domain: `posts_`, `comments_`, `graph_`
|
|
581
|
+
- Be specific and descriptive
|
|
582
|
+
|
|
583
|
+
### Annotations
|
|
584
|
+
- Always set `readOnlyHint` (true for queries, false for mutations)
|
|
585
|
+
- Set `idempotentHint` (true if repeated calls are safe)
|
|
586
|
+
- Set `destructiveHint` for delete/permanent operations
|
|
587
|
+
|
|
588
|
+
### Error Handling
|
|
589
|
+
- Throw descriptive errors from tool handlers
|
|
590
|
+
- Use `onError` callback for side effects (logging, toasts)
|
|
591
|
+
- Handle connection errors in client components
|
|
592
|
+
|
|
593
|
+
### Performance
|
|
594
|
+
- Tools automatically prevent duplicate registration in React StrictMode
|
|
595
|
+
- Use `useWebMCPContext` for lightweight read-only data exposure
|
|
596
|
+
- Client automatically manages reconnection and tool list updates
|
|
597
|
+
|
|
598
|
+
## Frequently Asked Questions
|
|
599
|
+
|
|
600
|
+
### What AI agents can use my React tools?
|
|
601
|
+
|
|
602
|
+
Any MCP-compatible client can discover and call your tools, including:
|
|
603
|
+
- **Claude Desktop** and Claude.ai
|
|
604
|
+
- **ChatGPT** (via plugins/GPTs)
|
|
605
|
+
- **Cursor** IDE
|
|
606
|
+
- **VS Code Copilot**
|
|
607
|
+
- **Gemini** applications
|
|
608
|
+
- **Windsurf**, **Cline**, and other MCP clients
|
|
609
|
+
|
|
610
|
+
### How do AI agents connect to my React app?
|
|
611
|
+
|
|
612
|
+
AI agents connect via browser extensions or the `@mcp-b/chrome-devtools-mcp` server, which bridges desktop AI clients to browser-based MCP tools.
|
|
613
|
+
|
|
614
|
+
### Is this production-ready?
|
|
615
|
+
|
|
616
|
+
Yes! The hooks handle React StrictMode, automatic cleanup, and proper lifecycle management. Tools are automatically unregistered when components unmount.
|
|
617
|
+
|
|
618
|
+
### Can I use this with Next.js / Remix / Gatsby?
|
|
619
|
+
|
|
620
|
+
Yes! These hooks work with any React framework. Just ensure `@mcp-b/global` is loaded on the client side.
|
|
621
|
+
|
|
622
|
+
### How do I validate tool inputs?
|
|
623
|
+
|
|
624
|
+
Use Zod schemas in `inputSchema`. Invalid inputs are automatically rejected with descriptive error messages.
|
|
625
|
+
|
|
626
|
+
```tsx
|
|
627
|
+
inputSchema: {
|
|
628
|
+
email: z.string().email().describe('User email address'),
|
|
629
|
+
age: z.number().min(0).max(120).describe('User age')
|
|
630
|
+
}
|
|
631
|
+
```
|
|
632
|
+
|
|
633
|
+
### Can tools access React state?
|
|
634
|
+
|
|
635
|
+
Yes! Tool handlers have access to component state via closures. State updates trigger re-renders as expected.
|
|
636
|
+
|
|
637
|
+
## Comparison with Alternatives
|
|
638
|
+
|
|
639
|
+
| Feature | @mcp-b/react-webmcp | Raw MCP SDK | Custom Implementation |
|
|
640
|
+
|---------|---------------------|-------------|----------------------|
|
|
641
|
+
| React Lifecycle Integration | Automatic | Manual | Manual |
|
|
642
|
+
| StrictMode Support | Yes | N/A | Manual |
|
|
643
|
+
| Zod Schema Validation | Built-in | Manual | Manual |
|
|
644
|
+
| Execution State Tracking | Built-in | Manual | Manual |
|
|
645
|
+
| TypeScript Support | Full | Partial | Varies |
|
|
646
|
+
|
|
647
|
+
## Related Packages
|
|
648
|
+
|
|
649
|
+
- [`@mcp-b/global`](https://docs.mcp-b.ai/packages/global) - W3C Web Model Context API polyfill (required for provider hooks)
|
|
650
|
+
- [`@mcp-b/transports`](https://docs.mcp-b.ai/packages/transports) - Browser-specific MCP transports
|
|
651
|
+
- [`@mcp-b/chrome-devtools-mcp`](https://docs.mcp-b.ai/packages/chrome-devtools-mcp) - Connect desktop AI agents to browser tools
|
|
652
|
+
- [`@modelcontextprotocol/sdk`](https://www.npmjs.com/package/@modelcontextprotocol/sdk) - Official MCP SDK
|
|
653
|
+
|
|
654
|
+
## Resources
|
|
655
|
+
|
|
656
|
+
- [WebMCP Documentation](https://docs.mcp-b.ai)
|
|
657
|
+
- [AI Framework Integration](https://docs.mcp-b.ai/ai-frameworks)
|
|
658
|
+
- [Best Practices](https://docs.mcp-b.ai/best-practices)
|
|
659
|
+
- [Model Context Protocol Spec](https://modelcontextprotocol.io)
|
|
660
|
+
- [MCP GitHub Repository](https://github.com/modelcontextprotocol)
|
|
661
|
+
|
|
662
|
+
## License
|
|
663
|
+
|
|
664
|
+
MIT - see [LICENSE](../../LICENSE) for details
|
|
665
|
+
|
|
666
|
+
## Support
|
|
667
|
+
|
|
668
|
+
- [GitHub Issues](https://github.com/WebMCP-org/npm-packages/issues)
|
|
669
|
+
- [Documentation](https://docs.mcp-b.ai)
|
|
670
|
+
- [Discord Community](https://discord.gg/a9fBR6Bw)
|