@mcp-b/react-webmcp 0.1.1

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 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,478 @@
1
+ # @mcp-b/react-webmcp
2
+
3
+ Complete React hooks for the Model Context Protocol - register tools via `navigator.modelContext` and consume tools from MCP servers.
4
+
5
+ ## Features
6
+
7
+ ### Provider Hooks (Registering Tools)
8
+ - **Type-Safe**: Full TypeScript support with Zod schema validation
9
+ - **State-Aware**: Track execution state (loading, success, error) for UI feedback
10
+ - **React-Native**: Designed for React's lifecycle, including StrictMode compatibility
11
+ - **Developer-Friendly**: Intuitive API with comprehensive examples
12
+
13
+ ### Client Hooks (Consuming Tools)
14
+ - **MCP Client Provider**: Connect to MCP servers and consume their tools
15
+ - **Real-time Updates**: Listen for tool list changes via MCP notifications
16
+ - **Connection Management**: Automatic connection handling with reconnect support
17
+ - **Type-Safe Tool Calls**: Full TypeScript support for client operations
18
+
19
+ ## Installation
20
+
21
+ ```bash
22
+ pnpm add @mcp-b/react-webmcp zod
23
+ ```
24
+
25
+ For client functionality, you'll also need:
26
+ ```bash
27
+ pnpm add @mcp-b/transports @modelcontextprotocol/sdk
28
+ ```
29
+
30
+ ## Prerequisites
31
+
32
+ **For Provider Hooks:** Requires the global `navigator.modelContext` API. Install `@mcp-b/global` or use a browser that implements the Web Model Context API.
33
+
34
+ **For Client Hooks:** Requires an MCP server to connect to (e.g., one created with `@mcp-b/global` or the Model Context Protocol SDK).
35
+
36
+ ---
37
+
38
+ # Part 1: Provider API (Registering Tools)
39
+
40
+ Use these hooks to expose tools from your React app that AI agents can discover and call.
41
+
42
+ ## Quick Start - Provider
43
+
44
+ ### Basic Tool Registration
45
+
46
+ ```tsx
47
+ import { useWebMCP } from '@mcp-b/react-webmcp';
48
+ import { z } from 'zod';
49
+
50
+ function PostsPage() {
51
+ const likeTool = useWebMCP({
52
+ name: 'posts_like',
53
+ description: 'Like a post by ID. Increments the like count.',
54
+ inputSchema: {
55
+ postId: z.string().uuid().describe('The post ID to like'),
56
+ },
57
+ annotations: {
58
+ title: 'Like Post',
59
+ readOnlyHint: false,
60
+ idempotentHint: true,
61
+ },
62
+ handler: async (input) => {
63
+ await api.posts.like(input.postId);
64
+ return { success: true, postId: input.postId };
65
+ },
66
+ formatOutput: (result) => `Post ${result.postId} liked successfully!`,
67
+ });
68
+
69
+ return (
70
+ <div>
71
+ {likeTool.state.isExecuting && <Spinner />}
72
+ {likeTool.state.error && <ErrorAlert error={likeTool.state.error} />}
73
+ {/* Your UI */}
74
+ </div>
75
+ );
76
+ }
77
+ ```
78
+
79
+ ### Context Tool
80
+
81
+ Expose read-only context to AI:
82
+
83
+ ```tsx
84
+ import { useWebMCPContext } from '@mcp-b/react-webmcp';
85
+
86
+ function PostDetailPage() {
87
+ const { postId } = useParams();
88
+ const { data: post } = useQuery(['post', postId], () => fetchPost(postId));
89
+
90
+ useWebMCPContext(
91
+ 'context_current_post',
92
+ 'Get the currently viewed post ID and metadata',
93
+ () => ({
94
+ postId,
95
+ title: post?.title,
96
+ author: post?.author,
97
+ tags: post?.tags,
98
+ })
99
+ );
100
+
101
+ return <div>{/* Post UI */}</div>;
102
+ }
103
+ ```
104
+
105
+ ## Provider API Reference
106
+
107
+ ### `useWebMCP`
108
+
109
+ Main hook for registering MCP tools with full control over behavior and state.
110
+
111
+ ```tsx
112
+ function useWebMCP<
113
+ TInputSchema extends Record<string, z.ZodTypeAny>,
114
+ TOutput = string
115
+ >(config: WebMCPConfig<TInputSchema, TOutput>): WebMCPReturn<TOutput>
116
+ ```
117
+
118
+ #### Configuration Options
119
+
120
+ | Option | Type | Required | Description |
121
+ |--------|------|----------|-------------|
122
+ | `name` | `string` | ✓ | Unique tool identifier (e.g., 'posts_like') |
123
+ | `description` | `string` | ✓ | Human-readable description for AI |
124
+ | `inputSchema` | `Record<string, ZodType>` | - | Input validation using Zod schemas |
125
+ | `outputSchema` | `Record<string, ZodType>` | - | Output validation (optional) |
126
+ | `annotations` | `ToolAnnotations` | - | Metadata hints for the AI |
127
+ | `elicitation` | `ElicitationConfig` | - | User confirmation settings |
128
+ | `handler` | `(input) => Promise<TOutput>` | ✓ | Function that executes the tool |
129
+ | `formatOutput` | `(output) => string` | - | Custom output formatter |
130
+ | `onError` | `(error, input) => void` | - | Error handler callback |
131
+
132
+ #### Return Value
133
+
134
+ ```tsx
135
+ interface WebMCPReturn<TOutput> {
136
+ state: {
137
+ isExecuting: boolean; // Currently running
138
+ lastResult: TOutput | null; // Last successful result
139
+ error: Error | null; // Last error
140
+ executionCount: number; // Total executions
141
+ };
142
+ execute: (input: unknown) => Promise<TOutput>; // Manual execution
143
+ reset: () => void; // Reset state
144
+ }
145
+ ```
146
+
147
+ ### `useWebMCPContext`
148
+
149
+ Simplified hook for read-only context exposure:
150
+
151
+ ```tsx
152
+ function useWebMCPContext<T>(
153
+ name: string,
154
+ description: string,
155
+ getValue: () => T
156
+ ): WebMCPReturn<T>
157
+ ```
158
+
159
+ ---
160
+
161
+ # Part 2: Client API (Consuming Tools)
162
+
163
+ Use these hooks to connect to MCP servers and call their tools from your React app.
164
+
165
+ ## Quick Start - Client
166
+
167
+ ### Connecting to an MCP Server
168
+
169
+ ```tsx
170
+ import { McpClientProvider, useMcpClient } from '@mcp-b/react-webmcp';
171
+ import { Client } from '@modelcontextprotocol/sdk/client/index.js';
172
+ import { TabClientTransport } from '@mcp-b/transports';
173
+
174
+ // Create client and transport
175
+ const client = new Client({ name: 'MyApp', version: '1.0.0' });
176
+ const transport = new TabClientTransport('mcp', { clientInstanceId: 'my-app' });
177
+
178
+ function App() {
179
+ return (
180
+ <McpClientProvider client={client} transport={transport}>
181
+ <ToolConsumer />
182
+ </McpClientProvider>
183
+ );
184
+ }
185
+
186
+ function ToolConsumer() {
187
+ const { client, tools, isConnected, capabilities } = useMcpClient();
188
+
189
+ const handleCallTool = async () => {
190
+ const result = await client.callTool({
191
+ name: 'posts_like',
192
+ arguments: { postId: '123' }
193
+ });
194
+ console.log('Result:', result.content[0].text);
195
+ };
196
+
197
+ return (
198
+ <div>
199
+ <p>Connected: {isConnected ? 'Yes' : 'No'}</p>
200
+ <p>Available Tools: {tools.length}</p>
201
+ <ul>
202
+ {tools.map(tool => (
203
+ <li key={tool.name}>{tool.name} - {tool.description}</li>
204
+ ))}
205
+ </ul>
206
+ <button onClick={handleCallTool} disabled={!isConnected}>
207
+ Call Tool
208
+ </button>
209
+ </div>
210
+ );
211
+ }
212
+ ```
213
+
214
+ ### Listening for Tool List Changes
215
+
216
+ ```tsx
217
+ function ToolList() {
218
+ const { tools, isConnected, capabilities } = useMcpClient();
219
+
220
+ // Tools automatically update when server sends notifications
221
+ // if capabilities.tools.listChanged is true
222
+
223
+ return (
224
+ <div>
225
+ <h3>Tools ({tools.length})</h3>
226
+ {capabilities?.tools?.listChanged && (
227
+ <p>✓ Server supports real-time tool updates</p>
228
+ )}
229
+ {tools.map(tool => (
230
+ <div key={tool.name}>
231
+ <h4>{tool.name}</h4>
232
+ <p>{tool.description}</p>
233
+ </div>
234
+ ))}
235
+ </div>
236
+ );
237
+ }
238
+ ```
239
+
240
+ ## Client API Reference
241
+
242
+ ### `McpClientProvider`
243
+
244
+ Provider component that manages an MCP client connection.
245
+
246
+ ```tsx
247
+ interface McpClientProviderProps {
248
+ children: ReactNode;
249
+ client: Client; // MCP client instance
250
+ transport: Transport; // Transport for connection
251
+ opts?: RequestOptions; // Optional connection options
252
+ }
253
+ ```
254
+
255
+ #### Example Transports
256
+
257
+ ```tsx
258
+ // Connect to same-page MCP server (via @mcp-b/global)
259
+ import { TabClientTransport } from '@mcp-b/transports';
260
+ const transport = new TabClientTransport('mcp', { clientInstanceId: 'my-app' });
261
+
262
+ // Connect to Chrome extension MCP server
263
+ import { ExtensionClientTransport } from '@mcp-b/transports';
264
+ const transport = new ExtensionClientTransport({ portName: 'mcp' });
265
+
266
+ // In-memory connection (for testing)
267
+ import { InMemoryTransport } from '@modelcontextprotocol/sdk/inMemory.js';
268
+ const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
269
+ ```
270
+
271
+ ### `useMcpClient`
272
+
273
+ Hook to access the MCP client context. Must be used within `McpClientProvider`.
274
+
275
+ ```tsx
276
+ interface McpClientContextValue {
277
+ client: Client; // MCP client instance
278
+ tools: Tool[]; // Available tools from server
279
+ resources: Resource[]; // Available resources
280
+ isConnected: boolean; // Connection status
281
+ isLoading: boolean; // Currently connecting
282
+ error: Error | null; // Connection error
283
+ capabilities: ServerCapabilities | null; // Server capabilities
284
+ reconnect: () => Promise<void>; // Manual reconnection
285
+ }
286
+ ```
287
+
288
+ #### Calling Tools
289
+
290
+ ```tsx
291
+ function MyComponent() {
292
+ const { client, isConnected } = useMcpClient();
293
+
294
+ const callTool = async () => {
295
+ if (!isConnected) return;
296
+
297
+ try {
298
+ const result = await client.callTool({
299
+ name: 'my_tool',
300
+ arguments: { foo: 'bar' }
301
+ });
302
+
303
+ // Extract text from result
304
+ const text = result.content
305
+ .filter(c => c.type === 'text')
306
+ .map(c => c.text)
307
+ .join('\n');
308
+
309
+ console.log(text);
310
+ } catch (error) {
311
+ console.error('Tool call failed:', error);
312
+ }
313
+ };
314
+
315
+ return <button onClick={callTool}>Call Tool</button>;
316
+ }
317
+ ```
318
+
319
+ ---
320
+
321
+ # Complete Example: Both Provider and Client
322
+
323
+ This example shows a React app that both exposes tools AND consumes tools from an MCP server.
324
+
325
+ ```tsx
326
+ import '@mcp-b/global'; // Provides navigator.modelContext
327
+ import { McpClientProvider, useWebMCP, useMcpClient } from '@mcp-b/react-webmcp';
328
+ import { Client } from '@modelcontextprotocol/sdk/client/index.js';
329
+ import { TabClientTransport } from '@mcp-b/transports';
330
+ import { z } from 'zod';
331
+
332
+ // Create client to consume tools
333
+ const client = new Client({ name: 'MyApp', version: '1.0.0' });
334
+ const transport = new TabClientTransport('mcp', { clientInstanceId: 'my-app' });
335
+
336
+ function App() {
337
+ return (
338
+ <McpClientProvider client={client} transport={transport}>
339
+ <ToolProvider />
340
+ <ToolConsumer />
341
+ </McpClientProvider>
342
+ );
343
+ }
344
+
345
+ // Component that REGISTERS tools
346
+ function ToolProvider() {
347
+ const [count, setCount] = useState(0);
348
+
349
+ // Expose a tool that increments the counter
350
+ useWebMCP({
351
+ name: 'increment_counter',
352
+ description: 'Increment the counter',
353
+ inputSchema: {
354
+ amount: z.number().default(1)
355
+ },
356
+ handler: async ({ amount }) => {
357
+ setCount(prev => prev + amount);
358
+ return { newValue: count + amount };
359
+ }
360
+ });
361
+
362
+ return <div>Counter: {count}</div>;
363
+ }
364
+
365
+ // Component that CONSUMES tools
366
+ function ToolConsumer() {
367
+ const { client, tools, isConnected } = useMcpClient();
368
+ const [result, setResult] = useState('');
369
+
370
+ const callIncrementTool = async () => {
371
+ const res = await client.callTool({
372
+ name: 'increment_counter',
373
+ arguments: { amount: 5 }
374
+ });
375
+ setResult(res.content[0].text);
376
+ };
377
+
378
+ return (
379
+ <div>
380
+ <p>Available Tools: {tools.map(t => t.name).join(', ')}</p>
381
+ <button onClick={callIncrementTool} disabled={!isConnected}>
382
+ Call increment_counter Tool
383
+ </button>
384
+ {result && <p>Result: {result}</p>}
385
+ </div>
386
+ );
387
+ }
388
+ ```
389
+
390
+ ---
391
+
392
+ # Migration from @mcp-b/mcp-react-hooks
393
+
394
+ If you're migrating from the deprecated `@mcp-b/mcp-react-hooks` package:
395
+
396
+ ## What Changed
397
+
398
+ - **Server providers removed**: `McpServerProvider` and `McpMemoryProvider` are gone
399
+ - **Everything in one package**: Both client and provider hooks are now in `@mcp-b/react-webmcp`
400
+ - **Tool registration**: Use `useWebMCP` instead of server providers
401
+ - **Client unchanged**: `McpClientProvider` and `useMcpClient` work the same way
402
+
403
+ ## Migration Guide
404
+
405
+ ### Before (mcp-react-hooks)
406
+
407
+ ```tsx
408
+ import { McpClientProvider, useMcpClient } from '@mcp-b/mcp-react-hooks';
409
+ import { McpServerProvider, useMcpServer } from '@mcp-b/mcp-react-hooks';
410
+ ```
411
+
412
+ ### After (react-webmcp)
413
+
414
+ ```tsx
415
+ // Client hooks - same API
416
+ import { McpClientProvider, useMcpClient } from '@mcp-b/react-webmcp';
417
+
418
+ // For registering tools, use useWebMCP instead of server providers
419
+ import { useWebMCP } from '@mcp-b/react-webmcp';
420
+ ```
421
+
422
+ ### Converting Server to Provider
423
+
424
+ **Before:**
425
+ ```tsx
426
+ function MyApp() {
427
+ const { registerTool } = useMcpServer();
428
+
429
+ useEffect(() => {
430
+ const tool = registerTool('my_tool', { description: '...' }, handler);
431
+ return () => tool.remove();
432
+ }, []);
433
+ }
434
+ ```
435
+
436
+ **After:**
437
+ ```tsx
438
+ function MyApp() {
439
+ useWebMCP({
440
+ name: 'my_tool',
441
+ description: '...',
442
+ handler: handler
443
+ });
444
+ // Auto-registers and cleans up on unmount
445
+ }
446
+ ```
447
+
448
+ ---
449
+
450
+ # Best Practices
451
+
452
+ ### Tool Naming
453
+ - Use verb-noun format: `posts_like`, `graph_navigate`, `table_filter`
454
+ - Prefix with domain: `posts_`, `comments_`, `graph_`
455
+ - Be specific and descriptive
456
+
457
+ ### Annotations
458
+ - Always set `readOnlyHint` (true for queries, false for mutations)
459
+ - Set `idempotentHint` (true if repeated calls are safe)
460
+ - Set `destructiveHint` for delete/permanent operations
461
+
462
+ ### Error Handling
463
+ - Throw descriptive errors from tool handlers
464
+ - Use `onError` callback for side effects (logging, toasts)
465
+ - Handle connection errors in client components
466
+
467
+ ### Performance
468
+ - Tools automatically prevent duplicate registration in React StrictMode
469
+ - Use `useWebMCPContext` for lightweight read-only data exposure
470
+ - Client automatically manages reconnection and tool list updates
471
+
472
+ ## License
473
+
474
+ MIT
475
+
476
+ ## Contributing
477
+
478
+ See the [main repository](https://github.com/WebMCP-org/WebMCP) for contribution guidelines.
@@ -0,0 +1,449 @@
1
+ import { ReactElement, ReactNode } from "react";
2
+ import { z } from "zod";
3
+ import { CallToolResult, Resource, Resource as Resource$1, ServerCapabilities, ServerCapabilities as ServerCapabilities$1, Tool, Tool as Tool$1 } from "@modelcontextprotocol/sdk/types.js";
4
+ import { ToolAnnotations } from "@mcp-b/webmcp-ts-sdk";
5
+ import { ModelContext as ModelContextProtocol, ToolDescriptor } from "@mcp-b/global";
6
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
7
+ import { RequestOptions } from "@modelcontextprotocol/sdk/shared/protocol.js";
8
+ import { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
9
+
10
+ //#region src/types.d.ts
11
+
12
+ /**
13
+ * Represents the current execution state of a tool, including loading status,
14
+ * results, errors, and execution history.
15
+ *
16
+ * @template TOutput - The type of data returned by the tool handler
17
+ * @public
18
+ */
19
+ interface ToolExecutionState<TOutput = unknown> {
20
+ /**
21
+ * Indicates whether the tool is currently executing.
22
+ * Use this to show loading states in your UI.
23
+ */
24
+ isExecuting: boolean;
25
+ /**
26
+ * The result from the most recent successful execution.
27
+ * Will be `null` if the tool hasn't been executed or last execution failed.
28
+ */
29
+ lastResult: TOutput | null;
30
+ /**
31
+ * The error from the most recent failed execution.
32
+ * Will be `null` if the tool hasn't been executed or last execution succeeded.
33
+ */
34
+ error: Error | null;
35
+ /**
36
+ * Total number of times this tool has been executed.
37
+ * Increments on both successful and failed executions.
38
+ */
39
+ executionCount: number;
40
+ }
41
+ /**
42
+ * Configuration options for the `useWebMCP` hook.
43
+ * Defines a tool's metadata, schema, handler, and lifecycle callbacks.
44
+ *
45
+ * @template TInputSchema - Zod schema object defining input parameters
46
+ * @template TOutput - The type of data returned by the handler function
47
+ * @public
48
+ *
49
+ * @example
50
+ * ```typescript
51
+ * const config: WebMCPConfig = {
52
+ * name: 'posts_like',
53
+ * description: 'Like a post by its ID',
54
+ * inputSchema: {
55
+ * postId: z.string().uuid(),
56
+ * },
57
+ * handler: async ({ postId }) => {
58
+ * await api.likePost(postId);
59
+ * return { success: true };
60
+ * },
61
+ * };
62
+ * ```
63
+ */
64
+ interface WebMCPConfig<TInputSchema extends Record<string, z.ZodTypeAny> = Record<string, never>, TOutput = string> {
65
+ /**
66
+ * Unique identifier for the tool (e.g., 'posts_like', 'graph_navigate').
67
+ * Must follow naming conventions: lowercase with underscores.
68
+ */
69
+ name: string;
70
+ /**
71
+ * Human-readable description explaining what the tool does.
72
+ * This description is used by AI assistants to understand when to use the tool.
73
+ */
74
+ description: string;
75
+ /**
76
+ * Zod schema object defining the input parameters for the tool.
77
+ * Each key is a parameter name, and the value is a Zod type definition.
78
+ *
79
+ * @example
80
+ * ```typescript
81
+ * inputSchema: {
82
+ * postId: z.string().uuid().describe('The ID of the post to like'),
83
+ * userId: z.string().optional(),
84
+ * }
85
+ * ```
86
+ */
87
+ inputSchema?: TInputSchema;
88
+ /**
89
+ * Optional Zod schema object defining the expected output structure.
90
+ * Used for runtime validation of handler return values.
91
+ */
92
+ outputSchema?: Record<string, z.ZodTypeAny>;
93
+ /**
94
+ * Optional metadata annotations providing hints about tool behavior.
95
+ * See {@link ToolAnnotations} for available options.
96
+ */
97
+ annotations?: ToolAnnotations;
98
+ /**
99
+ * The function that executes when the tool is called.
100
+ * Can be synchronous or asynchronous.
101
+ *
102
+ * @param input - Validated input parameters matching the inputSchema
103
+ * @returns The result data or a Promise resolving to the result
104
+ */
105
+ handler: (input: z.infer<z.ZodObject<TInputSchema>>) => Promise<TOutput> | TOutput;
106
+ /**
107
+ * Optional function to format the handler output for the MCP response.
108
+ * Defaults to JSON.stringify with indentation.
109
+ *
110
+ * @param output - The raw output from the handler
111
+ * @returns Formatted string for the MCP response
112
+ */
113
+ formatOutput?: (output: TOutput) => string;
114
+ /**
115
+ * Optional callback invoked when the tool execution succeeds.
116
+ * Useful for triggering side effects like navigation or analytics.
117
+ *
118
+ * @param result - The successful result from the handler
119
+ * @param input - The input that was passed to the handler
120
+ */
121
+ onSuccess?: (result: TOutput, input: unknown) => void;
122
+ /**
123
+ * Optional callback invoked when the tool execution fails.
124
+ * Useful for error handling, logging, or showing user notifications.
125
+ *
126
+ * @param error - The error that occurred during execution
127
+ * @param input - The input that was passed to the handler
128
+ */
129
+ onError?: (error: Error, input: unknown) => void;
130
+ }
131
+ /**
132
+ * Return value from the `useWebMCP` hook.
133
+ * Provides access to execution state and methods for manual tool control.
134
+ *
135
+ * @template TOutput - The type of data returned by the tool handler
136
+ * @public
137
+ */
138
+ interface WebMCPReturn<TOutput = unknown> {
139
+ /**
140
+ * Current execution state including loading status, results, and errors.
141
+ * See {@link ToolExecutionState} for details.
142
+ */
143
+ state: ToolExecutionState<TOutput>;
144
+ /**
145
+ * Manually execute the tool with the provided input.
146
+ * Useful for testing, debugging, or triggering execution from your UI.
147
+ *
148
+ * @param input - The input parameters to pass to the tool
149
+ * @returns Promise resolving to the tool's output
150
+ * @throws Error if validation fails or handler throws
151
+ */
152
+ execute: (input: unknown) => Promise<TOutput>;
153
+ /**
154
+ * Reset the execution state to its initial values.
155
+ * Clears results, errors, and resets the execution count.
156
+ */
157
+ reset: () => void;
158
+ }
159
+ //#endregion
160
+ //#region src/useWebMCP.d.ts
161
+ /**
162
+ * React hook for registering and managing Model Context Protocol (MCP) tools.
163
+ *
164
+ * This hook handles the complete lifecycle of an MCP tool:
165
+ * - Registers the tool with `window.navigator.modelContext`
166
+ * - Manages execution state (loading, results, errors)
167
+ * - Validates input using Zod schemas
168
+ * - Handles tool execution and lifecycle callbacks
169
+ * - Automatically unregisters on component unmount
170
+ *
171
+ * @template TInputSchema - Zod schema object defining input parameter types
172
+ * @template TOutput - Type of data returned by the handler function
173
+ *
174
+ * @param config - Configuration object for the tool
175
+ * @returns Object containing execution state and control methods
176
+ *
177
+ * @public
178
+ *
179
+ * @example
180
+ * Basic tool registration:
181
+ * ```tsx
182
+ * function PostActions() {
183
+ * const likeTool = useWebMCP({
184
+ * name: 'posts_like',
185
+ * description: 'Like a post by ID',
186
+ * inputSchema: {
187
+ * postId: z.string().uuid().describe('The ID of the post to like'),
188
+ * },
189
+ * handler: async ({ postId }) => {
190
+ * await api.posts.like(postId);
191
+ * return { success: true, postId };
192
+ * },
193
+ * });
194
+ *
195
+ * if (likeTool.state.isExecuting) {
196
+ * return <Spinner />;
197
+ * }
198
+ *
199
+ * return <div>Post actions ready</div>;
200
+ * }
201
+ * ```
202
+ *
203
+ * @example
204
+ * Tool with annotations and callbacks:
205
+ * ```tsx
206
+ * const deleteTool = useWebMCP({
207
+ * name: 'posts_delete',
208
+ * description: 'Delete a post permanently',
209
+ * inputSchema: {
210
+ * postId: z.string().uuid(),
211
+ * },
212
+ * annotations: {
213
+ * destructiveHint: true,
214
+ * idempotentHint: false,
215
+ * },
216
+ * handler: async ({ postId }) => {
217
+ * await api.posts.delete(postId);
218
+ * return { deleted: true };
219
+ * },
220
+ * onSuccess: () => {
221
+ * navigate('/posts');
222
+ * toast.success('Post deleted');
223
+ * },
224
+ * onError: (error) => {
225
+ * toast.error(`Failed to delete: ${error.message}`);
226
+ * },
227
+ * });
228
+ * ```
229
+ */
230
+ declare function useWebMCP<TInputSchema extends Record<string, z.ZodTypeAny> = Record<string, never>, TOutput = string>(config: WebMCPConfig<TInputSchema, TOutput>): WebMCPReturn<TOutput>;
231
+ //#endregion
232
+ //#region src/useWebMCPContext.d.ts
233
+ /**
234
+ * Convenience hook for exposing read-only context data to AI assistants.
235
+ *
236
+ * This is a simplified wrapper around {@link useWebMCP} specifically designed for
237
+ * context tools that expose data without performing actions. The hook automatically
238
+ * configures appropriate annotations (read-only, idempotent) and handles value
239
+ * serialization.
240
+ *
241
+ * @template T - The type of context data to expose
242
+ *
243
+ * @param name - Unique identifier for the context tool (e.g., 'context_current_post')
244
+ * @param description - Human-readable description of the context for AI assistants
245
+ * @param getValue - Function that returns the current context value
246
+ * @returns Tool execution state and control methods
247
+ *
248
+ * @public
249
+ *
250
+ * @example
251
+ * Expose current post context:
252
+ * ```tsx
253
+ * function PostDetailPage() {
254
+ * const { postId } = useParams();
255
+ * const { data: post } = useQuery(['post', postId], () => fetchPost(postId));
256
+ *
257
+ * useWebMCPContext(
258
+ * 'context_current_post',
259
+ * 'Get the currently viewed post ID and metadata',
260
+ * () => ({
261
+ * postId,
262
+ * title: post?.title,
263
+ * author: post?.author,
264
+ * tags: post?.tags,
265
+ * createdAt: post?.createdAt,
266
+ * })
267
+ * );
268
+ *
269
+ * return <PostContent post={post} />;
270
+ * }
271
+ * ```
272
+ *
273
+ * @example
274
+ * Expose user session context:
275
+ * ```tsx
276
+ * function AppRoot() {
277
+ * const { user, isAuthenticated } = useAuth();
278
+ *
279
+ * useWebMCPContext(
280
+ * 'context_user_session',
281
+ * 'Get the current user session information',
282
+ * () => ({
283
+ * isAuthenticated,
284
+ * userId: user?.id,
285
+ * email: user?.email,
286
+ * permissions: user?.permissions,
287
+ * })
288
+ * );
289
+ *
290
+ * return <App />;
291
+ * }
292
+ * ```
293
+ */
294
+ declare function useWebMCPContext<T>(name: string, description: string, getValue: () => T): WebMCPReturn<T>;
295
+ //#endregion
296
+ //#region src/client/McpClientProvider.d.ts
297
+ /**
298
+ * Context value provided by McpClientProvider.
299
+ *
300
+ * @internal
301
+ */
302
+ interface McpClientContextValue {
303
+ client: Client;
304
+ tools: Tool$1[];
305
+ resources: Resource$1[];
306
+ isConnected: boolean;
307
+ isLoading: boolean;
308
+ error: Error | null;
309
+ capabilities: ServerCapabilities$1 | null;
310
+ reconnect: () => Promise<void>;
311
+ }
312
+ /**
313
+ * Props for the McpClientProvider component.
314
+ *
315
+ * @public
316
+ */
317
+ interface McpClientProviderProps {
318
+ /**
319
+ * React children to render within the provider.
320
+ */
321
+ children: ReactNode;
322
+ /**
323
+ * MCP Client instance to use for communication.
324
+ */
325
+ client: Client;
326
+ /**
327
+ * Transport instance for the client to connect through.
328
+ */
329
+ transport: Transport;
330
+ /**
331
+ * Optional request options for the connection.
332
+ */
333
+ opts?: RequestOptions;
334
+ }
335
+ /**
336
+ * Provider component that manages an MCP client connection and exposes
337
+ * tools, resources, and connection state to child components.
338
+ *
339
+ * This provider handles:
340
+ * - Establishing and maintaining the MCP client connection
341
+ * - Fetching available tools and resources from the server
342
+ * - Listening for server notifications about tool/resource changes
343
+ * - Managing connection state and errors
344
+ * - Automatic cleanup on unmount
345
+ *
346
+ * @param props - Component props
347
+ * @returns Provider component wrapping children
348
+ *
349
+ * @public
350
+ *
351
+ * @example
352
+ * Connect to an MCP server via tab transport:
353
+ * ```tsx
354
+ * import { Client } from '@modelcontextprotocol/sdk/client/index.js';
355
+ * import { TabClientTransport } from '@mcp-b/transports';
356
+ * import { McpClientProvider } from '@mcp-b/react-webmcp';
357
+ *
358
+ * const client = new Client(
359
+ * { name: 'my-app', version: '1.0.0' },
360
+ * { capabilities: {} }
361
+ * );
362
+ *
363
+ * const transport = new TabClientTransport('mcp', {
364
+ * clientInstanceId: 'my-app-instance',
365
+ * });
366
+ *
367
+ * function App() {
368
+ * return (
369
+ * <McpClientProvider client={client} transport={transport}>
370
+ * <MyAppContent />
371
+ * </McpClientProvider>
372
+ * );
373
+ * }
374
+ * ```
375
+ *
376
+ * @example
377
+ * Access tools from child components:
378
+ * ```tsx
379
+ * function MyAppContent() {
380
+ * const { tools, isConnected, isLoading } = useMcpClient();
381
+ *
382
+ * if (isLoading) {
383
+ * return <div>Connecting to MCP server...</div>;
384
+ * }
385
+ *
386
+ * if (!isConnected) {
387
+ * return <div>Failed to connect to MCP server</div>;
388
+ * }
389
+ *
390
+ * return (
391
+ * <div>
392
+ * <h2>Available Tools:</h2>
393
+ * <ul>
394
+ * {tools.map(tool => (
395
+ * <li key={tool.name}>{tool.description}</li>
396
+ * ))}
397
+ * </ul>
398
+ * </div>
399
+ * );
400
+ * }
401
+ * ```
402
+ */
403
+ declare function McpClientProvider({
404
+ children,
405
+ client,
406
+ transport,
407
+ opts
408
+ }: McpClientProviderProps): ReactElement;
409
+ /**
410
+ * Hook to access the MCP client context.
411
+ * Must be used within an {@link McpClientProvider}.
412
+ *
413
+ * @returns The MCP client context including client instance, tools, resources, and connection state
414
+ * @throws Error if used outside of McpClientProvider
415
+ *
416
+ * @public
417
+ *
418
+ * @example
419
+ * ```tsx
420
+ * function ToolsList() {
421
+ * const { tools, isConnected, error, reconnect } = useMcpClient();
422
+ *
423
+ * if (error) {
424
+ * return (
425
+ * <div>
426
+ * Error: {error.message}
427
+ * <button onClick={reconnect}>Retry</button>
428
+ * </div>
429
+ * );
430
+ * }
431
+ *
432
+ * if (!isConnected) {
433
+ * return <div>Not connected</div>;
434
+ * }
435
+ *
436
+ * return (
437
+ * <ul>
438
+ * {tools.map(tool => (
439
+ * <li key={tool.name}>{tool.description}</li>
440
+ * ))}
441
+ * </ul>
442
+ * );
443
+ * }
444
+ * ```
445
+ */
446
+ declare function useMcpClient(): McpClientContextValue;
447
+ //#endregion
448
+ export { type CallToolResult, McpClientProvider, type McpClientProviderProps, type ModelContextProtocol, type Resource, type ServerCapabilities, type Tool, type ToolAnnotations, type ToolDescriptor, type ToolExecutionState, type WebMCPConfig, type WebMCPReturn, useMcpClient, useWebMCP, useWebMCPContext };
449
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/types.ts","../src/useWebMCP.ts","../src/useWebMCPContext.ts","../src/client/McpClientProvider.tsx"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;;;;;AAcA;AAiDiB,UAjDA,kBAiDY,CAAA,UAAA,OAAA,CAAA,CAAA;EACW;;;;EAiCN,WAAA,EAAA,OAAA;EAAjB;;;;EAeI,UAAA,EAvFP,OAuFO,GAAA,IAAA;EAA6C;;;;EAkB3C,KAAA,EAnGd,KAmGc,GAAA,IAAA;EASH;;AAUpB;;EAKS,cAAA,EAAA,MAAA;;;;;;;AClBT;;;;;;;;;;;;;ACvEA;;;;;UFFiB,kCACM,eAAe,CAAA,CAAE,cAAc;;;AG3CvC;;EASN,IAAA,EAAA,MAAA;EACI;;;;EAKa,WAAA,EAAA,MAAA;EAUT;;;;;;AA0FjB;;;;;;EAK4B,WAAA,CAAA,EHlDZ,YGkDY;EAAY;AAgMxC;;;iBH5OiB,eAAe,CAAA,CAAE;;;;;gBAMlB;;;;;;;;mBASG,CAAA,CAAE,MAAM,CAAA,CAAE,UAAU,mBAAmB,QAAQ,WAAW;;;;;;;;0BASnD;;;;;;;;uBASH;;;;;;;;oBASH;;;;;;;;;UAUH;;;;;SAKR,mBAAmB;;;;;;;;;+BAUG,QAAQ;;;;;;;;;;;;;;;;;AAtJvC;AAiDA;;;;;;;;;;;;;;;;;;AAsFA;;;;;;;;;ACbA;;;;;;;;;;;;;ACvEA;;;;;;;;AC5Ce;;;;;;;;AAyBf;;;;AAmBS,iBFuEO,SEvEP,CAAA,qBFwEc,MExEd,CAAA,MAAA,EFwE6B,CAAA,CAAE,UExE/B,CAAA,GFwE6C,MExE7C,CAAA,MAAA,EAAA,KAAA,CAAA,EAAA,UAAA,MAAA,CAAA,CAAA,MAAA,EF0EC,YE1ED,CF0Ec,YE1Ed,EF0E4B,OE1E5B,CAAA,CAAA,EF0EuC,YE1EvC,CF0EoD,OE1EpD,CAAA;;;;;;;;;;;;AHnDT;AAiDA;;;;;;;;;;;;;;;;;;AAsFA;;;;;;;;;ACbA;;;;;;;;;;;;;ACvEA;;;;;;;;AC5Ce;;;AAUF,iBDkCG,gBClCH,CAAA,CAAA,CAAA,CAAA,IAAA,EAAA,MAAA,EAAA,WAAA,EAAA,MAAA,EAAA,QAAA,EAAA,GAAA,GDqCK,CCrCL,CAAA,EDsCV,YCtCU,CDsCG,CCtCH,CAAA;;;;;;;;AHjBb,UGcU,qBAAA,CHdyB;EAiDlB,MAAA,EGlCP,MHkCO;EACuB,KAAA,EGlC/B,MHkC+B,EAAA;EAAjB,SAAA,EGjCV,UHiCU,EAAA;EAA+B,WAAA,EAAA,OAAA;EA2BtC,SAAA,EAAA,OAAA;EAMkB,KAAA,EG/DzB,KH+DyB,GAAA,IAAA;EAAjB,YAAA,EG9DD,oBH8DC,GAAA,IAAA;EAMD,SAAA,EAAA,GAAA,GGnEG,OHmEH,CAAA,IAAA,CAAA;;;;;;;AAkBU,UG3ET,sBAAA,CH2ES;EASH;;;EAmBN,QAAA,EGnGL,SHmGiB;EAKD;;;EAUG,MAAA,EG7GrB,MH6GqB;EAAO;;;aGxGzB;EF4EG;;;EACsC,IAAA,CAAA,EExE7C,cFwE6C;;;;;;;;;;ACxEtD;;;;;;;;AC5Ce;;;;;;;;AAyBf;;;;;;AA0FA;;;;;;;;AAqMA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBArMgB,iBAAA;;;;;GAKb,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAgMZ,YAAA,CAAA,GAAY"}
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ import{createContext as e,useCallback as t,useContext as n,useEffect as r,useRef as i,useState as a}from"react";import{z as o}from"zod";import{ResourceListChangedNotificationSchema as s,ToolListChangedNotificationSchema as c}from"@modelcontextprotocol/sdk/types.js";import{jsx as l}from"react/jsx-runtime";function u(e){let t={},n=[];for(let[r,i]of Object.entries(e)){let e=i.description||void 0,a=`string`;i instanceof o.ZodNumber?a=`number`:i instanceof o.ZodBoolean?a=`boolean`:i instanceof o.ZodArray?a=`array`:i instanceof o.ZodObject&&(a=`object`),t[r]={type:a,...e&&{description:e}},i.isOptional()||n.push(r)}return{type:`object`,properties:t,...n.length>0&&{required:n}}}function d(e){return typeof e==`string`?e:JSON.stringify(e,null,2)}function f(e){let{name:n,description:s,inputSchema:c,outputSchema:l,annotations:f,handler:p,formatOutput:m=d,onSuccess:h,onError:g}=e,[_,v]=a({isExecuting:!1,lastResult:null,error:null,executionCount:0}),y=i(p),b=i(h),x=i(g),S=i(m);r(()=>{y.current=p},[p]),r(()=>{b.current=h},[h]),r(()=>{x.current=g},[g]),r(()=>{S.current=m},[m]);let C=c?o.object(c):null,w=t(async e=>{v(e=>({...e,isExecuting:!0,error:null}));try{let t=C?C.parse(e):e,n=await y.current(t);return v(e=>({isExecuting:!1,lastResult:n,error:null,executionCount:e.executionCount+1})),b.current&&b.current(n,e),n}catch(t){let n=t instanceof Error?t:Error(String(t));throw v(e=>({...e,isExecuting:!1,error:n})),x.current&&x.current(n,e),n}},[C]),T=t(()=>{v({isExecuting:!1,lastResult:null,error:null,executionCount:0})},[]);return r(()=>{if(typeof window>`u`||!window.navigator?.modelContext){console.warn(`[useWebMCP] window.navigator.modelContext is not available. Tool "${n}" will not be registered.`);return}let e=c?u(c):void 0,t=l?u(l):void 0,r=async(e,t)=>{try{let t=await w(e);return{content:[{type:`text`,text:S.current(t)}]}}catch(e){return{content:[{type:`text`,text:`Error: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}},i=window.navigator.modelContext.registerTool({name:n,description:s,inputSchema:e||{type:`object`,properties:{}},...t&&{outputSchema:t},...f&&{annotations:f},execute:async e=>await r(e,{})});if(console.log(`[useWebMCP] Registered tool: ${n}`),typeof window<`u`){let e=window.navigator.modelContext.listTools(),t=window;t.mcpTools=e.map(e=>e.name)}return()=>{if(i&&(i.unregister(),console.log(`[useWebMCP] Unregistered tool: ${n}`),typeof window<`u`&&window.navigator?.modelContext)){let e=window.navigator.modelContext.listTools(),t=window;t.mcpTools=e.map(e=>e.name)}}},[n,s,c,l,f,w]),{state:_,execute:w,reset:T}}function p(e,t,n){let r=i(n);return r.current=n,f({name:e,description:t,annotations:{title:`Context: ${e}`,readOnlyHint:!0,idempotentHint:!0,destructiveHint:!1,openWorldHint:!1},handler:async()=>r.current(),formatOutput:e=>typeof e==`string`?e:JSON.stringify(e,null,2)})}const m=e(null);function h({children:e,client:n,transport:o,opts:u={}}){let[d,f]=a([]),[p,h]=a([]),[g,_]=a(!1),[v,y]=a(null),[b,x]=a(!1),[S,C]=a(null),w=i(`disconnected`),T=t(async()=>{if(n){if(!n.getServerCapabilities()?.resources){f([]);return}try{f((await n.listResources()).resources)}catch(e){throw console.error(`Error fetching resources:`,e),e}}},[n]),E=t(async()=>{if(n){if(!n.getServerCapabilities()?.tools){h([]);return}try{h((await n.listTools()).tools)}catch(e){throw console.error(`Error fetching tools:`,e),e}}},[n]),D=t(async()=>{if(!n||!o)throw Error(`Client or transport not available`);if(w.current===`disconnected`){w.current=`connecting`,_(!0),y(null);try{await n.connect(o,u);let e=n.getServerCapabilities();x(!0),C(e||null),w.current=`connected`,await Promise.all([T(),E()])}catch(e){let t=e instanceof Error?e:Error(String(e));throw w.current=`disconnected`,y(t),t}finally{_(!1)}}},[n,o,u,T,E]);return r(()=>{if(!b||!n)return;let e=n.getServerCapabilities();return e?.resources?.listChanged&&n.setNotificationHandler(s,()=>{T().catch(console.error)}),e?.tools?.listChanged&&n.setNotificationHandler(c,()=>{E().catch(console.error)}),()=>{e?.resources?.listChanged&&n.removeNotificationHandler(`notifications/resources/list_changed`),e?.tools?.listChanged&&n.removeNotificationHandler(`notifications/tools/list_changed`)}},[n,b,T,E]),r(()=>(D().catch(e=>{console.error(`Failed to connect MCP client:`,e)}),()=>{w.current=`disconnected`,x(!1)}),[n,o]),l(m.Provider,{value:{client:n,tools:p,resources:d,isConnected:b,isLoading:g,error:v,capabilities:S,reconnect:D},children:e})}function g(){let e=n(m);if(!e)throw Error(`useMcpClient must be used within an McpClientProvider`);return e}export{h as McpClientProvider,g as useMcpClient,f as useWebMCP,p as useWebMCPContext};
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["properties: Record<string, unknown>","required: string[]"],"sources":["../src/useWebMCP.ts","../src/useWebMCPContext.ts","../src/client/McpClientProvider.tsx"],"sourcesContent":["import type { InputSchema } from '@mcp-b/global';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { z } from 'zod';\nimport type { ToolExecutionState, WebMCPConfig, WebMCPReturn } from './types.js';\n\n/**\n * Converts a Zod schema object to JSON Schema format for MCP.\n * Handles basic type inference for common Zod types.\n *\n * @internal\n * @param schema - Record of Zod type definitions\n * @returns JSON Schema object with type, properties, and required fields\n */\nfunction zodToJsonSchema(schema: Record<string, z.ZodTypeAny>): {\n type: string;\n properties?: Record<string, unknown>;\n required?: string[];\n} {\n const properties: Record<string, unknown> = {};\n const required: string[] = [];\n\n for (const [key, zodType] of Object.entries(schema)) {\n const description = (zodType as { description?: string }).description || undefined;\n\n let type = 'string';\n if (zodType instanceof z.ZodNumber) {\n type = 'number';\n } else if (zodType instanceof z.ZodBoolean) {\n type = 'boolean';\n } else if (zodType instanceof z.ZodArray) {\n type = 'array';\n } else if (zodType instanceof z.ZodObject) {\n type = 'object';\n }\n\n properties[key] = {\n type,\n ...(description && { description }),\n };\n\n if (!zodType.isOptional()) {\n required.push(key);\n }\n }\n\n return {\n type: 'object',\n properties,\n ...(required.length > 0 && { required }),\n };\n}\n\n/**\n * Default output formatter that converts values to formatted JSON strings.\n *\n * @internal\n * @param output - The value to format\n * @returns Formatted string representation\n */\nfunction defaultFormatOutput(output: unknown): string {\n if (typeof output === 'string') {\n return output;\n }\n return JSON.stringify(output, null, 2);\n}\n\n/**\n * React hook for registering and managing Model Context Protocol (MCP) tools.\n *\n * This hook handles the complete lifecycle of an MCP tool:\n * - Registers the tool with `window.navigator.modelContext`\n * - Manages execution state (loading, results, errors)\n * - Validates input using Zod schemas\n * - Handles tool execution and lifecycle callbacks\n * - Automatically unregisters on component unmount\n *\n * @template TInputSchema - Zod schema object defining input parameter types\n * @template TOutput - Type of data returned by the handler function\n *\n * @param config - Configuration object for the tool\n * @returns Object containing execution state and control methods\n *\n * @public\n *\n * @example\n * Basic tool registration:\n * ```tsx\n * function PostActions() {\n * const likeTool = useWebMCP({\n * name: 'posts_like',\n * description: 'Like a post by ID',\n * inputSchema: {\n * postId: z.string().uuid().describe('The ID of the post to like'),\n * },\n * handler: async ({ postId }) => {\n * await api.posts.like(postId);\n * return { success: true, postId };\n * },\n * });\n *\n * if (likeTool.state.isExecuting) {\n * return <Spinner />;\n * }\n *\n * return <div>Post actions ready</div>;\n * }\n * ```\n *\n * @example\n * Tool with annotations and callbacks:\n * ```tsx\n * const deleteTool = useWebMCP({\n * name: 'posts_delete',\n * description: 'Delete a post permanently',\n * inputSchema: {\n * postId: z.string().uuid(),\n * },\n * annotations: {\n * destructiveHint: true,\n * idempotentHint: false,\n * },\n * handler: async ({ postId }) => {\n * await api.posts.delete(postId);\n * return { deleted: true };\n * },\n * onSuccess: () => {\n * navigate('/posts');\n * toast.success('Post deleted');\n * },\n * onError: (error) => {\n * toast.error(`Failed to delete: ${error.message}`);\n * },\n * });\n * ```\n */\nexport function useWebMCP<\n TInputSchema extends Record<string, z.ZodTypeAny> = Record<string, never>,\n TOutput = string,\n>(config: WebMCPConfig<TInputSchema, TOutput>): WebMCPReturn<TOutput> {\n const {\n name,\n description,\n inputSchema,\n outputSchema,\n annotations,\n handler,\n formatOutput = defaultFormatOutput,\n onSuccess,\n onError,\n } = config;\n\n const [state, setState] = useState<ToolExecutionState<TOutput>>({\n isExecuting: false,\n lastResult: null,\n error: null,\n executionCount: 0,\n });\n\n const handlerRef = useRef(handler);\n const onSuccessRef = useRef(onSuccess);\n const onErrorRef = useRef(onError);\n const formatOutputRef = useRef(formatOutput);\n\n useEffect(() => {\n handlerRef.current = handler;\n }, [handler]);\n\n useEffect(() => {\n onSuccessRef.current = onSuccess;\n }, [onSuccess]);\n\n useEffect(() => {\n onErrorRef.current = onError;\n }, [onError]);\n\n useEffect(() => {\n formatOutputRef.current = formatOutput;\n }, [formatOutput]);\n\n const validator = inputSchema ? z.object(inputSchema) : null;\n\n /**\n * Executes the tool handler with input validation and state management.\n *\n * @param input - The input parameters to validate and pass to the handler\n * @returns Promise resolving to the handler's output\n * @throws Error if validation fails or the handler throws\n */\n const execute = useCallback(\n async (input: unknown): Promise<TOutput> => {\n setState((prev) => ({\n ...prev,\n isExecuting: true,\n error: null,\n }));\n\n try {\n const validatedInput = validator ? validator.parse(input) : input;\n const result = await handlerRef.current(validatedInput as never);\n\n setState((prev) => ({\n isExecuting: false,\n lastResult: result,\n error: null,\n executionCount: prev.executionCount + 1,\n }));\n\n if (onSuccessRef.current) {\n onSuccessRef.current(result, input);\n }\n\n return result;\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n\n setState((prev) => ({\n ...prev,\n isExecuting: false,\n error: err,\n }));\n\n if (onErrorRef.current) {\n onErrorRef.current(err, input);\n }\n\n throw err;\n }\n },\n [validator]\n );\n\n /**\n * Resets the execution state to initial values.\n */\n const reset = useCallback(() => {\n setState({\n isExecuting: false,\n lastResult: null,\n error: null,\n executionCount: 0,\n });\n }, []);\n\n useEffect(() => {\n if (typeof window === 'undefined' || !window.navigator?.modelContext) {\n console.warn(\n `[useWebMCP] window.navigator.modelContext is not available. Tool \"${name}\" will not be registered.`\n );\n return;\n }\n\n const inputJsonSchema = inputSchema ? zodToJsonSchema(inputSchema) : undefined;\n const outputJsonSchema = outputSchema ? zodToJsonSchema(outputSchema) : undefined;\n\n const mcpHandler = async (input: unknown, _extra: unknown): Promise<CallToolResult> => {\n try {\n const result = await execute(input);\n const formattedOutput = formatOutputRef.current(result);\n\n return {\n content: [\n {\n type: 'text',\n text: formattedOutput,\n },\n ],\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n\n return {\n content: [\n {\n type: 'text',\n text: `Error: ${errorMessage}`,\n },\n ],\n isError: true,\n };\n }\n };\n\n const fallbackInputSchema: InputSchema = {\n type: 'object',\n properties: {},\n };\n\n const registration = window.navigator.modelContext.registerTool({\n name,\n description,\n inputSchema: (inputJsonSchema || fallbackInputSchema) as InputSchema,\n ...(outputJsonSchema && { outputSchema: outputJsonSchema as InputSchema }),\n ...(annotations && { annotations }),\n execute: async (args: Record<string, unknown>) => {\n const result = await mcpHandler(args, {});\n return result;\n },\n });\n\n console.log(`[useWebMCP] Registered tool: ${name}`);\n\n // Expose registered tools on window for testing\n if (typeof window !== 'undefined') {\n const tools = window.navigator.modelContext.listTools();\n const w = window as unknown as Window & { mcpTools: string[] };\n w.mcpTools = tools.map((t) => t.name);\n }\n\n return () => {\n if (registration) {\n registration.unregister();\n console.log(`[useWebMCP] Unregistered tool: ${name}`);\n\n // Update window.mcpTools after unregistration\n if (typeof window !== 'undefined' && window.navigator?.modelContext) {\n const tools = window.navigator.modelContext.listTools();\n const w = window as unknown as Window & { mcpTools: string[] };\n w.mcpTools = tools.map((t) => t.name);\n }\n }\n };\n }, [name, description, inputSchema, outputSchema, annotations, execute]);\n\n return {\n state,\n execute,\n reset,\n };\n}\n","import { useRef } from 'react';\nimport type { WebMCPReturn } from './types.js';\nimport { useWebMCP } from './useWebMCP.js';\n\n/**\n * Convenience hook for exposing read-only context data to AI assistants.\n *\n * This is a simplified wrapper around {@link useWebMCP} specifically designed for\n * context tools that expose data without performing actions. The hook automatically\n * configures appropriate annotations (read-only, idempotent) and handles value\n * serialization.\n *\n * @template T - The type of context data to expose\n *\n * @param name - Unique identifier for the context tool (e.g., 'context_current_post')\n * @param description - Human-readable description of the context for AI assistants\n * @param getValue - Function that returns the current context value\n * @returns Tool execution state and control methods\n *\n * @public\n *\n * @example\n * Expose current post context:\n * ```tsx\n * function PostDetailPage() {\n * const { postId } = useParams();\n * const { data: post } = useQuery(['post', postId], () => fetchPost(postId));\n *\n * useWebMCPContext(\n * 'context_current_post',\n * 'Get the currently viewed post ID and metadata',\n * () => ({\n * postId,\n * title: post?.title,\n * author: post?.author,\n * tags: post?.tags,\n * createdAt: post?.createdAt,\n * })\n * );\n *\n * return <PostContent post={post} />;\n * }\n * ```\n *\n * @example\n * Expose user session context:\n * ```tsx\n * function AppRoot() {\n * const { user, isAuthenticated } = useAuth();\n *\n * useWebMCPContext(\n * 'context_user_session',\n * 'Get the current user session information',\n * () => ({\n * isAuthenticated,\n * userId: user?.id,\n * email: user?.email,\n * permissions: user?.permissions,\n * })\n * );\n *\n * return <App />;\n * }\n * ```\n */\nexport function useWebMCPContext<T>(\n name: string,\n description: string,\n getValue: () => T\n): WebMCPReturn<T> {\n const getValueRef = useRef(getValue);\n getValueRef.current = getValue;\n\n return useWebMCP<Record<string, never>, T>({\n name,\n description,\n annotations: {\n title: `Context: ${name}`,\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: false,\n },\n handler: async () => {\n return getValueRef.current();\n },\n formatOutput: (output) => {\n if (typeof output === 'string') {\n return output;\n }\n return JSON.stringify(output, null, 2);\n },\n });\n}\n","import type { Client } from '@modelcontextprotocol/sdk/client/index.js';\nimport type { RequestOptions } from '@modelcontextprotocol/sdk/shared/protocol.js';\nimport type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';\nimport type {\n Tool as McpTool,\n Resource,\n ServerCapabilities,\n} from '@modelcontextprotocol/sdk/types.js';\nimport {\n ResourceListChangedNotificationSchema,\n ToolListChangedNotificationSchema,\n} from '@modelcontextprotocol/sdk/types.js';\nimport {\n createContext,\n type ReactElement,\n type ReactNode,\n useCallback,\n useContext,\n useEffect,\n useRef,\n useState,\n} from 'react';\n\n/**\n * Context value provided by McpClientProvider.\n *\n * @internal\n */\ninterface McpClientContextValue {\n client: Client;\n tools: McpTool[];\n resources: Resource[];\n isConnected: boolean;\n isLoading: boolean;\n error: Error | null;\n capabilities: ServerCapabilities | null;\n reconnect: () => Promise<void>;\n}\n\nconst McpClientContext = createContext<McpClientContextValue | null>(null);\n\n/**\n * Props for the McpClientProvider component.\n *\n * @public\n */\nexport interface McpClientProviderProps {\n /**\n * React children to render within the provider.\n */\n children: ReactNode;\n\n /**\n * MCP Client instance to use for communication.\n */\n client: Client;\n\n /**\n * Transport instance for the client to connect through.\n */\n transport: Transport;\n\n /**\n * Optional request options for the connection.\n */\n opts?: RequestOptions;\n}\n\n/**\n * Provider component that manages an MCP client connection and exposes\n * tools, resources, and connection state to child components.\n *\n * This provider handles:\n * - Establishing and maintaining the MCP client connection\n * - Fetching available tools and resources from the server\n * - Listening for server notifications about tool/resource changes\n * - Managing connection state and errors\n * - Automatic cleanup on unmount\n *\n * @param props - Component props\n * @returns Provider component wrapping children\n *\n * @public\n *\n * @example\n * Connect to an MCP server via tab transport:\n * ```tsx\n * import { Client } from '@modelcontextprotocol/sdk/client/index.js';\n * import { TabClientTransport } from '@mcp-b/transports';\n * import { McpClientProvider } from '@mcp-b/react-webmcp';\n *\n * const client = new Client(\n * { name: 'my-app', version: '1.0.0' },\n * { capabilities: {} }\n * );\n *\n * const transport = new TabClientTransport('mcp', {\n * clientInstanceId: 'my-app-instance',\n * });\n *\n * function App() {\n * return (\n * <McpClientProvider client={client} transport={transport}>\n * <MyAppContent />\n * </McpClientProvider>\n * );\n * }\n * ```\n *\n * @example\n * Access tools from child components:\n * ```tsx\n * function MyAppContent() {\n * const { tools, isConnected, isLoading } = useMcpClient();\n *\n * if (isLoading) {\n * return <div>Connecting to MCP server...</div>;\n * }\n *\n * if (!isConnected) {\n * return <div>Failed to connect to MCP server</div>;\n * }\n *\n * return (\n * <div>\n * <h2>Available Tools:</h2>\n * <ul>\n * {tools.map(tool => (\n * <li key={tool.name}>{tool.description}</li>\n * ))}\n * </ul>\n * </div>\n * );\n * }\n * ```\n */\nexport function McpClientProvider({\n children,\n client,\n transport,\n opts = {},\n}: McpClientProviderProps): ReactElement {\n const [resources, setResources] = useState<Resource[]>([]);\n const [tools, setTools] = useState<McpTool[]>([]);\n const [isLoading, setIsLoading] = useState<boolean>(false);\n const [error, setError] = useState<Error | null>(null);\n const [isConnected, setIsConnected] = useState<boolean>(false);\n const [capabilities, setCapabilities] = useState<ServerCapabilities | null>(null);\n\n const connectionStateRef = useRef<'disconnected' | 'connecting' | 'connected'>('disconnected');\n\n /**\n * Fetches available resources from the MCP server.\n * Only fetches if the server supports the resources capability.\n */\n const fetchResourcesInternal = useCallback(async () => {\n if (!client) return;\n\n const serverCapabilities = client.getServerCapabilities();\n if (!serverCapabilities?.resources) {\n setResources([]);\n return;\n }\n\n try {\n const response = await client.listResources();\n setResources(response.resources);\n } catch (e) {\n console.error('Error fetching resources:', e);\n throw e;\n }\n }, [client]);\n\n /**\n * Fetches available tools from the MCP server.\n * Only fetches if the server supports the tools capability.\n */\n const fetchToolsInternal = useCallback(async () => {\n if (!client) return;\n\n const serverCapabilities = client.getServerCapabilities();\n if (!serverCapabilities?.tools) {\n setTools([]);\n return;\n }\n\n try {\n const response = await client.listTools();\n setTools(response.tools);\n } catch (e) {\n console.error('Error fetching tools:', e);\n throw e;\n }\n }, [client]);\n\n /**\n * Establishes connection to the MCP server.\n * Safe to call multiple times - will no-op if already connected or connecting.\n */\n const reconnect = useCallback(async () => {\n if (!client || !transport) {\n throw new Error('Client or transport not available');\n }\n\n if (connectionStateRef.current !== 'disconnected') {\n return;\n }\n\n connectionStateRef.current = 'connecting';\n setIsLoading(true);\n setError(null);\n\n try {\n await client.connect(transport, opts);\n const caps = client.getServerCapabilities();\n setIsConnected(true);\n setCapabilities(caps || null);\n connectionStateRef.current = 'connected';\n\n await Promise.all([fetchResourcesInternal(), fetchToolsInternal()]);\n } catch (e) {\n const err = e instanceof Error ? e : new Error(String(e));\n connectionStateRef.current = 'disconnected';\n setError(err);\n throw err;\n } finally {\n setIsLoading(false);\n }\n }, [client, transport, opts, fetchResourcesInternal, fetchToolsInternal]);\n\n useEffect(() => {\n if (!isConnected || !client) {\n return;\n }\n\n const serverCapabilities = client.getServerCapabilities();\n\n const handleResourcesChanged = () => {\n fetchResourcesInternal().catch(console.error);\n };\n\n const handleToolsChanged = () => {\n fetchToolsInternal().catch(console.error);\n };\n\n if (serverCapabilities?.resources?.listChanged) {\n client.setNotificationHandler(ResourceListChangedNotificationSchema, handleResourcesChanged);\n }\n\n if (serverCapabilities?.tools?.listChanged) {\n client.setNotificationHandler(ToolListChangedNotificationSchema, handleToolsChanged);\n }\n\n return () => {\n if (serverCapabilities?.resources?.listChanged) {\n client.removeNotificationHandler('notifications/resources/list_changed');\n }\n\n if (serverCapabilities?.tools?.listChanged) {\n client.removeNotificationHandler('notifications/tools/list_changed');\n }\n };\n }, [client, isConnected, fetchResourcesInternal, fetchToolsInternal]);\n\n useEffect(() => {\n // Initial connection - reconnect() has its own guard to prevent concurrent connections\n reconnect().catch((err) => {\n console.error('Failed to connect MCP client:', err);\n });\n\n // Cleanup: mark as disconnected so next mount will reconnect\n return () => {\n connectionStateRef.current = 'disconnected';\n setIsConnected(false);\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [client, transport]);\n\n return (\n <McpClientContext.Provider\n value={{\n client,\n tools,\n resources,\n isConnected,\n isLoading,\n error,\n capabilities,\n reconnect,\n }}\n >\n {children}\n </McpClientContext.Provider>\n );\n}\n\n/**\n * Hook to access the MCP client context.\n * Must be used within an {@link McpClientProvider}.\n *\n * @returns The MCP client context including client instance, tools, resources, and connection state\n * @throws Error if used outside of McpClientProvider\n *\n * @public\n *\n * @example\n * ```tsx\n * function ToolsList() {\n * const { tools, isConnected, error, reconnect } = useMcpClient();\n *\n * if (error) {\n * return (\n * <div>\n * Error: {error.message}\n * <button onClick={reconnect}>Retry</button>\n * </div>\n * );\n * }\n *\n * if (!isConnected) {\n * return <div>Not connected</div>;\n * }\n *\n * return (\n * <ul>\n * {tools.map(tool => (\n * <li key={tool.name}>{tool.description}</li>\n * ))}\n * </ul>\n * );\n * }\n * ```\n */\nexport function useMcpClient() {\n const context = useContext(McpClientContext);\n if (!context) {\n throw new Error('useMcpClient must be used within an McpClientProvider');\n }\n return context;\n}\n"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,74 @@
1
+ {
2
+ "name": "@mcp-b/react-webmcp",
3
+ "version": "0.1.1",
4
+ "description": "React hooks for Model Context Protocol - register tools via navigator.modelContext and consume tools from MCP servers",
5
+ "keywords": [
6
+ "mcp",
7
+ "model-context-protocol",
8
+ "react",
9
+ "hooks",
10
+ "react-hooks",
11
+ "browser",
12
+ "ai",
13
+ "assistant",
14
+ "tools",
15
+ "zod"
16
+ ],
17
+ "homepage": "https://github.com/WebMCP-org/WebMCP#readme",
18
+ "bugs": {
19
+ "url": "https://github.com/WebMCP-org/WebMCP/issues"
20
+ },
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "git+https://github.com/WebMCP-org/WebMCP.git",
24
+ "directory": "packages/react-webmcp"
25
+ },
26
+ "license": "MIT",
27
+ "author": "WebMCP Team",
28
+ "type": "module",
29
+ "exports": {
30
+ ".": {
31
+ "import": "./dist/index.js",
32
+ "types": "./dist/index.d.ts"
33
+ }
34
+ },
35
+ "main": "./dist/index.js",
36
+ "files": [
37
+ "dist"
38
+ ],
39
+ "dependencies": {
40
+ "@modelcontextprotocol/sdk": "1.15.0",
41
+ "@mcp-b/global": "1.0.14",
42
+ "@mcp-b/webmcp-ts-sdk": "1.0.1",
43
+ "@mcp-b/transports": "1.0.3"
44
+ },
45
+ "devDependencies": {
46
+ "@types/node": "^22.15.21",
47
+ "@types/react": "^19.1.2",
48
+ "tsdown": "^0.15.10",
49
+ "typescript": "^5.8.3",
50
+ "zod": "^3.25.76"
51
+ },
52
+ "peerDependencies": {
53
+ "react": "^19.1.0",
54
+ "zod": "^3.25.76"
55
+ },
56
+ "publishConfig": {
57
+ "access": "public",
58
+ "registry": "https://registry.npmjs.org/"
59
+ },
60
+ "scripts": {
61
+ "build": "tsdown",
62
+ "build:prod": "NODE_ENV=prod tsdown",
63
+ "check": "biome check --write .",
64
+ "clean": "rm -rf dist .turbo",
65
+ "format": "biome format --write .",
66
+ "lint": "biome lint --write .",
67
+ "publish:dry": "pnpm publish --access public --dry-run",
68
+ "publish:npm": "pnpm publish --access public",
69
+ "typecheck": "tsc --noEmit",
70
+ "version:major": "pnpm version major --no-git-tag-version",
71
+ "version:minor": "pnpm version minor --no-git-tag-version",
72
+ "version:patch": "pnpm version patch --no-git-tag-version"
73
+ }
74
+ }