@frontmcp/react 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +263 -0
  3. package/ai/createToolHandler.d.ts +10 -0
  4. package/ai/createToolHandler.d.ts.map +1 -0
  5. package/ai/index.d.ts +7 -0
  6. package/ai/index.d.ts.map +1 -0
  7. package/ai/index.js +416 -0
  8. package/ai/types.d.ts +52 -0
  9. package/ai/types.d.ts.map +1 -0
  10. package/ai/useAITools.d.ts +17 -0
  11. package/ai/useAITools.d.ts.map +1 -0
  12. package/ai/useTools.d.ts +19 -0
  13. package/ai/useTools.d.ts.map +1 -0
  14. package/api/api.types.d.ts +61 -0
  15. package/api/api.types.d.ts.map +1 -0
  16. package/api/createFetchClient.d.ts +9 -0
  17. package/api/createFetchClient.d.ts.map +1 -0
  18. package/api/index.d.ts +12 -0
  19. package/api/index.d.ts.map +1 -0
  20. package/api/index.js +402 -0
  21. package/api/parseOpenApiSpec.d.ts +9 -0
  22. package/api/parseOpenApiSpec.d.ts.map +1 -0
  23. package/api/useApiClient.d.ts +9 -0
  24. package/api/useApiClient.d.ts.map +1 -0
  25. package/components/AgentContent.d.ts +30 -0
  26. package/components/AgentContent.d.ts.map +1 -0
  27. package/components/AgentSearch.d.ts +35 -0
  28. package/components/AgentSearch.d.ts.map +1 -0
  29. package/components/ComponentRegistry.d.ts +36 -0
  30. package/components/ComponentRegistry.d.ts.map +1 -0
  31. package/components/DomResources.d.ts +16 -0
  32. package/components/DomResources.d.ts.map +1 -0
  33. package/components/DynamicRenderer.d.ts +19 -0
  34. package/components/DynamicRenderer.d.ts.map +1 -0
  35. package/components/OutputDisplay.d.ts +11 -0
  36. package/components/OutputDisplay.d.ts.map +1 -0
  37. package/components/PromptForm.d.ts +13 -0
  38. package/components/PromptForm.d.ts.map +1 -0
  39. package/components/ResourceViewer.d.ts +18 -0
  40. package/components/ResourceViewer.d.ts.map +1 -0
  41. package/components/ToolForm.d.ts +16 -0
  42. package/components/ToolForm.d.ts.map +1 -0
  43. package/components/index.d.ts +21 -0
  44. package/components/index.d.ts.map +1 -0
  45. package/components/mcpComponent.d.ts +48 -0
  46. package/components/mcpComponent.d.ts.map +1 -0
  47. package/esm/ai/index.mjs +393 -0
  48. package/esm/api/index.mjs +379 -0
  49. package/esm/index.mjs +1814 -0
  50. package/esm/package.json +111 -0
  51. package/esm/router/index.mjs +157 -0
  52. package/esm/state/index.mjs +450 -0
  53. package/hooks/index.d.ts +21 -0
  54. package/hooks/index.d.ts.map +1 -0
  55. package/hooks/useCallTool.d.ts +9 -0
  56. package/hooks/useCallTool.d.ts.map +1 -0
  57. package/hooks/useComponentTree.d.ts +21 -0
  58. package/hooks/useComponentTree.d.ts.map +1 -0
  59. package/hooks/useDynamicResource.d.ts +20 -0
  60. package/hooks/useDynamicResource.d.ts.map +1 -0
  61. package/hooks/useDynamicTool.d.ts +39 -0
  62. package/hooks/useDynamicTool.d.ts.map +1 -0
  63. package/hooks/useFrontMcp.d.ts +8 -0
  64. package/hooks/useFrontMcp.d.ts.map +1 -0
  65. package/hooks/useGetPrompt.d.ts +13 -0
  66. package/hooks/useGetPrompt.d.ts.map +1 -0
  67. package/hooks/useListPrompts.d.ts +10 -0
  68. package/hooks/useListPrompts.d.ts.map +1 -0
  69. package/hooks/useListResources.d.ts +14 -0
  70. package/hooks/useListResources.d.ts.map +1 -0
  71. package/hooks/useListTools.d.ts +10 -0
  72. package/hooks/useListTools.d.ts.map +1 -0
  73. package/hooks/useReadResource.d.ts +23 -0
  74. package/hooks/useReadResource.d.ts.map +1 -0
  75. package/hooks/useResolvedServer.d.ts +16 -0
  76. package/hooks/useResolvedServer.d.ts.map +1 -0
  77. package/hooks/useServer.d.ts +17 -0
  78. package/hooks/useServer.d.ts.map +1 -0
  79. package/hooks/useStoreResource.d.ts +22 -0
  80. package/hooks/useStoreResource.d.ts.map +1 -0
  81. package/index.d.ts +33 -0
  82. package/index.d.ts.map +1 -0
  83. package/index.js +1821 -0
  84. package/package.json +111 -0
  85. package/provider/FrontMcpContext.d.ts +6 -0
  86. package/provider/FrontMcpContext.d.ts.map +1 -0
  87. package/provider/FrontMcpProvider.d.ts +34 -0
  88. package/provider/FrontMcpProvider.d.ts.map +1 -0
  89. package/provider/index.d.ts +4 -0
  90. package/provider/index.d.ts.map +1 -0
  91. package/registry/DynamicRegistry.d.ts +55 -0
  92. package/registry/DynamicRegistry.d.ts.map +1 -0
  93. package/registry/ServerRegistry.d.ts +43 -0
  94. package/registry/ServerRegistry.d.ts.map +1 -0
  95. package/registry/createWrappedServer.d.ts +14 -0
  96. package/registry/createWrappedServer.d.ts.map +1 -0
  97. package/registry/index.d.ts +5 -0
  98. package/registry/index.d.ts.map +1 -0
  99. package/router/current-route.resource.d.ts +11 -0
  100. package/router/current-route.resource.d.ts.map +1 -0
  101. package/router/go-back.tool.d.ts +18 -0
  102. package/router/go-back.tool.d.ts.map +1 -0
  103. package/router/index.d.ts +9 -0
  104. package/router/index.d.ts.map +1 -0
  105. package/router/index.js +180 -0
  106. package/router/navigate.tool.d.ts +35 -0
  107. package/router/navigate.tool.d.ts.map +1 -0
  108. package/router/router-bridge.d.ts +20 -0
  109. package/router/router-bridge.d.ts.map +1 -0
  110. package/router/router.entries.d.ts +23 -0
  111. package/router/router.entries.d.ts.map +1 -0
  112. package/router/useRouterBridge.d.ts +7 -0
  113. package/router/useRouterBridge.d.ts.map +1 -0
  114. package/state/adapters/createStore.d.ts +15 -0
  115. package/state/adapters/createStore.d.ts.map +1 -0
  116. package/state/adapters/index.d.ts +7 -0
  117. package/state/adapters/index.d.ts.map +1 -0
  118. package/state/adapters/reduxAdapter.d.ts +21 -0
  119. package/state/adapters/reduxAdapter.d.ts.map +1 -0
  120. package/state/adapters/valtioAdapter.d.ts +19 -0
  121. package/state/adapters/valtioAdapter.d.ts.map +1 -0
  122. package/state/index.d.ts +15 -0
  123. package/state/index.d.ts.map +1 -0
  124. package/state/index.js +473 -0
  125. package/state/state.types.d.ts +48 -0
  126. package/state/state.types.d.ts.map +1 -0
  127. package/state/useReduxResource.d.ts +8 -0
  128. package/state/useReduxResource.d.ts.map +1 -0
  129. package/state/useStoreRegistration.d.ts +14 -0
  130. package/state/useStoreRegistration.d.ts.map +1 -0
  131. package/state/useStoreResource.d.ts +10 -0
  132. package/state/useStoreResource.d.ts.map +1 -0
  133. package/state/useValtioResource.d.ts +9 -0
  134. package/state/useValtioResource.d.ts.map +1 -0
  135. package/types.d.ts +127 -0
  136. package/types.d.ts.map +1 -0
  137. package/utils/index.d.ts +2 -0
  138. package/utils/index.d.ts.map +1 -0
  139. package/utils/zodToJsonSchema.d.ts +9 -0
  140. package/utils/zodToJsonSchema.d.ts.map +1 -0
