usewebmcp 5.0.3 → 6.0.0-beta.20261001010549
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 +71 -75
- package/dist/index.d.ts +3 -56
- package/dist/index.js +1 -2
- package/dist/internal.d.ts +2 -0
- package/dist/internal.js +1 -0
- package/dist/useWebMCP-CD4hFHVo.d.ts +58 -0
- package/dist/useWebMCP-CQZUa6bR.js +2 -0
- package/dist/useWebMCP-CQZUa6bR.js.map +1 -0
- package/package.json +17 -14
- package/dist/index.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,108 +1,104 @@
|
|
|
1
1
|
# usewebmcp
|
|
2
2
|
|
|
3
|
-
React
|
|
4
|
-
|
|
5
|
-
Use `usewebmcp` when an app only needs standard tool registration. Use
|
|
6
|
-
`@mcp-b/react-webmcp` for prompts, resources, or MCP client/provider flows.
|
|
7
|
-
|
|
8
|
-
## Install
|
|
9
|
-
|
|
10
|
-
```bash
|
|
11
|
-
pnpm add usewebmcp react
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
The hook expects `document.modelContext` to exist before the component mounts. Provide it through
|
|
15
|
-
native browser support, `@mcp-b/webmcp-polyfill`, or `@mcp-b/global`. Older
|
|
16
|
-
`navigator.modelContext` runtimes remain a fallback.
|
|
17
|
-
|
|
18
|
-
## Quick start
|
|
3
|
+
Expose React state and actions as WebMCP tools, with automatic registration and cleanup.
|
|
19
4
|
|
|
20
5
|
```tsx
|
|
21
|
-
|
|
6
|
+
'use client';
|
|
7
|
+
|
|
8
|
+
import { useState } from 'react';
|
|
22
9
|
import { useWebMCP } from 'usewebmcp';
|
|
23
10
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const OUTPUT_SCHEMA = {
|
|
33
|
-
type: 'object',
|
|
34
|
-
properties: { total: { type: 'integer' } },
|
|
35
|
-
required: ['total'],
|
|
36
|
-
} as const;
|
|
37
|
-
|
|
38
|
-
export function SearchTool() {
|
|
39
|
-
const search = useWebMCP({
|
|
40
|
-
name: 'search',
|
|
41
|
-
description: 'Search indexed documents',
|
|
42
|
-
inputSchema: INPUT_SCHEMA,
|
|
43
|
-
outputSchema: OUTPUT_SCHEMA,
|
|
44
|
-
execute: async ({ query }) => ({ total: await countMatches(query) }),
|
|
11
|
+
export function Counter() {
|
|
12
|
+
const [count, setCount] = useState(0);
|
|
13
|
+
|
|
14
|
+
useWebMCP({
|
|
15
|
+
name: 'get_count',
|
|
16
|
+
description: 'Get the current counter value',
|
|
17
|
+
annotations: { readOnlyHint: true },
|
|
18
|
+
execute: () => ({ count }),
|
|
45
19
|
});
|
|
46
20
|
|
|
47
21
|
return (
|
|
48
|
-
<button
|
|
49
|
-
|
|
22
|
+
<button type="button" onClick={() => setCount((value) => value + 1)}>
|
|
23
|
+
Count: {count}
|
|
50
24
|
</button>
|
|
51
25
|
);
|
|
52
26
|
}
|
|
53
27
|
```
|
|
54
28
|
|
|
55
|
-
|
|
56
|
-
|
|
29
|
+
Each agent call reads the latest committed `count`.
|
|
30
|
+
|
|
31
|
+
[API reference](https://docs.mcp-b.ai/packages/usewebmcp/reference) · [Framework setup](https://docs.mcp-b.ai/how-to/frameworks)
|
|
32
|
+
|
|
33
|
+
## Install and provide a runtime
|
|
34
|
+
|
|
35
|
+
In a React 18 or 19 application:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
pnpm add usewebmcp
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
The hook reads `document.modelContext` when it registers and does not wait for a runtime installed
|
|
42
|
+
later. For browsers without it, install and initialize the polyfill before rendering tools:
|
|
57
43
|
|
|
58
|
-
|
|
44
|
+
```bash
|
|
45
|
+
pnpm add @mcp-b/webmcp-polyfill
|
|
46
|
+
```
|
|
59
47
|
|
|
60
48
|
```ts
|
|
61
|
-
|
|
49
|
+
import { installWebMCP } from '@mcp-b/webmcp-polyfill';
|
|
50
|
+
|
|
51
|
+
installWebMCP();
|
|
62
52
|
```
|
|
63
53
|
|
|
64
|
-
`
|
|
54
|
+
Use [`@mcp-b/global`](../global/README.md) for MCP server features. Browser types come from the Community Group's [`webmcp-types`](https://github.com/webmachinelearning/webmcp-types).
|
|
55
|
+
|
|
56
|
+
## Input schemas
|
|
65
57
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
58
|
+
`usewebmcp` accepts the JSON Schema object from the WebMCP API and infers TypeScript input types
|
|
59
|
+
from it. The schema is metadata; the hook does not validate arguments. Validate in your handler
|
|
60
|
+
when needed. Local calls to `execute()` are typed but do not run a validator.
|
|
69
61
|
|
|
70
|
-
|
|
71
|
-
`
|
|
72
|
-
|
|
62
|
+
Zod and other Standard Schema validators are rejected. Passing one is a type error, and at runtime
|
|
63
|
+
the hook sets `registrationError` without registering the tool. For Standard Schema validation,
|
|
64
|
+
output schemas, MCP annotations, MCP result formatting, or prompt and resource hooks, use
|
|
65
|
+
[`@mcp-b/react-webmcp`](../react-webmcp/README.md).
|
|
73
66
|
|
|
74
|
-
##
|
|
67
|
+
## State and lifecycle
|
|
75
68
|
|
|
76
|
-
|
|
69
|
+
- `state` exposes `isExecuting`, `lastResult`, `error`, and `executionCount`.
|
|
70
|
+
- `execute(input, options?)` calls the handler locally. `reset()` clears state without cancelling work.
|
|
71
|
+
- `isSupported` reports API availability; `registrationError` reports setup failures separately from `state.error`.
|
|
72
|
+
- A rejected registration, such as a duplicate tool name, also logs one `console.warn` naming the tool.
|
|
73
|
+
- `enabled: false` unregisters the tool while keeping local execution available.
|
|
74
|
+
- Local and agent failures reject. Agents receive `null` when the handler returns `undefined`; any
|
|
75
|
+
other result must be JSON-serializable, or the agent call fails and `state.error` records why.
|
|
76
|
+
- Handlers receive `(input, { signal })` for cancellation, which always rejects.
|
|
77
|
+
- The hook commits once after mount when `isSupported` becomes true. Later successful registrations
|
|
78
|
+
and unrelated renders add no commits.
|
|
79
|
+
- The package preserves `'use client'` and supports React 18/19, SSR, and StrictMode.
|
|
77
80
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
-
|
|
81
|
-
- Other values receive a safe text representation.
|
|
81
|
+
See the [reference](https://docs.mcp-b.ai/packages/usewebmcp/reference) for metadata updates,
|
|
82
|
+
cancellation, and raw result handling. The `usewebmcp/internal` entry exists for
|
|
83
|
+
`@mcp-b/react-webmcp` and can change in any release.
|
|
82
84
|
|
|
83
|
-
|
|
84
|
-
an MCP error response. Native Chrome WebMCP does not advertise `outputSchema`; it is MCP-B metadata
|
|
85
|
-
for output inference and compatible runtimes.
|
|
85
|
+
## Upgrading from 5.x
|
|
86
86
|
|
|
87
|
-
|
|
87
|
+
To keep Standard Schema validation, `outputSchema`, MCP annotations, `InferOutput`, or automatic
|
|
88
|
+
MCP responses, import `useWebMCP` from `@mcp-b/react-webmcp` instead. The
|
|
89
|
+
[changelog](./CHANGELOG.md) lists every breaking change.
|
|
88
90
|
|
|
89
|
-
|
|
90
|
-
schemas, and annotations use their latest committed values without reference-driven churn. Include
|
|
91
|
-
a primitive schema or annotation revision in `deps` when registered metadata must change.
|
|
91
|
+
## Development
|
|
92
92
|
|
|
93
|
-
|
|
94
|
-
registration; initialize the runtime first rather than polling once per hook.
|
|
93
|
+
From the repository root after `pnpm build`:
|
|
95
94
|
|
|
96
|
-
|
|
95
|
+
```bash
|
|
96
|
+
pnpm test:hooks
|
|
97
|
+
CHROME_BIN=/path/to/chrome-canary pnpm --filter usewebmcp test:native
|
|
98
|
+
```
|
|
97
99
|
|
|
98
|
-
-
|
|
99
|
-
- `WebMCPConfig`
|
|
100
|
-
- `WebMCPReturn`
|
|
101
|
-
- `ToolExecutionState`
|
|
102
|
-
- `ToolExecuteFunction`
|
|
103
|
-
- `InferToolInput`
|
|
104
|
-
- `InferOutput`
|
|
100
|
+
[Harness details](../../docs/TESTING.md#react-hook-harness). Prior art: [GoogleChromeLabs/use-webmcp-tool](https://github.com/GoogleChromeLabs/use-webmcp-tool).
|
|
105
101
|
|
|
106
102
|
## License
|
|
107
103
|
|
|
108
|
-
MIT
|
|
104
|
+
[MIT](../../LICENSE)
|
package/dist/index.d.ts
CHANGED
|
@@ -1,56 +1,3 @@
|
|
|
1
|
-
import { ToolInputSchema } from "
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
//#region src/types.d.ts
|
|
6
|
-
/** Infers tool input from a JSON Schema literal or Standard JSON Schema. */
|
|
7
|
-
type InferToolInput<T> = T extends {
|
|
8
|
-
readonly '~standard': {
|
|
9
|
-
readonly types?: infer Types;
|
|
10
|
-
};
|
|
11
|
-
} ? NonNullable<Types> extends {
|
|
12
|
-
readonly input: infer Input;
|
|
13
|
-
} ? Input : Record<string, unknown> : T extends InputSchema ? InferArgsFromInputSchema<T> : Record<string, unknown>;
|
|
14
|
-
/** Infers tool output from a JSON Schema literal. */
|
|
15
|
-
type InferOutput<TOutputSchema extends JsonSchemaForInference | undefined = undefined> = TOutputSchema extends undefined ? unknown : TOutputSchema extends JsonSchemaForInference ? InferJsonSchema<TOutputSchema> : unknown;
|
|
16
|
-
/** Current state for local and MCP-triggered tool executions. */
|
|
17
|
-
interface ToolExecutionState<TOutput = unknown> {
|
|
18
|
-
/** Whether at least one execution is pending. */
|
|
19
|
-
isExecuting: boolean;
|
|
20
|
-
/** Most recent successful result, or `null` before one exists. */
|
|
21
|
-
lastResult: TOutput | null;
|
|
22
|
-
/** Most recent execution error. */
|
|
23
|
-
error: Error | null;
|
|
24
|
-
/** Number of successful executions since the last reset. */
|
|
25
|
-
executionCount: number;
|
|
26
|
-
}
|
|
27
|
-
/** Synchronous or asynchronous tool implementation. */
|
|
28
|
-
type ToolExecuteFunction<TInputSchema extends ToolInputSchema = InputSchema, TOutputSchema extends JsonSchemaForInference | undefined = undefined> = (input: InferToolInput<TInputSchema>) => Promise<InferOutput<TOutputSchema>> | InferOutput<TOutputSchema>;
|
|
29
|
-
/** Configuration for a tool registered by `useWebMCP`. */
|
|
30
|
-
interface WebMCPConfig<TInputSchema extends ToolInputSchema = InputSchema, TOutputSchema extends JsonSchemaForInference | undefined = undefined> {
|
|
31
|
-
/** Unique WebMCP tool name. */
|
|
32
|
-
name: string;
|
|
33
|
-
/** Description shown to MCP clients. */
|
|
34
|
-
description: string;
|
|
35
|
-
/** JSON Schema literal or Standard JSON Schema for the tool input. */
|
|
36
|
-
inputSchema?: TInputSchema;
|
|
37
|
-
/** JSON Schema used for output inference and structured content. */
|
|
38
|
-
outputSchema?: TOutputSchema;
|
|
39
|
-
/** Optional WebMCP behavior hints. */
|
|
40
|
-
annotations?: ToolAnnotations;
|
|
41
|
-
/** Tool implementation. */
|
|
42
|
-
execute: ToolExecuteFunction<TInputSchema, TOutputSchema>;
|
|
43
|
-
}
|
|
44
|
-
/** State and controls returned by `useWebMCP`. */
|
|
45
|
-
interface WebMCPReturn<TOutputSchema extends JsonSchemaForInference | undefined = undefined, TInputSchema extends ToolInputSchema = InputSchema> {
|
|
46
|
-
state: ToolExecutionState<InferOutput<TOutputSchema>>;
|
|
47
|
-
execute: (input: InferToolInput<TInputSchema>) => Promise<InferOutput<TOutputSchema>>;
|
|
48
|
-
reset: () => void;
|
|
49
|
-
}
|
|
50
|
-
//#endregion
|
|
51
|
-
//#region src/useWebMCP.d.ts
|
|
52
|
-
/** Registers a React-owned tool with the current WebMCP model context. */
|
|
53
|
-
declare function useWebMCP<TInputSchema extends ToolInputSchema = InputSchema, TOutputSchema extends JsonSchemaForInference | undefined = undefined>(config: WebMCPConfig<TInputSchema, TOutputSchema>, deps?: DependencyList): WebMCPReturn<TOutputSchema, TInputSchema>;
|
|
54
|
-
//#endregion
|
|
55
|
-
export { type InferOutput, type InferToolInput, type ToolExecuteFunction, type ToolExecutionState, type WebMCPConfig, type WebMCPReturn, useWebMCP };
|
|
56
|
-
//# sourceMappingURL=index.d.ts.map
|
|
1
|
+
import { a as ToolExecuteFunction, c as WebMCPConfig, i as InferToolInput, l as WebMCPReturn, n as useWebMCP, o as ToolExecutionState, s as ToolInputSchema } from "./useWebMCP-CD4hFHVo.js";
|
|
2
|
+
import { WebMCP } from "webmcp-types";
|
|
3
|
+
export { type InferToolInput, type ToolExecuteFunction, type ToolExecutionState, type ToolInputSchema, type WebMCP, type WebMCPConfig, type WebMCPReturn, useWebMCP };
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
"use client";import{
|
|
2
|
-
//# sourceMappingURL=index.js.map
|
|
1
|
+
"use client";import{t as e}from"./useWebMCP-CQZUa6bR.js";export{e as useWebMCP};
|
package/dist/internal.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{n as e}from"./useWebMCP-CQZUa6bR.js";export{e as useWebMCPWithAdapter};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { DependencyList } from "react";
|
|
2
|
+
import { WebMCP } from "webmcp-types";
|
|
3
|
+
|
|
4
|
+
//#region src/types.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* The JSON Schema object accepted by the WebMCP tool contract. Standard Schema
|
|
7
|
+
* validators such as Zod belong to `@mcp-b/react-webmcp`.
|
|
8
|
+
*/
|
|
9
|
+
type ToolInputSchema = NonNullable<WebMCP.ModelContextTool['inputSchema']> & {
|
|
10
|
+
readonly '~standard'?: never;
|
|
11
|
+
};
|
|
12
|
+
/** Input inferred from the WebMCP JSON Schema. */
|
|
13
|
+
type InferToolInput<T extends object> = Parameters<WebMCP.ModelContextToolFromSchema<T>['execute']>[0];
|
|
14
|
+
/** Current state for local and agent-triggered tool executions. */
|
|
15
|
+
interface ToolExecutionState<TResult = unknown> {
|
|
16
|
+
/** Whether at least one execution is pending. */
|
|
17
|
+
isExecuting: boolean;
|
|
18
|
+
/** Most recent successful result, or null before one exists. */
|
|
19
|
+
lastResult: TResult | null;
|
|
20
|
+
/** Most recent execution error. */
|
|
21
|
+
error: Error | null;
|
|
22
|
+
/** Number of successful executions since the last reset. */
|
|
23
|
+
executionCount: number;
|
|
24
|
+
}
|
|
25
|
+
/** Synchronous or asynchronous tool implementation. */
|
|
26
|
+
type ToolExecuteFunction<TInputSchema extends ToolInputSchema = object, TResult = unknown> = (input: InferToolInput<TInputSchema>, options: WebMCP.ToolExecuteCallbackOptions) => WebMCP.MaybePromise<TResult>;
|
|
27
|
+
/** Standard tool metadata plus React lifecycle and execution options. */
|
|
28
|
+
interface WebMCPConfig<TInputSchema extends ToolInputSchema = object, TResult = unknown> extends Omit<WebMCP.ModelContextTool, 'inputSchema' | 'execute'> {
|
|
29
|
+
inputSchema?: TInputSchema;
|
|
30
|
+
execute: ToolExecuteFunction<TInputSchema, TResult>;
|
|
31
|
+
/** Register while true. Local execution remains available when false. */
|
|
32
|
+
enabled?: boolean;
|
|
33
|
+
/** Origins allowed to discover/call the tool, enforced by the browser. */
|
|
34
|
+
exposedTo?: WebMCP.ModelContextRegisterToolOptions['exposedTo'];
|
|
35
|
+
}
|
|
36
|
+
/** State and controls returned by useWebMCP. */
|
|
37
|
+
interface WebMCPReturn<TInputSchema extends ToolInputSchema = object, TResult = unknown> {
|
|
38
|
+
state: ToolExecutionState<TResult>;
|
|
39
|
+
isSupported: boolean;
|
|
40
|
+
registrationError: Error | null;
|
|
41
|
+
execute: (input: InferToolInput<TInputSchema>, options?: WebMCP.ToolExecuteCallbackOptions) => Promise<TResult>;
|
|
42
|
+
/** Clears observed execution state without cancelling pending work. */
|
|
43
|
+
reset: () => void;
|
|
44
|
+
}
|
|
45
|
+
//#endregion
|
|
46
|
+
//#region src/useWebMCP.d.ts
|
|
47
|
+
interface WebMCPAdapter<TResult> {
|
|
48
|
+
descriptor?: object;
|
|
49
|
+
preparationError?: Error;
|
|
50
|
+
formatOutput?: (result: TResult) => WebMCP.MaybePromise<unknown>;
|
|
51
|
+
formatError?: (error: Error) => WebMCP.MaybePromise<unknown>;
|
|
52
|
+
}
|
|
53
|
+
declare function useWebMCPWithAdapter<const TInputSchema extends ToolInputSchema = object, TResult = unknown>(config: WebMCPConfig<TInputSchema, TResult>, deps: DependencyList | undefined, adapter: WebMCPAdapter<TResult>): WebMCPReturn<TInputSchema, TResult>;
|
|
54
|
+
/** Registers a React-owned tool using the upstream WebMCP contract. */
|
|
55
|
+
declare function useWebMCP<const TInputSchema extends ToolInputSchema = object, TResult = unknown>(config: WebMCPConfig<TInputSchema, TResult>, deps?: DependencyList): WebMCPReturn<TInputSchema, TResult>;
|
|
56
|
+
//#endregion
|
|
57
|
+
export { ToolExecuteFunction as a, WebMCPConfig as c, InferToolInput as i, WebMCPReturn as l, useWebMCP as n, ToolExecutionState as o, useWebMCPWithAdapter as r, ToolInputSchema as s, WebMCPAdapter as t };
|
|
58
|
+
//# sourceMappingURL=useWebMCP-CD4hFHVo.d.ts.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{useCallback as e,useEffect as t,useLayoutEffect as n,useMemo as r,useRef as i,useState as a}from"react";const o={isExecuting:!1,lastResult:null,error:null,executionCount:0},s={isSupported:!1,registrationError:null},c=globalThis.window===void 0?t:n;function l(e){return e instanceof Error?e:Error(String(e))}function u(n,u,d){let[f,p]=a(o),[m,h]=a(s),g=i(0),_=r(()=>{try{let e=n.inputSchema;if(e!==void 0&&`~standard`in e)throw TypeError(`inputSchema must be JSON Schema. Use @mcp-b/react-webmcp for Zod and other Standard Schema validators.`);let t=JSON.stringify(e);if(e!==void 0&&t===void 0)throw TypeError(`inputSchema must serialize to JSON`);return{value:e,key:t}}catch(e){return{error:l(e)}}},[n.inputSchema]),{name:v,title:y,description:b,annotations:x,enabled:S=!0,exposedTo:C}=n,w={name:v,...y!==void 0&&{title:y},description:b,...x!==void 0&&{annotations:x},...d.descriptor},T={...w,..._.value!==void 0&&{inputSchema:_.value}},E=_.error??d.preparationError,D;try{D=JSON.stringify([w,_.key,C])}catch(e){E=l(e),D=E.message}let O=i({config:n,descriptor:T,preparationError:E,adapter:d});c(()=>{O.current={config:n,descriptor:T,preparationError:E,adapter:d}});let k=e(async(e,t={signal:new AbortController().signal},n=!1)=>{let{config:r,adapter:i}=O.current,{signal:a}=t;g.current+=1,p(e=>e.isExecuting&&e.error===null?e:{...e,isExecuting:!0,error:null});let o,s;try{a.throwIfAborted(),s=await Promise.race([new Promise((e,t)=>{o=()=>t(a.reason),a.addEventListener(`abort`,o,{once:!0})}),(async()=>{try{let o=await r.execute(e,t);if(a.throwIfAborted(),o instanceof Error)throw o;let s=n&&i.formatOutput?await i.formatOutput(o):o;if(a.throwIfAborted(),n&&s!==void 0)try{if(JSON.stringify(s)===void 0)throw TypeError(`JSON.stringify returned undefined`)}catch(e){throw TypeError(`Tool "${r.name}" returned a result that is not JSON-serializable`,{cause:e})}return{result:o,output:s??null}}catch(e){a.throwIfAborted();let t=l(e),r=i.formatError;if(!n||!r)return{error:t};let o=await r(t);return a.throwIfAborted(),{error:t,output:o}}})()])}catch(e){s={error:l(e)}}finally{o&&a.removeEventListener(`abort`,o),--g.current}let c=g.current>0;return p(e=>`error`in s?{...e,isExecuting:c,error:s.error}:{isExecuting:c,lastResult:s.result,error:null,executionCount:e.executionCount+1}),s},[]),A=e(async(e,t)=>{let n=await k(e,t);if(`error`in n)throw n.error;return n.result},[k]),j=e(()=>{let e=g.current>0;p(t=>t.isExecuting===e&&t.lastResult===null&&t.error===null&&t.executionCount===0?t:{...o,isExecuting:e})},[]);return t(()=>{let e=new AbortController,t=globalThis.document?.modelContext,n=typeof t?.registerTool==`function`,{config:r,descriptor:i,preparationError:a}=O.current;h(e=>e.isSupported===n&&e.registrationError===(a??null)?e:{isSupported:n,registrationError:a??null});let o=t=>{if(e.signal.aborted)return;e.abort();let n=l(t);console.warn(`[useWebMCP] registerTool("${r.name}") rejected:`,n),h({isSupported:!0,registrationError:n})};if(!a&&S&&n&&t)try{t.registerTool({...i,execute:async(e,t)=>{let n=await k(e,t,!0);if(`output`in n)return n.output;throw n.error}},{signal:e.signal,...r.exposedTo&&{exposedTo:r.exposedTo}}).catch(o)}catch(e){o(e)}return()=>e.abort()},[D,E?.message,S,...u??[]]),{state:f,...m,execute:A,reset:j}}function d(e,t){return u(e,t,{})}export{u as n,d as t};
|
|
2
|
+
//# sourceMappingURL=useWebMCP-CQZUa6bR.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useWebMCP-CQZUa6bR.js","names":[],"sources":["../src/useWebMCP.ts"],"sourcesContent":["'use client';\n\nimport type { DependencyList } from 'react';\nimport { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';\nimport type { WebMCP } from 'webmcp-types';\nimport type {\n InferToolInput,\n ToolExecutionState,\n ToolInputSchema,\n WebMCPConfig,\n WebMCPReturn,\n} from './types.js';\n\nconst INITIAL_STATE = { isExecuting: false, lastResult: null, error: null, executionCount: 0 };\nconst INITIAL_REGISTRATION = { isSupported: false, registrationError: null };\nconst useIsomorphicLayoutEffect = globalThis.window === undefined ? useEffect : useLayoutEffect;\n\ntype ExecutionOutcome<T> = { result: T; output: unknown } | { error: Error; output?: unknown };\ntype RegisteredToolInput = Parameters<WebMCP.ModelContextTool['execute']>[0];\n\nexport interface WebMCPAdapter<TResult> {\n descriptor?: object;\n preparationError?: Error;\n formatOutput?: (result: TResult) => WebMCP.MaybePromise<unknown>;\n formatError?: (error: Error) => WebMCP.MaybePromise<unknown>;\n}\n\nfunction toError(cause: unknown): Error {\n return cause instanceof Error ? cause : new Error(String(cause));\n}\n\nexport function useWebMCPWithAdapter<\n const TInputSchema extends ToolInputSchema = object,\n TResult = unknown,\n>(\n config: WebMCPConfig<TInputSchema, TResult>,\n deps: DependencyList | undefined,\n adapter: WebMCPAdapter<TResult>\n): WebMCPReturn<TInputSchema, TResult> {\n const [state, setState] = useState<ToolExecutionState<TResult>>(INITIAL_STATE);\n const [registration, setRegistration] =\n useState<Pick<WebMCPReturn, 'isSupported' | 'registrationError'>>(INITIAL_REGISTRATION);\n const pendingExecutions = useRef(0);\n const schema = useMemo(() => {\n try {\n const value = config.inputSchema;\n if (value !== undefined && '~standard' in value) {\n throw new TypeError(\n 'inputSchema must be JSON Schema. Use @mcp-b/react-webmcp for Zod and other Standard Schema validators.'\n );\n }\n const key = JSON.stringify(value);\n if (value !== undefined && key === undefined) {\n throw new TypeError('inputSchema must serialize to JSON');\n }\n return { value, key };\n } catch (error) {\n return { error: toError(error) };\n }\n }, [config.inputSchema]);\n const { name, title, description, annotations, enabled = true, exposedTo } = config;\n const metadata = {\n name,\n ...(title !== undefined && { title }),\n description,\n ...(annotations !== undefined && { annotations }),\n ...adapter.descriptor,\n };\n const descriptor = {\n ...metadata,\n ...(schema.value !== undefined && { inputSchema: schema.value }),\n };\n let preparationError = schema.error ?? adapter.preparationError;\n let descriptorKey: string;\n try {\n descriptorKey = JSON.stringify([metadata, schema.key, exposedTo]);\n } catch (error) {\n preparationError = toError(error);\n descriptorKey = preparationError.message;\n }\n const committed = useRef({ config, descriptor, preparationError, adapter });\n\n // Publish only committed renders, before external calls from later layout effects.\n useIsomorphicLayoutEffect(() => {\n committed.current = { config, descriptor, preparationError, adapter };\n });\n\n const run = useCallback(\n async (\n input: InferToolInput<TInputSchema> | RegisteredToolInput,\n options: WebMCP.ToolExecuteCallbackOptions = { signal: new AbortController().signal },\n forAgent = false\n ): Promise<ExecutionOutcome<TResult>> => {\n const { config: executionConfig, adapter: executionAdapter } = committed.current;\n const { signal } = options;\n pendingExecutions.current += 1;\n setState((previous) =>\n previous.isExecuting && previous.error === null\n ? previous\n : { ...previous, isExecuting: true, error: null }\n );\n let onAbort: (() => void) | undefined;\n let outcome: ExecutionOutcome<TResult>;\n try {\n signal.throwIfAborted();\n const operation = async (): Promise<ExecutionOutcome<TResult>> => {\n try {\n // SAFETY: registered calls are validated by inputSchema; local calls are typed.\n const result = await executionConfig.execute(\n input as InferToolInput<TInputSchema>,\n options\n );\n signal.throwIfAborted();\n if (result instanceof Error) throw result;\n const output =\n forAgent && executionAdapter.formatOutput\n ? await executionAdapter.formatOutput(result)\n : result;\n signal.throwIfAborted();\n if (forAgent && output !== undefined) {\n try {\n if (JSON.stringify(output) === undefined) {\n throw new TypeError('JSON.stringify returned undefined');\n }\n } catch (cause) {\n throw new TypeError(\n `Tool \"${executionConfig.name}\" returned a result that is not JSON-serializable`,\n { cause }\n );\n }\n }\n return { result, output: output ?? null };\n } catch (cause) {\n signal.throwIfAborted();\n const error = toError(cause);\n const formatError = executionAdapter.formatError;\n if (!forAgent || !formatError) return { error };\n const output = await formatError(error);\n signal.throwIfAborted();\n return { error, output };\n }\n };\n outcome = await Promise.race([\n new Promise<never>((_, reject) => {\n onAbort = () => reject(signal.reason);\n signal.addEventListener('abort', onAbort, { once: true });\n }),\n operation(),\n ]);\n } catch (error) {\n outcome = { error: toError(error) };\n } finally {\n if (onAbort) signal.removeEventListener('abort', onAbort);\n pendingExecutions.current -= 1;\n }\n const isExecuting = pendingExecutions.current > 0;\n setState((previous) =>\n 'error' in outcome\n ? { ...previous, isExecuting, error: outcome.error }\n : {\n isExecuting,\n lastResult: outcome.result,\n error: null,\n executionCount: previous.executionCount + 1,\n }\n );\n return outcome;\n },\n []\n );\n\n const execute = useCallback<WebMCPReturn<TInputSchema, TResult>['execute']>(\n async (input, options) => {\n const outcome = await run(input, options);\n if ('error' in outcome) throw outcome.error;\n return outcome.result;\n },\n [run]\n );\n\n const reset = useCallback(() => {\n const isExecuting = pendingExecutions.current > 0;\n setState((previous) =>\n previous.isExecuting === isExecuting &&\n previous.lastResult === null &&\n previous.error === null &&\n previous.executionCount === 0\n ? previous\n : { ...INITIAL_STATE, isExecuting }\n );\n }, []);\n\n useEffect(() => {\n const controller = new AbortController();\n const context = globalThis.document?.modelContext;\n const isSupported = typeof context?.registerTool === 'function';\n const { config: current, descriptor: tool, preparationError: error } = committed.current;\n setRegistration((previous) =>\n previous.isSupported === isSupported && previous.registrationError === (error ?? null)\n ? previous\n : { isSupported, registrationError: error ?? null }\n );\n const failed = (cause: unknown) => {\n if (controller.signal.aborted) return;\n controller.abort();\n const registrationError = toError(cause);\n console.warn(`[useWebMCP] registerTool(\"${current.name}\") rejected:`, registrationError);\n setRegistration({ isSupported: true, registrationError });\n };\n if (!error && enabled && isSupported && context) {\n try {\n const registered = context.registerTool(\n {\n ...tool,\n execute: async (input, options) => {\n const outcome = await run(input, options, true);\n if ('output' in outcome) return outcome.output;\n throw outcome.error;\n },\n },\n { signal: controller.signal, ...(current.exposedTo && { exposedTo: current.exposedTo }) }\n );\n void registered.catch(failed);\n } catch (cause) {\n failed(cause);\n }\n }\n return () => controller.abort();\n // Descriptor contents avoid churn from inline schemas; deps can explicitly refresh registration.\n // oxlint-disable-next-line react-doctor/exhaustive-deps -- Metadata is compared by value and callbacks are read after commit.\n }, [descriptorKey, preparationError?.message, enabled, ...(deps ?? [])]);\n\n return { state, ...registration, execute, reset };\n}\n\n/** Registers a React-owned tool using the upstream WebMCP contract. */\nexport function useWebMCP<const TInputSchema extends ToolInputSchema = object, TResult = unknown>(\n config: WebMCPConfig<TInputSchema, TResult>,\n deps?: DependencyList\n): WebMCPReturn<TInputSchema, TResult> {\n return useWebMCPWithAdapter(config, deps, {});\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "usewebmcp",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.0-beta.20261001010549",
|
|
4
4
|
"description": "Standalone React hooks for strict core WebMCP tool registration with document.modelContext",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -36,6 +36,10 @@
|
|
|
36
36
|
".": {
|
|
37
37
|
"types": "./dist/index.d.ts",
|
|
38
38
|
"import": "./dist/index.js"
|
|
39
|
+
},
|
|
40
|
+
"./internal": {
|
|
41
|
+
"types": "./dist/internal.d.ts",
|
|
42
|
+
"import": "./dist/internal.js"
|
|
39
43
|
}
|
|
40
44
|
},
|
|
41
45
|
"publishConfig": {
|
|
@@ -43,22 +47,20 @@
|
|
|
43
47
|
"registry": "https://registry.npmjs.org/"
|
|
44
48
|
},
|
|
45
49
|
"dependencies": {
|
|
46
|
-
"
|
|
47
|
-
"@mcp-b/webmcp-types": "5.0.3"
|
|
50
|
+
"webmcp-types": "0.1.9"
|
|
48
51
|
},
|
|
49
52
|
"devDependencies": {
|
|
50
|
-
"@types/node": "22.
|
|
51
|
-
"@types/react": "^19.2.
|
|
52
|
-
"@vitest/coverage-v8": "4.1.
|
|
53
|
-
"playwright": "^1.
|
|
54
|
-
"react": "^19.
|
|
55
|
-
"react-dom": "^19.
|
|
53
|
+
"@types/node": "22.20.1",
|
|
54
|
+
"@types/react": "^19.2.18",
|
|
55
|
+
"@vitest/coverage-v8": "4.1.8",
|
|
56
|
+
"playwright": "^1.62.1",
|
|
57
|
+
"react": "^19.2.8",
|
|
58
|
+
"react-dom": "^19.2.8",
|
|
56
59
|
"typescript": "^5.8.3",
|
|
57
|
-
"vite-plus": "0.1.
|
|
58
|
-
"vitest": "npm:@voidzero-dev/vite-plus-test@0.1.
|
|
59
|
-
"vitest-browser-react": "^2.0
|
|
60
|
-
"
|
|
61
|
-
"@mcp-b/global": "5.0.3"
|
|
60
|
+
"vite-plus": "0.1.24",
|
|
61
|
+
"vitest": "npm:@voidzero-dev/vite-plus-test@0.1.24",
|
|
62
|
+
"vitest-browser-react": "^2.2.0",
|
|
63
|
+
"@mcp-b/webmcp-polyfill": "6.0.0-beta.20261001010549"
|
|
62
64
|
},
|
|
63
65
|
"peerDependencies": {
|
|
64
66
|
"react": "^18.0.0 || ^19.0.0"
|
|
@@ -76,6 +78,7 @@
|
|
|
76
78
|
"publish:dry": "pnpm publish --access public --dry-run",
|
|
77
79
|
"publish:npm": "pnpm publish --access public",
|
|
78
80
|
"test": "vp test run",
|
|
81
|
+
"test:native": "WEBMCP_NATIVE=1 vp test run",
|
|
79
82
|
"test:watch": "vp test",
|
|
80
83
|
"typecheck": "tsc --noEmit && tsc -p tsconfig.strict-null-checks-false.json --noEmit"
|
|
81
84
|
}
|
package/dist/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/useWebMCP.ts"],"sourcesContent":["import {\n normalizeInputSchema,\n normalizeToolResponse,\n type ToolInputSchema,\n} from '@mcp-b/webmcp-polyfill/schema';\nimport type { InputSchema, JsonSchemaForInference } 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 ToolExecutionState,\n WebMCPConfig,\n WebMCPReturn,\n} from './types.js';\n\nconst INITIAL_STATE = {\n isExecuting: false,\n lastResult: null,\n error: null,\n executionCount: 0,\n};\n\nconst useIsomorphicLayoutEffect = typeof window === 'undefined' ? useEffect : useLayoutEffect;\n\n/** Registers a React-owned tool with the current WebMCP model context. */\nexport function useWebMCP<\n TInputSchema extends ToolInputSchema = InputSchema,\n TOutputSchema extends JsonSchemaForInference | 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 { name, description } = config;\n const [state, setState] = useState<ToolExecutionState<TOutput>>(INITIAL_STATE);\n const committedConfigRef = useRef(config);\n const pendingExecutionsRef = useRef(0);\n\n // MCP calls can arrive after commit but before passive effects. A layout effect\n // publishes only committed renders; the server fallback avoids the SSR warning.\n useIsomorphicLayoutEffect(() => {\n committedConfigRef.current = config;\n });\n\n const run = useCallback(async (input: TInput): Promise<TOutput> => {\n pendingExecutionsRef.current += 1;\n setState((previous) => ({ ...previous, isExecuting: true, error: null }));\n\n let result: TOutput;\n const executionConfig = committedConfigRef.current;\n try {\n result = await executionConfig.execute(input);\n if (\n executionConfig.outputSchema &&\n normalizeToolResponse(result).structuredContent === undefined\n ) {\n throw new Error(\n `Tool \"${executionConfig.name}\" outputSchema requires execute to return a JSON-serializable result`\n );\n }\n } catch (error) {\n pendingExecutionsRef.current -= 1;\n const normalizedError = error instanceof Error ? error : new Error(String(error));\n setState((previous) => ({\n ...previous,\n isExecuting: pendingExecutionsRef.current > 0,\n error: normalizedError,\n }));\n throw normalizedError;\n }\n\n pendingExecutionsRef.current -= 1;\n setState((previous) => ({\n isExecuting: pendingExecutionsRef.current > 0,\n lastResult: result,\n error: null,\n executionCount: previous.executionCount + 1,\n }));\n return result;\n }, []);\n\n const reset = useCallback(\n () => setState({ ...INITIAL_STATE, isExecuting: pendingExecutionsRef.current > 0 }),\n []\n );\n\n useEffect(() => {\n const modelContext =\n typeof document === 'undefined'\n ? undefined\n : (document.modelContext ??\n (typeof navigator === 'undefined' ? undefined : navigator.modelContext));\n if (!modelContext) {\n console.warn(\n `[useWebMCP] document.modelContext is not available. Tool \"${name}\" will not be registered.`\n );\n return;\n }\n\n const registeredConfig = committedConfigRef.current;\n const registeredOutputSchema = registeredConfig.outputSchema;\n const controller = new AbortController();\n const tool = {\n name,\n description,\n inputSchema: normalizeInputSchema(registeredConfig.inputSchema).inputSchema,\n ...(registeredOutputSchema && { outputSchema: registeredOutputSchema }),\n ...(registeredConfig.annotations && { annotations: registeredConfig.annotations }),\n execute: async (input: TInput) => {\n try {\n const response = normalizeToolResponse(await run(input));\n if (registeredOutputSchema && response.structuredContent === undefined) {\n throw new Error(\n `Tool \"${name}\" outputSchema requires the tool implementation to return a JSON-serializable result`\n );\n }\n return response;\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n content: [{ type: 'text' as const, text: `Error: ${message}` }],\n isError: true,\n };\n }\n },\n };\n\n try {\n const registration = modelContext.registerTool(tool, { signal: controller.signal });\n void Promise.resolve(registration).catch((error: unknown) => {\n if (!controller.signal.aborted) {\n controller.abort();\n console.warn(`[useWebMCP] registerTool(\"${name}\") rejected:`, error);\n }\n });\n } catch (error) {\n controller.abort();\n console.warn(`[useWebMCP] registerTool(\"${name}\") rejected:`, error);\n return;\n }\n\n return () => controller.abort();\n // `deps` lets callers explicitly opt descriptor values into re-registration.\n // oxlint-disable-next-line react-doctor/exhaustive-deps -- Public API deliberately forwards caller deps.\n }, [name, description, ...(deps ?? [])]);\n\n return { state, execute: run, reset };\n}\n"],"mappings":"+MAgBA,MAAM,EAAgB,CACpB,YAAa,GACb,WAAY,KACZ,MAAO,KACP,eAAgB,EACjB,CAEK,EAA4B,OAAO,OAAW,IAAc,EAAY,EAG9E,SAAgB,EAId,EACA,EAC2C,CAG3C,GAAM,CAAE,OAAM,eAAgB,EACxB,CAAC,EAAO,GAAY,EAAsC,EAAc,CACxE,EAAqB,EAAO,EAAO,CACnC,EAAuB,EAAO,EAAE,CAItC,MAAgC,CAC9B,EAAmB,QAAU,GAC7B,CAEF,IAAM,EAAM,EAAY,KAAO,IAAoC,CACjE,EAAqB,SAAW,EAChC,EAAU,IAAc,CAAE,GAAG,EAAU,YAAa,GAAM,MAAO,KAAM,EAAE,CAEzE,IAAI,EACE,EAAkB,EAAmB,QAC3C,GAAI,CAEF,GADA,EAAS,MAAM,EAAgB,QAAQ,EAAM,CAE3C,EAAgB,cAChB,EAAsB,EAAO,CAAC,oBAAsB,IAAA,GAEpD,MAAU,MACR,SAAS,EAAgB,KAAK,sEAC/B,OAEI,EAAO,CACd,IAAqB,QACrB,IAAM,EAAkB,aAAiB,MAAQ,EAAY,MAAM,OAAO,EAAM,CAAC,CAMjF,MALA,EAAU,IAAc,CACtB,GAAG,EACH,YAAa,EAAqB,QAAU,EAC5C,MAAO,EACR,EAAE,CACG,EAUR,MAPA,IAAqB,QACrB,EAAU,IAAc,CACtB,YAAa,EAAqB,QAAU,EAC5C,WAAY,EACZ,MAAO,KACP,eAAgB,EAAS,eAAiB,EAC3C,EAAE,CACI,GACN,EAAE,CAAC,CAEA,EAAQ,MACN,EAAS,CAAE,GAAG,EAAe,YAAa,EAAqB,QAAU,EAAG,CAAC,CACnF,EAAE,CACH,CA8DD,OA5DA,MAAgB,CACd,IAAM,EACJ,OAAO,SAAa,IAChB,IAAA,GACC,SAAS,eACT,OAAO,UAAc,IAAc,IAAA,GAAY,UAAU,cAChE,GAAI,CAAC,EAAc,CACjB,QAAQ,KACN,6DAA6D,EAAK,2BACnE,CACD,OAGF,IAAM,EAAmB,EAAmB,QACtC,EAAyB,EAAiB,aAC1C,EAAa,IAAI,gBACjB,EAAO,CACX,OACA,cACA,YAAa,EAAqB,EAAiB,YAAY,CAAC,YAChE,GAAI,GAA0B,CAAE,aAAc,EAAwB,CACtE,GAAI,EAAiB,aAAe,CAAE,YAAa,EAAiB,YAAa,CACjF,QAAS,KAAO,IAAkB,CAChC,GAAI,CACF,IAAM,EAAW,EAAsB,MAAM,EAAI,EAAM,CAAC,CACxD,GAAI,GAA0B,EAAS,oBAAsB,IAAA,GAC3D,MAAU,MACR,SAAS,EAAK,sFACf,CAEH,OAAO,QACA,EAAO,CAEd,MAAO,CACL,QAAS,CAAC,CAAE,KAAM,OAAiB,KAAM,UAF3B,aAAiB,MAAQ,EAAM,QAAU,OAAO,EAAM,GAEN,CAAC,CAC/D,QAAS,GACV,GAGN,CAED,GAAI,CACF,IAAM,EAAe,EAAa,aAAa,EAAM,CAAE,OAAQ,EAAW,OAAQ,CAAC,CACnF,QAAa,QAAQ,EAAa,CAAC,MAAO,GAAmB,CACtD,EAAW,OAAO,UACrB,EAAW,OAAO,CAClB,QAAQ,KAAK,6BAA6B,EAAK,cAAe,EAAM,GAEtE,OACK,EAAO,CACd,EAAW,OAAO,CAClB,QAAQ,KAAK,6BAA6B,EAAK,cAAe,EAAM,CACpE,OAGF,UAAa,EAAW,OAAO,EAG9B,CAAC,EAAM,EAAa,GAAI,GAAQ,EAAE,CAAE,CAAC,CAEjC,CAAE,QAAO,QAAS,EAAK,QAAO"}
|