@mcp-web/react 0.1.0

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.
Files changed (47) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +180 -0
  3. package/dist/index.d.ts +6 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +5 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/mcp-web-context.d.ts +16 -0
  8. package/dist/mcp-web-context.d.ts.map +1 -0
  9. package/dist/mcp-web-context.js +7 -0
  10. package/dist/mcp-web-context.js.map +1 -0
  11. package/dist/mcp-web-provider.d.ts +62 -0
  12. package/dist/mcp-web-provider.d.ts.map +1 -0
  13. package/dist/mcp-web-provider.js +54 -0
  14. package/dist/mcp-web-provider.js.map +1 -0
  15. package/dist/use-apps.d.ts +63 -0
  16. package/dist/use-apps.d.ts.map +1 -0
  17. package/dist/use-apps.js +58 -0
  18. package/dist/use-apps.js.map +1 -0
  19. package/dist/use-connected-mcp-web.d.ts +14 -0
  20. package/dist/use-connected-mcp-web.d.ts.map +1 -0
  21. package/dist/use-connected-mcp-web.js +44 -0
  22. package/dist/use-connected-mcp-web.js.map +1 -0
  23. package/dist/use-mcp-apps.d.ts +63 -0
  24. package/dist/use-mcp-apps.d.ts.map +1 -0
  25. package/dist/use-mcp-apps.js +58 -0
  26. package/dist/use-mcp-apps.js.map +1 -0
  27. package/dist/use-mcp-tools.d.ts +99 -0
  28. package/dist/use-mcp-tools.d.ts.map +1 -0
  29. package/dist/use-mcp-tools.js +90 -0
  30. package/dist/use-mcp-tools.js.map +1 -0
  31. package/dist/use-mcp-web.d.ts +18 -0
  32. package/dist/use-mcp-web.d.ts.map +1 -0
  33. package/dist/use-mcp-web.js +25 -0
  34. package/dist/use-mcp-web.js.map +1 -0
  35. package/dist/use-tools.d.ts +78 -0
  36. package/dist/use-tools.d.ts.map +1 -0
  37. package/dist/use-tools.js +64 -0
  38. package/dist/use-tools.js.map +1 -0
  39. package/package.json +31 -0
  40. package/src/index.ts +5 -0
  41. package/src/mcp-web-context.ts +18 -0
  42. package/src/mcp-web-provider.ts +87 -0
  43. package/src/use-connected-mcp-web.ts +49 -0
  44. package/src/use-mcp-apps.ts +141 -0
  45. package/src/use-mcp-tools.ts +221 -0
  46. package/src/use-mcp-web.ts +25 -0
  47. package/tsconfig.json +10 -0
