@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
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export { ComponentRegistry } from './ComponentRegistry';
|
|
2
|
+
export type { ComponentRegistryEntry } from './ComponentRegistry';
|
|
3
|
+
export { DynamicRenderer } from './DynamicRenderer';
|
|
4
|
+
export type { DynamicRendererProps } from './DynamicRenderer';
|
|
5
|
+
export { readDomById, readDomBySelector } from './DomResources';
|
|
6
|
+
export type { DomResourceResult } from './DomResources';
|
|
7
|
+
export { ToolForm } from './ToolForm';
|
|
8
|
+
export type { ToolFormProps } from './ToolForm';
|
|
9
|
+
export { PromptForm } from './PromptForm';
|
|
10
|
+
export type { PromptFormProps } from './PromptForm';
|
|
11
|
+
export { ResourceViewer } from './ResourceViewer';
|
|
12
|
+
export type { ResourceViewerProps, ResourceContent } from './ResourceViewer';
|
|
13
|
+
export { OutputDisplay } from './OutputDisplay';
|
|
14
|
+
export type { OutputDisplayProps } from './OutputDisplay';
|
|
15
|
+
export { AgentContent } from './AgentContent';
|
|
16
|
+
export type { AgentContentProps } from './AgentContent';
|
|
17
|
+
export { AgentSearch } from './AgentSearch';
|
|
18
|
+
export type { AgentSearchProps, SearchInputRenderProps } from './AgentSearch';
|
|
19
|
+
export { mcpComponent, mcpLazy } from './mcpComponent';
|
|
20
|
+
export type { McpComponentOptions, McpComponentInstance, LazyFactory } from './mcpComponent';
|
|
21
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,YAAY,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAClE,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,YAAY,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAChE,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,YAAY,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,YAAY,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAC7E,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,YAAY,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,YAAY,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAC9E,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACvD,YAAY,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mcpComponent — factory that wraps a React component + zod schema into
|
|
3
|
+
* an MCP-registered component.
|
|
4
|
+
*
|
|
5
|
+
* On mount, registers an MCP tool (via useDynamicTool with zod schema).
|
|
6
|
+
* When the agent calls the tool, data is validated against the zod schema
|
|
7
|
+
* and passed as typed props to the wrapped component.
|
|
8
|
+
*
|
|
9
|
+
* Supports:
|
|
10
|
+
* - Direct component wrapping
|
|
11
|
+
* - Inline function components
|
|
12
|
+
* - Lazy loading via () => import(...)
|
|
13
|
+
* - Table mode (columns option with null component)
|
|
14
|
+
*/
|
|
15
|
+
import React from 'react';
|
|
16
|
+
import type { ReactNode, ReactElement, ComponentType } from 'react';
|
|
17
|
+
import { z } from 'zod';
|
|
18
|
+
import type { McpColumnDef } from '../types';
|
|
19
|
+
/** Brand applied by mcpLazy to distinguish lazy imports from zero-arg components. */
|
|
20
|
+
type McpLazyBrand = {
|
|
21
|
+
readonly __mcpLazy: true;
|
|
22
|
+
};
|
|
23
|
+
/** A branded lazy factory returned by mcpLazy(). */
|
|
24
|
+
export type LazyFactory<Props> = (() => Promise<{
|
|
25
|
+
default: ComponentType<Props>;
|
|
26
|
+
}>) & McpLazyBrand;
|
|
27
|
+
/**
|
|
28
|
+
* Brand a factory function as a lazy import so mcpComponent can
|
|
29
|
+
* distinguish `() => import(...)` from zero-arg function components.
|
|
30
|
+
*/
|
|
31
|
+
export declare function mcpLazy<Props>(factory: () => Promise<{
|
|
32
|
+
default: ComponentType<Props>;
|
|
33
|
+
}>): LazyFactory<Props>;
|
|
34
|
+
export interface McpComponentOptions<S extends z.ZodObject<z.ZodRawShape>> {
|
|
35
|
+
name: string;
|
|
36
|
+
description?: string;
|
|
37
|
+
schema: S;
|
|
38
|
+
fallback?: ReactNode;
|
|
39
|
+
server?: string;
|
|
40
|
+
columns?: McpColumnDef[];
|
|
41
|
+
}
|
|
42
|
+
export interface McpComponentInstance<Props> extends React.FC<Partial<Props>> {
|
|
43
|
+
toolName: string;
|
|
44
|
+
}
|
|
45
|
+
type ComponentArg<Props> = ComponentType<Props> | ((props: Props) => ReactElement) | LazyFactory<Props> | null;
|
|
46
|
+
export declare function mcpComponent<S extends z.ZodObject<z.ZodRawShape>>(component: ComponentArg<z.infer<S>>, options: McpComponentOptions<S>): McpComponentInstance<z.infer<S>>;
|
|
47
|
+
export {};
|
|
48
|
+
//# sourceMappingURL=mcpComponent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcpComponent.d.ts","sourceRoot":"","sources":["../../src/components/mcpComponent.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAA0C,MAAM,OAAO,CAAC;AAC/D,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAEpE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAO7C,qFAAqF;AACrF,KAAK,YAAY,GAAG;IAAE,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAA;CAAE,CAAC;AAEjD,oDAAoD;AACpD,MAAM,MAAM,WAAW,CAAC,KAAK,IAAI,CAAC,MAAM,OAAO,CAAC;IAAE,OAAO,EAAE,aAAa,CAAC,KAAK,CAAC,CAAA;CAAE,CAAC,CAAC,GAAG,YAAY,CAAC;AAEnG;;;GAGG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;IAAE,OAAO,EAAE,aAAa,CAAC,KAAK,CAAC,CAAA;CAAE,CAAC,GAAG,WAAW,CAAC,KAAK,CAAC,CAE5G;AAID,MAAM,WAAW,mBAAmB,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC;IACvE,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,CAAC,CAAC;IACV,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,YAAY,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,oBAAoB,CAAC,KAAK,CAAE,SAAQ,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAC3E,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,KAAK,YAAY,CAAC,KAAK,IAAI,aAAa,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,KAAK,YAAY,CAAC,GAAG,WAAW,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC;AA6C/G,wBAAgB,YAAY,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,EAC/D,SAAS,EAAE,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EACnC,OAAO,EAAE,mBAAmB,CAAC,CAAC,CAAC,GAC9B,oBAAoB,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAqGlC"}
|
package/esm/ai/index.mjs
ADDED
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
// libs/react/src/ai/useAITools.ts
|
|
2
|
+
import { useState, useCallback as useCallback2, useEffect } from "react";
|
|
3
|
+
import { formatToolsForPlatform, formatResultForPlatform } from "@frontmcp/sdk";
|
|
4
|
+
|
|
5
|
+
// libs/react/src/hooks/useResolvedServer.ts
|
|
6
|
+
import { useContext } from "react";
|
|
7
|
+
|
|
8
|
+
// libs/react/src/provider/FrontMcpContext.ts
|
|
9
|
+
import { createContext } from "react";
|
|
10
|
+
|
|
11
|
+
// libs/react/src/components/ComponentRegistry.ts
|
|
12
|
+
var ComponentRegistry = class {
|
|
13
|
+
entries = /* @__PURE__ */ new Map();
|
|
14
|
+
register(uri, component, meta) {
|
|
15
|
+
const name = extractName(uri);
|
|
16
|
+
this.entries.set(uri, { uri, name, component, description: meta?.description });
|
|
17
|
+
}
|
|
18
|
+
registerAll(map) {
|
|
19
|
+
for (const [uri, component] of Object.entries(map)) {
|
|
20
|
+
this.register(uri, component);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
get(uri) {
|
|
24
|
+
return this.entries.get(uri)?.component;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Resolve a shorthand name like `'UserCard'` by trying
|
|
28
|
+
* `component://UserCard`, `element://UserCard`, `page://UserCard`.
|
|
29
|
+
*/
|
|
30
|
+
resolve(type) {
|
|
31
|
+
const exact = this.entries.get(type);
|
|
32
|
+
if (exact) return exact.component;
|
|
33
|
+
for (const protocol of ["component://", "element://", "page://"]) {
|
|
34
|
+
const entry = this.entries.get(`${protocol}${type}`);
|
|
35
|
+
if (entry) return entry.component;
|
|
36
|
+
}
|
|
37
|
+
return void 0;
|
|
38
|
+
}
|
|
39
|
+
has(uri) {
|
|
40
|
+
return this.entries.has(uri);
|
|
41
|
+
}
|
|
42
|
+
list() {
|
|
43
|
+
return Array.from(this.entries.values()).map(({ uri, name, description }) => ({
|
|
44
|
+
uri,
|
|
45
|
+
name,
|
|
46
|
+
description
|
|
47
|
+
}));
|
|
48
|
+
}
|
|
49
|
+
clear() {
|
|
50
|
+
this.entries.clear();
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
function extractName(uri) {
|
|
54
|
+
const idx = uri.indexOf("://");
|
|
55
|
+
return idx >= 0 ? uri.slice(idx + 3) : uri;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// libs/react/src/registry/DynamicRegistry.ts
|
|
59
|
+
var DynamicRegistry = class {
|
|
60
|
+
tools = /* @__PURE__ */ new Map();
|
|
61
|
+
resources = /* @__PURE__ */ new Map();
|
|
62
|
+
toolRefCounts = /* @__PURE__ */ new Map();
|
|
63
|
+
resourceRefCounts = /* @__PURE__ */ new Map();
|
|
64
|
+
listeners = /* @__PURE__ */ new Set();
|
|
65
|
+
version = 0;
|
|
66
|
+
/**
|
|
67
|
+
* Register a dynamic tool. Returns an unregister function
|
|
68
|
+
* suitable for useEffect cleanup.
|
|
69
|
+
*
|
|
70
|
+
* Multiple registrations of the same name are ref-counted:
|
|
71
|
+
* subsequent registrations update the definition but the tool
|
|
72
|
+
* is only removed when every registrant has unregistered.
|
|
73
|
+
*/
|
|
74
|
+
registerTool(def) {
|
|
75
|
+
const existing = this.toolRefCounts.get(def.name) ?? 0;
|
|
76
|
+
this.toolRefCounts.set(def.name, existing + 1);
|
|
77
|
+
this.tools.set(def.name, def);
|
|
78
|
+
if (existing === 0) {
|
|
79
|
+
this.notify();
|
|
80
|
+
}
|
|
81
|
+
let called = false;
|
|
82
|
+
return () => {
|
|
83
|
+
if (called) return;
|
|
84
|
+
called = true;
|
|
85
|
+
this.unregisterTool(def.name);
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
unregisterTool(name) {
|
|
89
|
+
const count = this.toolRefCounts.get(name);
|
|
90
|
+
if (count == null) return;
|
|
91
|
+
if (count <= 1) {
|
|
92
|
+
this.toolRefCounts.delete(name);
|
|
93
|
+
this.tools.delete(name);
|
|
94
|
+
this.notify();
|
|
95
|
+
} else {
|
|
96
|
+
this.toolRefCounts.set(name, count - 1);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Register a dynamic resource. Returns an unregister function
|
|
101
|
+
* suitable for useEffect cleanup.
|
|
102
|
+
*
|
|
103
|
+
* Multiple registrations of the same URI are ref-counted.
|
|
104
|
+
*/
|
|
105
|
+
registerResource(def) {
|
|
106
|
+
const existing = this.resourceRefCounts.get(def.uri) ?? 0;
|
|
107
|
+
this.resourceRefCounts.set(def.uri, existing + 1);
|
|
108
|
+
this.resources.set(def.uri, def);
|
|
109
|
+
if (existing === 0) {
|
|
110
|
+
this.notify();
|
|
111
|
+
}
|
|
112
|
+
let called = false;
|
|
113
|
+
return () => {
|
|
114
|
+
if (called) return;
|
|
115
|
+
called = true;
|
|
116
|
+
this.unregisterResource(def.uri);
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
unregisterResource(uri) {
|
|
120
|
+
const count = this.resourceRefCounts.get(uri);
|
|
121
|
+
if (count == null) return;
|
|
122
|
+
if (count <= 1) {
|
|
123
|
+
this.resourceRefCounts.delete(uri);
|
|
124
|
+
this.resources.delete(uri);
|
|
125
|
+
this.notify();
|
|
126
|
+
} else {
|
|
127
|
+
this.resourceRefCounts.set(uri, count - 1);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
/** Update the execute function for an existing tool (for stale closure prevention). */
|
|
131
|
+
updateToolExecute(name, execute) {
|
|
132
|
+
const existing = this.tools.get(name);
|
|
133
|
+
if (existing) {
|
|
134
|
+
existing.execute = execute;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/** Update the read function for an existing resource and notify subscribers. */
|
|
138
|
+
updateResourceRead(uri, read) {
|
|
139
|
+
const existing = this.resources.get(uri);
|
|
140
|
+
if (existing) {
|
|
141
|
+
existing.read = read;
|
|
142
|
+
this.notify();
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
getTools() {
|
|
146
|
+
return [...this.tools.values()];
|
|
147
|
+
}
|
|
148
|
+
getResources() {
|
|
149
|
+
return [...this.resources.values()];
|
|
150
|
+
}
|
|
151
|
+
findTool(name) {
|
|
152
|
+
return this.tools.get(name);
|
|
153
|
+
}
|
|
154
|
+
findResource(uri) {
|
|
155
|
+
return this.resources.get(uri);
|
|
156
|
+
}
|
|
157
|
+
hasTool(name) {
|
|
158
|
+
return this.tools.has(name);
|
|
159
|
+
}
|
|
160
|
+
hasResource(uri) {
|
|
161
|
+
return this.resources.has(uri);
|
|
162
|
+
}
|
|
163
|
+
subscribe(listener) {
|
|
164
|
+
this.listeners.add(listener);
|
|
165
|
+
return () => {
|
|
166
|
+
this.listeners.delete(listener);
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
getVersion() {
|
|
170
|
+
return this.version;
|
|
171
|
+
}
|
|
172
|
+
clear() {
|
|
173
|
+
if (this.tools.size === 0 && this.resources.size === 0) return;
|
|
174
|
+
this.tools.clear();
|
|
175
|
+
this.resources.clear();
|
|
176
|
+
this.toolRefCounts.clear();
|
|
177
|
+
this.resourceRefCounts.clear();
|
|
178
|
+
this.notify();
|
|
179
|
+
}
|
|
180
|
+
notify() {
|
|
181
|
+
this.version++;
|
|
182
|
+
this.listeners.forEach((l) => {
|
|
183
|
+
l();
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
// libs/react/src/provider/FrontMcpContext.ts
|
|
189
|
+
var defaultDynamicRegistry = new DynamicRegistry();
|
|
190
|
+
var FrontMcpContext = createContext({
|
|
191
|
+
name: "default",
|
|
192
|
+
registry: new ComponentRegistry(),
|
|
193
|
+
dynamicRegistry: defaultDynamicRegistry,
|
|
194
|
+
getDynamicRegistry: () => defaultDynamicRegistry,
|
|
195
|
+
connect: async () => {
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
// libs/react/src/hooks/useServer.ts
|
|
200
|
+
import { useSyncExternalStore, useCallback } from "react";
|
|
201
|
+
|
|
202
|
+
// libs/react/src/registry/ServerRegistry.ts
|
|
203
|
+
var ServerRegistry = class {
|
|
204
|
+
entries = /* @__PURE__ */ new Map();
|
|
205
|
+
listeners = /* @__PURE__ */ new Set();
|
|
206
|
+
version = 0;
|
|
207
|
+
register(name, server) {
|
|
208
|
+
this.entries.set(name, {
|
|
209
|
+
server,
|
|
210
|
+
client: null,
|
|
211
|
+
status: "idle",
|
|
212
|
+
error: null,
|
|
213
|
+
tools: [],
|
|
214
|
+
resources: [],
|
|
215
|
+
resourceTemplates: [],
|
|
216
|
+
prompts: []
|
|
217
|
+
});
|
|
218
|
+
this.notify();
|
|
219
|
+
}
|
|
220
|
+
unregister(name) {
|
|
221
|
+
this.entries.delete(name);
|
|
222
|
+
this.notify();
|
|
223
|
+
}
|
|
224
|
+
get(name) {
|
|
225
|
+
return this.entries.get(name);
|
|
226
|
+
}
|
|
227
|
+
has(name) {
|
|
228
|
+
return this.entries.has(name);
|
|
229
|
+
}
|
|
230
|
+
list() {
|
|
231
|
+
return [...this.entries.keys()];
|
|
232
|
+
}
|
|
233
|
+
async connect(name) {
|
|
234
|
+
const entry = this.entries.get(name);
|
|
235
|
+
if (!entry) throw new Error(`Server "${name}" not registered`);
|
|
236
|
+
if (entry.client) return entry.client;
|
|
237
|
+
this.entries.set(name, { ...entry, status: "connecting", error: null });
|
|
238
|
+
this.notify();
|
|
239
|
+
try {
|
|
240
|
+
const client = await entry.server.connect();
|
|
241
|
+
const [toolsResult, resourcesResult, templatesResult, promptsResult] = await Promise.all([
|
|
242
|
+
client.listTools(),
|
|
243
|
+
client.listResources(),
|
|
244
|
+
client.listResourceTemplates(),
|
|
245
|
+
client.listPrompts()
|
|
246
|
+
]);
|
|
247
|
+
const connected = {
|
|
248
|
+
...entry,
|
|
249
|
+
client,
|
|
250
|
+
tools: toolsResult,
|
|
251
|
+
resources: resourcesResult.resources ?? [],
|
|
252
|
+
resourceTemplates: templatesResult.resourceTemplates ?? [],
|
|
253
|
+
prompts: promptsResult.prompts ?? [],
|
|
254
|
+
status: "connected",
|
|
255
|
+
error: null
|
|
256
|
+
};
|
|
257
|
+
this.entries.set(name, connected);
|
|
258
|
+
this.notify();
|
|
259
|
+
return client;
|
|
260
|
+
} catch (err) {
|
|
261
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
262
|
+
this.entries.set(name, { ...entry, error, status: "error" });
|
|
263
|
+
this.notify();
|
|
264
|
+
throw error;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
async connectAll() {
|
|
268
|
+
await Promise.all(this.list().map((name) => this.connect(name)));
|
|
269
|
+
}
|
|
270
|
+
update(name, partial) {
|
|
271
|
+
const entry = this.entries.get(name);
|
|
272
|
+
if (entry) {
|
|
273
|
+
this.entries.set(name, { ...entry, ...partial });
|
|
274
|
+
this.notify();
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
clear() {
|
|
278
|
+
this.entries.clear();
|
|
279
|
+
this.notify();
|
|
280
|
+
}
|
|
281
|
+
subscribe(listener) {
|
|
282
|
+
this.listeners.add(listener);
|
|
283
|
+
return () => {
|
|
284
|
+
this.listeners.delete(listener);
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
getVersion() {
|
|
288
|
+
return this.version;
|
|
289
|
+
}
|
|
290
|
+
notify() {
|
|
291
|
+
this.version++;
|
|
292
|
+
this.listeners.forEach((l) => l());
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
var serverRegistry = new ServerRegistry();
|
|
296
|
+
|
|
297
|
+
// libs/react/src/hooks/useServer.ts
|
|
298
|
+
function useServer(name) {
|
|
299
|
+
const subscribe = useCallback((cb) => serverRegistry.subscribe(cb), []);
|
|
300
|
+
const getSnapshot = useCallback(() => {
|
|
301
|
+
return serverRegistry.get(name ?? "default");
|
|
302
|
+
}, [name]);
|
|
303
|
+
return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// libs/react/src/hooks/useResolvedServer.ts
|
|
307
|
+
function useResolvedServer(serverName) {
|
|
308
|
+
const ctx = useContext(FrontMcpContext);
|
|
309
|
+
const resolvedName = serverName ?? ctx.name;
|
|
310
|
+
const entry = useServer(resolvedName);
|
|
311
|
+
return { entry, name: resolvedName, registry: ctx.registry, connect: ctx.connect };
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// libs/react/src/ai/useAITools.ts
|
|
315
|
+
function useAITools(platform, options) {
|
|
316
|
+
const { entry } = useResolvedServer(options?.server);
|
|
317
|
+
const server = entry?.server ?? null;
|
|
318
|
+
const toolInfos = entry?.tools ?? [];
|
|
319
|
+
const status = entry?.status ?? "idle";
|
|
320
|
+
const [formattedTools, setFormattedTools] = useState(null);
|
|
321
|
+
const [loading, setLoading] = useState(true);
|
|
322
|
+
const [error, setError] = useState(null);
|
|
323
|
+
useEffect(() => {
|
|
324
|
+
if (status !== "connected" || toolInfos.length === 0) {
|
|
325
|
+
setFormattedTools(null);
|
|
326
|
+
setLoading(status !== "connected" && status !== "error");
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
try {
|
|
330
|
+
const mcpTools = toolInfos.filter((t) => t.inputSchema != null).map((t) => ({ name: t.name, description: t.description, inputSchema: t.inputSchema }));
|
|
331
|
+
if (mcpTools.length === 0) {
|
|
332
|
+
setFormattedTools(null);
|
|
333
|
+
setLoading(false);
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
const formatted = formatToolsForPlatform(
|
|
337
|
+
mcpTools,
|
|
338
|
+
platform
|
|
339
|
+
);
|
|
340
|
+
setFormattedTools(formatted);
|
|
341
|
+
setLoading(false);
|
|
342
|
+
setError(null);
|
|
343
|
+
} catch (err) {
|
|
344
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
345
|
+
setLoading(false);
|
|
346
|
+
}
|
|
347
|
+
}, [toolInfos, platform, status]);
|
|
348
|
+
const callTool = useCallback2(
|
|
349
|
+
async (name, args) => {
|
|
350
|
+
if (!server) {
|
|
351
|
+
throw new Error("FrontMCP server not available");
|
|
352
|
+
}
|
|
353
|
+
try {
|
|
354
|
+
const rawResult = await server.callTool(name, args);
|
|
355
|
+
return formatResultForPlatform(rawResult, platform);
|
|
356
|
+
} catch (err) {
|
|
357
|
+
const error2 = err instanceof Error ? err : new Error(String(err));
|
|
358
|
+
setError(error2);
|
|
359
|
+
throw error2;
|
|
360
|
+
}
|
|
361
|
+
},
|
|
362
|
+
[server, platform]
|
|
363
|
+
);
|
|
364
|
+
return { tools: formattedTools, callTool, loading, error };
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// libs/react/src/ai/useTools.ts
|
|
368
|
+
import { useCallback as useCallback3 } from "react";
|
|
369
|
+
import { processPlatformToolCalls } from "@frontmcp/utils";
|
|
370
|
+
function useTools(platform, options) {
|
|
371
|
+
const { tools, callTool, loading, error } = useAITools(platform, options);
|
|
372
|
+
const processToolCalls = useCallback3(
|
|
373
|
+
(calls) => processPlatformToolCalls(platform, calls, callTool),
|
|
374
|
+
[platform, callTool]
|
|
375
|
+
);
|
|
376
|
+
return { tools, processToolCalls, loading, error };
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// libs/react/src/ai/createToolHandler.ts
|
|
380
|
+
import { formatResultForPlatform as formatResultForPlatform2 } from "@frontmcp/sdk";
|
|
381
|
+
function createToolCallHandler(server, platform) {
|
|
382
|
+
return {
|
|
383
|
+
callTool: async (name, args) => {
|
|
384
|
+
const rawResult = await server.callTool(name, args);
|
|
385
|
+
return formatResultForPlatform2(rawResult, platform);
|
|
386
|
+
}
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
export {
|
|
390
|
+
createToolCallHandler,
|
|
391
|
+
useAITools,
|
|
392
|
+
useTools
|
|
393
|
+
};
|