mcp-use 1.11.0-canary.11 → 1.11.0-canary.13
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/dist/.tsbuildinfo +1 -1
- package/dist/{chunk-DPK5NHDR.js → chunk-2RSYU23F.js} +1 -1
- package/dist/{chunk-CVKKDXI3.js → chunk-5OHAUR7E.js} +1 -1
- package/dist/{chunk-2NE5H4KG.js → chunk-6I4P5WXY.js} +1 -1
- package/dist/{chunk-V4YUDB7N.js → chunk-AQVGN2CI.js} +1 -1
- package/dist/{chunk-7P2EMREO.js → chunk-C5YF5MPR.js} +2 -2
- package/dist/{chunk-SQSJ5NKY.js → chunk-HPAS2BOZ.js} +4 -4
- package/dist/{chunk-BOCIQYWG.js → chunk-LHNWYWSI.js} +2 -2
- package/dist/{chunk-EHCLF3JO.js → chunk-P4TBZOPX.js} +2 -2
- package/dist/{chunk-BPZJIV4V.js → chunk-T7V3VOS2.js} +4 -4
- package/dist/{chunk-J3WTIYVV.js → chunk-TZKOAITC.js} +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +27 -27
- package/dist/src/agents/index.cjs +1 -1
- package/dist/src/agents/index.js +9 -9
- package/dist/src/agents/mcp_agent.d.ts.map +1 -1
- package/dist/src/browser.cjs +1 -1
- package/dist/src/browser.js +15 -15
- package/dist/src/client/prompts.js +4 -4
- package/dist/src/client.cjs +1 -1
- package/dist/src/client.js +5 -5
- package/dist/src/react/index.cjs +1 -1
- package/dist/src/react/index.js +8 -8
- package/dist/src/server/index.cjs +1 -1
- package/dist/src/server/index.js +5 -5
- package/dist/src/version.d.ts +1 -1
- package/dist/{tool-execution-helpers-3BYYGIA5.js → tool-execution-helpers-CBMJLW7M.js} +2 -2
- package/package.json +21 -24
- package/dist/chunk-4QWS5ME6.js +0 -1873
- package/dist/chunk-7PSUUT4A.js +0 -1055
- package/dist/chunk-T4EDAWDS.js +0 -2638
package/dist/chunk-4QWS5ME6.js
DELETED
|
@@ -1,1873 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
BrowserMCPClient
|
|
3
|
-
} from "./chunk-7P2EMREO.js";
|
|
4
|
-
import {
|
|
5
|
-
BrowserOAuthClientProvider,
|
|
6
|
-
sanitizeUrl
|
|
7
|
-
} from "./chunk-J75I2C26.js";
|
|
8
|
-
import {
|
|
9
|
-
Tel
|
|
10
|
-
} from "./chunk-J3WTIYVV.js";
|
|
11
|
-
import {
|
|
12
|
-
__name
|
|
13
|
-
} from "./chunk-3GQAWCBQ.js";
|
|
14
|
-
|
|
15
|
-
// src/react/useMcp.ts
|
|
16
|
-
import { useCallback, useEffect, useRef, useState } from "react";
|
|
17
|
-
|
|
18
|
-
// src/utils/assert.ts
|
|
19
|
-
function assert(condition, message) {
|
|
20
|
-
if (!condition) {
|
|
21
|
-
throw new Error(message);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
__name(assert, "assert");
|
|
25
|
-
|
|
26
|
-
// src/react/useMcp.ts
|
|
27
|
-
var DEFAULT_RECONNECT_DELAY = 3e3;
|
|
28
|
-
var DEFAULT_RETRY_DELAY = 5e3;
|
|
29
|
-
function useMcp(options) {
|
|
30
|
-
const {
|
|
31
|
-
url,
|
|
32
|
-
enabled = true,
|
|
33
|
-
clientName,
|
|
34
|
-
clientUri,
|
|
35
|
-
callbackUrl = typeof window !== "undefined" ? sanitizeUrl(
|
|
36
|
-
new URL("/oauth/callback", window.location.origin).toString()
|
|
37
|
-
) : "/oauth/callback",
|
|
38
|
-
storageKeyPrefix = "mcp:auth",
|
|
39
|
-
clientConfig = {},
|
|
40
|
-
customHeaders = {},
|
|
41
|
-
debug: _debug = false,
|
|
42
|
-
autoRetry = false,
|
|
43
|
-
autoReconnect = DEFAULT_RECONNECT_DELAY,
|
|
44
|
-
transportType = "auto",
|
|
45
|
-
preventAutoAuth = false,
|
|
46
|
-
// Default to false for backward compatibility (auto-trigger OAuth)
|
|
47
|
-
useRedirectFlow = false,
|
|
48
|
-
// Default to false for backward compatibility (use popup)
|
|
49
|
-
onPopupWindow,
|
|
50
|
-
timeout = 3e4,
|
|
51
|
-
// 30 seconds default for connection timeout
|
|
52
|
-
sseReadTimeout = 3e5,
|
|
53
|
-
// 5 minutes default for SSE read timeout
|
|
54
|
-
wrapTransport,
|
|
55
|
-
onNotification,
|
|
56
|
-
samplingCallback,
|
|
57
|
-
onElicitation
|
|
58
|
-
} = options;
|
|
59
|
-
const [state, setState] = useState("discovering");
|
|
60
|
-
const [tools, setTools] = useState([]);
|
|
61
|
-
const [resources, setResources] = useState([]);
|
|
62
|
-
const [resourceTemplates, setResourceTemplates] = useState([]);
|
|
63
|
-
const [prompts, setPrompts] = useState([]);
|
|
64
|
-
const [serverInfo, setServerInfo] = useState();
|
|
65
|
-
const [capabilities, setCapabilities] = useState();
|
|
66
|
-
const [error, setError] = useState(void 0);
|
|
67
|
-
const [log, setLog] = useState([]);
|
|
68
|
-
const [authUrl, setAuthUrl] = useState(void 0);
|
|
69
|
-
const clientRef = useRef(null);
|
|
70
|
-
const authProviderRef = useRef(null);
|
|
71
|
-
const connectingRef = useRef(false);
|
|
72
|
-
const isMountedRef = useRef(true);
|
|
73
|
-
const connectAttemptRef = useRef(0);
|
|
74
|
-
const authTimeoutRef = useRef(null);
|
|
75
|
-
const stateRef = useRef(state);
|
|
76
|
-
const autoReconnectRef = useRef(autoReconnect);
|
|
77
|
-
const successfulTransportRef = useRef(null);
|
|
78
|
-
useEffect(() => {
|
|
79
|
-
stateRef.current = state;
|
|
80
|
-
autoReconnectRef.current = autoReconnect;
|
|
81
|
-
}, [state, autoReconnect]);
|
|
82
|
-
const addLog = useCallback(
|
|
83
|
-
(level, message, ...args) => {
|
|
84
|
-
const fullMessage = args.length > 0 ? `${message} ${args.map((arg) => JSON.stringify(arg)).join(" ")}` : message;
|
|
85
|
-
console[level](`[useMcp] ${fullMessage}`);
|
|
86
|
-
if (isMountedRef.current) {
|
|
87
|
-
setLog((prevLog) => [
|
|
88
|
-
...prevLog.slice(-100),
|
|
89
|
-
{ level, message: fullMessage, timestamp: Date.now() }
|
|
90
|
-
]);
|
|
91
|
-
}
|
|
92
|
-
},
|
|
93
|
-
[]
|
|
94
|
-
);
|
|
95
|
-
const disconnect = useCallback(
|
|
96
|
-
async (quiet = false) => {
|
|
97
|
-
if (!quiet) addLog("info", "Disconnecting...");
|
|
98
|
-
connectingRef.current = false;
|
|
99
|
-
if (authTimeoutRef.current) clearTimeout(authTimeoutRef.current);
|
|
100
|
-
authTimeoutRef.current = null;
|
|
101
|
-
if (clientRef.current) {
|
|
102
|
-
try {
|
|
103
|
-
const serverName = "inspector-server";
|
|
104
|
-
const session = clientRef.current.getSession(serverName);
|
|
105
|
-
if (session && session._healthCheckCleanup) {
|
|
106
|
-
session._healthCheckCleanup();
|
|
107
|
-
session._healthCheckCleanup = null;
|
|
108
|
-
}
|
|
109
|
-
await clientRef.current.closeSession(serverName);
|
|
110
|
-
} catch (err) {
|
|
111
|
-
if (!quiet) addLog("warn", "Error closing session:", err);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
clientRef.current = null;
|
|
115
|
-
if (isMountedRef.current && !quiet) {
|
|
116
|
-
setState("discovering");
|
|
117
|
-
setTools([]);
|
|
118
|
-
setResources([]);
|
|
119
|
-
setResourceTemplates([]);
|
|
120
|
-
setPrompts([]);
|
|
121
|
-
setError(void 0);
|
|
122
|
-
setAuthUrl(void 0);
|
|
123
|
-
}
|
|
124
|
-
},
|
|
125
|
-
[addLog]
|
|
126
|
-
);
|
|
127
|
-
const failConnection = useCallback(
|
|
128
|
-
(errorMessage, connectionError) => {
|
|
129
|
-
addLog("error", errorMessage, connectionError ?? "");
|
|
130
|
-
if (isMountedRef.current) {
|
|
131
|
-
setState("failed");
|
|
132
|
-
setError(errorMessage);
|
|
133
|
-
const manualUrl = authProviderRef.current?.getLastAttemptedAuthUrl();
|
|
134
|
-
if (manualUrl) {
|
|
135
|
-
setAuthUrl(manualUrl);
|
|
136
|
-
addLog(
|
|
137
|
-
"info",
|
|
138
|
-
"Manual authentication URL may be available.",
|
|
139
|
-
manualUrl
|
|
140
|
-
);
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
connectingRef.current = false;
|
|
144
|
-
if (url) {
|
|
145
|
-
Tel.getInstance().trackUseMcpConnection({
|
|
146
|
-
url,
|
|
147
|
-
transportType,
|
|
148
|
-
success: false,
|
|
149
|
-
errorType: connectionError?.name || "UnknownError",
|
|
150
|
-
hasOAuth: !!authProviderRef.current,
|
|
151
|
-
hasSampling: !!samplingCallback,
|
|
152
|
-
hasElicitation: !!onElicitation
|
|
153
|
-
}).catch(() => {
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
},
|
|
157
|
-
[addLog, url, transportType, samplingCallback, onElicitation]
|
|
158
|
-
);
|
|
159
|
-
const connect = useCallback(async () => {
|
|
160
|
-
if (!enabled || !url) {
|
|
161
|
-
addLog(
|
|
162
|
-
"debug",
|
|
163
|
-
enabled ? "No server URL provided, skipping connection." : "Connection disabled via enabled flag."
|
|
164
|
-
);
|
|
165
|
-
return;
|
|
166
|
-
}
|
|
167
|
-
if (connectingRef.current) {
|
|
168
|
-
addLog("debug", "Connection attempt already in progress.");
|
|
169
|
-
return;
|
|
170
|
-
}
|
|
171
|
-
if (!isMountedRef.current) {
|
|
172
|
-
addLog("debug", "Connect called after unmount, aborting.");
|
|
173
|
-
return;
|
|
174
|
-
}
|
|
175
|
-
connectingRef.current = true;
|
|
176
|
-
connectAttemptRef.current += 1;
|
|
177
|
-
setError(void 0);
|
|
178
|
-
setAuthUrl(void 0);
|
|
179
|
-
successfulTransportRef.current = null;
|
|
180
|
-
setState("discovering");
|
|
181
|
-
addLog(
|
|
182
|
-
"info",
|
|
183
|
-
`Connecting attempt #${connectAttemptRef.current} to ${url}...`
|
|
184
|
-
);
|
|
185
|
-
if (!authProviderRef.current) {
|
|
186
|
-
authProviderRef.current = new BrowserOAuthClientProvider(url, {
|
|
187
|
-
storageKeyPrefix,
|
|
188
|
-
clientName,
|
|
189
|
-
clientUri,
|
|
190
|
-
callbackUrl,
|
|
191
|
-
preventAutoAuth,
|
|
192
|
-
useRedirectFlow,
|
|
193
|
-
onPopupWindow
|
|
194
|
-
});
|
|
195
|
-
addLog("debug", "BrowserOAuthClientProvider initialized in connect.");
|
|
196
|
-
}
|
|
197
|
-
if (!clientRef.current) {
|
|
198
|
-
clientRef.current = new BrowserMCPClient();
|
|
199
|
-
addLog("debug", "BrowserMCPClient initialized in connect.");
|
|
200
|
-
}
|
|
201
|
-
const tryConnectWithTransport = /* @__PURE__ */ __name(async (transportTypeParam, isAuthRetry = false) => {
|
|
202
|
-
addLog(
|
|
203
|
-
"info",
|
|
204
|
-
`Attempting connection with transport: ${transportTypeParam}`
|
|
205
|
-
);
|
|
206
|
-
try {
|
|
207
|
-
const serverName = "inspector-server";
|
|
208
|
-
const serverConfig = {
|
|
209
|
-
url,
|
|
210
|
-
transport: transportTypeParam === "sse" ? "http" : transportTypeParam
|
|
211
|
-
};
|
|
212
|
-
if (customHeaders && Object.keys(customHeaders).length > 0) {
|
|
213
|
-
serverConfig.headers = customHeaders;
|
|
214
|
-
}
|
|
215
|
-
if (authProviderRef.current) {
|
|
216
|
-
const tokens = await authProviderRef.current.tokens();
|
|
217
|
-
if (tokens?.access_token) {
|
|
218
|
-
serverConfig.headers = {
|
|
219
|
-
...serverConfig.headers,
|
|
220
|
-
Authorization: `Bearer ${tokens.access_token}`
|
|
221
|
-
};
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
clientRef.current.addServer(serverName, {
|
|
225
|
-
...serverConfig,
|
|
226
|
-
authProvider: authProviderRef.current,
|
|
227
|
-
// ← SDK handles OAuth automatically!
|
|
228
|
-
clientOptions: clientConfig,
|
|
229
|
-
// ← Pass client config to connector
|
|
230
|
-
samplingCallback,
|
|
231
|
-
// ← Pass sampling callback to connector
|
|
232
|
-
elicitationCallback: onElicitation,
|
|
233
|
-
// ← Pass elicitation callback to connector
|
|
234
|
-
wrapTransport: wrapTransport ? (transport) => {
|
|
235
|
-
console.log(
|
|
236
|
-
"[useMcp] Applying transport wrapper for server:",
|
|
237
|
-
serverName,
|
|
238
|
-
"url:",
|
|
239
|
-
url
|
|
240
|
-
);
|
|
241
|
-
return wrapTransport(transport, url);
|
|
242
|
-
} : void 0
|
|
243
|
-
});
|
|
244
|
-
const session = await clientRef.current.createSession(
|
|
245
|
-
serverName,
|
|
246
|
-
false
|
|
247
|
-
);
|
|
248
|
-
session.on("notification", (notification) => {
|
|
249
|
-
onNotification?.(notification);
|
|
250
|
-
if (notification.method === "notifications/tools/list_changed") {
|
|
251
|
-
addLog("info", "Tools list changed, auto-refreshing...");
|
|
252
|
-
refreshTools().catch(
|
|
253
|
-
(err) => addLog("warn", "Auto-refresh tools failed:", err)
|
|
254
|
-
);
|
|
255
|
-
} else if (notification.method === "notifications/resources/list_changed") {
|
|
256
|
-
addLog("info", "Resources list changed, auto-refreshing...");
|
|
257
|
-
refreshResources().catch(
|
|
258
|
-
(err) => addLog("warn", "Auto-refresh resources failed:", err)
|
|
259
|
-
);
|
|
260
|
-
} else if (notification.method === "notifications/prompts/list_changed") {
|
|
261
|
-
addLog("info", "Prompts list changed, auto-refreshing...");
|
|
262
|
-
refreshPrompts().catch(
|
|
263
|
-
(err) => addLog("warn", "Auto-refresh prompts failed:", err)
|
|
264
|
-
);
|
|
265
|
-
}
|
|
266
|
-
});
|
|
267
|
-
await session.initialize();
|
|
268
|
-
addLog("info", "\u2705 Successfully connected to MCP server");
|
|
269
|
-
addLog("info", "Server info:", session.connector.serverInfo);
|
|
270
|
-
addLog(
|
|
271
|
-
"info",
|
|
272
|
-
"Server capabilities:",
|
|
273
|
-
session.connector.serverCapabilities
|
|
274
|
-
);
|
|
275
|
-
console.log("[useMcp] Server info:", session.connector.serverInfo);
|
|
276
|
-
console.log(
|
|
277
|
-
"[useMcp] Server capabilities:",
|
|
278
|
-
session.connector.serverCapabilities
|
|
279
|
-
);
|
|
280
|
-
setState("ready");
|
|
281
|
-
successfulTransportRef.current = transportTypeParam;
|
|
282
|
-
const setupConnectionMonitoring = /* @__PURE__ */ __name(() => {
|
|
283
|
-
let healthCheckInterval = null;
|
|
284
|
-
let lastSuccessfulCheck = Date.now();
|
|
285
|
-
const HEALTH_CHECK_INTERVAL = 1e4;
|
|
286
|
-
const HEALTH_CHECK_TIMEOUT = 3e4;
|
|
287
|
-
const checkConnectionHealth = /* @__PURE__ */ __name(async () => {
|
|
288
|
-
if (!isMountedRef.current || stateRef.current !== "ready") {
|
|
289
|
-
if (healthCheckInterval) {
|
|
290
|
-
clearInterval(healthCheckInterval);
|
|
291
|
-
healthCheckInterval = null;
|
|
292
|
-
}
|
|
293
|
-
return;
|
|
294
|
-
}
|
|
295
|
-
try {
|
|
296
|
-
await session.connector.listTools();
|
|
297
|
-
lastSuccessfulCheck = Date.now();
|
|
298
|
-
} catch (err) {
|
|
299
|
-
const timeSinceLastSuccess = Date.now() - lastSuccessfulCheck;
|
|
300
|
-
if (timeSinceLastSuccess > HEALTH_CHECK_TIMEOUT) {
|
|
301
|
-
addLog(
|
|
302
|
-
"warn",
|
|
303
|
-
`Connection appears to be broken (no response for ${Math.round(timeSinceLastSuccess / 1e3)}s), attempting to reconnect...`
|
|
304
|
-
);
|
|
305
|
-
if (healthCheckInterval) {
|
|
306
|
-
clearInterval(healthCheckInterval);
|
|
307
|
-
healthCheckInterval = null;
|
|
308
|
-
}
|
|
309
|
-
if (autoReconnectRef.current && isMountedRef.current) {
|
|
310
|
-
setState("discovering");
|
|
311
|
-
addLog("info", "Auto-reconnecting to MCP server...");
|
|
312
|
-
setTimeout(
|
|
313
|
-
() => {
|
|
314
|
-
if (isMountedRef.current && stateRef.current === "discovering") {
|
|
315
|
-
connect();
|
|
316
|
-
}
|
|
317
|
-
},
|
|
318
|
-
typeof autoReconnectRef.current === "number" ? autoReconnectRef.current : DEFAULT_RECONNECT_DELAY
|
|
319
|
-
);
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
}, "checkConnectionHealth");
|
|
324
|
-
healthCheckInterval = setInterval(
|
|
325
|
-
checkConnectionHealth,
|
|
326
|
-
HEALTH_CHECK_INTERVAL
|
|
327
|
-
);
|
|
328
|
-
return () => {
|
|
329
|
-
if (healthCheckInterval) {
|
|
330
|
-
clearInterval(healthCheckInterval);
|
|
331
|
-
healthCheckInterval = null;
|
|
332
|
-
}
|
|
333
|
-
};
|
|
334
|
-
}, "setupConnectionMonitoring");
|
|
335
|
-
if (autoReconnect) {
|
|
336
|
-
const cleanup = setupConnectionMonitoring();
|
|
337
|
-
session._healthCheckCleanup = cleanup;
|
|
338
|
-
}
|
|
339
|
-
Tel.getInstance().trackUseMcpConnection({
|
|
340
|
-
url,
|
|
341
|
-
transportType: transportTypeParam,
|
|
342
|
-
success: true,
|
|
343
|
-
hasOAuth: !!authProviderRef.current,
|
|
344
|
-
hasSampling: !!samplingCallback,
|
|
345
|
-
hasElicitation: !!onElicitation
|
|
346
|
-
}).catch(() => {
|
|
347
|
-
});
|
|
348
|
-
setTools(session.connector.tools || []);
|
|
349
|
-
const resourcesResult = await session.connector.listAllResources();
|
|
350
|
-
setResources(resourcesResult.resources || []);
|
|
351
|
-
const promptsResult = await session.connector.listPrompts();
|
|
352
|
-
setPrompts(promptsResult.prompts || []);
|
|
353
|
-
const serverInfo2 = session.connector.serverInfo;
|
|
354
|
-
const capabilities2 = session.connector.serverCapabilities;
|
|
355
|
-
if (serverInfo2) {
|
|
356
|
-
console.log("[useMcp] Server info:", serverInfo2);
|
|
357
|
-
setServerInfo(serverInfo2);
|
|
358
|
-
}
|
|
359
|
-
if (capabilities2) {
|
|
360
|
-
console.log("[useMcp] Server capabilities:", capabilities2);
|
|
361
|
-
setCapabilities(capabilities2);
|
|
362
|
-
}
|
|
363
|
-
return "success";
|
|
364
|
-
} catch (err) {
|
|
365
|
-
const error2 = err;
|
|
366
|
-
const errorMessage = error2?.message || String(err);
|
|
367
|
-
if (error2.code === 401 || errorMessage.includes("401") || errorMessage.includes("Unauthorized")) {
|
|
368
|
-
if (authProviderRef.current) {
|
|
369
|
-
addLog(
|
|
370
|
-
"info",
|
|
371
|
-
"Authentication required. OAuth provider available."
|
|
372
|
-
);
|
|
373
|
-
try {
|
|
374
|
-
const { auth } = await import("@mcp-use/modelcontextprotocol-sdk/client/auth.js");
|
|
375
|
-
const baseUrl = new URL(url).origin;
|
|
376
|
-
auth(authProviderRef.current, { serverUrl: baseUrl }).catch(
|
|
377
|
-
() => {
|
|
378
|
-
}
|
|
379
|
-
);
|
|
380
|
-
setTimeout(() => {
|
|
381
|
-
if (isMountedRef.current) {
|
|
382
|
-
const manualUrl = authProviderRef.current?.getLastAttemptedAuthUrl();
|
|
383
|
-
if (manualUrl) {
|
|
384
|
-
setAuthUrl(manualUrl);
|
|
385
|
-
addLog(
|
|
386
|
-
"info",
|
|
387
|
-
"Manual authentication URL available:",
|
|
388
|
-
manualUrl
|
|
389
|
-
);
|
|
390
|
-
} else {
|
|
391
|
-
addLog("warn", "Could not generate authentication URL");
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
}, 100);
|
|
395
|
-
} catch (authGenError) {
|
|
396
|
-
addLog("warn", "Error generating auth URL:", authGenError);
|
|
397
|
-
}
|
|
398
|
-
if (isMountedRef.current) {
|
|
399
|
-
setState("pending_auth");
|
|
400
|
-
}
|
|
401
|
-
connectingRef.current = false;
|
|
402
|
-
return "auth_redirect";
|
|
403
|
-
}
|
|
404
|
-
if (customHeaders && Object.keys(customHeaders).length > 0) {
|
|
405
|
-
failConnection(
|
|
406
|
-
"Authentication failed: Server returned 401 Unauthorized. Check your Authorization header value is correct."
|
|
407
|
-
);
|
|
408
|
-
return "failed";
|
|
409
|
-
}
|
|
410
|
-
failConnection(
|
|
411
|
-
"Authentication required: Server returned 401 Unauthorized. Add an Authorization header in the Custom Headers section (e.g., Authorization: Bearer YOUR_API_KEY)."
|
|
412
|
-
);
|
|
413
|
-
return "failed";
|
|
414
|
-
}
|
|
415
|
-
failConnection(
|
|
416
|
-
errorMessage,
|
|
417
|
-
error2 instanceof Error ? error2 : new Error(String(error2))
|
|
418
|
-
);
|
|
419
|
-
return "failed";
|
|
420
|
-
}
|
|
421
|
-
}, "tryConnectWithTransport");
|
|
422
|
-
let finalStatus = "failed";
|
|
423
|
-
if (transportType === "sse") {
|
|
424
|
-
addLog("debug", "Using SSE-only transport mode");
|
|
425
|
-
finalStatus = await tryConnectWithTransport("sse");
|
|
426
|
-
} else if (transportType === "http") {
|
|
427
|
-
addLog("debug", "Using HTTP-only transport mode");
|
|
428
|
-
finalStatus = await tryConnectWithTransport("http");
|
|
429
|
-
} else {
|
|
430
|
-
addLog("debug", "Using auto transport mode (HTTP with SSE fallback)");
|
|
431
|
-
const httpResult = await tryConnectWithTransport("http");
|
|
432
|
-
if (httpResult === "fallback" && isMountedRef.current && stateRef.current !== "authenticating") {
|
|
433
|
-
addLog("info", "HTTP failed, attempting SSE fallback...");
|
|
434
|
-
const sseResult = await tryConnectWithTransport("sse");
|
|
435
|
-
finalStatus = sseResult;
|
|
436
|
-
} else {
|
|
437
|
-
finalStatus = httpResult;
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
if (finalStatus === "success" || finalStatus === "failed" || finalStatus === "auth_redirect") {
|
|
441
|
-
connectingRef.current = false;
|
|
442
|
-
}
|
|
443
|
-
addLog("debug", `Connection sequence finished with status: ${finalStatus}`);
|
|
444
|
-
}, [
|
|
445
|
-
addLog,
|
|
446
|
-
failConnection,
|
|
447
|
-
disconnect,
|
|
448
|
-
url,
|
|
449
|
-
storageKeyPrefix,
|
|
450
|
-
clientName,
|
|
451
|
-
clientUri,
|
|
452
|
-
callbackUrl,
|
|
453
|
-
clientConfig.name,
|
|
454
|
-
clientConfig.version,
|
|
455
|
-
customHeaders,
|
|
456
|
-
transportType,
|
|
457
|
-
preventAutoAuth,
|
|
458
|
-
useRedirectFlow,
|
|
459
|
-
onPopupWindow,
|
|
460
|
-
enabled,
|
|
461
|
-
timeout,
|
|
462
|
-
sseReadTimeout
|
|
463
|
-
]);
|
|
464
|
-
const callTool = useCallback(
|
|
465
|
-
async (name, args, options2) => {
|
|
466
|
-
if (stateRef.current !== "ready" || !clientRef.current) {
|
|
467
|
-
throw new Error(
|
|
468
|
-
`MCP client is not ready (current state: ${state}). Cannot call tool "${name}".`
|
|
469
|
-
);
|
|
470
|
-
}
|
|
471
|
-
addLog("info", `Calling tool: ${name}`, args);
|
|
472
|
-
const startTime = Date.now();
|
|
473
|
-
try {
|
|
474
|
-
const serverName = "inspector-server";
|
|
475
|
-
const session = clientRef.current.getSession(serverName);
|
|
476
|
-
if (!session) {
|
|
477
|
-
throw new Error("No active session found");
|
|
478
|
-
}
|
|
479
|
-
const result = await session.connector.callTool(
|
|
480
|
-
name,
|
|
481
|
-
args || {},
|
|
482
|
-
options2
|
|
483
|
-
);
|
|
484
|
-
addLog("info", `Tool "${name}" call successful:`, result);
|
|
485
|
-
Tel.getInstance().trackUseMcpToolCall({
|
|
486
|
-
toolName: name,
|
|
487
|
-
success: true,
|
|
488
|
-
executionTimeMs: Date.now() - startTime
|
|
489
|
-
}).catch(() => {
|
|
490
|
-
});
|
|
491
|
-
return result;
|
|
492
|
-
} catch (err) {
|
|
493
|
-
addLog("error", `Tool "${name}" call failed:`, err);
|
|
494
|
-
Tel.getInstance().trackUseMcpToolCall({
|
|
495
|
-
toolName: name,
|
|
496
|
-
success: false,
|
|
497
|
-
errorType: err instanceof Error ? err.name : "UnknownError",
|
|
498
|
-
executionTimeMs: Date.now() - startTime
|
|
499
|
-
}).catch(() => {
|
|
500
|
-
});
|
|
501
|
-
throw err;
|
|
502
|
-
}
|
|
503
|
-
},
|
|
504
|
-
[state]
|
|
505
|
-
);
|
|
506
|
-
const retry = useCallback(() => {
|
|
507
|
-
if (stateRef.current === "failed") {
|
|
508
|
-
addLog("info", "Retry requested...");
|
|
509
|
-
connect();
|
|
510
|
-
} else {
|
|
511
|
-
addLog(
|
|
512
|
-
"warn",
|
|
513
|
-
`Retry called but state is not 'failed' (state: ${stateRef.current}). Ignoring.`
|
|
514
|
-
);
|
|
515
|
-
}
|
|
516
|
-
}, [addLog, connect]);
|
|
517
|
-
const authenticate = useCallback(async () => {
|
|
518
|
-
addLog("info", "Manual authentication requested...");
|
|
519
|
-
const currentState = stateRef.current;
|
|
520
|
-
if (currentState === "failed") {
|
|
521
|
-
addLog("info", "Attempting to reconnect and authenticate via retry...");
|
|
522
|
-
retry();
|
|
523
|
-
} else if (currentState === "pending_auth") {
|
|
524
|
-
addLog("info", "Proceeding with authentication from pending state...");
|
|
525
|
-
try {
|
|
526
|
-
assert(
|
|
527
|
-
authProviderRef.current,
|
|
528
|
-
"Auth Provider not available for manual auth"
|
|
529
|
-
);
|
|
530
|
-
assert(url, "Server URL is required for authentication");
|
|
531
|
-
addLog("info", "Clearing all OAuth state and initiating fresh flow...");
|
|
532
|
-
const hashPrefix = `${storageKeyPrefix}:${authProviderRef.current.serverUrlHash}`;
|
|
533
|
-
Object.keys(localStorage).forEach((key) => {
|
|
534
|
-
if (key.startsWith(hashPrefix)) {
|
|
535
|
-
addLog("debug", `Removing stale OAuth key: ${key}`);
|
|
536
|
-
localStorage.removeItem(key);
|
|
537
|
-
}
|
|
538
|
-
if (key.startsWith(`${storageKeyPrefix}:state_`)) {
|
|
539
|
-
addLog("debug", `Removing orphaned state: ${key}`);
|
|
540
|
-
localStorage.removeItem(key);
|
|
541
|
-
}
|
|
542
|
-
});
|
|
543
|
-
setState("authenticating");
|
|
544
|
-
const freshAuthProvider = new BrowserOAuthClientProvider(url, {
|
|
545
|
-
storageKeyPrefix,
|
|
546
|
-
clientName,
|
|
547
|
-
clientUri,
|
|
548
|
-
callbackUrl,
|
|
549
|
-
preventAutoAuth: false,
|
|
550
|
-
// ← Allow OAuth to proceed
|
|
551
|
-
useRedirectFlow,
|
|
552
|
-
onPopupWindow
|
|
553
|
-
});
|
|
554
|
-
authProviderRef.current = freshAuthProvider;
|
|
555
|
-
addLog("info", "Triggering fresh OAuth authorization...");
|
|
556
|
-
const { auth } = await import("@mcp-use/modelcontextprotocol-sdk/client/auth.js");
|
|
557
|
-
const baseUrl = new URL(url).origin;
|
|
558
|
-
auth(freshAuthProvider, {
|
|
559
|
-
serverUrl: baseUrl
|
|
560
|
-
}).catch((err) => {
|
|
561
|
-
addLog(
|
|
562
|
-
"info",
|
|
563
|
-
"OAuth flow initiated:",
|
|
564
|
-
err instanceof Error ? err.message : "Redirecting..."
|
|
565
|
-
);
|
|
566
|
-
});
|
|
567
|
-
} catch (authError) {
|
|
568
|
-
if (!isMountedRef.current) return;
|
|
569
|
-
setState("pending_auth");
|
|
570
|
-
addLog(
|
|
571
|
-
"error",
|
|
572
|
-
`Manual authentication failed: ${authError instanceof Error ? authError.message : String(authError)}`
|
|
573
|
-
);
|
|
574
|
-
}
|
|
575
|
-
} else if (currentState === "authenticating") {
|
|
576
|
-
addLog(
|
|
577
|
-
"warn",
|
|
578
|
-
"Already attempting authentication. Check for blocked popups or wait for timeout."
|
|
579
|
-
);
|
|
580
|
-
const manualUrl = authProviderRef.current?.getLastAttemptedAuthUrl();
|
|
581
|
-
if (manualUrl && !authUrl) {
|
|
582
|
-
setAuthUrl(manualUrl);
|
|
583
|
-
addLog("info", "Manual authentication URL retrieved:", manualUrl);
|
|
584
|
-
}
|
|
585
|
-
} else {
|
|
586
|
-
addLog(
|
|
587
|
-
"info",
|
|
588
|
-
`Client not in a state requiring manual authentication trigger (state: ${currentState}). If needed, try disconnecting and reconnecting.`
|
|
589
|
-
);
|
|
590
|
-
}
|
|
591
|
-
}, [
|
|
592
|
-
addLog,
|
|
593
|
-
retry,
|
|
594
|
-
authUrl,
|
|
595
|
-
url,
|
|
596
|
-
useRedirectFlow,
|
|
597
|
-
onPopupWindow,
|
|
598
|
-
storageKeyPrefix,
|
|
599
|
-
clientName,
|
|
600
|
-
clientUri,
|
|
601
|
-
callbackUrl
|
|
602
|
-
]);
|
|
603
|
-
const clearStorage = useCallback(() => {
|
|
604
|
-
if (authProviderRef.current) {
|
|
605
|
-
const count = authProviderRef.current.clearStorage();
|
|
606
|
-
addLog("info", `Cleared ${count} item(s) from localStorage for ${url}.`);
|
|
607
|
-
setAuthUrl(void 0);
|
|
608
|
-
disconnect();
|
|
609
|
-
} else {
|
|
610
|
-
addLog("warn", "Auth provider not initialized, cannot clear storage.");
|
|
611
|
-
}
|
|
612
|
-
}, [url, addLog, disconnect]);
|
|
613
|
-
const listResources = useCallback(async () => {
|
|
614
|
-
if (stateRef.current !== "ready" || !clientRef.current) {
|
|
615
|
-
throw new Error(
|
|
616
|
-
`MCP client is not ready (current state: ${state}). Cannot list resources.`
|
|
617
|
-
);
|
|
618
|
-
}
|
|
619
|
-
addLog("info", "Listing resources");
|
|
620
|
-
try {
|
|
621
|
-
const serverName = "inspector-server";
|
|
622
|
-
const session = clientRef.current.getSession(serverName);
|
|
623
|
-
if (!session) {
|
|
624
|
-
throw new Error("No active session found");
|
|
625
|
-
}
|
|
626
|
-
const resourcesResult = await session.connector.listAllResources();
|
|
627
|
-
setResources(resourcesResult.resources || []);
|
|
628
|
-
addLog("info", "Resources listed successfully");
|
|
629
|
-
} catch (err) {
|
|
630
|
-
addLog("error", "List resources failed:", err);
|
|
631
|
-
throw err;
|
|
632
|
-
}
|
|
633
|
-
}, [state]);
|
|
634
|
-
const readResource = useCallback(
|
|
635
|
-
async (uri) => {
|
|
636
|
-
if (stateRef.current !== "ready" || !clientRef.current) {
|
|
637
|
-
throw new Error(
|
|
638
|
-
`MCP client is not ready (current state: ${state}). Cannot read resource.`
|
|
639
|
-
);
|
|
640
|
-
}
|
|
641
|
-
addLog("info", `Reading resource: ${uri}`);
|
|
642
|
-
try {
|
|
643
|
-
const serverName = "inspector-server";
|
|
644
|
-
const session = clientRef.current.getSession(serverName);
|
|
645
|
-
if (!session) {
|
|
646
|
-
throw new Error("No active session found");
|
|
647
|
-
}
|
|
648
|
-
const result = await session.connector.readResource(uri);
|
|
649
|
-
addLog("info", "Resource read successful:", result);
|
|
650
|
-
Tel.getInstance().trackUseMcpResourceRead({
|
|
651
|
-
resourceUri: uri,
|
|
652
|
-
success: true
|
|
653
|
-
}).catch(() => {
|
|
654
|
-
});
|
|
655
|
-
return result;
|
|
656
|
-
} catch (err) {
|
|
657
|
-
addLog("error", "Resource read failed:", err);
|
|
658
|
-
Tel.getInstance().trackUseMcpResourceRead({
|
|
659
|
-
resourceUri: uri,
|
|
660
|
-
success: false,
|
|
661
|
-
errorType: err instanceof Error ? err.name : "UnknownError"
|
|
662
|
-
}).catch(() => {
|
|
663
|
-
});
|
|
664
|
-
throw err;
|
|
665
|
-
}
|
|
666
|
-
},
|
|
667
|
-
[state]
|
|
668
|
-
);
|
|
669
|
-
const listPrompts = useCallback(async () => {
|
|
670
|
-
if (stateRef.current !== "ready" || !clientRef.current) {
|
|
671
|
-
throw new Error(
|
|
672
|
-
`MCP client is not ready (current state: ${state}). Cannot list prompts.`
|
|
673
|
-
);
|
|
674
|
-
}
|
|
675
|
-
addLog("info", "Listing prompts");
|
|
676
|
-
try {
|
|
677
|
-
const serverName = "inspector-server";
|
|
678
|
-
const session = clientRef.current.getSession(serverName);
|
|
679
|
-
if (!session) {
|
|
680
|
-
throw new Error("No active session found");
|
|
681
|
-
}
|
|
682
|
-
const promptsResult = await session.connector.listPrompts();
|
|
683
|
-
setPrompts(promptsResult.prompts || []);
|
|
684
|
-
addLog("info", "Prompts listed successfully");
|
|
685
|
-
} catch (err) {
|
|
686
|
-
addLog("error", "List prompts failed:", err);
|
|
687
|
-
throw err;
|
|
688
|
-
}
|
|
689
|
-
}, [state]);
|
|
690
|
-
const refreshTools = useCallback(async () => {
|
|
691
|
-
if (stateRef.current !== "ready" || !clientRef.current) {
|
|
692
|
-
addLog("debug", "Cannot refresh tools - client not ready");
|
|
693
|
-
return;
|
|
694
|
-
}
|
|
695
|
-
addLog("debug", "Refreshing tools list");
|
|
696
|
-
try {
|
|
697
|
-
const serverName = "inspector-server";
|
|
698
|
-
const session = clientRef.current.getSession(serverName);
|
|
699
|
-
if (!session) {
|
|
700
|
-
addLog("warn", "No active session found for tools refresh");
|
|
701
|
-
return;
|
|
702
|
-
}
|
|
703
|
-
const toolsResult = await session.connector.listTools();
|
|
704
|
-
setTools(toolsResult || []);
|
|
705
|
-
addLog("info", "Tools list refreshed successfully");
|
|
706
|
-
} catch (err) {
|
|
707
|
-
addLog("warn", "Failed to refresh tools:", err);
|
|
708
|
-
}
|
|
709
|
-
}, [addLog]);
|
|
710
|
-
const refreshResources = useCallback(async () => {
|
|
711
|
-
if (stateRef.current !== "ready" || !clientRef.current) {
|
|
712
|
-
addLog("debug", "Cannot refresh resources - client not ready");
|
|
713
|
-
return;
|
|
714
|
-
}
|
|
715
|
-
addLog("debug", "Refreshing resources list");
|
|
716
|
-
try {
|
|
717
|
-
const serverName = "inspector-server";
|
|
718
|
-
const session = clientRef.current.getSession(serverName);
|
|
719
|
-
if (!session) {
|
|
720
|
-
addLog("warn", "No active session found for resources refresh");
|
|
721
|
-
return;
|
|
722
|
-
}
|
|
723
|
-
const resourcesResult = await session.connector.listAllResources();
|
|
724
|
-
setResources(resourcesResult.resources || []);
|
|
725
|
-
addLog("info", "Resources list refreshed successfully");
|
|
726
|
-
} catch (err) {
|
|
727
|
-
addLog("warn", "Failed to refresh resources:", err);
|
|
728
|
-
}
|
|
729
|
-
}, [addLog]);
|
|
730
|
-
const refreshPrompts = useCallback(async () => {
|
|
731
|
-
if (stateRef.current !== "ready" || !clientRef.current) {
|
|
732
|
-
addLog("debug", "Cannot refresh prompts - client not ready");
|
|
733
|
-
return;
|
|
734
|
-
}
|
|
735
|
-
addLog("debug", "Refreshing prompts list");
|
|
736
|
-
try {
|
|
737
|
-
const serverName = "inspector-server";
|
|
738
|
-
const session = clientRef.current.getSession(serverName);
|
|
739
|
-
if (!session) {
|
|
740
|
-
addLog("warn", "No active session found for prompts refresh");
|
|
741
|
-
return;
|
|
742
|
-
}
|
|
743
|
-
const promptsResult = await session.connector.listPrompts();
|
|
744
|
-
setPrompts(promptsResult.prompts || []);
|
|
745
|
-
addLog("info", "Prompts list refreshed successfully");
|
|
746
|
-
} catch (err) {
|
|
747
|
-
addLog("warn", "Failed to refresh prompts:", err);
|
|
748
|
-
}
|
|
749
|
-
}, [addLog]);
|
|
750
|
-
const refreshAll = useCallback(async () => {
|
|
751
|
-
addLog("info", "Refreshing all lists (tools, resources, prompts)");
|
|
752
|
-
await Promise.all([refreshTools(), refreshResources(), refreshPrompts()]);
|
|
753
|
-
}, [refreshTools, refreshResources, refreshPrompts, addLog]);
|
|
754
|
-
const getPrompt = useCallback(
|
|
755
|
-
async (name, args) => {
|
|
756
|
-
if (stateRef.current !== "ready" || !clientRef.current) {
|
|
757
|
-
throw new Error(
|
|
758
|
-
`MCP client is not ready (current state: ${state}). Cannot get prompt.`
|
|
759
|
-
);
|
|
760
|
-
}
|
|
761
|
-
addLog("info", `Getting prompt: ${name}`, args);
|
|
762
|
-
try {
|
|
763
|
-
const serverName = "inspector-server";
|
|
764
|
-
const session = clientRef.current.getSession(serverName);
|
|
765
|
-
if (!session) {
|
|
766
|
-
throw new Error("No active session found");
|
|
767
|
-
}
|
|
768
|
-
const result = await session.connector.getPrompt(name, args || {});
|
|
769
|
-
addLog("info", `Prompt "${name}" retrieved successfully:`, result);
|
|
770
|
-
return result;
|
|
771
|
-
} catch (err) {
|
|
772
|
-
addLog("error", `Prompt "${name}" retrieval failed:`, err);
|
|
773
|
-
throw err;
|
|
774
|
-
}
|
|
775
|
-
},
|
|
776
|
-
[state]
|
|
777
|
-
);
|
|
778
|
-
const connectRef = useRef(connect);
|
|
779
|
-
const failConnectionRef = useRef(failConnection);
|
|
780
|
-
useEffect(() => {
|
|
781
|
-
connectRef.current = connect;
|
|
782
|
-
failConnectionRef.current = failConnection;
|
|
783
|
-
});
|
|
784
|
-
useEffect(() => {
|
|
785
|
-
const messageHandler = /* @__PURE__ */ __name((event) => {
|
|
786
|
-
if (event.origin !== window.location.origin) return;
|
|
787
|
-
if (event.data?.type === "mcp_auth_callback") {
|
|
788
|
-
addLog("info", "Received auth callback message.", event.data);
|
|
789
|
-
if (authTimeoutRef.current) clearTimeout(authTimeoutRef.current);
|
|
790
|
-
authTimeoutRef.current = null;
|
|
791
|
-
if (event.data.success) {
|
|
792
|
-
addLog(
|
|
793
|
-
"info",
|
|
794
|
-
"Authentication successful via popup. Reconnecting client..."
|
|
795
|
-
);
|
|
796
|
-
if (connectingRef.current) {
|
|
797
|
-
addLog(
|
|
798
|
-
"debug",
|
|
799
|
-
"Connection attempt already in progress, resetting flag to allow reconnection."
|
|
800
|
-
);
|
|
801
|
-
}
|
|
802
|
-
connectingRef.current = false;
|
|
803
|
-
setTimeout(() => {
|
|
804
|
-
if (isMountedRef.current) {
|
|
805
|
-
addLog(
|
|
806
|
-
"debug",
|
|
807
|
-
"Initiating reconnection after successful auth callback."
|
|
808
|
-
);
|
|
809
|
-
connectRef.current();
|
|
810
|
-
}
|
|
811
|
-
}, 100);
|
|
812
|
-
} else {
|
|
813
|
-
failConnectionRef.current(
|
|
814
|
-
`Authentication failed in callback: ${event.data.error || "Unknown reason."}`
|
|
815
|
-
);
|
|
816
|
-
}
|
|
817
|
-
}
|
|
818
|
-
}, "messageHandler");
|
|
819
|
-
window.addEventListener("message", messageHandler);
|
|
820
|
-
addLog("debug", "Auth callback message listener added.");
|
|
821
|
-
return () => {
|
|
822
|
-
window.removeEventListener("message", messageHandler);
|
|
823
|
-
addLog("debug", "Auth callback message listener removed.");
|
|
824
|
-
if (authTimeoutRef.current) clearTimeout(authTimeoutRef.current);
|
|
825
|
-
};
|
|
826
|
-
}, [addLog]);
|
|
827
|
-
useEffect(() => {
|
|
828
|
-
isMountedRef.current = true;
|
|
829
|
-
if (!enabled || !url) {
|
|
830
|
-
addLog(
|
|
831
|
-
"debug",
|
|
832
|
-
enabled ? "No server URL provided, skipping connection." : "Connection disabled via enabled flag."
|
|
833
|
-
);
|
|
834
|
-
setState("discovering");
|
|
835
|
-
return () => {
|
|
836
|
-
isMountedRef.current = false;
|
|
837
|
-
};
|
|
838
|
-
}
|
|
839
|
-
addLog("debug", "useMcp mounted, initiating connection.");
|
|
840
|
-
connectAttemptRef.current = 0;
|
|
841
|
-
if (!authProviderRef.current || authProviderRef.current.serverUrl !== url) {
|
|
842
|
-
authProviderRef.current = new BrowserOAuthClientProvider(url, {
|
|
843
|
-
storageKeyPrefix,
|
|
844
|
-
clientName,
|
|
845
|
-
clientUri,
|
|
846
|
-
callbackUrl,
|
|
847
|
-
preventAutoAuth,
|
|
848
|
-
useRedirectFlow,
|
|
849
|
-
onPopupWindow
|
|
850
|
-
});
|
|
851
|
-
addLog(
|
|
852
|
-
"debug",
|
|
853
|
-
"BrowserOAuthClientProvider initialized/updated on mount/option change."
|
|
854
|
-
);
|
|
855
|
-
}
|
|
856
|
-
connect();
|
|
857
|
-
return () => {
|
|
858
|
-
isMountedRef.current = false;
|
|
859
|
-
addLog("debug", "useMcp unmounting, disconnecting.");
|
|
860
|
-
disconnect(true);
|
|
861
|
-
};
|
|
862
|
-
}, [
|
|
863
|
-
url,
|
|
864
|
-
enabled,
|
|
865
|
-
storageKeyPrefix,
|
|
866
|
-
callbackUrl,
|
|
867
|
-
clientName,
|
|
868
|
-
clientUri,
|
|
869
|
-
clientConfig.name,
|
|
870
|
-
clientConfig.version,
|
|
871
|
-
useRedirectFlow
|
|
872
|
-
]);
|
|
873
|
-
useEffect(() => {
|
|
874
|
-
let retryTimeoutId = null;
|
|
875
|
-
if (state === "failed" && autoRetry && connectAttemptRef.current > 0) {
|
|
876
|
-
const delay = typeof autoRetry === "number" ? autoRetry : DEFAULT_RETRY_DELAY;
|
|
877
|
-
addLog("info", `Connection failed, auto-retrying in ${delay}ms...`);
|
|
878
|
-
retryTimeoutId = setTimeout(() => {
|
|
879
|
-
if (isMountedRef.current && stateRef.current === "failed") {
|
|
880
|
-
retry();
|
|
881
|
-
}
|
|
882
|
-
}, delay);
|
|
883
|
-
}
|
|
884
|
-
return () => {
|
|
885
|
-
if (retryTimeoutId) clearTimeout(retryTimeoutId);
|
|
886
|
-
};
|
|
887
|
-
}, [state, autoRetry, retry, addLog]);
|
|
888
|
-
return {
|
|
889
|
-
state,
|
|
890
|
-
tools,
|
|
891
|
-
resources,
|
|
892
|
-
resourceTemplates,
|
|
893
|
-
prompts,
|
|
894
|
-
serverInfo,
|
|
895
|
-
capabilities,
|
|
896
|
-
error,
|
|
897
|
-
log,
|
|
898
|
-
authUrl,
|
|
899
|
-
client: clientRef.current,
|
|
900
|
-
callTool,
|
|
901
|
-
readResource,
|
|
902
|
-
listResources,
|
|
903
|
-
listPrompts,
|
|
904
|
-
getPrompt,
|
|
905
|
-
refreshTools,
|
|
906
|
-
refreshResources,
|
|
907
|
-
refreshPrompts,
|
|
908
|
-
refreshAll,
|
|
909
|
-
retry,
|
|
910
|
-
disconnect,
|
|
911
|
-
authenticate,
|
|
912
|
-
clearStorage
|
|
913
|
-
};
|
|
914
|
-
}
|
|
915
|
-
__name(useMcp, "useMcp");
|
|
916
|
-
|
|
917
|
-
// src/react/ErrorBoundary.tsx
|
|
918
|
-
import React from "react";
|
|
919
|
-
var ErrorBoundary = class extends React.Component {
|
|
920
|
-
static {
|
|
921
|
-
__name(this, "ErrorBoundary");
|
|
922
|
-
}
|
|
923
|
-
constructor(props) {
|
|
924
|
-
super(props);
|
|
925
|
-
this.state = { hasError: false, error: null };
|
|
926
|
-
}
|
|
927
|
-
static getDerivedStateFromError(error) {
|
|
928
|
-
return { hasError: true, error };
|
|
929
|
-
}
|
|
930
|
-
componentDidCatch(error, errorInfo) {
|
|
931
|
-
console.error("Widget Error:", error, errorInfo);
|
|
932
|
-
}
|
|
933
|
-
render() {
|
|
934
|
-
if (this.state.hasError) {
|
|
935
|
-
return /* @__PURE__ */ React.createElement("div", { className: "p-4 border border-red-500 bg-red-50 text-red-900 rounded-md dark:bg-red-900/20 dark:text-red-100" }, /* @__PURE__ */ React.createElement("h3", { className: "font-bold mb-2" }, "Widget Error"), /* @__PURE__ */ React.createElement("pre", { className: "text-sm whitespace-pre-wrap" }, this.state.error?.message));
|
|
936
|
-
}
|
|
937
|
-
return this.props.children;
|
|
938
|
-
}
|
|
939
|
-
};
|
|
940
|
-
|
|
941
|
-
// src/react/Image.tsx
|
|
942
|
-
import React2 from "react";
|
|
943
|
-
var Image = /* @__PURE__ */ __name(({ src, ...props }) => {
|
|
944
|
-
const publicUrl = typeof window !== "undefined" ? window.__mcpPublicAssetsUrl || window.__mcpPublicUrl || "" : "";
|
|
945
|
-
const getFinalSrc = /* @__PURE__ */ __name((source) => {
|
|
946
|
-
if (!source) return source;
|
|
947
|
-
if (source.startsWith("http://") || source.startsWith("https://") || source.startsWith("data:")) {
|
|
948
|
-
return source;
|
|
949
|
-
}
|
|
950
|
-
if (!publicUrl) {
|
|
951
|
-
return source;
|
|
952
|
-
}
|
|
953
|
-
const cleanSrc = source.startsWith("/") ? source.slice(1) : source;
|
|
954
|
-
return `${publicUrl}/${cleanSrc}`;
|
|
955
|
-
}, "getFinalSrc");
|
|
956
|
-
const finalSrc = getFinalSrc(src);
|
|
957
|
-
return /* @__PURE__ */ React2.createElement("img", { src: finalSrc, ...props });
|
|
958
|
-
}, "Image");
|
|
959
|
-
|
|
960
|
-
// src/react/ThemeProvider.tsx
|
|
961
|
-
import React3, { useEffect as useEffect3, useLayoutEffect, useState as useState3 } from "react";
|
|
962
|
-
|
|
963
|
-
// src/react/useWidget.ts
|
|
964
|
-
import {
|
|
965
|
-
useCallback as useCallback2,
|
|
966
|
-
useEffect as useEffect2,
|
|
967
|
-
useMemo,
|
|
968
|
-
useState as useState2,
|
|
969
|
-
useSyncExternalStore
|
|
970
|
-
} from "react";
|
|
971
|
-
|
|
972
|
-
// src/react/widget-types.ts
|
|
973
|
-
var SET_GLOBALS_EVENT_TYPE = "openai:set_globals";
|
|
974
|
-
|
|
975
|
-
// src/react/useWidget.ts
|
|
976
|
-
function useOpenAiGlobal(key) {
|
|
977
|
-
return useSyncExternalStore(
|
|
978
|
-
(onChange) => {
|
|
979
|
-
const handleSetGlobal = /* @__PURE__ */ __name((event) => {
|
|
980
|
-
const customEvent = event;
|
|
981
|
-
const value = customEvent.detail.globals[key];
|
|
982
|
-
if (value === void 0) {
|
|
983
|
-
return;
|
|
984
|
-
}
|
|
985
|
-
onChange();
|
|
986
|
-
}, "handleSetGlobal");
|
|
987
|
-
if (typeof window !== "undefined") {
|
|
988
|
-
window.addEventListener(SET_GLOBALS_EVENT_TYPE, handleSetGlobal);
|
|
989
|
-
}
|
|
990
|
-
return () => {
|
|
991
|
-
if (typeof window !== "undefined") {
|
|
992
|
-
window.removeEventListener(SET_GLOBALS_EVENT_TYPE, handleSetGlobal);
|
|
993
|
-
}
|
|
994
|
-
};
|
|
995
|
-
},
|
|
996
|
-
() => typeof window !== "undefined" && window.openai ? window.openai[key] : void 0
|
|
997
|
-
);
|
|
998
|
-
}
|
|
999
|
-
__name(useOpenAiGlobal, "useOpenAiGlobal");
|
|
1000
|
-
function useWidget(defaultProps) {
|
|
1001
|
-
const [isOpenAiAvailable, setIsOpenAiAvailable] = useState2(
|
|
1002
|
-
() => typeof window !== "undefined" && !!window.openai
|
|
1003
|
-
);
|
|
1004
|
-
useEffect2(() => {
|
|
1005
|
-
if (typeof window !== "undefined" && window.openai) {
|
|
1006
|
-
setIsOpenAiAvailable(true);
|
|
1007
|
-
return;
|
|
1008
|
-
}
|
|
1009
|
-
const checkInterval = setInterval(() => {
|
|
1010
|
-
if (typeof window !== "undefined" && window.openai) {
|
|
1011
|
-
setIsOpenAiAvailable(true);
|
|
1012
|
-
clearInterval(checkInterval);
|
|
1013
|
-
}
|
|
1014
|
-
}, 100);
|
|
1015
|
-
const handleSetGlobals = /* @__PURE__ */ __name(() => {
|
|
1016
|
-
if (typeof window !== "undefined" && window.openai) {
|
|
1017
|
-
setIsOpenAiAvailable(true);
|
|
1018
|
-
clearInterval(checkInterval);
|
|
1019
|
-
}
|
|
1020
|
-
}, "handleSetGlobals");
|
|
1021
|
-
if (typeof window !== "undefined") {
|
|
1022
|
-
window.addEventListener(SET_GLOBALS_EVENT_TYPE, handleSetGlobals);
|
|
1023
|
-
}
|
|
1024
|
-
const timeout = setTimeout(() => {
|
|
1025
|
-
clearInterval(checkInterval);
|
|
1026
|
-
if (typeof window !== "undefined") {
|
|
1027
|
-
window.removeEventListener(SET_GLOBALS_EVENT_TYPE, handleSetGlobals);
|
|
1028
|
-
}
|
|
1029
|
-
}, 5e3);
|
|
1030
|
-
return () => {
|
|
1031
|
-
clearInterval(checkInterval);
|
|
1032
|
-
clearTimeout(timeout);
|
|
1033
|
-
if (typeof window !== "undefined") {
|
|
1034
|
-
window.removeEventListener(SET_GLOBALS_EVENT_TYPE, handleSetGlobals);
|
|
1035
|
-
}
|
|
1036
|
-
};
|
|
1037
|
-
}, []);
|
|
1038
|
-
const provider = useMemo(() => {
|
|
1039
|
-
return isOpenAiAvailable ? "openai" : "mcp-ui";
|
|
1040
|
-
}, [isOpenAiAvailable]);
|
|
1041
|
-
const searchString = typeof window !== "undefined" ? window.location.search : "";
|
|
1042
|
-
const urlParams = useMemo(() => {
|
|
1043
|
-
const urlParams2 = new URLSearchParams(searchString);
|
|
1044
|
-
if (urlParams2.has("mcpUseParams")) {
|
|
1045
|
-
return JSON.parse(urlParams2.get("mcpUseParams"));
|
|
1046
|
-
}
|
|
1047
|
-
return {
|
|
1048
|
-
toolInput: {},
|
|
1049
|
-
toolOutput: {},
|
|
1050
|
-
toolId: ""
|
|
1051
|
-
};
|
|
1052
|
-
}, [searchString]);
|
|
1053
|
-
const toolInput = provider === "openai" ? useOpenAiGlobal("toolInput") : urlParams.toolInput;
|
|
1054
|
-
const toolOutput = provider === "openai" ? useOpenAiGlobal("toolOutput") : urlParams.toolOutput;
|
|
1055
|
-
const toolResponseMetadata = useOpenAiGlobal("toolResponseMetadata");
|
|
1056
|
-
const widgetProps = useMemo(() => {
|
|
1057
|
-
if (toolResponseMetadata && typeof toolResponseMetadata === "object") {
|
|
1058
|
-
const metaProps = toolResponseMetadata["mcp-use/props"];
|
|
1059
|
-
if (metaProps) {
|
|
1060
|
-
return metaProps;
|
|
1061
|
-
}
|
|
1062
|
-
}
|
|
1063
|
-
return defaultProps || {};
|
|
1064
|
-
}, [toolResponseMetadata, defaultProps]);
|
|
1065
|
-
const widgetState = useOpenAiGlobal("widgetState");
|
|
1066
|
-
const theme = useOpenAiGlobal("theme");
|
|
1067
|
-
const displayMode = useOpenAiGlobal("displayMode");
|
|
1068
|
-
const safeArea = useOpenAiGlobal("safeArea");
|
|
1069
|
-
const maxHeight = useOpenAiGlobal("maxHeight");
|
|
1070
|
-
const userAgent = useOpenAiGlobal("userAgent");
|
|
1071
|
-
const locale = useOpenAiGlobal("locale");
|
|
1072
|
-
const mcp_url = useMemo(() => {
|
|
1073
|
-
if (typeof window !== "undefined" && window.__mcpPublicUrl) {
|
|
1074
|
-
return window.__mcpPublicUrl.replace(/\/mcp-use\/public$/, "");
|
|
1075
|
-
}
|
|
1076
|
-
return "";
|
|
1077
|
-
}, []);
|
|
1078
|
-
const [localWidgetState, setLocalWidgetState] = useState2(null);
|
|
1079
|
-
useEffect2(() => {
|
|
1080
|
-
if (widgetState !== void 0) {
|
|
1081
|
-
setLocalWidgetState(widgetState);
|
|
1082
|
-
}
|
|
1083
|
-
}, [widgetState]);
|
|
1084
|
-
const callTool = useCallback2(
|
|
1085
|
-
async (name, args) => {
|
|
1086
|
-
if (!window.openai?.callTool) {
|
|
1087
|
-
throw new Error("window.openai.callTool is not available");
|
|
1088
|
-
}
|
|
1089
|
-
return window.openai.callTool(name, args);
|
|
1090
|
-
},
|
|
1091
|
-
[]
|
|
1092
|
-
);
|
|
1093
|
-
const sendFollowUpMessage = useCallback2(
|
|
1094
|
-
async (prompt) => {
|
|
1095
|
-
if (!window.openai?.sendFollowUpMessage) {
|
|
1096
|
-
throw new Error("window.openai.sendFollowUpMessage is not available");
|
|
1097
|
-
}
|
|
1098
|
-
return window.openai.sendFollowUpMessage({ prompt });
|
|
1099
|
-
},
|
|
1100
|
-
[]
|
|
1101
|
-
);
|
|
1102
|
-
const openExternal = useCallback2((href) => {
|
|
1103
|
-
if (!window.openai?.openExternal) {
|
|
1104
|
-
throw new Error("window.openai.openExternal is not available");
|
|
1105
|
-
}
|
|
1106
|
-
window.openai.openExternal({ href });
|
|
1107
|
-
}, []);
|
|
1108
|
-
const requestDisplayMode = useCallback2(
|
|
1109
|
-
async (mode) => {
|
|
1110
|
-
if (!window.openai?.requestDisplayMode) {
|
|
1111
|
-
throw new Error("window.openai.requestDisplayMode is not available");
|
|
1112
|
-
}
|
|
1113
|
-
return window.openai.requestDisplayMode({ mode });
|
|
1114
|
-
},
|
|
1115
|
-
[]
|
|
1116
|
-
);
|
|
1117
|
-
const setState = useCallback2(
|
|
1118
|
-
async (state) => {
|
|
1119
|
-
if (!window.openai?.setWidgetState) {
|
|
1120
|
-
throw new Error("window.openai.setWidgetState is not available");
|
|
1121
|
-
}
|
|
1122
|
-
const currentState = widgetState !== void 0 ? widgetState : localWidgetState;
|
|
1123
|
-
const newState = typeof state === "function" ? state(currentState) : state;
|
|
1124
|
-
setLocalWidgetState(newState);
|
|
1125
|
-
return window.openai.setWidgetState(newState);
|
|
1126
|
-
},
|
|
1127
|
-
[widgetState, localWidgetState]
|
|
1128
|
-
);
|
|
1129
|
-
const isPending = useMemo(() => {
|
|
1130
|
-
return provider === "openai" && toolResponseMetadata === null;
|
|
1131
|
-
}, [provider, toolResponseMetadata]);
|
|
1132
|
-
return {
|
|
1133
|
-
// Props and state (with defaults)
|
|
1134
|
-
props: widgetProps,
|
|
1135
|
-
toolInput: toolInput || {},
|
|
1136
|
-
output: toolOutput ?? null,
|
|
1137
|
-
metadata: toolResponseMetadata ?? null,
|
|
1138
|
-
state: localWidgetState,
|
|
1139
|
-
setState,
|
|
1140
|
-
// Layout and theme (with safe defaults)
|
|
1141
|
-
theme: theme || "light",
|
|
1142
|
-
displayMode: displayMode || "inline",
|
|
1143
|
-
safeArea: safeArea || { insets: { top: 0, bottom: 0, left: 0, right: 0 } },
|
|
1144
|
-
maxHeight: maxHeight || 600,
|
|
1145
|
-
userAgent: userAgent || {
|
|
1146
|
-
device: { type: "desktop" },
|
|
1147
|
-
capabilities: { hover: true, touch: false }
|
|
1148
|
-
},
|
|
1149
|
-
locale: locale || "en",
|
|
1150
|
-
mcp_url,
|
|
1151
|
-
// Actions
|
|
1152
|
-
callTool,
|
|
1153
|
-
sendFollowUpMessage,
|
|
1154
|
-
openExternal,
|
|
1155
|
-
requestDisplayMode,
|
|
1156
|
-
// Availability
|
|
1157
|
-
isAvailable: isOpenAiAvailable,
|
|
1158
|
-
isPending
|
|
1159
|
-
};
|
|
1160
|
-
}
|
|
1161
|
-
__name(useWidget, "useWidget");
|
|
1162
|
-
function useWidgetProps(defaultProps) {
|
|
1163
|
-
const { props } = useWidget(defaultProps);
|
|
1164
|
-
return props;
|
|
1165
|
-
}
|
|
1166
|
-
__name(useWidgetProps, "useWidgetProps");
|
|
1167
|
-
function useWidgetTheme() {
|
|
1168
|
-
const { theme } = useWidget();
|
|
1169
|
-
return theme;
|
|
1170
|
-
}
|
|
1171
|
-
__name(useWidgetTheme, "useWidgetTheme");
|
|
1172
|
-
function useWidgetState(defaultState) {
|
|
1173
|
-
const { state, setState } = useWidget();
|
|
1174
|
-
useEffect2(() => {
|
|
1175
|
-
if (state === null && defaultState !== void 0 && window.openai?.setWidgetState) {
|
|
1176
|
-
setState(defaultState);
|
|
1177
|
-
}
|
|
1178
|
-
}, []);
|
|
1179
|
-
return [state, setState];
|
|
1180
|
-
}
|
|
1181
|
-
__name(useWidgetState, "useWidgetState");
|
|
1182
|
-
|
|
1183
|
-
// src/react/ThemeProvider.tsx
|
|
1184
|
-
var ThemeProvider = /* @__PURE__ */ __name(({
|
|
1185
|
-
children
|
|
1186
|
-
}) => {
|
|
1187
|
-
const { theme, isAvailable } = useWidget();
|
|
1188
|
-
console.log("theme", theme);
|
|
1189
|
-
const [systemPreference, setSystemPreference] = useState3(
|
|
1190
|
-
() => {
|
|
1191
|
-
if (typeof window === "undefined") return "light";
|
|
1192
|
-
return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
|
1193
|
-
}
|
|
1194
|
-
);
|
|
1195
|
-
useEffect3(() => {
|
|
1196
|
-
if (typeof window === "undefined") return;
|
|
1197
|
-
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
|
|
1198
|
-
const handleChange = /* @__PURE__ */ __name((e) => {
|
|
1199
|
-
setSystemPreference(e.matches ? "dark" : "light");
|
|
1200
|
-
}, "handleChange");
|
|
1201
|
-
mediaQuery.addEventListener("change", handleChange);
|
|
1202
|
-
return () => mediaQuery.removeEventListener("change", handleChange);
|
|
1203
|
-
}, []);
|
|
1204
|
-
const effectiveTheme = isAvailable ? theme : systemPreference;
|
|
1205
|
-
useLayoutEffect(() => {
|
|
1206
|
-
if (typeof document === "undefined") return;
|
|
1207
|
-
if (effectiveTheme === "dark") {
|
|
1208
|
-
document.documentElement.classList.add("dark");
|
|
1209
|
-
} else {
|
|
1210
|
-
document.documentElement.classList.remove("dark");
|
|
1211
|
-
}
|
|
1212
|
-
}, [effectiveTheme]);
|
|
1213
|
-
return /* @__PURE__ */ React3.createElement(React3.Fragment, null, children);
|
|
1214
|
-
}, "ThemeProvider");
|
|
1215
|
-
|
|
1216
|
-
// src/react/WidgetControls.tsx
|
|
1217
|
-
import React4, { useEffect as useEffect4, useRef as useRef2, useState as useState4 } from "react";
|
|
1218
|
-
function WidgetControls({
|
|
1219
|
-
children,
|
|
1220
|
-
className = "",
|
|
1221
|
-
position = "top-right",
|
|
1222
|
-
attachTo,
|
|
1223
|
-
showLabels = true,
|
|
1224
|
-
debugger: enableDebugger = false,
|
|
1225
|
-
viewControls = false
|
|
1226
|
-
}) {
|
|
1227
|
-
const {
|
|
1228
|
-
props,
|
|
1229
|
-
output,
|
|
1230
|
-
metadata,
|
|
1231
|
-
state,
|
|
1232
|
-
theme,
|
|
1233
|
-
displayMode,
|
|
1234
|
-
safeArea,
|
|
1235
|
-
maxHeight,
|
|
1236
|
-
userAgent,
|
|
1237
|
-
locale,
|
|
1238
|
-
isAvailable,
|
|
1239
|
-
callTool,
|
|
1240
|
-
sendFollowUpMessage,
|
|
1241
|
-
openExternal,
|
|
1242
|
-
requestDisplayMode,
|
|
1243
|
-
setState
|
|
1244
|
-
} = useWidget();
|
|
1245
|
-
const [isHovered, setIsHovered] = useState4(false);
|
|
1246
|
-
const [isOverlayOpen, setIsOverlayOpen] = useState4(false);
|
|
1247
|
-
const containerRef = useRef2(null);
|
|
1248
|
-
const overlayRef = useRef2(null);
|
|
1249
|
-
const [windowOpenAiKeys, setWindowOpenAiKeys] = useState4([]);
|
|
1250
|
-
const [actionResult, setActionResult] = useState4("");
|
|
1251
|
-
const [toolName, setToolName] = useState4("get-my-city");
|
|
1252
|
-
const [toolArgs, setToolArgs] = useState4("{}");
|
|
1253
|
-
const [followUpMessage, setFollowUpMessage] = useState4(
|
|
1254
|
-
"Test follow-up message"
|
|
1255
|
-
);
|
|
1256
|
-
const [externalUrl, setExternalUrl] = useState4(
|
|
1257
|
-
"https://docs.mcp-use.com"
|
|
1258
|
-
);
|
|
1259
|
-
const isFullscreen = displayMode === "fullscreen" && isAvailable;
|
|
1260
|
-
const isPip = displayMode === "pip" && isAvailable;
|
|
1261
|
-
const isInInspector = typeof window !== "undefined" && window.location.pathname.includes("/inspector/api/");
|
|
1262
|
-
useEffect4(() => {
|
|
1263
|
-
const timeoutId = setTimeout(() => {
|
|
1264
|
-
if (typeof window !== "undefined" && window.openai) {
|
|
1265
|
-
try {
|
|
1266
|
-
const keys = Object.keys(window.openai);
|
|
1267
|
-
setWindowOpenAiKeys(keys);
|
|
1268
|
-
} catch (e) {
|
|
1269
|
-
setWindowOpenAiKeys([]);
|
|
1270
|
-
}
|
|
1271
|
-
} else {
|
|
1272
|
-
setWindowOpenAiKeys([]);
|
|
1273
|
-
}
|
|
1274
|
-
}, 100);
|
|
1275
|
-
return () => {
|
|
1276
|
-
clearTimeout(timeoutId);
|
|
1277
|
-
};
|
|
1278
|
-
}, []);
|
|
1279
|
-
const isDark = theme === "dark";
|
|
1280
|
-
const getPositionClasses = /* @__PURE__ */ __name(() => {
|
|
1281
|
-
const baseClasses = [
|
|
1282
|
-
"absolute",
|
|
1283
|
-
"z-[1000]",
|
|
1284
|
-
"flex",
|
|
1285
|
-
"gap-2",
|
|
1286
|
-
"transition-opacity",
|
|
1287
|
-
"duration-200",
|
|
1288
|
-
"ease-in-out",
|
|
1289
|
-
isHovered ? "opacity-100" : "opacity-0",
|
|
1290
|
-
isHovered ? "pointer-events-auto" : "pointer-events-none"
|
|
1291
|
-
];
|
|
1292
|
-
switch (position) {
|
|
1293
|
-
case "top-left":
|
|
1294
|
-
return [...baseClasses, "top-4", "left-4"];
|
|
1295
|
-
case "top-center":
|
|
1296
|
-
return [...baseClasses, "top-4", "left-1/2", "-translate-x-1/2"];
|
|
1297
|
-
case "top-right":
|
|
1298
|
-
return [...baseClasses, "top-4", "right-4"];
|
|
1299
|
-
case "center-left":
|
|
1300
|
-
return [...baseClasses, "top-1/2", "left-4", "-translate-y-1/2"];
|
|
1301
|
-
case "center-right":
|
|
1302
|
-
return [...baseClasses, "top-1/2", "right-4", "-translate-y-1/2"];
|
|
1303
|
-
case "bottom-left":
|
|
1304
|
-
return [...baseClasses, "bottom-4", "left-4"];
|
|
1305
|
-
case "bottom-center":
|
|
1306
|
-
return [...baseClasses, "bottom-4", "left-1/2", "-translate-x-1/2"];
|
|
1307
|
-
case "bottom-right":
|
|
1308
|
-
return [...baseClasses, "bottom-4", "right-4"];
|
|
1309
|
-
default:
|
|
1310
|
-
return [...baseClasses, "top-4", "right-4"];
|
|
1311
|
-
}
|
|
1312
|
-
}, "getPositionClasses");
|
|
1313
|
-
const getPositionOffsetStyles = /* @__PURE__ */ __name(() => {
|
|
1314
|
-
const baseOffset = 16;
|
|
1315
|
-
const topOffset = safeArea?.insets?.top ? Math.max(baseOffset, safeArea.insets.top + 8) : baseOffset;
|
|
1316
|
-
const rightOffset = safeArea?.insets?.right ? Math.max(baseOffset, safeArea.insets.right + 8) : baseOffset;
|
|
1317
|
-
const bottomOffset = safeArea?.insets?.bottom ? Math.max(baseOffset, safeArea.insets.bottom + 8) : baseOffset;
|
|
1318
|
-
const leftOffset = safeArea?.insets?.left ? Math.max(baseOffset, safeArea.insets.left + 8) : baseOffset;
|
|
1319
|
-
const styles = {};
|
|
1320
|
-
switch (position) {
|
|
1321
|
-
case "top-left":
|
|
1322
|
-
styles.top = `${topOffset}px`;
|
|
1323
|
-
styles.left = `${leftOffset}px`;
|
|
1324
|
-
break;
|
|
1325
|
-
case "top-center":
|
|
1326
|
-
styles.top = `${topOffset}px`;
|
|
1327
|
-
break;
|
|
1328
|
-
case "top-right":
|
|
1329
|
-
styles.top = `${topOffset}px`;
|
|
1330
|
-
styles.right = `${rightOffset}px`;
|
|
1331
|
-
break;
|
|
1332
|
-
case "center-left":
|
|
1333
|
-
styles.left = `${leftOffset}px`;
|
|
1334
|
-
break;
|
|
1335
|
-
case "center-right":
|
|
1336
|
-
styles.right = `${rightOffset}px`;
|
|
1337
|
-
break;
|
|
1338
|
-
case "bottom-left":
|
|
1339
|
-
styles.bottom = `${bottomOffset}px`;
|
|
1340
|
-
styles.left = `${leftOffset}px`;
|
|
1341
|
-
break;
|
|
1342
|
-
case "bottom-center":
|
|
1343
|
-
styles.bottom = `${bottomOffset}px`;
|
|
1344
|
-
break;
|
|
1345
|
-
case "bottom-right":
|
|
1346
|
-
styles.bottom = `${bottomOffset}px`;
|
|
1347
|
-
styles.right = `${rightOffset}px`;
|
|
1348
|
-
break;
|
|
1349
|
-
default:
|
|
1350
|
-
styles.top = `${topOffset}px`;
|
|
1351
|
-
styles.right = `${rightOffset}px`;
|
|
1352
|
-
break;
|
|
1353
|
-
}
|
|
1354
|
-
return styles;
|
|
1355
|
-
}, "getPositionOffsetStyles");
|
|
1356
|
-
useEffect4(() => {
|
|
1357
|
-
if (!attachTo) return;
|
|
1358
|
-
const handleMouseEnter = /* @__PURE__ */ __name(() => setIsHovered(true), "handleMouseEnter");
|
|
1359
|
-
const handleMouseLeave = /* @__PURE__ */ __name(() => setIsHovered(false), "handleMouseLeave");
|
|
1360
|
-
attachTo.addEventListener("mouseenter", handleMouseEnter);
|
|
1361
|
-
attachTo.addEventListener("mouseleave", handleMouseLeave);
|
|
1362
|
-
return () => {
|
|
1363
|
-
attachTo.removeEventListener("mouseenter", handleMouseEnter);
|
|
1364
|
-
attachTo.removeEventListener("mouseleave", handleMouseLeave);
|
|
1365
|
-
};
|
|
1366
|
-
}, [attachTo]);
|
|
1367
|
-
useEffect4(() => {
|
|
1368
|
-
if (!isOverlayOpen) return;
|
|
1369
|
-
const handleClickOutside = /* @__PURE__ */ __name((event) => {
|
|
1370
|
-
if (overlayRef.current && !overlayRef.current.contains(event.target)) {
|
|
1371
|
-
setIsOverlayOpen(false);
|
|
1372
|
-
}
|
|
1373
|
-
}, "handleClickOutside");
|
|
1374
|
-
document.addEventListener("mousedown", handleClickOutside);
|
|
1375
|
-
return () => {
|
|
1376
|
-
document.removeEventListener("mousedown", handleClickOutside);
|
|
1377
|
-
};
|
|
1378
|
-
}, [isOverlayOpen]);
|
|
1379
|
-
useEffect4(() => {
|
|
1380
|
-
if (isOverlayOpen) {
|
|
1381
|
-
document.body.style.overflow = "hidden";
|
|
1382
|
-
} else {
|
|
1383
|
-
document.body.style.overflow = "";
|
|
1384
|
-
}
|
|
1385
|
-
return () => {
|
|
1386
|
-
document.body.style.overflow = "";
|
|
1387
|
-
};
|
|
1388
|
-
}, [isOverlayOpen]);
|
|
1389
|
-
const handleToggleOverlay = /* @__PURE__ */ __name(() => {
|
|
1390
|
-
setIsOverlayOpen(!isOverlayOpen);
|
|
1391
|
-
}, "handleToggleOverlay");
|
|
1392
|
-
const handleCallTool = /* @__PURE__ */ __name(async () => {
|
|
1393
|
-
try {
|
|
1394
|
-
setActionResult("Calling tool...");
|
|
1395
|
-
const args = toolArgs.trim() ? JSON.parse(toolArgs) : {};
|
|
1396
|
-
const result = await callTool(toolName, args);
|
|
1397
|
-
setActionResult(`Success: ${JSON.stringify(result, null, 2)}`);
|
|
1398
|
-
} catch (error) {
|
|
1399
|
-
const err = error;
|
|
1400
|
-
setActionResult(`Error: ${err.message}`);
|
|
1401
|
-
}
|
|
1402
|
-
}, "handleCallTool");
|
|
1403
|
-
const handleSendFollowUpMessage = /* @__PURE__ */ __name(async () => {
|
|
1404
|
-
try {
|
|
1405
|
-
setActionResult("Sending follow-up message...");
|
|
1406
|
-
await sendFollowUpMessage(followUpMessage);
|
|
1407
|
-
setActionResult("Follow-up message sent successfully");
|
|
1408
|
-
} catch (error) {
|
|
1409
|
-
const err = error;
|
|
1410
|
-
setActionResult(`Error: ${err.message}`);
|
|
1411
|
-
}
|
|
1412
|
-
}, "handleSendFollowUpMessage");
|
|
1413
|
-
const handleOpenExternal = /* @__PURE__ */ __name(() => {
|
|
1414
|
-
try {
|
|
1415
|
-
openExternal(externalUrl);
|
|
1416
|
-
setActionResult(`Opened external link: ${externalUrl}`);
|
|
1417
|
-
} catch (error) {
|
|
1418
|
-
const err = error;
|
|
1419
|
-
setActionResult(`Error: ${err.message}`);
|
|
1420
|
-
}
|
|
1421
|
-
}, "handleOpenExternal");
|
|
1422
|
-
const handleRequestDisplayMode = /* @__PURE__ */ __name(async (mode) => {
|
|
1423
|
-
try {
|
|
1424
|
-
setActionResult(`Requesting display mode: ${mode}...`);
|
|
1425
|
-
const result = await requestDisplayMode(mode);
|
|
1426
|
-
setActionResult(`Display mode granted: ${result.mode}`);
|
|
1427
|
-
} catch (error) {
|
|
1428
|
-
const err = error;
|
|
1429
|
-
setActionResult(`Error: ${err.message}`);
|
|
1430
|
-
}
|
|
1431
|
-
}, "handleRequestDisplayMode");
|
|
1432
|
-
const handleSetState = /* @__PURE__ */ __name(async () => {
|
|
1433
|
-
try {
|
|
1434
|
-
const newState = state ? { ...state, debugTimestamp: (/* @__PURE__ */ new Date()).toISOString() } : { debugTimestamp: (/* @__PURE__ */ new Date()).toISOString() };
|
|
1435
|
-
setActionResult("Setting state...");
|
|
1436
|
-
await setState(newState);
|
|
1437
|
-
setActionResult(`State updated: ${JSON.stringify(newState, null, 2)}`);
|
|
1438
|
-
} catch (error) {
|
|
1439
|
-
const err = error;
|
|
1440
|
-
setActionResult(`Error: ${err.message}`);
|
|
1441
|
-
}
|
|
1442
|
-
}, "handleSetState");
|
|
1443
|
-
const handleFullscreen = /* @__PURE__ */ __name(async () => {
|
|
1444
|
-
try {
|
|
1445
|
-
await requestDisplayMode("fullscreen");
|
|
1446
|
-
} catch (error) {
|
|
1447
|
-
console.error("Failed to go fullscreen:", error);
|
|
1448
|
-
}
|
|
1449
|
-
}, "handleFullscreen");
|
|
1450
|
-
const handlePip = /* @__PURE__ */ __name(async () => {
|
|
1451
|
-
try {
|
|
1452
|
-
await requestDisplayMode("pip");
|
|
1453
|
-
} catch (error) {
|
|
1454
|
-
console.error("Failed to go pip:", error);
|
|
1455
|
-
}
|
|
1456
|
-
}, "handlePip");
|
|
1457
|
-
const getTooltipClasses = /* @__PURE__ */ __name(() => {
|
|
1458
|
-
const baseClasses = [
|
|
1459
|
-
"absolute",
|
|
1460
|
-
"px-2",
|
|
1461
|
-
"py-1",
|
|
1462
|
-
"bg-black/90",
|
|
1463
|
-
"text-white",
|
|
1464
|
-
"rounded",
|
|
1465
|
-
"text-xs",
|
|
1466
|
-
"whitespace-nowrap",
|
|
1467
|
-
"pointer-events-none",
|
|
1468
|
-
"transition-opacity",
|
|
1469
|
-
"duration-200",
|
|
1470
|
-
"ease-in-out"
|
|
1471
|
-
];
|
|
1472
|
-
switch (position) {
|
|
1473
|
-
case "top-right":
|
|
1474
|
-
return [...baseClasses, "top-full", "right-0", "mt-2"];
|
|
1475
|
-
case "top-left":
|
|
1476
|
-
return [...baseClasses, "top-full", "left-0", "mt-2"];
|
|
1477
|
-
case "top-center":
|
|
1478
|
-
return [
|
|
1479
|
-
...baseClasses,
|
|
1480
|
-
"top-full",
|
|
1481
|
-
"left-1/2",
|
|
1482
|
-
"-translate-x-1/2",
|
|
1483
|
-
"mt-2"
|
|
1484
|
-
];
|
|
1485
|
-
case "bottom-right":
|
|
1486
|
-
return [...baseClasses, "bottom-full", "right-0", "mb-2"];
|
|
1487
|
-
case "bottom-left":
|
|
1488
|
-
return [...baseClasses, "bottom-full", "left-0", "mb-2"];
|
|
1489
|
-
case "bottom-center":
|
|
1490
|
-
return [
|
|
1491
|
-
...baseClasses,
|
|
1492
|
-
"bottom-full",
|
|
1493
|
-
"left-1/2",
|
|
1494
|
-
"-translate-x-1/2",
|
|
1495
|
-
"mb-2"
|
|
1496
|
-
];
|
|
1497
|
-
case "center-left":
|
|
1498
|
-
return [
|
|
1499
|
-
...baseClasses,
|
|
1500
|
-
"left-full",
|
|
1501
|
-
"top-1/2",
|
|
1502
|
-
"-translate-y-1/2",
|
|
1503
|
-
"ml-2"
|
|
1504
|
-
];
|
|
1505
|
-
case "center-right":
|
|
1506
|
-
return [
|
|
1507
|
-
...baseClasses,
|
|
1508
|
-
"right-full",
|
|
1509
|
-
"top-1/2",
|
|
1510
|
-
"-translate-y-1/2",
|
|
1511
|
-
"mr-2"
|
|
1512
|
-
];
|
|
1513
|
-
default:
|
|
1514
|
-
return [...baseClasses, "top-full", "right-0", "mt-2"];
|
|
1515
|
-
}
|
|
1516
|
-
}, "getTooltipClasses");
|
|
1517
|
-
const IconButton = /* @__PURE__ */ __name(({
|
|
1518
|
-
onClick,
|
|
1519
|
-
label,
|
|
1520
|
-
children: icon
|
|
1521
|
-
}) => {
|
|
1522
|
-
const [isButtonHovered, setIsButtonHovered] = useState4(false);
|
|
1523
|
-
const tooltipClasses = getTooltipClasses();
|
|
1524
|
-
return /* @__PURE__ */ React4.createElement(
|
|
1525
|
-
"button",
|
|
1526
|
-
{
|
|
1527
|
-
className: `p-2 ${isDark ? "bg-white/10 hover:bg-white/20" : "bg-black/70 hover:bg-black/90"} text-white border-none rounded-lg cursor-pointer flex items-center justify-center w-8 h-8 transition-colors duration-200 backdrop-blur-md ${isDark ? "shadow-[0_2px_8px_rgba(0,0,0,0.3)]" : "shadow-[0_2px_8px_rgba(0,0,0,0.2)]"} relative`,
|
|
1528
|
-
onMouseEnter: () => setIsButtonHovered(true),
|
|
1529
|
-
onMouseLeave: () => setIsButtonHovered(false),
|
|
1530
|
-
onClick,
|
|
1531
|
-
"aria-label": label
|
|
1532
|
-
},
|
|
1533
|
-
/* @__PURE__ */ React4.createElement(
|
|
1534
|
-
"svg",
|
|
1535
|
-
{
|
|
1536
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
1537
|
-
width: "16",
|
|
1538
|
-
height: "16",
|
|
1539
|
-
viewBox: "0 0 24 24",
|
|
1540
|
-
fill: "none",
|
|
1541
|
-
stroke: "currentColor",
|
|
1542
|
-
strokeWidth: "2",
|
|
1543
|
-
strokeLinecap: "round",
|
|
1544
|
-
strokeLinejoin: "round",
|
|
1545
|
-
className: "block"
|
|
1546
|
-
},
|
|
1547
|
-
icon
|
|
1548
|
-
),
|
|
1549
|
-
showLabels && /* @__PURE__ */ React4.createElement(
|
|
1550
|
-
"span",
|
|
1551
|
-
{
|
|
1552
|
-
className: `${tooltipClasses.join(" ")} ${isButtonHovered ? "opacity-100" : "opacity-0"}`
|
|
1553
|
-
},
|
|
1554
|
-
label
|
|
1555
|
-
)
|
|
1556
|
-
);
|
|
1557
|
-
}, "IconButton");
|
|
1558
|
-
const formatValue = /* @__PURE__ */ __name((value) => {
|
|
1559
|
-
if (value === null) return "null";
|
|
1560
|
-
if (value === void 0) return "undefined";
|
|
1561
|
-
if (typeof value === "object") {
|
|
1562
|
-
try {
|
|
1563
|
-
return JSON.stringify(value, null, 2);
|
|
1564
|
-
} catch {
|
|
1565
|
-
return String(value);
|
|
1566
|
-
}
|
|
1567
|
-
}
|
|
1568
|
-
return String(value);
|
|
1569
|
-
}, "formatValue");
|
|
1570
|
-
const formatUserAgent = /* @__PURE__ */ __name((ua) => {
|
|
1571
|
-
if (!ua) return "N/A";
|
|
1572
|
-
return `${ua.device?.type || "unknown"}`;
|
|
1573
|
-
}, "formatUserAgent");
|
|
1574
|
-
const formatSafeArea = /* @__PURE__ */ __name((sa) => {
|
|
1575
|
-
if (!sa?.insets) return "N/A";
|
|
1576
|
-
const { top, bottom, left, right } = sa.insets;
|
|
1577
|
-
return `T:${top} B:${bottom} L:${left} R:${right}`;
|
|
1578
|
-
}, "formatSafeArea");
|
|
1579
|
-
return /* @__PURE__ */ React4.createElement(React4.Fragment, null, /* @__PURE__ */ React4.createElement(
|
|
1580
|
-
"div",
|
|
1581
|
-
{
|
|
1582
|
-
ref: containerRef,
|
|
1583
|
-
className: `${className} relative h-fit`,
|
|
1584
|
-
onMouseEnter: () => !attachTo && setIsHovered(true),
|
|
1585
|
-
onMouseLeave: () => !attachTo && setIsHovered(false)
|
|
1586
|
-
},
|
|
1587
|
-
/* @__PURE__ */ React4.createElement(
|
|
1588
|
-
"div",
|
|
1589
|
-
{
|
|
1590
|
-
className: getPositionClasses().join(" "),
|
|
1591
|
-
style: getPositionOffsetStyles()
|
|
1592
|
-
},
|
|
1593
|
-
!isInInspector && /* @__PURE__ */ React4.createElement(React4.Fragment, null, !isFullscreen && !isPip && /* @__PURE__ */ React4.createElement(React4.Fragment, null, (viewControls === true || viewControls === "fullscreen") && /* @__PURE__ */ React4.createElement(IconButton, { onClick: handleFullscreen, label: "Fullscreen" }, /* @__PURE__ */ React4.createElement("path", { d: "M15 3h6v6" }), /* @__PURE__ */ React4.createElement("path", { d: "m21 3-7 7" }), /* @__PURE__ */ React4.createElement("path", { d: "m3 21 7-7" }), /* @__PURE__ */ React4.createElement("path", { d: "M9 21H3v-6" })), (viewControls === true || viewControls === "pip") && /* @__PURE__ */ React4.createElement(IconButton, { onClick: handlePip, label: "Picture in Picture" }, /* @__PURE__ */ React4.createElement("path", { d: "M21 9V6a2 2 0 0 0-2-2H4a2 2 0 0 0-2 2v10c0 1.1.9 2 2 2h4" }), /* @__PURE__ */ React4.createElement("rect", { width: "10", height: "7", x: "12", y: "13", rx: "2" }))), enableDebugger && /* @__PURE__ */ React4.createElement(IconButton, { onClick: handleToggleOverlay, label: "Debug Info" }, /* @__PURE__ */ React4.createElement("path", { d: "M12 20v-9" }), /* @__PURE__ */ React4.createElement("path", { d: "M14 7a4 4 0 0 1 4 4v3a6 6 0 0 1-12 0v-3a4 4 0 0 1 4-4z" }), /* @__PURE__ */ React4.createElement("path", { d: "M14.12 3.88 16 2" }), /* @__PURE__ */ React4.createElement("path", { d: "M21 21a4 4 0 0 0-3.81-4" }), /* @__PURE__ */ React4.createElement("path", { d: "M21 5a4 4 0 0 1-3.55 3.97" }), /* @__PURE__ */ React4.createElement("path", { d: "M22 13h-4" }), /* @__PURE__ */ React4.createElement("path", { d: "M3 21a4 4 0 0 1 3.81-4" }), /* @__PURE__ */ React4.createElement("path", { d: "M3 5a4 4 0 0 0 3.55 3.97" }), /* @__PURE__ */ React4.createElement("path", { d: "M6 13H2" }), /* @__PURE__ */ React4.createElement("path", { d: "m8 2 1.88 1.88" }), /* @__PURE__ */ React4.createElement("path", { d: "M9 7.13V6a3 3 0 1 1 6 0v1.13" })))
|
|
1594
|
-
),
|
|
1595
|
-
children
|
|
1596
|
-
), isOverlayOpen && enableDebugger && /* @__PURE__ */ React4.createElement(
|
|
1597
|
-
"div",
|
|
1598
|
-
{
|
|
1599
|
-
ref: overlayRef,
|
|
1600
|
-
className: "fixed inset-0 bg-black text-white font-mono text-xs z-[10000] overflow-auto p-4",
|
|
1601
|
-
onClick: (e) => {
|
|
1602
|
-
if (e.target === overlayRef.current) {
|
|
1603
|
-
setIsOverlayOpen(false);
|
|
1604
|
-
}
|
|
1605
|
-
}
|
|
1606
|
-
},
|
|
1607
|
-
/* @__PURE__ */ React4.createElement(
|
|
1608
|
-
"button",
|
|
1609
|
-
{
|
|
1610
|
-
onClick: () => setIsOverlayOpen(false),
|
|
1611
|
-
className: "absolute top-4 right-4 bg-white/10 text-white border-none rounded w-8 h-8 cursor-pointer flex items-center justify-center text-lg leading-none",
|
|
1612
|
-
"aria-label": "Close"
|
|
1613
|
-
},
|
|
1614
|
-
"\xD7"
|
|
1615
|
-
),
|
|
1616
|
-
/* @__PURE__ */ React4.createElement("div", { className: "max-w-[1200px] mx-auto pt-10" }, /* @__PURE__ */ React4.createElement("h1", { className: "text-lg font-bold mb-4 border-b border-gray-700 pb-2" }, "Debug Info"), /* @__PURE__ */ React4.createElement("table", { className: "w-full border-collapse border-spacing-0" }, /* @__PURE__ */ React4.createElement("tbody", null, /* @__PURE__ */ React4.createElement("tr", { className: "border-b border-gray-700" }, /* @__PURE__ */ React4.createElement("td", { className: "p-2 font-bold w-[200px] align-top" }, "Props"), /* @__PURE__ */ React4.createElement("td", { className: "p-2 whitespace-pre-wrap break-all" }, formatValue(props))), /* @__PURE__ */ React4.createElement("tr", { className: "border-b border-gray-700" }, /* @__PURE__ */ React4.createElement("td", { className: "p-2 font-bold w-[200px] align-top" }, "Output"), /* @__PURE__ */ React4.createElement("td", { className: "p-2 whitespace-pre-wrap break-all" }, formatValue(output))), /* @__PURE__ */ React4.createElement("tr", { className: "border-b border-gray-700" }, /* @__PURE__ */ React4.createElement("td", { className: "p-2 font-bold w-[200px] align-top" }, "Metadata"), /* @__PURE__ */ React4.createElement("td", { className: "p-2 whitespace-pre-wrap break-all" }, formatValue(metadata))), /* @__PURE__ */ React4.createElement("tr", { className: "border-b border-gray-700" }, /* @__PURE__ */ React4.createElement("td", { className: "p-2 font-bold w-[200px] align-top" }, "State"), /* @__PURE__ */ React4.createElement("td", { className: "p-2 whitespace-pre-wrap break-all" }, formatValue(state))), /* @__PURE__ */ React4.createElement("tr", { className: "border-b border-gray-700" }, /* @__PURE__ */ React4.createElement("td", { className: "p-2 font-bold w-[200px] align-top" }, "Theme"), /* @__PURE__ */ React4.createElement("td", { className: "p-2" }, theme)), /* @__PURE__ */ React4.createElement("tr", { className: "border-b border-gray-700" }, /* @__PURE__ */ React4.createElement("td", { className: "p-2 font-bold w-[200px] align-top" }, "Display Mode"), /* @__PURE__ */ React4.createElement("td", { className: "p-2" }, displayMode)), /* @__PURE__ */ React4.createElement("tr", { className: "border-b border-gray-700" }, /* @__PURE__ */ React4.createElement("td", { className: "p-2 font-bold w-[200px] align-top" }, "Locale"), /* @__PURE__ */ React4.createElement("td", { className: "p-2" }, locale)), /* @__PURE__ */ React4.createElement("tr", { className: "border-b border-gray-700" }, /* @__PURE__ */ React4.createElement("td", { className: "p-2 font-bold w-[200px] align-top" }, "Max Height"), /* @__PURE__ */ React4.createElement("td", { className: "p-2" }, maxHeight, "px")), /* @__PURE__ */ React4.createElement("tr", { className: "border-b border-gray-700" }, /* @__PURE__ */ React4.createElement("td", { className: "p-2 font-bold w-[200px] align-top" }, "User Agent"), /* @__PURE__ */ React4.createElement("td", { className: "p-2" }, formatUserAgent(userAgent))), /* @__PURE__ */ React4.createElement("tr", { className: "border-b border-gray-700" }, /* @__PURE__ */ React4.createElement("td", { className: "p-2 font-bold w-[200px] align-top" }, "Safe Area"), /* @__PURE__ */ React4.createElement("td", { className: "p-2" }, formatSafeArea(safeArea))), /* @__PURE__ */ React4.createElement("tr", { className: "border-b border-gray-700" }, /* @__PURE__ */ React4.createElement("td", { className: "p-2 font-bold w-[200px] align-top" }, "API Available"), /* @__PURE__ */ React4.createElement("td", { className: "p-2" }, isAvailable ? "Yes" : "No")), /* @__PURE__ */ React4.createElement("tr", { className: "border-b border-gray-700" }, /* @__PURE__ */ React4.createElement("td", { className: "p-2 font-bold w-[200px] align-top" }, "window.openai Keys"), /* @__PURE__ */ React4.createElement("td", { className: "p-2" }, windowOpenAiKeys.length > 0 ? windowOpenAiKeys.join(", ") : "N/A")))), /* @__PURE__ */ React4.createElement("h2", { className: "text-base font-bold mt-8 mb-4 border-b border-gray-700 pb-2" }, "Actions"), /* @__PURE__ */ React4.createElement("div", { className: "flex flex-col gap-3" }, /* @__PURE__ */ React4.createElement("div", { className: "flex gap-2 items-center" }, /* @__PURE__ */ React4.createElement(
|
|
1617
|
-
"input",
|
|
1618
|
-
{
|
|
1619
|
-
type: "text",
|
|
1620
|
-
value: toolName,
|
|
1621
|
-
onChange: (e) => setToolName(e.target.value),
|
|
1622
|
-
placeholder: "Tool name",
|
|
1623
|
-
className: "py-1.5 px-2 bg-[#1a1a1a] text-white border border-gray-700 rounded font-mono text-xs w-[150px]"
|
|
1624
|
-
}
|
|
1625
|
-
), /* @__PURE__ */ React4.createElement(
|
|
1626
|
-
"input",
|
|
1627
|
-
{
|
|
1628
|
-
type: "text",
|
|
1629
|
-
value: toolArgs,
|
|
1630
|
-
onChange: (e) => setToolArgs(e.target.value),
|
|
1631
|
-
placeholder: '{"key": "value"}',
|
|
1632
|
-
className: "py-1.5 px-2 bg-[#1a1a1a] text-white border border-gray-700 rounded font-mono text-xs flex-1"
|
|
1633
|
-
}
|
|
1634
|
-
), /* @__PURE__ */ React4.createElement(
|
|
1635
|
-
"button",
|
|
1636
|
-
{
|
|
1637
|
-
onClick: handleCallTool,
|
|
1638
|
-
className: "py-1.5 px-3 bg-gray-800 text-white border border-gray-600 rounded cursor-pointer font-mono text-xs"
|
|
1639
|
-
},
|
|
1640
|
-
"Call Tool"
|
|
1641
|
-
)), /* @__PURE__ */ React4.createElement("div", { className: "flex gap-2 items-center" }, /* @__PURE__ */ React4.createElement(
|
|
1642
|
-
"input",
|
|
1643
|
-
{
|
|
1644
|
-
type: "text",
|
|
1645
|
-
value: followUpMessage,
|
|
1646
|
-
onChange: (e) => setFollowUpMessage(e.target.value),
|
|
1647
|
-
placeholder: "Follow-up message",
|
|
1648
|
-
className: "py-1.5 px-2 bg-[#1a1a1a] text-white border border-gray-700 rounded font-mono text-xs flex-1"
|
|
1649
|
-
}
|
|
1650
|
-
), /* @__PURE__ */ React4.createElement(
|
|
1651
|
-
"button",
|
|
1652
|
-
{
|
|
1653
|
-
onClick: handleSendFollowUpMessage,
|
|
1654
|
-
className: "py-1.5 px-3 bg-gray-800 text-white border border-gray-600 rounded cursor-pointer font-mono text-xs"
|
|
1655
|
-
},
|
|
1656
|
-
"Send Follow-Up"
|
|
1657
|
-
)), /* @__PURE__ */ React4.createElement("div", { className: "flex gap-2 items-center" }, /* @__PURE__ */ React4.createElement(
|
|
1658
|
-
"input",
|
|
1659
|
-
{
|
|
1660
|
-
type: "text",
|
|
1661
|
-
value: externalUrl,
|
|
1662
|
-
onChange: (e) => setExternalUrl(e.target.value),
|
|
1663
|
-
placeholder: "External URL",
|
|
1664
|
-
className: "py-1.5 px-2 bg-[#1a1a1a] text-white border border-gray-700 rounded font-mono text-xs flex-1"
|
|
1665
|
-
}
|
|
1666
|
-
), /* @__PURE__ */ React4.createElement(
|
|
1667
|
-
"button",
|
|
1668
|
-
{
|
|
1669
|
-
onClick: handleOpenExternal,
|
|
1670
|
-
className: "py-1.5 px-3 bg-gray-800 text-white border border-gray-600 rounded cursor-pointer font-mono text-xs"
|
|
1671
|
-
},
|
|
1672
|
-
"Open Link"
|
|
1673
|
-
)), /* @__PURE__ */ React4.createElement("div", { className: "flex gap-2 items-center" }, /* @__PURE__ */ React4.createElement("span", { className: "w-[150px] text-xs" }, "Display Mode:"), /* @__PURE__ */ React4.createElement(
|
|
1674
|
-
"button",
|
|
1675
|
-
{
|
|
1676
|
-
onClick: () => handleRequestDisplayMode("inline"),
|
|
1677
|
-
className: "py-1.5 px-3 bg-gray-800 text-white border border-gray-600 rounded cursor-pointer font-mono text-xs flex-1"
|
|
1678
|
-
},
|
|
1679
|
-
"Inline"
|
|
1680
|
-
), /* @__PURE__ */ React4.createElement(
|
|
1681
|
-
"button",
|
|
1682
|
-
{
|
|
1683
|
-
onClick: () => handleRequestDisplayMode("pip"),
|
|
1684
|
-
className: "py-1.5 px-3 bg-gray-800 text-white border border-gray-600 rounded cursor-pointer font-mono text-xs flex-1"
|
|
1685
|
-
},
|
|
1686
|
-
"PiP"
|
|
1687
|
-
), /* @__PURE__ */ React4.createElement(
|
|
1688
|
-
"button",
|
|
1689
|
-
{
|
|
1690
|
-
onClick: () => handleRequestDisplayMode("fullscreen"),
|
|
1691
|
-
className: "py-1.5 px-3 bg-gray-800 text-white border border-gray-600 rounded cursor-pointer font-mono text-xs flex-1"
|
|
1692
|
-
},
|
|
1693
|
-
"Fullscreen"
|
|
1694
|
-
)), /* @__PURE__ */ React4.createElement("div", { className: "flex gap-2 items-center" }, /* @__PURE__ */ React4.createElement(
|
|
1695
|
-
"button",
|
|
1696
|
-
{
|
|
1697
|
-
onClick: handleSetState,
|
|
1698
|
-
className: "py-1.5 px-3 bg-gray-800 text-white border border-gray-600 rounded cursor-pointer font-mono text-xs"
|
|
1699
|
-
},
|
|
1700
|
-
"Set State (Add Timestamp)"
|
|
1701
|
-
)), actionResult && /* @__PURE__ */ React4.createElement("div", { className: "mt-2 p-2 bg-[#1a1a1a] border border-gray-700 rounded whitespace-pre-wrap break-all text-[11px] max-h-[200px] overflow-auto" }, /* @__PURE__ */ React4.createElement("div", { className: "font-bold mb-1 text-gray-400" }, "Result:"), actionResult, /* @__PURE__ */ React4.createElement(
|
|
1702
|
-
"button",
|
|
1703
|
-
{
|
|
1704
|
-
onClick: () => setActionResult(""),
|
|
1705
|
-
className: "mt-2 py-1 px-2 bg-gray-800 text-white border border-gray-600 rounded cursor-pointer font-mono text-[11px]"
|
|
1706
|
-
},
|
|
1707
|
-
"Clear"
|
|
1708
|
-
))))
|
|
1709
|
-
));
|
|
1710
|
-
}
|
|
1711
|
-
__name(WidgetControls, "WidgetControls");
|
|
1712
|
-
|
|
1713
|
-
// src/react/McpUseProvider.tsx
|
|
1714
|
-
import React5, {
|
|
1715
|
-
StrictMode,
|
|
1716
|
-
useCallback as useCallback3,
|
|
1717
|
-
useEffect as useEffect5,
|
|
1718
|
-
useRef as useRef3,
|
|
1719
|
-
useState as useState5
|
|
1720
|
-
} from "react";
|
|
1721
|
-
function getBasename() {
|
|
1722
|
-
if (typeof window === "undefined") return "/";
|
|
1723
|
-
const path = window.location.pathname;
|
|
1724
|
-
const match = path.match(/^(\/inspector\/api\/dev-widget\/[^/]+)/);
|
|
1725
|
-
if (match) {
|
|
1726
|
-
return match[1];
|
|
1727
|
-
}
|
|
1728
|
-
return "/";
|
|
1729
|
-
}
|
|
1730
|
-
__name(getBasename, "getBasename");
|
|
1731
|
-
var HEIGHT_DEBOUNCE_MS = 150;
|
|
1732
|
-
var MIN_HEIGHT_CHANGE_PX = 5;
|
|
1733
|
-
function McpUseProvider({
|
|
1734
|
-
children,
|
|
1735
|
-
debugger: enableDebugger = false,
|
|
1736
|
-
viewControls = false,
|
|
1737
|
-
autoSize = false
|
|
1738
|
-
}) {
|
|
1739
|
-
const basename = getBasename();
|
|
1740
|
-
const containerRef = useRef3(null);
|
|
1741
|
-
const lastHeightRef = useRef3(0);
|
|
1742
|
-
const debounceTimeoutRef = useRef3(null);
|
|
1743
|
-
const notificationInProgressRef = useRef3(false);
|
|
1744
|
-
const [BrowserRouter, setBrowserRouter] = useState5(null);
|
|
1745
|
-
const [routerError, setRouterError] = useState5(null);
|
|
1746
|
-
const [isRouterLoading, setIsRouterLoading] = useState5(true);
|
|
1747
|
-
useEffect5(() => {
|
|
1748
|
-
let mounted = true;
|
|
1749
|
-
(async () => {
|
|
1750
|
-
try {
|
|
1751
|
-
const routerModule = await import("react-router");
|
|
1752
|
-
if (mounted) {
|
|
1753
|
-
setBrowserRouter(() => routerModule.BrowserRouter);
|
|
1754
|
-
setIsRouterLoading(false);
|
|
1755
|
-
}
|
|
1756
|
-
} catch (error) {
|
|
1757
|
-
if (mounted) {
|
|
1758
|
-
setRouterError(
|
|
1759
|
-
new Error(
|
|
1760
|
-
"\u274C react-router not installed!\n\nTo use MCP widgets with McpUseProvider, you need to install:\n\n npm install react-router\n # or\n pnpm add react-router\n\nThis dependency is automatically included in projects created with 'create-mcp-use-app'."
|
|
1761
|
-
)
|
|
1762
|
-
);
|
|
1763
|
-
setIsRouterLoading(false);
|
|
1764
|
-
}
|
|
1765
|
-
}
|
|
1766
|
-
})();
|
|
1767
|
-
return () => {
|
|
1768
|
-
mounted = false;
|
|
1769
|
-
};
|
|
1770
|
-
}, []);
|
|
1771
|
-
const notifyHeight = useCallback3((height) => {
|
|
1772
|
-
if (typeof window !== "undefined" && window.openai?.notifyIntrinsicHeight) {
|
|
1773
|
-
notificationInProgressRef.current = true;
|
|
1774
|
-
window.openai.notifyIntrinsicHeight(height).then(() => {
|
|
1775
|
-
notificationInProgressRef.current = false;
|
|
1776
|
-
}).catch((error) => {
|
|
1777
|
-
notificationInProgressRef.current = false;
|
|
1778
|
-
console.error(
|
|
1779
|
-
"[McpUseProvider] Failed to notify intrinsic height:",
|
|
1780
|
-
error
|
|
1781
|
-
);
|
|
1782
|
-
});
|
|
1783
|
-
}
|
|
1784
|
-
}, []);
|
|
1785
|
-
const debouncedNotifyHeight = useCallback3(
|
|
1786
|
-
(height) => {
|
|
1787
|
-
if (debounceTimeoutRef.current) {
|
|
1788
|
-
clearTimeout(debounceTimeoutRef.current);
|
|
1789
|
-
}
|
|
1790
|
-
debounceTimeoutRef.current = setTimeout(() => {
|
|
1791
|
-
const heightDiff = Math.abs(height - lastHeightRef.current);
|
|
1792
|
-
if (heightDiff >= MIN_HEIGHT_CHANGE_PX && height > 0) {
|
|
1793
|
-
lastHeightRef.current = height;
|
|
1794
|
-
notifyHeight(height);
|
|
1795
|
-
}
|
|
1796
|
-
}, HEIGHT_DEBOUNCE_MS);
|
|
1797
|
-
},
|
|
1798
|
-
[notifyHeight]
|
|
1799
|
-
);
|
|
1800
|
-
useEffect5(() => {
|
|
1801
|
-
if (!autoSize) {
|
|
1802
|
-
return;
|
|
1803
|
-
}
|
|
1804
|
-
const container = containerRef.current;
|
|
1805
|
-
if (!container || typeof ResizeObserver === "undefined") {
|
|
1806
|
-
return;
|
|
1807
|
-
}
|
|
1808
|
-
const observer = new ResizeObserver((entries) => {
|
|
1809
|
-
if (notificationInProgressRef.current) {
|
|
1810
|
-
return;
|
|
1811
|
-
}
|
|
1812
|
-
for (const entry of entries) {
|
|
1813
|
-
const height = entry.contentRect.height;
|
|
1814
|
-
const scrollHeight = entry.target.scrollHeight;
|
|
1815
|
-
const intrinsicHeight = Math.max(height, scrollHeight);
|
|
1816
|
-
debouncedNotifyHeight(intrinsicHeight);
|
|
1817
|
-
}
|
|
1818
|
-
});
|
|
1819
|
-
observer.observe(container);
|
|
1820
|
-
const initialHeight = Math.max(
|
|
1821
|
-
container.offsetHeight,
|
|
1822
|
-
container.scrollHeight
|
|
1823
|
-
);
|
|
1824
|
-
if (initialHeight > 0) {
|
|
1825
|
-
debouncedNotifyHeight(initialHeight);
|
|
1826
|
-
}
|
|
1827
|
-
return () => {
|
|
1828
|
-
observer.disconnect();
|
|
1829
|
-
if (debounceTimeoutRef.current) {
|
|
1830
|
-
clearTimeout(debounceTimeoutRef.current);
|
|
1831
|
-
debounceTimeoutRef.current = null;
|
|
1832
|
-
}
|
|
1833
|
-
notificationInProgressRef.current = false;
|
|
1834
|
-
};
|
|
1835
|
-
}, [autoSize, debouncedNotifyHeight]);
|
|
1836
|
-
if (isRouterLoading) {
|
|
1837
|
-
return /* @__PURE__ */ React5.createElement(StrictMode, null, /* @__PURE__ */ React5.createElement(ThemeProvider, null, /* @__PURE__ */ React5.createElement("div", { style: { padding: "20px", textAlign: "center" } }, "Loading...")));
|
|
1838
|
-
}
|
|
1839
|
-
if (routerError) {
|
|
1840
|
-
throw routerError;
|
|
1841
|
-
}
|
|
1842
|
-
let content = children;
|
|
1843
|
-
content = /* @__PURE__ */ React5.createElement(ErrorBoundary, null, content);
|
|
1844
|
-
if (enableDebugger || viewControls) {
|
|
1845
|
-
content = /* @__PURE__ */ React5.createElement(WidgetControls, { debugger: enableDebugger, viewControls }, content);
|
|
1846
|
-
}
|
|
1847
|
-
if (BrowserRouter) {
|
|
1848
|
-
content = /* @__PURE__ */ React5.createElement(BrowserRouter, { basename }, content);
|
|
1849
|
-
}
|
|
1850
|
-
content = /* @__PURE__ */ React5.createElement(ThemeProvider, null, content);
|
|
1851
|
-
if (autoSize) {
|
|
1852
|
-
const containerStyle = {
|
|
1853
|
-
width: "100%",
|
|
1854
|
-
minHeight: 0
|
|
1855
|
-
};
|
|
1856
|
-
content = /* @__PURE__ */ React5.createElement("div", { ref: containerRef, style: containerStyle }, content);
|
|
1857
|
-
}
|
|
1858
|
-
return /* @__PURE__ */ React5.createElement(StrictMode, null, content);
|
|
1859
|
-
}
|
|
1860
|
-
__name(McpUseProvider, "McpUseProvider");
|
|
1861
|
-
|
|
1862
|
-
export {
|
|
1863
|
-
useMcp,
|
|
1864
|
-
ErrorBoundary,
|
|
1865
|
-
Image,
|
|
1866
|
-
useWidget,
|
|
1867
|
-
useWidgetProps,
|
|
1868
|
-
useWidgetTheme,
|
|
1869
|
-
useWidgetState,
|
|
1870
|
-
ThemeProvider,
|
|
1871
|
-
WidgetControls,
|
|
1872
|
-
McpUseProvider
|
|
1873
|
-
};
|