@@ -0,0 +1,58 @@
1
+ import { isCreatedApp } from '@mcp-web/types';
2
+ import { useContext, useEffect, useRef } from 'react';
3
+ import { MCPWebContext } from './mcp-web-context';
4
+ export function useApps(firstArg, ...rest) {
5
+ // Determine if first arg is MCPWeb instance or an app
6
+ const isMCPWebInstance = (value) => typeof value === 'object' &&
7
+ value !== null &&
8
+ 'addApp' in value &&
9
+ 'removeApp' in value &&
10
+ typeof value.addApp === 'function';
11
+ let mcpWebProp;
12
+ let appsToRegister;
13
+ if (isMCPWebInstance(firstArg)) {
14
+ mcpWebProp = firstArg;
15
+ appsToRegister = rest.flat();
16
+ }
17
+ else {
18
+ mcpWebProp = undefined;
19
+ appsToRegister = [firstArg, ...rest].flat();
20
+ }
21
+ // Try to get from context if not provided
22
+ const context = useContext(MCPWebContext);
23
+ const mcpWeb = mcpWebProp ?? context?.mcpWeb;
24
+ if (!mcpWeb) {
25
+ throw new Error('useApps requires either mcpWeb as first argument or MCPWebProvider in component tree');
26
+ }
27
+ // Keep a stable reference to the apps array
28
+ const appsRef = useRef(appsToRegister);
29
+ appsRef.current = appsToRegister;
30
+ // Keep a stable reference to mcpWeb
31
+ const mcpWebRef = useRef(mcpWeb);
32
+ mcpWebRef.current = mcpWeb;
33
+ useEffect(() => {
34
+ const cleanupFns = [];
35
+ const mcp = mcpWebRef.current;
36
+ for (const app of appsRef.current) {
37
+ if (isCreatedApp(app)) {
38
+ // Register CreatedApp
39
+ mcp.addApp(app);
40
+ cleanupFns.push(() => mcp.removeApp(app.definition.name));
41
+ }
42
+ else {
43
+ // Register raw AppDefinition
44
+ mcp.addApp(app);
45
+ cleanupFns.push(() => mcp.removeApp(app.name));
46
+ }
47
+ }
48
+ return () => {
49
+ for (const cleanup of cleanupFns) {
50
+ cleanup();
51
+ }
52
+ };
53
+ }, []);
54
+ // Note: Empty deps because we use refs - apps are registered once on mount
55
+ // and cleaned up on unmount. If you need to re-register on app change,
56
+ // use a key prop on the component.
57
+ }
58
+ //# sourceMappingURL=use-apps.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-apps.js","sourceRoot":"","sources":["../src/use-apps.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAoElD,MAAM,UAAU,OAAO,CACrB,QAAsD,EACtD,GAAG,IAA6C;IAEhD,sDAAsD;IACtD,MAAM,gBAAgB,GAAG,CAAC,KAAc,EAAmB,EAAE,CAC3D,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACd,QAAQ,IAAI,KAAK;QACjB,WAAW,IAAI,KAAK;QACpB,OAAQ,KAAgB,CAAC,MAAM,KAAK,UAAU,CAAC;IAEjD,IAAI,UAA8B,CAAC;IACnC,IAAI,cAAiC,CAAC;IAEtC,IAAI,gBAAgB,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC/B,UAAU,GAAG,QAAQ,CAAC;QACtB,cAAc,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC/B,CAAC;SAAM,CAAC;QACN,UAAU,GAAG,SAAS,CAAC;QACvB,cAAc,GAAG,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;IAC9C,CAAC;IAED,0CAA0C;IAC1C,MAAM,OAAO,GAAG,UAAU,CAAC,aAAa,CAAC,CAAC;IAC1C,MAAM,MAAM,GAAG,UAAU,IAAI,OAAO,EAAE,MAAM,CAAC;IAE7C,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CACb,sFAAsF,CACvF,CAAC;IACJ,CAAC;IAED,4CAA4C;IAC5C,MAAM,OAAO,GAAG,MAAM,CAAC,cAAc,CAAC,CAAC;IACvC,OAAO,CAAC,OAAO,GAAG,cAAc,CAAC;IAEjC,oCAAoC;IACpC,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;IACjC,SAAS,CAAC,OAAO,GAAG,MAAM,CAAC;IAE3B,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,UAAU,GAAmB,EAAE,CAAC;QACtC,MAAM,GAAG,GAAG,SAAS,CAAC,OAAO,CAAC;QAE9B,KAAK,MAAM,GAAG,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YAClC,IAAI,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC;gBACtB,sBAAsB;gBACtB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBAChB,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;YAC5D,CAAC;iBAAM,CAAC;gBACN,6BAA6B;gBAC7B,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBAChB,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;YACjD,CAAC;QACH,CAAC;QAED,OAAO,GAAG,EAAE;YACV,KAAK,MAAM,OAAO,IAAI,UAAU,EAAE,CAAC;gBACjC,OAAO,EAAE,CAAC;YACZ,CAAC;QACH,CAAC,CAAC;IACJ,CAAC,EAAE,EAAE,CAAC,CAAC;IACP,2EAA2E;IAC3E,uEAAuE;IACvE,mCAAmC;AACrC,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { MCPWeb } from "@mcp-web/core";
2
+ import type { MCPWebContextValue } from "./mcp-web-context";
3
+ /**
4
+ * Internal hook for managing MCPWeb connection lifecycle.
5
+ * Connects on mount and disconnects on unmount.
6
+ * Returns reactive connection state for triggering re-renders.
7
+ *
8
+ * Handles React StrictMode's double-mount behavior by using a ref to track
9
+ * whether we should actually disconnect on cleanup.
10
+ *
11
+ * @internal
12
+ */
13
+ export declare function useConnectedMCPWeb(mcpInstance: MCPWeb): MCPWebContextValue;
14
+ //# sourceMappingURL=use-connected-mcp-web.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-connected-mcp-web.d.ts","sourceRoot":"","sources":["../src/use-connected-mcp-web.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAE5C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAE5D;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,kBAAkB,CAkC1E"}
@@ -0,0 +1,44 @@
1
+ import { useEffect, useRef, useState } from "react";
2
+ /**
3
+ * Internal hook for managing MCPWeb connection lifecycle.
4
+ * Connects on mount and disconnects on unmount.
5
+ * Returns reactive connection state for triggering re-renders.
6
+ *
7
+ * Handles React StrictMode's double-mount behavior by using a ref to track
8
+ * whether we should actually disconnect on cleanup.
9
+ *
10
+ * @internal
11
+ */
12
+ export function useConnectedMCPWeb(mcpInstance) {
13
+ const [isConnected, setIsConnected] = useState(mcpInstance.connected);
14
+ // Track if the effect has been cleaned up to handle StrictMode double-mount
15
+ const cleanedUpRef = useRef(false);
16
+ useEffect(() => {
17
+ // Reset the cleanup flag on mount
18
+ cleanedUpRef.current = false;
19
+ if (!mcpInstance.connected) {
20
+ mcpInstance.connect().then(() => {
21
+ // Only update state if we haven't been cleaned up
22
+ if (!cleanedUpRef.current) {
23
+ setIsConnected(true);
24
+ }
25
+ });
26
+ }
27
+ else {
28
+ setIsConnected(true);
29
+ }
30
+ return () => {
31
+ cleanedUpRef.current = true;
32
+ // Use setTimeout to defer disconnect, allowing StrictMode's remount to cancel it
33
+ // If the component remounts (StrictMode), the new effect will run before this timeout
34
+ setTimeout(() => {
35
+ // Only disconnect if we're still in a cleaned-up state (no remount happened)
36
+ if (cleanedUpRef.current) {
37
+ mcpInstance.disconnect();
38
+ }
39
+ }, 0);
40
+ };
41
+ }, [mcpInstance]);
42
+ return { mcpWeb: mcpInstance, isConnected };
43
+ }
44
+ //# sourceMappingURL=use-connected-mcp-web.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-connected-mcp-web.js","sourceRoot":"","sources":["../src/use-connected-mcp-web.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAGpD;;;;;;;;;GASG;AACH,MAAM,UAAU,kBAAkB,CAAC,WAAmB;IACpD,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;IACtE,4EAA4E;IAC5E,MAAM,YAAY,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAEnC,SAAS,CAAC,GAAG,EAAE;QACb,kCAAkC;QAClC,YAAY,CAAC,OAAO,GAAG,KAAK,CAAC;QAE7B,IAAI,CAAC,WAAW,CAAC,SAAS,EAAE,CAAC;YAC3B,WAAW,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE;gBAC9B,kDAAkD;gBAClD,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,CAAC;oBAC1B,cAAc,CAAC,IAAI,CAAC,CAAC;gBACvB,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,cAAc,CAAC,IAAI,CAAC,CAAC;QACvB,CAAC;QAED,OAAO,GAAG,EAAE;YACV,YAAY,CAAC,OAAO,GAAG,IAAI,CAAC;YAC5B,iFAAiF;YACjF,sFAAsF;YACtF,UAAU,CAAC,GAAG,EAAE;gBACd,6EAA6E;gBAC7E,IAAI,YAAY,CAAC,OAAO,EAAE,CAAC;oBACzB,WAAW,CAAC,UAAU,EAAE,CAAC;gBAC3B,CAAC;YACH,CAAC,EAAE,CAAC,CAAC,CAAC;QACR,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;IAElB,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,CAAC;AAC9C,CAAC"}
@@ -0,0 +1,63 @@
1
+ import type { MCPWeb } from '@mcp-web/core';
2
+ import type { AppDefinition, CreatedApp } from '@mcp-web/types';
3
+ /**
4
+ * An app that can be registered with useApps.
5
+ * Can be a CreatedApp or a raw AppDefinition.
6
+ */
7
+ export type RegisterableApp = CreatedApp | AppDefinition;
8
+ /**
9
+ * Hook for registering MCP Apps with automatic cleanup on unmount.
10
+ *
11
+ * This is the recommended way to register MCP Apps in React applications.
12
+ * Apps are registered when the component mounts and automatically
13
+ * unregistered when the component unmounts.
14
+ *
15
+ * MCP Apps are visual UI components that AI can render inline in chat
16
+ * interfaces like Claude Desktop.
17
+ *
18
+ * @example Basic usage with createApp
19
+ * ```tsx
20
+ * // apps.ts
21
+ * import { createApp } from '@mcp-web/app';
22
+ *
23
+ * export const statisticsApp = createApp({
24
+ * name: 'show_statistics',
25
+ * description: 'Display statistics visualization',
26
+ * handler: () => ({
27
+ * totalTasks: todos.length,
28
+ * completedTasks: completedTodos.length,
29
+ * }),
30
+ * });
31
+ *
32
+ * // App.tsx
33
+ * import { useMCPApps } from '@mcp-web/react';
34
+ * import { statisticsApp } from './apps';
35
+ *
36
+ * function App() {
37
+ * useMCPApps(statisticsApp);
38
+ * return <div>...</div>;
39
+ * }
40
+ * ```
41
+ *
42
+ * @example Multiple apps
43
+ * ```tsx
44
+ * function App() {
45
+ * useMCPApps(statisticsApp, chartApp, dashboardApp);
46
+ * return <div>...</div>;
47
+ * }
48
+ * ```
49
+ *
50
+ * @example Conditional app registration
51
+ * ```tsx
52
+ * function Analytics() {
53
+ * // This app only exists while Analytics is mounted
54
+ * useMCPApps(analyticsApp);
55
+ * return <div>Analytics enabled</div>;
56
+ * }
57
+ * ```
58
+ *
59
+ * @param apps - Apps to register (variadic or array)
60
+ */
61
+ export declare function useMCPApps(...apps: (RegisterableApp | RegisterableApp[])[]): void;
62
+ export declare function useMCPApps(mcpWeb: MCPWeb, ...apps: (RegisterableApp | RegisterableApp[])[]): void;
63
+ //# sourceMappingURL=use-mcp-apps.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-mcp-apps.d.ts","sourceRoot":"","sources":["../src/use-mcp-apps.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAKhE;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG,UAAU,GAAG,aAAa,CAAC;AAEzD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AACH,wBAAgB,UAAU,CACxB,GAAG,IAAI,EAAE,CAAC,eAAe,GAAG,eAAe,EAAE,CAAC,EAAE,GAC/C,IAAI,CAAC;AAER,wBAAgB,UAAU,CACxB,MAAM,EAAE,MAAM,EACd,GAAG,IAAI,EAAE,CAAC,eAAe,GAAG,eAAe,EAAE,CAAC,EAAE,GAC/C,IAAI,CAAC"}
@@ -0,0 +1,58 @@
1
+ import { isCreatedApp } from '@mcp-web/types';
2
+ import { useContext, useEffect, useRef } from 'react';
3
+ import { MCPWebContext } from './mcp-web-context';
4
+ export function useMCPApps(firstArg, ...rest) {
5
+ // Determine if first arg is MCPWeb instance or an app
6
+ const isMCPWebInstance = (value) => typeof value === 'object' &&
7
+ value !== null &&
8
+ 'addApp' in value &&
9
+ 'removeApp' in value &&
10
+ typeof value.addApp === 'function';
11
+ let mcpWebProp;
12
+ let appsToRegister;
13
+ if (isMCPWebInstance(firstArg)) {
14
+ mcpWebProp = firstArg;
15
+ appsToRegister = rest.flat();
16
+ }
17
+ else {
18
+ mcpWebProp = undefined;
19
+ appsToRegister = [firstArg, ...rest].flat();
20
+ }
21
+ // Try to get from context if not provided
22
+ const context = useContext(MCPWebContext);
23
+ const mcpWeb = mcpWebProp ?? context?.mcpWeb;
24
+ if (!mcpWeb) {
25
+ throw new Error('useApps requires either mcpWeb as first argument or MCPWebProvider in component tree');
26
+ }
27
+ // Keep a stable reference to the apps array
28
+ const appsRef = useRef(appsToRegister);
29
+ appsRef.current = appsToRegister;
30
+ // Keep a stable reference to mcpWeb
31
+ const mcpWebRef = useRef(mcpWeb);
32
+ mcpWebRef.current = mcpWeb;
33
+ useEffect(() => {
34
+ const cleanupFns = [];
35
+ const mcp = mcpWebRef.current;
36
+ for (const app of appsRef.current) {
37
+ if (isCreatedApp(app)) {
38
+ // Register CreatedApp
39
+ mcp.addApp(app);
40
+ cleanupFns.push(() => mcp.removeApp(app.definition.name));
41
+ }
42
+ else {
43
+ // Register raw AppDefinition
44
+ mcp.addApp(app);
45
+ cleanupFns.push(() => mcp.removeApp(app.name));
46
+ }
47
+ }
48
+ return () => {
49
+ for (const cleanup of cleanupFns) {
50
+ cleanup();
51
+ }
52
+ };
53
+ }, []);
54
+ // Note: Empty deps because we use refs - apps are registered once on mount
55
+ // and cleaned up on unmount. If you need to re-register on app change,
56
+ // use a key prop on the component.
57
+ }
58
+ //# sourceMappingURL=use-mcp-apps.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-mcp-apps.js","sourceRoot":"","sources":["../src/use-mcp-apps.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAsElD,MAAM,UAAU,UAAU,CACxB,QAAsD,EACtD,GAAG,IAA6C;IAEhD,sDAAsD;IACtD,MAAM,gBAAgB,GAAG,CAAC,KAAc,EAAmB,EAAE,CAC3D,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACd,QAAQ,IAAI,KAAK;QACjB,WAAW,IAAI,KAAK;QACpB,OAAQ,KAAgB,CAAC,MAAM,KAAK,UAAU,CAAC;IAEjD,IAAI,UAA8B,CAAC;IACnC,IAAI,cAAiC,CAAC;IAEtC,IAAI,gBAAgB,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC/B,UAAU,GAAG,QAAQ,CAAC;QACtB,cAAc,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC/B,CAAC;SAAM,CAAC;QACN,UAAU,GAAG,SAAS,CAAC;QACvB,cAAc,GAAG,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;IAC9C,CAAC;IAED,0CAA0C;IAC1C,MAAM,OAAO,GAAG,UAAU,CAAC,aAAa,CAAC,CAAC;IAC1C,MAAM,MAAM,GAAG,UAAU,IAAI,OAAO,EAAE,MAAM,CAAC;IAE7C,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CACb,sFAAsF,CACvF,CAAC;IACJ,CAAC;IAED,4CAA4C;IAC5C,MAAM,OAAO,GAAG,MAAM,CAAC,cAAc,CAAC,CAAC;IACvC,OAAO,CAAC,OAAO,GAAG,cAAc,CAAC;IAEjC,oCAAoC;IACpC,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;IACjC,SAAS,CAAC,OAAO,GAAG,MAAM,CAAC;IAE3B,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,UAAU,GAAmB,EAAE,CAAC;QACtC,MAAM,GAAG,GAAG,SAAS,CAAC,OAAO,CAAC;QAE9B,KAAK,MAAM,GAAG,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YAClC,IAAI,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC;gBACtB,sBAAsB;gBACtB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBAChB,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;YAC5D,CAAC;iBAAM,CAAC;gBACN,6BAA6B;gBAC7B,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBAChB,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;YACjD,CAAC;QACH,CAAC;QAED,OAAO,GAAG,EAAE;YACV,KAAK,MAAM,OAAO,IAAI,UAAU,EAAE,CAAC;gBACjC,OAAO,EAAE,CAAC;YACZ,CAAC;QACH,CAAC,CAAC;IACJ,CAAC,EAAE,EAAE,CAAC,CAAC;IACP,2EAA2E;IAC3E,uEAAuE;IACvE,mCAAmC;AACrC,CAAC"}
@@ -0,0 +1,99 @@
1
+ import type { CreatedStateTools, CreatedTool, MCPWeb, ToolRegistrationError } from '@mcp-web/core';
2
+ import type { ToolDefinition } from '@mcp-web/types';
3
+ /**
4
+ * A tool that can be registered with useMCPTools.
5
+ * Can be a CreatedTool, CreatedStateTools, or a raw ToolDefinition.
6
+ */
7
+ export type RegisterableTool = CreatedTool | CreatedStateTools<any> | ToolDefinition;
8
+ /**
9
+ * Options for the useMCPTools hook.
10
+ */
11
+ export interface UseMCPToolsOptions {
12
+ /** Called if the bridge rejects any tool registration (e.g., schema conflict with a sibling session). */
13
+ onRegistrationError?: (error: ToolRegistrationError) => void;
14
+ }
15
+ /**
16
+ * Hook for registering MCP tools with automatic cleanup on unmount.
17
+ *
18
+ * This is the recommended way to register tools in React applications.
19
+ * Tools are registered when the component mounts and automatically
20
+ * unregistered when the component unmounts.
21
+ *
22
+ * @example Basic usage with created tools
23
+ * ```tsx
24
+ * // tools.ts
25
+ * import { createTool, createStateTools } from '@mcp-web/core';
26
+ *
27
+ * export const timeTool = createTool({
28
+ * name: 'get_time',
29
+ * description: 'Get current time',
30
+ * handler: () => new Date().toISOString(),
31
+ * });
32
+ *
33
+ * export const todoTools = createStateTools({
34
+ * name: 'todos',
35
+ * description: 'Todo list',
36
+ * get: () => store.get(todosAtom),
37
+ * set: (value) => store.set(todosAtom, value),
38
+ * schema: TodosSchema,
39
+ * expand: true,
40
+ * });
41
+ *
42
+ * // App.tsx
43
+ * import { useMCPTools } from '@mcp-web/react';
44
+ * import { timeTool, todoTools } from './tools';
45
+ *
46
+ * function App() {
47
+ * useMCPTools(timeTool, todoTools);
48
+ * return <div>...</div>;
49
+ * }
50
+ * ```
51
+ *
52
+ * @example With registration error handling
53
+ * ```tsx
54
+ * function App() {
55
+ * useMCPTools(myTool, {
56
+ * onRegistrationError: (error) => {
57
+ * console.error(`Tool ${error.toolName} rejected: ${error.message}`);
58
+ * },
59
+ * });
60
+ * return <div>...</div>;
61
+ * }
62
+ * ```
63
+ *
64
+ * @example Conditional tool registration
65
+ * ```tsx
66
+ * function AdminPanel() {
67
+ * // These tools only exist while AdminPanel is mounted
68
+ * useMCPTools(adminTools);
69
+ * return <div>Admin controls</div>;
70
+ * }
71
+ *
72
+ * function App() {
73
+ * const [isAdmin, setIsAdmin] = useState(false);
74
+ * return (
75
+ * <div>
76
+ * {isAdmin && <AdminPanel />}
77
+ * </div>
78
+ * );
79
+ * }
80
+ * ```
81
+ *
82
+ * @example With array of tools
83
+ * ```tsx
84
+ * const allTools = [todoTools, projectTools, settingsTools];
85
+ *
86
+ * function App() {
87
+ * useMCPTools(allTools);
88
+ * // or: useMCPTools(...allTools);
89
+ * return <div>...</div>;
90
+ * }
91
+ * ```
92
+ *
93
+ * @param tools - Tools to register (variadic or array), optionally followed by an options object
94
+ */
95
+ export declare function useMCPTools(...tools: (RegisterableTool | RegisterableTool[])[]): void;
96
+ export declare function useMCPTools(mcpWeb: MCPWeb, ...tools: (RegisterableTool | RegisterableTool[])[]): void;
97
+ export declare function useMCPTools(...args: [...(RegisterableTool | RegisterableTool[])[], UseMCPToolsOptions]): void;
98
+ export declare function useMCPTools(mcpWeb: MCPWeb, ...args: [...(RegisterableTool | RegisterableTool[])[], UseMCPToolsOptions]): void;
99
+ //# sourceMappingURL=use-mcp-tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-mcp-tools.d.ts","sourceRoot":"","sources":["../src/use-mcp-tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAEnG,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAIrD;;;GAGG;AACH,MAAM,MAAM,gBAAgB,GACxB,WAAW,GAEX,iBAAiB,CAAC,GAAG,CAAC,GACtB,cAAc,CAAC;AAEnB;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,yGAAyG;IACzG,mBAAmB,CAAC,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,IAAI,CAAC;CAC9D;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+EG;AACH,wBAAgB,WAAW,CACzB,GAAG,KAAK,EAAE,CAAC,gBAAgB,GAAG,gBAAgB,EAAE,CAAC,EAAE,GAClD,IAAI,CAAC;AAER,wBAAgB,WAAW,CACzB,MAAM,EAAE,MAAM,EACd,GAAG,KAAK,EAAE,CAAC,gBAAgB,GAAG,gBAAgB,EAAE,CAAC,EAAE,GAClD,IAAI,CAAC;AAER,wBAAgB,WAAW,CACzB,GAAG,IAAI,EAAE,CAAC,GAAG,CAAC,gBAAgB,GAAG,gBAAgB,EAAE,CAAC,EAAE,EAAE,kBAAkB,CAAC,GAC1E,IAAI,CAAC;AAER,wBAAgB,WAAW,CACzB,MAAM,EAAE,MAAM,EACd,GAAG,IAAI,EAAE,CAAC,GAAG,CAAC,gBAAgB,GAAG,gBAAgB,EAAE,CAAC,EAAE,EAAE,kBAAkB,CAAC,GAC1E,IAAI,CAAC"}
@@ -0,0 +1,90 @@
1
+ import { isCreatedStateTools, isCreatedTool } from '@mcp-web/core';
2
+ import { useContext, useEffect, useRef } from 'react';
3
+ import { MCPWebContext } from './mcp-web-context';
4
+ // biome-ignore lint/suspicious/noExplicitAny: Implementation signature must be broad to support all overloads
5
+ export function useMCPTools(...allRawArgs) {
6
+ const firstArg = allRawArgs[0];
7
+ const rest = allRawArgs.slice(1);
8
+ // Determine if first arg is MCPWeb instance or a tool
9
+ const isMCPWebInstance = (value) => typeof value === 'object' &&
10
+ value !== null &&
11
+ 'addTool' in value &&
12
+ 'addStateTools' in value &&
13
+ typeof value.addTool === 'function';
14
+ const isOptions = (value) => typeof value === 'object' &&
15
+ value !== null &&
16
+ !Array.isArray(value) &&
17
+ !isMCPWebInstance(value) &&
18
+ !isCreatedTool(value) &&
19
+ !isCreatedStateTools(value) &&
20
+ !('handler' in value) &&
21
+ 'onRegistrationError' in value;
22
+ let mcpWebProp;
23
+ let toolsToRegister;
24
+ let options;
25
+ // Extract options from the last argument if present
26
+ const allArgs = [firstArg, ...rest];
27
+ const lastArg = allArgs[allArgs.length - 1];
28
+ if (isOptions(lastArg)) {
29
+ options = lastArg;
30
+ allArgs.pop();
31
+ }
32
+ if (isMCPWebInstance(allArgs[0])) {
33
+ mcpWebProp = allArgs[0];
34
+ toolsToRegister = allArgs.slice(1).flat();
35
+ }
36
+ else {
37
+ mcpWebProp = undefined;
38
+ toolsToRegister = allArgs.flat();
39
+ }
40
+ // Try to get from context if not provided
41
+ const context = useContext(MCPWebContext);
42
+ const mcpWeb = mcpWebProp ?? context?.mcpWeb;
43
+ if (!mcpWeb) {
44
+ throw new Error('useMCPTools requires either mcpWeb as first argument or MCPWebProvider in component tree');
45
+ }
46
+ // Keep a stable reference to the tools array
47
+ const toolsRef = useRef(toolsToRegister);
48
+ toolsRef.current = toolsToRegister;
49
+ // Keep a stable reference to mcpWeb
50
+ const mcpWebRef = useRef(mcpWeb);
51
+ mcpWebRef.current = mcpWeb;
52
+ // Keep a stable reference to options
53
+ const optionsRef = useRef(options);
54
+ optionsRef.current = options;
55
+ useEffect(() => {
56
+ const cleanupFns = [];
57
+ const mcp = mcpWebRef.current;
58
+ const opts = optionsRef.current;
59
+ const addToolOptions = opts?.onRegistrationError
60
+ ? { onRegistrationError: opts.onRegistrationError }
61
+ : undefined;
62
+ for (const tool of toolsRef.current) {
63
+ if (isCreatedTool(tool)) {
64
+ // Register CreatedTool
65
+ mcp.addTool(tool, addToolOptions);
66
+ cleanupFns.push(() => mcp.removeTool(tool.definition.name));
67
+ }
68
+ else if (isCreatedStateTools(tool)) {
69
+ // Register CreatedStateTools
70
+ const [, , cleanup] = mcp.addStateTools(tool);
71
+ cleanupFns.push(cleanup);
72
+ }
73
+ else {
74
+ // Register raw ToolDefinition
75
+ // biome-ignore lint/suspicious/noExplicitAny: Internal addTool accepts ToolDefinition, but overloads are stricter
76
+ mcp.addTool(tool, addToolOptions);
77
+ cleanupFns.push(() => mcp.removeTool(tool.name));
78
+ }
79
+ }
80
+ return () => {
81
+ for (const cleanup of cleanupFns) {
82
+ cleanup();
83
+ }
84
+ };
85
+ }, []);
86
+ // Note: Empty deps because we use refs - tools are registered once on mount
87
+ // and cleaned up on unmount. If you need to re-register on tool change,
88
+ // use a key prop on the component.
89
+ }
90
+ //# sourceMappingURL=use-mcp-tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-mcp-tools.js","sourceRoot":"","sources":["../src/use-mcp-tools.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import { type MCPWebContextValue } from "./mcp-web-context";
2
+ /**
3
+ * Hook for accessing MCPWeb instance from context.
4
+ * Must be used within MCPWebProvider.
5
+ *
6
+ * @returns Object containing the MCPWeb instance and connection state
7
+ * @throws Error if used outside of MCPWebProvider
8
+ *
9
+ * @example
10
+ * ```tsx
11
+ * function MyComponent() {
12
+ * const { mcpWeb, isConnected } = useMCPWeb();
13
+ * // Use mcpWeb...
14
+ * }
15
+ * ```
16
+ */
17
+ export declare function useMCPWeb(): MCPWebContextValue;
18
+ //# sourceMappingURL=use-mcp-web.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-mcp-web.d.ts","sourceRoot":"","sources":["../src/use-mcp-web.ts"],"names":[],"mappings":"AACA,OAAO,EAAiB,KAAK,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAE3E;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,SAAS,IAAI,kBAAkB,CAM9C"}
@@ -0,0 +1,25 @@
1
+ import { useContext } from "react";
2
+ import { MCPWebContext } from "./mcp-web-context";
3
+ /**
4
+ * Hook for accessing MCPWeb instance from context.
5
+ * Must be used within MCPWebProvider.
6
+ *
7
+ * @returns Object containing the MCPWeb instance and connection state
8
+ * @throws Error if used outside of MCPWebProvider
9
+ *
10
+ * @example
11
+ * ```tsx
12
+ * function MyComponent() {
13
+ * const { mcpWeb, isConnected } = useMCPWeb();
14
+ * // Use mcpWeb...
15
+ * }
16
+ * ```
17
+ */
18
+ export function useMCPWeb() {
19
+ const context = useContext(MCPWebContext);
20
+ if (!context) {
21
+ throw new Error('useMCPWeb must be used within MCPWebProvider');
22
+ }
23
+ return context;
24
+ }
25
+ //# sourceMappingURL=use-mcp-web.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-mcp-web.js","sourceRoot":"","sources":["../src/use-mcp-web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AACnC,OAAO,EAAE,aAAa,EAA2B,MAAM,mBAAmB,CAAC;AAE3E;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,SAAS;IACvB,MAAM,OAAO,GAAG,UAAU,CAAC,aAAa,CAAC,CAAC;IAC1C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;IAClE,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,78 @@
1
+ import type { CreatedStateTools, CreatedTool, MCPWeb } from '@mcp-web/core';
2
+ import type { ToolDefinition } from '@mcp-web/types';
3
+ /**
4
+ * A tool that can be registered with useTools.
5
+ * Can be a CreatedTool, CreatedStateTools, or a raw ToolDefinition.
6
+ */
7
+ export type RegisterableTool = CreatedTool | CreatedStateTools<any> | ToolDefinition;
8
+ /**
9
+ * Hook for registering pre-created tools with automatic cleanup on unmount.
10
+ *
11
+ * This is the recommended way to register tools in React applications.
12
+ * Tools are registered when the component mounts and automatically
13
+ * unregistered when the component unmounts.
14
+ *
15
+ * @example Basic usage with created tools
16
+ * ```tsx
17
+ * // tools.ts
18
+ * import { createTool, createStateTools } from '@mcp-web/core';
19
+ *
20
+ * export const timeTool = createTool({
21
+ * name: 'get_time',
22
+ * description: 'Get current time',
23
+ * handler: () => new Date().toISOString(),
24
+ * });
25
+ *
26
+ * export const todoTools = createStateTools({
27
+ * name: 'todos',
28
+ * description: 'Todo list',
29
+ * get: () => store.get(todosAtom),
30
+ * set: (value) => store.set(todosAtom, value),
31
+ * schema: TodosSchema,
32
+ * expand: true,
33
+ * });
34
+ *
35
+ * // App.tsx
36
+ * import { useTools } from '@mcp-web/react';
37
+ * import { timeTool, todoTools } from './tools';
38
+ *
39
+ * function App() {
40
+ * useTools(timeTool, todoTools);
41
+ * return <div>...</div>;
42
+ * }
43
+ * ```
44
+ *
45
+ * @example Conditional tool registration
46
+ * ```tsx
47
+ * function AdminPanel() {
48
+ * // These tools only exist while AdminPanel is mounted
49
+ * useTools(adminTools);
50
+ * return <div>Admin controls</div>;
51
+ * }
52
+ *
53
+ * function App() {
54
+ * const [isAdmin, setIsAdmin] = useState(false);
55
+ * return (
56
+ * <div>
57
+ * {isAdmin && <AdminPanel />}
58
+ * </div>
59
+ * );
60
+ * }
61
+ * ```
62
+ *
63
+ * @example With array of tools
64
+ * ```tsx
65
+ * const allTools = [todoTools, projectTools, settingsTools];
66
+ *
67
+ * function App() {
68
+ * useTools(allTools);
69
+ * // or: useTools(...allTools);
70
+ * return <div>...</div>;
71
+ * }
72
+ * ```
73
+ *
74
+ * @param tools - Tools to register (variadic or array)
75
+ */
76
+ export declare function useTools(...tools: (RegisterableTool | RegisterableTool[])[]): void;
77
+ export declare function useTools(mcpWeb: MCPWeb, ...tools: (RegisterableTool | RegisterableTool[])[]): void;
78
+ //# sourceMappingURL=use-tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-tools.d.ts","sourceRoot":"","sources":["../src/use-tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAE5E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAIrD;;;GAGG;AACH,MAAM,MAAM,gBAAgB,GACxB,WAAW,GAEX,iBAAiB,CAAC,GAAG,CAAC,GACtB,cAAc,CAAC;AAEnB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmEG;AACH,wBAAgB,QAAQ,CACtB,GAAG,KAAK,EAAE,CAAC,gBAAgB,GAAG,gBAAgB,EAAE,CAAC,EAAE,GAClD,IAAI,CAAC;AAER,wBAAgB,QAAQ,CACtB,MAAM,EAAE,MAAM,EACd,GAAG,KAAK,EAAE,CAAC,gBAAgB,GAAG,gBAAgB,EAAE,CAAC,EAAE,GAClD,IAAI,CAAC"}
@@ -0,0 +1,64 @@
1
+ import { isCreatedStateTools, isCreatedTool } from '@mcp-web/core';
2
+ import { useContext, useEffect, useRef } from 'react';
3
+ import { MCPWebContext } from './mcp-web-context';
4
+ export function useTools(firstArg, ...rest) {
5
+ // Determine if first arg is MCPWeb instance or a tool
6
+ const isMCPWebInstance = (value) => typeof value === 'object' &&
7
+ value !== null &&
8
+ 'addTool' in value &&
9
+ 'addStateTools' in value &&
10
+ typeof value.addTool === 'function';
11
+ let mcpWebProp;
12
+ let toolsToRegister;
13
+ if (isMCPWebInstance(firstArg)) {
14
+ mcpWebProp = firstArg;
15
+ toolsToRegister = rest.flat();
16
+ }
17
+ else {
18
+ mcpWebProp = undefined;
19
+ toolsToRegister = [firstArg, ...rest].flat();
20
+ }
21
+ // Try to get from context if not provided
22
+ const context = useContext(MCPWebContext);
23
+ const mcpWeb = mcpWebProp ?? context?.mcpWeb;
24
+ if (!mcpWeb) {
25
+ throw new Error('useTools requires either mcpWeb as first argument or MCPWebProvider in component tree');
26
+ }
27
+ // Keep a stable reference to the tools array
28
+ const toolsRef = useRef(toolsToRegister);
29
+ toolsRef.current = toolsToRegister;
30
+ // Keep a stable reference to mcpWeb
31
+ const mcpWebRef = useRef(mcpWeb);
32
+ mcpWebRef.current = mcpWeb;
33
+ useEffect(() => {
34
+ const cleanupFns = [];
35
+ const mcp = mcpWebRef.current;
36
+ for (const tool of toolsRef.current) {
37
+ if (isCreatedTool(tool)) {
38
+ // Register CreatedTool
39
+ mcp.addTool(tool);
40
+ cleanupFns.push(() => mcp.removeTool(tool.definition.name));
41
+ }
42
+ else if (isCreatedStateTools(tool)) {
43
+ // Register CreatedStateTools
44
+ const [, , cleanup] = mcp.addStateTools(tool);
45
+ cleanupFns.push(cleanup);
46
+ }
47
+ else {
48
+ // Register raw ToolDefinition
49
+ // biome-ignore lint/suspicious/noExplicitAny: Internal addTool accepts ToolDefinition, but overloads are stricter
50
+ mcp.addTool(tool);
51
+ cleanupFns.push(() => mcp.removeTool(tool.name));
52
+ }
53
+ }
54
+ return () => {
55
+ for (const cleanup of cleanupFns) {
56
+ cleanup();
57
+ }
58
+ };
59
+ }, []);
60
+ // Note: Empty deps because we use refs - tools are registered once on mount
61
+ // and cleaned up on unmount. If you need to re-register on tool change,
62
+ // use a key prop on the component.
63
+ }
64
+ //# sourceMappingURL=use-tools.js.map