@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/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
|
+
};
|