@decocms/mesh-sdk 1.2.2 → 1.2.3
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/README.md +10 -10
- package/package.json +3 -2
- package/src/context/index.ts +0 -1
- package/src/context/project-context.tsx +0 -10
- package/src/hooks/index.ts +3 -0
- package/src/hooks/use-collections.ts +19 -12
- package/src/hooks/use-connection.ts +12 -1
- package/src/hooks/use-mcp-client.ts +27 -10
- package/src/hooks/use-virtual-mcp.ts +64 -0
- package/src/index.ts +38 -2
- package/src/lib/bridge-transport.ts +6 -434
- package/src/lib/constants.test.ts +26 -0
- package/src/lib/constants.ts +121 -67
- package/src/lib/default-model.ts +188 -3
- package/src/lib/mcp-oauth.ts +59 -8
- package/src/lib/query-keys.ts +19 -4
- package/src/lib/server-client-bridge.ts +4 -146
- package/src/lib/usage.test.ts +66 -0
- package/src/lib/usage.ts +26 -0
- package/src/types/ai-providers.ts +19 -1
- package/src/types/connection.ts +5 -0
- package/src/types/decopilot-events.test.ts +78 -0
- package/src/types/decopilot-events.ts +51 -8
- package/src/types/index.ts +18 -0
- package/src/types/virtual-mcp.test.ts +202 -0
- package/src/types/virtual-mcp.ts +416 -9
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @decocms/mesh-sdk
|
|
2
2
|
|
|
3
|
-
SDK for building external apps that integrate with
|
|
3
|
+
SDK for building external apps that integrate with Studio MCP servers. Provides React hooks and utilities for managing connections, authenticating with OAuth, and calling MCP tools.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -22,7 +22,7 @@ npm install sonner
|
|
|
22
22
|
|
|
23
23
|
### 1. Create an API Key
|
|
24
24
|
|
|
25
|
-
In
|
|
25
|
+
In Studio, call the `API_KEY_CREATE` tool to create an API key with the appropriate scopes for the connections you want to access. The API key will be used to authenticate your external app.
|
|
26
26
|
|
|
27
27
|
```typescript
|
|
28
28
|
// Example: Create an API key via MCP
|
|
@@ -35,7 +35,7 @@ await client.callTool({
|
|
|
35
35
|
});
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
-
### 2. Server-Side: Connect to
|
|
38
|
+
### 2. Server-Side: Connect to Studio
|
|
39
39
|
|
|
40
40
|
```typescript
|
|
41
41
|
// server.ts (Node.js / Bun / your backend)
|
|
@@ -213,12 +213,12 @@ const result = await specificClient.callTool({
|
|
|
213
213
|
|
|
214
214
|
### `createMCPClient(options)` - Server-Side
|
|
215
215
|
|
|
216
|
-
Creates and connects an MCP client to a
|
|
216
|
+
Creates and connects an MCP client to a Studio server. **Use on server only** - don't expose your API key to the client.
|
|
217
217
|
|
|
218
218
|
```typescript
|
|
219
219
|
// server-side only
|
|
220
220
|
const client = await createMCPClient({
|
|
221
|
-
meshUrl: "https://
|
|
221
|
+
meshUrl: "https://studio.example.com", // Required for external apps
|
|
222
222
|
connectionId: "self", // "self" for management API, or connection ID
|
|
223
223
|
orgId: "org_xxx", // Organization ID
|
|
224
224
|
token: process.env.MESH_API_KEY, // API key from environment
|
|
@@ -227,7 +227,7 @@ const client = await createMCPClient({
|
|
|
227
227
|
|
|
228
228
|
### `useMCPClient(options)` - Client-Side (Same-Origin Only)
|
|
229
229
|
|
|
230
|
-
React hook version of `createMCPClient`. Uses Suspense. **Only use when running on the same origin as
|
|
230
|
+
React hook version of `createMCPClient`. Uses Suspense. **Only use when running on the same origin as Studio** (e.g., inside Studio app itself).
|
|
231
231
|
|
|
232
232
|
```typescript
|
|
233
233
|
// client-side - only for same-origin apps
|
|
@@ -249,7 +249,7 @@ Triggers OAuth authentication flow for an MCP connection. **This runs client-sid
|
|
|
249
249
|
```typescript
|
|
250
250
|
// client-side - safe to use in browser
|
|
251
251
|
const result = await authenticateMcp({
|
|
252
|
-
meshUrl: "https://
|
|
252
|
+
meshUrl: "https://studio.example.com", // Required for external apps
|
|
253
253
|
connectionId: "conn_xxx", // Connection to authenticate
|
|
254
254
|
callbackUrl: "https://your-app.com/oauth/callback", // Your OAuth callback URL
|
|
255
255
|
timeout: 120000, // Timeout in ms (default: 120000)
|
|
@@ -274,9 +274,9 @@ Check if a connection is authenticated. Can be used on either server or client.
|
|
|
274
274
|
|
|
275
275
|
```typescript
|
|
276
276
|
const status = await isConnectionAuthenticated({
|
|
277
|
-
url: "https://
|
|
277
|
+
url: "https://studio.example.com/mcp/conn_xxx",
|
|
278
278
|
token: "bearer_token", // Optional
|
|
279
|
-
meshUrl: "https://
|
|
279
|
+
meshUrl: "https://studio.example.com", // For API calls
|
|
280
280
|
});
|
|
281
281
|
|
|
282
282
|
console.log(status.isAuthenticated); // boolean
|
|
@@ -286,7 +286,7 @@ console.log(status.hasOAuthToken); // boolean
|
|
|
286
286
|
|
|
287
287
|
### Collection Hooks - Client-Side (Same-Origin Only)
|
|
288
288
|
|
|
289
|
-
When using with `ProjectContextProvider`, you get access to collection hooks. **Only use when running on the same origin as
|
|
289
|
+
When using with `ProjectContextProvider`, you get access to collection hooks. **Only use when running on the same origin as Studio** (e.g., inside Studio app or plugins).
|
|
290
290
|
|
|
291
291
|
```typescript
|
|
292
292
|
// client-side - only for same-origin apps (inside Mesh)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@decocms/mesh-sdk",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.3",
|
|
4
4
|
"description": "SDK for building external apps that integrate with Mesh MCP servers",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"@decocms/bindings": "^1.1.1",
|
|
19
|
-
"@
|
|
19
|
+
"@decocms/mcp-utils": "workspace:*",
|
|
20
|
+
"@modelcontextprotocol/sdk": "1.29.0",
|
|
20
21
|
"zod": "^4.0.0"
|
|
21
22
|
},
|
|
22
23
|
"peerDependencies": {
|
package/src/context/index.ts
CHANGED
|
@@ -73,8 +73,6 @@ export interface ProjectData {
|
|
|
73
73
|
enabledPlugins?: string[] | null;
|
|
74
74
|
/** UI customization */
|
|
75
75
|
ui?: ProjectUI | null;
|
|
76
|
-
/** Whether this is the org-admin project */
|
|
77
|
-
isOrgAdmin?: boolean;
|
|
78
76
|
}
|
|
79
77
|
|
|
80
78
|
interface ProjectContextType {
|
|
@@ -110,14 +108,6 @@ export const useCurrentProject = () => {
|
|
|
110
108
|
return useProjectContext().project;
|
|
111
109
|
};
|
|
112
110
|
|
|
113
|
-
/**
|
|
114
|
-
* Convenience hook to check if current project is org-admin
|
|
115
|
-
*/
|
|
116
|
-
export const useIsOrgAdmin = () => {
|
|
117
|
-
const project = useProjectContext().project;
|
|
118
|
-
return project.isOrgAdmin === true;
|
|
119
|
-
};
|
|
120
|
-
|
|
121
111
|
export type ProjectContextProviderProps = {
|
|
122
112
|
org: OrganizationData;
|
|
123
113
|
project: ProjectData;
|
package/src/hooks/index.ts
CHANGED
|
@@ -74,7 +74,10 @@ export {
|
|
|
74
74
|
export {
|
|
75
75
|
useVirtualMCPs,
|
|
76
76
|
useVirtualMCP,
|
|
77
|
+
virtualMcpItemQueryOptions,
|
|
77
78
|
useVirtualMCPActions,
|
|
79
|
+
useVirtualMCPsLastUsed,
|
|
78
80
|
type VirtualMCPFilter,
|
|
79
81
|
type UseVirtualMCPsOptions,
|
|
82
|
+
type VirtualMCPLastUsed,
|
|
80
83
|
} from "./use-virtual-mcp";
|
|
@@ -146,7 +146,7 @@ export function buildOrderByExpression<T extends CollectionEntity>(
|
|
|
146
146
|
defaultSortKey: keyof T,
|
|
147
147
|
): OrderByExpression[] | undefined {
|
|
148
148
|
const key = sortKey ?? defaultSortKey;
|
|
149
|
-
const direction = sortDirection ?? "
|
|
149
|
+
const direction = sortDirection ?? "desc";
|
|
150
150
|
|
|
151
151
|
return [
|
|
152
152
|
{
|
|
@@ -182,15 +182,12 @@ function extractPayload<T>(result: unknown): T {
|
|
|
182
182
|
}
|
|
183
183
|
|
|
184
184
|
/**
|
|
185
|
-
*
|
|
186
|
-
*
|
|
187
|
-
*
|
|
188
|
-
*
|
|
189
|
-
* @param itemId - The ID of the item to fetch (undefined returns null without making an API call)
|
|
190
|
-
* @param client - The MCP client used to call collection tools
|
|
191
|
-
* @returns Suspense query result with the item, or null if itemId is undefined
|
|
185
|
+
* Query options for a single collection item. Shared between useCollectionItem
|
|
186
|
+
* and parallel-prefetch batches (useSuspenseQueries) so both build an identical
|
|
187
|
+
* query key + queryFn — letting a prefetch warm the exact cache entry the hook
|
|
188
|
+
* later reads.
|
|
192
189
|
*/
|
|
193
|
-
export function
|
|
190
|
+
export function collectionItemQueryOptions<T extends CollectionEntity>(
|
|
194
191
|
scopeKey: string,
|
|
195
192
|
collectionName: string,
|
|
196
193
|
itemId: string | undefined,
|
|
@@ -198,8 +195,7 @@ export function useCollectionItem<T extends CollectionEntity>(
|
|
|
198
195
|
) {
|
|
199
196
|
const upperName = collectionName.toUpperCase();
|
|
200
197
|
const getToolName = `COLLECTION_${upperName}_GET`;
|
|
201
|
-
|
|
202
|
-
const { data } = useSuspenseQuery({
|
|
198
|
+
return {
|
|
203
199
|
queryKey: KEYS.collectionItem(
|
|
204
200
|
client,
|
|
205
201
|
scopeKey,
|
|
@@ -220,7 +216,18 @@ export function useCollectionItem<T extends CollectionEntity>(
|
|
|
220
216
|
return extractPayload<CollectionGetOutput<T>>(result);
|
|
221
217
|
},
|
|
222
218
|
staleTime: 60_000,
|
|
223
|
-
}
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export function useCollectionItem<T extends CollectionEntity>(
|
|
223
|
+
scopeKey: string,
|
|
224
|
+
collectionName: string,
|
|
225
|
+
itemId: string | undefined,
|
|
226
|
+
client: Client,
|
|
227
|
+
) {
|
|
228
|
+
const { data } = useSuspenseQuery(
|
|
229
|
+
collectionItemQueryOptions<T>(scopeKey, collectionName, itemId, client),
|
|
230
|
+
);
|
|
224
231
|
|
|
225
232
|
return data?.item ?? null;
|
|
226
233
|
}
|
|
@@ -37,6 +37,10 @@ export interface UseConnectionsOptions
|
|
|
37
37
|
* Whether to include VIRTUAL connections in results. Defaults to false (server default).
|
|
38
38
|
*/
|
|
39
39
|
includeVirtual?: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Filter by computed connection slug (matches app_name, or slug derived from connection_url/title).
|
|
42
|
+
*/
|
|
43
|
+
slug?: string;
|
|
40
44
|
}
|
|
41
45
|
|
|
42
46
|
/**
|
|
@@ -46,7 +50,7 @@ export interface UseConnectionsOptions
|
|
|
46
50
|
* @returns Suspense query result with connections as ConnectionEntity[]
|
|
47
51
|
*/
|
|
48
52
|
export function useConnections(options: UseConnectionsOptions = {}) {
|
|
49
|
-
const { binding, includeVirtual, ...collectionOptions } = options;
|
|
53
|
+
const { binding, includeVirtual, slug, ...collectionOptions } = options;
|
|
50
54
|
|
|
51
55
|
// Build additional tool args for the COLLECTION_CONNECTIONS_LIST tool
|
|
52
56
|
const additionalToolArgs: Record<string, unknown> = {
|
|
@@ -61,6 +65,10 @@ export function useConnections(options: UseConnectionsOptions = {}) {
|
|
|
61
65
|
additionalToolArgs.include_virtual = includeVirtual;
|
|
62
66
|
}
|
|
63
67
|
|
|
68
|
+
if (slug !== undefined) {
|
|
69
|
+
additionalToolArgs.slug = slug;
|
|
70
|
+
}
|
|
71
|
+
|
|
64
72
|
const finalOptions: UseCollectionListOptions<ConnectionEntity> = {
|
|
65
73
|
...collectionOptions,
|
|
66
74
|
additionalToolArgs:
|
|
@@ -73,6 +81,7 @@ export function useConnections(options: UseConnectionsOptions = {}) {
|
|
|
73
81
|
const client = useMCPClient({
|
|
74
82
|
connectionId: SELF_MCP_ALIAS_ID,
|
|
75
83
|
orgId: org.id,
|
|
84
|
+
orgSlug: org.slug,
|
|
76
85
|
});
|
|
77
86
|
return useCollectionList<ConnectionEntity>(
|
|
78
87
|
org.id,
|
|
@@ -93,6 +102,7 @@ export function useConnection(connectionId: string | undefined) {
|
|
|
93
102
|
const client = useMCPClient({
|
|
94
103
|
connectionId: SELF_MCP_ALIAS_ID,
|
|
95
104
|
orgId: org.id,
|
|
105
|
+
orgSlug: org.slug,
|
|
96
106
|
});
|
|
97
107
|
return useCollectionItem<ConnectionEntity>(
|
|
98
108
|
org.id,
|
|
@@ -112,6 +122,7 @@ export function useConnectionActions() {
|
|
|
112
122
|
const client = useMCPClient({
|
|
113
123
|
connectionId: SELF_MCP_ALIAS_ID,
|
|
114
124
|
orgId: org.id,
|
|
125
|
+
orgSlug: org.slug,
|
|
115
126
|
});
|
|
116
127
|
return useCollectionActions<ConnectionEntity>(org.id, "CONNECTIONS", client);
|
|
117
128
|
}
|
|
@@ -11,8 +11,10 @@ const DEFAULT_CLIENT_INFO = {
|
|
|
11
11
|
export interface CreateMcpClientOptions {
|
|
12
12
|
/** Connection ID - use SELF_MCP_ALIAS_ID for the self/management MCP (ALL_TOOLS), or any connectionId for other MCPs */
|
|
13
13
|
connectionId: string | null;
|
|
14
|
-
/** Organization ID - required
|
|
14
|
+
/** Organization ID - required for query-key scoping */
|
|
15
15
|
orgId: string;
|
|
16
|
+
/** Organization slug - required, used to build the /api/:org/mcp URL */
|
|
17
|
+
orgSlug: string;
|
|
16
18
|
/** Authorization token - optional */
|
|
17
19
|
token?: string | null;
|
|
18
20
|
/** Mesh server URL - optional, defaults to window.location.origin (for external apps, provide your Mesh server URL) */
|
|
@@ -28,10 +30,14 @@ export interface UseMcpClientOptionalOptions
|
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
/**
|
|
31
|
-
* Build the MCP URL from connectionId and optional meshUrl
|
|
32
|
-
* Uses /mcp/:connectionId for all servers
|
|
33
|
+
* Build the MCP URL from connectionId and optional meshUrl.
|
|
34
|
+
* Uses /api/:org/mcp/:connectionId for all servers (org-scoped routing).
|
|
33
35
|
*/
|
|
34
|
-
function buildMcpUrl(
|
|
36
|
+
function buildMcpUrl(
|
|
37
|
+
connectionId: string | null,
|
|
38
|
+
orgSlug: string,
|
|
39
|
+
meshUrl?: string,
|
|
40
|
+
): string {
|
|
35
41
|
const baseUrl =
|
|
36
42
|
meshUrl ??
|
|
37
43
|
(typeof window !== "undefined" ? window.location.origin : undefined);
|
|
@@ -41,7 +47,10 @@ function buildMcpUrl(connectionId: string | null, meshUrl?: string): string {
|
|
|
41
47
|
);
|
|
42
48
|
}
|
|
43
49
|
|
|
44
|
-
const
|
|
50
|
+
const orgPath = `/api/${encodeURIComponent(orgSlug)}`;
|
|
51
|
+
const path = connectionId
|
|
52
|
+
? `${orgPath}/mcp/${connectionId}`
|
|
53
|
+
: `${orgPath}/mcp`;
|
|
45
54
|
return new URL(path, baseUrl).href;
|
|
46
55
|
}
|
|
47
56
|
|
|
@@ -55,10 +64,11 @@ function buildMcpUrl(connectionId: string | null, meshUrl?: string): string {
|
|
|
55
64
|
export async function createMCPClient({
|
|
56
65
|
connectionId,
|
|
57
66
|
orgId,
|
|
67
|
+
orgSlug,
|
|
58
68
|
token,
|
|
59
69
|
meshUrl,
|
|
60
70
|
}: CreateMcpClientOptions): Promise<Client> {
|
|
61
|
-
const url = buildMcpUrl(connectionId, meshUrl);
|
|
71
|
+
const url = buildMcpUrl(connectionId, orgSlug, meshUrl);
|
|
62
72
|
|
|
63
73
|
const client = new Client(DEFAULT_CLIENT_INFO, {
|
|
64
74
|
capabilities: {
|
|
@@ -79,7 +89,6 @@ export async function createMCPClient({
|
|
|
79
89
|
headers: {
|
|
80
90
|
"Content-Type": "application/json",
|
|
81
91
|
Accept: "application/json, text/event-stream",
|
|
82
|
-
"x-org-id": orgId,
|
|
83
92
|
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
|
84
93
|
},
|
|
85
94
|
},
|
|
@@ -112,6 +121,7 @@ export async function createMCPClient({
|
|
|
112
121
|
export function useMCPClient({
|
|
113
122
|
connectionId,
|
|
114
123
|
orgId,
|
|
124
|
+
orgSlug,
|
|
115
125
|
token,
|
|
116
126
|
meshUrl,
|
|
117
127
|
}: UseMcpClientOptions): Client {
|
|
@@ -124,9 +134,13 @@ export function useMCPClient({
|
|
|
124
134
|
|
|
125
135
|
const { data: client } = useSuspenseQuery({
|
|
126
136
|
queryKey,
|
|
127
|
-
queryFn: () =>
|
|
137
|
+
queryFn: () =>
|
|
138
|
+
createMCPClient({ connectionId, orgId, orgSlug, token, meshUrl }),
|
|
128
139
|
staleTime: Infinity, // Keep client alive while query is active
|
|
129
|
-
|
|
140
|
+
// Keep the client cached for a minute after the last subscriber detaches so
|
|
141
|
+
// brief unmount/remount transitions (sidebar collapse toggle, popover open,
|
|
142
|
+
// etc.) re-use the same transport instead of re-establishing it.
|
|
143
|
+
gcTime: 60_000,
|
|
130
144
|
});
|
|
131
145
|
|
|
132
146
|
return client!;
|
|
@@ -146,6 +160,7 @@ export function useMCPClient({
|
|
|
146
160
|
export function useMCPClientOptional({
|
|
147
161
|
connectionId,
|
|
148
162
|
orgId,
|
|
163
|
+
orgSlug,
|
|
149
164
|
token,
|
|
150
165
|
meshUrl,
|
|
151
166
|
}: UseMcpClientOptionalOptions): Client | null {
|
|
@@ -168,12 +183,14 @@ export function useMCPClientOptional({
|
|
|
168
183
|
return createMCPClient({
|
|
169
184
|
connectionId: connectionId as string | null,
|
|
170
185
|
orgId,
|
|
186
|
+
orgSlug,
|
|
171
187
|
token,
|
|
172
188
|
meshUrl,
|
|
173
189
|
});
|
|
174
190
|
},
|
|
175
191
|
staleTime: Infinity,
|
|
176
|
-
|
|
192
|
+
// Match the non-optional variant — see useMCPClient for the rationale.
|
|
193
|
+
gcTime: 60_000,
|
|
177
194
|
});
|
|
178
195
|
|
|
179
196
|
return client ?? null;
|
|
@@ -5,17 +5,28 @@
|
|
|
5
5
|
* These hooks offer a reactive interface for accessing and manipulating virtual MCPs.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
import { useQuery } from "@tanstack/react-query";
|
|
9
|
+
import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
8
10
|
import type { VirtualMCPEntity } from "../types/virtual-mcp";
|
|
9
11
|
import { useProjectContext } from "../context";
|
|
10
12
|
import {
|
|
13
|
+
collectionItemQueryOptions,
|
|
11
14
|
useCollectionActions,
|
|
12
15
|
useCollectionItem,
|
|
13
16
|
useCollectionList,
|
|
14
17
|
type CollectionFilter,
|
|
15
18
|
type UseCollectionListOptions,
|
|
16
19
|
} from "./use-collections";
|
|
20
|
+
import type { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
17
21
|
import { useMCPClient } from "./use-mcp-client";
|
|
18
22
|
import { SELF_MCP_ALIAS_ID } from "../lib/constants";
|
|
23
|
+
import { KEYS } from "../lib/query-keys";
|
|
24
|
+
|
|
25
|
+
export interface VirtualMCPLastUsed {
|
|
26
|
+
id: string;
|
|
27
|
+
last_used_at?: string;
|
|
28
|
+
last_used_by?: string;
|
|
29
|
+
}
|
|
19
30
|
|
|
20
31
|
/**
|
|
21
32
|
* Filter definition for virtual MCPs (matches @deco/ui Filter shape)
|
|
@@ -38,6 +49,7 @@ export function useVirtualMCPs(options: UseVirtualMCPsOptions = {}) {
|
|
|
38
49
|
const client = useMCPClient({
|
|
39
50
|
connectionId: SELF_MCP_ALIAS_ID,
|
|
40
51
|
orgId: org.id,
|
|
52
|
+
orgSlug: org.slug,
|
|
41
53
|
});
|
|
42
54
|
|
|
43
55
|
return useCollectionList<VirtualMCPEntity>(
|
|
@@ -48,6 +60,23 @@ export function useVirtualMCPs(options: UseVirtualMCPsOptions = {}) {
|
|
|
48
60
|
);
|
|
49
61
|
}
|
|
50
62
|
|
|
63
|
+
/**
|
|
64
|
+
* Query options for a single virtual MCP — shared with parallel-prefetch
|
|
65
|
+
* batches so they warm the exact cache entry useVirtualMCP reads.
|
|
66
|
+
*/
|
|
67
|
+
export function virtualMcpItemQueryOptions(
|
|
68
|
+
orgId: string,
|
|
69
|
+
virtualMcpId: string | null | undefined,
|
|
70
|
+
client: Client,
|
|
71
|
+
) {
|
|
72
|
+
return collectionItemQueryOptions<VirtualMCPEntity>(
|
|
73
|
+
orgId,
|
|
74
|
+
"VIRTUAL_MCP",
|
|
75
|
+
virtualMcpId ?? undefined,
|
|
76
|
+
client,
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
51
80
|
/**
|
|
52
81
|
* Hook to get a single virtual MCP by ID
|
|
53
82
|
*
|
|
@@ -61,6 +90,7 @@ export function useVirtualMCP(
|
|
|
61
90
|
const client = useMCPClient({
|
|
62
91
|
connectionId: SELF_MCP_ALIAS_ID,
|
|
63
92
|
orgId: org.id,
|
|
93
|
+
orgSlug: org.slug,
|
|
64
94
|
});
|
|
65
95
|
|
|
66
96
|
// If null/undefined, return null (use default virtual MCP)
|
|
@@ -75,6 +105,39 @@ export function useVirtualMCP(
|
|
|
75
105
|
return dbVirtualMCP;
|
|
76
106
|
}
|
|
77
107
|
|
|
108
|
+
/**
|
|
109
|
+
* Hook to fetch last-used info (most recent thread timestamp + user) for a set
|
|
110
|
+
* of virtual MCPs. Backed by VIRTUAL_MCP_LAST_USED_LIST so the data isn't
|
|
111
|
+
* loaded on the agent fetch hot path.
|
|
112
|
+
*/
|
|
113
|
+
export function useVirtualMCPsLastUsed(ids: string[]) {
|
|
114
|
+
const { org } = useProjectContext();
|
|
115
|
+
const client = useMCPClient({
|
|
116
|
+
connectionId: SELF_MCP_ALIAS_ID,
|
|
117
|
+
orgId: org.id,
|
|
118
|
+
orgSlug: org.slug,
|
|
119
|
+
});
|
|
120
|
+
const sortedIds = [...ids].sort();
|
|
121
|
+
|
|
122
|
+
return useQuery<Map<string, VirtualMCPLastUsed>>({
|
|
123
|
+
queryKey: KEYS.virtualMcpLastUsed(org.id, sortedIds),
|
|
124
|
+
enabled: sortedIds.length > 0,
|
|
125
|
+
staleTime: 30_000,
|
|
126
|
+
queryFn: async () => {
|
|
127
|
+
const result = (await client.callTool({
|
|
128
|
+
name: "VIRTUAL_MCP_LAST_USED_LIST",
|
|
129
|
+
arguments: { ids: sortedIds },
|
|
130
|
+
})) as CallToolResult;
|
|
131
|
+
const payload = (result.structuredContent ?? { items: [] }) as {
|
|
132
|
+
items: VirtualMCPLastUsed[];
|
|
133
|
+
};
|
|
134
|
+
const map = new Map<string, VirtualMCPLastUsed>();
|
|
135
|
+
for (const item of payload.items) map.set(item.id, item);
|
|
136
|
+
return map;
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
78
141
|
/**
|
|
79
142
|
* Hook to get virtual MCP mutation actions (create, update, delete)
|
|
80
143
|
*
|
|
@@ -85,6 +148,7 @@ export function useVirtualMCPActions() {
|
|
|
85
148
|
const client = useMCPClient({
|
|
86
149
|
connectionId: SELF_MCP_ALIAS_ID,
|
|
87
150
|
orgId: org.id,
|
|
151
|
+
orgSlug: org.slug,
|
|
88
152
|
});
|
|
89
153
|
|
|
90
154
|
return useCollectionActions<VirtualMCPEntity>(org.id, "VIRTUAL_MCP", client);
|
package/src/index.ts
CHANGED
|
@@ -4,7 +4,6 @@ export {
|
|
|
4
4
|
useProjectContext,
|
|
5
5
|
useOrg,
|
|
6
6
|
useCurrentProject,
|
|
7
|
-
useIsOrgAdmin,
|
|
8
7
|
Locator,
|
|
9
8
|
type ProjectContextProviderProps,
|
|
10
9
|
type ProjectLocator,
|
|
@@ -73,9 +72,12 @@ export {
|
|
|
73
72
|
// Virtual MCP hooks
|
|
74
73
|
useVirtualMCPs,
|
|
75
74
|
useVirtualMCP,
|
|
75
|
+
virtualMcpItemQueryOptions,
|
|
76
76
|
useVirtualMCPActions,
|
|
77
|
+
useVirtualMCPsLastUsed,
|
|
77
78
|
type VirtualMCPFilter,
|
|
78
79
|
type UseVirtualMCPsOptions,
|
|
80
|
+
type VirtualMCPLastUsed,
|
|
79
81
|
} from "./hooks";
|
|
80
82
|
|
|
81
83
|
// Types
|
|
@@ -109,10 +111,28 @@ export {
|
|
|
109
111
|
VirtualMCPEntitySchema,
|
|
110
112
|
VirtualMCPCreateDataSchema,
|
|
111
113
|
VirtualMCPUpdateDataSchema,
|
|
114
|
+
VirtualMcpUILayoutSchema,
|
|
115
|
+
VirtualMcpUILayoutTabSchema,
|
|
112
116
|
type VirtualMCPEntity,
|
|
113
117
|
type VirtualMCPCreateData,
|
|
114
118
|
type VirtualMCPUpdateData,
|
|
115
119
|
type VirtualMCPConnection,
|
|
120
|
+
type VirtualMcpUILayout,
|
|
121
|
+
type VirtualMcpUILayoutTab,
|
|
122
|
+
type VirtualMcpHomeTile,
|
|
123
|
+
getHomeTiles,
|
|
124
|
+
SandboxMapSchema,
|
|
125
|
+
type SandboxMap,
|
|
126
|
+
SandboxRecordSchema,
|
|
127
|
+
type SandboxRecord,
|
|
128
|
+
type RuntimeMetadata,
|
|
129
|
+
type RuntimeEnvEntry,
|
|
130
|
+
ENV_VAR_KEY_RE,
|
|
131
|
+
parseSandboxRecord,
|
|
132
|
+
parseBranchMap,
|
|
133
|
+
normalizeSandboxMap,
|
|
134
|
+
type SandboxProviderKind,
|
|
135
|
+
type GithubRepo,
|
|
116
136
|
// Decopilot event types
|
|
117
137
|
THREAD_STATUSES,
|
|
118
138
|
THREAD_DISPLAY_STATUSES,
|
|
@@ -155,8 +175,15 @@ export { KEYS } from "./lib/query-keys";
|
|
|
155
175
|
export {
|
|
156
176
|
DEFAULT_MODEL_PREFERENCES,
|
|
157
177
|
FAST_MODEL_PREFERENCES,
|
|
178
|
+
SMART_MODEL_PREFERENCES,
|
|
179
|
+
THINKING_MODEL_PREFERENCES,
|
|
180
|
+
IMAGE_MODEL_PREFERENCES,
|
|
181
|
+
WEB_RESEARCH_MODEL_PREFERENCES,
|
|
158
182
|
selectDefaultModel,
|
|
159
183
|
getFastModel,
|
|
184
|
+
pickSimpleModeDefaults,
|
|
185
|
+
type SimpleModeModelSlot,
|
|
186
|
+
type SimpleModeDefaults,
|
|
160
187
|
} from "./lib/default-model";
|
|
161
188
|
|
|
162
189
|
// MCP OAuth utilities
|
|
@@ -196,7 +223,6 @@ export {
|
|
|
196
223
|
getWellKnownCommunityRegistryConnection,
|
|
197
224
|
getWellKnownSelfConnection,
|
|
198
225
|
getWellKnownDevAssetsConnection,
|
|
199
|
-
getWellKnownOpenRouterConnection,
|
|
200
226
|
getWellKnownMcpStudioConnection,
|
|
201
227
|
// Virtual MCP factory functions
|
|
202
228
|
getWellKnownDecopilotVirtualMCP,
|
|
@@ -204,4 +230,14 @@ export {
|
|
|
204
230
|
// Decopilot utilities
|
|
205
231
|
isDecopilot,
|
|
206
232
|
getDecopilotId,
|
|
233
|
+
// Site Diagnostics utilities
|
|
234
|
+
isSiteDiagnostics,
|
|
235
|
+
getSiteDiagnosticsId,
|
|
236
|
+
// Brand-Context Setup utilities
|
|
237
|
+
isBrandContextSetup,
|
|
238
|
+
getBrandContextSetupId,
|
|
239
|
+
getWellKnownBrandContextSetupVirtualMCP,
|
|
240
|
+
// Studio Pack utilities
|
|
241
|
+
StudioPackAgentId,
|
|
242
|
+
isStudioPackAgent,
|
|
207
243
|
} from "./lib/constants";
|