package/esm/index.mjs ADDED
@@ -0,0 +1,1814 @@
1
+ // libs/react/src/index.ts
2
+ import { create, clearCreateCache } from "@frontmcp/sdk";
3
+ import { connect, connectOpenAI, connectClaude, connectLangChain, connectVercelAI } from "@frontmcp/sdk";
4
+ import {
5
+ Tool,
6
+ FrontMcpTool,
7
+ tool,
8
+ frontMcpTool,
9
+ Resource,
10
+ FrontMcpResource,
11
+ resource,
12
+ frontMcpResource,
13
+ ResourceTemplate,
14
+ FrontMcpResourceTemplate,
15
+ resourceTemplate,
16
+ frontMcpResourceTemplate,
17
+ Prompt,
18
+ FrontMcpPrompt,
19
+ prompt,
20
+ frontMcpPrompt,
21
+ App,
22
+ FrontMcpApp,
23
+ FrontMcp,
24
+ Adapter,
25
+ FrontMcpAdapter,
26
+ Plugin,
27
+ FrontMcpPlugin
28
+ } from "@frontmcp/sdk";
29
+ import { ToolContext, ResourceContext, PromptContext, ExecutionContextBase } from "@frontmcp/sdk";
30
+
31
+ // libs/react/src/registry/ServerRegistry.ts
32
+ var ServerRegistry = class {
33
+ entries = /* @__PURE__ */ new Map();
34
+ listeners = /* @__PURE__ */ new Set();
35
+ version = 0;
36
+ register(name, server) {
37
+ this.entries.set(name, {
38
+ server,
39
+ client: null,
40
+ status: "idle",
41
+ error: null,
42
+ tools: [],
43
+ resources: [],
44
+ resourceTemplates: [],
45
+ prompts: []
46
+ });
47
+ this.notify();
48
+ }
49
+ unregister(name) {
50
+ this.entries.delete(name);
51
+ this.notify();
52
+ }
53
+ get(name) {
54
+ return this.entries.get(name);
55
+ }
56
+ has(name) {
57
+ return this.entries.has(name);
58
+ }
59
+ list() {
60
+ return [...this.entries.keys()];
61
+ }
62
+ async connect(name) {
63
+ const entry = this.entries.get(name);
64
+ if (!entry) throw new Error(`Server "${name}" not registered`);
65
+ if (entry.client) return entry.client;
66
+ this.entries.set(name, { ...entry, status: "connecting", error: null });
67
+ this.notify();
68
+ try {
69
+ const client = await entry.server.connect();
70
+ const [toolsResult, resourcesResult, templatesResult, promptsResult] = await Promise.all([
71
+ client.listTools(),
72
+ client.listResources(),
73
+ client.listResourceTemplates(),
74
+ client.listPrompts()
75
+ ]);
76
+ const connected = {
77
+ ...entry,
78
+ client,
79
+ tools: toolsResult,
80
+ resources: resourcesResult.resources ?? [],
81
+ resourceTemplates: templatesResult.resourceTemplates ?? [],
82
+ prompts: promptsResult.prompts ?? [],
83
+ status: "connected",
84
+ error: null
85
+ };
86
+ this.entries.set(name, connected);
87
+ this.notify();
88
+ return client;
89
+ } catch (err) {
90
+ const error = err instanceof Error ? err : new Error(String(err));
91
+ this.entries.set(name, { ...entry, error, status: "error" });
92
+ this.notify();
93
+ throw error;
94
+ }
95
+ }
96
+ async connectAll() {
97
+ await Promise.all(this.list().map((name) => this.connect(name)));
98
+ }
99
+ update(name, partial) {
100
+ const entry = this.entries.get(name);
101
+ if (entry) {
102
+ this.entries.set(name, { ...entry, ...partial });
103
+ this.notify();
104
+ }
105
+ }
106
+ clear() {
107
+ this.entries.clear();
108
+ this.notify();
109
+ }
110
+ subscribe(listener) {
111
+ this.listeners.add(listener);
112
+ return () => {
113
+ this.listeners.delete(listener);
114
+ };
115
+ }
116
+ getVersion() {
117
+ return this.version;
118
+ }
119
+ notify() {
120
+ this.version++;
121
+ this.listeners.forEach((l) => l());
122
+ }
123
+ };
124
+ var serverRegistry = new ServerRegistry();
125
+
126
+ // libs/react/src/registry/DynamicRegistry.ts
127
+ var DynamicRegistry = class {
128
+ tools = /* @__PURE__ */ new Map();
129
+ resources = /* @__PURE__ */ new Map();
130
+ toolRefCounts = /* @__PURE__ */ new Map();
131
+ resourceRefCounts = /* @__PURE__ */ new Map();
132
+ listeners = /* @__PURE__ */ new Set();
133
+ version = 0;
134
+ /**
135
+ * Register a dynamic tool. Returns an unregister function
136
+ * suitable for useEffect cleanup.
137
+ *
138
+ * Multiple registrations of the same name are ref-counted:
139
+ * subsequent registrations update the definition but the tool
140
+ * is only removed when every registrant has unregistered.
141
+ */
142
+ registerTool(def) {
143
+ const existing = this.toolRefCounts.get(def.name) ?? 0;
144
+ this.toolRefCounts.set(def.name, existing + 1);
145
+ this.tools.set(def.name, def);
146
+ if (existing === 0) {
147
+ this.notify();
148
+ }
149
+ let called = false;
150
+ return () => {
151
+ if (called) return;
152
+ called = true;
153
+ this.unregisterTool(def.name);
154
+ };
155
+ }
156
+ unregisterTool(name) {
157
+ const count = this.toolRefCounts.get(name);
158
+ if (count == null) return;
159
+ if (count <= 1) {
160
+ this.toolRefCounts.delete(name);
161
+ this.tools.delete(name);
162
+ this.notify();
163
+ } else {
164
+ this.toolRefCounts.set(name, count - 1);
165
+ }
166
+ }
167
+ /**
168
+ * Register a dynamic resource. Returns an unregister function
169
+ * suitable for useEffect cleanup.
170
+ *
171
+ * Multiple registrations of the same URI are ref-counted.
172
+ */
173
+ registerResource(def) {
174
+ const existing = this.resourceRefCounts.get(def.uri) ?? 0;
175
+ this.resourceRefCounts.set(def.uri, existing + 1);
176
+ this.resources.set(def.uri, def);
177
+ if (existing === 0) {
178
+ this.notify();
179
+ }
180
+ let called = false;
181
+ return () => {
182
+ if (called) return;
183
+ called = true;
184
+ this.unregisterResource(def.uri);
185
+ };
186
+ }
187
+ unregisterResource(uri) {
188
+ const count = this.resourceRefCounts.get(uri);
189
+ if (count == null) return;
190
+ if (count <= 1) {
191
+ this.resourceRefCounts.delete(uri);
192
+ this.resources.delete(uri);
193
+ this.notify();
194
+ } else {
195
+ this.resourceRefCounts.set(uri, count - 1);
196
+ }
197
+ }
198
+ /** Update the execute function for an existing tool (for stale closure prevention). */
199
+ updateToolExecute(name, execute) {
200
+ const existing = this.tools.get(name);
201
+ if (existing) {
202
+ existing.execute = execute;
203
+ }
204
+ }
205
+ /** Update the read function for an existing resource and notify subscribers. */
206
+ updateResourceRead(uri, read) {
207
+ const existing = this.resources.get(uri);
208
+ if (existing) {
209
+ existing.read = read;
210
+ this.notify();
211
+ }
212
+ }
213
+ getTools() {
214
+ return [...this.tools.values()];
215
+ }
216
+ getResources() {
217
+ return [...this.resources.values()];
218
+ }
219
+ findTool(name) {
220
+ return this.tools.get(name);
221
+ }
222
+ findResource(uri) {
223
+ return this.resources.get(uri);
224
+ }
225
+ hasTool(name) {
226
+ return this.tools.has(name);
227
+ }
228
+ hasResource(uri) {
229
+ return this.resources.has(uri);
230
+ }
231
+ subscribe(listener) {
232
+ this.listeners.add(listener);
233
+ return () => {
234
+ this.listeners.delete(listener);
235
+ };
236
+ }
237
+ getVersion() {
238
+ return this.version;
239
+ }
240
+ clear() {
241
+ if (this.tools.size === 0 && this.resources.size === 0) return;
242
+ this.tools.clear();
243
+ this.resources.clear();
244
+ this.toolRefCounts.clear();
245
+ this.resourceRefCounts.clear();
246
+ this.notify();
247
+ }
248
+ notify() {
249
+ this.version++;
250
+ this.listeners.forEach((l) => {
251
+ l();
252
+ });
253
+ }
254
+ };
255
+
256
+ // libs/react/src/registry/createWrappedServer.ts
257
+ function patchClientWithDynamic(client, dynamicRegistry) {
258
+ if (typeof client.callTool === "function") {
259
+ const originalCallTool = client.callTool.bind(client);
260
+ client.callTool = async (name, args) => {
261
+ const dynamicTool = dynamicRegistry.findTool(name);
262
+ if (dynamicTool) {
263
+ return dynamicTool.execute(args ?? {});
264
+ }
265
+ return originalCallTool(name, args);
266
+ };
267
+ }
268
+ if (typeof client.readResource === "function") {
269
+ const originalReadResource = client.readResource.bind(client);
270
+ client.readResource = async (uri) => {
271
+ const dynamicResource = dynamicRegistry.findResource(uri);
272
+ if (dynamicResource) {
273
+ return dynamicResource.read();
274
+ }
275
+ return originalReadResource(uri);
276
+ };
277
+ }
278
+ return client;
279
+ }
280
+ function createWrappedServer(base, dynamicRegistry) {
281
+ return {
282
+ get ready() {
283
+ return base.ready;
284
+ },
285
+ async listTools(options) {
286
+ const baseResult = await base.listTools(options);
287
+ const dynamicTools = dynamicRegistry.getTools();
288
+ if (dynamicTools.length === 0) return baseResult;
289
+ const dynamicNames = new Set(dynamicTools.map((t) => t.name));
290
+ const baseTools = (baseResult.tools ?? []).filter((t) => !dynamicNames.has(t.name));
291
+ const mergedTools = [
292
+ ...baseTools,
293
+ ...dynamicTools.map((t) => ({
294
+ name: t.name,
295
+ description: t.description,
296
+ inputSchema: t.inputSchema
297
+ }))
298
+ ];
299
+ return { ...baseResult, tools: mergedTools };
300
+ },
301
+ async callTool(name, args, options) {
302
+ const dynamicTool = dynamicRegistry.findTool(name);
303
+ if (dynamicTool) {
304
+ return dynamicTool.execute(args ?? {});
305
+ }
306
+ return base.callTool(name, args, options);
307
+ },
308
+ async listResources(options) {
309
+ const baseResult = await base.listResources(options);
310
+ const dynamicResources = dynamicRegistry.getResources();
311
+ if (dynamicResources.length === 0) return baseResult;
312
+ const dynamicUris = new Set(dynamicResources.map((r) => r.uri));
313
+ const baseResources = (baseResult.resources ?? []).filter(
314
+ (r) => !dynamicUris.has(r.uri)
315
+ );
316
+ const mergedResources = [
317
+ ...baseResources,
318
+ ...dynamicResources.map((r) => ({
319
+ uri: r.uri,
320
+ name: r.name ?? r.uri,
321
+ description: r.description,
322
+ mimeType: r.mimeType
323
+ }))
324
+ ];
325
+ return { ...baseResult, resources: mergedResources };
326
+ },
327
+ async listResourceTemplates(options) {
328
+ return base.listResourceTemplates(options);
329
+ },
330
+ async readResource(uri, options) {
331
+ const dynamicResource = dynamicRegistry.findResource(uri);
332
+ if (dynamicResource) {
333
+ return dynamicResource.read();
334
+ }
335
+ return base.readResource(uri, options);
336
+ },
337
+ async listPrompts(options) {
338
+ return base.listPrompts(options);
339
+ },
340
+ async getPrompt(name, args, options) {
341
+ return base.getPrompt(name, args, options);
342
+ },
343
+ async listJobs(options) {
344
+ return base.listJobs(options);
345
+ },
346
+ async executeJob(name, input, options) {
347
+ return base.executeJob(name, input, options);
348
+ },
349
+ async getJobStatus(runId, options) {
350
+ return base.getJobStatus(runId, options);
351
+ },
352
+ async listWorkflows(options) {
353
+ return base.listWorkflows(options);
354
+ },
355
+ async executeWorkflow(name, input, options) {
356
+ return base.executeWorkflow(name, input, options);
357
+ },
358
+ async getWorkflowStatus(runId, options) {
359
+ return base.getWorkflowStatus(runId, options);
360
+ },
361
+ async connect(sessionIdOrOptions) {
362
+ const client = await base.connect(sessionIdOrOptions);
363
+ return patchClientWithDynamic(client, dynamicRegistry);
364
+ },
365
+ async dispose() {
366
+ return base.dispose();
367
+ }
368
+ };
369
+ }
370
+
371
+ // libs/react/src/provider/FrontMcpContext.ts
372
+ import { createContext } from "react";
373
+
374
+ // libs/react/src/components/ComponentRegistry.ts
375
+ var ComponentRegistry = class {
376
+ entries = /* @__PURE__ */ new Map();
377
+ register(uri, component, meta) {
378
+ const name = extractName(uri);
379
+ this.entries.set(uri, { uri, name, component, description: meta?.description });
380
+ }
381
+ registerAll(map) {
382
+ for (const [uri, component] of Object.entries(map)) {
383
+ this.register(uri, component);
384
+ }
385
+ }
386
+ get(uri) {
387
+ return this.entries.get(uri)?.component;
388
+ }
389
+ /**
390
+ * Resolve a shorthand name like `'UserCard'` by trying
391
+ * `component://UserCard`, `element://UserCard`, `page://UserCard`.
392
+ */
393
+ resolve(type) {
394
+ const exact = this.entries.get(type);
395
+ if (exact) return exact.component;
396
+ for (const protocol of ["component://", "element://", "page://"]) {
397
+ const entry = this.entries.get(`${protocol}${type}`);
398
+ if (entry) return entry.component;
399
+ }
400
+ return void 0;
401
+ }
402
+ has(uri) {
403
+ return this.entries.has(uri);
404
+ }
405
+ list() {
406
+ return Array.from(this.entries.values()).map(({ uri, name, description }) => ({
407
+ uri,
408
+ name,
409
+ description
410
+ }));
411
+ }
412
+ clear() {
413
+ this.entries.clear();
414
+ }
415
+ };
416
+ function extractName(uri) {
417
+ const idx = uri.indexOf("://");
418
+ return idx >= 0 ? uri.slice(idx + 3) : uri;
419
+ }
420
+
421
+ // libs/react/src/provider/FrontMcpContext.ts
422
+ var defaultDynamicRegistry = new DynamicRegistry();
423
+ var FrontMcpContext = createContext({
424
+ name: "default",
425
+ registry: new ComponentRegistry(),
426
+ dynamicRegistry: defaultDynamicRegistry,
427
+ getDynamicRegistry: () => defaultDynamicRegistry,
428
+ connect: async () => {
429
+ }
430
+ });
431
+
432
+ // libs/react/src/provider/FrontMcpProvider.tsx
433
+ import React, { useCallback, useEffect as useEffect2, useRef, useMemo } from "react";
434
+
435
+ // libs/react/src/state/useStoreRegistration.ts
436
+ import { useEffect } from "react";
437
+ var VALID_NAME_RE = /^[a-zA-Z0-9_-]+$/;
438
+ function validateStoreName(name) {
439
+ if (!name || !VALID_NAME_RE.test(name)) {
440
+ throw new Error(`useStoreRegistration: invalid store name "${name}". Names must match ${VALID_NAME_RE}.`);
441
+ }
442
+ }
443
+ function useStoreRegistration(stores, dynamicRegistry) {
444
+ useEffect(() => {
445
+ if (stores.length === 0) return;
446
+ const cleanups = [];
447
+ for (const adapter of stores) {
448
+ const { name, subscribe, selectors, actions } = adapter;
449
+ validateStoreName(name);
450
+ const getStateWrapper = () => adapter.getState();
451
+ const readState = async () => ({
452
+ contents: [
453
+ {
454
+ uri: `state://${name}`,
455
+ mimeType: "application/json",
456
+ text: JSON.stringify(getStateWrapper())
457
+ }
458
+ ]
459
+ });
460
+ cleanups.push(
461
+ dynamicRegistry.registerResource({
462
+ uri: `state://${name}`,
463
+ name: `${name}-state`,
464
+ description: `Full state of ${name} store`,
465
+ mimeType: "application/json",
466
+ read: readState
467
+ })
468
+ );
469
+ const selectorEntries = [];
470
+ if (selectors) {
471
+ for (const [key, selector] of Object.entries(selectors)) {
472
+ if (!key || !VALID_NAME_RE.test(key)) {
473
+ throw new Error(`useStoreRegistration: invalid selector key "${key}". Keys must match ${VALID_NAME_RE}.`);
474
+ }
475
+ const uri = `state://${name}/${key}`;
476
+ const readSelector = async () => ({
477
+ contents: [
478
+ {
479
+ uri,
480
+ mimeType: "application/json",
481
+ text: JSON.stringify(selector(getStateWrapper()))
482
+ }
483
+ ]
484
+ });
485
+ selectorEntries.push({ uri, readSelector });
486
+ cleanups.push(
487
+ dynamicRegistry.registerResource({
488
+ uri,
489
+ name: `${name}-${key}`,
490
+ description: `Selector "${key}" from ${name} store`,
491
+ mimeType: "application/json",
492
+ read: readSelector
493
+ })
494
+ );
495
+ }
496
+ }
497
+ const unsubscribe = subscribe(() => {
498
+ dynamicRegistry.updateResourceRead(`state://${name}`, readState);
499
+ for (const { uri, readSelector } of selectorEntries) {
500
+ dynamicRegistry.updateResourceRead(uri, readSelector);
501
+ }
502
+ });
503
+ cleanups.push(unsubscribe);
504
+ if (actions) {
505
+ for (const [key, action] of Object.entries(actions)) {
506
+ const toolName = `${name}_${key}`;
507
+ const execute = async (args) => {
508
+ const argsArray = args["args"];
509
+ const result = await (Array.isArray(argsArray) ? action(...argsArray) : action(args));
510
+ return {
511
+ content: [{ type: "text", text: JSON.stringify({ success: true, result }) }]
512
+ };
513
+ };
514
+ cleanups.push(
515
+ dynamicRegistry.registerTool({
516
+ name: toolName,
517
+ description: `Action "${key}" on ${name} store`,
518
+ inputSchema: {
519
+ type: "object",
520
+ properties: {
521
+ args: { type: "array", description: "Arguments to pass to the action" }
522
+ }
523
+ },
524
+ execute
525
+ })
526
+ );
527
+ }
528
+ }
529
+ }
530
+ return () => {
531
+ cleanups.forEach((fn) => {
532
+ fn();
533
+ });
534
+ };
535
+ }, [stores, dynamicRegistry]);
536
+ }
537
+
538
+ // libs/react/src/provider/FrontMcpProvider.tsx
539
+ function FrontMcpProvider({
540
+ name: nameProp,
541
+ server,
542
+ servers,
543
+ components,
544
+ stores,
545
+ autoConnect = true,
546
+ children,
547
+ onConnected,
548
+ onError
549
+ }) {
550
+ const resolvedName = nameProp ?? "default";
551
+ const mountedRef = useRef(true);
552
+ const clientRef = useRef(null);
553
+ const registry = useMemo(() => {
554
+ const reg = new ComponentRegistry();
555
+ if (components) {
556
+ reg.registerAll(components);
557
+ }
558
+ return reg;
559
+ }, [components]);
560
+ const registryMapRef = useRef(/* @__PURE__ */ new Map());
561
+ const getDynamicRegistry = useCallback(
562
+ (serverName) => {
563
+ const key = serverName ?? resolvedName;
564
+ let reg = registryMapRef.current.get(key);
565
+ if (!reg) {
566
+ reg = new DynamicRegistry();
567
+ registryMapRef.current.set(key, reg);
568
+ }
569
+ return reg;
570
+ },
571
+ [resolvedName]
572
+ );
573
+ const dynamicRegistry = useMemo(() => getDynamicRegistry(resolvedName), [getDynamicRegistry, resolvedName]);
574
+ useStoreRegistration(stores ?? [], dynamicRegistry);
575
+ const wrappedServer = useMemo(() => createWrappedServer(server, dynamicRegistry), [server, dynamicRegistry]);
576
+ useEffect2(() => {
577
+ serverRegistry.register(resolvedName, wrappedServer);
578
+ if (servers) {
579
+ for (const [sName, srv] of Object.entries(servers)) {
580
+ const srvRegistry = getDynamicRegistry(sName);
581
+ const wrappedSrv = createWrappedServer(srv, srvRegistry);
582
+ serverRegistry.register(sName, wrappedSrv);
583
+ }
584
+ }
585
+ return () => {
586
+ serverRegistry.unregister(resolvedName);
587
+ if (servers) {
588
+ for (const sName of Object.keys(servers)) {
589
+ serverRegistry.unregister(sName);
590
+ const srvRegistry = registryMapRef.current.get(sName);
591
+ if (srvRegistry) {
592
+ srvRegistry.clear();
593
+ registryMapRef.current.delete(sName);
594
+ }
595
+ }
596
+ }
597
+ };
598
+ }, [resolvedName, wrappedServer, servers, getDynamicRegistry]);
599
+ useEffect2(() => {
600
+ const refreshServerEntry = (name) => {
601
+ const entry = serverRegistry.get(name);
602
+ if (!entry || !entry.client) return;
603
+ const srv = entry.server;
604
+ if (!srv) return;
605
+ Promise.all([srv.listTools(), srv.listResources()]).then(([toolsResult, resourcesResult]) => {
606
+ if (mountedRef.current) {
607
+ serverRegistry.update(name, {
608
+ tools: toolsResult.tools ?? [],
609
+ resources: resourcesResult.resources ?? []
610
+ });
611
+ }
612
+ }).catch(() => {
613
+ });
614
+ };
615
+ const unsubs = [];
616
+ unsubs.push(
617
+ dynamicRegistry.subscribe(() => {
618
+ refreshServerEntry(resolvedName);
619
+ })
620
+ );
621
+ if (servers) {
622
+ for (const sName of Object.keys(servers)) {
623
+ const srvRegistry = registryMapRef.current.get(sName);
624
+ if (srvRegistry) {
625
+ unsubs.push(
626
+ srvRegistry.subscribe(() => {
627
+ refreshServerEntry(sName);
628
+ })
629
+ );
630
+ }
631
+ }
632
+ }
633
+ return () => {
634
+ unsubs.forEach((fn) => {
635
+ fn();
636
+ });
637
+ };
638
+ }, [dynamicRegistry, resolvedName, servers]);
639
+ const connectClient = useCallback(async () => {
640
+ if (clientRef.current) return;
641
+ try {
642
+ serverRegistry.update(resolvedName, { status: "connecting", error: null });
643
+ const client = await wrappedServer.connect();
644
+ clientRef.current = client;
645
+ const safeList = (fn, fallback) => fn().catch(() => fallback);
646
+ const [toolsResult, resourcesResult, templatesResult, promptsResult] = await Promise.all([
647
+ safeList(() => client.listTools(), []),
648
+ safeList(() => client.listResources(), { resources: [] }),
649
+ safeList(() => client.listResourceTemplates(), { resourceTemplates: [] }),
650
+ safeList(() => client.listPrompts(), { prompts: [] })
651
+ ]);
652
+ if (mountedRef.current) {
653
+ const dynamicTools = dynamicRegistry.getTools().map((t) => ({
654
+ name: t.name,
655
+ description: t.description,
656
+ inputSchema: t.inputSchema
657
+ }));
658
+ const dynamicResources = dynamicRegistry.getResources().map((r) => ({
659
+ uri: r.uri,
660
+ name: r.name,
661
+ description: r.description,
662
+ mimeType: r.mimeType
663
+ }));
664
+ const baseTools = toolsResult;
665
+ const dynamicToolNames = new Set(dynamicTools.map((t) => t.name));
666
+ const filteredBaseTools = (Array.isArray(baseTools) ? baseTools : []).filter(
667
+ (t) => !dynamicToolNames.has(t.name)
668
+ );
669
+ const baseResources = resourcesResult.resources ?? [];
670
+ const dynamicResourceUris = new Set(dynamicResources.map((r) => r.uri));
671
+ const filteredBaseResources = baseResources.filter((r) => !dynamicResourceUris.has(r.uri));
672
+ serverRegistry.update(resolvedName, {
673
+ client,
674
+ status: "connected",
675
+ error: null,
676
+ tools: [...filteredBaseTools, ...dynamicTools],
677
+ resources: [...filteredBaseResources, ...dynamicResources],
678
+ resourceTemplates: templatesResult.resourceTemplates ?? [],
679
+ prompts: promptsResult.prompts ?? []
680
+ });
681
+ onConnected?.(client);
682
+ }
683
+ if (servers) {
684
+ for (const sName of Object.keys(servers)) {
685
+ serverRegistry.connect(sName).catch(() => {
686
+ });
687
+ }
688
+ }
689
+ } catch (err) {
690
+ const e = err instanceof Error ? err : new Error(String(err));
691
+ if (mountedRef.current) {
692
+ serverRegistry.update(resolvedName, { error: e, status: "error" });
693
+ onError?.(e);
694
+ }
695
+ }
696
+ }, [resolvedName, wrappedServer, servers, onConnected, onError, dynamicRegistry]);
697
+ useEffect2(() => {
698
+ mountedRef.current = true;
699
+ if (autoConnect) {
700
+ connectClient();
701
+ }
702
+ return () => {
703
+ mountedRef.current = false;
704
+ clientRef.current = null;
705
+ };
706
+ }, [autoConnect, connectClient]);
707
+ const contextValue = useMemo(
708
+ () => ({
709
+ name: resolvedName,
710
+ registry,
711
+ dynamicRegistry,
712
+ getDynamicRegistry,
713
+ connect: connectClient
714
+ }),
715
+ [resolvedName, registry, dynamicRegistry, getDynamicRegistry, connectClient]
716
+ );
717
+ return React.createElement(FrontMcpContext.Provider, { value: contextValue }, children);
718
+ }
719
+
720
+ // libs/react/src/hooks/useResolvedServer.ts
721
+ import { useContext } from "react";
722
+
723
+ // libs/react/src/hooks/useServer.ts
724
+ import { useSyncExternalStore, useCallback as useCallback2 } from "react";
725
+ function useServer(name) {
726
+ const subscribe = useCallback2((cb) => serverRegistry.subscribe(cb), []);
727
+ const getSnapshot = useCallback2(() => {
728
+ return serverRegistry.get(name ?? "default");
729
+ }, [name]);
730
+ return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
731
+ }
732
+
733
+ // libs/react/src/hooks/useResolvedServer.ts
734
+ function useResolvedServer(serverName) {
735
+ const ctx = useContext(FrontMcpContext);
736
+ const resolvedName = serverName ?? ctx.name;
737
+ const entry = useServer(resolvedName);
738
+ return { entry, name: resolvedName, registry: ctx.registry, connect: ctx.connect };
739
+ }
740
+
741
+ // libs/react/src/hooks/useFrontMcp.ts
742
+ function useFrontMcp(name) {
743
+ const { entry, name: resolvedName, registry, connect: connect2 } = useResolvedServer(name);
744
+ return {
745
+ name: resolvedName,
746
+ server: entry?.server ?? null,
747
+ client: entry?.client ?? null,
748
+ status: entry?.status ?? "idle",
749
+ error: entry?.error ?? null,
750
+ tools: entry?.tools ?? [],
751
+ resources: entry?.resources ?? [],
752
+ resourceTemplates: entry?.resourceTemplates ?? [],
753
+ prompts: entry?.prompts ?? [],
754
+ registry,
755
+ connect: connect2
756
+ };
757
+ }
758
+
759
+ // libs/react/src/hooks/useCallTool.ts
760
+ import { useState, useCallback as useCallback3, useEffect as useEffect3 } from "react";
761
+ function useCallTool(toolName, options = {}) {
762
+ const { onSuccess, onError, resetOnToolChange = true, server: serverName } = options;
763
+ const { entry } = useResolvedServer(serverName);
764
+ const client = entry?.client ?? null;
765
+ const status = entry?.status ?? "idle";
766
+ const [state, setState] = useState({
767
+ data: null,
768
+ loading: false,
769
+ error: null,
770
+ called: false
771
+ });
772
+ useEffect3(() => {
773
+ if (resetOnToolChange) {
774
+ setState({ data: null, loading: false, error: null, called: false });
775
+ }
776
+ }, [toolName, resetOnToolChange]);
777
+ const reset = useCallback3(() => {
778
+ setState({ data: null, loading: false, error: null, called: false });
779
+ }, []);
780
+ const callTool = useCallback3(
781
+ async (args) => {
782
+ if (status !== "connected" || !client) {
783
+ const error = new Error("FrontMCP not connected");
784
+ setState((prev) => ({ ...prev, error, called: true }));
785
+ onError?.(error);
786
+ return null;
787
+ }
788
+ setState((prev) => ({ ...prev, loading: true, error: null, called: true }));
789
+ try {
790
+ const result = await client.callTool(toolName, args);
791
+ const data = result;
792
+ setState({ data, loading: false, error: null, called: true });
793
+ onSuccess?.(data);
794
+ return data;
795
+ } catch (err) {
796
+ const error = err instanceof Error ? err : new Error(String(err));
797
+ setState({ data: null, loading: false, error, called: true });
798
+ onError?.(error);
799
+ return null;
800
+ }
801
+ },
802
+ [client, status, toolName, onSuccess, onError]
803
+ );
804
+ return [callTool, state, reset];
805
+ }
806
+
807
+ // libs/react/src/hooks/useReadResource.ts
808
+ import { useState as useState2, useCallback as useCallback4, useEffect as useEffect4 } from "react";
809
+ function useReadResource(uriOrOptions, maybeOptions) {
810
+ const uri = typeof uriOrOptions === "string" ? uriOrOptions : void 0;
811
+ const options = typeof uriOrOptions === "object" ? uriOrOptions : maybeOptions;
812
+ const serverName = options?.server;
813
+ const { entry } = useResolvedServer(serverName);
814
+ const client = entry?.client ?? null;
815
+ const status = entry?.status ?? "idle";
816
+ const [state, setState] = useState2({
817
+ data: null,
818
+ loading: false,
819
+ error: null
820
+ });
821
+ const read = useCallback4(
822
+ async (targetUri) => {
823
+ if (status !== "connected" || !client) {
824
+ const error = new Error("FrontMCP not connected");
825
+ setState({ data: null, loading: false, error });
826
+ return null;
827
+ }
828
+ setState({ data: null, loading: true, error: null });
829
+ try {
830
+ const result = await client.readResource(targetUri);
831
+ setState({ data: result, loading: false, error: null });
832
+ return result;
833
+ } catch (err) {
834
+ const error = err instanceof Error ? err : new Error(String(err));
835
+ setState({ data: null, loading: false, error });
836
+ return null;
837
+ }
838
+ },
839
+ [client, status]
840
+ );
841
+ useEffect4(() => {
842
+ if (uri && status === "connected" && client) {
843
+ read(uri);
844
+ }
845
+ }, [uri, status, client, read]);
846
+ if (uri !== void 0) {
847
+ return {
848
+ ...state,
849
+ refetch: () => {
850
+ read(uri);
851
+ }
852
+ };
853
+ }
854
+ return [read, state];
855
+ }
856
+
857
+ // libs/react/src/hooks/useGetPrompt.ts
858
+ import { useState as useState3, useCallback as useCallback5 } from "react";
859
+ function useGetPrompt(promptName, options) {
860
+ const { entry } = useResolvedServer(options?.server);
861
+ const client = entry?.client ?? null;
862
+ const status = entry?.status ?? "idle";
863
+ const [state, setState] = useState3({
864
+ data: null,
865
+ loading: false,
866
+ error: null
867
+ });
868
+ const getPrompt = useCallback5(
869
+ async (args) => {
870
+ if (status !== "connected" || !client) {
871
+ const error = new Error("FrontMCP not connected");
872
+ setState({ data: null, loading: false, error });
873
+ return null;
874
+ }
875
+ setState({ data: null, loading: true, error: null });
876
+ try {
877
+ const result = await client.getPrompt(promptName, args);
878
+ setState({ data: result, loading: false, error: null });
879
+ return result;
880
+ } catch (err) {
881
+ const error = err instanceof Error ? err : new Error(String(err));
882
+ setState({ data: null, loading: false, error });
883
+ return null;
884
+ }
885
+ },
886
+ [client, status, promptName]
887
+ );
888
+ return [getPrompt, state];
889
+ }
890
+
891
+ // libs/react/src/hooks/useListTools.ts
892
+ var EMPTY_TOOLS = [];
893
+ function useListTools(options) {
894
+ const { entry } = useResolvedServer(options?.server);
895
+ return entry?.tools ?? EMPTY_TOOLS;
896
+ }
897
+
898
+ // libs/react/src/hooks/useListResources.ts
899
+ var EMPTY_RESOURCES = [];
900
+ var EMPTY_TEMPLATES = [];
901
+ function useListResources(options) {
902
+ const { entry } = useResolvedServer(options?.server);
903
+ return {
904
+ resources: entry?.resources ?? EMPTY_RESOURCES,
905
+ resourceTemplates: entry?.resourceTemplates ?? EMPTY_TEMPLATES
906
+ };
907
+ }
908
+
909
+ // libs/react/src/hooks/useListPrompts.ts
910
+ var EMPTY_PROMPTS = [];
911
+ function useListPrompts(options) {
912
+ const { entry } = useResolvedServer(options?.server);
913
+ return entry?.prompts ?? EMPTY_PROMPTS;
914
+ }
915
+
916
+ // libs/react/src/hooks/useStoreResource.ts
917
+ import { useState as useState4, useEffect as useEffect5, useCallback as useCallback6, useRef as useRef2 } from "react";
918
+ function parseResourceContent(result) {
919
+ const r = result;
920
+ if (r?.contents?.[0]?.text) {
921
+ try {
922
+ return JSON.parse(r.contents[0].text);
923
+ } catch {
924
+ return r.contents[0].text;
925
+ }
926
+ }
927
+ return result;
928
+ }
929
+ function useStoreResource(uri, options) {
930
+ const { entry } = useResolvedServer(options?.server);
931
+ const client = entry?.client ?? null;
932
+ const status = entry?.status ?? "idle";
933
+ const [state, setState] = useState4({ data: null, loading: true, error: null });
934
+ const uriRef = useRef2(uri);
935
+ uriRef.current = uri;
936
+ const fetchResource = useCallback6(async () => {
937
+ if (status !== "connected" || !client) return;
938
+ try {
939
+ const result = await client.readResource(uri);
940
+ setState({ data: parseResourceContent(result), loading: false, error: null });
941
+ } catch (err) {
942
+ setState({ data: null, loading: false, error: err instanceof Error ? err : new Error(String(err)) });
943
+ }
944
+ }, [uri, client, status]);
945
+ const fetchRef = useRef2(fetchResource);
946
+ fetchRef.current = fetchResource;
947
+ useEffect5(() => {
948
+ if (status !== "connected" || !client) return;
949
+ let cancelled = false;
950
+ setState((prev) => ({ ...prev, loading: true }));
951
+ fetchRef.current();
952
+ let unsubNotification;
953
+ (async () => {
954
+ try {
955
+ await client.subscribeResource(uri);
956
+ } catch {
957
+ }
958
+ if (cancelled) {
959
+ client.unsubscribeResource(uri).catch(() => {
960
+ });
961
+ return;
962
+ }
963
+ unsubNotification = client.onResourceUpdated((updatedUri) => {
964
+ if (updatedUri === uriRef.current) {
965
+ fetchRef.current();
966
+ }
967
+ });
968
+ })();
969
+ return () => {
970
+ cancelled = true;
971
+ unsubNotification?.();
972
+ client.unsubscribeResource(uri).catch(() => {
973
+ });
974
+ };
975
+ }, [uri, client, status]);
976
+ return {
977
+ ...state,
978
+ refetch: fetchResource
979
+ };
980
+ }
981
+
982
+ // libs/react/src/hooks/useDynamicTool.ts
983
+ import { useContext as useContext2, useEffect as useEffect6, useRef as useRef3, useMemo as useMemo2 } from "react";
984
+
985
+ // libs/react/src/utils/zodToJsonSchema.ts
986
+ import { toJSONSchema } from "zod/v4";
987
+ function zodToJsonSchema(schema) {
988
+ return toJSONSchema(schema);
989
+ }
990
+
991
+ // libs/react/src/hooks/useDynamicTool.ts
992
+ function useDynamicTool(options) {
993
+ const { name, description, enabled = true } = options;
994
+ const { getDynamicRegistry } = useContext2(FrontMcpContext);
995
+ const dynamicRegistry = getDynamicRegistry(options.server);
996
+ const resolvedInputSchema = useMemo2(() => {
997
+ if ("schema" in options && options.schema) {
998
+ return zodToJsonSchema(options.schema);
999
+ }
1000
+ return options.inputSchema;
1001
+ }, ["schema" in options ? options.schema : void 0, "inputSchema" in options ? options.inputSchema : void 0]);
1002
+ const executeRef = useRef3(options.execute);
1003
+ executeRef.current = options.execute;
1004
+ const schemaRef = useRef3("schema" in options && options.schema ? options.schema : null);
1005
+ schemaRef.current = "schema" in options && options.schema ? options.schema : null;
1006
+ useEffect6(() => {
1007
+ if (!enabled) return;
1008
+ const stableExecute = async (args) => {
1009
+ const zodSchema = schemaRef.current;
1010
+ if (zodSchema) {
1011
+ const result = zodSchema.safeParse(args);
1012
+ if (!result.success) {
1013
+ return {
1014
+ isError: true,
1015
+ content: [
1016
+ {
1017
+ type: "text",
1018
+ text: JSON.stringify({
1019
+ error: "validation_error",
1020
+ issues: result.error.issues.map((i) => ({
1021
+ path: i.path,
1022
+ message: i.message
1023
+ }))
1024
+ })
1025
+ }
1026
+ ]
1027
+ };
1028
+ }
1029
+ return executeRef.current(result.data);
1030
+ }
1031
+ return executeRef.current(args);
1032
+ };
1033
+ const unregister = dynamicRegistry.registerTool({
1034
+ name,
1035
+ description,
1036
+ inputSchema: resolvedInputSchema,
1037
+ execute: stableExecute
1038
+ });
1039
+ return unregister;
1040
+ }, [dynamicRegistry, name, description, resolvedInputSchema, enabled]);
1041
+ }
1042
+
1043
+ // libs/react/src/hooks/useDynamicResource.ts
1044
+ import { useContext as useContext3, useEffect as useEffect7, useRef as useRef4 } from "react";
1045
+ function useDynamicResource(options) {
1046
+ const { uri, name, description, mimeType, read, enabled = true } = options;
1047
+ const { getDynamicRegistry } = useContext3(FrontMcpContext);
1048
+ const dynamicRegistry = getDynamicRegistry(options.server);
1049
+ const readRef = useRef4(read);
1050
+ readRef.current = read;
1051
+ useEffect7(() => {
1052
+ if (!enabled) return;
1053
+ const stableRead = () => readRef.current();
1054
+ const unregister = dynamicRegistry.registerResource({
1055
+ uri,
1056
+ name,
1057
+ description,
1058
+ mimeType,
1059
+ read: stableRead
1060
+ });
1061
+ return unregister;
1062
+ }, [dynamicRegistry, uri, name, description, mimeType, enabled]);
1063
+ }
1064
+
1065
+ // libs/react/src/hooks/useComponentTree.ts
1066
+ import { useCallback as useCallback7 } from "react";
1067
+ var RFC_3986_SCHEME_RE = /^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//;
1068
+ function walkDom(element, maxDepth, includeProps, depth = 0) {
1069
+ if (depth > maxDepth) return null;
1070
+ const component = element.getAttribute("data-component") ?? void 0;
1071
+ const tag = element.tagName.toLowerCase();
1072
+ const children = [];
1073
+ for (let i = 0; i < element.children.length; i++) {
1074
+ const child = walkDom(element.children[i], maxDepth, includeProps, depth + 1);
1075
+ if (child) children.push(child);
1076
+ }
1077
+ const node = {
1078
+ component: component ?? tag,
1079
+ tag,
1080
+ children
1081
+ };
1082
+ if (includeProps) {
1083
+ const props = {};
1084
+ for (let i = 0; i < element.attributes.length; i++) {
1085
+ const attr = element.attributes[i];
1086
+ if (attr.name.startsWith("data-") && attr.name !== "data-component") {
1087
+ props[attr.name] = attr.value;
1088
+ }
1089
+ }
1090
+ if (Object.keys(props).length > 0) {
1091
+ node.props = props;
1092
+ }
1093
+ }
1094
+ return node;
1095
+ }
1096
+ function useComponentTree(options) {
1097
+ const { rootRef, uri = "react://component-tree", maxDepth = 10, includeProps = false, server } = options;
1098
+ if (!RFC_3986_SCHEME_RE.test(uri)) {
1099
+ throw new Error("URI must have a valid scheme (e.g., file://, https://, custom://)");
1100
+ }
1101
+ const read = useCallback7(async () => {
1102
+ const root = rootRef.current;
1103
+ if (!root) {
1104
+ return {
1105
+ contents: [{ uri, mimeType: "application/json", text: JSON.stringify({ error: "Root element not mounted" }) }]
1106
+ };
1107
+ }
1108
+ const tree = walkDom(root, maxDepth, includeProps);
1109
+ return {
1110
+ contents: [{ uri, mimeType: "application/json", text: JSON.stringify(tree) }]
1111
+ };
1112
+ }, [rootRef, uri, maxDepth, includeProps]);
1113
+ useDynamicResource({
1114
+ uri,
1115
+ name: "component-tree",
1116
+ description: "React component tree (DOM-based with data-component attributes)",
1117
+ mimeType: "application/json",
1118
+ read,
1119
+ server
1120
+ });
1121
+ }
1122
+
1123
+ // libs/react/src/components/DynamicRenderer.tsx
1124
+ import React2 from "react";
1125
+ function DynamicRenderer({ tree, registry, fallback }) {
1126
+ return renderNode(tree, registry, fallback, 0);
1127
+ }
1128
+ function renderNode(node, registry, fallback, index) {
1129
+ const Component = registry.resolve(node.type) ?? fallback ?? "div";
1130
+ const childElements = renderChildren(node.children, registry, fallback);
1131
+ return React2.createElement(
1132
+ Component,
1133
+ { ...node.props, key: `dynamic-${index}` },
1134
+ ...childElements
1135
+ );
1136
+ }
1137
+ function renderChildren(children, registry, fallback) {
1138
+ if (children === void 0 || children === null) {
1139
+ return [];
1140
+ }
1141
+ if (typeof children === "string") {
1142
+ return [children];
1143
+ }
1144
+ if (Array.isArray(children)) {
1145
+ return children.map((child, i) => renderNode(child, registry, fallback, i));
1146
+ }
1147
+ return [renderNode(children, registry, fallback, 0)];
1148
+ }
1149
+
1150
+ // libs/react/src/components/DomResources.ts
1151
+ function readDomById(id) {
1152
+ if (typeof document === "undefined") {
1153
+ return {
1154
+ contents: [
1155
+ {
1156
+ uri: `dom://byId/${id}`,
1157
+ mimeType: "text/plain",
1158
+ text: "DOM not available (not in a browser environment)"
1159
+ }
1160
+ ]
1161
+ };
1162
+ }
1163
+ const el = document.getElementById(id);
1164
+ if (!el) {
1165
+ return {
1166
+ contents: [
1167
+ {
1168
+ uri: `dom://byId/${id}`,
1169
+ mimeType: "text/plain",
1170
+ text: `Element with id "${id}" not found`
1171
+ }
1172
+ ]
1173
+ };
1174
+ }
1175
+ return {
1176
+ contents: [
1177
+ {
1178
+ uri: `dom://byId/${id}`,
1179
+ mimeType: "application/json",
1180
+ text: JSON.stringify({
1181
+ outerHTML: el.outerHTML,
1182
+ textContent: el.textContent ?? "",
1183
+ tagName: el.tagName.toLowerCase()
1184
+ })
1185
+ }
1186
+ ]
1187
+ };
1188
+ }
1189
+ function readDomBySelector(selector) {
1190
+ if (typeof document === "undefined") {
1191
+ return {
1192
+ contents: [
1193
+ {
1194
+ uri: `dom://selector/${selector}`,
1195
+ mimeType: "text/plain",
1196
+ text: "DOM not available (not in a browser environment)"
1197
+ }
1198
+ ]
1199
+ };
1200
+ }
1201
+ let elements;
1202
+ try {
1203
+ elements = document.querySelectorAll(selector);
1204
+ } catch {
1205
+ return {
1206
+ contents: [
1207
+ {
1208
+ uri: `dom://selector/${selector}`,
1209
+ mimeType: "text/plain",
1210
+ text: `Invalid selector: "${selector}"`
1211
+ }
1212
+ ]
1213
+ };
1214
+ }
1215
+ if (elements.length === 0) {
1216
+ return {
1217
+ contents: [
1218
+ {
1219
+ uri: `dom://selector/${selector}`,
1220
+ mimeType: "text/plain",
1221
+ text: `No elements found matching "${selector}"`
1222
+ }
1223
+ ]
1224
+ };
1225
+ }
1226
+ const items = Array.from(elements).map((el) => ({
1227
+ outerHTML: el.outerHTML,
1228
+ textContent: el.textContent ?? "",
1229
+ tagName: el.tagName.toLowerCase()
1230
+ }));
1231
+ return {
1232
+ contents: [
1233
+ {
1234
+ uri: `dom://selector/${selector}`,
1235
+ mimeType: "application/json",
1236
+ text: JSON.stringify(items)
1237
+ }
1238
+ ]
1239
+ };
1240
+ }
1241
+
1242
+ // libs/react/src/components/ToolForm.tsx
1243
+ import React3, { useState as useState5, useCallback as useCallback8 } from "react";
1244
+ function ToolForm({
1245
+ tool: tool2,
1246
+ onSubmit,
1247
+ renderField,
1248
+ submitLabel = "Call Tool"
1249
+ }) {
1250
+ const schema = tool2.inputSchema ?? {};
1251
+ const properties = schema["properties"] ?? {};
1252
+ const required = schema["required"] ?? [];
1253
+ const [values, setValues] = useState5({});
1254
+ const handleSubmit = useCallback8(
1255
+ (e) => {
1256
+ e.preventDefault();
1257
+ const args = {};
1258
+ for (const [key, prop] of Object.entries(properties)) {
1259
+ const raw = values[key] ?? "";
1260
+ if (!required.includes(key) && raw === "") continue;
1261
+ if (prop["type"] === "number" || prop["type"] === "integer") {
1262
+ args[key] = Number(raw);
1263
+ } else if (prop["type"] === "boolean") {
1264
+ args[key] = raw === "true";
1265
+ } else {
1266
+ args[key] = raw;
1267
+ }
1268
+ }
1269
+ onSubmit(args);
1270
+ },
1271
+ [values, properties, required, onSubmit]
1272
+ );
1273
+ const handleChange = useCallback8((key, value) => {
1274
+ setValues((prev) => ({ ...prev, [key]: value }));
1275
+ }, []);
1276
+ return React3.createElement(
1277
+ "form",
1278
+ { onSubmit: handleSubmit },
1279
+ ...Object.entries(properties).map(([key, prop]) => {
1280
+ const isRequired = required.includes(key);
1281
+ const enumValues = prop["enum"];
1282
+ const fieldType = getFieldType(prop);
1283
+ const value = values[key] ?? "";
1284
+ if (renderField) {
1285
+ return React3.createElement(
1286
+ React3.Fragment,
1287
+ { key },
1288
+ renderField({
1289
+ name: key,
1290
+ type: fieldType,
1291
+ required: isRequired,
1292
+ description: prop["description"],
1293
+ enumValues,
1294
+ value,
1295
+ onChange: (v) => handleChange(key, v)
1296
+ })
1297
+ );
1298
+ }
1299
+ return React3.createElement(
1300
+ "div",
1301
+ { key, style: { marginBottom: "8px" } },
1302
+ React3.createElement(
1303
+ "label",
1304
+ { htmlFor: `field-${key}`, style: { display: "block", marginBottom: "4px" } },
1305
+ `${key}${isRequired ? " *" : ""}`
1306
+ ),
1307
+ enumValues ? React3.createElement(
1308
+ "select",
1309
+ {
1310
+ id: `field-${key}`,
1311
+ value: value || enumValues[0] || "",
1312
+ onChange: (e) => handleChange(key, e.target.value)
1313
+ },
1314
+ ...enumValues.map((v) => React3.createElement("option", { key: v, value: v }, v))
1315
+ ) : React3.createElement("input", {
1316
+ id: `field-${key}`,
1317
+ type: fieldType === "number" || fieldType === "integer" ? "number" : "text",
1318
+ step: fieldType === "integer" ? "1" : void 0,
1319
+ placeholder: prop["description"] ?? "",
1320
+ required: isRequired,
1321
+ value,
1322
+ onChange: (e) => handleChange(key, e.target.value)
1323
+ })
1324
+ );
1325
+ }),
1326
+ React3.createElement("button", { type: "submit" }, submitLabel)
1327
+ );
1328
+ }
1329
+ function getFieldType(prop) {
1330
+ if (prop["enum"]) return "enum";
1331
+ return prop["type"] ?? "string";
1332
+ }
1333
+
1334
+ // libs/react/src/components/PromptForm.tsx
1335
+ import React4, { useState as useState6, useCallback as useCallback9 } from "react";
1336
+ function PromptForm({
1337
+ prompt: prompt2,
1338
+ onSubmit,
1339
+ renderField,
1340
+ submitLabel = "Get Prompt"
1341
+ }) {
1342
+ const args = prompt2.arguments ?? [];
1343
+ const [values, setValues] = useState6({});
1344
+ const handleSubmit = useCallback9(
1345
+ (e) => {
1346
+ e.preventDefault();
1347
+ const result = {};
1348
+ for (const arg of args) {
1349
+ result[arg.name] = values[arg.name] ?? "";
1350
+ }
1351
+ onSubmit(result);
1352
+ },
1353
+ [values, args, onSubmit]
1354
+ );
1355
+ const handleChange = useCallback9((key, value) => {
1356
+ setValues((prev) => ({ ...prev, [key]: value }));
1357
+ }, []);
1358
+ return React4.createElement(
1359
+ "form",
1360
+ { onSubmit: handleSubmit },
1361
+ ...args.map((arg) => {
1362
+ const value = values[arg.name] ?? "";
1363
+ if (renderField) {
1364
+ return React4.createElement(
1365
+ React4.Fragment,
1366
+ { key: arg.name },
1367
+ renderField({
1368
+ name: arg.name,
1369
+ type: "string",
1370
+ required: arg.required ?? false,
1371
+ description: arg.description,
1372
+ value,
1373
+ onChange: (v) => handleChange(arg.name, v)
1374
+ })
1375
+ );
1376
+ }
1377
+ return React4.createElement(
1378
+ "div",
1379
+ { key: arg.name, style: { marginBottom: "8px" } },
1380
+ React4.createElement(
1381
+ "label",
1382
+ { htmlFor: `prompt-${arg.name}`, style: { display: "block", marginBottom: "4px" } },
1383
+ `${arg.name}${arg.required ? " *" : ""}`
1384
+ ),
1385
+ React4.createElement("textarea", {
1386
+ id: `prompt-${arg.name}`,
1387
+ name: arg.name,
1388
+ placeholder: arg.description ?? "",
1389
+ required: arg.required,
1390
+ value,
1391
+ onChange: (e) => handleChange(arg.name, e.target.value),
1392
+ rows: 3,
1393
+ style: { width: "100%" }
1394
+ })
1395
+ );
1396
+ }),
1397
+ React4.createElement("button", { type: "submit" }, submitLabel)
1398
+ );
1399
+ }
1400
+
1401
+ // libs/react/src/components/ResourceViewer.tsx
1402
+ import React5 from "react";
1403
+ function ResourceViewer({ data, loading, error }) {
1404
+ if (loading) {
1405
+ return React5.createElement("div", { "data-testid": "resource-loading" }, "Loading...");
1406
+ }
1407
+ if (error) {
1408
+ return React5.createElement(
1409
+ "div",
1410
+ { "data-testid": "resource-error", style: { color: "red" } },
1411
+ `Error: ${error.message}`
1412
+ );
1413
+ }
1414
+ if (!data || !data.contents || data.contents.length === 0) {
1415
+ return React5.createElement("div", { "data-testid": "resource-empty" }, "No content");
1416
+ }
1417
+ return React5.createElement(
1418
+ "div",
1419
+ { "data-testid": "resource-viewer" },
1420
+ ...data.contents.map(
1421
+ (content, i) => React5.createElement(
1422
+ "div",
1423
+ { key: `${content.uri}-${i}`, style: { marginBottom: "8px" } },
1424
+ React5.createElement("div", { style: { fontSize: "0.8em", color: "#666" } }, content.uri),
1425
+ content.mimeType === "application/json" ? React5.createElement("pre", { style: { overflow: "auto" } }, formatJson(content.text ?? "")) : React5.createElement("div", null, content.text ?? "")
1426
+ )
1427
+ )
1428
+ );
1429
+ }
1430
+ function formatJson(text) {
1431
+ try {
1432
+ return JSON.stringify(JSON.parse(text), null, 2);
1433
+ } catch {
1434
+ return text;
1435
+ }
1436
+ }
1437
+
1438
+ // libs/react/src/components/OutputDisplay.tsx
1439
+ import React6 from "react";
1440
+ function OutputDisplay({ data, loading, error }) {
1441
+ if (loading) {
1442
+ return React6.createElement("div", { "data-testid": "output-loading" }, "Loading...");
1443
+ }
1444
+ if (error) {
1445
+ return React6.createElement(
1446
+ "div",
1447
+ { "data-testid": "output-error", style: { color: "red" } },
1448
+ `Error: ${error.message}`
1449
+ );
1450
+ }
1451
+ if (data === null || data === void 0) {
1452
+ return React6.createElement("div", { "data-testid": "output-empty" }, "");
1453
+ }
1454
+ let formatted;
1455
+ if (typeof data === "string") {
1456
+ formatted = data;
1457
+ } else {
1458
+ try {
1459
+ formatted = JSON.stringify(data, null, 2);
1460
+ } catch {
1461
+ formatted = String(data);
1462
+ }
1463
+ }
1464
+ return React6.createElement(
1465
+ "pre",
1466
+ { "data-testid": "output-display", style: { overflow: "auto", whiteSpace: "pre-wrap" } },
1467
+ formatted
1468
+ );
1469
+ }
1470
+
1471
+ // libs/react/src/components/AgentContent.tsx
1472
+ import React7, { useState as useState7, useCallback as useCallback10 } from "react";
1473
+ function AgentContent({
1474
+ name,
1475
+ description,
1476
+ inputSchema = { type: "object" },
1477
+ render,
1478
+ fallback = null,
1479
+ server
1480
+ }) {
1481
+ const [lastData, setLastData] = useState7(null);
1482
+ const execute = useCallback10(
1483
+ async (args) => {
1484
+ setLastData(args);
1485
+ return {
1486
+ content: [{ type: "text", text: JSON.stringify({ success: true, rendered: name }) }]
1487
+ };
1488
+ },
1489
+ [name]
1490
+ );
1491
+ useDynamicTool({ name, description, inputSchema, execute, server });
1492
+ return React7.createElement(React7.Fragment, null, lastData !== null ? render(lastData) : fallback);
1493
+ }
1494
+
1495
+ // libs/react/src/components/AgentSearch.tsx
1496
+ import React8, { useState as useState8, useCallback as useCallback11 } from "react";
1497
+ function AgentSearch({
1498
+ toolName,
1499
+ description,
1500
+ placeholder,
1501
+ onResults,
1502
+ renderInput,
1503
+ server
1504
+ }) {
1505
+ const [query, setQuery] = useState8("");
1506
+ const execute = useCallback11(
1507
+ async (args) => {
1508
+ const results = args["results"] ?? args;
1509
+ onResults(results);
1510
+ return {
1511
+ content: [{ type: "text", text: JSON.stringify({ success: true, delivered: true }) }]
1512
+ };
1513
+ },
1514
+ [onResults]
1515
+ );
1516
+ useDynamicTool({
1517
+ name: toolName,
1518
+ description,
1519
+ inputSchema: {
1520
+ type: "object",
1521
+ properties: {
1522
+ query: { type: "string", description: "The search query" },
1523
+ results: { type: "array", description: "Search results to display" }
1524
+ }
1525
+ },
1526
+ execute,
1527
+ server
1528
+ });
1529
+ const readQuery = useCallback11(
1530
+ async () => ({
1531
+ contents: [{ uri: `search://${toolName}/query`, mimeType: "text/plain", text: query }]
1532
+ }),
1533
+ [query, toolName]
1534
+ );
1535
+ useDynamicResource({
1536
+ uri: `search://${toolName}/query`,
1537
+ name: `${toolName}-query`,
1538
+ description: `Current search query for ${toolName}`,
1539
+ mimeType: "text/plain",
1540
+ read: readQuery,
1541
+ server
1542
+ });
1543
+ const inputProps = {
1544
+ value: query,
1545
+ onChange: setQuery,
1546
+ placeholder
1547
+ };
1548
+ if (renderInput) {
1549
+ return React8.createElement(React8.Fragment, null, renderInput(inputProps));
1550
+ }
1551
+ return React8.createElement("input", {
1552
+ type: "text",
1553
+ value: query,
1554
+ onChange: (e) => setQuery(e.target.value),
1555
+ placeholder
1556
+ });
1557
+ }
1558
+
1559
+ // libs/react/src/components/mcpComponent.tsx
1560
+ import React9, { useState as useState9, useCallback as useCallback12, Suspense } from "react";
1561
+ import { z } from "zod";
1562
+ var MCP_LAZY_MARKER = /* @__PURE__ */ Symbol.for("frontmcp:lazy");
1563
+ function mcpLazy(factory) {
1564
+ return Object.assign(factory, { [MCP_LAZY_MARKER]: true });
1565
+ }
1566
+ function DefaultTable({ rows, columns }) {
1567
+ return React9.createElement(
1568
+ "table",
1569
+ null,
1570
+ React9.createElement(
1571
+ "thead",
1572
+ null,
1573
+ React9.createElement(
1574
+ "tr",
1575
+ null,
1576
+ columns.map((col) => React9.createElement("th", { key: col.key }, col.header))
1577
+ )
1578
+ ),
1579
+ React9.createElement(
1580
+ "tbody",
1581
+ null,
1582
+ rows.map(
1583
+ (row, i) => React9.createElement(
1584
+ "tr",
1585
+ { key: i },
1586
+ columns.map((col) => {
1587
+ const value = row[col.key];
1588
+ const rendered = col.render ? col.render(value) : String(value ?? "");
1589
+ return React9.createElement("td", { key: col.key }, rendered);
1590
+ })
1591
+ )
1592
+ )
1593
+ )
1594
+ );
1595
+ }
1596
+ function isLazyImport(fn) {
1597
+ if (typeof fn !== "function") return false;
1598
+ return MCP_LAZY_MARKER in fn;
1599
+ }
1600
+ function mcpComponent(component, options) {
1601
+ const { name, description, schema, fallback = null, server, columns } = options;
1602
+ const isTableMode = component === null && columns != null;
1603
+ let ResolvedComponent = null;
1604
+ if (component !== null && !isTableMode) {
1605
+ if (isLazyImport(component)) {
1606
+ ResolvedComponent = React9.lazy(component);
1607
+ } else {
1608
+ ResolvedComponent = component;
1609
+ }
1610
+ }
1611
+ let toolSchema;
1612
+ if (isTableMode) {
1613
+ toolSchema = z.object({ rows: z.array(schema) });
1614
+ } else {
1615
+ toolSchema = schema;
1616
+ }
1617
+ const isLazy = component !== null && !isTableMode && isLazyImport(component);
1618
+ const McpWrappedComponent = Object.assign(
1619
+ function McpWrappedComponentInner(directProps) {
1620
+ const [lastData, setLastData] = useState9(null);
1621
+ const [tableRows, setTableRows] = useState9(null);
1622
+ const execute = useCallback12(
1623
+ async (args) => {
1624
+ if (isTableMode) {
1625
+ const data2 = args;
1626
+ setTableRows(data2.rows);
1627
+ } else {
1628
+ setLastData(args);
1629
+ }
1630
+ return {
1631
+ content: [{ type: "text", text: JSON.stringify({ success: true, rendered: name }) }]
1632
+ };
1633
+ },
1634
+ [name]
1635
+ );
1636
+ useDynamicTool({
1637
+ name,
1638
+ description: description ?? name,
1639
+ schema: toolSchema,
1640
+ execute,
1641
+ server
1642
+ });
1643
+ const hasDirectProps = Object.keys(directProps).length > 0;
1644
+ if (isTableMode && columns) {
1645
+ if (tableRows !== null) {
1646
+ return React9.createElement(DefaultTable, { rows: tableRows, columns });
1647
+ }
1648
+ return React9.createElement(React9.Fragment, null, fallback);
1649
+ }
1650
+ const data = hasDirectProps ? { ...lastData, ...directProps } : lastData;
1651
+ if (data !== null && ResolvedComponent) {
1652
+ if (isLazy) {
1653
+ return React9.createElement(
1654
+ Suspense,
1655
+ { fallback: fallback ?? null },
1656
+ React9.createElement(ResolvedComponent, data)
1657
+ );
1658
+ }
1659
+ return React9.createElement(ResolvedComponent, data);
1660
+ }
1661
+ if (hasDirectProps && ResolvedComponent) {
1662
+ if (isLazy) {
1663
+ return React9.createElement(
1664
+ Suspense,
1665
+ { fallback: fallback ?? null },
1666
+ React9.createElement(ResolvedComponent, directProps)
1667
+ );
1668
+ }
1669
+ return React9.createElement(ResolvedComponent, directProps);
1670
+ }
1671
+ return React9.createElement(React9.Fragment, null, fallback);
1672
+ },
1673
+ { toolName: name }
1674
+ );
1675
+ McpWrappedComponent.displayName = `mcpComponent(${name})`;
1676
+ return McpWrappedComponent;
1677
+ }
1678
+
1679
+ // libs/react/src/state/adapters/reduxAdapter.ts
1680
+ function reduxStore(options) {
1681
+ const { store, name = "redux", selectors, actions: rawActions } = options;
1682
+ let actions;
1683
+ if (rawActions) {
1684
+ actions = {};
1685
+ for (const [key, actionCreator] of Object.entries(rawActions)) {
1686
+ actions[key] = (...args) => {
1687
+ const action = actionCreator(...args);
1688
+ return store.dispatch(action);
1689
+ };
1690
+ }
1691
+ }
1692
+ return {
1693
+ name,
1694
+ getState: store.getState.bind(store),
1695
+ subscribe: store.subscribe.bind(store),
1696
+ selectors,
1697
+ actions
1698
+ };
1699
+ }
1700
+
1701
+ // libs/react/src/state/adapters/valtioAdapter.ts
1702
+ function getByPath(obj, path) {
1703
+ const parts = path.split(".");
1704
+ let current = obj;
1705
+ for (const part of parts) {
1706
+ if (current == null || typeof current !== "object") return void 0;
1707
+ current = current[part];
1708
+ }
1709
+ return current;
1710
+ }
1711
+ function valtioStore(options) {
1712
+ const { proxy, subscribe: valtioSubscribe, name = "valtio", paths, mutations } = options;
1713
+ let selectors;
1714
+ if (paths) {
1715
+ selectors = {};
1716
+ for (const [key, path] of Object.entries(paths)) {
1717
+ selectors[key] = (state) => getByPath(state, path);
1718
+ }
1719
+ }
1720
+ let actions;
1721
+ if (mutations) {
1722
+ actions = {};
1723
+ for (const [key, mutation] of Object.entries(mutations)) {
1724
+ actions[key] = (...args) => mutation(...args);
1725
+ }
1726
+ }
1727
+ return {
1728
+ name,
1729
+ getState: () => JSON.parse(JSON.stringify(proxy)),
1730
+ subscribe: (cb) => valtioSubscribe(proxy, cb),
1731
+ selectors,
1732
+ actions
1733
+ };
1734
+ }
1735
+
1736
+ // libs/react/src/state/adapters/createStore.ts
1737
+ function createStore(options) {
1738
+ return {
1739
+ name: options.name,
1740
+ getState: options.getState,
1741
+ subscribe: options.subscribe,
1742
+ selectors: options.selectors,
1743
+ actions: options.actions
1744
+ };
1745
+ }
1746
+ export {
1747
+ Adapter,
1748
+ AgentContent,
1749
+ AgentSearch,
1750
+ App,
1751
+ ComponentRegistry,
1752
+ DynamicRegistry,
1753
+ DynamicRenderer,
1754
+ ExecutionContextBase,
1755
+ FrontMcp,
1756
+ FrontMcpAdapter,
1757
+ FrontMcpApp,
1758
+ FrontMcpContext,
1759
+ FrontMcpPlugin,
1760
+ FrontMcpPrompt,
1761
+ FrontMcpProvider,
1762
+ FrontMcpResource,
1763
+ FrontMcpResourceTemplate,
1764
+ FrontMcpTool,
1765
+ OutputDisplay,
1766
+ Plugin,
1767
+ Prompt,
1768
+ PromptContext,
1769
+ PromptForm,
1770
+ Resource,
1771
+ ResourceContext,
1772
+ ResourceTemplate,
1773
+ ResourceViewer,
1774
+ ServerRegistry,
1775
+ Tool,
1776
+ ToolContext,
1777
+ ToolForm,
1778
+ clearCreateCache,
1779
+ connect,
1780
+ connectClaude,
1781
+ connectLangChain,
1782
+ connectOpenAI,
1783
+ connectVercelAI,
1784
+ create,
1785
+ createStore,
1786
+ frontMcpPrompt,
1787
+ frontMcpResource,
1788
+ frontMcpResourceTemplate,
1789
+ frontMcpTool,
1790
+ mcpComponent,
1791
+ mcpLazy,
1792
+ prompt,
1793
+ readDomById,
1794
+ readDomBySelector,
1795
+ reduxStore,
1796
+ resource,
1797
+ resourceTemplate,
1798
+ serverRegistry,
1799
+ tool,
1800
+ useCallTool,
1801
+ useComponentTree,
1802
+ useDynamicResource,
1803
+ useDynamicTool,
1804
+ useFrontMcp,
1805
+ useGetPrompt,
1806
+ useListPrompts,
1807
+ useListResources,
1808
+ useListTools,
1809
+ useReadResource,
1810
+ useResolvedServer,
1811
+ useServer,
1812
+ useStoreResource,
1813
+ valtioStore
1814
+ };