@mcp-b/react-webmcp 3.0.0 → 4.0.0-beta.20260702173007

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/README.md CHANGED
@@ -8,7 +8,7 @@
8
8
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.0+-blue?style=flat-square)](https://www.typescriptlang.org/)
9
9
  [![React](https://img.shields.io/badge/React-18+-61DAFB?style=flat-square&logo=react)](https://reactjs.org/)
10
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)**
11
+ **[Reference](https://docs.mcp-b.ai/packages/react-webmcp/reference)** | **[React Tutorial](https://docs.mcp-b.ai/tutorials/first-react-tool)** | **[Framework Guides](https://docs.mcp-b.ai/how-to/frameworks)**
12
12
 
13
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
14
 
@@ -38,7 +38,11 @@ pnpm add @mcp-b/transports @modelcontextprotocol/sdk
38
38
 
39
39
  **Prerequisites:** Provider hooks require the `document.modelContext` API. Install `@mcp-b/global` or use a browser that implements the Web Model Context API.
40
40
 
41
- Provider hooks register tools with `document.modelContext.registerTool(tool, { signal })` and abort the controller on unmount. The hooks retain a `navigator.modelContext` fallback for older preview runtimes, but `document.modelContext` is the canonical v3 surface. On Chrome Beta 147 native (which ignores the second arg) cleanup cannot remove the tool. Install `@mcp-b/global` for spec-aligned behavior.
41
+ Provider hooks register tools with `document.modelContext.registerTool(tool, {
42
+ signal })` and abort the controller on unmount. The hooks retain a
43
+ `navigator.modelContext` fallback for older preview runtimes, but
44
+ `document.modelContext` is the canonical v3 surface. Install `@mcp-b/global`
45
+ when you need a portable runtime with spec-aligned cleanup behavior.
42
46
 
43
47
  ## Quick Start - Provider (Registering Tools)
44
48
 
@@ -138,9 +142,9 @@ For full API reference, output schemas, memoization patterns, migration guide, b
138
142
 
139
143
  ## Related Packages
140
144
 
141
- - [`@mcp-b/global`](https://docs.mcp-b.ai/packages/global) - W3C Web Model Context API polyfill (required for provider hooks)
142
- - [`@mcp-b/transports`](https://docs.mcp-b.ai/packages/transports) - Browser-specific MCP transports
143
- - [`@mcp-b/chrome-devtools-mcp`](https://docs.mcp-b.ai/packages/chrome-devtools-mcp) - Connect desktop AI agents to browser tools
145
+ - [`@mcp-b/global`](https://docs.mcp-b.ai/packages/global/reference) - Full MCP-B browser runtime (required for provider hooks)
146
+ - [`@mcp-b/transports`](https://docs.mcp-b.ai/packages/transports/reference) - Browser-specific MCP transports
147
+ - [`@mcp-b/chrome-devtools-mcp`](https://docs.mcp-b.ai/packages/chrome-devtools-mcp/reference) - Connect desktop AI agents to browser tools
144
148
  - [`usewebmcp`](../usewebmcp) - React hooks for strict core WebMCP API only
145
149
 
146
150
  ## Resources
package/dist/index.d.ts CHANGED
@@ -1,11 +1,12 @@
1
+ import { ToolInputSchema, ToolInputSchema as ToolInputSchema$1 } from "@mcp-b/webmcp-polyfill/schema";
1
2
  import { DependencyList, ReactElement, ReactNode } from "react";
2
3
  import { BrowserMcpServer as ModelContextProtocol, Client, PromptDescriptor, PromptMessage, RequestOptions, Resource, ResourceContents, ResourceDescriptor, SamplingRequestParams, SamplingResult, ServerCapabilities, Tool, Transport } from "@mcp-b/webmcp-ts-sdk";
3
- import { ToolInputSchema, ToolInputSchema as ToolInputSchema$1 } from "@mcp-b/webmcp-polyfill";
4
4
  import { CallToolResult, ElicitationParams, ElicitationResult, InferArgsFromInputSchema, InferJsonSchema, InputSchema, JsonSchemaForInference, ToolAnnotations, ToolDescriptor } from "@mcp-b/webmcp-types";
5
5
  import { z } from "zod";
6
6
 
7
7
  //#region src/zod-utils.d.ts
8
8
  type ZodSchemaObject = Record<string, z.ZodTypeAny>;
9
+ type ZodSchema = ZodSchemaObject | z.ZodTypeAny;
9
10
  //#endregion
10
11
  //#region src/types.d.ts
11
12
  /**
@@ -17,18 +18,9 @@ type ReactWebMCPInputSchema = ToolInputSchema$1 | ZodSchemaObject;
17
18
  /**
18
19
  * Union of all output schema types supported by react-webmcp:
19
20
  * - `JsonSchemaForInference` (MCP output schema)
20
- * - `ZodSchemaObject` (Zod v3 `Record<string, z.ZodTypeAny>`, converted at runtime)
21
+ * - `ZodSchema` (converted to the inferable JSON Schema subset at runtime)
21
22
  */
22
- type ReactWebMCPOutputSchema = JsonSchemaForInference | ZodSchemaObject;
23
- interface ReactWebMCPStandardOutputSchema<TInput = unknown, TOutput = unknown> {
24
- readonly '~standard': {
25
- readonly types?: {
26
- readonly input: TInput;
27
- readonly output: TOutput;
28
- };
29
- };
30
- }
31
- type ReactWebMCPSupportedOutputSchema = ReactWebMCPOutputSchema | ReactWebMCPStandardOutputSchema;
23
+ type ReactWebMCPOutputSchema = JsonSchemaForInference | ZodSchema;
32
24
  /**
33
25
  * Infers handler input type from a Standard Schema, Zod v3 schema, or JSON Schema.
34
26
  *
@@ -58,13 +50,7 @@ type InferToolInput<T> = T extends Record<string, z.ZodTypeAny> ? z.infer<z.ZodO
58
50
  * @template TFallback - Fallback type when no schema is provided
59
51
  * @internal
60
52
  */
61
- type InferOutput<TOutputSchema extends ReactWebMCPSupportedOutputSchema | undefined = undefined, TFallback = unknown> = TOutputSchema extends undefined ? TFallback : TOutputSchema extends {
62
- readonly '~standard': {
63
- readonly types?: infer Types;
64
- };
65
- } ? NonNullable<Types> extends {
66
- readonly output: infer O;
67
- } ? O : TFallback : TOutputSchema extends Record<string, z.ZodTypeAny> ? z.infer<z.ZodObject<TOutputSchema>> : TOutputSchema extends JsonSchemaForInference ? InferJsonSchema<TOutputSchema> : TFallback;
53
+ type InferOutput<TOutputSchema extends ReactWebMCPOutputSchema | undefined = undefined, TFallback = unknown> = TOutputSchema extends undefined ? TFallback : TOutputSchema extends z.ZodTypeAny ? z.infer<TOutputSchema> : TOutputSchema extends Record<string, z.ZodTypeAny> ? z.infer<z.ZodObject<TOutputSchema>> : TOutputSchema extends JsonSchemaForInference ? InferJsonSchema<TOutputSchema> : TFallback;
68
54
  /**
69
55
  * Represents the current execution state of a tool, including loading status,
70
56
  * results, errors, and execution history.
@@ -98,10 +84,9 @@ interface ToolExecutionState<TOutput = unknown> {
98
84
  * Configuration options for the `useWebMCP` hook.
99
85
  *
100
86
  * Defines a tool's metadata, schema, handler, and lifecycle callbacks.
101
- * Uses JSON Schema for type inference via `as const`.
102
87
  *
103
- * @template TInputSchema - JSON Schema defining input parameters
104
- * @template TOutputSchema - Output schema defining output structure (object schemas enable structuredContent)
88
+ * @template TInputSchema - Schema defining input parameters
89
+ * @template TOutputSchema - Output schema defining output structure
105
90
  *
106
91
  * @public
107
92
  *
@@ -146,7 +131,7 @@ interface ToolExecutionState<TOutput = unknown> {
146
131
  * });
147
132
  * ```
148
133
  */
149
- interface WebMCPConfig<TInputSchema extends ReactWebMCPInputSchema = InputSchema, TOutputSchema extends ReactWebMCPSupportedOutputSchema | undefined = undefined> {
134
+ interface WebMCPConfig<TInputSchema extends ReactWebMCPInputSchema = InputSchema, TOutputSchema extends ReactWebMCPOutputSchema | undefined = undefined> {
150
135
  /**
151
136
  * Unique identifier for the tool (e.g., 'posts_like', 'graph_navigate').
152
137
  * Must follow naming conventions: lowercase with underscores.
@@ -158,7 +143,7 @@ interface WebMCPConfig<TInputSchema extends ReactWebMCPInputSchema = InputSchema
158
143
  */
159
144
  description: string;
160
145
  /**
161
- * JSON Schema defining the input parameters for the tool.
146
+ * Schema defining the input parameters for the tool.
162
147
  * Use `as const` to enable type inference for the handler's input.
163
148
  *
164
149
  * @example
@@ -176,7 +161,7 @@ interface WebMCPConfig<TInputSchema extends ReactWebMCPInputSchema = InputSchema
176
161
  inputSchema?: TInputSchema;
177
162
  /**
178
163
  * **Recommended:** Output schema defining the expected output structure.
179
- * Accepts either an inferable JSON Schema or a Zod schema map.
164
+ * Accepts an inferable JSON Schema or a Zod schema that converts to one.
180
165
  *
181
166
  * When provided, this enables three key features:
182
167
  * 1. **Type Safety**: The handler's return type is inferred from this schema
@@ -249,7 +234,7 @@ interface WebMCPConfig<TInputSchema extends ReactWebMCPInputSchema = InputSchema
249
234
  * @template TOutputSchema - Output schema defining output structure
250
235
  * @public
251
236
  */
252
- interface WebMCPReturn<TOutputSchema extends ReactWebMCPSupportedOutputSchema | undefined = undefined, TInputSchema extends ReactWebMCPInputSchema = InputSchema> {
237
+ interface WebMCPReturn<TOutputSchema extends ReactWebMCPOutputSchema | undefined = undefined, TInputSchema extends ReactWebMCPInputSchema = InputSchema> {
253
238
  /**
254
239
  * Current execution state including loading status, results, and errors.
255
240
  * See {@link ToolExecutionState} for details.
@@ -459,7 +444,7 @@ interface WebMCPResourceReturn {
459
444
  * ```
460
445
  *
461
446
  * @template TInputSchema - JSON Schema defining input parameter types (use `as const` for inference)
462
- * @template TOutputSchema - JSON Schema defining output structure (object schemas enable structuredContent)
447
+ * @template TOutputSchema - JSON Schema defining output structure
463
448
  *
464
449
  * @param config - Configuration object for the tool
465
450
  * @param deps - Optional dependency array that triggers tool re-registration when values change.
@@ -1004,5 +989,5 @@ declare function McpClientProvider({
1004
989
  */
1005
990
  declare function useMcpClient(): McpClientContextValue;
1006
991
  //#endregion
1007
- export { type CallToolResult, type ElicitationState as ElicitationHandlerState, type ElicitationState, type InferOutput, type InferToolInput, McpClientProvider, type McpClientProviderProps, type ModelContextProtocol, type PromptDescriptor, type PromptMessage, type ReactWebMCPInputSchema, type ResourceContents, type ResourceDescriptor, type SamplingState as SamplingHandlerState, type SamplingState, type ToolAnnotations, type ToolDescriptor, type ToolExecutionState, type ToolInputSchema, type UseElicitationConfig, type UseElicitationConfig as UseElicitationHandlerConfig, type UseElicitationReturn as UseElicitationHandlerReturn, type UseElicitationReturn, type UseSamplingConfig, type UseSamplingConfig as UseSamplingHandlerConfig, type UseSamplingReturn as UseSamplingHandlerReturn, type UseSamplingReturn, type WebMCPConfig, type WebMCPPromptConfig, type WebMCPPromptReturn, type WebMCPResourceConfig, type WebMCPResourceReturn, type WebMCPReturn, type ZodSchemaObject, useElicitation, useElicitation as useElicitationHandler, useMcpClient, useSampling, useSampling as useSamplingHandler, useWebMCP, useWebMCPContext, useWebMCPPrompt, useWebMCPResource };
992
+ export { type CallToolResult, type ElicitationState as ElicitationHandlerState, type ElicitationState, type InferOutput, type InferToolInput, McpClientProvider, type McpClientProviderProps, type ModelContextProtocol, type PromptDescriptor, type PromptMessage, type ReactWebMCPInputSchema, type ResourceContents, type ResourceDescriptor, type SamplingState as SamplingHandlerState, type SamplingState, type ToolAnnotations, type ToolDescriptor, type ToolExecutionState, type ToolInputSchema, type UseElicitationConfig, type UseElicitationConfig as UseElicitationHandlerConfig, type UseElicitationReturn as UseElicitationHandlerReturn, type UseElicitationReturn, type UseSamplingConfig, type UseSamplingConfig as UseSamplingHandlerConfig, type UseSamplingReturn as UseSamplingHandlerReturn, type UseSamplingReturn, type WebMCPConfig, type WebMCPPromptConfig, type WebMCPPromptReturn, type WebMCPResourceConfig, type WebMCPResourceReturn, type WebMCPReturn, type ZodSchema, type ZodSchemaObject, useElicitation, useElicitation as useElicitationHandler, useMcpClient, useSampling, useSampling as useSamplingHandler, useWebMCP, useWebMCPContext, useWebMCPPrompt, useWebMCPResource };
1008
993
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/zod-utils.ts","../src/types.ts","../src/useWebMCP.ts","../src/useWebMCPContext.ts","../src/useWebMCPPrompt.ts","../src/useWebMCPResource.ts","../src/useElicitationHandler.ts","../src/useSamplingHandler.ts","../src/client/McpClientProvider.tsx"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/zod-utils.ts","../src/types.ts","../src/useWebMCP.ts","../src/useWebMCPContext.ts","../src/useWebMCPPrompt.ts","../src/useWebMCPResource.ts","../src/useElicitationHandler.ts","../src/useSamplingHandler.ts","../src/client/McpClientProvider.tsx"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- "use client";import{createContext as e,useCallback as t,useContext as n,useEffect as r,useLayoutEffect as i,useMemo as a,useRef as o,useState as s}from"react";import{zodToJsonSchema as c}from"zod-to-json-schema";import{ResourceListChangedNotificationSchema as l,ToolListChangedNotificationSchema as u}from"@mcp-b/webmcp-ts-sdk";import{jsx as d}from"react/jsx-runtime";function f(){if(!(typeof window>`u`))return window.document?.modelContext??window.navigator?.modelContext}function p(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function m(e){return p(e)&&`_def`in e}function h(e){if(!p(e))return!1;let t=e._def;return p(t)&&`typeName`in t}function g(e){if(!p(e))return!1;let t=Object.values(e);return t.length===0?!1:t.some(e=>m(e))}function _(e){if(!h(e))return!p(e)||!p(e._def)?!1:e._def.type===`optional`||e._def.type===`default`;let{typeName:t}=e._def;return t===`ZodOptional`||t===`ZodDefault`}function v(e){return p(e)&&typeof e.toJSONSchema==`function`}function y(e){let t={...e};if(delete t.$schema,t.properties){let e={};for(let[n,r]of Object.entries(t.properties))e[n]=y(r);t.properties=e}return t}function b(e){let t={},n=[];for(let[r,i]of Object.entries(e)){if(!m(i))continue;let e=i,a=c(e,{strictUnions:!0,$refStrategy:`none`});p(a)&&!(`type`in a)&&v(e)&&(a=e.toJSONSchema()),t[r]=y(a),_(e)||n.push(r)}let r={type:`object`,properties:t};return n.length>0&&(r.required=n),r}function x(e){return typeof e==`string`?e:JSON.stringify(e,null,2)}const S=new Map,C={type:`object`,properties:{}},w=[`draft-2020-12`,`draft-07`];function T(e){return e?g(e)?!0:`type`in e&&e.type===`object`:!1}function E(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function D(e){return!(!E(e)||`type`in e&&e.type!==void 0&&typeof e.type!=`string`||`properties`in e&&e.properties!==void 0&&!E(e.properties)||`required`in e&&e.required!==void 0&&(!Array.isArray(e.required)||e.required.some(e=>typeof e!=`string`)))}function O(e){if(!E(e)||!(`type`in e))return!1;let t=e.type;return typeof t==`string`?[`array`,`boolean`,`integer`,`null`,`number`,`object`,`string`].includes(t)?t===`array`?`items`in e&&O(e.items):t===`object`&&`properties`in e&&e.properties!==void 0?E(e.properties)&&Object.values(e.properties).every(O):!0:!1:Array.isArray(t)&&t.length>0&&t.every(e=>[`array`,`boolean`,`integer`,`null`,`number`,`object`,`string`].includes(e))}function k(e){return e===null||typeof e==`string`||typeof e==`number`||typeof e==`boolean`?!0:Array.isArray(e)?e.every(k):typeof e==`object`?Object.values(e).every(k):!1}function A(e){return typeof e==`object`&&!!e&&!Array.isArray(e)&&k(e)}function j(e){if(!e||typeof e!=`object`||Array.isArray(e))return null;try{let t=JSON.parse(JSON.stringify(e));return A(t)?t:null}catch{return null}}const M=typeof window<`u`?i:r;function N(e){return!!e&&(typeof e==`object`||typeof e==`function`)&&typeof e.then==`function`}function P(e,t){let n=new AbortController,r=e.registerTool.call(e,t,{signal:n.signal});return N(r)&&r.then(void 0,e=>{console.warn(`[ReactWebMCP:useWebMCP] registerTool("${t.name}") rejected:`,e)}),n}function F(e){if(!e)return;if(g(e))return b(e);if(!E(e)||!(`~standard`in e))return D(e)?e:C;let t=e[`~standard`];if(!E(t))return C;let n=t.jsonSchema;if(!E(n)||typeof n.input!=`function`)return C;for(let e of w)try{let t=n.input({target:e});if(D(t))return t}catch{}return C}function I(e){if(!e)return;let t=g(e)?b(e):e;return O(t)?t:void 0}function L(e,n){let{name:i,description:a,inputSchema:c,outputSchema:l,annotations:u,handler:d,formatOutput:p=x,onSuccess:m,onError:h}=e,[g,_]=s({isExecuting:!1,lastResult:null,error:null,executionCount:0}),v=o(d),y=o(m),b=o(h),C=o(p),w=o(!0);M(()=>{v.current=d,y.current=m,b.current=h,C.current=p},[d,m,h,p]),r(()=>(w.current=!0,()=>{w.current=!1}),[]);let E=t(async e=>{_(e=>({...e,isExecuting:!0,error:null}));try{let t=await v.current(e);return w.current&&_(e=>({isExecuting:!1,lastResult:t,error:null,executionCount:e.executionCount+1})),y.current&&y.current(t,e),t}catch(t){let n=t instanceof Error?t:Error(String(t));throw w.current&&_(e=>({...e,isExecuting:!1,error:n})),b.current&&b.current(n,e),n}},[]),D=o(E);r(()=>{D.current=E},[E]);let O=t(e=>D.current(e),[]),k=t(()=>{_({isExecuting:!1,lastResult:null,error:null,executionCount:0})},[]);return r(()=>{let e=f();if(!e){console.warn(`[ReactWebMCP:useWebMCP]`,`Tool "${i}" skipped: modelContext is not available`);return}let t=async e=>{try{let t=await Reflect.apply(D.current,void 0,[e]),n={content:[{type:`text`,text:C.current(t)}]};if(T(l)){let e=j(t);if(!e)throw Error(`Tool "${i}" outputSchema requires the handler to return a JSON object result`);n.structuredContent=e}return n}catch(e){return{content:[{type:`text`,text:`Error: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}},n=F(c),r=I(l),o=Symbol(i),s=P(e,{name:i,description:a,...n&&{inputSchema:n},...r&&{outputSchema:r},...u&&{annotations:u},execute:t});return S.set(i,o),()=>{S.get(i)===o&&(S.delete(i),s.abort())}},[i,a,c,l,u,...n??[]]),{state:g,execute:O,reset:k}}function R(e,t,n){let r=o(n);return r.current=n,L({name:e,description:t,annotations:a(()=>({title:`Context: ${e}`,readOnlyHint:!0,idempotentHint:!0,destructiveHint:!1,openWorldHint:!1}),[e]),handler:async e=>r.current(),formatOutput:e=>typeof e==`string`?e:JSON.stringify(e,null,2)})}function z(e){let{name:t,description:n,argsSchema:i,get:a}=e,[c,l]=s(!1),u=o(a);return r(()=>{u.current=a},[a]),r(()=>{let e=f();if(!e){console.warn(`[ReactWebMCP] window.document.modelContext is not available. Prompt "${t}" will not be registered.`);return}let r=async e=>u.current(e),a=i?g(i)?b(i):i:void 0,o;try{o=e.registerPrompt({name:t,...n!==void 0&&{description:n},...a&&{argsSchema:a},get:r})}catch(e){throw l(!1),e}if(!o){console.warn(`[ReactWebMCP] Prompt "${t}" did not return a registration handle.`),l(!1);return}return l(!0),()=>{o.unregister(),l(!1)}},[t,n,i]),{isRegistered:c}}function B(e){let{uri:t,name:n,description:i,mimeType:a,read:c}=e,[l,u]=s(!1),d=o(c);return r(()=>{d.current=c},[c]),r(()=>{let e=f();if(!e){console.warn(`[ReactWebMCP] window.document.modelContext is not available. Resource "${t}" will not be registered.`);return}let r=async(e,t)=>d.current(e,t),o;try{o=e.registerResource({uri:t,name:n,...i!==void 0&&{description:i},...a!==void 0&&{mimeType:a},read:r})}catch(e){throw u(!1),e}if(!o){console.warn(`[ReactWebMCP] Resource "${t}" did not return a registration handle.`),u(!1);return}return u(!0),()=>{o.unregister(),u(!1)}},[t,n,i,a]),{isRegistered:l}}function V(e={}){let{onSuccess:n,onError:r}=e,[i,a]=s({isLoading:!1,result:null,error:null,requestCount:0}),o=t(()=>{a({isLoading:!1,result:null,error:null,requestCount:0})},[]);return{state:i,elicitInput:t(async e=>{let t=f();if(!t)throw Error(`document.modelContext is not available`);a(e=>({...e,isLoading:!0,error:null}));try{let r=await t.elicitInput(e);return a(e=>({isLoading:!1,result:r,error:null,requestCount:e.requestCount+1})),n?.(r),r}catch(e){let t=e instanceof Error?e:Error(String(e));throw a(e=>({...e,isLoading:!1,error:t})),r?.(t),t}},[n,r]),reset:o}}function H(e={}){let{onSuccess:n,onError:r}=e,[i,a]=s({isLoading:!1,result:null,error:null,requestCount:0}),o=t(()=>{a({isLoading:!1,result:null,error:null,requestCount:0})},[]);return{state:i,createMessage:t(async e=>{let t=f();if(!t)throw Error(`document.modelContext is not available`);a(e=>({...e,isLoading:!0,error:null}));try{let r=await t.createMessage(e);return a(e=>({isLoading:!1,result:r,error:null,requestCount:e.requestCount+1})),n?.(r),r}catch(e){let t=e instanceof Error?e:Error(String(e));throw a(e=>({...e,isLoading:!1,error:t})),r?.(t),t}},[n,r]),reset:o}}const U=e(null),W={};function G(e,t){let n=globalThis.console;if(!n)return;let r=n.debug??n.log;typeof r==`function`&&r.call(n,`[ReactWebMCP:McpClientProvider:ToolFlow]`,e,t)}function K(){if(typeof window>`u`)return!1;try{return window.localStorage.getItem(`WEBMCP_TRACE_TOOL_FLOW`)===`1`}catch{return!1}}function q({children:e,client:n,transport:i,opts:a}){let[c,f]=s([]),[p,m]=s([]),[h,g]=s(!1),[_,v]=s(null),[y,b]=s(!1),[x,S]=s(null),C=a??W,w=o(`disconnected`),T=o(0),E=t((e,t={})=>{let n=`[${++T.current}] ${e}`;K()&&G(n,t)},[]),D=t(async()=>{if(n){if(!n.getServerCapabilities()?.resources){f([]);return}try{f((await n.listResources()).resources)}catch(e){throw console.error(`[ReactWebMCP:McpClientProvider]`,`Error fetching resources:`,e),e}}},[n]),O=t(async()=>{if(!n)return;let e=n.getServerCapabilities();if(!e?.tools){E(`listTools:capability_missing`,{}),m([]);return}let t=Date.now();E(`listTools:start`,{hasToolsCapability:!!e.tools});try{let e=await n.listTools();m(e.tools),E(`listTools:success`,{durationMs:Date.now()-t,toolCount:e.tools.length})}catch(e){throw E(`listTools:error`,{durationMs:Date.now()-t,errorMessage:e instanceof Error?e.message:String(e)}),console.error(`[ReactWebMCP:McpClientProvider]`,`Error fetching tools:`,e),e}},[n,E]),k=t(async()=>{if(!n||!i)throw Error(`Client or transport not available`);if(w.current===`disconnected`){w.current=`connecting`,g(!0),v(null);try{await n.connect(i,C);let e=n.getServerCapabilities();b(!0),S(e||null),w.current=`connected`,E(`reconnect:connected`,{hasToolsListChanged:!!e?.tools?.listChanged}),await Promise.all([D(),O()])}catch(e){let t=e instanceof Error?e:Error(String(e));throw w.current=`disconnected`,v(t),t}finally{g(!1)}}},[n,i,C,D,O,E]);return r(()=>{if(!y||!n)return;let e=n.getServerCapabilities();return e?.resources?.listChanged&&n.setNotificationHandler(l,()=>{D().catch(e=>{console.error(`[ReactWebMCP:McpClientProvider]`,`Failed to refresh resources after list_changed:`,e)})}),e?.tools?.listChanged&&n.setNotificationHandler(u,()=>{E(`notification:tools/list_changed`,{}),O().catch(e=>{console.error(`[ReactWebMCP:McpClientProvider]`,`Failed to refresh tools after list_changed:`,e)})}),Promise.all([D(),O()]).catch(e=>{console.error(`[ReactWebMCP:McpClientProvider]`,`Failed to refresh tools/resources after handler registration:`,e)}),()=>{e?.resources?.listChanged&&n.removeNotificationHandler(`notifications/resources/list_changed`),e?.tools?.listChanged&&n.removeNotificationHandler(`notifications/tools/list_changed`)}},[n,y,D,O,E]),r(()=>(k().catch(e=>{console.error(`[ReactWebMCP:McpClientProvider]`,`Failed to connect MCP client:`,e)}),()=>{w.current=`disconnected`,b(!1)}),[n,i,k]),d(U.Provider,{value:{client:n,tools:p,resources:c,isConnected:y,isLoading:h,error:_,capabilities:x,reconnect:k},children:e})}function J(){let e=n(U);if(!e)throw Error(`useMcpClient must be used within an McpClientProvider`);return e}export{q as McpClientProvider,V as useElicitation,V as useElicitationHandler,J as useMcpClient,H as useSampling,H as useSamplingHandler,L as useWebMCP,R as useWebMCPContext,z as useWebMCPPrompt,B as useWebMCPResource};
1
+ "use client";import{isPlainObject as e,normalizeInputSchema as t,toJsonValue as n}from"@mcp-b/webmcp-polyfill/schema";import{createContext as r,useCallback as i,useContext as a,useEffect as o,useLayoutEffect as s,useMemo as c,useRef as l,useState as u}from"react";import{normalizeObjectSchema as d}from"@modelcontextprotocol/sdk/server/zod-compat.js";import{toJsonSchemaCompat as f}from"@modelcontextprotocol/sdk/server/zod-json-schema-compat.js";import{ResourceListChangedNotificationSchema as p,ToolListChangedNotificationSchema as m}from"@mcp-b/webmcp-ts-sdk";import{jsx as h}from"react/jsx-runtime";function g(){if(typeof window>`u`)return;let e=window.document.modelContext,t=window.navigator.modelContext;return e??t}function _(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function v(e){return _(e)&&(`_def`in e||`_zod`in e)}function y(e){return!_(e)||v(e)?!1:d(e)!==void 0}function b(e){let t=d(e)??(v(e)?e:void 0);if(!t)throw Error(`Expected a Zod schema or Zod schema object`);return f(t,{strictUnions:!0,pipeStrategy:`input`})}function x(e){return typeof e==`string`?e:JSON.stringify(e,null,2)}const S=new Map,C=[`array`,`boolean`,`integer`,`null`,`number`,`object`,`string`],w=[`$ref`,`allOf`,`anyOf`,`oneOf`,`not`];function T(e){return typeof e==`string`&&C.includes(e)}function E(e){throw Error(`Unsupported outputSchema: ${e}`)}function D(t,n=`$`){e(t)||E(`${n} must be a JSON Schema object`);for(let e of w)e in t&&E(`${n}.${e} is outside the inferable JSON Schema subset`);let r=typeof t.type==`string`?[t.type]:Array.isArray(t.type)?t.type:void 0;(!r?.length||!r.every(e=>T(e)))&&E(`${n} must declare an inferable JSON Schema type`);let i=t.required;if(i!==void 0&&(!Array.isArray(i)||i.some(e=>typeof e!=`string`))&&E(`${n}.required must be an array of strings`),r.includes(`array`)&&(e(t.items)||E(`${n}.items must be an inferable schema for array outputs`),D(t.items,`${n}.items`)),r.includes(`object`)){if(t.properties!==void 0&&!e(t.properties)&&E(`${n}.properties must be an object`),e(t.properties))for(let[e,r]of Object.entries(t.properties))D(r,`${n}.properties.${e}`);t.additionalProperties!==void 0&&typeof t.additionalProperties!=`boolean`&&D(t.additionalProperties,`${n}.additionalProperties`)}}const O=typeof window<`u`?s:o;function k(e,r){let{name:a,description:s,inputSchema:c,outputSchema:d,annotations:f,handler:p,formatOutput:m=x,onSuccess:h,onError:_}=e,[C,w]=u({isExecuting:!1,lastResult:null,error:null,executionCount:0}),T=l(p),E=l(h),k=l(_),A=l(m),j=l(!0);O(()=>{T.current=p,E.current=h,k.current=_,A.current=m},[p,h,_,m]),o(()=>(j.current=!0,()=>{j.current=!1}),[]);let M=i(async e=>{w(e=>({...e,isExecuting:!0,error:null}));try{let t=await T.current(e);return j.current&&w(e=>({isExecuting:!1,lastResult:t,error:null,executionCount:e.executionCount+1})),E.current&&E.current(t,e),t}catch(t){let n=t instanceof Error?t:Error(String(t));throw j.current&&w(e=>({...e,isExecuting:!1,error:n})),k.current&&k.current(n,e),n}},[]),N=l(M);o(()=>{N.current=M},[M]);let P=i(e=>N.current(e),[]),F=i(()=>{w({isExecuting:!1,lastResult:null,error:null,executionCount:0})},[]);return o(()=>{let e=g();if(!e){console.warn(`[ReactWebMCP:useWebMCP]`,`Tool "${a}" skipped: modelContext is not available`);return}let r=y(c)?b(c):t(c).inputSchema,i;if(d){let e=y(d)||v(d)?b(d):d;D(e),i=e}let o=async e=>{try{let t=await Reflect.apply(N.current,void 0,[e]),r={content:[{type:`text`,text:A.current(t)}]};if(i){let e=n(t);if(e===void 0)throw Error(`Tool "${a}" outputSchema requires the handler to return a JSON-serializable result`);r.structuredContent=e}return r}catch(e){return{content:[{type:`text`,text:`Error: ${e instanceof Error?e.message:String(e)}`}],isError:!0}}},l=Symbol(a),u={name:a,description:s,inputSchema:r,...i&&{outputSchema:i},...f&&{annotations:f},execute:o},p=new AbortController,m=!1,h=!1;try{let t=e.registerTool(u,{signal:p.signal});Promise.resolve(t).then(()=>{!h&&!p.signal.aborted&&(m=!0,S.set(a,l))},e=>{p.signal.aborted||(p.abort(),console.warn(`[ReactWebMCP:useWebMCP] registerTool("${a}") rejected:`,e))})}catch(e){p.abort(),console.warn(`[ReactWebMCP:useWebMCP] registerTool("${a}") rejected:`,e);return}return()=>{if(h=!0,m&&S.get(a)===l){S.delete(a),p.abort();return}m||p.abort()}},[a,s,...r??[]]),{state:C,execute:P,reset:F}}function A(e,t,n){let r=l(n);return r.current=n,k({name:e,description:t,annotations:c(()=>({title:`Context: ${e}`,readOnlyHint:!0,idempotentHint:!0,destructiveHint:!1,openWorldHint:!1}),[e]),handler:async e=>r.current(),formatOutput:e=>typeof e==`string`?e:JSON.stringify(e,null,2)})}function j(e){let{name:n,description:r,argsSchema:i,get:a}=e,[s,c]=u(!1),d=l(a);return o(()=>{d.current=a},[a]),o(()=>{let e=g();if(!e){console.warn(`[ReactWebMCP] window.document.modelContext is not available. Prompt "${n}" will not be registered.`);return}let a=async e=>d.current(e),o=i?y(i)?b(i):t(i).inputSchema:void 0,s;try{s=e.registerPrompt({name:n,...r!==void 0&&{description:r},...o&&{argsSchema:o},get:a})}catch(e){throw c(!1),e}if(!s){console.warn(`[ReactWebMCP] Prompt "${n}" did not return a registration handle.`),c(!1);return}return c(!0),()=>{s.unregister(),c(!1)}},[n,r,i]),{isRegistered:s}}function M(e){let{uri:t,name:n,description:r,mimeType:i,read:a}=e,[s,c]=u(!1),d=l(a);return o(()=>{d.current=a},[a]),o(()=>{let e=g();if(!e){console.warn(`[ReactWebMCP] window.document.modelContext is not available. Resource "${t}" will not be registered.`);return}let a=async(e,t)=>d.current(e,t),o;try{o=e.registerResource({uri:t,name:n,...r!==void 0&&{description:r},...i!==void 0&&{mimeType:i},read:a})}catch(e){throw c(!1),e}if(!o){console.warn(`[ReactWebMCP] Resource "${t}" did not return a registration handle.`),c(!1);return}return c(!0),()=>{o.unregister(),c(!1)}},[t,n,r,i]),{isRegistered:s}}function N(e={}){let{onSuccess:t,onError:n}=e,[r,a]=u({isLoading:!1,result:null,error:null,requestCount:0}),o=i(()=>{a({isLoading:!1,result:null,error:null,requestCount:0})},[]);return{state:r,elicitInput:i(async e=>{let r=g();if(!r)throw Error(`document.modelContext is not available`);a(e=>({...e,isLoading:!0,error:null}));try{let n=await r.elicitInput(e);return a(e=>({isLoading:!1,result:n,error:null,requestCount:e.requestCount+1})),t?.(n),n}catch(e){let t=e instanceof Error?e:Error(String(e));throw a(e=>({...e,isLoading:!1,error:t})),n?.(t),t}},[t,n]),reset:o}}function P(e={}){let{onSuccess:t,onError:n}=e,[r,a]=u({isLoading:!1,result:null,error:null,requestCount:0}),o=i(()=>{a({isLoading:!1,result:null,error:null,requestCount:0})},[]);return{state:r,createMessage:i(async e=>{let r=g();if(!r)throw Error(`document.modelContext is not available`);a(e=>({...e,isLoading:!0,error:null}));try{let n=await r.createMessage(e);return a(e=>({isLoading:!1,result:n,error:null,requestCount:e.requestCount+1})),t?.(n),n}catch(e){let t=e instanceof Error?e:Error(String(e));throw a(e=>({...e,isLoading:!1,error:t})),n?.(t),t}},[t,n]),reset:o}}const F=r(null),I={};function L(e,t){let n=globalThis.console;if(!n)return;let r=n.debug??n.log;typeof r==`function`&&r.call(n,`[ReactWebMCP:McpClientProvider:ToolFlow]`,e,t)}function R(){if(typeof window>`u`)return!1;try{return window.localStorage.getItem(`WEBMCP_TRACE_TOOL_FLOW`)===`1`}catch{return!1}}function z({children:e,client:t,transport:n,opts:r}){let[a,s]=u([]),[c,d]=u([]),[f,g]=u(!1),[_,v]=u(null),[y,b]=u(!1),[x,S]=u(null),C=r??I,w=l(`disconnected`),T=l(0),E=i((e,t={})=>{let n=`[${++T.current}] ${e}`;R()&&L(n,t)},[]),D=i(async()=>{if(t){if(!t.getServerCapabilities()?.resources){s([]);return}try{s((await t.listResources()).resources)}catch(e){throw console.error(`[ReactWebMCP:McpClientProvider]`,`Error fetching resources:`,e),e}}},[t]),O=i(async()=>{if(!t)return;let e=t.getServerCapabilities();if(!e?.tools){E(`listTools:capability_missing`,{}),d([]);return}let n=Date.now();E(`listTools:start`,{hasToolsCapability:!!e.tools});try{let e=await t.listTools();d(e.tools),E(`listTools:success`,{durationMs:Date.now()-n,toolCount:e.tools.length})}catch(e){throw E(`listTools:error`,{durationMs:Date.now()-n,errorMessage:e instanceof Error?e.message:String(e)}),console.error(`[ReactWebMCP:McpClientProvider]`,`Error fetching tools:`,e),e}},[t,E]),k=i(async()=>{if(!t||!n)throw Error(`Client or transport not available`);if(w.current===`disconnected`){w.current=`connecting`,g(!0),v(null);try{await t.connect(n,C);let e=t.getServerCapabilities();b(!0),S(e||null),w.current=`connected`,E(`reconnect:connected`,{hasToolsListChanged:!!e?.tools?.listChanged}),await Promise.all([D(),O()])}catch(e){let t=e instanceof Error?e:Error(String(e));throw w.current=`disconnected`,v(t),t}finally{g(!1)}}},[t,n,C,D,O,E]);return o(()=>{if(!y||!t)return;let e=t.getServerCapabilities();return e?.resources?.listChanged&&t.setNotificationHandler(p,()=>{D().catch(e=>{console.error(`[ReactWebMCP:McpClientProvider]`,`Failed to refresh resources after list_changed:`,e)})}),e?.tools?.listChanged&&t.setNotificationHandler(m,()=>{E(`notification:tools/list_changed`,{}),O().catch(e=>{console.error(`[ReactWebMCP:McpClientProvider]`,`Failed to refresh tools after list_changed:`,e)})}),Promise.all([D(),O()]).catch(e=>{console.error(`[ReactWebMCP:McpClientProvider]`,`Failed to refresh tools/resources after handler registration:`,e)}),()=>{e?.resources?.listChanged&&t.removeNotificationHandler(`notifications/resources/list_changed`),e?.tools?.listChanged&&t.removeNotificationHandler(`notifications/tools/list_changed`)}},[t,y,D,O,E]),o(()=>(k().catch(e=>{console.error(`[ReactWebMCP:McpClientProvider]`,`Failed to connect MCP client:`,e)}),()=>{w.current=`disconnected`,b(!1)}),[t,n,k]),h(F.Provider,{value:{client:t,tools:c,resources:a,isConnected:y,isLoading:f,error:_,capabilities:x,reconnect:k},children:e})}function B(){let e=a(F);if(!e)throw Error(`useMcpClient must be used within an McpClientProvider`);return e}export{z as McpClientProvider,N as useElicitation,N as useElicitationHandler,B as useMcpClient,P as useSampling,P as useSamplingHandler,k as useWebMCP,A as useWebMCPContext,j as useWebMCPPrompt,M as useWebMCPResource};
2
2
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["zodToJsonSchema","zodToJsonSchemaLib","zodToJsonSchema","zodToJsonSchema"],"sources":["../src/model-context.ts","../src/zod-utils.ts","../src/useWebMCP.ts","../src/useWebMCPContext.ts","../src/useWebMCPPrompt.ts","../src/useWebMCPResource.ts","../src/useElicitationHandler.ts","../src/useSamplingHandler.ts","../src/client/McpClientProvider.tsx"],"sourcesContent":["export type ModelContextSurface = Document['modelContext'];\n\nexport function getModelContext(): ModelContextSurface | undefined {\n if (typeof window === 'undefined') {\n return undefined;\n }\n\n return window.document?.modelContext ?? window.navigator?.modelContext;\n}\n","import type { InputSchema } from '@mcp-b/webmcp-types';\nimport type { z } from 'zod';\nimport { zodToJsonSchema as zodToJsonSchemaLib } from 'zod-to-json-schema';\n\nexport type ZodSchemaObject = Record<string, z.ZodTypeAny>;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction isZodLikeValue(value: unknown): boolean {\n // `_def` is present on both zod/v3 and zod v4 schema instances.\n // Restricting detection to `_def` avoids misclassifying non-Zod Standard Schema values.\n return isRecord(value) && '_def' in value;\n}\n\ntype ZodDefinitionCarrier = {\n _def: {\n typeName: unknown;\n type?: unknown;\n };\n};\n\ntype ZodJsonSchemaCarrier = {\n toJSONSchema: () => unknown;\n};\n\nfunction hasZodTypeName(schema: unknown): schema is ZodDefinitionCarrier {\n if (!isRecord(schema)) {\n return false;\n }\n\n const definition = schema._def;\n return isRecord(definition) && 'typeName' in definition;\n}\n\nexport function isZodSchema(schema: unknown): schema is ZodSchemaObject {\n if (!isRecord(schema)) return false;\n const values = Object.values(schema);\n if (values.length === 0) return false;\n return values.some((value) => isZodLikeValue(value));\n}\n\nfunction isOptionalSchema(schema: unknown): boolean {\n if (!hasZodTypeName(schema)) {\n if (!isRecord(schema) || !isRecord(schema._def)) {\n return false;\n }\n\n return schema._def.type === 'optional' || schema._def.type === 'default';\n }\n\n const { typeName } = schema._def;\n return typeName === 'ZodOptional' || typeName === 'ZodDefault';\n}\n\nfunction hasNativeJsonSchema(schema: unknown): schema is ZodJsonSchemaCarrier {\n return isRecord(schema) && typeof schema.toJSONSchema === 'function';\n}\n\nfunction stripSchemaMeta(schema: InputSchema): InputSchema {\n const rest = { ...schema } as InputSchema & { $schema?: string };\n delete rest.$schema;\n if (rest.properties) {\n const props: Record<string, InputSchema> = {};\n for (const [k, v] of Object.entries(rest.properties)) {\n props[k] = stripSchemaMeta(v as InputSchema);\n }\n rest.properties = props;\n }\n return rest;\n}\n\nexport function zodToJsonSchema(schema: ZodSchemaObject): InputSchema {\n const properties: Record<string, InputSchema> = {};\n const required: string[] = [];\n\n for (const [key, rawValue] of Object.entries(schema)) {\n if (!isZodLikeValue(rawValue)) {\n continue;\n }\n\n const zodSchema = rawValue as z.ZodTypeAny;\n let propSchema: unknown = zodToJsonSchemaLib(zodSchema, {\n strictUnions: true,\n $refStrategy: 'none',\n });\n\n if (isRecord(propSchema) && !('type' in propSchema) && hasNativeJsonSchema(zodSchema)) {\n propSchema = zodSchema.toJSONSchema();\n }\n\n properties[key] = stripSchemaMeta(propSchema as InputSchema);\n if (!isOptionalSchema(zodSchema)) {\n required.push(key);\n }\n }\n\n const result: InputSchema = { type: 'object', properties };\n if (required.length > 0) result.required = required;\n return result;\n}\n","import type {\n CallToolResult,\n InputSchema,\n JsonObject,\n JsonSchemaForInference,\n ToolDescriptor,\n} from '@mcp-b/webmcp-types';\nimport type { DependencyList } from 'react';\nimport { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';\nimport type {\n InferOutput,\n InferToolInput,\n ReactWebMCPInputSchema,\n ReactWebMCPOutputSchema,\n ToolExecutionState,\n WebMCPConfig,\n WebMCPReturn,\n} from './types.js';\nimport { getModelContext, type ModelContextSurface } from './model-context.js';\nimport { isZodSchema, zodToJsonSchema } from './zod-utils.js';\n\n/**\n * Default output formatter that converts values to formatted JSON strings.\n *\n * String values are returned as-is; all other types are serialized to\n * indented JSON for readability.\n *\n * @internal\n */\nfunction defaultFormatOutput(output: unknown): string {\n if (typeof output === 'string') {\n return output;\n }\n return JSON.stringify(output, null, 2);\n}\n\nconst TOOL_OWNER_BY_NAME = new Map<string, symbol>();\nconst DEFAULT_REGISTERED_INPUT_SCHEMA: InputSchema = { type: 'object', properties: {} };\nconst STANDARD_JSON_SCHEMA_TARGETS = ['draft-2020-12', 'draft-07'] as const;\ntype StructuredContent = Exclude<CallToolResult['structuredContent'], undefined>;\n\nfunction isObjectOutputSchema(schema: ReactWebMCPOutputSchema | undefined): boolean {\n if (!schema) {\n return false;\n }\n\n if (isZodSchema(schema)) {\n return true;\n }\n\n return 'type' in schema && schema.type === 'object';\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction isInputSchema(value: unknown): value is InputSchema {\n if (!isPlainObject(value)) {\n return false;\n }\n\n if ('type' in value && value.type !== undefined && typeof value.type !== 'string') {\n return false;\n }\n\n if ('properties' in value && value.properties !== undefined && !isPlainObject(value.properties)) {\n return false;\n }\n\n if (\n 'required' in value &&\n value.required !== undefined &&\n (!Array.isArray(value.required) || value.required.some((entry) => typeof entry !== 'string'))\n ) {\n return false;\n }\n\n return true;\n}\n\nfunction isJsonSchemaForInference(value: unknown): value is JsonSchemaForInference {\n if (!isPlainObject(value) || !('type' in value)) {\n return false;\n }\n\n const schemaType = value.type;\n if (typeof schemaType === 'string') {\n if (\n !['array', 'boolean', 'integer', 'null', 'number', 'object', 'string'].includes(schemaType)\n ) {\n return false;\n }\n\n if (schemaType === 'array') {\n return 'items' in value && isJsonSchemaForInference(value.items);\n }\n\n if (schemaType === 'object' && 'properties' in value && value.properties !== undefined) {\n return (\n isPlainObject(value.properties) &&\n Object.values(value.properties).every(isJsonSchemaForInference)\n );\n }\n\n return true;\n }\n\n return (\n Array.isArray(schemaType) &&\n schemaType.length > 0 &&\n schemaType.every((entry) =>\n ['array', 'boolean', 'integer', 'null', 'number', 'object', 'string'].includes(entry)\n )\n );\n}\n\nfunction isJsonValue(value: unknown): boolean {\n if (value === null) {\n return true;\n }\n\n if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {\n return true;\n }\n\n if (Array.isArray(value)) {\n return value.every(isJsonValue);\n }\n\n if (typeof value !== 'object') {\n return false;\n }\n\n return Object.values(value).every(isJsonValue);\n}\n\nfunction isJsonObject(value: unknown): value is JsonObject {\n return typeof value === 'object' && value !== null && !Array.isArray(value) && isJsonValue(value);\n}\n\nfunction toStructuredContent(value: unknown): StructuredContent | null {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n return null;\n }\n\n try {\n const normalized = JSON.parse(JSON.stringify(value));\n return isJsonObject(normalized) ? normalized : null;\n } catch {\n return null;\n }\n}\n\nconst useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect;\n\nfunction isPromiseLike(value: unknown): value is PromiseLike<unknown> {\n return (\n Boolean(value) &&\n (typeof value === 'object' || typeof value === 'function') &&\n typeof (value as { then?: unknown }).then === 'function'\n );\n}\n\n/**\n * On Chrome Beta 147 native (which ignores the second arg), aborting\n * the controller cannot remove the tool. Install `@mcp-b/global`\n * or `@mcp-b/webmcp-polyfill` there.\n */\nfunction registerToolWithCleanup(\n modelContext: ModelContextSurface,\n toolDescriptor: ToolDescriptor\n): AbortController {\n const controller = new AbortController();\n const result = (\n modelContext.registerTool as (\n tool: ToolDescriptor,\n options?: { signal?: AbortSignal }\n ) => unknown\n ).call(modelContext, toolDescriptor, { signal: controller.signal });\n\n if (isPromiseLike(result)) {\n result.then(undefined, (error: unknown) => {\n console.warn(\n `[ReactWebMCP:useWebMCP] registerTool(\"${toolDescriptor.name}\") rejected:`,\n error\n );\n });\n }\n\n return controller;\n}\n\nfunction toRegisteredInputSchema(\n schema: ReactWebMCPInputSchema | undefined\n): InputSchema | undefined {\n if (!schema) {\n return undefined;\n }\n\n if (isZodSchema(schema)) {\n return zodToJsonSchema(schema);\n }\n\n if (!isPlainObject(schema) || !('~standard' in schema)) {\n return isInputSchema(schema) ? schema : DEFAULT_REGISTERED_INPUT_SCHEMA;\n }\n\n const standard = schema['~standard'];\n if (!isPlainObject(standard)) {\n return DEFAULT_REGISTERED_INPUT_SCHEMA;\n }\n\n const jsonSchema = standard.jsonSchema;\n if (!isPlainObject(jsonSchema) || typeof jsonSchema.input !== 'function') {\n return DEFAULT_REGISTERED_INPUT_SCHEMA;\n }\n\n for (const target of STANDARD_JSON_SCHEMA_TARGETS) {\n try {\n const converted = jsonSchema.input({ target });\n if (isInputSchema(converted)) {\n return converted;\n }\n } catch {\n // Try the next target before falling back to the default registration schema.\n }\n }\n\n return DEFAULT_REGISTERED_INPUT_SCHEMA;\n}\n\nfunction toRegisteredOutputSchema(\n schema: ReactWebMCPOutputSchema | undefined\n): JsonSchemaForInference | undefined {\n if (!schema) {\n return undefined;\n }\n\n const jsonSchema = isZodSchema(schema) ? zodToJsonSchema(schema) : schema;\n return isJsonSchemaForInference(jsonSchema) ? jsonSchema : undefined;\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.document.modelContext`\n * - Manages execution state (loading, results, errors)\n * - Handles tool execution and lifecycle callbacks\n * - Automatically unregisters on component unmount\n * - Returns `structuredContent` when `outputSchema` is defined\n *\n * ## Output Schema (Recommended)\n *\n * Always define an `outputSchema` for your tools. This provides:\n * - **Type Safety**: Handler return type is inferred from the schema\n * - **MCP structuredContent**: AI models receive structured, typed data\n * - **Better AI Understanding**: Models can reason about your tool's output format\n *\n * ```tsx\n * useWebMCP({\n * name: 'get_user',\n * description: 'Get user by ID',\n * inputSchema: {\n * type: 'object',\n * properties: { userId: { type: 'string' } },\n * required: ['userId'],\n * } as const,\n * outputSchema: {\n * type: 'object',\n * properties: {\n * id: { type: 'string' },\n * name: { type: 'string' },\n * email: { type: 'string' },\n * },\n * } as const,\n * handler: async ({ userId }) => {\n * const user = await fetchUser(userId);\n * return { id: user.id, name: user.name, email: user.email };\n * },\n * });\n * ```\n *\n * @template TInputSchema - JSON Schema defining input parameter types (use `as const` for inference)\n * @template TOutputSchema - JSON Schema defining output structure (object schemas enable structuredContent)\n *\n * @param config - Configuration object for the tool\n * @param deps - Optional dependency array that triggers tool re-registration when values change.\n *\n * @returns Object containing execution state and control methods\n *\n * @public\n */\nexport function useWebMCP<\n TInputSchema extends ReactWebMCPInputSchema = InputSchema,\n TOutputSchema extends ReactWebMCPOutputSchema | undefined = undefined,\n>(\n config: WebMCPConfig<TInputSchema, TOutputSchema>,\n deps?: DependencyList\n): WebMCPReturn<TOutputSchema, TInputSchema> {\n type TOutput = InferOutput<TOutputSchema>;\n type TInput = InferToolInput<TInputSchema>;\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 const isMountedRef = useRef(true);\n // Update refs when callbacks change (doesn't trigger re-registration)\n useIsomorphicLayoutEffect(() => {\n handlerRef.current = handler;\n onSuccessRef.current = onSuccess;\n onErrorRef.current = onError;\n formatOutputRef.current = formatOutput;\n }, [handler, onSuccess, onError, formatOutput]);\n\n // Cleanup: mark component as unmounted\n useEffect(() => {\n isMountedRef.current = true;\n return () => {\n isMountedRef.current = false;\n };\n }, []);\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(async (input: TInput): Promise<TOutput> => {\n setState((prev) => ({\n ...prev,\n isExecuting: true,\n error: null,\n }));\n\n try {\n const result = await handlerRef.current(input);\n\n // Only update state if component is still mounted\n if (isMountedRef.current) {\n setState((prev) => ({\n isExecuting: false,\n lastResult: result,\n error: null,\n executionCount: prev.executionCount + 1,\n }));\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 // Only update state if component is still mounted\n if (isMountedRef.current) {\n setState((prev) => ({\n ...prev,\n isExecuting: false,\n error: err,\n }));\n }\n\n if (onErrorRef.current) {\n onErrorRef.current(err, input);\n }\n\n throw err;\n }\n }, []);\n const executeRef = useRef(execute);\n\n useEffect(() => {\n executeRef.current = execute;\n }, [execute]);\n\n const stableExecute = useCallback(\n (input: TInput): Promise<TOutput> => executeRef.current(input),\n []\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 const modelContext = getModelContext();\n if (!modelContext) {\n console.warn(\n '[ReactWebMCP:useWebMCP]',\n `Tool \"${name}\" skipped: modelContext is not available`\n );\n return;\n }\n\n /**\n * Handles MCP tool execution by running the handler and formatting the response.\n *\n * @param input - The input parameters from the MCP client\n * @returns CallToolResult with text content and optional structuredContent\n */\n const mcpHandler = async (input: unknown): Promise<CallToolResult> => {\n try {\n const result = await Reflect.apply(executeRef.current, undefined, [input]);\n const formattedOutput = formatOutputRef.current(result);\n\n const response: CallToolResult = {\n content: [\n {\n type: 'text',\n text: formattedOutput,\n },\n ],\n };\n\n if (isObjectOutputSchema(outputSchema)) {\n const structuredContent = toStructuredContent(result);\n if (!structuredContent) {\n throw new Error(\n `Tool \"${name}\" outputSchema requires the handler to return a JSON object result`\n );\n }\n response.structuredContent = structuredContent;\n }\n\n return response;\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 resolvedInputSchema = toRegisteredInputSchema(inputSchema);\n const resolvedOutputSchema = toRegisteredOutputSchema(outputSchema);\n\n const ownerToken = Symbol(name);\n const toolDescriptor: ToolDescriptor = {\n name,\n description,\n ...(resolvedInputSchema && { inputSchema: resolvedInputSchema }),\n ...(resolvedOutputSchema && { outputSchema: resolvedOutputSchema }),\n ...(annotations && { annotations }),\n execute: mcpHandler,\n };\n const controller = registerToolWithCleanup(modelContext, toolDescriptor);\n TOOL_OWNER_BY_NAME.set(name, ownerToken);\n\n return () => {\n const currentOwner = TOOL_OWNER_BY_NAME.get(name);\n if (currentOwner !== ownerToken) {\n return;\n }\n\n TOOL_OWNER_BY_NAME.delete(name);\n controller.abort();\n };\n // Spread operator in dependencies intentionally allows consumers to trigger\n // re-registration with custom reactive inputs.\n }, [name, description, inputSchema, outputSchema, annotations, ...(deps ?? [])]);\n\n return {\n state,\n execute: stableExecute,\n reset,\n };\n}\n","import { useMemo, 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 * Note: This hook does not use an output schema, so the result will not include\n * `structuredContent` in the MCP response. Use {@link useWebMCP} directly with\n * `outputSchema` if you need structured output for MCP compliance.\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 {\n const getValueRef = useRef(getValue);\n getValueRef.current = getValue;\n const annotations = useMemo(\n () => ({\n title: `Context: ${name}`,\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: false,\n }),\n [name]\n );\n\n // Use default generics (no input/output schema) since context tools\n // don't define structured schemas. The handler returns T but it's\n // treated as `unknown` in the return type since no outputSchema is defined.\n return useWebMCP({\n name,\n description,\n annotations,\n // Cast to unknown since context tools return arbitrary types\n // that don't need to conform to a specific schema\n handler: async (_input: Record<string, unknown>) => {\n return getValueRef.current() as Record<string, unknown>;\n },\n formatOutput: (output) => {\n if (typeof output === 'string') {\n return output as string;\n }\n return JSON.stringify(output, null, 2);\n },\n });\n}\n","import type { InputSchema } from '@mcp-b/webmcp-types';\nimport { useEffect, useRef, useState } from 'react';\nimport type {\n PromptMessage,\n ReactWebMCPInputSchema,\n WebMCPPromptConfig,\n WebMCPPromptReturn,\n} from './types.js';\nimport { getModelContext, type ModelContextSurface } from './model-context.js';\nimport { isZodSchema, zodToJsonSchema } from './zod-utils.js';\n\ntype PromptModelContext = ModelContextSurface & {\n registerPrompt: (descriptor: {\n name: string;\n description?: string;\n argsSchema?: InputSchema;\n get: (args: Record<string, unknown>) => Promise<{ messages: PromptMessage[] }>;\n }) => { unregister: () => void } | undefined;\n};\n\n/**\n * React hook for registering Model Context Protocol (MCP) prompts.\n *\n * This hook handles the complete lifecycle of an MCP prompt:\n * - Registers the prompt with `window.document.modelContext`\n * - Converts Zod schemas to JSON Schema for argument validation\n * - Automatically unregisters on component unmount\n *\n * @template TArgsSchema - Zod schema object defining argument types\n *\n * @param config - Configuration object for the prompt\n * @returns Object indicating registration status\n *\n * @public\n *\n * @example\n * Simple prompt without arguments:\n * ```tsx\n * function HelpPrompt() {\n * const { isRegistered } = useWebMCPPrompt({\n * name: 'help',\n * description: 'Get help with using the application',\n * get: async () => ({\n * messages: [{\n * role: 'user',\n * content: { type: 'text', text: 'How do I use this application?' }\n * }]\n * }),\n * });\n *\n * return <div>Help prompt {isRegistered ? 'ready' : 'loading'}</div>;\n * }\n * ```\n *\n * @example\n * Prompt with typed arguments:\n * ```tsx\n * function CodeReviewPrompt() {\n * const { isRegistered } = useWebMCPPrompt({\n * name: 'review_code',\n * description: 'Review code for best practices',\n * argsSchema: {\n * type: 'object',\n * properties: {\n * code: { type: 'string', description: 'The code to review' },\n * language: { type: 'string', description: 'Programming language' },\n * },\n * required: ['code'],\n * } as const,\n * get: async ({ code, language }) => ({\n * messages: [{\n * role: 'user',\n * content: {\n * type: 'text',\n * text: `Please review this ${language ?? ''} code:\\n\\n${code}`\n * }\n * }]\n * }),\n * });\n *\n * return <div>Code review prompt {isRegistered ? 'ready' : 'loading'}</div>;\n * }\n * ```\n */\nexport function useWebMCPPrompt<TArgsSchema extends ReactWebMCPInputSchema = InputSchema>(\n config: WebMCPPromptConfig<TArgsSchema>\n): WebMCPPromptReturn {\n const { name, description, argsSchema, get } = config;\n\n const [isRegistered, setIsRegistered] = useState(false);\n\n const getRef = useRef(get);\n\n useEffect(() => {\n getRef.current = get;\n }, [get]);\n\n useEffect(() => {\n const modelContext = getModelContext() as PromptModelContext | undefined;\n if (!modelContext) {\n console.warn(\n `[ReactWebMCP] window.document.modelContext is not available. Prompt \"${name}\" will not be registered.`\n );\n return;\n }\n\n const promptHandler = async (\n args: Record<string, unknown>\n ): Promise<{ messages: PromptMessage[] }> => {\n return getRef.current(args as never);\n };\n\n const resolvedArgsSchema = argsSchema\n ? isZodSchema(argsSchema)\n ? zodToJsonSchema(argsSchema)\n : (argsSchema as InputSchema)\n : undefined;\n\n let registration: { unregister: () => void } | undefined;\n try {\n registration = modelContext.registerPrompt({\n name,\n ...(description !== undefined && { description }),\n ...(resolvedArgsSchema && { argsSchema: resolvedArgsSchema }),\n get: promptHandler,\n });\n } catch (error) {\n setIsRegistered(false);\n throw error;\n }\n\n if (!registration) {\n console.warn(`[ReactWebMCP] Prompt \"${name}\" did not return a registration handle.`);\n setIsRegistered(false);\n return;\n }\n\n setIsRegistered(true);\n\n return () => {\n registration.unregister();\n setIsRegistered(false);\n };\n }, [name, description, argsSchema]);\n\n return {\n isRegistered,\n };\n}\n","import { useEffect, useRef, useState } from 'react';\nimport { getModelContext, type ModelContextSurface } from './model-context.js';\nimport type { ResourceContents, WebMCPResourceConfig, WebMCPResourceReturn } from './types.js';\n\ntype ResourceModelContext = ModelContextSurface & {\n registerResource: (descriptor: {\n uri: string;\n name: string;\n description?: string;\n mimeType?: string;\n read: (uri: URL, params?: Record<string, string>) => Promise<{ contents: ResourceContents[] }>;\n }) => { unregister: () => void } | undefined;\n};\n\n/**\n * React hook for registering Model Context Protocol (MCP) resources.\n *\n * This hook handles the complete lifecycle of an MCP resource:\n * - Registers the resource with `window.document.modelContext`\n * - Supports both static URIs and URI templates with parameters\n * - Automatically unregisters on component unmount\n *\n * @param config - Configuration object for the resource\n * @returns Object indicating registration status\n *\n * @public\n *\n * @example\n * Static resource:\n * ```tsx\n * function AppSettingsResource() {\n * const { isRegistered } = useWebMCPResource({\n * uri: 'config://app-settings',\n * name: 'App Settings',\n * description: 'Application configuration',\n * mimeType: 'application/json',\n * read: async (uri) => ({\n * contents: [{\n * uri: uri.href,\n * text: JSON.stringify({ theme: 'dark', language: 'en' })\n * }]\n * }),\n * });\n *\n * return <div>Settings resource {isRegistered ? 'ready' : 'loading'}</div>;\n * }\n * ```\n *\n * @example\n * Dynamic resource with URI template:\n * ```tsx\n * function UserProfileResource() {\n * const { isRegistered } = useWebMCPResource({\n * uri: 'user://{userId}/profile',\n * name: 'User Profile',\n * description: 'User profile data by ID',\n * mimeType: 'application/json',\n * read: async (uri, params) => {\n * const userId = params?.userId ?? '';\n * const profile = await fetchUserProfile(userId);\n * return {\n * contents: [{\n * uri: uri.href,\n * text: JSON.stringify(profile)\n * }]\n * };\n * },\n * });\n *\n * return <div>User profile resource {isRegistered ? 'ready' : 'loading'}</div>;\n * }\n * ```\n */\nexport function useWebMCPResource(config: WebMCPResourceConfig): WebMCPResourceReturn {\n const { uri, name, description, mimeType, read } = config;\n\n const [isRegistered, setIsRegistered] = useState(false);\n\n const readRef = useRef(read);\n\n useEffect(() => {\n readRef.current = read;\n }, [read]);\n\n useEffect(() => {\n const modelContext = getModelContext() as ResourceModelContext | undefined;\n if (!modelContext) {\n console.warn(\n `[ReactWebMCP] window.document.modelContext is not available. Resource \"${uri}\" will not be registered.`\n );\n return;\n }\n\n const resourceHandler = async (\n resolvedUri: URL,\n params?: Record<string, string>\n ): Promise<{ contents: ResourceContents[] }> => {\n return readRef.current(resolvedUri, params);\n };\n\n let registration: { unregister: () => void } | undefined;\n try {\n registration = modelContext.registerResource({\n uri,\n name,\n ...(description !== undefined && { description }),\n ...(mimeType !== undefined && { mimeType }),\n read: resourceHandler,\n });\n } catch (error) {\n setIsRegistered(false);\n throw error;\n }\n\n if (!registration) {\n console.warn(`[ReactWebMCP] Resource \"${uri}\" did not return a registration handle.`);\n setIsRegistered(false);\n return;\n }\n\n setIsRegistered(true);\n\n return () => {\n registration.unregister();\n setIsRegistered(false);\n };\n }, [uri, name, description, mimeType]);\n\n return {\n isRegistered,\n };\n}\n","import type { ElicitationParams, ElicitationResult } from '@mcp-b/webmcp-types';\nimport { useCallback, useState } from 'react';\nimport { getModelContext, type ModelContextSurface } from './model-context.js';\n\ntype ElicitationModelContext = ModelContextSurface & {\n elicitInput: (params: ElicitationParams) => Promise<ElicitationResult>;\n};\n\n/**\n * State for elicitation requests, tracking the current request and results.\n */\nexport interface ElicitationState {\n /** Whether an elicitation request is currently in progress */\n isLoading: boolean;\n /** The last elicitation result received */\n result: ElicitationResult | null;\n /** Any error that occurred during the last request */\n error: Error | null;\n /** Total number of requests made */\n requestCount: number;\n}\n\n/**\n * Configuration options for the useElicitation hook.\n */\nexport interface UseElicitationConfig {\n /**\n * Optional callback invoked when an elicitation request completes successfully.\n */\n onSuccess?: (result: ElicitationResult) => void;\n\n /**\n * Optional callback invoked when an elicitation request fails.\n */\n onError?: (error: Error) => void;\n}\n\n/**\n * Return value from the useElicitation hook.\n */\nexport interface UseElicitationReturn {\n /** Current state of elicitation */\n state: ElicitationState;\n /** Function to request user input from the connected client */\n elicitInput: (params: ElicitationParams) => Promise<ElicitationResult>;\n /** Reset the state */\n reset: () => void;\n}\n\n/**\n * React hook for requesting user input from the connected MCP client.\n *\n * Elicitation allows the server (webpage) to request user input from the\n * connected client. This is useful when the page needs additional information\n * from the user, such as API keys, configuration options, or confirmations.\n *\n * There are two modes:\n * 1. **Form mode**: For non-sensitive data collection using a schema-driven form.\n * 2. **URL mode**: For sensitive data collection via a web URL (API keys, OAuth, etc.).\n *\n * @param config - Optional configuration including callbacks\n * @returns Object containing state and the elicitInput function\n *\n * @example Form elicitation:\n * ```tsx\n * function ConfigForm() {\n * const { state, elicitInput } = useElicitation({\n * onSuccess: (result) => console.log('Got input:', result),\n * onError: (error) => console.error('Elicitation failed:', error),\n * });\n *\n * const handleConfigure = async () => {\n * const result = await elicitInput({\n * message: 'Please provide your configuration',\n * requestedSchema: {\n * type: 'object',\n * properties: {\n * apiKey: { type: 'string', title: 'API Key', description: 'Your API key' },\n * model: { type: 'string', enum: ['gpt-4', 'gpt-3.5'], title: 'Model' }\n * },\n * required: ['apiKey']\n * }\n * });\n *\n * if (result.action === 'accept') {\n * console.log('Config:', result.content);\n * }\n * };\n *\n * return (\n * <button onClick={handleConfigure} disabled={state.isLoading}>\n * Configure\n * </button>\n * );\n * }\n * ```\n *\n * @example URL elicitation (for sensitive data):\n * ```tsx\n * const { elicitInput } = useElicitation();\n *\n * const handleOAuth = async () => {\n * const result = await elicitInput({\n * mode: 'url',\n * message: 'Please authenticate with GitHub',\n * elicitationId: 'github-oauth-123',\n * url: 'https://github.com/login/oauth/authorize?client_id=...'\n * });\n *\n * if (result.action === 'accept') {\n * console.log('OAuth completed');\n * }\n * };\n * ```\n */\nexport function useElicitation(config: UseElicitationConfig = {}): UseElicitationReturn {\n const { onSuccess, onError } = config;\n\n const [state, setState] = useState<ElicitationState>({\n isLoading: false,\n result: null,\n error: null,\n requestCount: 0,\n });\n\n const reset = useCallback(() => {\n setState({\n isLoading: false,\n result: null,\n error: null,\n requestCount: 0,\n });\n }, []);\n\n const elicitInput = useCallback(\n async (params: ElicitationParams): Promise<ElicitationResult> => {\n const mc = getModelContext() as ElicitationModelContext | undefined;\n if (!mc) {\n throw new Error('document.modelContext is not available');\n }\n\n setState((prev) => ({\n ...prev,\n isLoading: true,\n error: null,\n }));\n\n try {\n const result: ElicitationResult = await mc.elicitInput(params);\n\n setState((prev) => ({\n isLoading: false,\n result,\n error: null,\n requestCount: prev.requestCount + 1,\n }));\n\n onSuccess?.(result);\n return result;\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n\n setState((prev) => ({\n ...prev,\n isLoading: false,\n error,\n }));\n\n onError?.(error);\n throw error;\n }\n },\n [onSuccess, onError]\n );\n\n return {\n state,\n elicitInput,\n reset,\n };\n}\n\n// Also export with the old name for backwards compatibility during migration\nexport { useElicitation as useElicitationHandler };\nexport type { ElicitationState as ElicitationHandlerState };\nexport type { UseElicitationConfig as UseElicitationHandlerConfig };\nexport type { UseElicitationReturn as UseElicitationHandlerReturn };\n","import type { SamplingRequestParams, SamplingResult } from '@mcp-b/webmcp-ts-sdk';\nimport { useCallback, useState } from 'react';\nimport { getModelContext, type ModelContextSurface } from './model-context.js';\n\ntype SamplingModelContext = ModelContextSurface & {\n createMessage: (params: SamplingRequestParams) => Promise<SamplingResult>;\n};\n\n/**\n * State for sampling requests, tracking the current request and results.\n */\nexport interface SamplingState {\n /** Whether a sampling request is currently in progress */\n isLoading: boolean;\n /** The last sampling result received */\n result: SamplingResult | null;\n /** Any error that occurred during the last request */\n error: Error | null;\n /** Total number of requests made */\n requestCount: number;\n}\n\n/**\n * Configuration options for the useSampling hook.\n */\nexport interface UseSamplingConfig {\n /**\n * Optional callback invoked when a sampling request completes successfully.\n */\n onSuccess?: (result: SamplingResult) => void;\n\n /**\n * Optional callback invoked when a sampling request fails.\n */\n onError?: (error: Error) => void;\n}\n\n/**\n * Return value from the useSampling hook.\n */\nexport interface UseSamplingReturn {\n /** Current state of sampling */\n state: SamplingState;\n /** Function to request LLM completion from the connected client */\n createMessage: (params: SamplingRequestParams) => Promise<SamplingResult>;\n /** Reset the state */\n reset: () => void;\n}\n\n/**\n * React hook for requesting LLM completions from the connected MCP client.\n *\n * Sampling allows the server (webpage) to request LLM completions from the\n * connected client. This is useful when the page needs AI capabilities like\n * summarization, generation, or analysis.\n *\n * @param config - Optional configuration including callbacks\n * @returns Object containing state and the createMessage function\n *\n * @example Basic usage:\n * ```tsx\n * function AIAssistant() {\n * const { state, createMessage } = useSampling({\n * onSuccess: (result) => console.log('Got response:', result),\n * onError: (error) => console.error('Sampling failed:', error),\n * });\n *\n * const handleAsk = async () => {\n * const result = await createMessage({\n * messages: [\n * { role: 'user', content: { type: 'text', text: 'What is 2+2?' } }\n * ],\n * maxTokens: 100,\n * });\n * console.log(result.content);\n * };\n *\n * return (\n * <div>\n * <button onClick={handleAsk} disabled={state.isLoading}>\n * Ask AI\n * </button>\n * {state.result && <p>{JSON.stringify(state.result.content)}</p>}\n * </div>\n * );\n * }\n * ```\n */\nexport function useSampling(config: UseSamplingConfig = {}): UseSamplingReturn {\n const { onSuccess, onError } = config;\n\n const [state, setState] = useState<SamplingState>({\n isLoading: false,\n result: null,\n error: null,\n requestCount: 0,\n });\n\n const reset = useCallback(() => {\n setState({\n isLoading: false,\n result: null,\n error: null,\n requestCount: 0,\n });\n }, []);\n\n const createMessage = useCallback(\n async (params: SamplingRequestParams): Promise<SamplingResult> => {\n const modelContext = getModelContext() as SamplingModelContext | undefined;\n if (!modelContext) {\n throw new Error('document.modelContext is not available');\n }\n\n setState((prev) => ({\n ...prev,\n isLoading: true,\n error: null,\n }));\n\n try {\n const result = await modelContext.createMessage(params);\n\n setState((prev) => ({\n isLoading: false,\n result,\n error: null,\n requestCount: prev.requestCount + 1,\n }));\n\n onSuccess?.(result);\n return result;\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n\n setState((prev) => ({\n ...prev,\n isLoading: false,\n error,\n }));\n\n onError?.(error);\n throw error;\n }\n },\n [onSuccess, onError]\n );\n\n return {\n state,\n createMessage,\n reset,\n };\n}\n\n// Also export with the old name for backwards compatibility during migration\nexport { useSampling as useSamplingHandler };\nexport type { SamplingState as SamplingHandlerState };\nexport type { UseSamplingConfig as UseSamplingHandlerConfig };\nexport type { UseSamplingReturn as UseSamplingHandlerReturn };\n","import {\n type Client,\n type Tool as McpTool,\n type RequestOptions,\n type Resource,\n ResourceListChangedNotificationSchema,\n type ServerCapabilities,\n ToolListChangedNotificationSchema,\n type Transport,\n} from '@mcp-b/webmcp-ts-sdk';\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);\nconst EMPTY_REQUEST_OPTS: RequestOptions = {};\nconst TOOL_FLOW_TRACE_KEY = 'WEBMCP_TRACE_TOOL_FLOW';\n\nfunction emitForcedToolFlowTrace(event: string, details: Record<string, unknown>): void {\n const consoleRef = globalThis.console;\n if (!consoleRef) {\n return;\n }\n\n const method = consoleRef.debug ?? consoleRef.log;\n if (typeof method !== 'function') {\n return;\n }\n\n method.call(consoleRef, '[ReactWebMCP:McpClientProvider:ToolFlow]', event, details);\n}\n\nfunction isToolFlowTraceEnabled(): boolean {\n if (typeof window === 'undefined') {\n return false;\n }\n\n try {\n return window.localStorage.getItem(TOOL_FLOW_TRACE_KEY) === '1';\n } catch {\n return false;\n }\n}\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 const requestOpts = opts ?? EMPTY_REQUEST_OPTS;\n\n const connectionStateRef = useRef<'disconnected' | 'connecting' | 'connected'>('disconnected');\n const toolFlowSequenceRef = useRef(0);\n const logToolFlow = useCallback((event: string, details: Record<string, unknown> = {}) => {\n const sequence = ++toolFlowSequenceRef.current;\n const message = `[${sequence}] ${event}`;\n\n if (isToolFlowTraceEnabled()) {\n emitForcedToolFlowTrace(message, details);\n }\n }, []);\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('[ReactWebMCP:McpClientProvider]', '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 logToolFlow('listTools:capability_missing', {});\n setTools([]);\n return;\n }\n\n const startedAt = Date.now();\n logToolFlow('listTools:start', {\n hasToolsCapability: Boolean(serverCapabilities.tools),\n });\n try {\n const response = await client.listTools();\n setTools(response.tools);\n logToolFlow('listTools:success', {\n durationMs: Date.now() - startedAt,\n toolCount: response.tools.length,\n });\n } catch (e) {\n logToolFlow('listTools:error', {\n durationMs: Date.now() - startedAt,\n errorMessage: e instanceof Error ? e.message : String(e),\n });\n console.error('[ReactWebMCP:McpClientProvider]', 'Error fetching tools:', e);\n throw e;\n }\n }, [client, logToolFlow]);\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, requestOpts);\n const caps = client.getServerCapabilities();\n setIsConnected(true);\n setCapabilities(caps || null);\n connectionStateRef.current = 'connected';\n logToolFlow('reconnect:connected', {\n hasToolsListChanged: Boolean(caps?.tools?.listChanged),\n });\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, requestOpts, fetchResourcesInternal, fetchToolsInternal, logToolFlow]);\n\n useEffect(() => {\n if (!isConnected || !client) {\n return;\n }\n\n const serverCapabilities = client.getServerCapabilities();\n\n const handleResourcesChanged = () => {\n fetchResourcesInternal().catch((error) => {\n console.error(\n '[ReactWebMCP:McpClientProvider]',\n 'Failed to refresh resources after list_changed:',\n error\n );\n });\n };\n\n const handleToolsChanged = () => {\n logToolFlow('notification:tools/list_changed', {});\n fetchToolsInternal().catch((error) => {\n console.error(\n '[ReactWebMCP:McpClientProvider]',\n 'Failed to refresh tools after list_changed:',\n error\n );\n });\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 // Re-fetch after setting up handlers to catch any changes that occurred\n // during the gap between initial fetch and handler setup\n Promise.all([fetchResourcesInternal(), fetchToolsInternal()]).catch((error) => {\n console.error(\n '[ReactWebMCP:McpClientProvider]',\n 'Failed to refresh tools/resources after handler registration:',\n error\n );\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, logToolFlow]);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: intentional - reconnect when client/transport props change\n useEffect(() => {\n // Initial connection - reconnect() has its own guard to prevent concurrent connections\n reconnect().catch((err) => {\n console.error('[ReactWebMCP:McpClientProvider]', '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 }, [client, transport, reconnect]);\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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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/model-context.ts","../src/zod-utils.ts","../src/useWebMCP.ts","../src/useWebMCPContext.ts","../src/useWebMCPPrompt.ts","../src/useWebMCPResource.ts","../src/useElicitationHandler.ts","../src/useSamplingHandler.ts","../src/client/McpClientProvider.tsx"],"sourcesContent":["import type { ModelContext } from '@mcp-b/webmcp-types';\n\nexport type ModelContextSurface = ModelContext;\ntype ModelContextHost = { modelContext?: ModelContext };\n\nexport function getModelContext(): ModelContextSurface | undefined {\n if (typeof window === 'undefined') {\n return undefined;\n }\n\n const documentContext = (window.document as Document & ModelContextHost).modelContext;\n const navigatorContext = (window.navigator as Navigator & ModelContextHost).modelContext;\n return documentContext ?? navigatorContext;\n}\n","import type { InputSchema } from '@mcp-b/webmcp-types';\nimport type { AnySchema, ZodRawShapeCompat } from '@modelcontextprotocol/sdk/server/zod-compat.js';\nimport { normalizeObjectSchema } from '@modelcontextprotocol/sdk/server/zod-compat.js';\nimport { toJsonSchemaCompat } from '@modelcontextprotocol/sdk/server/zod-json-schema-compat.js';\nimport type { z } from 'zod';\n\nexport type ZodSchemaObject = Record<string, z.ZodTypeAny>;\nexport type ZodSchema = ZodSchemaObject | z.ZodTypeAny;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\nexport function isZodType(schema: unknown): schema is z.ZodTypeAny {\n return isRecord(schema) && ('_def' in schema || '_zod' in schema);\n}\n\nexport function isZodSchema(schema: unknown): schema is ZodSchemaObject {\n if (!isRecord(schema) || isZodType(schema)) {\n return false;\n }\n\n return normalizeObjectSchema(schema as ZodRawShapeCompat) !== undefined;\n}\n\nexport function zodToJsonSchema(schema: ZodSchema): InputSchema {\n const normalized = normalizeObjectSchema(schema as AnySchema | ZodRawShapeCompat);\n const zodSchema = normalized ?? (isZodType(schema) ? (schema as AnySchema) : undefined);\n if (!zodSchema) {\n throw new Error('Expected a Zod schema or Zod schema object');\n }\n\n return toJsonSchemaCompat(zodSchema, {\n strictUnions: true,\n pipeStrategy: 'input',\n }) as InputSchema;\n}\n","import type {\n CallToolResult,\n InputSchema,\n JsonSchemaForInference,\n ToolDescriptor,\n} from '@mcp-b/webmcp-types';\nimport { isPlainObject, normalizeInputSchema, toJsonValue } from '@mcp-b/webmcp-polyfill/schema';\nimport type { DependencyList } from 'react';\nimport { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';\nimport type {\n InferOutput,\n InferToolInput,\n ReactWebMCPInputSchema,\n ReactWebMCPOutputSchema,\n ToolExecutionState,\n WebMCPConfig,\n WebMCPReturn,\n} from './types.js';\nimport { getModelContext } from './model-context.js';\nimport { isZodSchema, isZodType, zodToJsonSchema } from './zod-utils.js';\n\n/**\n * Default output formatter that converts values to formatted JSON strings.\n *\n * String values are returned as-is; all other types are serialized to\n * indented JSON for readability.\n *\n * @internal\n */\nfunction defaultFormatOutput(output: unknown): string {\n if (typeof output === 'string') {\n return output;\n }\n return JSON.stringify(output, null, 2);\n}\n\nconst TOOL_OWNER_BY_NAME = new Map<string, symbol>();\nconst INFERABLE_JSON_SCHEMA_TYPES = [\n 'array',\n 'boolean',\n 'integer',\n 'null',\n 'number',\n 'object',\n 'string',\n] as const;\nconst UNSUPPORTED_OUTPUT_SCHEMA_KEYS = ['$ref', 'allOf', 'anyOf', 'oneOf', 'not'] as const;\n\nfunction isInferableJsonSchemaType(\n value: unknown\n): value is (typeof INFERABLE_JSON_SCHEMA_TYPES)[number] {\n return (\n typeof value === 'string' &&\n INFERABLE_JSON_SCHEMA_TYPES.includes(value as (typeof INFERABLE_JSON_SCHEMA_TYPES)[number])\n );\n}\n\nfunction unsupportedOutputSchema(detail: string): never {\n throw new Error(`Unsupported outputSchema: ${detail}`);\n}\n\nfunction assertInferableJsonSchema(\n value: unknown,\n path = '$'\n): asserts value is JsonSchemaForInference {\n if (!isPlainObject(value)) {\n unsupportedOutputSchema(`${path} must be a JSON Schema object`);\n }\n\n for (const key of UNSUPPORTED_OUTPUT_SCHEMA_KEYS) {\n if (key in value) {\n unsupportedOutputSchema(`${path}.${key} is outside the inferable JSON Schema subset`);\n }\n }\n\n const schemaTypes =\n typeof value.type === 'string'\n ? [value.type]\n : Array.isArray(value.type)\n ? value.type\n : undefined;\n if (\n !schemaTypes?.length ||\n !schemaTypes.every((schemaType) => isInferableJsonSchemaType(schemaType))\n ) {\n unsupportedOutputSchema(`${path} must declare an inferable JSON Schema type`);\n }\n\n const requiredValue = value.required;\n if (\n requiredValue !== undefined &&\n (!Array.isArray(requiredValue) || requiredValue.some((entry) => typeof entry !== 'string'))\n ) {\n unsupportedOutputSchema(`${path}.required must be an array of strings`);\n }\n\n if (schemaTypes.includes('array')) {\n if (!isPlainObject(value.items)) {\n unsupportedOutputSchema(`${path}.items must be an inferable schema for array outputs`);\n }\n assertInferableJsonSchema(value.items, `${path}.items`);\n }\n\n if (schemaTypes.includes('object')) {\n if (value.properties !== undefined && !isPlainObject(value.properties)) {\n unsupportedOutputSchema(`${path}.properties must be an object`);\n }\n\n if (isPlainObject(value.properties)) {\n for (const [key, propertySchema] of Object.entries(value.properties)) {\n assertInferableJsonSchema(propertySchema, `${path}.properties.${key}`);\n }\n }\n\n if (\n value.additionalProperties !== undefined &&\n typeof value.additionalProperties !== 'boolean'\n ) {\n assertInferableJsonSchema(value.additionalProperties, `${path}.additionalProperties`);\n }\n }\n}\n\nconst useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect;\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.document.modelContext`\n * - Manages execution state (loading, results, errors)\n * - Handles tool execution and lifecycle callbacks\n * - Automatically unregisters on component unmount\n * - Returns `structuredContent` when `outputSchema` is defined\n *\n * ## Output Schema (Recommended)\n *\n * Always define an `outputSchema` for your tools. This provides:\n * - **Type Safety**: Handler return type is inferred from the schema\n * - **MCP structuredContent**: AI models receive structured, typed data\n * - **Better AI Understanding**: Models can reason about your tool's output format\n *\n * ```tsx\n * useWebMCP({\n * name: 'get_user',\n * description: 'Get user by ID',\n * inputSchema: {\n * type: 'object',\n * properties: { userId: { type: 'string' } },\n * required: ['userId'],\n * } as const,\n * outputSchema: {\n * type: 'object',\n * properties: {\n * id: { type: 'string' },\n * name: { type: 'string' },\n * email: { type: 'string' },\n * },\n * } as const,\n * handler: async ({ userId }) => {\n * const user = await fetchUser(userId);\n * return { id: user.id, name: user.name, email: user.email };\n * },\n * });\n * ```\n *\n * @template TInputSchema - JSON Schema defining input parameter types (use `as const` for inference)\n * @template TOutputSchema - JSON Schema defining output structure\n *\n * @param config - Configuration object for the tool\n * @param deps - Optional dependency array that triggers tool re-registration when values change.\n *\n * @returns Object containing execution state and control methods\n *\n * @public\n */\nexport function useWebMCP<\n TInputSchema extends ReactWebMCPInputSchema = InputSchema,\n TOutputSchema extends ReactWebMCPOutputSchema | undefined = undefined,\n>(\n config: WebMCPConfig<TInputSchema, TOutputSchema>,\n deps?: DependencyList\n): WebMCPReturn<TOutputSchema, TInputSchema> {\n type TOutput = InferOutput<TOutputSchema>;\n type TInput = InferToolInput<TInputSchema>;\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 const isMountedRef = useRef(true);\n // Keep the registered handler current without re-registering the tool.\n useIsomorphicLayoutEffect(() => {\n handlerRef.current = handler;\n onSuccessRef.current = onSuccess;\n onErrorRef.current = onError;\n formatOutputRef.current = formatOutput;\n }, [handler, onSuccess, onError, formatOutput]);\n\n // Cleanup: mark component as unmounted\n useEffect(() => {\n isMountedRef.current = true;\n return () => {\n isMountedRef.current = false;\n };\n }, []);\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(async (input: TInput): Promise<TOutput> => {\n setState((prev) => ({\n ...prev,\n isExecuting: true,\n error: null,\n }));\n\n try {\n const result = await handlerRef.current(input);\n\n // Only update state if component is still mounted\n if (isMountedRef.current) {\n setState((prev) => ({\n isExecuting: false,\n lastResult: result,\n error: null,\n executionCount: prev.executionCount + 1,\n }));\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 // Only update state if component is still mounted\n if (isMountedRef.current) {\n setState((prev) => ({\n ...prev,\n isExecuting: false,\n error: err,\n }));\n }\n\n if (onErrorRef.current) {\n onErrorRef.current(err, input);\n }\n\n throw err;\n }\n }, []);\n const executeRef = useRef(execute);\n\n useEffect(() => {\n executeRef.current = execute;\n }, [execute]);\n\n const stableExecute = useCallback(\n (input: TInput): Promise<TOutput> => executeRef.current(input),\n []\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 const modelContext = getModelContext();\n if (!modelContext) {\n console.warn(\n '[ReactWebMCP:useWebMCP]',\n `Tool \"${name}\" skipped: modelContext is not available`\n );\n return;\n }\n\n const resolvedInputSchema = isZodSchema(inputSchema)\n ? zodToJsonSchema(inputSchema)\n : normalizeInputSchema(inputSchema).inputSchema;\n let resolvedOutputSchema: JsonSchemaForInference | undefined;\n if (outputSchema) {\n const jsonSchema =\n isZodSchema(outputSchema) || isZodType(outputSchema)\n ? zodToJsonSchema(outputSchema)\n : outputSchema;\n assertInferableJsonSchema(jsonSchema);\n resolvedOutputSchema = jsonSchema;\n }\n const mcpHandler = async (input: unknown): Promise<CallToolResult> => {\n try {\n const result = await Reflect.apply(executeRef.current, undefined, [input]);\n const formattedOutput = formatOutputRef.current(result);\n\n const response: CallToolResult = {\n content: [\n {\n type: 'text',\n text: formattedOutput,\n },\n ],\n };\n\n if (resolvedOutputSchema) {\n const structuredContent = toJsonValue(result);\n if (structuredContent === undefined) {\n throw new Error(\n `Tool \"${name}\" outputSchema requires the handler to return a JSON-serializable result`\n );\n }\n response.structuredContent = structuredContent;\n }\n\n return response;\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 ownerToken = Symbol(name);\n const toolDescriptor: ToolDescriptor & { inputSchema: InputSchema } = {\n name,\n description,\n inputSchema: resolvedInputSchema,\n ...(resolvedOutputSchema && { outputSchema: resolvedOutputSchema }),\n ...(annotations && { annotations }),\n execute: mcpHandler,\n };\n const controller = new AbortController();\n let registered = false;\n let disposed = false;\n\n try {\n const registerResult = modelContext.registerTool(toolDescriptor, {\n signal: controller.signal,\n });\n\n void Promise.resolve(registerResult).then(\n () => {\n if (!disposed && !controller.signal.aborted) {\n registered = true;\n TOOL_OWNER_BY_NAME.set(name, ownerToken);\n }\n },\n (error: unknown) => {\n if (!controller.signal.aborted) {\n controller.abort();\n console.warn(`[ReactWebMCP:useWebMCP] registerTool(\"${name}\") rejected:`, error);\n }\n }\n );\n } catch (error) {\n controller.abort();\n console.warn(`[ReactWebMCP:useWebMCP] registerTool(\"${name}\") rejected:`, error);\n return;\n }\n\n return () => {\n disposed = true;\n\n if (registered && TOOL_OWNER_BY_NAME.get(name) === ownerToken) {\n TOOL_OWNER_BY_NAME.delete(name);\n controller.abort();\n return;\n }\n\n if (!registered) {\n controller.abort();\n }\n };\n // Spread operator in dependencies intentionally allows consumers to trigger\n // re-registration with custom reactive inputs.\n }, [name, description, ...(deps ?? [])]);\n\n return {\n state,\n execute: stableExecute,\n reset,\n };\n}\n","import { useMemo, 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 * Note: This hook does not use an output schema, so the result will not include\n * `structuredContent` in the MCP response. Use {@link useWebMCP} directly with\n * `outputSchema` if you need structured output for MCP compliance.\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 {\n const getValueRef = useRef(getValue);\n getValueRef.current = getValue;\n const annotations = useMemo(\n () => ({\n title: `Context: ${name}`,\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: false,\n }),\n [name]\n );\n\n // Use default generics (no input/output schema) since context tools\n // don't define structured schemas. The handler returns T but it's\n // treated as `unknown` in the return type since no outputSchema is defined.\n return useWebMCP({\n name,\n description,\n annotations,\n // Cast to unknown since context tools return arbitrary types\n // that don't need to conform to a specific schema\n handler: async (_input: Record<string, unknown>) => {\n return getValueRef.current() as Record<string, unknown>;\n },\n formatOutput: (output) => {\n if (typeof output === 'string') {\n return output as string;\n }\n return JSON.stringify(output, null, 2);\n },\n });\n}\n","import type { InputSchema } from '@mcp-b/webmcp-types';\nimport { normalizeInputSchema } from '@mcp-b/webmcp-polyfill/schema';\nimport { useEffect, useRef, useState } from 'react';\nimport type {\n PromptMessage,\n ReactWebMCPInputSchema,\n WebMCPPromptConfig,\n WebMCPPromptReturn,\n} from './types.js';\nimport { getModelContext, type ModelContextSurface } from './model-context.js';\nimport { isZodSchema, zodToJsonSchema } from './zod-utils.js';\n\ntype PromptModelContext = ModelContextSurface & {\n registerPrompt: (descriptor: {\n name: string;\n description?: string;\n argsSchema?: InputSchema;\n get: (args: Record<string, unknown>) => Promise<{ messages: PromptMessage[] }>;\n }) => { unregister: () => void } | undefined;\n};\n\n/**\n * React hook for registering Model Context Protocol (MCP) prompts.\n *\n * This hook handles the complete lifecycle of an MCP prompt:\n * - Registers the prompt with `window.document.modelContext`\n * - Converts Zod schemas to JSON Schema for argument validation\n * - Automatically unregisters on component unmount\n *\n * @template TArgsSchema - Zod schema object defining argument types\n *\n * @param config - Configuration object for the prompt\n * @returns Object indicating registration status\n *\n * @public\n *\n * @example\n * Simple prompt without arguments:\n * ```tsx\n * function HelpPrompt() {\n * const { isRegistered } = useWebMCPPrompt({\n * name: 'help',\n * description: 'Get help with using the application',\n * get: async () => ({\n * messages: [{\n * role: 'user',\n * content: { type: 'text', text: 'How do I use this application?' }\n * }]\n * }),\n * });\n *\n * return <div>Help prompt {isRegistered ? 'ready' : 'loading'}</div>;\n * }\n * ```\n *\n * @example\n * Prompt with typed arguments:\n * ```tsx\n * function CodeReviewPrompt() {\n * const { isRegistered } = useWebMCPPrompt({\n * name: 'review_code',\n * description: 'Review code for best practices',\n * argsSchema: {\n * type: 'object',\n * properties: {\n * code: { type: 'string', description: 'The code to review' },\n * language: { type: 'string', description: 'Programming language' },\n * },\n * required: ['code'],\n * } as const,\n * get: async ({ code, language }) => ({\n * messages: [{\n * role: 'user',\n * content: {\n * type: 'text',\n * text: `Please review this ${language ?? ''} code:\\n\\n${code}`\n * }\n * }]\n * }),\n * });\n *\n * return <div>Code review prompt {isRegistered ? 'ready' : 'loading'}</div>;\n * }\n * ```\n */\nexport function useWebMCPPrompt<TArgsSchema extends ReactWebMCPInputSchema = InputSchema>(\n config: WebMCPPromptConfig<TArgsSchema>\n): WebMCPPromptReturn {\n const { name, description, argsSchema, get } = config;\n\n const [isRegistered, setIsRegistered] = useState(false);\n\n const getRef = useRef(get);\n\n useEffect(() => {\n getRef.current = get;\n }, [get]);\n\n useEffect(() => {\n const modelContext = getModelContext() as PromptModelContext | undefined;\n if (!modelContext) {\n console.warn(\n `[ReactWebMCP] window.document.modelContext is not available. Prompt \"${name}\" will not be registered.`\n );\n return;\n }\n\n const promptHandler = async (\n args: Record<string, unknown>\n ): Promise<{ messages: PromptMessage[] }> => {\n return getRef.current(args as never);\n };\n\n const resolvedArgsSchema = argsSchema\n ? isZodSchema(argsSchema)\n ? zodToJsonSchema(argsSchema)\n : normalizeInputSchema(argsSchema).inputSchema\n : undefined;\n\n let registration: { unregister: () => void } | undefined;\n try {\n registration = modelContext.registerPrompt({\n name,\n ...(description !== undefined && { description }),\n ...(resolvedArgsSchema && { argsSchema: resolvedArgsSchema }),\n get: promptHandler,\n });\n } catch (error) {\n setIsRegistered(false);\n throw error;\n }\n\n if (!registration) {\n console.warn(`[ReactWebMCP] Prompt \"${name}\" did not return a registration handle.`);\n setIsRegistered(false);\n return;\n }\n\n setIsRegistered(true);\n\n return () => {\n registration.unregister();\n setIsRegistered(false);\n };\n }, [name, description, argsSchema]);\n\n return {\n isRegistered,\n };\n}\n","import { useEffect, useRef, useState } from 'react';\nimport { getModelContext, type ModelContextSurface } from './model-context.js';\nimport type { ResourceContents, WebMCPResourceConfig, WebMCPResourceReturn } from './types.js';\n\ntype ResourceModelContext = ModelContextSurface & {\n registerResource: (descriptor: {\n uri: string;\n name: string;\n description?: string;\n mimeType?: string;\n read: (uri: URL, params?: Record<string, string>) => Promise<{ contents: ResourceContents[] }>;\n }) => { unregister: () => void } | undefined;\n};\n\n/**\n * React hook for registering Model Context Protocol (MCP) resources.\n *\n * This hook handles the complete lifecycle of an MCP resource:\n * - Registers the resource with `window.document.modelContext`\n * - Supports both static URIs and URI templates with parameters\n * - Automatically unregisters on component unmount\n *\n * @param config - Configuration object for the resource\n * @returns Object indicating registration status\n *\n * @public\n *\n * @example\n * Static resource:\n * ```tsx\n * function AppSettingsResource() {\n * const { isRegistered } = useWebMCPResource({\n * uri: 'config://app-settings',\n * name: 'App Settings',\n * description: 'Application configuration',\n * mimeType: 'application/json',\n * read: async (uri) => ({\n * contents: [{\n * uri: uri.href,\n * text: JSON.stringify({ theme: 'dark', language: 'en' })\n * }]\n * }),\n * });\n *\n * return <div>Settings resource {isRegistered ? 'ready' : 'loading'}</div>;\n * }\n * ```\n *\n * @example\n * Dynamic resource with URI template:\n * ```tsx\n * function UserProfileResource() {\n * const { isRegistered } = useWebMCPResource({\n * uri: 'user://{userId}/profile',\n * name: 'User Profile',\n * description: 'User profile data by ID',\n * mimeType: 'application/json',\n * read: async (uri, params) => {\n * const userId = params?.userId ?? '';\n * const profile = await fetchUserProfile(userId);\n * return {\n * contents: [{\n * uri: uri.href,\n * text: JSON.stringify(profile)\n * }]\n * };\n * },\n * });\n *\n * return <div>User profile resource {isRegistered ? 'ready' : 'loading'}</div>;\n * }\n * ```\n */\nexport function useWebMCPResource(config: WebMCPResourceConfig): WebMCPResourceReturn {\n const { uri, name, description, mimeType, read } = config;\n\n const [isRegistered, setIsRegistered] = useState(false);\n\n const readRef = useRef(read);\n\n useEffect(() => {\n readRef.current = read;\n }, [read]);\n\n useEffect(() => {\n const modelContext = getModelContext() as ResourceModelContext | undefined;\n if (!modelContext) {\n console.warn(\n `[ReactWebMCP] window.document.modelContext is not available. Resource \"${uri}\" will not be registered.`\n );\n return;\n }\n\n const resourceHandler = async (\n resolvedUri: URL,\n params?: Record<string, string>\n ): Promise<{ contents: ResourceContents[] }> => {\n return readRef.current(resolvedUri, params);\n };\n\n let registration: { unregister: () => void } | undefined;\n try {\n registration = modelContext.registerResource({\n uri,\n name,\n ...(description !== undefined && { description }),\n ...(mimeType !== undefined && { mimeType }),\n read: resourceHandler,\n });\n } catch (error) {\n setIsRegistered(false);\n throw error;\n }\n\n if (!registration) {\n console.warn(`[ReactWebMCP] Resource \"${uri}\" did not return a registration handle.`);\n setIsRegistered(false);\n return;\n }\n\n setIsRegistered(true);\n\n return () => {\n registration.unregister();\n setIsRegistered(false);\n };\n }, [uri, name, description, mimeType]);\n\n return {\n isRegistered,\n };\n}\n","import type { ElicitationParams, ElicitationResult } from '@mcp-b/webmcp-types';\nimport { useCallback, useState } from 'react';\nimport { getModelContext, type ModelContextSurface } from './model-context.js';\n\ntype ElicitationModelContext = ModelContextSurface & {\n elicitInput: (params: ElicitationParams) => Promise<ElicitationResult>;\n};\n\n/**\n * State for elicitation requests, tracking the current request and results.\n */\nexport interface ElicitationState {\n /** Whether an elicitation request is currently in progress */\n isLoading: boolean;\n /** The last elicitation result received */\n result: ElicitationResult | null;\n /** Any error that occurred during the last request */\n error: Error | null;\n /** Total number of requests made */\n requestCount: number;\n}\n\n/**\n * Configuration options for the useElicitation hook.\n */\nexport interface UseElicitationConfig {\n /**\n * Optional callback invoked when an elicitation request completes successfully.\n */\n onSuccess?: (result: ElicitationResult) => void;\n\n /**\n * Optional callback invoked when an elicitation request fails.\n */\n onError?: (error: Error) => void;\n}\n\n/**\n * Return value from the useElicitation hook.\n */\nexport interface UseElicitationReturn {\n /** Current state of elicitation */\n state: ElicitationState;\n /** Function to request user input from the connected client */\n elicitInput: (params: ElicitationParams) => Promise<ElicitationResult>;\n /** Reset the state */\n reset: () => void;\n}\n\n/**\n * React hook for requesting user input from the connected MCP client.\n *\n * Elicitation allows the server (webpage) to request user input from the\n * connected client. This is useful when the page needs additional information\n * from the user, such as API keys, configuration options, or confirmations.\n *\n * There are two modes:\n * 1. **Form mode**: For non-sensitive data collection using a schema-driven form.\n * 2. **URL mode**: For sensitive data collection via a web URL (API keys, OAuth, etc.).\n *\n * @param config - Optional configuration including callbacks\n * @returns Object containing state and the elicitInput function\n *\n * @example Form elicitation:\n * ```tsx\n * function ConfigForm() {\n * const { state, elicitInput } = useElicitation({\n * onSuccess: (result) => console.log('Got input:', result),\n * onError: (error) => console.error('Elicitation failed:', error),\n * });\n *\n * const handleConfigure = async () => {\n * const result = await elicitInput({\n * message: 'Please provide your configuration',\n * requestedSchema: {\n * type: 'object',\n * properties: {\n * apiKey: { type: 'string', title: 'API Key', description: 'Your API key' },\n * model: { type: 'string', enum: ['gpt-4', 'gpt-3.5'], title: 'Model' }\n * },\n * required: ['apiKey']\n * }\n * });\n *\n * if (result.action === 'accept') {\n * console.log('Config:', result.content);\n * }\n * };\n *\n * return (\n * <button onClick={handleConfigure} disabled={state.isLoading}>\n * Configure\n * </button>\n * );\n * }\n * ```\n *\n * @example URL elicitation (for sensitive data):\n * ```tsx\n * const { elicitInput } = useElicitation();\n *\n * const handleOAuth = async () => {\n * const result = await elicitInput({\n * mode: 'url',\n * message: 'Please authenticate with GitHub',\n * elicitationId: 'github-oauth-123',\n * url: 'https://github.com/login/oauth/authorize?client_id=...'\n * });\n *\n * if (result.action === 'accept') {\n * console.log('OAuth completed');\n * }\n * };\n * ```\n */\nexport function useElicitation(config: UseElicitationConfig = {}): UseElicitationReturn {\n const { onSuccess, onError } = config;\n\n const [state, setState] = useState<ElicitationState>({\n isLoading: false,\n result: null,\n error: null,\n requestCount: 0,\n });\n\n const reset = useCallback(() => {\n setState({\n isLoading: false,\n result: null,\n error: null,\n requestCount: 0,\n });\n }, []);\n\n const elicitInput = useCallback(\n async (params: ElicitationParams): Promise<ElicitationResult> => {\n const mc = getModelContext() as ElicitationModelContext | undefined;\n if (!mc) {\n throw new Error('document.modelContext is not available');\n }\n\n setState((prev) => ({\n ...prev,\n isLoading: true,\n error: null,\n }));\n\n try {\n const result: ElicitationResult = await mc.elicitInput(params);\n\n setState((prev) => ({\n isLoading: false,\n result,\n error: null,\n requestCount: prev.requestCount + 1,\n }));\n\n onSuccess?.(result);\n return result;\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n\n setState((prev) => ({\n ...prev,\n isLoading: false,\n error,\n }));\n\n onError?.(error);\n throw error;\n }\n },\n [onSuccess, onError]\n );\n\n return {\n state,\n elicitInput,\n reset,\n };\n}\n\n// Also export with the old name for backwards compatibility during migration\nexport { useElicitation as useElicitationHandler };\nexport type { ElicitationState as ElicitationHandlerState };\nexport type { UseElicitationConfig as UseElicitationHandlerConfig };\nexport type { UseElicitationReturn as UseElicitationHandlerReturn };\n","import type { SamplingRequestParams, SamplingResult } from '@mcp-b/webmcp-ts-sdk';\nimport { useCallback, useState } from 'react';\nimport { getModelContext, type ModelContextSurface } from './model-context.js';\n\ntype SamplingModelContext = ModelContextSurface & {\n createMessage: (params: SamplingRequestParams) => Promise<SamplingResult>;\n};\n\n/**\n * State for sampling requests, tracking the current request and results.\n */\nexport interface SamplingState {\n /** Whether a sampling request is currently in progress */\n isLoading: boolean;\n /** The last sampling result received */\n result: SamplingResult | null;\n /** Any error that occurred during the last request */\n error: Error | null;\n /** Total number of requests made */\n requestCount: number;\n}\n\n/**\n * Configuration options for the useSampling hook.\n */\nexport interface UseSamplingConfig {\n /**\n * Optional callback invoked when a sampling request completes successfully.\n */\n onSuccess?: (result: SamplingResult) => void;\n\n /**\n * Optional callback invoked when a sampling request fails.\n */\n onError?: (error: Error) => void;\n}\n\n/**\n * Return value from the useSampling hook.\n */\nexport interface UseSamplingReturn {\n /** Current state of sampling */\n state: SamplingState;\n /** Function to request LLM completion from the connected client */\n createMessage: (params: SamplingRequestParams) => Promise<SamplingResult>;\n /** Reset the state */\n reset: () => void;\n}\n\n/**\n * React hook for requesting LLM completions from the connected MCP client.\n *\n * Sampling allows the server (webpage) to request LLM completions from the\n * connected client. This is useful when the page needs AI capabilities like\n * summarization, generation, or analysis.\n *\n * @param config - Optional configuration including callbacks\n * @returns Object containing state and the createMessage function\n *\n * @example Basic usage:\n * ```tsx\n * function AIAssistant() {\n * const { state, createMessage } = useSampling({\n * onSuccess: (result) => console.log('Got response:', result),\n * onError: (error) => console.error('Sampling failed:', error),\n * });\n *\n * const handleAsk = async () => {\n * const result = await createMessage({\n * messages: [\n * { role: 'user', content: { type: 'text', text: 'What is 2+2?' } }\n * ],\n * maxTokens: 100,\n * });\n * console.log(result.content);\n * };\n *\n * return (\n * <div>\n * <button onClick={handleAsk} disabled={state.isLoading}>\n * Ask AI\n * </button>\n * {state.result && <p>{JSON.stringify(state.result.content)}</p>}\n * </div>\n * );\n * }\n * ```\n */\nexport function useSampling(config: UseSamplingConfig = {}): UseSamplingReturn {\n const { onSuccess, onError } = config;\n\n const [state, setState] = useState<SamplingState>({\n isLoading: false,\n result: null,\n error: null,\n requestCount: 0,\n });\n\n const reset = useCallback(() => {\n setState({\n isLoading: false,\n result: null,\n error: null,\n requestCount: 0,\n });\n }, []);\n\n const createMessage = useCallback(\n async (params: SamplingRequestParams): Promise<SamplingResult> => {\n const modelContext = getModelContext() as SamplingModelContext | undefined;\n if (!modelContext) {\n throw new Error('document.modelContext is not available');\n }\n\n setState((prev) => ({\n ...prev,\n isLoading: true,\n error: null,\n }));\n\n try {\n const result = await modelContext.createMessage(params);\n\n setState((prev) => ({\n isLoading: false,\n result,\n error: null,\n requestCount: prev.requestCount + 1,\n }));\n\n onSuccess?.(result);\n return result;\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n\n setState((prev) => ({\n ...prev,\n isLoading: false,\n error,\n }));\n\n onError?.(error);\n throw error;\n }\n },\n [onSuccess, onError]\n );\n\n return {\n state,\n createMessage,\n reset,\n };\n}\n\n// Also export with the old name for backwards compatibility during migration\nexport { useSampling as useSamplingHandler };\nexport type { SamplingState as SamplingHandlerState };\nexport type { UseSamplingConfig as UseSamplingHandlerConfig };\nexport type { UseSamplingReturn as UseSamplingHandlerReturn };\n","import {\n type Client,\n type Tool as McpTool,\n type RequestOptions,\n type Resource,\n ResourceListChangedNotificationSchema,\n type ServerCapabilities,\n ToolListChangedNotificationSchema,\n type Transport,\n} from '@mcp-b/webmcp-ts-sdk';\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);\nconst EMPTY_REQUEST_OPTS: RequestOptions = {};\nconst TOOL_FLOW_TRACE_KEY = 'WEBMCP_TRACE_TOOL_FLOW';\n\nfunction emitForcedToolFlowTrace(event: string, details: Record<string, unknown>): void {\n const consoleRef = globalThis.console;\n if (!consoleRef) {\n return;\n }\n\n const method = consoleRef.debug ?? consoleRef.log;\n if (typeof method !== 'function') {\n return;\n }\n\n method.call(consoleRef, '[ReactWebMCP:McpClientProvider:ToolFlow]', event, details);\n}\n\nfunction isToolFlowTraceEnabled(): boolean {\n if (typeof window === 'undefined') {\n return false;\n }\n\n try {\n return window.localStorage.getItem(TOOL_FLOW_TRACE_KEY) === '1';\n } catch {\n return false;\n }\n}\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 const requestOpts = opts ?? EMPTY_REQUEST_OPTS;\n\n const connectionStateRef = useRef<'disconnected' | 'connecting' | 'connected'>('disconnected');\n const toolFlowSequenceRef = useRef(0);\n const logToolFlow = useCallback((event: string, details: Record<string, unknown> = {}) => {\n const sequence = ++toolFlowSequenceRef.current;\n const message = `[${sequence}] ${event}`;\n\n if (isToolFlowTraceEnabled()) {\n emitForcedToolFlowTrace(message, details);\n }\n }, []);\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('[ReactWebMCP:McpClientProvider]', '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 logToolFlow('listTools:capability_missing', {});\n setTools([]);\n return;\n }\n\n const startedAt = Date.now();\n logToolFlow('listTools:start', {\n hasToolsCapability: Boolean(serverCapabilities.tools),\n });\n try {\n const response = await client.listTools();\n setTools(response.tools);\n logToolFlow('listTools:success', {\n durationMs: Date.now() - startedAt,\n toolCount: response.tools.length,\n });\n } catch (e) {\n logToolFlow('listTools:error', {\n durationMs: Date.now() - startedAt,\n errorMessage: e instanceof Error ? e.message : String(e),\n });\n console.error('[ReactWebMCP:McpClientProvider]', 'Error fetching tools:', e);\n throw e;\n }\n }, [client, logToolFlow]);\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, requestOpts);\n const caps = client.getServerCapabilities();\n setIsConnected(true);\n setCapabilities(caps || null);\n connectionStateRef.current = 'connected';\n logToolFlow('reconnect:connected', {\n hasToolsListChanged: Boolean(caps?.tools?.listChanged),\n });\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, requestOpts, fetchResourcesInternal, fetchToolsInternal, logToolFlow]);\n\n useEffect(() => {\n if (!isConnected || !client) {\n return;\n }\n\n const serverCapabilities = client.getServerCapabilities();\n\n const handleResourcesChanged = () => {\n fetchResourcesInternal().catch((error) => {\n console.error(\n '[ReactWebMCP:McpClientProvider]',\n 'Failed to refresh resources after list_changed:',\n error\n );\n });\n };\n\n const handleToolsChanged = () => {\n logToolFlow('notification:tools/list_changed', {});\n fetchToolsInternal().catch((error) => {\n console.error(\n '[ReactWebMCP:McpClientProvider]',\n 'Failed to refresh tools after list_changed:',\n error\n );\n });\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 // Re-fetch after setting up handlers to catch any changes that occurred\n // during the gap between initial fetch and handler setup\n Promise.all([fetchResourcesInternal(), fetchToolsInternal()]).catch((error) => {\n console.error(\n '[ReactWebMCP:McpClientProvider]',\n 'Failed to refresh tools/resources after handler registration:',\n error\n );\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, logToolFlow]);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: intentional - reconnect when client/transport props change\n useEffect(() => {\n // Initial connection - reconnect() has its own guard to prevent concurrent connections\n reconnect().catch((err) => {\n console.error('[ReactWebMCP:McpClientProvider]', '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 }, [client, transport, reconnect]);\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":"2lBAKA,SAAgB,GAAmD,CACjE,GAAI,OAAO,OAAW,IACpB,OAGF,IAAM,EAAmB,OAAO,SAAyC,aACnE,EAAoB,OAAO,UAA2C,aAC5E,OAAO,GAAmB,ECH5B,SAAS,EAAS,EAAkD,CAClE,OAAyB,OAAO,GAAU,YAAnC,GAA+C,CAAC,MAAM,QAAQ,EAAM,CAG7E,SAAgB,EAAU,EAAyC,CACjE,OAAO,EAAS,EAAO,GAAK,SAAU,GAAU,SAAU,GAG5D,SAAgB,EAAY,EAA4C,CAKtE,MAJI,CAAC,EAAS,EAAO,EAAI,EAAU,EAAO,CACjC,GAGF,EAAsB,EAA4B,GAAK,IAAA,GAGhE,SAAgB,EAAgB,EAAgC,CAE9D,IAAM,EADa,EAAsB,EACb,GAAK,EAAU,EAAO,CAAI,EAAuB,IAAA,IAC7E,GAAI,CAAC,EACH,MAAU,MAAM,6CAA6C,CAG/D,OAAO,EAAmB,EAAW,CACnC,aAAc,GACd,aAAc,QACf,CAAC,CCNJ,SAAS,EAAoB,EAAyB,CAIpD,OAHI,OAAO,GAAW,SACb,EAEF,KAAK,UAAU,EAAQ,KAAM,EAAE,CAGxC,MAAM,EAAqB,IAAI,IACzB,EAA8B,CAClC,QACA,UACA,UACA,OACA,SACA,SACA,SACD,CACK,EAAiC,CAAC,OAAQ,QAAS,QAAS,QAAS,MAAM,CAEjF,SAAS,EACP,EACuD,CACvD,OACE,OAAO,GAAU,UACjB,EAA4B,SAAS,EAAsD,CAI/F,SAAS,EAAwB,EAAuB,CACtD,MAAU,MAAM,6BAA6B,IAAS,CAGxD,SAAS,EACP,EACA,EAAO,IACkC,CACpC,EAAc,EAAM,EACvB,EAAwB,GAAG,EAAK,+BAA+B,CAGjE,IAAK,IAAM,KAAO,EACZ,KAAO,GACT,EAAwB,GAAG,EAAK,GAAG,EAAI,8CAA8C,CAIzF,IAAM,EACJ,OAAO,EAAM,MAAS,SAClB,CAAC,EAAM,KAAK,CACZ,MAAM,QAAQ,EAAM,KAAK,CACvB,EAAM,KACN,IAAA,IAEN,CAAC,GAAa,QACd,CAAC,EAAY,MAAO,GAAe,EAA0B,EAAW,CAAC,GAEzE,EAAwB,GAAG,EAAK,6CAA6C,CAG/E,IAAM,EAAgB,EAAM,SAe5B,GAbE,IAAkB,IAAA,KACjB,CAAC,MAAM,QAAQ,EAAc,EAAI,EAAc,KAAM,GAAU,OAAO,GAAU,SAAS,GAE1F,EAAwB,GAAG,EAAK,uCAAuC,CAGrE,EAAY,SAAS,QAAQ,GAC1B,EAAc,EAAM,MAAM,EAC7B,EAAwB,GAAG,EAAK,sDAAsD,CAExF,EAA0B,EAAM,MAAO,GAAG,EAAK,QAAQ,EAGrD,EAAY,SAAS,SAAS,CAAE,CAKlC,GAJI,EAAM,aAAe,IAAA,IAAa,CAAC,EAAc,EAAM,WAAW,EACpE,EAAwB,GAAG,EAAK,+BAA+B,CAG7D,EAAc,EAAM,WAAW,CACjC,IAAK,GAAM,CAAC,EAAK,KAAmB,OAAO,QAAQ,EAAM,WAAW,CAClE,EAA0B,EAAgB,GAAG,EAAK,cAAc,IAAM,CAKxE,EAAM,uBAAyB,IAAA,IAC/B,OAAO,EAAM,sBAAyB,WAEtC,EAA0B,EAAM,qBAAsB,GAAG,EAAK,uBAAuB,EAK3F,MAAM,EAA4B,OAAO,OAAW,IAAc,EAAkB,EAqDpF,SAAgB,EAId,EACA,EAC2C,CAG3C,GAAM,CACJ,OACA,cACA,cACA,eACA,cACA,UACA,eAAe,EACf,YACA,WACE,EAEE,CAAC,EAAO,GAAY,EAAsC,CAC9D,YAAa,GACb,WAAY,KACZ,MAAO,KACP,eAAgB,EACjB,CAAC,CAEI,EAAa,EAAO,EAAQ,CAC5B,EAAe,EAAO,EAAU,CAChC,EAAa,EAAO,EAAQ,CAC5B,EAAkB,EAAO,EAAa,CACtC,EAAe,EAAO,GAAK,CAEjC,MAAgC,CAC9B,EAAW,QAAU,EACrB,EAAa,QAAU,EACvB,EAAW,QAAU,EACrB,EAAgB,QAAU,GACzB,CAAC,EAAS,EAAW,EAAS,EAAa,CAAC,CAG/C,OACE,EAAa,QAAU,OACV,CACX,EAAa,QAAU,KAExB,EAAE,CAAC,CASN,IAAM,EAAU,EAAY,KAAO,IAAoC,CACrE,EAAU,IAAU,CAClB,GAAG,EACH,YAAa,GACb,MAAO,KACR,EAAE,CAEH,GAAI,CACF,IAAM,EAAS,MAAM,EAAW,QAAQ,EAAM,CAgB9C,OAbI,EAAa,SACf,EAAU,IAAU,CAClB,YAAa,GACb,WAAY,EACZ,MAAO,KACP,eAAgB,EAAK,eAAiB,EACvC,EAAE,CAGD,EAAa,SACf,EAAa,QAAQ,EAAQ,EAAM,CAG9B,QACA,EAAO,CACd,IAAM,EAAM,aAAiB,MAAQ,EAAY,MAAM,OAAO,EAAM,CAAC,CAerE,MAZI,EAAa,SACf,EAAU,IAAU,CAClB,GAAG,EACH,YAAa,GACb,MAAO,EACR,EAAE,CAGD,EAAW,SACb,EAAW,QAAQ,EAAK,EAAM,CAG1B,IAEP,EAAE,CAAC,CACA,EAAa,EAAO,EAAQ,CAElC,MAAgB,CACd,EAAW,QAAU,GACpB,CAAC,EAAQ,CAAC,CAEb,IAAM,EAAgB,EACnB,GAAoC,EAAW,QAAQ,EAAM,CAC9D,EAAE,CACH,CAKK,EAAQ,MAAkB,CAC9B,EAAS,CACP,YAAa,GACb,WAAY,KACZ,MAAO,KACP,eAAgB,EACjB,CAAC,EACD,EAAE,CAAC,CAuHN,OArHA,MAAgB,CACd,IAAM,EAAe,GAAiB,CACtC,GAAI,CAAC,EAAc,CACjB,QAAQ,KACN,0BACA,SAAS,EAAK,0CACf,CACD,OAGF,IAAM,EAAsB,EAAY,EAAY,CAChD,EAAgB,EAAY,CAC5B,EAAqB,EAAY,CAAC,YAClC,EACJ,GAAI,EAAc,CAChB,IAAM,EACJ,EAAY,EAAa,EAAI,EAAU,EAAa,CAChD,EAAgB,EAAa,CAC7B,EACN,EAA0B,EAAW,CACrC,EAAuB,EAEzB,IAAM,EAAa,KAAO,IAA4C,CACpE,GAAI,CACF,IAAM,EAAS,MAAM,QAAQ,MAAM,EAAW,QAAS,IAAA,GAAW,CAAC,EAAM,CAAC,CAGpE,EAA2B,CAC/B,QAAS,CACP,CACE,KAAM,OACN,KANkB,EAAgB,QAAQ,EAMrB,CACtB,CACF,CACF,CAED,GAAI,EAAsB,CACxB,IAAM,EAAoB,EAAY,EAAO,CAC7C,GAAI,IAAsB,IAAA,GACxB,MAAU,MACR,SAAS,EAAK,0EACf,CAEH,EAAS,kBAAoB,EAG/B,OAAO,QACA,EAAO,CAGd,MAAO,CACL,QAAS,CACP,CACE,KAAM,OACN,KAAM,UANS,aAAiB,MAAQ,EAAM,QAAU,OAAO,EAAM,GAOtE,CACF,CACD,QAAS,GACV,GAIC,EAAa,OAAO,EAAK,CACzB,EAAgE,CACpE,OACA,cACA,YAAa,EACb,GAAI,GAAwB,CAAE,aAAc,EAAsB,CAClE,GAAI,GAAe,CAAE,cAAa,CAClC,QAAS,EACV,CACK,EAAa,IAAI,gBACnB,EAAa,GACb,EAAW,GAEf,GAAI,CACF,IAAM,EAAiB,EAAa,aAAa,EAAgB,CAC/D,OAAQ,EAAW,OACpB,CAAC,CAEF,QAAa,QAAQ,EAAe,CAAC,SAC7B,CACA,CAAC,GAAY,CAAC,EAAW,OAAO,UAClC,EAAa,GACb,EAAmB,IAAI,EAAM,EAAW,GAG3C,GAAmB,CACb,EAAW,OAAO,UACrB,EAAW,OAAO,CAClB,QAAQ,KAAK,yCAAyC,EAAK,cAAe,EAAM,GAGrF,OACM,EAAO,CACd,EAAW,OAAO,CAClB,QAAQ,KAAK,yCAAyC,EAAK,cAAe,EAAM,CAChF,OAGF,UAAa,CAGX,GAFA,EAAW,GAEP,GAAc,EAAmB,IAAI,EAAK,GAAK,EAAY,CAC7D,EAAmB,OAAO,EAAK,CAC/B,EAAW,OAAO,CAClB,OAGG,GACH,EAAW,OAAO,GAKrB,CAAC,EAAM,EAAa,GAAI,GAAQ,EAAE,CAAE,CAAC,CAEjC,CACL,QACA,QAAS,EACT,QACD,CC/VH,SAAgB,EACd,EACA,EACA,EACc,CACd,IAAM,EAAc,EAAO,EAAS,CAgBpC,MAfA,GAAY,QAAU,EAef,EAAU,CACf,OACA,cACA,YAjBkB,OACX,CACL,MAAO,YAAY,IACnB,aAAc,GACd,eAAgB,GAChB,gBAAiB,GACjB,cAAe,GAChB,EACD,CAAC,EAAK,CASK,CAGX,QAAS,KAAO,IACP,EAAY,SAAS,CAE9B,aAAe,GACT,OAAO,GAAW,SACb,EAEF,KAAK,UAAU,EAAQ,KAAM,EAAE,CAEzC,CAAC,CCpBJ,SAAgB,EACd,EACoB,CACpB,GAAM,CAAE,OAAM,cAAa,aAAY,OAAQ,EAEzC,CAAC,EAAc,GAAmB,EAAS,GAAM,CAEjD,EAAS,EAAO,EAAI,CAsD1B,OApDA,MAAgB,CACd,EAAO,QAAU,GAChB,CAAC,EAAI,CAAC,CAET,MAAgB,CACd,IAAM,EAAe,GAAiB,CACtC,GAAI,CAAC,EAAc,CACjB,QAAQ,KACN,wEAAwE,EAAK,2BAC9E,CACD,OAGF,IAAM,EAAgB,KACpB,IAEO,EAAO,QAAQ,EAAc,CAGhC,EAAqB,EACvB,EAAY,EAAW,CACrB,EAAgB,EAAW,CAC3B,EAAqB,EAAW,CAAC,YACnC,IAAA,GAEA,EACJ,GAAI,CACF,EAAe,EAAa,eAAe,CACzC,OACA,GAAI,IAAgB,IAAA,IAAa,CAAE,cAAa,CAChD,GAAI,GAAsB,CAAE,WAAY,EAAoB,CAC5D,IAAK,EACN,CAAC,OACK,EAAO,CAEd,MADA,EAAgB,GAAM,CAChB,EAGR,GAAI,CAAC,EAAc,CACjB,QAAQ,KAAK,yBAAyB,EAAK,yCAAyC,CACpF,EAAgB,GAAM,CACtB,OAKF,OAFA,EAAgB,GAAK,KAER,CACX,EAAa,YAAY,CACzB,EAAgB,GAAM,GAEvB,CAAC,EAAM,EAAa,EAAW,CAAC,CAE5B,CACL,eACD,CC3EH,SAAgB,EAAkB,EAAoD,CACpF,GAAM,CAAE,MAAK,OAAM,cAAa,WAAU,QAAS,EAE7C,CAAC,EAAc,GAAmB,EAAS,GAAM,CAEjD,EAAU,EAAO,EAAK,CAkD5B,OAhDA,MAAgB,CACd,EAAQ,QAAU,GACjB,CAAC,EAAK,CAAC,CAEV,MAAgB,CACd,IAAM,EAAe,GAAiB,CACtC,GAAI,CAAC,EAAc,CACjB,QAAQ,KACN,0EAA0E,EAAI,2BAC/E,CACD,OAGF,IAAM,EAAkB,MACtB,EACA,IAEO,EAAQ,QAAQ,EAAa,EAAO,CAGzC,EACJ,GAAI,CACF,EAAe,EAAa,iBAAiB,CAC3C,MACA,OACA,GAAI,IAAgB,IAAA,IAAa,CAAE,cAAa,CAChD,GAAI,IAAa,IAAA,IAAa,CAAE,WAAU,CAC1C,KAAM,EACP,CAAC,OACK,EAAO,CAEd,MADA,EAAgB,GAAM,CAChB,EAGR,GAAI,CAAC,EAAc,CACjB,QAAQ,KAAK,2BAA2B,EAAI,yCAAyC,CACrF,EAAgB,GAAM,CACtB,OAKF,OAFA,EAAgB,GAAK,KAER,CACX,EAAa,YAAY,CACzB,EAAgB,GAAM,GAEvB,CAAC,EAAK,EAAM,EAAa,EAAS,CAAC,CAE/B,CACL,eACD,CCfH,SAAgB,EAAe,EAA+B,EAAE,CAAwB,CACtF,GAAM,CAAE,YAAW,WAAY,EAEzB,CAAC,EAAO,GAAY,EAA2B,CACnD,UAAW,GACX,OAAQ,KACR,MAAO,KACP,aAAc,EACf,CAAC,CAEI,EAAQ,MAAkB,CAC9B,EAAS,CACP,UAAW,GACX,OAAQ,KACR,MAAO,KACP,aAAc,EACf,CAAC,EACD,EAAE,CAAC,CA2CN,MAAO,CACL,QACA,YA3CkB,EAClB,KAAO,IAA0D,CAC/D,IAAM,EAAK,GAAiB,CAC5B,GAAI,CAAC,EACH,MAAU,MAAM,yCAAyC,CAG3D,EAAU,IAAU,CAClB,GAAG,EACH,UAAW,GACX,MAAO,KACR,EAAE,CAEH,GAAI,CACF,IAAM,EAA4B,MAAM,EAAG,YAAY,EAAO,CAU9D,OARA,EAAU,IAAU,CAClB,UAAW,GACX,SACA,MAAO,KACP,aAAc,EAAK,aAAe,EACnC,EAAE,CAEH,IAAY,EAAO,CACZ,QACA,EAAK,CACZ,IAAM,EAAQ,aAAe,MAAQ,EAAU,MAAM,OAAO,EAAI,CAAC,CASjE,MAPA,EAAU,IAAU,CAClB,GAAG,EACH,UAAW,GACX,QACD,EAAE,CAEH,IAAU,EAAM,CACV,IAGV,CAAC,EAAW,EAAQ,CAKT,CACX,QACD,CC3FH,SAAgB,EAAY,EAA4B,EAAE,CAAqB,CAC7E,GAAM,CAAE,YAAW,WAAY,EAEzB,CAAC,EAAO,GAAY,EAAwB,CAChD,UAAW,GACX,OAAQ,KACR,MAAO,KACP,aAAc,EACf,CAAC,CAEI,EAAQ,MAAkB,CAC9B,EAAS,CACP,UAAW,GACX,OAAQ,KACR,MAAO,KACP,aAAc,EACf,CAAC,EACD,EAAE,CAAC,CA2CN,MAAO,CACL,QACA,cA3CoB,EACpB,KAAO,IAA2D,CAChE,IAAM,EAAe,GAAiB,CACtC,GAAI,CAAC,EACH,MAAU,MAAM,yCAAyC,CAG3D,EAAU,IAAU,CAClB,GAAG,EACH,UAAW,GACX,MAAO,KACR,EAAE,CAEH,GAAI,CACF,IAAM,EAAS,MAAM,EAAa,cAAc,EAAO,CAUvD,OARA,EAAU,IAAU,CAClB,UAAW,GACX,SACA,MAAO,KACP,aAAc,EAAK,aAAe,EACnC,EAAE,CAEH,IAAY,EAAO,CACZ,QACA,EAAK,CACZ,IAAM,EAAQ,aAAe,MAAQ,EAAU,MAAM,OAAO,EAAI,CAAC,CASjE,MAPA,EAAU,IAAU,CAClB,GAAG,EACH,UAAW,GACX,QACD,EAAE,CAEH,IAAU,EAAM,CACV,IAGV,CAAC,EAAW,EAAQ,CAKP,CACb,QACD,CCnHH,MAAM,EAAmB,EAA4C,KAAK,CACpE,EAAqC,EAAE,CAG7C,SAAS,EAAwB,EAAe,EAAwC,CACtF,IAAM,EAAa,WAAW,QAC9B,GAAI,CAAC,EACH,OAGF,IAAM,EAAS,EAAW,OAAS,EAAW,IAC1C,OAAO,GAAW,YAItB,EAAO,KAAK,EAAY,2CAA4C,EAAO,EAAQ,CAGrF,SAAS,GAAkC,CACzC,GAAI,OAAO,OAAW,IACpB,MAAO,GAGT,GAAI,CACF,OAAO,OAAO,aAAa,QAAQ,yBAAoB,GAAK,SACtD,CACN,MAAO,IAmGX,SAAgB,EAAkB,CAChC,WACA,SACA,YACA,QACuC,CACvC,GAAM,CAAC,EAAW,GAAgB,EAAqB,EAAE,CAAC,CACpD,CAAC,EAAO,GAAY,EAAoB,EAAE,CAAC,CAC3C,CAAC,EAAW,GAAgB,EAAkB,GAAM,CACpD,CAAC,EAAO,GAAY,EAAuB,KAAK,CAChD,CAAC,EAAa,GAAkB,EAAkB,GAAM,CACxD,CAAC,EAAc,GAAmB,EAAoC,KAAK,CAC3E,EAAc,GAAQ,EAEtB,EAAqB,EAAoD,eAAe,CACxF,EAAsB,EAAO,EAAE,CAC/B,EAAc,GAAa,EAAe,EAAmC,EAAE,GAAK,CAExF,IAAM,EAAU,IAAI,EADD,EAAoB,QACV,IAAI,IAE7B,GAAwB,EAC1B,EAAwB,EAAS,EAAQ,EAE1C,EAAE,CAAC,CAMA,EAAyB,EAAY,SAAY,CAChD,KAGL,IAAI,CADuB,EAAO,uBACX,EAAE,UAAW,CAClC,EAAa,EAAE,CAAC,CAChB,OAGF,GAAI,CAEF,GAAa,MADU,EAAO,eAAe,EACvB,UAAU,OACzB,EAAG,CAEV,MADA,QAAQ,MAAM,kCAAmC,4BAA6B,EAAE,CAC1E,KAEP,CAAC,EAAO,CAAC,CAMN,EAAqB,EAAY,SAAY,CACjD,GAAI,CAAC,EAAQ,OAEb,IAAM,EAAqB,EAAO,uBAAuB,CACzD,GAAI,CAAC,GAAoB,MAAO,CAC9B,EAAY,+BAAgC,EAAE,CAAC,CAC/C,EAAS,EAAE,CAAC,CACZ,OAGF,IAAM,EAAY,KAAK,KAAK,CAC5B,EAAY,kBAAmB,CAC7B,mBAAoB,EAAQ,EAAmB,MAChD,CAAC,CACF,GAAI,CACF,IAAM,EAAW,MAAM,EAAO,WAAW,CACzC,EAAS,EAAS,MAAM,CACxB,EAAY,oBAAqB,CAC/B,WAAY,KAAK,KAAK,CAAG,EACzB,UAAW,EAAS,MAAM,OAC3B,CAAC,OACK,EAAG,CAMV,MALA,EAAY,kBAAmB,CAC7B,WAAY,KAAK,KAAK,CAAG,EACzB,aAAc,aAAa,MAAQ,EAAE,QAAU,OAAO,EAAE,CACzD,CAAC,CACF,QAAQ,MAAM,kCAAmC,wBAAyB,EAAE,CACtE,IAEP,CAAC,EAAQ,EAAY,CAAC,CAMnB,EAAY,EAAY,SAAY,CACxC,GAAI,CAAC,GAAU,CAAC,EACd,MAAU,MAAM,oCAAoC,CAGlD,KAAmB,UAAY,eAMnC,CAFA,EAAmB,QAAU,aAC7B,EAAa,GAAK,CAClB,EAAS,KAAK,CAEd,GAAI,CACF,MAAM,EAAO,QAAQ,EAAW,EAAY,CAC5C,IAAM,EAAO,EAAO,uBAAuB,CAC3C,EAAe,GAAK,CACpB,EAAgB,GAAQ,KAAK,CAC7B,EAAmB,QAAU,YAC7B,EAAY,sBAAuB,CACjC,oBAAqB,EAAQ,GAAM,OAAO,YAC3C,CAAC,CAEF,MAAM,QAAQ,IAAI,CAAC,GAAwB,CAAE,GAAoB,CAAC,CAAC,OAC5D,EAAG,CACV,IAAM,EAAM,aAAa,MAAQ,EAAQ,MAAM,OAAO,EAAE,CAAC,CAGzD,KAFA,GAAmB,QAAU,eAC7B,EAAS,EAAI,CACP,SACE,CACR,EAAa,GAAM,IAEpB,CAAC,EAAQ,EAAW,EAAa,EAAwB,EAAoB,EAAY,CAAC,CAyE7F,OAvEA,MAAgB,CACd,GAAI,CAAC,GAAe,CAAC,EACnB,OAGF,IAAM,EAAqB,EAAO,uBAAuB,CAyCzD,OAlBI,GAAoB,WAAW,aACjC,EAAO,uBAAuB,MAtBK,CACnC,GAAwB,CAAC,MAAO,GAAU,CACxC,QAAQ,MACN,kCACA,kDACA,EACD,EACD,EAe0F,CAG1F,GAAoB,OAAO,aAC7B,EAAO,uBAAuB,MAhBC,CAC/B,EAAY,kCAAmC,EAAE,CAAC,CAClD,GAAoB,CAAC,MAAO,GAAU,CACpC,QAAQ,MACN,kCACA,8CACA,EACD,EACD,EAQkF,CAKtF,QAAQ,IAAI,CAAC,GAAwB,CAAE,GAAoB,CAAC,CAAC,CAAC,MAAO,GAAU,CAC7E,QAAQ,MACN,kCACA,gEACA,EACD,EACD,KAEW,CACP,GAAoB,WAAW,aACjC,EAAO,0BAA0B,uCAAuC,CAGtE,GAAoB,OAAO,aAC7B,EAAO,0BAA0B,mCAAmC,GAGvE,CAAC,EAAQ,EAAa,EAAwB,EAAoB,EAAY,CAAC,CAGlF,OAEE,GAAW,CAAC,MAAO,GAAQ,CACzB,QAAQ,MAAM,kCAAmC,gCAAiC,EAAI,EACtF,KAGW,CACX,EAAmB,QAAU,eAC7B,EAAe,GAAM,GAEtB,CAAC,EAAQ,EAAW,EAAU,CAAC,CAGhC,EAAC,EAAiB,SAAlB,CACE,MAAO,CACL,SACA,QACA,YACA,cACA,YACA,QACA,eACA,YACD,CAEA,WACyB,CAAA,CAyChC,SAAgB,GAAe,CAC7B,IAAM,EAAU,EAAW,EAAiB,CAC5C,GAAI,CAAC,EACH,MAAU,MAAM,wDAAwD,CAE1E,OAAO"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mcp-b/react-webmcp",
3
- "version": "3.0.0",
3
+ "version": "4.0.0-beta.20260702173007",
4
4
  "description": "React hooks for Model Context Protocol (MCP) - expose React components as AI tools for Claude, ChatGPT, Cursor, and Copilot with Zod validation",
5
5
  "keywords": [
6
6
  "ai",
@@ -31,7 +31,7 @@
31
31
  "web-ai",
32
32
  "webmcp"
33
33
  ],
34
- "homepage": "https://docs.mcp-b.ai/packages/react-webmcp",
34
+ "homepage": "https://docs.mcp-b.ai/packages/react-webmcp/reference",
35
35
  "bugs": {
36
36
  "url": "https://github.com/WebMCP-org/npm-packages/issues"
37
37
  },
@@ -58,11 +58,12 @@
58
58
  "registry": "https://registry.npmjs.org/"
59
59
  },
60
60
  "dependencies": {
61
- "@mcp-b/global": "3.0.0",
62
- "@mcp-b/transports": "3.0.0",
63
- "@mcp-b/webmcp-polyfill": "3.0.0",
64
- "@mcp-b/webmcp-ts-sdk": "3.0.0",
65
- "@mcp-b/webmcp-types": "3.0.0"
61
+ "@modelcontextprotocol/sdk": "1.29.0",
62
+ "@mcp-b/global": "4.0.0-beta.20260702173007",
63
+ "@mcp-b/transports": "4.0.0-beta.20260702173007",
64
+ "@mcp-b/webmcp-polyfill": "4.0.0-beta.20260702173007",
65
+ "@mcp-b/webmcp-ts-sdk": "4.0.0-beta.20260702173007",
66
+ "@mcp-b/webmcp-types": "4.0.0-beta.20260702173007"
66
67
  },
67
68
  "devDependencies": {
68
69
  "@types/node": "22.17.2",
@@ -78,15 +79,11 @@
78
79
  },
79
80
  "peerDependencies": {
80
81
  "react": "^17.0.0 || ^18.0.0 || ^19.0.0",
81
- "zod": "^3.25 || ^4.0",
82
- "zod-to-json-schema": "^3.25.0"
82
+ "zod": "^3.25 || ^4.0"
83
83
  },
84
84
  "peerDependenciesMeta": {
85
85
  "zod": {
86
86
  "optional": true
87
- },
88
- "zod-to-json-schema": {
89
- "optional": true
90
87
  }
91
88
  },
92
89
  "scripts": {