mcp-app-studio 0.5.1 → 0.6.0
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 +66 -18
- package/dist/{bridge-BXW_-p2R.d.ts → bridge-BKLezf-H.d.ts} +13 -0
- package/dist/{chunk-2OPSDEPI.js → chunk-IEZAKOIG.js} +34 -2
- package/dist/{chunk-4LAH4JH6.js → chunk-QNH5NSRH.js} +0 -19
- package/dist/cli/index.js +162 -133
- package/dist/core/index.d.ts +11 -29
- package/dist/core/index.js +1 -3
- package/dist/index.d.ts +114 -33
- package/dist/index.js +73 -49
- package/dist/platforms/mcp/index.d.ts +2 -2
- package/dist/platforms/mcp/index.js +13 -3
- package/package.json +4 -8
- package/dist/chunk-EPZCYA26.js +0 -162
- package/dist/platforms/chatgpt/index.d.ts +0 -159
- package/dist/platforms/chatgpt/index.js +0 -167
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Platform, ExtendedBridge, ToolResult, HostCapabilities, DisplayMode, FeatureKey, HostContext, ContentBlock } from './core/index.js';
|
|
2
|
-
export { AudioContentBlock,
|
|
2
|
+
export { AudioContentBlock, ChatMessage, ContainerDimensions, ContentBlockAnnotations, ContentBlockIcon, HostBridge, HostContextChangedCallback, HostStyles, ImageContentBlock, MCP_CAPABILITIES, ResourceContentBlock, ResourceLinkContentBlock, TeardownCallback, TextContentBlock, Theme, ToolCancelledCallback, ToolInputCallback, ToolInputPartialCallback, ToolResultCallback, hasFeature, imageBlock, textBlock } from './core/index.js';
|
|
3
3
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
4
4
|
import { ReactNode } from 'react';
|
|
5
|
-
import { A as AppCapabilities } from './bridge-
|
|
5
|
+
import { A as AppCapabilities } from './bridge-BKLezf-H.js';
|
|
6
6
|
import '@modelcontextprotocol/ext-apps';
|
|
7
7
|
|
|
8
8
|
/**
|
|
@@ -39,17 +39,18 @@ declare function detectPlatformDetailed(): DetectionResult;
|
|
|
39
39
|
/**
|
|
40
40
|
* Detects the current platform the widget is running on.
|
|
41
41
|
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
42
|
+
* Host detection:
|
|
43
|
+
* - URL has `?mcp-host` param → MCP
|
|
44
|
+
* - `window.__MCP_HOST__` exists → MCP
|
|
45
|
+
* - iframe has `data-mcp-host` attribute → MCP
|
|
46
|
+
* - None of the above → unknown
|
|
47
|
+
*
|
|
48
|
+
* Note: `window.openai` is a ChatGPT-only *extensions* layer, not the MCP host protocol.
|
|
48
49
|
*
|
|
49
50
|
* **Debugging tip:** Set `window.__MCP_APP_STUDIO_DEBUG__ = true` before
|
|
50
51
|
* loading your widget to see detailed detection logs in the console.
|
|
51
52
|
*
|
|
52
|
-
* @returns The detected platform: "
|
|
53
|
+
* @returns The detected platform: "mcp" or "unknown"
|
|
53
54
|
*
|
|
54
55
|
* @example
|
|
55
56
|
* ```ts
|
|
@@ -61,16 +62,16 @@ declare function detectPlatformDetailed(): DetectionResult;
|
|
|
61
62
|
*/
|
|
62
63
|
declare function detectPlatform(): Platform;
|
|
63
64
|
/**
|
|
64
|
-
* Returns true if
|
|
65
|
+
* Returns true if ChatGPT-only extensions are available (`window.openai`).
|
|
65
66
|
*
|
|
66
67
|
* @example
|
|
67
68
|
* ```ts
|
|
68
|
-
* if (
|
|
69
|
-
* // Use ChatGPT-
|
|
69
|
+
* if (hasChatGPTExtensions()) {
|
|
70
|
+
* // Use ChatGPT-only extensions (e.g. widgetState, file upload)
|
|
70
71
|
* }
|
|
71
72
|
* ```
|
|
72
73
|
*/
|
|
73
|
-
declare function
|
|
74
|
+
declare function hasChatGPTExtensions(): boolean;
|
|
74
75
|
/**
|
|
75
76
|
* Returns true if running inside an MCP host (e.g., Claude Desktop).
|
|
76
77
|
*
|
|
@@ -209,10 +210,10 @@ declare function useCapabilities(): HostCapabilities | null;
|
|
|
209
210
|
*/
|
|
210
211
|
declare function useToolInput<T = Record<string, unknown>>(): T | null;
|
|
211
212
|
/**
|
|
212
|
-
* Returns partial tool input as it's being streamed (
|
|
213
|
+
* Returns partial tool input as it's being streamed (host-dependent).
|
|
213
214
|
* Useful for showing real-time feedback as the user types.
|
|
214
215
|
*
|
|
215
|
-
* **
|
|
216
|
+
* **Host support:** MCP Apps hosts that stream partial input. Returns null otherwise.
|
|
216
217
|
*
|
|
217
218
|
* @typeParam T - The expected shape of the tool input
|
|
218
219
|
* @returns Partial tool input, or null
|
|
@@ -370,26 +371,19 @@ declare function useOpenLink(): (url: string) => Promise<void>;
|
|
|
370
371
|
*/
|
|
371
372
|
declare function useSendMessage(): (text: string) => Promise<void>;
|
|
372
373
|
/**
|
|
373
|
-
* Returns a function to update the model
|
|
374
|
+
* Returns a function to update the model-visible context.
|
|
374
375
|
* Use this to provide additional context to the AI model.
|
|
375
376
|
*
|
|
376
|
-
* **Platform support:** MCP only. Logs a warning on ChatGPT.
|
|
377
|
-
*
|
|
378
377
|
* @returns Async function to update model context
|
|
379
378
|
*
|
|
380
379
|
* @example
|
|
381
380
|
* ```tsx
|
|
382
381
|
* function DataViewer({ data }: { data: object }) {
|
|
383
382
|
* const updateContext = useUpdateModelContext();
|
|
384
|
-
* const platform = usePlatform();
|
|
385
383
|
*
|
|
386
384
|
* useEffect(() => {
|
|
387
|
-
*
|
|
388
|
-
*
|
|
389
|
-
* structuredContent: { currentData: data }
|
|
390
|
-
* });
|
|
391
|
-
* }
|
|
392
|
-
* }, [data, platform, updateContext]);
|
|
385
|
+
* updateContext({ structuredContent: { currentData: data } });
|
|
386
|
+
* }, [data, updateContext]);
|
|
393
387
|
*
|
|
394
388
|
* return <pre>{JSON.stringify(data, null, 2)}</pre>;
|
|
395
389
|
* }
|
|
@@ -400,10 +394,9 @@ declare function useUpdateModelContext(): (ctx: {
|
|
|
400
394
|
structuredContent?: Record<string, unknown>;
|
|
401
395
|
}) => Promise<void>;
|
|
402
396
|
/**
|
|
403
|
-
* Returns persisted widget state and a setter (ChatGPT only).
|
|
397
|
+
* Returns persisted widget state and a setter (ChatGPT extensions only).
|
|
404
398
|
* State is preserved across page refreshes and conversation turns.
|
|
405
|
-
*
|
|
406
|
-
* **Platform support:** ChatGPT only. Logs a warning on MCP.
|
|
399
|
+
* Requires `window.openai` (feature-detected by the SDK).
|
|
407
400
|
*
|
|
408
401
|
* @typeParam T - The shape of your widget state
|
|
409
402
|
* @returns Tuple of [state, setState]
|
|
@@ -438,10 +431,8 @@ declare function useWidgetState<T = Record<string, unknown>>(): [
|
|
|
438
431
|
(state: T | null) => void
|
|
439
432
|
];
|
|
440
433
|
/**
|
|
441
|
-
* Returns a function for structured logging
|
|
442
|
-
*
|
|
443
|
-
*
|
|
444
|
-
* **Platform support:** MCP only. Falls back to console.log on other platforms.
|
|
434
|
+
* Returns a function for structured logging when the current host supports it.
|
|
435
|
+
* Falls back to `console.log` otherwise.
|
|
445
436
|
*
|
|
446
437
|
* @returns Log function that accepts level and message
|
|
447
438
|
*
|
|
@@ -505,4 +496,94 @@ declare function useLog(): (level: "debug" | "info" | "warning" | "error", data:
|
|
|
505
496
|
*/
|
|
506
497
|
declare function useFeature(feature: FeatureKey): boolean;
|
|
507
498
|
|
|
508
|
-
|
|
499
|
+
/**
|
|
500
|
+
* ChatGPT-only extensions.
|
|
501
|
+
*
|
|
502
|
+
* ChatGPT is an MCP Apps host (standard `ui/*` bridge). It may also expose
|
|
503
|
+
* optional extras via `window.openai` (widget state, file APIs, host modals…).
|
|
504
|
+
*
|
|
505
|
+
* This module intentionally treats `window.openai` as an *optional* layer:
|
|
506
|
+
* - Never required for MCP Apps interoperability
|
|
507
|
+
* - Always feature-detected before use
|
|
508
|
+
*/
|
|
509
|
+
type ChatGPTExtensions = {
|
|
510
|
+
theme?: "light" | "dark";
|
|
511
|
+
locale?: string;
|
|
512
|
+
displayMode?: "pip" | "inline" | "fullscreen";
|
|
513
|
+
previousDisplayMode?: "pip" | "inline" | "fullscreen" | null;
|
|
514
|
+
maxHeight?: number;
|
|
515
|
+
safeArea?: {
|
|
516
|
+
insets: {
|
|
517
|
+
top: number;
|
|
518
|
+
bottom: number;
|
|
519
|
+
left: number;
|
|
520
|
+
right: number;
|
|
521
|
+
};
|
|
522
|
+
};
|
|
523
|
+
userAgent?: Record<string, unknown>;
|
|
524
|
+
view?: {
|
|
525
|
+
mode: "modal" | "inline";
|
|
526
|
+
params: Record<string, unknown> | null;
|
|
527
|
+
} | null;
|
|
528
|
+
userLocation?: Record<string, unknown> | null;
|
|
529
|
+
toolInput?: Record<string, unknown>;
|
|
530
|
+
toolOutput?: Record<string, unknown> | null;
|
|
531
|
+
toolResponseMetadata?: Record<string, unknown> | null;
|
|
532
|
+
widgetState?: Record<string, unknown> | null;
|
|
533
|
+
setWidgetState?: (state: Record<string, unknown> | null) => void;
|
|
534
|
+
callTool?: (name: string, args: Record<string, unknown>) => Promise<unknown>;
|
|
535
|
+
sendFollowUpMessage?: (args: {
|
|
536
|
+
prompt: string;
|
|
537
|
+
}) => Promise<void>;
|
|
538
|
+
openExternal?: (payload: {
|
|
539
|
+
href: string;
|
|
540
|
+
}) => void;
|
|
541
|
+
notifyIntrinsicHeight?: (height: number) => void;
|
|
542
|
+
requestDisplayMode?: (args: {
|
|
543
|
+
mode: string;
|
|
544
|
+
}) => Promise<{
|
|
545
|
+
mode: string;
|
|
546
|
+
}>;
|
|
547
|
+
uploadFile?: (file: File) => Promise<{
|
|
548
|
+
fileId: string;
|
|
549
|
+
}>;
|
|
550
|
+
getFileDownloadUrl?: (args: {
|
|
551
|
+
fileId: string;
|
|
552
|
+
}) => Promise<{
|
|
553
|
+
downloadUrl: string;
|
|
554
|
+
}>;
|
|
555
|
+
setOpenInAppUrl?: (args: {
|
|
556
|
+
href: string;
|
|
557
|
+
}) => void;
|
|
558
|
+
requestCheckout?: (...args: unknown[]) => unknown;
|
|
559
|
+
requestClose?: () => void;
|
|
560
|
+
requestModal?: (options: Record<string, unknown>) => Promise<void>;
|
|
561
|
+
};
|
|
562
|
+
/**
|
|
563
|
+
* Wraps an MCP-first bridge with ChatGPT-only extensions when `window.openai`
|
|
564
|
+
* exists.
|
|
565
|
+
*
|
|
566
|
+
* Note: this function mutates `bridge` in-place so class instances preserve
|
|
567
|
+
* prototype methods.
|
|
568
|
+
*
|
|
569
|
+
* The returned bridge:
|
|
570
|
+
* - Delegates all MCP behavior to `bridge`
|
|
571
|
+
* - Adds ChatGPT-only helpers (widget state, file APIs, modals) when available
|
|
572
|
+
*
|
|
573
|
+
* @param bridge - Base MCP bridge to extend.
|
|
574
|
+
* @returns The same `bridge` instance with ChatGPT-only extensions attached
|
|
575
|
+
* when available.
|
|
576
|
+
*/
|
|
577
|
+
declare function withChatGPTExtensions(bridge: ExtendedBridge): ExtendedBridge;
|
|
578
|
+
declare global {
|
|
579
|
+
interface Window {
|
|
580
|
+
/**
|
|
581
|
+
* ChatGPT-only extension layer. Optional.
|
|
582
|
+
*
|
|
583
|
+
* Prefer using the MCP Apps bridge (`ui/*`) for core functionality.
|
|
584
|
+
*/
|
|
585
|
+
openai?: ChatGPTExtensions;
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
export { type ChatGPTExtensions, ContentBlock, type DetectionResult, DisplayMode, ExtendedBridge, FeatureKey, HostCapabilities, HostContext, Platform, ToolResult, UniversalProvider, type UniversalProviderProps, detectPlatform, detectPlatformDetailed, disableDebugMode, enableDebugMode, hasChatGPTExtensions, isMCP, useCallTool, useCapabilities, useDisplayMode, useFeature, useHostContext, useLog, useOpenLink, usePlatform, useSendMessage, useTheme, useToolInput, useToolInputPartial, useToolResult, useUniversalBridge, useUpdateModelContext, useWidgetState, withChatGPTExtensions };
|
package/dist/index.js
CHANGED
|
@@ -2,17 +2,13 @@ import {
|
|
|
2
2
|
imageBlock,
|
|
3
3
|
textBlock
|
|
4
4
|
} from "./chunk-KRCGOYZ5.js";
|
|
5
|
-
import {
|
|
6
|
-
ChatGPTBridge
|
|
7
|
-
} from "./chunk-EPZCYA26.js";
|
|
8
5
|
import {
|
|
9
6
|
MCPBridge
|
|
10
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-IEZAKOIG.js";
|
|
11
8
|
import {
|
|
12
|
-
CHATGPT_CAPABILITIES,
|
|
13
9
|
MCP_CAPABILITIES,
|
|
14
10
|
hasFeature
|
|
15
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-QNH5NSRH.js";
|
|
16
12
|
|
|
17
13
|
// src/universal/detect.ts
|
|
18
14
|
var MCP_MARKERS = {
|
|
@@ -42,8 +38,7 @@ function detectPlatformDetailed() {
|
|
|
42
38
|
}
|
|
43
39
|
if (window["openai"]) {
|
|
44
40
|
checks.windowOpenai = true;
|
|
45
|
-
debugLog("detectPlatform: Found window.openai
|
|
46
|
-
return { platform: "chatgpt", detectedBy: "window.openai", checks };
|
|
41
|
+
debugLog("detectPlatform: Found window.openai (extensions)");
|
|
47
42
|
}
|
|
48
43
|
try {
|
|
49
44
|
const params = new URLSearchParams(window.location.search);
|
|
@@ -97,8 +92,9 @@ function detectPlatformDetailed() {
|
|
|
97
92
|
function detectPlatform() {
|
|
98
93
|
return detectPlatformDetailed().platform;
|
|
99
94
|
}
|
|
100
|
-
function
|
|
101
|
-
|
|
95
|
+
function hasChatGPTExtensions() {
|
|
96
|
+
if (typeof window === "undefined") return false;
|
|
97
|
+
return Boolean(window["openai"]);
|
|
102
98
|
}
|
|
103
99
|
function isMCP() {
|
|
104
100
|
return detectPlatform() === "mcp";
|
|
@@ -124,6 +120,48 @@ import {
|
|
|
124
120
|
useEffect,
|
|
125
121
|
useState
|
|
126
122
|
} from "react";
|
|
123
|
+
|
|
124
|
+
// src/extensions/chatgpt.ts
|
|
125
|
+
function getChatGPTExtensions() {
|
|
126
|
+
if (typeof window === "undefined") return null;
|
|
127
|
+
const openai = window["openai"];
|
|
128
|
+
if (!openai || typeof openai !== "object") return null;
|
|
129
|
+
return openai;
|
|
130
|
+
}
|
|
131
|
+
function withExtensionsCapabilities(base, openai) {
|
|
132
|
+
return {
|
|
133
|
+
...base,
|
|
134
|
+
widgetState: typeof openai.setWidgetState === "function",
|
|
135
|
+
fileUpload: typeof openai.uploadFile === "function",
|
|
136
|
+
fileDownload: typeof openai.getFileDownloadUrl === "function",
|
|
137
|
+
closeWidget: typeof openai.requestClose === "function",
|
|
138
|
+
modal: typeof openai.requestModal === "function"
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
function withChatGPTExtensions(bridge) {
|
|
142
|
+
const openai = getChatGPTExtensions();
|
|
143
|
+
if (!openai) return bridge;
|
|
144
|
+
bridge.capabilities = withExtensionsCapabilities(bridge.capabilities, openai);
|
|
145
|
+
if (typeof openai.setWidgetState === "function") {
|
|
146
|
+
bridge.setWidgetState = (state) => openai.setWidgetState?.(state);
|
|
147
|
+
}
|
|
148
|
+
bridge.getWidgetState = () => openai.widgetState ?? null;
|
|
149
|
+
if (typeof openai.uploadFile === "function") {
|
|
150
|
+
bridge.uploadFile = (file) => openai.uploadFile(file);
|
|
151
|
+
}
|
|
152
|
+
if (typeof openai.getFileDownloadUrl === "function") {
|
|
153
|
+
bridge.getFileDownloadUrl = (fileId) => openai.getFileDownloadUrl({ fileId });
|
|
154
|
+
}
|
|
155
|
+
if (typeof openai.requestClose === "function") {
|
|
156
|
+
bridge.requestClose = () => openai.requestClose?.();
|
|
157
|
+
}
|
|
158
|
+
if (typeof openai.requestModal === "function") {
|
|
159
|
+
bridge.requestModal = (options) => openai.requestModal(options);
|
|
160
|
+
}
|
|
161
|
+
return bridge;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// src/universal/provider.tsx
|
|
127
165
|
import { jsx } from "react/jsx-runtime";
|
|
128
166
|
var UniversalContext = createContext(null);
|
|
129
167
|
var PlatformContext = createContext("unknown");
|
|
@@ -137,24 +175,25 @@ function UniversalProvider({
|
|
|
137
175
|
const [ready, setReady] = useState(false);
|
|
138
176
|
useEffect(() => {
|
|
139
177
|
let cancelled = false;
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
newBridge = new ChatGPTBridge();
|
|
145
|
-
} else if (detected === "mcp") {
|
|
146
|
-
newBridge = new MCPBridge(appInfo, appCapabilities);
|
|
147
|
-
} else {
|
|
178
|
+
const detectedPlatform = detectPlatform();
|
|
179
|
+
if (detectedPlatform !== "mcp") {
|
|
180
|
+
setBridge(null);
|
|
181
|
+
setPlatform("unknown");
|
|
148
182
|
setReady(true);
|
|
149
183
|
return;
|
|
150
184
|
}
|
|
185
|
+
const newBridge = withChatGPTExtensions(
|
|
186
|
+
new MCPBridge(appInfo, appCapabilities)
|
|
187
|
+
);
|
|
151
188
|
newBridge.connect().then(() => {
|
|
152
189
|
if (cancelled) return;
|
|
153
190
|
setBridge(newBridge);
|
|
191
|
+
setPlatform("mcp");
|
|
154
192
|
setReady(true);
|
|
155
193
|
}).catch((error) => {
|
|
156
194
|
if (cancelled) return;
|
|
157
195
|
console.error("[mcp-app-studio] Bridge connection failed:", error);
|
|
196
|
+
setPlatform("unknown");
|
|
158
197
|
setReady(true);
|
|
159
198
|
});
|
|
160
199
|
return () => {
|
|
@@ -225,13 +264,11 @@ function useToolInput() {
|
|
|
225
264
|
}
|
|
226
265
|
function useToolInputPartial() {
|
|
227
266
|
const bridge = useUniversalBridge();
|
|
228
|
-
const platform = usePlatform();
|
|
229
267
|
const [input, setInput] = useState2(null);
|
|
230
268
|
useEffect2(() => {
|
|
231
|
-
if (!bridge
|
|
232
|
-
if (!bridge.onToolInputPartial) return;
|
|
269
|
+
if (!bridge?.onToolInputPartial) return;
|
|
233
270
|
return bridge.onToolInputPartial((args) => setInput(args));
|
|
234
|
-
}, [bridge
|
|
271
|
+
}, [bridge]);
|
|
235
272
|
return input;
|
|
236
273
|
}
|
|
237
274
|
function useToolResult() {
|
|
@@ -312,64 +349,51 @@ function useSendMessage() {
|
|
|
312
349
|
}
|
|
313
350
|
function useUpdateModelContext() {
|
|
314
351
|
const bridge = useUniversalBridge();
|
|
315
|
-
const platform = usePlatform();
|
|
316
352
|
return useCallback(
|
|
317
353
|
async (ctx) => {
|
|
318
|
-
if (
|
|
354
|
+
if (!bridge?.updateModelContext) {
|
|
319
355
|
console.warn(
|
|
320
|
-
"useUpdateModelContext:
|
|
356
|
+
"useUpdateModelContext: updateModelContext not available on the current host."
|
|
321
357
|
);
|
|
322
358
|
return;
|
|
323
359
|
}
|
|
324
|
-
if (!bridge?.updateModelContext) {
|
|
325
|
-
throw new Error(
|
|
326
|
-
"updateModelContext not available on the current bridge."
|
|
327
|
-
);
|
|
328
|
-
}
|
|
329
360
|
return bridge.updateModelContext(ctx);
|
|
330
361
|
},
|
|
331
|
-
[bridge
|
|
362
|
+
[bridge]
|
|
332
363
|
);
|
|
333
364
|
}
|
|
334
365
|
function useWidgetState() {
|
|
335
366
|
const bridge = useUniversalBridge();
|
|
336
|
-
const platform = usePlatform();
|
|
337
367
|
const [state, setState] = useState2(() => {
|
|
338
|
-
if (
|
|
368
|
+
if (!bridge?.getWidgetState) return null;
|
|
339
369
|
return bridge.getWidgetState();
|
|
340
370
|
});
|
|
341
371
|
const setWidgetState = useCallback(
|
|
342
372
|
(newState) => {
|
|
343
|
-
if (
|
|
373
|
+
if (!bridge?.setWidgetState) {
|
|
344
374
|
console.warn(
|
|
345
|
-
"useWidgetState:
|
|
375
|
+
"useWidgetState: widget state is not available on the current host."
|
|
346
376
|
);
|
|
347
377
|
return;
|
|
348
378
|
}
|
|
349
|
-
if (!bridge?.setWidgetState) return;
|
|
350
379
|
bridge.setWidgetState(newState);
|
|
351
380
|
setState(newState);
|
|
352
381
|
},
|
|
353
|
-
[bridge
|
|
382
|
+
[bridge]
|
|
354
383
|
);
|
|
355
384
|
return [state, setWidgetState];
|
|
356
385
|
}
|
|
357
386
|
function useLog() {
|
|
358
387
|
const bridge = useUniversalBridge();
|
|
359
|
-
const platform = usePlatform();
|
|
360
388
|
return useCallback(
|
|
361
389
|
(level, data) => {
|
|
362
|
-
if (
|
|
363
|
-
|
|
364
|
-
"useLog: Structured logging is only available on MCP hosts. Falling back to console.log."
|
|
365
|
-
);
|
|
366
|
-
console.log(`[${level}]`, data);
|
|
390
|
+
if (bridge?.sendLog) {
|
|
391
|
+
bridge.sendLog(level, data);
|
|
367
392
|
return;
|
|
368
393
|
}
|
|
369
|
-
|
|
370
|
-
bridge.sendLog(level, data);
|
|
394
|
+
console.log(`[${level}]`, data);
|
|
371
395
|
},
|
|
372
|
-
[bridge
|
|
396
|
+
[bridge]
|
|
373
397
|
);
|
|
374
398
|
}
|
|
375
399
|
function useFeature(feature) {
|
|
@@ -377,16 +401,15 @@ function useFeature(feature) {
|
|
|
377
401
|
return hasFeature(capabilities, feature);
|
|
378
402
|
}
|
|
379
403
|
export {
|
|
380
|
-
CHATGPT_CAPABILITIES,
|
|
381
404
|
MCP_CAPABILITIES,
|
|
382
405
|
UniversalProvider,
|
|
383
406
|
detectPlatform,
|
|
384
407
|
detectPlatformDetailed,
|
|
385
408
|
disableDebugMode,
|
|
386
409
|
enableDebugMode,
|
|
410
|
+
hasChatGPTExtensions,
|
|
387
411
|
hasFeature,
|
|
388
412
|
imageBlock,
|
|
389
|
-
isChatGPT,
|
|
390
413
|
isMCP,
|
|
391
414
|
textBlock,
|
|
392
415
|
useCallTool,
|
|
@@ -404,5 +427,6 @@ export {
|
|
|
404
427
|
useToolResult,
|
|
405
428
|
useUniversalBridge,
|
|
406
429
|
useUpdateModelContext,
|
|
407
|
-
useWidgetState
|
|
430
|
+
useWidgetState,
|
|
431
|
+
withChatGPTExtensions
|
|
408
432
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { A as AppCapabilities } from '../../bridge-
|
|
2
|
-
export { M as MCPBridge, a as MCPBridgeOptions } from '../../bridge-
|
|
1
|
+
import { A as AppCapabilities } from '../../bridge-BKLezf-H.js';
|
|
2
|
+
export { M as MCPBridge, a as MCPBridgeOptions } from '../../bridge-BKLezf-H.js';
|
|
3
3
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
4
4
|
import { ReactNode } from 'react';
|
|
5
5
|
import { ToolResult, DisplayMode, HostContext, ContentBlock } from '../../core/index.js';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
MCPBridge
|
|
3
|
-
} from "../../chunk-
|
|
4
|
-
import "../../chunk-
|
|
3
|
+
} from "../../chunk-IEZAKOIG.js";
|
|
4
|
+
import "../../chunk-QNH5NSRH.js";
|
|
5
5
|
|
|
6
6
|
// src/platforms/mcp/hooks.tsx
|
|
7
7
|
import {
|
|
@@ -23,7 +23,17 @@ function MCPProvider({
|
|
|
23
23
|
const [bridge] = useState(() => new MCPBridge(appInfo, appCapabilities));
|
|
24
24
|
const [ready, setReady] = useState(false);
|
|
25
25
|
useEffect(() => {
|
|
26
|
-
|
|
26
|
+
let cancelled = false;
|
|
27
|
+
bridge.connect().catch((error) => {
|
|
28
|
+
if (cancelled) return;
|
|
29
|
+
console.error("[mcp-app-studio] Bridge connection failed:", error);
|
|
30
|
+
}).finally(() => {
|
|
31
|
+
if (cancelled) return;
|
|
32
|
+
setReady(true);
|
|
33
|
+
});
|
|
34
|
+
return () => {
|
|
35
|
+
cancelled = true;
|
|
36
|
+
};
|
|
27
37
|
}, [bridge]);
|
|
28
38
|
if (!ready) return null;
|
|
29
39
|
return /* @__PURE__ */ jsx(MCPContext.Provider, { value: bridge, children });
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-app-studio",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Build interactive apps for
|
|
3
|
+
"version": "0.6.0",
|
|
4
|
+
"description": "Build interactive apps for MCP Apps hosts (ChatGPT, Claude Desktop, etc.)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"chatgpt",
|
|
7
7
|
"openai",
|
|
@@ -42,12 +42,6 @@
|
|
|
42
42
|
"default": "./dist/core/index.js"
|
|
43
43
|
}
|
|
44
44
|
},
|
|
45
|
-
"./chatgpt": {
|
|
46
|
-
"import": {
|
|
47
|
-
"types": "./dist/platforms/chatgpt/index.d.ts",
|
|
48
|
-
"default": "./dist/platforms/chatgpt/index.js"
|
|
49
|
-
}
|
|
50
|
-
},
|
|
51
45
|
"./mcp": {
|
|
52
46
|
"import": {
|
|
53
47
|
"types": "./dist/platforms/mcp/index.d.ts",
|
|
@@ -82,9 +76,11 @@
|
|
|
82
76
|
"@modelcontextprotocol/ext-apps": "^1.0.1",
|
|
83
77
|
"@types/node": "^25.2.0",
|
|
84
78
|
"@types/react": "^19.2.10",
|
|
79
|
+
"@types/react-dom": "^19.2.0",
|
|
85
80
|
"@types/tar": "^6.1.13",
|
|
86
81
|
"@vitest/coverage-v8": "^4.0.18",
|
|
87
82
|
"react": "^19.2.4",
|
|
83
|
+
"react-dom": "^19.2.4",
|
|
88
84
|
"tsup": "^8.5.1",
|
|
89
85
|
"tsx": "^4.21.0",
|
|
90
86
|
"typescript": "^5.9.3",
|