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